FE-1123: Validate single-select none comments at acceptance#287
FE-1123: Validate single-select none comments at acceptance#287lunelson wants to merge 18 commits into
Conversation
Reject Other/None single-select responses without a comment at the session acceptance boundary so bad answers return the friendly exchange error instead of relying on projection parsing.
Move the non-empty multi-select answer invariant to session acceptance so empty choices return the exchange boundary error shape instead of a projection parse failure.
Centralize the Other/None/request_changes comment rule beside the request schemas and route schema refinements, UI collection, and session acceptance through the same predicate.
Move non-empty trimmed heading enforcement into the present tool parameter schemas so invalid headings fail before projection construction.
Convert present exchange projections to typed branch construction so write-side detail creation no longer revalidates objects it just built.
Convert request exchange projections to typed status branches so answered details require their payloads statically instead of relying on constructor-time schema parses.
Record the structured-exchange validation boundary decision and update topology docs so projections are typed detail constructors while schemas remain boundary/read-back recognizers.
…(D104-L) Head slice of the exchange-rendering sweep: renderResult consumes result.details via a pure rounded-box projection instead of re-rendering the model-facing markdown string. Adds the render-honesty helper + elision-list convention, live/persisted metamorphic test, dual-family snapshots (content vs renderResult), shared fixtures, and a dev:components static preview entry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Design session outcomes: SPEC oracle design revised to tuple-form goldens (present + request results together); design-permutations.md captures the content-register grammar exploration (★ pattern: h2 Question/Answer frames, em-dash rationale, numbered answer echo with struck rejected options) and the review-set evaluation. Sweep ledger restructured around two new proving rows; content-grammar scope card covers the ★ formatters, answered-payload option echo, and tuple goldens. Consumed head-slice card deleted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Restating original option numbers inside checkbox items resolves the numbering-vs-checkbox tension and handles Other write-ins naturally. Strike variant stays the single-choice alternate; final pick at build. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…k rejected The composed stack settles the echo grammar: selection state, original numbering, and item-level rejection legibility in one line; one grammar for choice and choices; Other write-ins unnumbered and unstruck. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…trings Route through the existing src/agents/shared/markdown.ts wrapper; use md-pen escape for untrusted option/answer text embedded in the grammar. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ntent Simplest current solution: TUI renderResult feeds the formatter's content markdown to pi-tui's Markdown component (wraps + renders inline styles for free); details-built TUI enhancement stays a named ceiling. renderResult golden family + metamorphic leg suspended; render-honesty retargets the details→content pipeline. Ledger row rewritten; revert rides the content-grammar slice. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pass-through Builder slice: D106-L answered-payload option echo (schema recognizer + projection constructors), ★ grammar formatters, tuple content goldens. Snapshot-review batch: terminal states to h2 ## Response; comments as bare blockquotes (no ## Comment heading); free-text answers plain, not quoted; review renders as "## Review: accepted|changes requested|rejected"; option content bolded in questions; Other/None/comment affordances elided from content (collection-UI concerns, named in the elision list); write-ins join the checkbox echo as "- [x] *Other:* …"; shared option-echo/terminal formatters extracted. renderResult pass-through row built per revised D104-L: box renderer, its golden, and metamorphic test retired; render-honesty helper moved beside the content formatters and retargeted at details → content; preview entry shows the Markdown render. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
PR SummaryLow Risk Overview The draft sweep inventory table is reformatted for readability and explicitly superseded by the authored sweep ledger. Traceability no longer waits on a future head-slice SPEC note—it records D104-L (formatter-home retained, details-backed TUI render direction, render-honesty/elision convention,
Reviewed by Cursor Bugbot for commit 0c1a6a0. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Pull request overview
This PR tightens structured-exchange validation and rendering by moving key invariants (comment requirements, non-empty multi-select, trimmed non-empty headings) to earlier trust boundaries, and by standardizing transcript content formatting through shared, details-backed formatters (with render-honesty checks and updated goldens).
Changes:
- Enforce exchange invariants at session/tool boundaries (comment required for Other/None and
request_changes; multi-select must be non-empty; headings must be trimmed + non-empty). - Route accepted responses and tool results through centralized projections + markdown formatters (option-echo payload added; updated snapshot/golden strategy).
- Add/propagate proposed graph codes in review sets and enforce “stale proposed code” detection during acceptance.
Reviewed changes
Copilot reviewed 85 out of 85 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/session/structured-exchange-loop/accepted-response.ts | Moves comment + empty-selection validation into acceptance; emits formatted content via request formatters. |
| src/session/tests/structured-exchange-loop.test.ts | Updates expectations for new content grammar and adds tests for new acceptance validations. |
| src/session/tests/exchange-projection.test.ts | Updates fixtures to include proposed codes and answered option echoes. |
| src/rpc/methods/session.ts | Threads proposed codes into RPC payload derived from details. |
| src/rpc/tests/handlers.test.ts | Updates RPC handler expectations for proposed codes in review-set payloads. |
| src/projections/TOPOLOGY.md | Records D104-L and updates projection-layer migration notes for typed constructors vs recognizers. |
| src/projections/exchanges/request-review.ts | Converts to typed branch construction (removes Zod parse). |
| src/projections/exchanges/request-choices.ts | Adds answered options echo + typed constructors; removes Zod parse. |
| src/projections/exchanges/request-choice.ts | Adds answered options echo + typed constructors; removes Zod parse. |
| src/projections/exchanges/request-answer.ts | Converts to typed branch construction; trims answered text. |
| src/projections/exchanges/present-review-set.ts | Adds proposed_code to persisted review-set node details; typed details construction. |
| src/projections/exchanges/present-question.ts | Splits answer vs option forms explicitly; typed details construction. |
| src/projections/exchanges/present-candidates.ts | Typed details construction (removes Zod parse). |
| src/projections/exchanges/tests/request-choice.test.ts | Updates tests for required answered options echo. |
| src/probes/structured-exchange-rpc-proof.ts | Updates proof fixture to include answered options echo. |
| src/probes/tests/structured-exchange-rpc-proof.test.ts | Updates probe expectations for answered options echo. |
| src/probes/tests/project-graph-review-cycle-proof.test.ts | Updates proof fixtures to include proposed codes. |
| src/graph/review-set.ts | Introduces proposed-code assignment + stale-code diagnostics; validates entity draft proposedCode presence/shape. |
| src/graph/command-executor/tests/accept-review-set.test.ts | Adds coverage for honoring proposed codes and failing on divergence. |
| src/graph/command-executor.ts | Adds proposed-code validation before mutation planning and exposes assignment helper. |
| src/graph/tests/review-set.test.ts | Adds tests for deterministic proposed-code assignment across consecutive drafts. |
| src/dev/component-preview/registry.ts | Adds preview entries rendering exchange markdown results. |
| src/dev/component-preview/exchange-fixtures.ts | New fixtures for present_question and present_review_set projections + formatted results. |
| src/dev/tests/support/tier-2-test-support.ts | Updates helper messages for request_choices to supply answered options echo. |
| src/agents/shared/tree.ts | Switches code-block rendering to md-pen primitives. |
| src/agents/shared/toon.ts | Switches code-block rendering to md-pen primitives. |
| src/agents/shared/markdown.ts | Narrows shared markdown util to house block-composition (joinMarkdownBlocks). |
| src/agents/shared/tests/markdown.test.ts | Updates tests to focus on block-composition semantics. |
| src/agents/contexts/seeds/graph-fact-seed.ts | Uses md-pen list primitive directly instead of wrapper. |
| src/agents/contexts/exchanges/TOPOLOGY.md | Updates exchange formatter ownership notes and records D104-L/D106-L grammar decisions. |
| src/agents/contexts/exchanges/request-review.ts | Updates request_review content formatting to new “Review:” grammar. |
| src/agents/contexts/exchanges/request-response.ts | Updates diagnostic header level to match new grammar. |
| src/agents/contexts/exchanges/request-choices.ts | Implements ★ answer echo grammar for multi-select responses. |
| src/agents/contexts/exchanges/request-choice.ts | Implements ★ answer echo grammar for single-choice responses. |
| src/agents/contexts/exchanges/request-answer.ts | Implements ★ answer grammar for free-text responses. |
| src/agents/contexts/exchanges/render-honesty.ts | New helper to verify details-leaf visibility vs declared elisions. |
| src/agents/contexts/exchanges/present-review-set.ts | Reworks review-set content formatting to proposed-code neighborhood grammar + elision list. |
| src/agents/contexts/exchanges/present-question.ts | Reworks question content formatting + provides elision list for honesty checks. |
| src/agents/contexts/exchanges/option-echo.ts | New shared option-echo formatter and terminal-state formatter. |
| src/agents/contexts/exchanges/design-permutations.md | Adds design exploration doc for transcript/content grammar. |
| src/agents/contexts/exchanges/design-permutations-neighborhood.md | Adds neighborhood-grammar doc for review-set content. |
| src/agents/contexts/exchanges/tests/present-review-set.test.ts | Adds tuple goldens + render-honesty invariant coverage for present_review_set. |
| src/agents/contexts/exchanges/tests/present-question-honesty.test.ts | Adds render-honesty invariant coverage for present_question. |
| src/agents/contexts/exchanges/tests/exchange-renderer-inventory.test.ts | Updates inventory to tuple goldens and adds present_question content golden. |
| src/agents/contexts/exchanges/snapshots/present-review-set.md | Removes old snapshot (superseded by tuple snapshots). |
| src/agents/contexts/exchanges/snapshots/present-review-set-trailing-group-changes-tuple.md | New tuple snapshot for trailing existing-edge group + changes-requested review. |
| src/agents/contexts/exchanges/snapshots/present-review-set-rejected-tuple.md | New tuple snapshot for rejected review tuple. |
| src/agents/contexts/exchanges/snapshots/present-review-set-accepted-tuple.md | New tuple snapshot for accepted review tuple. |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-unavailable-choices.md | Updates unavailable formatting to new header conventions. |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-unavailable-choice.md | Updates unavailable formatting to new header conventions. |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-review.md | Updates review formatting to new “Review:” grammar. |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-question-choices-tuple.md | New tuple snapshot for question→choices. |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-question-choice-tuple.md | New tuple snapshot for question→choice. |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-question-answer-tuple.md | New tuple snapshot for question→answer. |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-present.md | Removes old snapshot (superseded by tuple inventory). |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-present-question-content.md | New snapshot for present_question model-facing content. |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-diagnostic.md | Updates diagnostic formatting to new header conventions. |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-choices.md | Updates request_choices rendering to option-echo grammar. |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-choice.md | Updates request_choice rendering to option-echo grammar. |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-cancelled-review.md | Updates cancelled review formatting to new conventions. |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-cancelled-answer.md | Updates cancelled answer formatting to new conventions. |
| src/agents/contexts/exchanges/snapshots/exchange-renderer-inventory-answer.md | Removes old snapshot (superseded by tuple inventory). |
| src/agents/contexts/data-model/workspace/workspace-context.ts | Switches to md-pen primitives; keeps house composition via joinMarkdownBlocks. |
| src/agents/contexts/data-model/spec/spec-output.ts | Switches to md-pen primitives for headings and bullets. |
| src/agents/contexts/data-model/spec/spec-context.ts | Switches to md-pen primitives for lists/tables. |
| src/agents/contexts/data-model/plan/plan-output.ts | Switches to md-pen primitives for headings and bullets. |
| src/agents/contexts/data-model/graph/graph-slice.ts | Switches to md-pen table primitive. |
| src/.pi/extensions/exchanges/TOPOLOGY.md | Updates tool family ownership + D104-L renderResult rule + D106/D107 notes. |
| src/.pi/extensions/exchanges/shared/markdown.ts | Removes unused local markdown escaping helper. |
| src/.pi/extensions/exchanges/shared/choices-editor.ts | Centralizes comment requirement predicate use; threads answered options echo. |
| src/.pi/extensions/exchanges/shared/choice-source.ts | Enforces comment requirement for Other/None; threads answered options echo. |
| src/.pi/extensions/exchanges/schemas/TOPOLOGY.md | Updates boundary chain notes for typed constructors and read-side recognizers. |
| src/.pi/extensions/exchanges/schemas/request.ts | Adds answered.options echo + shared comment predicate; updates invariants. |
| src/.pi/extensions/exchanges/schemas/present.ts | Requires proposed_code on review-set node drafts. |
| src/.pi/extensions/exchanges/schemas/params.ts | Trims and rejects blank present headings at params boundary. |
| src/.pi/extensions/exchanges/request-response.ts | Threads options echo through UI collectors (question/candidates). |
| src/.pi/extensions/exchanges/present-review-set.ts | Assigns proposed codes before persistence and dry-run validation. |
| src/.pi/extensions/exchanges/present-question.ts | Documents ceiling: renderResult is markdown pass-through of content. |
| src/.pi/extensions/tests/exchanges-schemas.test.ts | Adds tests for new predicate, proposed_code, options echo, and heading trimming. |
| src/.pi/extensions/tests/exchanges-present-request.test.ts | Updates end-to-end present/request expectations for new grammar and payloads. |
| src/.pi/extensions/tests/exchanges-extension.test.ts | Updates renderResult expectations per D104-L revision. |
| src/.pi/extensions/tests/exchanges-editor-envelope.test.ts | Updates editor envelope reconstruction to supply answered options echo. |
| memory/PLAN.md | Updates exchange-rendering frontier metadata (Linear/branch pointer) and notes. |
| memory/cards/exchange-rendering--sweep.md | Adds sweep ledger capturing row inventory, DoD, and verification plan. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (input.status === 'answered' && input.review === 'request_changes') { | ||
| return { | ||
| ...base, | ||
| unavailable: { message: input.message ?? 'request_review requires interactive UI' }, | ||
| }); | ||
| tool_meta: { ...base.tool_meta, next: 'capture_review' }, | ||
| answered: { decision: input.review, comment: input.comment ?? '' }, |
| return collectPrimitiveLeaves(details) | ||
| .filter(({ path }) => !matchesAny(path, elisionPatterns)) | ||
| .filter( | ||
| ({ path, value }) => | ||
| !renderedText.includes(value) && !hasRenderedRepresentation(path, renderedText, options), | ||
| ) | ||
| .map(({ path, value }) => ({ path, value })); | ||
| } | ||
|
|
||
| function hasRenderedRepresentation( | ||
| path: string, | ||
| renderedText: string, | ||
| options: RenderHonestyOptions, | ||
| ): boolean { | ||
| const representations = options.representations ?? {}; | ||
| for (const [pattern, tokens] of Object.entries(representations)) { | ||
| if (matchesPath(path, pattern) && tokens.some((token) => renderedText.includes(token))) return true; | ||
| } | ||
| return false; | ||
| } |

FE-1123: Validate single-select none comments at acceptance
Reject Other/None single-select responses without a comment at the session acceptance boundary so bad answers return the friendly exchange error instead of relying on projection parsing.
FE-1123: Reject empty multi-select exchange responses
Move the non-empty multi-select answer invariant to session acceptance so empty choices return the exchange boundary error shape instead of a projection parse failure.
FE-1123: Share exchange comment requirement rule
Centralize the Other/None/request_changes comment rule beside the request schemas and route schema refinements, UI collection, and session acceptance through the same predicate.
FE-1123: Validate present headings at params boundary
Move non-empty trimmed heading enforcement into the present tool parameter schemas so invalid headings fail before projection construction.
FE-1123: Type present exchange detail constructors
Convert present exchange projections to typed branch construction so write-side detail creation no longer revalidates objects it just built.
FE-1123: Type request exchange detail constructors
Convert request exchange projections to typed status branches so answered details require their payloads statically instead of relying on constructor-time schema parses.
FE-1123: Reconcile exchange detail validation topology
Record the structured-exchange validation boundary decision and update topology docs so projections are typed detail constructors while schemas remain boundary/read-back recognizers.
FE-1123: present_question renders from details; F7 template redesign (D104-L)
Head slice of the exchange-rendering sweep: renderResult consumes
result.details via a pure rounded-box projection instead of re-rendering
the model-facing markdown string. Adds the render-honesty helper +
elision-list convention, live/persisted metamorphic test, dual-family
snapshots (content vs renderResult), shared fixtures, and a
dev:components static preview entry.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
FE-1123: tuple-golden oracle revision, content-grammar design + scopes
Design session outcomes: SPEC oracle design revised to tuple-form goldens
(present + request results together); design-permutations.md captures the
content-register grammar exploration (★ pattern: h2 Question/Answer frames,
em-dash rationale, numbered answer echo with struck rejected options) and
the review-set evaluation. Sweep ledger restructured around two new proving
rows; content-grammar scope card covers the ★ formatters, answered-payload
option echo, and tuple goldens. Consumed head-slice card deleted.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
FE-1123: answer-echo lead shape — checkbox echo with embedded numbers
Restating original option numbers inside checkbox items resolves the
numbering-vs-checkbox tension and handles Other write-ins naturally.
Strike variant stays the single-choice alternate; final pick at build.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
FE-1123: answer-echo final shape — checkbox + embedded number + struck rejected
The composed stack settles the echo grammar: selection state, original
numbering, and item-level rejection legibility in one line; one grammar
for choice and choices; Other write-ins unnumbered and unstruck.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
FE-1123: content-grammar card — compose via md-pen, not hand-rolled strings
Route through the existing src/agents/shared/markdown.ts wrapper; use
md-pen escape for untrusted option/answer text embedded in the grammar.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
FE-1123: D104-L revised — renderResult is Markdown pass-through of content
Simplest current solution: TUI renderResult feeds the formatter's content
markdown to pi-tui's Markdown component (wraps + renders inline styles for
free); details-built TUI enhancement stays a named ceiling. renderResult
golden family + metamorphic leg suspended; render-honesty retargets the
details→content pipeline. Ledger row rewritten; revert rides the
content-grammar slice.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
FE-1123: content-grammar slice + snapshot-review fixes; renderResult pass-through
Builder slice: D106-L answered-payload option echo (schema recognizer +
projection constructors), ★ grammar formatters, tuple content goldens.
Snapshot-review batch: terminal states to h2 ## Response; comments as bare
blockquotes (no ## Comment heading); free-text answers plain, not quoted;
review renders as "## Review: accepted|changes requested|rejected"; option
content bolded in questions; Other/None/comment affordances elided from
content (collection-UI concerns, named in the elision list); write-ins join
the checkbox echo as "- [x] Other: …"; shared option-echo/terminal
formatters extracted.
renderResult pass-through row built per revised D104-L: box renderer, its
golden, and metamorphic test retired; render-honesty helper moved beside
the content formatters and retargeted at details → content; preview entry
shows the Markdown render.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
FE-1123: markdown-escape honesty — stop neutralizing zMarkdown fields
FE-1123: retire markdown wrapper around md-pen
FE-1123: render review sets with proposed graph codes
FE-1123: lock review-set tuple rendering