monorepo: absorb m4ttstack/apps - #489
Merged
Merged
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cross-app tab routing Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eftovers Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…oute to the window Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* app-server: add shellHandoff middleware helper * app-server: wire shellHandoff into createApp; board calls it manually Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * app-server: final-review fixes (comment scrub, no-store stub) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * apps hide their launcher inside the mattstack shell Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * prettier pass on shell-handoff and launcher files Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…window Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…-client /gate (#73) * deps: rt-client 0.23.0 (gateAsk + gate-options) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * board: gate open verbs converge onto daemon gate:ask; presentation copy deleted Also add the consumedAt field GateRow fixtures need after the rt-client 0.23.0 bump (task 1), across gates-verbs/answer/cache/ingest/resume/sweep tests, reconciler-join.test.ts, and src/gates/cache.ts's applyOpened. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * gate-kit: consume rt-client's canonical answer/option helpers (C2) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * format: prettier the gate-ask and gate-kit edits Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * board: presentation-parity tests pin the wrapper CLI contract Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * board: parity tests drive the canonical presentation rule Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * board: launched wrapper panes carry their mr: gate subject (C9) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Revert gate-kit onto rt-client's canonical helpers pending a browser-safe entry The value import drags rt-client's single Node-only bundle into the board's client build, where it throws "process is not defined" and aborts the React render. Re-lands against the browser-safe subpath once that entry publishes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * gate-kit: consume rt-client's canonical answer/option helpers (C2) Imports the browser-safe `@mattstack/rt-client/gate` subpath. The main entry is a single Node-only bundle, and gate-kit reaches the board's client build, so a value import from "." puts `process` in the browser. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix findings from the whole-branch review Adds the missing consumedAt fixture default to four apps/console GateRow test builders, matching the fix already applied to apps/board, which restores apps/console's typecheck (and CI) to green. Also strips ticket citations from test names and comments, rewords a drifting line-number citation, and pins the paneId-set/no-sessionId parity case with a new test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…74) * board:review: form-rendering + CAS/doorbell points at gate-protocol * board:review: fix gate-protocol misattribution (recommended suffix + framing are local rules) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * board:respond: form-rendering + CAS/doorbell points at gate-protocol Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * board:review: restore the general never-fold-an-answer-in rule Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * board:respond: restore framing-placement and never-fold rules as local content Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * board:doctor: form-rendering + CAS/doorbell points at gate-protocol; degraded-mode override untouched * board: final-review fix wave -- respond Gate 2's missing answer command, consistent doorbell-read translation across all gate sites --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
…follow-up) (#75) * bump @mattstack/rt-client catalog pin to 0.25.0 * board+deck test preloads: scrub live daemon pointers via guardTestDaemonEnv An ambient RT_DAEMON_SOCK (herdr panes) wins over the repointed HOME inside rt-client's rtCommand, so both suites could dispatch at the LIVE rt daemon (board fixture rejections appear in the daemon log). The preloads now call guardTestDaemonEnv() before the HOME repoint, and a probe test per app asserts the scrub and the armed forbidden-socket list on every run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * prettier: format preloads and probes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* console server: expose rt.workspacePrefs.defaultEditor at /api/settings/default-editor Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * console: build open-in-editor hrefs from the default-editor preference useEditorHref fetches /api/settings/default-editor once and maps the editor id (or open -a command) to its URL scheme; unset, unknown, or a failed fetch falls back to vscode. All seven vscode://file link sites (wiring pencils, Open pack, include/fill/skill sources, config layer files, run failure excerpts) now go through it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * console: forward defaultEditor only when it is a string Registry validates rt.workspacePrefs as top-level object only, so a truthy non-string defaultEditor could reach editorScheme and throw on .trim(). Route now answers null for non-strings; editorScheme also guards its own input. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…dedupe (#77) * BOARD-33: GateForm falls back to raw context when no question sections it parseGateContext now returns its preamble instead of null when zero sections parse, so a plain-prose context still carries something a caller can render. GateForm mirrors DecisionQueueModal's own raw fallback for a context no question ends up sectioning. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * BOARD-34: gate-kit lint-bans the bare rt-client entry Adds a no-restricted-imports rule scoped to packages/gate-kit/src that bans @mattstack/rt-client's main entry, pointing at /gate instead, so a value import cannot silently re-break the browser bundle the way it did before. collapse.ts and react/index.ts move to /gate now (GateQuestion is already exported there). index.ts, summary.ts, and server/index.ts split their remaining GateOrigin/GateRow/GATE_BY_PANE imports onto a disabled line each, documented as waiting on RT-180 (/gate entry completeness). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * BOARD-35: dedupe strict-membership/CAS-loss/reading-answers-back blocks The three gate wrapper skills (review, respond, doctor) each carried a full local copy of gate-protocol's strict-membership, CAS-loss, and reading-answers-back mechanics. Collapse each to one pointer sentence at mattstack:gate-protocol's "Answers are option values" and "CAS and the doorbell" sections, delete-and-point style like BOARD-32's form branch, keeping only what is genuinely gate-specific (the note-form example and, where a multi question exists, the empty-array rule). The wait-recipe and closed-gate/degraded blocks stay local pending Matt's ruling (see herd ask). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * BOARD-35: extract shared wait-recipe/closed-gate/degraded rule for wrappers Per Matt's ruling on the design fork (gate d64b11df): the wait-recipe, closed-or-missing-gate handling, and the failing-wait-is-not-degradation rule were duplicated word for word across review/respond/doctor's own SKILL.md files. This content is board-CLI-specific (wraps <status-bin>, not the raw rt gate CLI), so it stays out of mattstack:gate-protocol and moves instead into a new board-local, non-invocable reference, apps/board/skills/gate-cli-recipes/SKILL.md. Each wrapper now points at it, keeping only its own gate-specific fallback logic (what a degraded review/respond/doctor gate actually falls back to) local. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * BOARD-33 follow-up: GateForm's raw-context fallback is opt-out The unconditional fallback duplicated content DecisionQueueModal already renders in its own "Decision context" ScrollPane for any unsectioned gate, breaking the modal's shipped layout contract (decision-queue-context-layout.test.ts: the body was scrolling because the form column grew to hold a second copy of the same raw text). Adds showContextFallback (default true), same pattern as showFocusAction: the modal passes false since it already covers this; a bare GateForm host still gets the fallback for free. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * board-cleanup: fix prettier formatting on GateForm and gate-kit files Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * board-cleanup: restore CAS-loss/reading-answers-back rule into gate-cli-recipes BOARD-35's dedup dropped two agent-facing rules that only lived in the per-wrapper CAS-loss bullets: the status-bin's own silent-success/ JSON-line answer contract, and the value-unwrap rule for a noted answer. Neither is covered by mattstack:gate-protocol's write-side note-form docs. Restored into the shared gate-cli-recipes doc and pointed to it from all three wrappers alongside the existing gate-protocol pointer. Also fixes a stale test comment: parseGateContext returns an empty section list for plain prose now, not null. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* BOARD-33: GateForm falls back to raw context when no question sections it parseGateContext now returns its preamble instead of null when zero sections parse, so a plain-prose context still carries something a caller can render. GateForm mirrors DecisionQueueModal's own raw fallback for a context no question ends up sectioning. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * BOARD-34: gate-kit lint-bans the bare rt-client entry Adds a no-restricted-imports rule scoped to packages/gate-kit/src that bans @mattstack/rt-client's main entry, pointing at /gate instead, so a value import cannot silently re-break the browser bundle the way it did before. collapse.ts and react/index.ts move to /gate now (GateQuestion is already exported there). index.ts, summary.ts, and server/index.ts split their remaining GateOrigin/GateRow/GATE_BY_PANE imports onto a disabled line each, documented as waiting on RT-180 (/gate entry completeness). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * BOARD-35: dedupe strict-membership/CAS-loss/reading-answers-back blocks The three gate wrapper skills (review, respond, doctor) each carried a full local copy of gate-protocol's strict-membership, CAS-loss, and reading-answers-back mechanics. Collapse each to one pointer sentence at mattstack:gate-protocol's "Answers are option values" and "CAS and the doorbell" sections, delete-and-point style like BOARD-32's form branch, keeping only what is genuinely gate-specific (the note-form example and, where a multi question exists, the empty-array rule). The wait-recipe and closed-gate/degraded blocks stay local pending Matt's ruling (see herd ask). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * BOARD-35: extract shared wait-recipe/closed-gate/degraded rule for wrappers Per Matt's ruling on the design fork (gate d64b11df): the wait-recipe, closed-or-missing-gate handling, and the failing-wait-is-not-degradation rule were duplicated word for word across review/respond/doctor's own SKILL.md files. This content is board-CLI-specific (wraps <status-bin>, not the raw rt gate CLI), so it stays out of mattstack:gate-protocol and moves instead into a new board-local, non-invocable reference, apps/board/skills/gate-cli-recipes/SKILL.md. Each wrapper now points at it, keeping only its own gate-specific fallback logic (what a degraded review/respond/doctor gate actually falls back to) local. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * BOARD-33 follow-up: GateForm's raw-context fallback is opt-out The unconditional fallback duplicated content DecisionQueueModal already renders in its own "Decision context" ScrollPane for any unsectioned gate, breaking the modal's shipped layout contract (decision-queue-context-layout.test.ts: the body was scrolling because the form column grew to hold a second copy of the same raw text). Adds showContextFallback (default true), same pattern as showFocusAction: the modal passes false since it already covers this; a bare GateForm host still gets the fallback for free. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * BOARD-36 item 1: gate-kit carries option description and question context Local GateOption/GateQuestion shapes (types.ts) add the two optional fields ahead of rt-client publishing them (RT-180): description on an object-form option, context on a question. gateItems now threads both into GateItemChoice.subtitle and GateItemDisplay.context. * BOARD-36 items 2-5: GateForm renders option description and question context An option's description renders as a muted line under its label, matching the pane's AskUserQuestion layout; recommended stays a label suffix. A question's own context renders with its card, above its choices, separate from the gate-level context block. Gates without the new fields render exactly as before -- no change to the blob/section/ thread parsing or BOARD-33's raw fallback. DOM coverage: options with and without descriptions, a question with and without context, and a mixed gate. * board-36: fix prettier formatting Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Every MR the doctor had ever touched was still wearing "diagnosed" a day later, in a tone that outranks the row's standing state, so nine rows in a row said what the doctor did yesterday instead of what the MR needs now. A finished run is a note, not an achievement: the line is quiet rather than go, it carries the dismiss verb the stuck line already had, and it stops being a candidate once the run is older than two hours. Fresh enough to read what the doctor did on the next glance at the board; stale enough to get out of the way after that. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Picks up the agent.provider/agent.claude.*/agent.codex.* settings keys the console Agent Defaults page reads (rt#291), plus RT-173/ RT-124's gate re-nudge delivery fixes already on that version.
… gate option-description contract BOARD-36 renders) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…erences catalog:) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
) * console: add agent model catalog route, prefix filter on settings defs GET /api/settings/defs now accepts ?prefix= to filter keys (empty prefix keeps returning everything). New GET /api/agent/models serves a curated static list for claude and shells out to `codex debug models` for codex, degrading to an empty list rather than a thrown error if the binary is missing or its output shape changes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * console: add Agent Defaults settings page New /settings route with a rail entry: provider (claude/codex), model, effort, account (claude only), extra args, and a yolo toggle, writable to the user or machine scope. Consumes Task 8's settings/defs prefix filter and agent/models catalog route. Per-key current values come from a page-local useCurrentValue hook (a graceful variant of useExplainKey that treats an unknown key as "unset" instead of throwing) rather than the brief's illustrative Def.effective.value, since /api/settings/defs only carries schema metadata, never resolved values. A yellow banner surfaces when the registry doesn't have the provider-scoped agent.* keys yet, which is the real state until rt-client republishes with them -- verified live against the current (old) registry: the page renders, the banner shows, and a write attempt 404s without crashing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * console: polish Agent Defaults layout per visual review - pack fields into a dense 2-column grid instead of one full-width row each, matching board's settings-panel density - show each field's currently-winning scope as a badge beside its label (default/unset/pending/user/machine), mirroring board's per-setting scope display - wrap the form in a centered, bordered Paper card on the console's grid background instead of floating unbounded fields directly on it - drop the page-level heading duplicate ("Agent defaults" was shown both in the top strip and the card); top strip now reads "Settings" to match the rail entry, card keeps the specific heading * console: fix dark-mode contrast on the Agent Defaults card bg.level2 (the default card surface) reads too close to this app's dark-mode input background -- card and fields were barely distinguishable. bg.level4 is deliberately lighter in dark schemes (vs. darker in light), so it stays visually distinct from its own inputs in both modes; confirmed in the browser, both schemes. * docs: record two UI lessons from building the Agent Defaults page - bg.level2 can look identical to a Mantine input's own background in dark mode even when light mode is fine; bg.level4 stays distinct in both schemes for a card whose job is to hold form inputs - a custom label/header over a kit input needs its own aria-label, or dropping the input's built-in `label` prop silently breaks its accessible name for both screen readers and getByLabelText queries * console: replace the global "Write to" selector with per-field scope A single page-wide scope toggle governing every field's writes is easy to leave pointed at "machine" from a previous visit and forget -- machine outranks user for every one of these keys, so an unnoticed stray write silently creates a sticky override. Each field now gets its own user/machine SegmentedControl, seeded from wherever that field's value currently resolves from, matching board's ConfigModal/LayerRow pattern of scoping the choice to the write itself rather than a shared control. * console: add a delayed tooltip explaining each field's scope control Grounded in the real store semantics (rt:settings): user settings live in the home repo, machine settings stay on this machine only. 500ms open delay so it doesn't fire on a passing hover. * console: fix review findings on Agent Defaults page Format: run prettier on the four files the branch touched (CI's format:check gate was failing). Per-field scope now resets on a provider switch instead of going stale: Effort/Extra args/Yolo/Model are each their own component owning current-value + scope + mutation, mounted with key={settingKey} so switching providers remounts (and resets) the whole field, not just its input. Write failures now surface via notifications.error instead of leaving an uncontrolled field silently unsaved. Model switches from a locked Select to an Autocomplete, per the spec's free-text + suggestions requirement -- a locked select made agent.codex.model unsettable whenever the codex catalog shell-out returns an empty list. codex debug models gets a 5s timeout and an unconditional proc.kill() so a hung binary can't hold the request (and the child process) open forever. Also: dedupe AgentModelOption onto the server type, give useSettingsPrefix the same staleTime: Infinity as its sibling query, and add a regression test for the scope-reset fix. * console: skip blur writes when a settings field wasn't actually edited Tabbing through Effort/Extra args/Account/Model without changing them was still posting to /api/settings/set, materializing the current value into whichever scope that row's control happened to be set to. Compares against the value the field mounted with and skips the mutation when they match. CodeRabbit finding on PR #79. --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* test: assert sessionId in gate:wait payload (BOARD-37, RED) gateWait's payload never carries a session id, so mr: gates cannot stamp consumedAt for a gate wait; the daemon side already accepts an optional sessionId (rt-client 0.27.0). This test asserts the payload carries it when passed and omits it when not; it fails to typecheck until gateWait grows the extra parameter. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix: thread sessionId into gate wait payload (BOARD-37, GREEN) gate wait's status-bin call never passed a session id, so the rt daemon could not stamp consumedAt when the wrapper read its answer, letting mr: gates re-nudge up to five times against a pane that had already moved on. Mirrors gate open's existing extras.sessionId pattern: read CLAUDE_CODE_SESSION_ID in bin/gate.ts and thread it through gateWait's payload, omitted when unset. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
syncIndex fetched only messages after lastTs and appended them, on the assumption that a message's text never changes. A Slack edit keeps the message ts, so a review request amended to add a stacked child MR's link never entered the index and that child resolved "notfound" forever. Later syncs now re-read the last 14 days and merge by ts (freshest copy wins), falling back to lastTs when the index is staler than the window. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* board skills: gate questions carry their own context (BOARD-39) The review and respond wrappers now put per-question material in each question's context field (thread quote + draft on respond-plan questions, finding titles on the review tiers question, finalized replies on the respond-post replies question with per-option description lines) and narrow gate-level --context to shared background, with the shared 8192 budget rule stated at each site. Doctor's single-question gate is deliberately unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * respond: cap gate questions at the form's 4-option limit One question over 4 options sends the whole gate to the wait queue (live specimen: a 6-thread replies question). Gate 2 now chunks replies into replies-1..N questions of up to 4 options, and the answer reads as the union of every replies-* answer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…es back A finished respond lane's posted line only offered read, and while it stood it suppressed the author line that carries the respond verb, so a row with fresh reviewer pushback looked terminal. When awaiting threads flip back above zero, the line turns warn with a restart-respond verb. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
statusBucket only read the approval rule's isApproved, so an MR whose every assigned reviewer approved still showed comments resolved while a project rule wanted more approvals. The roster's verdict now counts as approved; the rule shortfall stays on the awaiting-approvals blocker. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Several dead panes can share one MR subject after a relaunch; last-write- wins on the subject key could attach the stale executor, whose sessionId matched no lane, so the row never read interrupted and kept spinning on the dead run's status. Subject candidates are now all kept and the one matching the active lane's session wins, falling back to the most recently gone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… no pins
apps/board, apps/deck, apps/chat, apps/console and apps/boxscore now ship
as source: "tree" rows built in-tree by scripts/build-apps.ts, so the
release gate can no longer classify a diff by a deps.lock pin move.
checkGate now reads the tag..ref file diff directly: a diff confined to
the served apps' own directories, RELEASE_NOTES.md and website/ keeps
the fast path, anything else forces the full gate.
classifyRows drops its apps bucket (no row carries a repo/subdir pin for
an apps-monorepo row any more) and returns only { standalone, tools }.
checkAppPins and checkRtClient are removed along with the deps.lock-pin
rows they produced, since neither has an upstream to check any more.
lib/release/release-app.ts's apps-monorepo pin-only release path
(eligibleApps, qualifyRow, heldApps, noteSections) has nothing left to
select now that apps carry no per-app pin; its functions are stubbed to
reflect that pending a full rewrite of that module onto the new
path-based gate. Tests exercising that pin-only flow in
lib/release/__tests__/release-app-run.test.ts fail as a result and are
left for that rewrite.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
release.yml now has build-apps and release, not one job, so the job-list and step-order pins were red since the build-apps split landed. Repoints them at the new truth and adds coverage for the split's own guarantees: release needs build-apps, build-apps is read-only and never imports a certificate, and its checkout carries persist-credentials: false. Also drops unnamed steps from the step-order helper: a bare run: step (the tree rows' own untar, right after "Land the tree rows") has neither a name nor a uses, and indexing past it threw before this fix. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…bot PR lib/release/release-app.ts drops the apps-monorepo bump/bundle/deps.lock bot-PR pipeline (apps now build from a tree row in this same repo) and becomes: qualify the fast-path diff since the last tag, generate and approve RELEASE_NOTES.md, commit it locally and push, tag, verify the publish. ReleaseAppSeams sheds every gh-workflow/bot-PR/apps-repo seam; commands/release.ts's releaseAppOptions now offers the served tree rows (board, boxscore, chat, console) plus gitq, filtered through keepsFastPath. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
e2e/tests/release-app.test.ts drove the deleted bump/bundle/deps.lock bot-PR flow through a fake gh shim and a separate apps clone. Rewrites it against the new module: a fresh local origin per scenario (apps live under apps/<name>/ in this one repo now, so no apps clone or gh shim is needed for these paths), covering a fast-path dry-run plan one patch tag up, a diff that leaves the fast path naming the offending file, and a headless run stopping for notes approval with nothing written to the origin or the checkout. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ePhase commitNotes goes back to the GitHub-API tree/commit/PATCH-refs sequence built on the origin/main sha qualify already read, never touching the operator's working tree or local HEAD, so a feature branch, an untracked file, or a stale local main cannot wedge or misdirect a release; a rejected ref update maps to a StepFailure naming the resume command. resolvePhase now detects an already-released newest tag from the tag itself (peeled to its commit) rather than from a next tag that can never exist yet, so a rerun after an unverified or failed publish re-verifies that tag instead of trying to stack a new one on top of it. inStep wraps every stage so a plain error (a failed fetch, ls-remote, or push) still comes back as a failed step with a resume command and a full --json envelope, instead of escaping uncaught. Also: releaseAppOptions parses deps.lock with parseDepsLock so a corrupt lock fails loudly; the module header describes the four current steps; a dry run marks already-committed notes done rather than planned; the verify step logs its 25-50 minute notice again. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…y status qualify now runs a read-only verify snapshot of the newest tag before deciding anything else, whether or not it is about to cut a new tag: a clean newest tag that already covers origin/main means nothing moved to release, so qualify declines instead of silently re-verifying an app that was never part of it; an unverified one that already covers origin/main is re-checked, worded from the real verify rows instead of a hard-coded string; and a new served-app diff on top of an unverified newest tag now refuses at qualify with the verify resume, rather than gating the diff and cutting a second tag on top of the first. A dry run in the released phase no longer runs the real, potentially long-waiting verify: it plans a re-verify and reports the notes at the tagged commit rather than origin/main's, which can have drifted with notes-only edits since. seams.confirm is wrapped the same way every other stage is, so a throwing prompt is a failed step, not a crash. commands/release.ts removes the release-app scratch directory at the end of the command the way update-machine already does, in a try/finally around the run. The e2e test gained a `gh` shim answering the newest tag's read-only verify snapshot, which qualify now always takes before it looks at the diff. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs: console JSON editors and fix flow spec Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: spec 2 review round 1 fixes, per-repo view, page audit findings Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: spec 2 follows spec 3's versioned store names, no floor rule Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: spec 2 handles a diverged store name in the fix flow Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: spec 2 diverged fix flow can remove the older store name Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: spec 2 removes an older store name through settings-kit /prune Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * docs: plan 2, console JSON editors, per-repo view and fix flow (draft for review) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: plan 2 review round 1 fixes: fixtures, deck seeding, board test swaps, matchers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: plan 2 review round 2 note on the board test comment Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * apps: rt-client 0.32.0, settings-kit 0.4.0; console and board read composite shapes from the schema Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: drop rollout narration from the EDITOR_KINDS comment Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * apps: pin console, board, deck and boxscore settings writers against validateWrite Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * boxscore: composite rows take their editor from the schema Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * kit: CodeMirror completes and lints JSON against a schema Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * kit: fix JSON completion range, stabilize schema/check props Completion now matches from the opening quote and consumes the closing quote on pick, instead of filtering an empty auto-closed pair against both quote characters (which no label ever matched). A fresh jsonSchema/jsonCheck identity no longer reconfigures the completion and lint extensions on every render; both are read through refs so a real change still takes effect on the next completion or lint. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: repo-aware settings hooks, layer rungs, writes carry repo Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: name repo rungs distinctly from global layers via layerLabel Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: repo picker, repo reach on rows, repos that set a key in the explain modal Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: JSON values read in full on rows and explain layers Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: formShape and issues helpers for form-mode composite editors Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: item cards for lists of objects, over a checked local draft Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: fix optional-field unmount, Select-Escape draft loss, key reorder Clearing a set optional field's text deleted it from the draft, which FieldGrid's visibleFields then hid mid-edit since it was never added to `shown`; seed `shown` from the entry's own set optional keys at mount so only the remove control hides a row. An open Select/Autocomplete's own Escape handler closes its dropdown without stopping the event, so it reached DraftEditor's handler and discarded the whole draft; skip that Escape when the target still reads aria-expanded="true" (stale until the next render). Clearing then retyping a field also moved it to the end of the written object since delete+reassign always appends; rebuild the entry from a stable per-field key order instead, seeded at mount and extended only the first time a name is newly set. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: item cards follow the approved field grid design Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: fix faded disabled move arrows, footer fallback for unexplained issues Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: let item card footer issue text shrink so Cancel/Save never overflow Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: named sections for maps of objects, nested properties kept read-only Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: fix round 1 for named sections (crash, overflow, contrast, touched state) Fixes a prototype-key crash (an entry named constructor/toString made NamedSections' touched lookup resolve an inherited Object.prototype function instead of undefined, since it was a Record; now a Map), a long name error pushing Cancel/Save out of the footer, an off Switch's invisible track in dark scheme, a stale touched Set surviving entry removal, and a duplicate/empty name no longer marking the input's own error border. Also fixes a genuine horizontal overflow found while redoing the rt.roles live check with the correct team repo picked: an unbroken JSON string in a read-only nested-property row has an unbounded min-content width that propagates through Mantine's ScrollArea (its content wrapper is min-width: min-content), widening the whole settings panel instead of ellipsizing in place; fixed with CSS containment on that one box. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * apps: rt-client 0.33.0 and settings-kit 0.5.0 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: JSON editor for every JSON row and explain layer, form and JSON share one draft Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: fix round 1 for JSON editor (invalid-row guard, segmented mode bar, growing height) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * kit: CodeMirror syntax colours follow the colour scheme basicSetup's fallback defaultHighlightStyle painted JSON strings the same red family as error text in every scheme, left numbers near invisible in dark, and the lint underline/gutter marker used a raw-hex data URI that read as almost invisible on a dark surface. The dark active line and selection also used CodeMirror's own fixed heavy teal wash instead of a token. Installs a kit HighlightStyle (packages/ui/src/lazy/codemirror/ highlightStyle.ts) built from --tk-text-* role tokens, bundled into the theme compartment so it reconfigures alongside the scheme-aware chrome; CodeMirror gives it full precedence over the fallback style. The lint underline/marker now draw from the bad/warn role tokens as plain CSS instead of a raw-hex SVG data URI, and the active line/selection use a color-mix wash over --tk-wash. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * kit: fix zero-width lint points and anchor parse errors at the real break A zero-width or all-whitespace diagnostic range renders as a cm-lintPoint widget instead of a cm-lintRange mark, still using CodeMirror's hardcoded colours; the kit's lint underline/marker CSS only covered the mark case. Styles .cm-lintPoint-error/-warning from the same --tk-text-<hue>-vivid tokens. Also anchors a JSON parse error at the first lezer error node in the tree instead of always 0..1, falling back to 0..1 only when the tree has no error node, a parse error now underlines where the JSON actually breaks, not always the document start. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: Needs fixing chip, issue lines with Fix into the failing layer and repo Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: fix round 1 for Needs fixing (editable gate, touched fields, one draft-issue testid) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: read-only ready-approval row with Revoke, footer note for unregistered keys Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: gate ExplainModal's per-layer editor on the ready-approval key Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: diverged older store names show both values, can be kept or pruned Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: fix round 1 for diverged names (real-data carry-over, secret gating, form-fit guard, overflow) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: fix round 2, diverged columns re-enable shrink and JsonBlock stops reporting its own width Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: fix round 3, UnregisteredNote's nowrap file path stops setting the page's min-content Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: form-mode Use the older value remounts cards, keeps extra keys DraftEditor bumps a formGeneration counter on replaceWith, keyed onto ItemCards/NamedSections so card ids, key order and per-field local state (the NumberInput raw text especially) reset from the new value instead of staying seeded from the value at mount. FieldGrid.set backstops by writing any entry key missing from its own order.current too. Also renames ItemCards.test.tsx's stale "surfaces as a footer fallback" title to match what it checks now that a stored value's issues seed touched at mount, and adds coverage for editing a number, a switch and an enum field on the same card. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: scalar clear follows the write target, not a bare store scope ScalarControl takes writeScope and clears only when the effective value's own scope matches it, the same rule LeavesBody already uses for a leaf field. Fixes a repo-scoped scalar inherited from a global layer emptying into a no-op unset of the picked repo's own (empty) section, and fixes a repo-rung scalar in the explain modal never unsetting at all. RowMenu labels a global layer's Remove "(all repos)" when a repo-scoped key is being edited with a repo picked, matching RepoReach's own "for acme/app" framing elsewhere on the row. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: skip a /set repo patch that does not match the hook's own repo A repo-scoped def's effective value from a write response is resolved for the repo the write body carried. Patching it into defs unconditionally showed a repo-specific value on a hook reading a different repo (or all of them); the reread that already follows re-resolves it correctly, so the patch now only applies when the repos agree. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * console: a failed deep-key explain read shows the error, not a permanent skeleton DraftBody's loading guard covered only the still-loading case; a failed read left explained.rows empty forever, so the Skeleton never resolved. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * apps: tokens waiver for the kit CodeMirror, boxscore number-only leaves, scheme reset in a kit test Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…erify deck against the tree Adds a checkout-sync leg (main-only pull plus bun install --frozen-lockfile) between dev-bundle and daemon, so the dev daemon and deck's from-source apps run from one shared ~/Documents/GitHub/repo-tools checkout instead of a separate mattstack-apps checkout. served-suite now re-registers any deck app whose registry entry still points at the old checkout instead of pulling a branch itself. dev-bundle builds the workspace (bun install, then scripts/build-apps.ts) before rt-tray/build.sh. verify compares deck --version against apps/deck/package.json at the release tag via deckVersionAtTag, replacing the deps.lock pin comparison. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Rewrites skills/rt-release/SKILL.md's release-flow sections for the build-apps era: apps ship at HEAD via release.yml's build-apps job with nothing to pin or bump, rt release app is a path-gated notes/tag/verify shortcut, and update-machine's legs match the shared repo-tools checkout. gitq stays its own repo with a standalone deps.lock pin, same as fast-browser; the skill, AGENTS.md and release-and-distribution.md all say so explicitly rather than folding it into the tree-built apps. Adds AGENTS.md's Monorepo layout section, corrects two stale footguns (rt-client publishing, dist freshness) for the now-private workspace packages, and replaces release-and-distribution.md's bundle-apps.yml section and docs/apps/README.md's identity/publishing notes with the in-tree build-apps mechanism. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> # Conflicts: # apps/board/src/client/__tests__/config-shapes.test.ts # apps/console/src/app/settings/CompositeControls.test.tsx # apps/console/src/app/settings/SettingRow.test.tsx # apps/console/src/app/settings/SettingsPage.test.tsx # apps/console/src/app/settings/view.test.ts # package.json
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…-tools AGENTS.md: gitq resolves @mattstack/rt-client from npm (its package.json pins ^0.14.0), not from the workspace; corrects both rt-client footguns. Adds bun install --frozen-lockfile between fetch-deps and build-apps in the tray rebuild bullet, names the checkout-sync leg by its real id, and fixes the chat viewer's location to apps/chat. skills/rt-release/SKILL.md: drops apps/gitq from the served-app directory list, states plainly that gitq releases take the full process through 2c, and lists gitq alongside fast-browser wherever the full gate applies (Step 8, Step 12's halt sentence gains the checkout-sync leg). skills/rt-build-dev-app/SKILL.md: points the served-apps and deck rows at the repo-tools checkout instead of the retired mattstack-apps checkout. docs/release-and-distribution.md: restores an Adding a served app list covering the version/exit-0 smoke test, embedded assets, the serve row rules in parseDepsLock, and identity/skills staging into <name>-identity and <name>-skills, all reworded for build-apps; fixes the build-apps job description (bun install then build-apps, which runs the packages build itself) and the skills-channel bullet (a bundled binary, not a tarball). docs/apps/bundle-cutover-brief.md: rewrites the recipe-path sentence so it states the current mechanism directly instead of contradicting itself in an appended parenthetical. lib/command-tree-def.ts: rt release app's description matches what it actually does (qualify the path gate, write the notes, tag and verify); regenerates the command reference. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
apps/boxscore pinned jsdom ^30.0.1 while the root, console, chat and gate-kit all pin ^29.1.1. Vitest 4.1.11's jsdom environment setup crashes against jsdom 30.1.1 with a 'not a valid instance of EventTarget' error from catchWindowErrors, taking down all 13 jsdom-project test files. Aligning boxscore to ^29.1.1 collapses the workspace to one jsdom copy and fixes the crash (45 files, 331 tests green). Also updates bundle-ready.test.ts's build recipe assertion: the manifest already dropped the 'bun install --frozen-lockfile &&' prefix since the workspace installs once at the root, so the test was pinning a stale string. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A squash flattens the imported apps history into one commit and loses blame and --follow. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
commitFiles lands the RELEASE_NOTES.md commit on GitHub through the API, but nothing pulled the new object into the local repo before tagStep ran git tag against its sha, so the first real run failed at the tag step. commitNotes now refreshes main right after commitFiles succeeds. Also wraps the notes-step inStep calls in runReleaseApp in try/catch so a git failure there returns the --json envelope instead of throwing a bare StepFailure, and adds --no-renames to the two git diff --name-only calls that gate the served-app fast path, so a file moved between apps/ dirs is never misread as untouched. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The release job's bun install now runs with --ignore-scripts, followed by bun run postinstall (rt's own packages only); nothing later in that job needs a third-party lifecycle script to run. build-apps keeps the plain install since it needs the apps' scripts. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Board's dev server and deck import @mattstack/tui-kit from its dist/, which a plain bun install on the shared checkout would otherwise never produce. Confirmed bun install rebuilds packages/tui-kit/dist/src/index.js. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
fetch-deps.sh no longer covers the tree rows (board, boxscore, chat, console, gitq), so a worktree's stale rt-tray/deps got bundled silently, or build.sh dev refused for lacking them. The scratch copy now runs bun install --frozen-lockfile then scripts/build-apps.ts --arch arm64, matching update-machine's dev-bundle leg, after fetch-deps and before build.sh dev. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…n repo apps/AGENTS.md's reading order, CI shape and Publishing sections named the old m4ttstack/apps repo's docs paths, CI file and registry-based rt-client/settings-kit; point them at docs/apps/*, the rt monorepo's checks.yml (static + deck-macos + turbo:test), and workspace:* linking. Its rt identity note now says plainly it is about the retired m4ttstack/apps remote, not this directory. Every apps/*/AGENTS.md and packages/ui/src/lazy/codemirror/highlightStyle.ts pointed at docs/ui-authoring.md "at the repo root"; it lives at docs/apps/ui-authoring.md now. docs/apps/bundle-cutover-brief.md gets a historical marker at the top. docs/settings-architecture.md's add-a-key checklist and skills/rt-settings/SKILL.md both described rt-client delivery as a version-bump-and-publish story; board, console and deck now link it in-tree, so the next bun install or turbo build (deck: the next release) delivers a new key. Only gitq, still standalone, needs the publish step. docs/release-and-distribution.md: build-apps only checks --version's exit status, not its printed value (update-machine compares that separately); the served-app port uniqueness check is against other served rows, not every deps.lock row. Root AGENTS.md drops the "(Stage C)" plan-stage label from the rt-client footgun note. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ckages test-scope.ts, the deps-lock-serve-parity fixtures and update-machine's checkout-sync test carried comments citing the bug a change fixed or a prior test's own review note; keep the constraint, drop the narration. rt-client and settings-kit are private, so their publishConfig (dead weight, never read) goes. update-machine's header leg list gains checkout-sync. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nt.config.mjs None of these are TypeScript sources rt's typecheck should walk. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comments and test names across rt-tray, rt-client, scripts/lib and the apps still said bundle-apps (now build-apps), pointed at the m4ttstack/apps checkout by name, described the mattstack bundle gate comparing deck's --version against a deps.lock row it never reads, or claimed rt-client publishes to consumers. Reword each to the in-tree mechanism: build-apps.ts's name, in-tree parity anchors with no repo prefix, update-machine's served-suite leg comparing --version against apps/deck/package.json at the tag, and workspace:* linking. board's config-shapes test drops the retired board.rtRepos entry and its comment: the row is unregistered in-tree, not pending a publish. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Both jobs ran an unpinned setup-bun and a plain bun install; pin to 1.4.2 (matching every other workflow) and add --frozen-lockfile so a lockfile drift fails loudly instead of silently resolving something new. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
scripts/bundle-ci/ only ever held this one file and its test after the bot-PR half of the bundle pipeline was deleted; scripts/lib is where build-apps.ts's other helpers already live. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
release-app-run.test.ts: a test that fails a git log call inside the notes step and asserts the returned envelope always carries status, steps and resume; the World doc comment now names only the command git tag -a gates, not rev-parse too. deps-lock-file.test.ts: build-apps never writes deps.lock, so flipping a row from pending to bundled is a hand edit, not something build-apps does. apps/deck/src/cli/commands.ts: the --version comparison against apps/deck/package.json lives in update-machine's verify leg, not served-suite. dev-app-stage.ts and rt-build-dev-app/SKILL.md: state the fetch-deps constraint in the present tense, with no plan-stage label. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
apps/AGENTS.md: the UI-authoring pointer and the two mentions of a served-app path for a not-yet-folded-in app now point at real sections (docs/apps/ui-authoring.md; docs/release-and-distribution.md's "Adding a served app" list, which never had a "Bundle-transition tarballs" section to point at). The rt identity note states the current rule directly instead of citing a plan step. apps/chat/AGENTS.md and apps/console/AGENTS.md: the kit contract lives in apps/AGENTS.md, not "AGENTS.md at this repo's root". docs/superpowers/plans/2026-09-25-mattstack-monorepo.md: Tasks 17 and 21's merge-method reasons name glance's and gitq's own imported history, not "the apps history". docs/settings-architecture.md and skills/rt-settings/SKILL.md: a workspace consumer links rt-client and resolves dist/ directly; it never holds a copy the way gitq's published npm install does. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
WalkthroughWarning Review details and warnings were omitted to fit the comment limit. |
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.
Folds the m4ttstack/apps repo into rt with its full main history so rt-client and settings-kit stop being npm publishes and the bundled apps build from the tagged commit. Stage A of
docs/superpowers/specs/2026-09-25-mattstack-monorepo-design.md; glance and gitq follow in later PRs.Merge with a merge commit, never squash or rebase: a squash flattens the 2300 imported commits and loses blame.
What changed
Import (
apps/*,packages/{gate-kit,server,tokens,tokyo,tui-kit,ui},docs/apps/)workspace:*; rootpostinstallbuilds rt-client, settings-kit and tui-kitGates (
turbo.json,scripts/turbo.sh,scripts/ci/test-scope.ts,checks.yml)//#turbo:testfor the tests that glob the apps treesstaticruns turbo--affected; newdeck-macosjob; one purity gateRelease (
rt-tray/deps.lock,scripts/build-apps.ts,release.yml,lib/release/*)source: "tree"rows for deck, board, console, chat, boxscore;build-apps.tsbuilds them intort-tray/deps/arm64; abuild-appsjob with no signing key hands the bytes toreleasert release appis qualify, notes, tag, verify with no bump, bundle or bot PRrt release update-machinegains a checkout-sync leg and re-registers deck's apps at the shared checkoutAlso
SERVE_ONLY_APPSstill names gitq for the Stage C contract; the docs say gitq stays standalone until thenVerification
Release rehearsal on this branch at the final HEAD: https://github.com/m4ttstack/rt/actions/runs/36235585229 (an earlier one at 6be9e62 was green end to end, signed and notarized, publish skipped). Locally
scripts/turbo.sh checkis fully green,bun run typecheckexits 0 and rt's unit suite passes apart from the six known machine-state flakes.🤖 Generated with Claude Code