✨ Describe terminal grids as executable document structure (#729) - #733
Conversation
PR #733: ✨ Describe terminal grids as executable document structure (#729)9 files, +1293 / -2 Scope🔴 PR has 1295 lines changed. Split into focused PRs. 🟡 1295 lines changed. PRs under 400 receive more thorough review. StructuralOxlint structural signals:
Slop
Oxlint slop signals:
Static AnalysisOxlint: 25 diagnostics across 2 files (11 rules) no-unused-vars (7): packages/core/src/expand.ts CorrectnessNo extraneous code patterns detected. |
| case "Terminal.Grid": | ||
| // The whole layout is decided from source, so every pane's own mistake | ||
| // is reported where it was written — and so is a construct written | ||
| // below the grid that the grid does not lay out. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // below the grid that the grid does not lay out. |
| case "Terminal": | ||
| // A well-placed `<Terminal>` is its grid's, and one placed wrongly | ||
| // under a grid is already reported by that grid's own structure. What | ||
| // is left is a pane with no grid above it at all. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // is left is a pane with no grid above it at all. |
97be063 to
cf6c7e6
Compare
| case "Terminal.Grid": | ||
| // The whole layout is decided from source, so every pane's own mistake | ||
| // is reported where it was written — and so is a construct written | ||
| // below the grid that the grid does not lay out. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // below the grid that the grid does not lay out. |
| case "Terminal": | ||
| // A well-placed `<Terminal>` is its grid's, and one placed wrongly | ||
| // under a grid is already reported by that grid's own structure. What | ||
| // is left is a pane with no grid above it at all. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // is left is a pane with no grid above it at all. |
| // A well-placed <Terminal> is consumed by its <Terminal.Grid> and | ||
| // never expanded on its own. Reaching this branch means the pane sits | ||
| // outside every grid, so it names no component and is diagnosed | ||
| // rather than resolved from the filesystem. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // rather than resolved from the filesystem. |
cf6c7e6 to
ff1144c
Compare
ff1144c to
8986da0
Compare
| case "Terminal.Grid": | ||
| // The whole layout is decided from source, so every pane's own mistake | ||
| // is reported where it was written — and so is a construct written | ||
| // below the grid that the grid does not lay out. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // below the grid that the grid does not lay out. |
|
|
||
| if (segment.name === "Terminal.Grid") { | ||
| // No raise() here, like the branches above: expandTerminalGrid | ||
| // reports every error it creates. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // reports every error it creates. |
| // A well-placed <Terminal> is consumed by its <Terminal.Grid> and | ||
| // never expanded on its own. Reaching this branch means the pane sits | ||
| // outside every grid, so it names no component and is diagnosed | ||
| // rather than resolved from the filesystem. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // rather than resolved from the filesystem. |
8986da0 to
bf2f228
Compare
| case "Terminal.Grid": | ||
| // The whole layout is decided from source, so every pane's own mistake | ||
| // is reported where it was written — and so is a construct written | ||
| // below the grid that the grid does not lay out. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // below the grid that the grid does not lay out. |
| case "Terminal": | ||
| // A well-placed `<Terminal>` is its grid's, and one placed wrongly | ||
| // under a grid is already reported by that grid's own structure. What | ||
| // is left is a pane with no grid above it at all. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // is left is a pane with no grid above it at all. |
|
|
||
| if (segment.name === "Terminal.Grid") { | ||
| // No raise() here, like the branches above: expandTerminalGrid | ||
| // reports every error it creates. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // reports every error it creates. |
| // A well-placed <Terminal> is consumed by its <Terminal.Grid> and | ||
| // never expanded on its own. Reaching this branch means the pane sits | ||
| // outside every grid, so it names no component and is diagnosed | ||
| // rather than resolved from the filesystem. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // rather than resolved from the filesystem. |
| source: "Terminal.Grid", | ||
| // The grid the author asked for, carried beside the sentence so an | ||
| // assertion is about the layout that was derived rather than about the | ||
| // wording of a refusal. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // wording of a refusal. |
`<Terminal.Grid>` and `<Terminal>` become reserved core structural syntax. This Story owns the authored structure alone: the grammar, the placement rules, and the row-major layout a grid derives. No terminal authority, provider, pane execution, shell, durability or replay is built here. The grid's closed props hold one required positive-integer `columns`; a pane's hold one required non-empty `title`. Titles are display labels and identify nothing — a pane's structural identity is its ordinal among the grid's direct children, and rows are derived in authored row-major order with the last row left short. `structural-rules.ts` decides what the source says, so expansion and document validation cannot disagree about it: only whitespace and direct `<Terminal>` panes may appear in a grid, and an empty grid, direct text, a non-pane element, a control structure that would produce panes, a nested grid, and a pane written anywhere else are refused. `terminal-grid.ts` places the panes once `columns` and each `title` are known. A grid the grammar accepts runs until a terminal provider would be asked for one. This build installs none, so it refuses there, before any pane body expands or a default shell starts, and carries the layout it derived beside the refusal. Evidence rows TG1-TG4: the new structural suite owns TG1, TG2 and TG4; the catalog, validation and `xmd syntax` suites own TG3.
Both descriptions lead with what the author can do and show the invocation to copy. The placement rule, the row-major detail and the title's display role are the catalog's structured fields and §6.21's to state, not a second reference entry beside the forms. The frozen catalog entries in `syntax-catalog.test.ts` mirror the two declarations, so they move with them.
bf2f228 to
106028e
Compare
Two call sites still named `syntaxCatalog` and `parseCatalog`, which nothing declares. The file imports `syntaxSymbols` and declares `parseSymbols`, and uses them correctly everywhere else; these two were missed when the pair was renamed. `deno task check` is the first step of every test job, so the whole matrix stopped there rather than running anything: five Deno shards and four Node shards reported a failure none of them had reached a test to find. The two implicit-`any` reports beside them were the same defect seen twice — with `syntaxCatalog` unresolved the catalog degraded to `any`, so the callbacks reading its entries had nothing to infer from. Naming the helper settles both.
| case "Terminal.Grid": | ||
| // The whole layout is decided from source, so every pane's own mistake | ||
| // is reported where it was written — and so is a construct written | ||
| // below the grid that the grid does not lay out. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // below the grid that the grid does not lay out. |
| case "Terminal": | ||
| // A well-placed `<Terminal>` is its grid's, and one placed wrongly | ||
| // under a grid is already reported by that grid's own structure. What | ||
| // is left is a pane with no grid above it at all. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // is left is a pane with no grid above it at all. |
| // A well-placed <Terminal> is consumed by its <Terminal.Grid> and | ||
| // never expanded on its own. Reaching this branch means the pane sits | ||
| // outside every grid, so it names no component and is diagnosed | ||
| // rather than resolved from the filesystem. |
There was a problem hiding this comment.
Redundant comment — restates what the code does.
| // rather than resolved from the filesystem. |
TG3 still froze the catalog at version 1. Its two neighbours in the same file already read 2, and so does `inspect.ts` here, on main, and on every branch above this one: the constant moved and this one assertion did not follow. Both runtimes reported it, because the number is the catalog's rather than either runtime's. The rest of the row is untouched. What TG3 exists to freeze is the pair of structural entries the catalog publishes, and that is what it still checks.
Closes #729. First implementation layer under Quest #717, stacked on #734.
Why
An author needs to be able to write, inspect, and validate a grid before any host attempts to present it. Later lifecycle and provider layers depend on that structure being static and fully known.
What changes
This layer adds reserved core syntax for a paired grid and its paired or self-closing panes. It validates a positive integer
columns, a non-empty panetitle, direct-child placement, nesting, and the exact row-major layout before any pane body, shell, Agent, or provider work begins.The final authored surface, applied later by #781, is:
This PR's exact diff predates that rename and therefore uses the provisional names
<Terminal.Grid>and<Terminal>in its source paths and tests. PR #797, now included in #771, replaces those unshipped names without compatibility aliases.Executing a valid grid at this layer still refuses because no provider is installed. The refusal occurs only after the complete layout is derived and before pane content or a default shell runs.
Contract
Review and evidence
Start with the structural grid test, then inspect the declarations, structural rules, expansion, and document validation.
At this layer the focused entrypoints retain their provisional filenames:
TG1–TG4 distinguish the complete grammar, placement, non-observation, catalog, and one-through-five-pane row-major behavior.
Scope
Included: authored structure, validation, inspection, layout derivation, and fail-closed execution without a provider.
Excluded: concurrent pane execution, provider authority, native launch, tmux, durability, and replay. Those belong to the layers above this one.
Stack order: #734 → #733 → #738.