Skip to content

FE-1123: Validate single-select none comments at acceptance#287

Draft
lunelson wants to merge 18 commits into
ln/fe-1122-walkthrough-fixesfrom
ln/fe-1123-exchange-rendering
Draft

FE-1123: Validate single-select none comments at acceptance#287
lunelson wants to merge 18 commits into
ln/fe-1122-walkthrough-fixesfrom
ln/fe-1123-exchange-rendering

Conversation

@lunelson

@lunelson lunelson commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

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

lunelson and others added 18 commits July 2, 2026 14:34
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>

lunelson commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

@lunelson lunelson marked this pull request as ready for review July 2, 2026 16:13
Copilot AI review requested due to automatic review settings July 2, 2026 16:13
@lunelson lunelson marked this pull request as draft July 2, 2026 16:13
@cursor

cursor Bot commented Jul 2, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Documentation-only plan bookkeeping; no runtime or validation behavior changes in this diff.

Overview
Updates memory/PLAN.md so the exchange-rendering frontier is tied to Linear FE-1123 and branch ln/fe-1123-exchange-rendering, with a live execution pointer into memory/cards/exchange-rendering--sweep.md (content grammar / option echo / D106-L done; next open work called out as renderResult text handling; head slice noted as landed under D104-L).

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, present_alternatives out of sweep family).

exchange-answering-chrome gains a carried design question from exchange-rendering: GitHub-style per-item review commentary (payload vs collection UI split).

Reviewed by Cursor Bugbot for commit 0c1a6a0. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Comment on lines +30 to +34
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 ?? '' },
Comment on lines +29 to +48
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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants