vscode: inline composer for preview-pane review comments (#1107)#1121
Conversation
…ent seam to (line, text)
…oser-collected text
…teElement to JSX (review feedback)
…e); fix stale header comment
Architect Integration ReviewVerified all three claims in the builder's disposition independently against PR head. Codex finding addressed (commit 27c2c87)The defect codex identified — new comments on an already-commented block insert at the top of the existing thread while the composer appears below — is real and now fixed:
Implementation quality observations
Escalation acknowledged — filing follow-upThe builder's escalation is correct and surfaced honestly: Filing a follow-up to align the editor path with the preview's append semantics (and the canvas adapter's rendered order). The fix is mechanical (swap RecommendationAPPROVE for the pr gate. Ready for merge. The fix is correct, well-tested, properly placed in the core codec, and the escalation is handled by a follow-up rather than scope-creep on this PR. Architect integration review |
PIR Review: Inline composer for preview-pane review comments
Fixes #1107
Summary
Adding a review comment from the Codev Markdown Preview previously opened
vscode.window.showInputBox— a center-top Quick Pick far from the block thereviewer clicked
+on, breaking the visual anchor while typing. This replaces itwith an inline composer rendered in-flow directly below the block (a textarea
with Submit/Cancel), so the reviewer types the comment exactly where it will live.
The comment-intent seam widened from
onAddComment(line)toonAddComment(line, text); the host dropped its text prompt and writes the markerstraight from the body the composer collected. The on-disk REVIEW-marker format is
unchanged (multi-line input collapses to single-line at write time, as before).
Files Changed
packages/artifact-canvas/src/overlays/CommentComposer.tsx(+88 / −0) — new composer componentpackages/artifact-canvas/src/overlays/__tests__/comment-composer.test.tsx(+83 / −0) — new unit testspackages/artifact-canvas/src/components/ArtifactCanvas.tsx(+110 / −24) — composer state, in-flow placeholder injection, portal wiring; JSX conversionpackages/artifact-canvas/src/components/__tests__/artifact-canvas.test.tsx(+80 / −15) — open-composer→submit flow, Esc/reload coveragepackages/artifact-canvas/src/__tests__/end-to-end.test.tsx(+20 / −14) — drive round-trip through the composerpackages/artifact-canvas/src/types.ts(+8 / −4) —onAddComment(line, text)contract amendmentpackages/artifact-canvas/src/overlays/CommentAffordance.tsx(+11 / −9) — JSX conversionpackages/artifact-canvas/src/overlays/MarkerMinimap.tsx(+21 / −17) — JSX conversionpackages/artifact-canvas/src/renderer/MarkdownView.tsx(+7 / −3) — JSX conversionpackages/artifact-canvas/src/styles/default-theme.css(+58 / −0) — composer stylingpackages/artifact-canvas/examples/main.tsx(+4 / −4) — example uses the new seampackages/core/src/review-markers.ts(+19 / −0) — newmarkerAppendLinecodec helper (append-below-thread)packages/core/src/__tests__/review-markers.test.ts(+27 / −0) —markerAppendLineregression testspackages/vscode/src/markdown-preview/messages.ts(+24 / −0) — new named webview↔host protocol typespackages/vscode/src/markdown-preview/preview-provider.ts(+22 / −15) — dropshowInputBox; write from posted text; use protocol typespackages/vscode/src/markdown-preview/webview/main.ts(+9 / −6) — post{line, text}; use protocol typescodev/plans/1107-preview-inline-comment-composer.md,codev/reviews/1107-preview-inline-comment-composer.md,codev/state/pir-1107_thread.md— PIR artifactscodev/resources/arch.md,codev/resources/lessons-learned.md— governance updates (below)Commits
87a6788d[PIR vscode: replace top-of-window Quick Pick input for adding review comments from the markdown preview with an inline composer #1107] artifact-canvas: inline comment composer; widen onAddComment seam to (line, text)1f5e0614[PIR vscode: replace top-of-window Quick Pick input for adding review comments from the markdown preview with an inline composer #1107] vscode preview: drop showInputBox; write marker from composer-collected text69b6e39c[PIR vscode: replace top-of-window Quick Pick input for adding review comments from the markdown preview with an inline composer #1107] Define named webview<->host message protocol types (review feedback)2b9528c4[PIR vscode: replace top-of-window Quick Pick input for adding review comments from the markdown preview with an inline composer #1107] Convert artifact-canvas source components from React.createElement to JSX (review feedback)Test Results
pnpm --filter @cluesmith/codev-artifact-canvas build: ✓ passpnpm --filter @cluesmith/codev-artifact-canvas test: ✓ pass (68 tests; 9 new composer unit tests + updated canvas/e2e tests driving the open-composer→submit flow)pnpm --filter @cluesmith/codev-artifact-canvas check-types: ✓ passcheck-types(host +tsconfig.webview.json): ✓ passnode esbuild.js --production): ✓ passlint: ✓ passtest:unit: ✓ pass (516 tests)dev-approvalgate — composer appears at the block (not the window top), block stays visible while typing, ⌘/Ctrl+Enter submits, Esc cancels and restores focus, multi-line input works, submitted comment collapses into the persisted card in place.Architecture Updates
COLD —
codev/resources/arch.mdupdated (the "Markdown Preview / artifact-canvashost integration" entry). The previous text described the now-removed flow
(
onAddComment(line)→ hostshowInputBox→WorkspaceEdit). Updated to reflect:the inline composer (
overlays/CommentComposer.tsx, portalled in-flow below theblock), the widened
onAddComment(line, text)seam, and the new named host↔webviewmessage protocol (
markdown-preview/messages.ts, shared by both ends; inbound datastill validated at runtime because it's untrusted).
HOT — no
arch-critical.mdchange. This is a package-level seam/UX change, not aframework-wide cross-cutting fact; it does not meet the hot-tier bar (and the file is
at/near its cap). Correctly routed to the cold reference.
Lessons Learned Updates
COLD —
codev/resources/lessons-learned.mdupdated (Architecture section): thereusable pattern for placing an interactive React widget inside an
innerHTML-managed body — inject a placeholder node in an effect andcreatePortalthe component into it, with an idempotent injection effect to avoid a
setState-on-inject loop. Spec-narrow recipe → cold tier, not the capped hot file.HOT — no
lessons-critical.mdchange. No behavior-changing cross-cutting ruleemerged that warrants displacing a capped hot lesson.
Consultation Findings (PIR single advisory pass)
The PR-stage consultation (claude + codex,
type=impl,max_iterations: 1) returned:claude = APPROVE (HIGH), codex = REQUEST_CHANGES (HIGH).
Codex finding (real defect — FIXED in
4a…+ regression test): the host insertedthe new marker at
markerInsertionLine(line)(line+1), which prepends ahead of anymarkers already stacked on the block — so for a block with existing comments, the new
card rendered at the top of the thread, while the inline composer had appeared
below the existing cards. Visual position ≠ result, and it violated the approved
plan's append-to-thread behavior.
markerAppendLine(text, annotatedLine)to@cluesmith/codev-core/review-markers(returns the line after the contiguous marker run; falls back to
markerInsertionLinewhen the block has none).
preview-provider.tsnow inserts there, so the new commentlands where the composer was (newest-last).
packages/core/src/__tests__/review-markers.test.ts—markerAppendLineappends after a 2-marker run (asserts file/render order
first, second, third, allanchored to the block) and handles end-of-file; without the fix the new comment would
be first.
by the regression test above; (b) the stale
stripMarkersForRenderheader comment inpreview-provider.ts— corrected to describe the raw-text + renderer-strips flow.prgate (PIR will not re-review this): the fix changes thecanvas surface to append-below (newest-last). The editor Comments-API path
(
comments/plan-review.ts:171) still inserts atmarkerInsertionLine(line)(newest-first),so the two authoring surfaces now stack a new comment on an already-commented block in
different order. Aligning the editor path is out of scope for #1107 (the issue lists
it as out of scope) and is a one-line change best done deliberately — recommend a
follow-up issue. Please confirm the append-below choice (it matches this PR's approved
plan and conventional thread UX) at the gate.
Things to Look At During PR Review
ArtifactCanvas.tsxplaceholder-injection effect — the trickiest part. Itinjects an in-flow
.codev-canvas-comment-composer-hostbelow the block (after themarker-card stack if present) and is guarded to be idempotent: it bails when a
correctly-placed host already exists (
isConnected && previousElementSibling === anchor), so thesetComposerHostcall doesn't loop. Anhtmlrebuild disconnectsthe node and the guard re-creates it. Worth a careful read.
React routes synthetic events through the fiber tree (the portal's parent is the
canvas root, not the body div), so the body's
onKeyDown"open composer" handlerdoes not fire for keystrokes typed into the composer. This is why plain Enter in the
textarea inserts a newline rather than re-triggering the open path.
review-composer convention). This changed the old single-line Enter-to-submit muscle
memory; confirmed acceptable at the dev-approval gate.
postMessage—preview-provider.tscasts inbound to the named unionfor the discriminant but still validates
line/textat runtime. The named typedocuments the shape; it does not vouch for an arbitrary runtime value.
source components were converted from
React.createElementto JSX in this PR (notjust the new file), so the package is internally consistent. Behavior is unchanged;
it inflates the diff. The package's
tsconfig.jsonalready had"jsx": "react-jsx".How to Test Locally
pir-1107→ View Diffafx dev pir-1107codev/specs|plans|reviews/*.mdin the Codev Markdown Preview ("Reopen With… → Codev Markdown Preview").+on blocks at the top, middle, and bottom of a long doc — the composer appears at the block each time, and the block stays visible while typing.+, Enter to open, type, ⌘/Ctrl+Enter to submit.