Skip to content

feat(daemon): persist team-collab comment anchor state - #5225

Closed
lefarcen wants to merge 1 commit into
feat/workspace-teamfrom
feat/collab-comment-storage
Closed

feat(daemon): persist team-collab comment anchor state#5225
lefarcen wants to merge 1 commit into
feat/workspace-teamfrom
feat/collab-comment-storage

Conversation

@lefarcen

@lefarcen lefarcen commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Why

Storage layer for the team-edition read-only comment drift ladder (C lane, OPEND-444, spec §D2), building on the anchor contract from #5222. The comment layer resolves each render through a ladder (anchored → reanchored → stale → lost) instead of today's silent exact-match; that resolution needs a durable home.

What users will see

Nothing yet — backend storage only (no route/UI wired). The drift-ladder engine (next PR) and UI consume it.

What changed

  • preview_comments gains anchor_state, anchored_version, author_member_id, last_good_position_json. Migration ALTERs run after the slide-key table rebuild so a legacy rebuild can't drop them.
  • upsertPreviewComment persists creation metadata (anchoredVersion, authorMemberId); resolved state stays null for the engine.
  • New updatePreviewCommentAnchor = the engine write-back. COALESCE keeps the last-good position/version on a lost resolve; it never bumps updated_at (anchor resolution is a derived read, not an edit).
  • Contract: anchoredVersion on PreviewCommentTarget, authorMemberId on the upsert request (server-set from identity), PreviewCommentAnchorUpdateRequest.

Surface area

  • Shared contracts (packages/contracts)
  • Daemon (apps/daemon — storage + migration)
  • UI / CLI (follow-up PRs)

Tests

apps/daemon/tests/comment-attachments.test.ts: fresh-db columns, creation round-trip, engine write-back + lost-keeps-last-good, legacy-migration backfill. 21/21 green; contracts + daemon typecheck green.

Notes

Stacked on #5222 (merged). Series into feat/workspace-team: PR1 contracts ✓ · PR2 storage (this) · PR3 xpath anchoring engine + drift ladder (web) · PR4 comment UI · PR5 sync trigger.

Storage layer for the read-only comment drift ladder (C lane, spec D2),
building on the contract from #5222.

- preview_comments gains anchor_state / anchored_version / author_member_id /
  last_good_position_json. The migration runs after the slide-key table rebuild
  so a legacy rebuild cannot drop the new columns.
- upsert persists creation metadata (anchoredVersion, authorMemberId); resolved
  state stays null for the drift ladder to fill in.
- updatePreviewCommentAnchor is the engine write-back: COALESCE keeps the
  last-good position/version on a lost resolve, and it never bumps updated_at.
- contract: anchoredVersion on PreviewCommentTarget, authorMemberId on the upsert
  request (server-set), and PreviewCommentAnchorUpdateRequest.

Tests cover fresh-db columns, creation round-trip, engine write-back with
lost-keeps-last-good, and legacy-migration backfill.
@lefarcen
lefarcen requested a review from mrcfps July 6, 2026 16:40
@lefarcen lefarcen added size/M PR changes 100-300 lines risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps type/feature New feature labels Jul 6, 2026

@mrcfps mrcfps left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lefarcen Thanks for the focused storage-layer work here. I reviewed the migration order, the new read/write paths for anchor metadata, and the daemon coverage added around fresh DBs, legacy migration, and lost-anchor preservation. I found one small validation gap that looks follow-up sized rather than merge-blocking.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

Comment thread apps/daemon/src/db.ts
id: string,
input: DbRow,
) {
const anchorState = typeof input?.anchorState === 'string' ? input.anchorState : null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider validating anchorState against the four contract states before writing it. The shared contract now exposes PreviewCommentAnchorState as anchored | reanchored | stale | lost, but this storage helper currently persists any string and normalizePreviewComment will then return that string as anchorState. If the follow-up engine or route sends a typo, the DB can store a value the web layer cannot safely switch on, which undermines the drift-ladder states this PR is setting up. A small PREVIEW_COMMENT_ANCHOR_STATES set, mirroring the nearby PREVIEW_COMMENT_STATUSES check in updatePreviewCommentStatus, would keep persisted rows aligned with the contract and make invalid write-backs fail fast.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

@lefarcen

lefarcen commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Quick PR-body follow-up: the write-up is already clear overall, but could you switch the body to the repo's full Surface area checklist and add an explicit Validation section?

The current notes are useful, but the standard checklist + validation heading make stacked branch review a lot easier to scan.

@lefarcen

lefarcen commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

策略调整:C 线(协作)的 WIP 集中到专属分支 feat/collab-c-lane,端到端做完再一次性合进 feat/workspace-team,避免半成品影响其他线。本 PR 的存储改动(28ed729)已在该分支上,故关闭此 PR。契约 PR #5222 已合入 feature 分支(共享地基,无害)保留不动。

@lefarcen lefarcen closed this Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps size/M PR changes 100-300 lines type/feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants