feat(desktop): workflows family (Plan-023 T-023p-1C-6) - #424
Conversation
|
You have reached your Codex usage limits for security reviews. Please try again later. |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
@codex review |
|
You have reached your Codex usage limits for security reviews. Please try again later. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5497b72d94
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
You have reached your Codex usage limits for security reviews. Please try again later. |
2 similar comments
|
You have reached your Codex usage limits for security reviews. Please try again later. |
|
You have reached your Codex usage limits for security reviews. Please try again later. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7f47716a51
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
You have reached your Codex usage limits for security reviews. Please try again later. |
|
@codex review |
|
You have reached your Codex usage limits for security reviews. Please try again later. |
|
Codex Review: Something went wrong. Try again later by commenting “@codex review”. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 992b4b4f78
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
You have reached your Codex usage limits for security reviews. Please try again later. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 66951eb759
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
You have reached your Codex usage limits for security reviews. Please try again later. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e8c56bd4f3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 540f0dd721
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6bc9eeb3c8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c613298ba2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fcd05a4994
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4bbdac659a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c6fdd87bf3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A first page carrying `nextCursor` and no row for a scope establishes nothing about that scope: the cursor pages the whole resolved union at once. The groups said "No project definitions" anyway, and kept saying it while the continuation read and after the daemon refused it. What a group with no rows may claim is now projected from the continuation the read already carries, beside the pages themselves, and threaded to the groups untouched. Three absences, three next moves: a wait while a page is arriving, "read on" while pages are unread, and a definitive empty only once the daemon says there are no more. A refused continuation lands on the same unresolved arm as an unfollowed cursor, deliberately. The daemon's own sentence is rendered once under the groups, beside the control that retries it, rather than three times over as three empty results. Refs: Spec-023, Plan-023 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
run-list-rows.test.ts carried a byte-identical private copy of the builder the run-list-projection split hoisted; one home, both suites. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The scope picker offers the union of the node's session directory and this window's own open sessions. With the directory refused and one session open, the union still returned that session, the zero-length refusal branch was skipped, and the picker presented the one session as though it were the complete node list. That is the release build's path rather than a corner: the live bridge refuses `sessionList` by name, so an operator who pressed "choose a different session" was shown the session already open and nothing saying the rest had not been read. The choices stay, because withdrawing a session this window genuinely holds helps nobody, and the daemon's refusal is rendered beside them through the same partial-read shape the definitions browser uses for a refused continuation. The console's own sentence about what it managed to offer stands beside the daemon's code and message rather than paraphrasing either. Refs: Spec-023, Plan-023 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…-phase-1c-workflows
…-phase-1c-workflows
Rewritten by the console-screenshot-baselines workflow (mode: regenerate, run 34008266823) against this branch's head, so the committed references are the ones ci.yml's console-screenshot-macos job compares against. Refs: Plan-023 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
# Conflicts: # apps/desktop/src/renderer/src/console/bridge/fixture/fixture-growth-port.test-support.ts # apps/desktop/src/renderer/src/console/bridge/fixture/fixture-growth-port.test.ts # apps/desktop/src/renderer/src/console/bridge/fixture/fixture-growth-port.ts # apps/desktop/src/renderer/src/console/bridge/fixture/fixture-scripted-answer.ts # apps/desktop/src/renderer/src/console/bridge/fixture/fixture-session-directory.ts # apps/desktop/src/renderer/src/console/bridge/growth-port/growth-outcome.ts # apps/desktop/src/renderer/src/console/bridge/index.ts # apps/desktop/src/renderer/src/console/bridge/scenarios/index.ts # apps/desktop/src/renderer/src/console/families.ts # apps/desktop/src/renderer/src/console/frame/ConsoleRoot.routing.test.tsx # apps/desktop/src/renderer/src/console/frame/ContextPicker.tsx # apps/desktop/src/renderer/src/console/frame/SessionsAbsence.tsx # apps/desktop/src/renderer/src/console/frame/SessionsSurface.tsx # apps/desktop/src/renderer/src/console/primitives/wire-figures.ts # apps/desktop/src/renderer/src/console/seats/session-directory.test.tsx # apps/desktop/test/console/architecture/console-layering-rules.test.ts # apps/desktop/test/console/architecture/console-layering-trees.ts
The console bridge split (substrate-5) landed on develop; this folds the workflows family onto it and places what the family adds. Bridge placement, one directory per concern: the two fixture answer builders and the scripted-answer suite to `fixture/`, the untyped-member reads and the scripted probe identity to `scenario-runtime/` beside the seam they serve, and the growth read settlement to a new `readings/` with no door — every reader is a view family, so an inner barrel there would publish a name no sibling reaches. The family's own `bridge/session-directory.ts` is deleted for the substrate's `seats/session-directory.ts`, which is the same hook with a rejection arm; its three consumers rebind through the seats door. `WireChoiceList` stays hoisted to `primitives/` and the frame's two readers rebind to it. Zone grouping: `browser/` and `destination/` each become a module with a door a sibling takes from. `pane-addressing.ts` moves beside its two readers in `pane/`. The shared probe scaffolding stays at zone level — fourteen importers across four sub-modules make it the family's, not the browser's. The untyped-member read now takes `core`'s `isWireRecord` instead of restating the container check, and the wire envelope a harness types reaches `core`'s declaring module rather than `src/shared/`. Refs: Spec-023, Plan-023 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The node's session directory settled a rejected read through the growth port's own builder, which stamps `call-rejected` and composes a sentence around whatever the other side said. The three sibling reads one family up settle through `bridge/readings/read-settlement.ts`, which keeps the daemon's dotted code and message verbatim — so one surface showed `call-rejected` where another, one navigation later, showed `workflow.session_not_found` for the same class of failure. Two refusal vocabularies for one seam, and a person met whichever surface they were on. `useSessionDirectory` now settles through the reading layer like every other growth read in the console. The port's builder keeps `call-rejected` as its own classification but stops dropping what it read: `GrowthUnavailable` becomes a two-arm union whose rejected arm carries the normalized refusal on a required `cause`, so no caller can mint one that discards a daemon code. The builder has no production caller today and its own header says so; a code the vocabulary carries and nothing can construct would be worse, and its new co-located suite drives what it produces. Three surfaces then folded EVERY refused directory into `not-checked` under a sentence asserting the console had not asked the daemon, with the refusal appended — so a closed channel read as an idle console that chose not to look. `isUnbuiltWireRefusal` answers which kind of nothing a refusal is, once, beside the code it reads; only the unregistered-wire arm keeps `not-checked`, and a failed read renders the daemon's own code and sentence. Fix-first, against the pre-change hook: expected 'call-rejected' to be 'session.list_unavailable' expected 'call-rejected' not to be 'call-rejected' expected 'call-rejected' to be 'growth-read-call-failed' `growthUnavailableFromRejection` comes off `bridge/index.ts`: its only importer is now the suite beside it, which is the class `barrel-census` fails on a door. Refs: Spec-023, Plan-023 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Nine review findings against this family, folded into what each one is about rather than recorded beside it. STYLESHEET OWNERSHIP. The placement gave `destination/` a door and left its sheet entering through `workflows.css`, which is the shape both that sheet's own header and the package rules call forbidden — a sheet in one directory made the reason another is styled at all — while `destination/index.ts` asserted the opposite rule about the same file. The sheet now enters through its owner's door and the family sheet's "three doors below this one" is count-free, since a count in prose goes stale the next time a door lands. No pixel moves: the one selector the two sheets share is overridden at `(0,2,0)` against `(0,1,0)`, so specificity decides it and cascade order never did. The gate could not have caught it — `isOwningBarrel` treated any `index.ts` as an owner and the walk asserted one edge from a barrel, never one edge from the OWNER. It computes ownership now, and its own suite drives the offending shape, its repair, and the doorless sub-directory the rule must keep admitting. Against the pre-fix tree: workflows/destination/workflows-destination.css: owned by workflows/destination/index.ts, reached from workflows/workflows.css TWO HEADERS THAT DESCRIBED A DELETED CONFIG. `workflows/index.ts` carried a fourteen-line census of an exemption the substrate had already removed, and sent a reader to find a `to.pathNot` entry that is in neither cruiser config. Both boards live in `seats/` now, so the import is one ordinary door and the comment says that instead. Three files' duplicate same-specifier imports merge with it. THE ENVELOPE SHAPE HAS ONE CONSOLE HOME. One module was moved onto `core`'s re-export of `WireErrorEnvelope` under a header stating the one-home rule while eight others kept reaching `src/shared/` — a rule with eight violations. All nine take `core/index.js` now, and the door line lands on the condition that header itself named: two production readers. The claim is also scoped to what it governs — the SHAPE — since the envelope's readers are still reached from the leaf by two suites, and a door line for those would be the census failure the same note records. A SET PROVEN UNDER ONE SCENARIO, JUSTIFIED BY A SUITE THAT DOES NOT EXIST. The served-set sweep cited a file absent from the tree and a workflow suite absent from its own foot. It is two claims now: everything served answers under the scenario that scripts them all, nothing unserved answers under ANY scenario the fixture plays — read from `scenarios/index.ts`, so a family's scenario is swept the day it lands — plus the counter-arm those cites promised, a served workflow read still refusing where no script speaks. THE HARNESS THE BROWSER LEFT BEHIND. `WorkflowsBrowser.test-support.tsx` stayed at zone level when its component moved into `browser/`, so a module named for a component sat where that component was not and reached past the new door to find it. Its four browser importers were four of twenty-six. It splits on the seam its own header drew: the mount goes with the component, and the probe identities, the row factory, the settled-page port and the `act` boundary become `workflows-probe.test-support.ts`. Also: the scope picker's refusal splits the way its siblings' now do, and its verbatim-code claim is pinned rather than asserted; `readUnknownMember` gets the suite its narrowing shipped without, driving the array arm that is the only place the two readings differ; four prose cites follow `pane-addressing.ts` into `pane/`; `fixture/index.ts` records the deep edge that keeps four cycles closed; and two frame cases stop explaining themselves by a branch this family already ships on. Refs: Spec-023, Plan-023 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Six family branches each fill their own seat in `registerConsolePanes` and in `families.ts`, and both suites only stay one-line diffs across those branches while every branch carries them byte-identical. Adopted from lane/seat-probe 742e4a7: the board is read as a census over its own grammar rather than compared against an ordered literal of the exact seat lines, which is family-specific by construction. This family's pane registration carried no task id — `registerWorkflowPanes` with a bare kind list — so the census reported it twice over, once as an unmarked line inside a seat group and once as a seat 6 that no group filled. It takes the id its surface seat already carries. Refs: Spec-023, Plan-023 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The run pane's re-pin picker shipped ABSENT, and the comment beside it said why: a run carries one opaque `workflowVersionId` and no registered read takes that id anywhere. `workflow.runRead` answers the pin; `workflow.versionRead` addresses a version by `(definitionId, versionNumber)`, which a caller holding a pin holds neither half of; the definition enumeration carries only each definition's latest. So no re-pin target could be NAMED, and an operator repairing a frozen pin had nothing to choose from. Register the read that closes it. `workflowVersionChainRead` joins the growth ledger on a slate row of its own — the mirror image of the run enumeration's row, and like it naming no wire method, because inventing `workflow.versionChainRead` would be a string traceable to nothing. Its request is keyed by the version and by nothing else, and its reply carries each version's id and ordinal: the id is what a re-pin travels with, the ordinal is what a person reads instead of it, and which entry is the current pin is absent on purpose, since the caller asked by that id and can compare. The pane reads it through the family's own settlement path, keyed by the pin the served snapshot reports. That ordering is why the dispatcher stops taking a chain: its round is what puts the snapshot the chain is addressed by, so a chain handed to it would have had to be resolved before the value it resolves from existed. `WorkflowResumeDispatch` splits out of `WorkflowResumeControl` for that — one interface per producer — and the pane joins them at the mount, which is the one place both are in hand. Every arm that is not served offers nothing: unasked, in flight, refused by the port, refused by a daemon, rejected at the seam. The picker stays absent rather than empty and the resume travels with no re-pin, because synthesising a chain from the one id in hand would offer a target nobody read. The refusal is deliberately not rendered — under a live bridge that would put a banner about an unregistered wire beside a control the operator can still press. The workflows fixture answers per requested version out of the chains its definition table now holds, complete rather than sampled (a definition at version N has N versions), and refuses a version it states nothing for through the one not-found constructor the scope module owns. Controls: the pane renders exactly the chain the fixture answers, in the order answered, with the current pin marked; the absent arm renders no picker and still offers resume. Planted negative controls both fail on the guardless code — synthesising on the unserved arm fails two hook cases, and addressing the read with the run id fails the pane's absent arm with a picker whose only target is the run. Refs: Spec-023, Plan-023 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`ScenarioRejectingReply`'s note put the console's one home for the wire's
`{code, message}` shape and for `normalizeWireRejection` in
`src/shared/wire-errors.ts`. The normalizer is not there — it is declared in
`core/wire-rejection.ts`, which is also the module that re-publishes the
envelope, and this file has read the shape through `core/index.js` since the
rebind that gave that door its production readers.
Stated against the door the module actually reads, with the reason the rule
exists: `src/shared/` sits on no rung of the console's family DAG, so taking
the shape from `core` is what keeps one reading of it above that floor
rather than one per family.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Substrate-6 lands the five cross-cutting commits on develop once. Thirteen
conflicts, resolved to the rules the fold plan sets out:
- seam paths (readings/read-settlement.test.ts, frame/SessionsAbsence.test.tsx,
seats/session-directory.frames.test.tsx) and the seat-adoption list
(families.test.ts, panes/panes.test.ts, seats/{index,pane-registry}.ts) take
develop's; panes/seat-census.test-support.ts is deleted where it moved.
- the doors take develop's plus this family's own lines. GrowthUnavailable,
settleGrowthRead and the workflow projection block come back because this
family supplies the readers develop had none for, and the paragraph
justifying their removal goes with them.
- the served workflow operations re-home into fixture-served-operations.ts,
spread into the annotated tuple so the ids and the handlers stay one set.
- families.ts hands registerWorkflowSurfaces the surface board by its own name,
and the two scripted-reply call sites answer with the whole outcome, which is
what this family's operation-keyed adapter asks for.
Eleven @consumedby markers on seats/index.ts are deleted: this family's modules
are the readers they were holding a place for, and a marker that outlives its
consumer fails the run rather than rotting.
One red is left deliberately. seat-census.test-support.ts pins a filled seat to
the literal `register<X>(registry);` — the pane board's parameter name, which
the family board does not have — so this family's seat line cannot match it.
The widening belongs to the substrate rather than to six family branches, and
lands from its own lane.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The seat census pinned a filled seat to `register<X>(registry);` — an argument list of exactly one name, and that name spelled `registry`. It reads the pane board, whose one parameter is called that, and it can never read `console/families.ts`, which hands out five registries and so has no parameter by that name. Every family seat therefore parsed as an unmarked line, the seat block began at the first still-reserved comment below it, and the census answered `missing-task` for the ordinal that had just been filled: a board refusing the one edit it exists to accept. All six family branches hit it at their first seat. The registration now takes the comma-separated NAMES of the boards it writes into. Identifiers and not arbitrary text, so the grammar stays a grammar: an empty list and a call expression are both unmarked lines, each with a planted case, and a seat needing a value that is not a board names it above the block and passes that name. The pane board's own seats are unchanged, and its header says why a single parameter is an instance of the list rather than the rule. Refs: Plan-023 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
# Conflicts: # apps/desktop/AGENTS.md # apps/desktop/package.json # apps/desktop/src/renderer/src/console/bridge/console-bridge.ts # apps/desktop/src/renderer/src/console/bridge/index.ts # apps/desktop/src/renderer/src/console/bridge/scenarios/index.ts # apps/desktop/src/renderer/src/console/core/index.ts # apps/desktop/src/renderer/src/console/families.ts # apps/desktop/src/renderer/src/console/frame/RouteSurface.tsx # apps/desktop/src/renderer/src/console/frame/SessionsSurface.tsx # apps/desktop/src/renderer/src/console/panes/index.ts # apps/desktop/src/renderer/src/console/persistence/index.ts # apps/desktop/src/renderer/src/console/primitives/index.ts # apps/desktop/src/renderer/src/console/primitives/wire-figures.ts # apps/desktop/src/renderer/src/console/store/index.ts # apps/desktop/test/console/accessibility/axe-run.ts # apps/desktop/test/console/architecture/stylesheet-edges.test.ts # apps/desktop/test/console/budget/budgets.json # apps/desktop/test/console/electron-harness.ts # apps/desktop/test/console/endurance/steady-state.test.ts # apps/desktop/tsconfig.console-browser-test.json # apps/desktop/tsconfig.console-electron-test.json # apps/desktop/tsconfig.test.json # docs/plans/023-desktop-shell-and-renderer.md # pnpm-lock.yaml
Two gates develop landed while this family was in flight fail over the merged tree, and both are real rather than cosmetic. `cap-constant-home.test.ts` says a ceiling lives in one module and no view family declares one of its own. This family declared two, and the header it was written against — `core/constants.ts` saying a family adds its own module beside its subtree — is the sentence that gate exists to retire. So the cancel reason's byte cap and the phase graph's zoom range move to the home and reach this family through the core door, on the precedent the terminal family's caps already set. The zoom FLOOR travels with its ceiling although its name carries no bound segment: the two are one decision about what the graph is for, and split across two homes one of them moves alone. The family's constants module and its suite are retired, its relations folded into the home's own. Four whole-tree parse gates then began timing out on vitest's 5 s default — `catch-stringification-chokepoint`, `no-browser-namespace`, `resize-observer-chokepoint`, and the stylesheet gate. None asserts anything new; the tree grew by two view families and the passes crossed the default. Measured warm they are 1.8-2.6 s and on a cold cache or under the aggregate's five-project concurrency they cross 5 s, which is the load class `source-walk-chokepoint.test.ts` documents and answers with an explicit budget. Each states one now, at that file's figure and for its stated reason. The stylesheet gate also gains the control the merge owed it: its reachability claims walk the shared walk's tree while its floor claim guards Vite's module graph, so an empty model sheet list would have left both silently green. The two lists are now compared. Proven by perturbation - shortening the model list by one fails that test and only that test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
# Conflicts: # apps/desktop/src/renderer/src/console/bridge/fixture/fixture-growth-port.test.ts # apps/desktop/src/renderer/src/console/bridge/fixture/fixture-served-operations.ts # apps/desktop/src/renderer/src/console/bridge/fixture/fixture-session-directory.ts # apps/desktop/src/renderer/src/console/bridge/growth-operations/index.test.ts # apps/desktop/src/renderer/src/console/bridge/index.ts # apps/desktop/src/renderer/src/console/core/constants.ts # apps/desktop/src/renderer/src/console/core/index.ts # apps/desktop/src/renderer/src/console/frame/SessionsSurface.tsx # apps/desktop/src/renderer/src/console/frame/frame.css # apps/desktop/src/renderer/src/console/primitives/index.ts # apps/desktop/src/renderer/src/console/primitives/wire-figures.ts # apps/desktop/src/renderer/src/console/seats/index.ts # apps/desktop/src/renderer/src/console/seats/owner-slot.ts # apps/desktop/tsconfig.test.json
Four of them, each named by a gate rather than found by reading. `seats/index.ts` — `OwnerSlotContract` came back from develop carrying a task marker while this family already imports the type. A marker that outlives its consumer fails the dead-code gate under `--treat-tag-hints-as-errors`, so it leaves in the diff that imports the symbol, which is the rule the package standard already states. `scenario-runtime` — `readUnknownMember` lost its last importer when develop's typed session directory replaced the reader that took it. The door publishes the string read alone now, the container read it is built on stays private, and the header counts two importers instead of three. `fixture-served-operations.ts` — the script-only subset widens from writes to the criterion it was always naming: an answer ABOUT a named subject has no honest empty form, because an empty one asserts the subject exists. The three subject-addressed workflow reads join the four writes there. A read-side control lands beside the write control so the subtraction is not the same act as deleting the coverage; driven under a scenario that scripts no workflow it fails, once. `e2e/frame-boot` — the reserved-slot probe pointed at `#/workflows`, which this family now owns, so it asserted the reserved arm against a filled slot. Re-pointed to `timeline`, the one declared surface slot still unclaimed, and addressed with the scenario's own session because a bare auxiliary route answers with the context picker rather than an absence. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Rewritten by the console-screenshot-baselines workflow (mode: regenerate, run 34040980116) against this branch's head, so the committed references are the ones ci.yml's console-screenshot-macos job compares against. Refs: Plan-023 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
The screenshot tier pinned its runner and every condition Playwright can be told, and still could not be green: on `macos-15` the console's monospace stack resolves two ways across runs of the SAME tree. Nothing self-hosts IBM Plex, so the face is decided by whichever remaining entry the host has activated, and that answer moved between one run and the next — a 0.600-advance face with an unslashed zero in some runs, Menlo in others. A 0.002 em difference is not cosmetic. It moves the browser capture card's `Open preview` control one pixel and grows the terminal pane by 24 px, its 24-row grid one pixel taller per row. Both modes reached the committed set: the browser and terminal references were minted under the first and the repos references under the second, so each regeneration only moved which half of the corpus was wrong. So the tier states the face instead of inheriting it. `capture-faces.ts` pins the monospace custom property per test through a project setup file, which a family added later inherits without opting in. Menlo is the value because it is the face macOS registers system-wide and the one both observed modes reach — by name where name lookups work, through the generic where they do not — so the two arms converge rather than alternate. The sans stack is deliberately left alone: it has rendered identically in every run observed, and pinning it would re-mint every reference in the repository to close a hazard with no instance. Measured on a macOS 26.6.1 host, which had been rendering the first mode: the four references this drift had split now compare byte-clean against the committed set, and the whole tier's residue is the six documented pixels on a single sans keycap glyph. `screenshot-pins.ts` no longer credits `ui-monospace` for a residue it no longer contributes to. Refs: Plan-023 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit e0f5193)
`emulator.css` sets `font-family: var(--meridian-font-mono)` on the terminal host, and the grid never read it. `@xterm/xterm` measures its cell from its OWN `fontFamily` option and never from the element it was opened onto, and this family passed none — so the declaration reached the accessible row list and nothing else, while the grid drew in the library's default `courier-new, courier, monospace`. Two faces for one role, and the row height that sizes the whole pane came from the one nobody chose. That is also why pinning the capture typeface did not settle the terminal reference: the pin moves a custom property the emulator was not reading. Attach now reads the host's computed family and tells the emulator, so the stylesheet's own declaration is what decides — one source of truth, a document that overrides the property is followed, and no copy of a token value lives in the emulator. A host that declares nothing leaves the library's default alone rather than clearing it, because a grid with no face draws nothing; and a face that has not moved is not rewritten, because the write re-measures the cell and repaints every row while attach runs on every remount. Measured with the capture pin in place: the two degraded-lease references, which a macOS 26.6.1 host rendered 24 px short of the committed images, now compare byte-clean against them. Refs: Plan-023 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit fa34d58)
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Rewritten by the console-screenshot-baselines workflow (mode: regenerate, run 34043139872) against this branch's head, so the committed references are the ones ci.yml's console-screenshot-macos job compares against. Refs: Plan-023 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Summary
Plan-023 Phase 1C, T-023p-1C-6 — workflows. The workflows rail destination, the definitions browser, the run pane with its phase graph, and the run-list projection over the registered workflow reads, built over the fixture bridge with typed owner slots for the five bodies Plan-017 authors and this task does not.
Based on
develop; this diff is the family alone.What the family renders
The workflows family: the rail destination, both workflow pane chromes, and the
run-list projection over the registered workflow reads — with typed owner slots for
the five bodies Plan-017 authors and this task does not.
The rail destination is now claimed. The rail has had a workflows destination
since the frame shipped and nothing had ever claimed the slot, so pressing it
reached the frame's reserved-slot absence — a true sentence about a definitions
browser this family had in fact already built. The family fills its reserved seat in
console/families.ts, and the browser goes and gets the rows it shows.Both surfaces read. The definitions browser puts the definition enumeration and
the run pane puts the run read, both through the growth port. A refused read stays a
refusal and never becomes an empty list or an unparked run.
The phase graph. The run's phase sequence is drawn with
@xyflow/react, thelibrary
Spec-023 §Console LibrariesADOPTs-with-constraints for this canvas, behinda memoised dynamic import so it costs the initial bundle nothing. The layered
auto-layout, the node and edge visuals and the stylesheet are own-built, which is
what that row's OWN-BUILD half requires, and every one of the library's custom
properties is set from a Meridian token. The graph is read-only: no connect mode, no
inspector, no drag — the authoring canvas is another plan's body and stays a slot.
The pin is
@xyflow/reactat exactly 12.11.5, not the 12.11.6 the spec row names.pnpm-workspace.yamlsetsminimumReleaseAge: 1440, and 12.11.6 was published under24 hours before this branch was cut, so
pnpm installrefuses it outright; 12.11.5 isthe newest release the guard admits, sits inside the
12.11.xband the row requires,and is the release that fixed the broken 12.11.4 the row warns about. This is the
precedent the Electron pin already set. No
minimumReleaseAgeExcludeentry was addedand no
zustandalias or override exists.@xyflow/systemis deliberately not a direct dependency, and the lockstep the rowdemands is stronger without one. Every
@xyflow/reactrelease declares its systempackage as an exact version rather than a range — 12.11.5 declares
0.0.81,and the broken 12.11.4 declared
0.0.80, the very version that lacked the symbol itimported. So a direct pin on our side could not have prevented that breakage and can
only ever restate what the parent already fixes; what protects the build is the exact
parent pin plus the resolved lockfile under CI's
--frozen-lockfile, and the lockfiledoes resolve
@xyflow/react@12.11.5 → @xyflow/system 0.0.81. A declared dependencynothing imports is what the dead-code gate exists to reject, and
apps/desktop/AGENTS.mdadmits no
ignoreDependenciesexemption for it.test/console/architecture/workflow-no-graph-library.test.tsis deleted with theadoption: its entire claim was that this family imports no graph library before the
body that needs one, and that is now false by design.
The three scripted reads are routed. The workflows scenario had scripted the
definition enumeration, the run read and the phase-output read since the scenario
lane, and the fixture growth port answered none of them, so both panes rendered "not
checked" in every fixture build. All three are served now, each with a fallback that
is honest rather than convenient: an enumeration nobody answered is an empty list,
because an enumeration has an empty form and that is a real daemon answer; a run read
and a phase-output read nobody answered are typed refusals, because every member of
those shapes is required and an "empty" run would be five invented facts the operator
controls sit on.
Tiers
The family is pinned in the screenshot tier and the accessibility tier, on the two
surfaces that carry its visual argument — the definitions browser's three scoped
groups and a parked run — in both schemes. Both mount out of the pane registry rather
than by rendering a component directly, so what the tiers photograph is what the
console actually seats.
The pinned-platform skip and the axe runner are hoisted out of the frame tier's files
into modules of their own, unchanged, so a second tier file does not restate either
rule. The accessibility file keeps its planted-violation control: a run that reports
nothing has proved the checker still fails on a known-bad tree.
The family barrel now registers a surface seat beside its pane registrations, and it
reaches the registry type through
frame/surface-registry.jsrather than the frame'sbarrel. That is not a style choice — the frame barrel also exports the composition
root, so a family reaching the seat through it closes
families.ts → workflows → frame → ConsoleRoot → families.ts, which the layering gaterejects. The reason is written at the import for the next family to read.
What it consumes from the substrate
console/core— refusals, the keyed registry, the clock.console/primitives—Nothing,RefusalBanner,Chip,WireFigure,Glyph,and
wire-figures.tsas the one figure chokepoint.console/bridge— the growth port, the fixture bridge, the workflows scenario,and
workflow-projection.ts's read shapes (which leave through the bridge barreland are deleted with that module when
packages/contractsregisters the plane).console/frame— the surface registry the family's seat registers into.console/workspace/seats—PANE_KINDS, the pane registry, andOwnerSlotContract.Wires this family does not have
workflow.definitionCreateworkflow.definitionRead,workflow.versionReadworkflow.runCancel,workflow.runResume,workflow.gateResolve,workflow.humanFormSubmit,workflow.runStartworkflow-run-control; no scenario settles a workflow mutation, so each renders a typed refusalworkflow.*event typesworkflow-event-registrationworkflow.versionReadservesnextCursoris omitted from the scripted replyBudgets
The budget set is the spec's eight rows plus the rows sibling families and the launch
harness have registered, and this family mints none: its surfaces are
chrome over the substrate's primitives, and the one new dependency is a lazy chunk
the
renderer-initial-bundlesubject excludes by name.Measured on this branch: the initial graph is two assets at 186,584 B gzip,
41.5 % of the 450 kB budget, verdict
WITHIN BUDGET(brotli 160,661 B, reported andnever gated). The graph library and its stylesheet land in
PhaseGraphCanvas-*,61,371 B gzip that the entry document's import graph does not reach — which is the
claim the manifest, not the comment, settles.
Residuals, re-derived on this head
The residuals the first version of this body listed were re-checked against the current tree rather than carried:
bridge/fixture-growth-port.tsover the line ceiling — closed. The port is 284 lines and its test 221; the attention derivation and the scripted-reply adapter each have their own module.WorkflowsDestination.tsxresolves the session it reads from (the one a person chose there, else the one this window last opened, recorded by every route transition that names a session), so the definition enumeration is asked with the required session id.bridge.growthand render the port's own refusal; the hand-composed one is deleted.Nothingthis family renders issurfaceorinlineplacement.What remains open is the growth slate: the re-pin picker ships absent because no registered read maps a
workflowVersionIdto its version chain (workflow.runReadanswers one id;workflow.versionReadaddresses by definition and version number, which the pane does not hold). RegisteringworkflowVersionChainReadon the slate — a registry row, no Status flip — lands with the bridge-placement commit that follows the console bridge split, and the pane'sversionChainparameter is already threaded end-to-end for it.Screenshot references
All six of this family's references were regenerated on the
macos-15runner byconsole-screenshot-baselines.yml(moderegenerate, run 33988482268) against this branch's head and committed in5d75e6de—workflow-builder-definition-{light,dark},workflow-definitions-browser-{light,dark},workflow-parked-run-{light,dark}— so the committed set is the oneci.yml'sconsole-screenshot-macosjob compares against.After the run-controls fold, the two
workflow-parked-run-{light,dark}references were regenerated again on the same runner (run 34004476246) and committed in677b9d9d. The delta is exactly the fold: the two footer cells no longer show a hand-composedwire-unregisteredrefusal reading "the operation is not on the bridge yet"; they offer Cancel this run with its optional-reason disclosure and Resume this run, each under its one-line explanation, and the panel is 5 px taller for the disclosure row. The parked-phase cards above them, the dependency notice, and the header are pixel-identical.That second regeneration also encoded a regression the review caught and this head fixes: the phase graph's canvas was an empty 20 rem box in both parked-run references. The pair was regenerated a third time on the same runner (run 34008266823) and committed in
6800ff10; the canvas now paints the four fitted phase nodes, their connectors and the attribution plate exactly as the first regeneration did, with everything below the graph unchanged from677b9d9d. Verified by reading the new PNG against the pre-regression reference, not against its immediate parent.Since the earlier review head
Two lanes landed between the head the 2026-09-04 review threads were written against and this one; each thread was re-verified against the current tree by reading the code rather than the diff, and every reply names where.
Run controls through the growth port (
c01681a9). The workflow run pane mounted its cancel and resume controls as hand-composed refusals saying the operation was "not on the bridge yet", whilebridge/growth-operations/workflows.tshas carriedworkflowRunCancelandworkflowRunResumeall along — so an operator was told an act was unreachable that nothing had checked. Both controls are now offered unconditionally, a press dispatches throughbridge.growth, and the refusal a person reads is the port's own — its origin, its code, its structured operation and slate row — never one this mount site composed about a wire it had never consulted.run-control-dispatch.tsowns the call, the single flight and the settlement: one act per(action, run)through the substrate's subject-scoped holder and generation latch, so a second press while one is outstanding is refused visibly rather than queued or dropped, and an answer arriving after the pane was retargeted installs nowhere. A served act advances a read round the run snapshot joins into its subject key, so the run is read once more per act a person performed and by no timer —packages/contractsregisters noworkflow.*event type, so there is no stream to subscribe to.unregisteredRunControland itswire-unregisteredmember are deleted; every other hard-coded refusal inconsole/workflows/**was enumerated and either relays a served read's refusal, guards a pane address, or — in the builder's case — makes a claim that is still true, since noworkflow.definitionCreateoperation exists to reach.Round-2 delta review fold (
4a5ae3b1). Four correctness defects are fixed as normative behaviour: the re-pin target is resolved against the version chain on screen and not merely scoped to the run, so a chain that moves cannot leave a blank picker disagreeing with a named target the submit would still send; the pane host's chosen scope and open pane address are held against the port that served them, so a bridge swap re-mints both instead of asserting a session's emptiness about a daemon that was never asked; a refused graph chunk can be asked for again, reaching the retry the loader was already built for through a banner action drawn from the initial document; and the destination's row openers are held still soRunListItem'smemoholds. Two smaller shapes go with them — the builder pane's chrome actions are phrasing content, and the fixture's run-enumeration key is spent from its constant rather than restated. Each fix ships with a test that drives the real control and was proven by perturbation; one control that passed on the defective shape was replaced rather than kept. The structure half repairs eleven claims the family made about itself that the pane move had made false — stylesheet edges, theframe/deep-import census, the cruise budget's measurement, and the announcement adapter's unverifiable promise — widens the pane board's seat gate so a filled line must name the kinds it claims, and deletes a written-never-read intermediate fromWorkflowSlotMountwhile keeping the door line it was the only reader of.Substrate-4 rebind (
72351f97, merged through#437). The screenshot tier's per-file host reading isbaseline-host.ts, and the guard it wraps is a class rather than three module bindings, so this family's ownbaseline-guard.tsand the browser-tier control that drove its latch are deleted rather than kept beside it — the substrate's control makes every claim that one made and four more, on a required CI job. The layering rule set, its twelve planted trees and its sixteen cases are the substrate's; this family's copies were a strict subset and are gone, and the family's own.dependency-cruiser.mjsblock was byte-identical to what the substrate now owns across its two files, so the rules file is taken wholesale and the vocabulary file needs no workflows entry — this family lands no root registrar. What survives the substrate's version ofseats/index.tsis this family's claim retirements: nine door specifiers it imports in production carry no@consumedBytag, and the two knip already counts referenced keep the line-comment form a tag would fail the run on. Every new gate is green — the console-wide directory ceiling, the widened stacked-doc walk, the third catch-stringification shape, the glyph-size home, and all three new layering rules.Round-3 delta review fold (
792b9f30). The regenerated parked-run references encoded a real regression: the phase graph's canvas was an empty 20 rem box.ConsolePaneChrome's.meridian-panedeclares no block size, so the column above the canvas resolved everyflex: 1against an indefinite height and the canvas carried only a floor — an indefinite containing block, against which@xyflow/react's inlineheight: 100%root resolves to zero and clips every node. The canvas now statesblock-sizebeside that floor and keepsflex: 1 1 auto, so a bounded seat still grows it, and the browser tier gains the two readings a collapsed root cannot satisfy whileisPhaseGraphSettledrequires a painted phase rather than a fitted transform alone. The layering harness's cruise, tree and rule counts are count-free or derived; the single-flight case presses twice from one captured control inside oneact, which a rendereddispatchingflag cannot survive; and thirty-four door tags stop namingT-023p-1C-6for symbols this family never imports, verified with the TypeScript parser.WorkflowsBrowser.test-support.tsxbecomes the family's one home forsettle, the probe identities and the page cursor, andrun-directory.test.tsxdrives every case through the store's own commit-recording probe instead of a local render-call copy. Eleven false header and comment claims are corrected to what the tree actually does.Round-4 delta review fold (
lane/wf-fix-g,9b00d20ec..e9a93a154). Eighteen findings folded across four commits. The node's session directory settled a rejected read through the growth port's own builder, which stampscall-rejected, while the three sibling reads one family up settle throughbridge/readings/read-settlement.tsand keep the daemon's dotted code verbatim — two refusal vocabularies for one seam, and a person met whichever surface they were on;useSessionDirectorynow settles through the reading layer like every other growth read,GrowthUnavailablebecomes a two-arm union whose rejected arm carries the normalized refusal on a requiredcauseso no caller can mint one that discards a daemon code, and three surfaces that folded every refused directory intonot-checkedunder a sentence asserting the console had not asked (a closed channel read as an idle console that chose not to look) now split onisUnbuiltWireRefusal, minted beside the code it reads: only the unregistered-wire arm keepsnot-checked, and a failed read renders the daemon's own code and sentence — fix-first against the pre-change hook (expected 'call-rejected' to be 'session.list_unavailable'). Nine more findings folded into what each is about: thedestination/sheet entered throughworkflows.css, the shape both headers call forbidden, and now enters through its owner's door with no pixel moved (the one shared selector is overridden at(0,2,0)against(0,1,0), so specificity decides and cascade order never did) — and the gate that could not have caught it now can,isOwningBarrelhaving treated anyindex.tsas an owner, sostylesheet-edge-graph.tscomputes ownership and its suite drives the offending shape, its repair, and the doorless sub-directory the rule must keep admitting; a fourteen-line census inworkflows/index.tsof an exemption the substrate had already removed becomes one ordinary door import and three files' duplicate same-specifier imports merge;WireErrorEnvelope's one-console-home rule had eight violators still reachingsrc/shared/and all nine takecore/index.jsnow, the door line landing on the condition the header itself named (two production readers); the served-set sweep cited a file absent from the tree and a suite absent from its own foot, and is two claims now — everything served answers under the scenario that scripts them all, nothing unserved answers under any scenario the fixture plays, read fromscenarios/index.tsso a family's scenario is swept the day it lands — plus the counter-arm those cites promised;WorkflowsBrowser.test-support.tsxstayed at zone level when its component moved intobrowser/and splits on its own seam (the mount with the component, the probe identities / row factory / settled-page port /actboundary intoworkflows-probe.test-support.ts, twenty-six importers rebound); the scope picker's refusal splits the way its siblings' now do;readUnknownMembergets the suite its narrowing shipped without, driving the array arm (lengthand"0") where the two readings differ; four prose cites followpane-addressing.tsintopane/;fixture/index.tsrecords the deep edge that keeps four cycles closed. The family-independent pane seat suites are adopted,registerWorkflowPanestaking the task id its surface seat already carried. And the run pane's re-pin picker, which shipped absent because a run carries one opaqueworkflowVersionIdand no registered read takes that id anywhere, gets the read that closes it:workflowVersionChainReadjoins the growth ledger on a slate row of its own (the mirror image of the run enumeration's row, naming no wire method because inventing one would be a string traceable to nothing), keyed by the version and nothing else, its reply carrying each version's id and ordinal with the current pin deliberately absent since the caller asked by that id and can compare.createRefusingGrowthPortstays homed in its declaring module for its ~21 cross-family test readers, with the doc naming the three rejected alternatives (the family door, which publishes only what an outside production reader takes; the sub-module door, reachable only intra-family; atest/console/re-export, the shimAGENTS.mdforbids).The develop merges (
lane/wf-fix-g: substrate-68b0e62119ata5a743f07, then browser-terminal947d9e33c+ substrate-79445133e8). The substrate-6 merge adopted develop's seat contracts wholesale; this family's...FIXTURE_SERVED_WORKFLOW_OPERATION_IDSmoves into develop'sbridge/fixture/fixture-served-operations.ts, itsbridge/readings/read-settlement.*pair is the half substrate-6 landed (so the merge sees identical content),answerFromScriptedReplyis re-generified overTOperationIdwith tsc enforcing theread-settlement.test.tscall-site update, and theGrowthUnavailable/settleGrowthReaddoor lines return tobridge/index.tsfor their readers here (run-control-dispatch,definition-directory). The seat-grammar widening (41e6487fb, substrate-7 #440) cherry-picked clean asa8810204f—panes/index.tsauto-merged, itseslint-disableblock for the once-unusedregistryparameter gone now that the parameter is read, theregisterWorkflowPanesimport andregisterWorkflowPanes(registry); // T-023p-1C-6 workflow-run workflow-buildersurviving on top, andregisterWorkflowSurfaces(surfaces); // T-023p-1C-6 workflowson the family board. A one-identifier form of the same widening drafted on this lane was withdrawn unshipped: it would have refused the multi-boardregisterSeatFamily(surfaces, panes, projectors)case the repos seat needs, and lacked the two negative controls (an empty list, a call expression) that keep the argument list a grammar over identifier names rather than arbitrary text.console-unitmoved 2437 → 2441 tests (the family seat now counting plus the three planted controls); eleven tiers, 334 files / 3351 tests. Noworkflows/production file changed across the fold, and the only non-test.tsxtouched wasframe/ConsoleRoot.tsx(two more boards passed toregisterConsoleFamiliesplus header prose — no JSX, no styles). The browser-terminal + substrate-7 merge (4914f65b8) was a criss-cross with two merge bases (8b0e6211and68ee0388), which is why some files conflicted while showing no diff against either base alone and why every resolution class was derived by comparing the merged blob against each side's blob rather than by reading hunks: 24 conflicts, 22 content and two add/add — develop's file forAGENTS.md,bridge/console-bridge.ts,frame/RouteSurface.tsx,budgets.json,electron-harness.ts,steady-state.test.ts, andtsconfig.console-electron-test.json; ordered unions forpackage.json,bridge/index.ts, thebridge/scenarios,families.ts, andpanes/index.tsseat boards,core/index.ts(both families' constants alphabetical,1C-6retired from three@consumedBytags),primitives/index.ts(nine hunks, then a uniform retirement of fifteen1C-6and seven1C-7tags),store/index.ts,tsconfig.test.json, and the Plan-023 manifest rows; this family's superset forframe/SessionsSurface.tsx(WireChoiceListthroughprimitives/index.jsinstead of the retired local file),persistence/index.ts(measureUtf8ByteLength),primitives/wire-figures.ts(the dated-instant formatter),tsconfig.console-browser-test.json, and the add/addaxe-run.ts; and for the add/addstylesheet-edges.test.ts, where both branches had authored a whole gate, a measured union — each instrument is red on the other family's tree and all four claims hold over the merged one — composed on develop's superseding TypeScript-parser instrument carrying this family's two model-backed claims and three negative controls;pnpm-lock.yamlnever hand-merged (develop's,pnpm install --no-frozen-lockfile,--frozen-lockfileclean; the merged blob equals neither side because regeneration is the rule's expected outcome).4c4da860danswered three things:cap-constant-homenamedPHASE_GRAPH_MAX_ZOOMandWORKFLOW_CANCEL_REASON_BYTE_CAPinworkflows/constants.ts, so all three constants moved tocore/constants.ts—PHASE_GRAPH_MIN_ZOOMwith them, since it is half of one range decision — exported through the core door, five readers re-pointed, the family's constants module and suite retired, and the header sentence that authorised a per-family module corrected, the same answer the ledger lane gave; four whole-tree parse gates (catch-stringification-chokepoint,no-browser-namespace,resize-observer-chokepoint,stylesheet-edges) crossed vitest's 5 s default once the tree grew by two families while asserting nothing new — verified solo (still red cold) and at 120 s (31/31 green, warm 1.8–2.6 s) and answered with the tree's own remedy, an explicitCONSOLE_PARSE_ALLOWANCE_MS = 30_000on thesource-walk-chokepointprecedent with each measurement recorded,resize-observer-chokepointnever having had a violation against this family; and a vacuity hole the stylesheet union itself opened — two claims moved ontoCONSOLE_STYLESHEET_TREEwhile the floor claim still guarded the Vite glob, so an empty model list would have left both silently green — closed with a cross-check between the two sheet lists, proven by perturbation (.slice(1)fails exactly one test). Gates on that tip were green across all eleven tiers; 80.tsx/.cssunderconsole/differed from the pre-merge tip with 77 byte-identical to develop, the three others beingframe/RouteSurface.test.tsx(develop's suite had reserved the rail's middle destination for this family by task id, so the reserved-slot claim is re-scoped onto a slot deliberately left unclaimed) and two of this family's own files re-pointed at the core door. The collaboration re-merge (a45fb97c7, 14 conflicts, merge-base9445133e8) was classed file by file by comparing the merged blob against both sides:fixture-growth-port.test.tsis develop's suite with this family's one refusal test re-inserted (a naive both-sides fold had opened the samedescribetwice);fixture-served-operations.tstakes develop's eight new ids into both halves, the initializer and theisolatedDeclarationstuple annotation;fixture-session-directory.ts,frame/frame.css, andprimitives/wire-figures.tsare develop's (its typed state read supersedes the untyped one);frame/SessionsSurface.tsx's retirement stands, this family having no production reader;growth-operations/index.test.ts,bridge/index.ts,core/index.ts(WHEN_CLAUSE_OVERLAP_MAX_CONTEXT_KEYSbesideWORKFLOW_CANCEL_REASON_BYTE_CAP),core/constants.ts(develop's fuller licensing header over this family's appended bounds block — 462 lines, the over-400 split being 1C-8's), andtsconfig.test.jsonare unions;primitives/index.tsandseats/owner-slot.tsare unions of removals; andpnpm-lock.yamlwas never hand-merged (develop's copy,pnpm install --no-frozen-lockfile,--frozen-lockfileexits 0). What the collaboration delta forced is3b5887ff4, five claims the merge left false, each named by a gate:DraftStore'smaximumDraftCountbecame required, so the family's test surface supplies it through the core door in the browser-terminal surface's exact form;OwnerSlotContractcame back tagged inseats/index.tswhile this family imports it in production, which knip under--treat-tag-hints-as-errorsrefuses, so the claim is struck with the reason beside the markers that legitimately stay;readUnknownMemberlost its last importer when develop's typed session directory replaced the reader built on it, so the door publishes the string read alone and the container read stays private; the fixture's script-only subset was stated too narrowly (develop's "writes have no honest empty answer"), and the real criterion — an answer about a named subject has no empty form, because an empty one asserts the subject exists — brings the three subject-addressed workflow reads in beside the four writes, with a read-side control landing beside develop's write control and the subtraction perturbation-proved (under a scenario scripting no workflow exactly one test fails); and the e2e reserved-slot probe develop had pointed at#/workflowswith a note that this family's landing would re-point it again did exactly that — of the seven declared surface slots onlytimelineis still unclaimed, so the probe now names it, addressed with the scenario's own session because a bare auxiliary route answers with the context picker rather than an absence (a 10,676 ms locator timeout became a 694 ms pass). Because the collaboration delta movedtokens/palette.tsandframe/frame.css, which this family's pinned references render against, the screenshot tier was owed rather than optional and ran clean. Against the pre-merge tip, 226.tsx/.cssunderconsole/differ and 222 are byte-identical to develop;SessionsSurface.tsxand its test are absent from both trees,builder/slots/slots.test.tsxis this family's own, andframe/ConsoleFrame.tsxdiffers by exactly this family's fivepaneRegistrycomposition-prop lines, whose production reader isworkflows/OpenPaneBody.tsx.Capture determinism (
b9d710aca,471e988c2— cherry-picked from #427'se0f519377/fa34d584b). The screenshot tier on themacos-15runner had been resolving the console's monospace stack two different ways across runs of the same tree: nothing self-hosts IBM Plex, so the DOM face was whichever remaining--meridian-font-monoentry the host had activated (a 0.600-advance face with an unslashed zero in one mode, Menlo at 0.602051 em with a slashed zero in the other), and the terminal grid was drawing in@xterm/xterm's owncourier-new, courier, monospacedefault becausexterm-adapter.tsnever passed the token it declared on the host — 17 px rows in one mode, 18 px in the other, a 24 px taller pane. Both modes had reached the committed corpus, so every regeneration only moved which references were wrong. The first commit pins--meridian-font-monotoMenlo, monospaceper test as an inline root property through the screenshot project'ssetupFiles(test/console/screenshot/capture-faces.ts+.setup.ts, four-case suite, a negative control that fails 3 of 4 without the wiring), chosen because both observed modes reach Menlo so the arms converge; the second addsterminal/emulator/xterm-typeface.ts, which tells the emulator the host's computed family onattach(five-case suite). The pair was verified on the runner itself before it reached this branch: aregeneraterun against the repos head carrying it (run 34043018643) wrote no PNG change. On this head after the cherry-pick: typecheck 0, lint 0, structure 0,xterm-typeface.test.ts5/5, and the console-architecture tier green. The regeneration on3b5887ff4(run 34040980116, committed asb47d71aec) had rewritten six references — the four browser-terminal ones and this family'sworkflow-parked-run-{light,dark}— in whichever mode that run sampled; after the cherry-pick the regeneration on471e988c2(run 34043139872, committed as5294b5a1b) rewrote exactly two,workflow-definitions-browser-{light,dark}, this family's one surface with monospace text, and left the four browser-terminal references untouched — they are byte-identical to the repos head's29c06285fcopies (git diff --statacross the heads is empty), which is the convergence the pin promises. The compare job on5294b5a1bis this family's runner-side verification.The repos re-merge (
56b11d23b: develope17c9b6d3— the #441 lefthook worktree lock on top of the repos family squash680260e8a). 302 files, 15 conflicts, every one hand-merged from both sides and none byte-identical to either (recomputed withgit merge-tree --write-tree --name-only). Seven ordered unions:families.ts(develop'sregisterRepos(sidebarSections, inlineCardSeats)besideregisterWorkflowSurfaces(surfaces)in seat order),panes/index.ts, the scenario registry (REPOS_SCENARIO+WORKFLOWS_SCENARIO),package.json(@xyflow/react@12.11.6beside develop'sdiff@9.0.0),core/constants.ts(both sides' constant groups with both header paragraphs — 651 lines, the split is 1C-8's),constants.test.ts(COUNTING_BOUNDSrows unioned, the phase-graph zoom-rangedescribeappended after develop's four), andfixture-growth-port.test.ts(both declarations and all three cases, develop's branch-context refusal case included). Three doors on the tag-set rule —core/index.tsandprimitives/index.ts@consumedBytags resolved as the intersection of the two sides' surviving lists, a tag deleted outright wherever either side deleted it because that side became a real importer (InstantReadingfor workflows,formatDurationfor repos) — andbridge/index.ts, where both sides had re-addedexport type { GrowthUnavailable }at different positions, which would have been a duplicate re-export: develop's placement besideGROWTH_PORT_REFUSAL_ORIGINkept, the door's paragraph rewritten to the merged truth (both symbols travel —repos/growth-call.tsfor a rejected call,workflows/pane/run/run-control-dispatch.ts:47,85naming the refusal arm — verified by grep). Two hand-merges applying each side's rule to the other's code:fixture-served-operations.tstakes develop's corrected gitflow sentence behind the family's served-operation block, andfixture-growth-port.tstakes develop's semantics on this branch's seam —fixture-scripted-answer.ts's fallback is now() => GrowthOutcome<…>keyed on the operation id, so develop's() => undefinedplus ascripted.value === undefinedre-read is unrepresentable and is said directly as() => growthUnavailable("gitflowBranchContextRead"), the post-check disappearing with its reason.stylesheet-edges.test.tskeeps the family's edge-count case under develop's broadenedisDoorModuletitle;CALL_DOOR_CONSUMER_COUNTre-derived lane 5 / develop 6 / merged 6 (workflows adds no call-door consumer, repos adds one). Plan-023 is an ordered union — develop's T-023p-1C-5 row verbatim beside this family's T-023p-1C-6 row (Files: console/workflows/, confirmed against the tree) and both growth-slate rows.pnpm-lock.yamlnever hand-merged: develop's copy, thenpnpm install --no-frozen-lockfile, +184 lines that are exactly the@xyflow/reactimporter entry and itsd3-*subtree. No develop-deleted line was kept and no path took this family's side verbatim. No fix commit was needed: typecheck 0, lint 0, structure 0 (969 modules / 3,326 dependencies), test 0 across eleven tiers — renderer 12 / 135, main-unit 14 / 207, console-unit 543 / 5,447, console-architecture 46 / 486, console-assets 1 / 12, console-browser 5 / 22, console-accessibility 7 / 48, console-bundle 9 / 68, smoke 3 / 42, console-e2e 1 / 5, console-endurance 8 / 40 — first time, no re-runs. Rendered surface: 92.tsx/.cssfiles underconsole/differ from5294b5a1band all 92 are byte-identical to develop and underconsole/repos/— develop's family arriving whole — so not one workflows.tsxor.csschanged and no shared rendered surface moved.Codex. Code-review credits are exhausted account-wide; the merge records one
codex-gateattempt against the PR head56b11d23b:rate_limited(2026-09-06, the gate's NON-ack terminal — no findings were produced, so none are folded).Gates (on
3b5887ff4; each its own invocation,TURBO_DAEMON=false)pnpm typecheck0pnpm lint0structure(knip + dependency-cruiser: 813 modules, 2,713 dependencies, no violations)0test(eleven tiers via turbo)0test:console-screenshot(owed: the collaboration delta movedtokens/palette.tsandframe/frame.css)0— 25 passed, 25 skipped off the pinned hostPer tier: renderer 135, main-unit 207, console-unit 4,480, console-architecture 483, console-assets 12, console-browser 18, console-accessibility 32, console-bundle 68, smoke 42, console-e2e 5, console-endurance 31. Every clean assertion has a negative control.
pnpm install --frozen-lockfileexits 0.This lane adds or changes 233 files, 204 of them under
console/— 103 production modules (71 added, 31 modified, 1 renamed) across 30 directories, of which the workflows family itself is 60 production modules across 12 directories; the largest file the family authors is 400 lines (pane/run/phase-graph/phase-graph.css), and the one source file over 400 lines this branch carries is the sharedcore/constants.tsat 462, whose split is T-023p-1C-8's.Refs: Spec-023, Plan-023
🤖 Generated with Claude Code
Co-Authored-By: Claude Fable 5.1 noreply@anthropic.com
Review notes — jaw-drop verdict (retroactive, 2026-09-06)
Verdict: NO (would not screen-record and post unprompted as merged). Reason: the definitions browser can enumerate and open nothing, the park attention fold is projected but never rendered, and a run in another window's pane never updates live.
Fix pass: the 2026-09-06 console coverage wave (Plan-023 Phase 1C follow-up PRs). Re-check: a second binary verdict is recorded on the wave PR that closes these rows; never an open loop.