Skip to content

feat(s2): sub-component containment (spec v0.4 §5.1) — 0.3.0 - #53

Merged
ryandmonk merged 1 commit into
mainfrom
feat/s2-containment
Aug 7, 2026
Merged

feat(s2): sub-component containment (spec v0.4 §5.1) — 0.3.0#53
ryandmonk merged 1 commit into
mainfrom
feat/s2-containment

Conversation

@ryandmonk

Copy link
Copy Markdown
Contributor

Implements the ratified containment invariant in S2 and wires S2 errors into the repair loop. Companion to aestheticfunction/dspack#41 (the spec amendment).

  • Ancestor-chain check (children + slots, walk-parity with S3); owners strictly from composition.subComponents; both-declared ids exempt; pathed findings naming orphan + owner(s).
  • The four fail-first pins from the post-T3 Build evidence, inverted (7/9 failed on old code, pasted in the commit); the dspack#40 exemplar fails under the inverted declaration and passes under the corrected one in the same test.
  • Repair gap closed: S2 errors previously never reached renderRepairMessage — an S2-failing surface got a "0 violations" repair prompt. Now they render in their own section; byte-identical when absent (F1 golden untouched).
  • pipeline.test.ts refusal fixture repointed at a casualty (dropdown-menu) — the stray-sub shape is now lint-catchable by design.

138/138 green.

🤖 Generated with Claude Code

…oop (0.3.0)

The ratified invariant: a sub-declared component id may appear only within
the subtree of an instance of a declaring compound, unless the contract
also declares the id as a top-level component (independently usable).
Ownership comes only from composition.subComponents — never names,
prefixes, adjacency, or examples. Owner may be ANY ancestor (intermediate
structure allowed); root orphans and sibling placement are the same
refusal; findings are pathed and name the orphan and its owner(s).

Fail-first (containment.test.ts written against unmodified code):
  Tests  7 failed | 2 passed (9)
all four measured production shapes PASSED S2 as membership — root-level
form-label, select-trigger beside its select, bare alert-dialog-content
duplicated next to a nested one, and the dspack#40 field-trio exemplar
(which also PASSES under the corrected ownership in the same test — the
amendment and the contract fix converge).

Repair wiring (the amendment's point): S2 gate errors now ride the repair
message in their own section ahead of governance findings — previously
renderRepairMessage received S3 findings only, so an S2-failing surface
got a repair prompt claiming zero violations. Byte-compatible when no
vocabulary errors exist (F1 repair golden unchanged).

Collateral: pipeline.test.ts's emitter-REFUSAL fixture (stray table-footer
under card) is exactly the shape §5.1 makes lint-catchable, so it no
longer reaches the emitter; the lint-clean-but-refused class it pins is
now exercised via its other member, a declared casualty (dropdown-menu).

Suite: 138/138.
Copilot AI lite review requested due to automatic review settings August 7, 2026 21:08

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 updates the S2 “contract vocabulary” gate to enforce the spec v0.4 §5.1 sub-component containment invariant, and ensures S2 gate errors are surfaced to (and actionable within) the bounded repair loop.

Changes:

  • Add S2 containment checking so sub-declared component IDs are only valid under a declaring compound’s subtree (unless also declared top-level).
  • Thread S2 gate error strings into renderRepairMessage, rendering them in a dedicated section ahead of governance findings.
  • Update/extend tests to cover containment semantics and adjust the “emitter refusal” fixture to remain lint-clean under the new S2 behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/run/pipeline.test.ts Updates the refusal fixture to use a lint-clean “casualty” component now that stray subs are caught by S2 containment.
src/run/orchestrator.ts Passes S2 gate errors into the repair message so containment/vocabulary defects are repairable in-loop.
src/repair/render.ts Extends repair rendering to include S2 vocabulary errors in their own section while keeping output byte-identical when absent.
src/core/lint/vocabulary.ts Implements containment validation (spec v0.4 §5.1) as part of S2 vocabulary checking.
src/core/lint/containment.test.ts Adds focused tests for containment failure modes, exemptions, walk parity (children + slots), and repair-loop plumbing.
package.json Bumps package version to 0.3.0.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ryandmonk
ryandmonk merged commit 9169456 into main Aug 7, 2026
3 checks passed
@ryandmonk
ryandmonk deleted the feat/s2-containment branch August 7, 2026 21:15
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