feat(layout): collapse LayoutNode to container | segment (2de.11)#70
Merged
Conversation
[LAW:one-type-per-behavior] LayoutNode is now exactly `container | segment`. The `inline` and `stepper` node kinds are deleted: interaction, state-driven display, and multi-region clickability all live in a segment's TEMPLATE (via widgets today; the `actions:` model in .12), so they were variability the node type should never have carried. A `segment` is THE unit of rendering — one ref into the named segments map, rendered to one strip item (the 2de.10 structural join). `cells` and `layout` rows survive as authoring SUGAR, lowered at the loader to `container(horizontal, [segment…])` so nothing downstream sees more than two kinds [LAW:one-source-of-truth]. Deleted (their surface is gone, not relocated yet): - InlineNode/StepperNode/InlineCell/ClickWrite types + nodeStateUse projection - node-registry inline/stepper arms, the composite "HUE PIN", setStateUrl/glyphs - validateInlineNode/InlineCell/ClickWrite/StepperNode loader validators - deriveNodeValidators/nodeContributions/nodeDeriveSpecs; deriveValidators is now widget-only (the actions surface merges in at .12) - the node-set-write session.id trigger + node backing-var cross-ref loop Hue rotation is retained but purely DECORATIVE — each segment advances the cursor by one, a container by none; it carries no structural meaning now that cohesion is one-segment-one-item. Tests: dsl-inline-cell + dsl-stepper-node deleted (they pinned the removed surfaces); segment-render-unit #1/#2 re-expressed through the segment surface (a link-bearing template; an empty template) [LAW:behavior-not-structure]; node builders in the suite construct the canonical container|segment tree. dsl-spine snapshot byte-identical; full suite green (1057); live daemon renders the real config (widgets, hue, OSC-8) unchanged.
There was a problem hiding this comment.
Pull request overview
This PR collapses the DSL layout substrate so downstream code only ever sees two node kinds (container | segment), removing the former inline and stepper node kinds and treating cells/layout rows as loader-only authoring sugar. It updates rendering, payload gating, debug/introspection, and tests to align with “segment = unit of rendering (one strip item)” and keeps hue rotation as a decorative per-segment cursor.
Changes:
- Collapse
LayoutNodetocontainer | segment, deletinginline/steppernode kinds and loweringcells/layoutsugar at load time. - Simplify the render pipeline and node registry to render segment leaves only, advancing hue per segment and removing inline/stepper click/state handling.
- Remove node-derived state validators (now widget-only) and update daemon payload gating/debug ordering plus the test suite and default config.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/config/dsl-types.ts |
Redefines the layout union to `container |
src/config/dsl-loader.ts |
Lowers layout rows and cells sugar into container(horizontal,[segment…]); removes inline/stepper validation and related cross-ref logic. |
src/dsl/node-registry.ts |
Deletes cells/inline/stepper node implementations; introduces segment node type as the sole leaf renderer. |
src/dsl/render.ts |
Updates render driver/context for the two-kind tree; hue cursor advances per segment; removes inline session-id plumbing. |
src/daemon/render-payload.ts |
Updates provider gating reachability walk to seed from segment nodes instead of cells/inline surfaces. |
src/daemon/verbs/state-validators.ts |
Removes node-derived validator contributions; validators are derived from widgets only (pre-actions:). |
src/daemon/debug.ts |
Updates layout-order segment enumeration to follow segment nodes. |
src/config/default-dsl-config.ts |
Updates bundled default root to the canonical container(vertical)->container(horizontal)->segment… form. |
test/segment-render-unit.test.ts |
Re-expresses render-unit assertions using segment templates (OSC-8 links / empty template) instead of inline leaves. |
test/render-payload-gating.test.ts |
Updates test layout helpers/fixtures to build `container |
test/dsl-spine.test.ts |
Updates spine assertions to collect segment names via segment nodes. |
test/dsl-merge.test.ts |
Updates merge tests’ layout builders to emit canonical `container |
test/dsl-loader.test.ts |
Updates loader tests to reflect cells lowering and segment-based cross-ref checks. |
test/default-dsl-config.test.ts |
Updates default-config assertions to validate segment nodes rather than cells nodes. |
test/daemon-render-cache.test.ts |
Updates layout flattening helpers to read segment names from segment nodes. |
test/daemon-debug.test.ts |
Updates expected introspected layout shape to the new canonical tree. |
test/dsl-inline-cell.test.ts |
Deletes tests that pinned the removed inline-cell surface. |
test/dsl-stepper-node.test.ts |
Deletes tests that pinned the removed stepper-node surface. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
[LAW:comments-explain-why-only] Remove a stale WHAT-comment above layoutRowsToNode — it still described the lowering as "a vertical container of cells leaves" and sat directly above the correct description, two divergent copies back-to-back. [LAW:one-source-of-truth] deriveValidators delegates to deriveWidgetValidators rather than duplicating its body. The widget surface IS the whole writable-key surface today, so one body means no drift; when the actions table lands (.12) this single site becomes the widget+action merge. Addresses PR #70 review (both nits). lint + typecheck clean; validator/loader suites green.
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.
What
Collapses
LayoutNodeto exactlycontainer | segment(epic 2de, child .11).segmentis the unit of rendering — one ref into the named segments map → one strip item (the 2de.10 structural join). Theinlineandsteppernode kinds are deleted: their job (interaction, state-driven display, multi-region clickability) belongs in a segment's template (widgets today; theactions:model lands in .12), not in extra node kinds.cellsandlayoutrows survive as authoring sugar, lowered at the loader tocontainer(horizontal, [segment…])— so nothing downstream sees more than two kinds ([LAW:one-source-of-truth]).Why
[LAW:one-type-per-behavior]/[LAW:no-mode-explosion]: the four old kinds encoded interaction-variability in the node union. Once "one unit = one strip item" became structural (2de.10), that variability is just template content. Collapsing it is a net −1445 lines — the validators, derivation paths, and dead tests the extra kinds required all fall away.Deleted (surface gone, not relocated yet)
InlineNode/StepperNode/InlineCell/ClickWrite+ thenodeStateUseprojectionsetStateUrl/step glyphsvalidateInlineNode/validateInlineCell/validateClickWrite/validateStepperNodederiveNodeValidators/nodeContributions/nodeDeriveSpecs—deriveValidatorsis now widget-only (the actions surface merges in at .12)session.idtrigger + the node backing-var cross-ref loopHue rotation is retained but purely decorative (each segment advances the cursor by one, a container by none) — it carries no structural meaning now.
Tests
dsl-inline-cell+dsl-stepper-nodedeleted — they pinned the removed surfaces.segment-render-unitfeat(config): JSON5 DSL loader with cross-ref + cycle validation (3rq.1) #1/feat(config): extend cycle detection to depends_on + cache.key edges (3rq.3) #2 re-expressed through the surviving segment surface (a link-bearing template; an empty template) — same behaviors, surviving vehicle ([LAW:behavior-not-structure]).container | segmenttree.Verification
dsl-spinesnapshot byte-identical (default bar visual-equivalent)Epic
brandon-layout-substrate-2de.11— next: .12 (staticactions:table + sub-templateactionfn + derived validators).