Skip to content

monorepo: absorb m4ttstack/apps - #489

Merged
m4ttheweric merged 2349 commits into
mainfrom
monorepo-spec
Sep 26, 2026
Merged

m4ttheweric merged 2349 commits into
mainfrom
monorepo-spec

Conversation

@m4ttheweric

Copy link
Copy Markdown
Collaborator

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/)

  • Imports apps main via git-filter-repo with path renames and a three-rule commit-message scrub, then refreshes it after apps#169
  • One Bun workspace and lockfile; rt-client and settings-kit are private, consumed with workspace:*; root postinstall builds rt-client, settings-kit and tui-kit

Gates (turbo.json, scripts/turbo.sh, scripts/ci/test-scope.ts, checks.yml)

  • Turbo runs the apps' gates and rt's static gates as root tasks, plus //#turbo:test for the tests that glob the apps trees
  • Apps-only PRs skip the macOS unit shards; static runs turbo --affected; new deck-macos job; one purity gate

Release (rt-tray/deps.lock, scripts/build-apps.ts, release.yml, lib/release/*)

  • deps.lock gains source: "tree" rows for deck, board, console, chat, boxscore; build-apps.ts builds them into rt-tray/deps/arm64; a build-apps job with no signing key hands the bytes to release
  • Deletes bundle-apps, plan-matrix, update-lock, stage-identity and deck's standalone updater
  • Preflight classifies the gate by path; rt release app is qualify, notes, tag, verify with no bump, bundle or bot PR
  • rt release update-machine gains a checkout-sync leg and re-registers deck's apps at the shared checkout

Also

  • SERVE_ONLY_APPS still names gitq for the Stage C contract; the docs say gitq stays standalone until then
  • boxscore pinned to the workspace's jsdom 29 (vitest 4.1 crashes on jsdom 30)

Verification

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 check is fully green, bun run typecheck exits 0 and rt's unit suite passes apart from the six known machine-state flakes.

🤖 Generated with Claude Code

m4ttheweric and others added 30 commits September 15, 2026 09:24
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>
m4ttheweric and others added 28 commits September 26, 2026 01:18
… 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>
@coderabbitai

coderabbitai Bot commented Sep 26, 2026

Copy link
Copy Markdown

Walkthrough

Warning

Review details and warnings were omitted to fit the comment limit.

@m4ttheweric
m4ttheweric merged commit 27fed2f into main Sep 26, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant