T2: homogeneous repeated sub-structure → data array (item-mode collection) - #32
Merged
Conversation
… collection)
The second representation capability, scoped by measurement of the
production shapes it targets. Fail-first captured before any code
(/tmp/t2-failfirst.txt): radio-group-item and select's seven subs sat in the
80-unresolved eval ledger, the item-mode spelling was refused by the v2
grammar, and ex.notification-preferences refused end-to-end.
ITEM-MODE COLLECTS. A collect may declare `item: { field: selector }`
instead of the table-mode shape: each descendant matching `of` (document
order) becomes ONE RECORD whose fields resolve against that item's own node
— self.text, self.props.<prop>, and the new item-local self.id. Absent
sources omit the field and gate A3 arbitrates required record shapes:
relocation, never synthesis. Mixing item-mode and table-mode keys refuses;
item fields are closed to item-local selectors at the schema AND the parser
(sibling reads refuse; the parse layer names T3 as defense-in-depth).
THE MEASURED SHAPES, honestly scoped. select-item carries its label as its
own text — the pure homogeneous shape, collected completely and A3-green.
radio-group-item carries ONLY its id: its label is a sibling `label`
component joined by htmlFor->id — a DECLARED KEY JOIN, which is T3's
mechanism by the ratified boundary, and position-based pairing is banned.
T2 collects what each item itself carries ({value: self.id}); the sibling
labels are dropped WITH RECORD (mode-aware messages naming T3 — the v1
table-mode strings stay byte-frozen), pinned as the measured T3 frontier.
Also recorded, not papered over: neither item declares a `value` prop in the
contract (the examples encode value into ids by convention) — a
contract-modeling gap for the taxonomy trail alongside dspack#38.
Eval overlay: the full receiving plans (a collecting plan IS a catalog
component, unlike T1's transparent plans) land as committed evidence.
Production-v3 derived coverage: 80 -> 72 unresolved (radio-group-item
collected; select-item collected, four select subs dropped with reasons,
content/group absorbed). The 72 stay deliberately open as the T3-T5 measure.
267 tests green (+8 T2). All byte gates untouched.
…ole is closed Same six prompts, same model and config as the T1 matrix; contract 3.1.0 (the form-control rule live), gen 0.2.2, emit 0.5.0+T1. The T1-exposed defect now fails at the layer that owns it: zero-control forms are caught at S3 with repairable findings, and the 'donation boundary found 0' emit blocker is gone from the entire post-T1 column. The old 0/6 number stands only as historical evidence of the hole. Authoritative post-T1: pre-T1 1/6; post-T1 0/6 with every failure at an honest frontier — unmapped components (alert, field-set, dialog), stray subs outside their compound (correctly refused), and lint-exhausted repairs where the model cannot satisfy the tightened governance in two attempts. Two adapter timeouts retried once, originals preserved. T1's conversion on this model is limited by model quality, not representation: the named chain emits deterministically in the corpus tests, and under generation the model's empty forms now die at governance instead of sailing through — the system working.
There was a problem hiding this comment.
Pull request overview
Adds the T2 “item-mode collection” capability to the v2 profile grammar and A2UI emitter, enabling homogeneous repeated sub-structures (e.g., select items, radio-group items) to be collected into array-valued props while explicitly deferring joins/sibling pairing to T3. This extends the existing T1 baseline and updates the evaluation fixture and documentation to reflect the new measured coverage.
Changes:
- Extend the v2 profile schema + parser to support
collects[].itemitem-mode (and forbid mixing with table-mode keys). - Implement item-mode collection in the A2UI surface emitter, including diagnostics updates and
self.idselector support for item fields. - Add a dedicated
src/t2.test.tssuite and update eval fixture artifacts/counts to reflect the new resolved coverage.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/transform/shadcn-v2-respelling.ts | Adds production v3 T2 receiving plans for radio-group and select using item-mode collects. |
| src/transform/profile.v2.schema.json | Updates JSON schema to allow item-mode collects via oneOf alongside table-mode. |
| src/transform/profile-schema-v2.ts | Mirrors the schema change in the TS-embedded schema. |
| src/transform/parse-v2.ts | Parses self.id, validates item-mode vs table-mode exclusivity, and builds the internal collect model for item-mode. |
| src/transform/model.ts | Extends selector and collect model to represent item-mode fields and self-id. |
| src/targets/a2ui/surface.ts | Emits item-mode collected records and updates drop/composition diagnostics for item-mode. |
| src/t2.test.ts | Adds fail-first regression + coverage tests for the new item-mode behavior. |
| src/eval-fixture.test.ts | Updates fixture narrative and expected unresolved counts (80 → 72) and resolved breakdown. |
| eval/t1-rebaseline-matrix.json | Adds the authoritative post‑T1 baseline measurement artifact. |
| eval/shadcn-v3.eval.profile.json | Updates the committed eval profile fixture to use T2 plans for radio-group/select. |
| eval/build-eval-profile.mjs | Incorporates the new T2 plans when building the eval profile. |
| docs/PROFILES.md | Documents T2 item-mode syntax and constraints (no joins/sibling reads). |
Suppressed comments (1)
src/targets/a2ui/surface.ts:924
- In item-mode, the
surface-composition-flatteneddiagnostic message correctly mentions “collected item records”, but the corresponding fidelity entry still hard-codes the table-mode note about “cell content beyond text”. This makes the ledger inconsistent/misleading for item-mode collects; the fidelity note should mirror the selected mode.
code: "surface-composition-flattened",
message: itemsOnly
? `${path}: compound '${node.component}' subtree consumed into collected item records (uncollected content is not carried).`
: `${path}: compound '${node.component}' subtree consumed into the synthesized table shape (documented casualty; cell content beyond text is not carried).`,
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
893
to
+897
| message: reason | ||
| ? `${childPath}: '${c}' dropped: ${reason}.` | ||
| : `${childPath}: '${c}' has no slot in the synthesized table shape; dropped.`, | ||
| : itemMode | ||
| ? `${childPath}: '${c}' is not a collected item and has no disposition; dropped (sibling pairing is T3's declared join).` | ||
| : `${childPath}: '${c}' has no slot in the synthesized table shape; dropped.`, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The second representation capability, on the T1 baseline, scoped by measurement. 267 tests (+8); all byte gates untouched.
Fail-first
radio-group-itemand select's seven subs sat in the 80-unresolved eval ledger; the item-mode spelling was refused by the v2 grammar;ex.notification-preferencesrefused end-to-end (/tmp/t2-failfirst.txt, quoted in the suite).What landed
Item-mode collects —
{ "of": ["select-item"], "into": "prop:options", "item": { "label": "self.text" } }: each matching descendant becomes one record whose fields resolve on that item's own node (self.text,self.props.<prop>, the new item-localself.id). Absent sources omit the field and A3 arbitrates — relocation, never synthesis. Mixed item/table keys refuse; item fields are closed to item-local selectors at schema and parser (sibling reads refuse; the parse layer names T3).Measured scoping, reported not papered over
select-itemcarries its label as own text — pure homogeneous shape, collected completely, A3-green.radio-group-itemcarries only its id; its label is a siblinglabeljoined byhtmlFor→id— a declared key join, T3's mechanism by the ratified boundary (position-pairing is banned). T2 collects{value: self.id}; the sibling labels drop with record (mode-aware messages naming T3) — pinned as the measured T3 frontier.valueprop in the contract (examples encode value into ids by convention) — a contract-modeling gap noted alongside dspack#38.Measurements
Also in this PR: the authoritative post-T1 Build re-baseline
Same prompts/model/config; contract 3.1.0 (the dspack#37 governance rule live via #36+gen#52): the zero-control-form hole is closed — caught at S3 with repairable findings, the
found 0emit blocker gone from the whole post-T1 column. Post-T1 0/6 with every failure at an honest frontier (unmappedalert/field-set/dialog, stray subs correctly refused, governance-tightened lint exhaustion). Evidence ineval/t1-rebaseline-matrix.json.Boundaries held
No T3 joins, no T4 slots, no T5 variants (all still refuse); pins intact; no downstream migration; not merged, not published.
🤖 Generated with Claude Code