Skip to content

RT keys wave: every rt legacy config lives in the stores; the legacy rung dies - #7

Merged
m4ttheweric merged 12 commits into
mainfrom
goodwinmattheweric/rt-50-keys-wave
Aug 21, 2026
Merged

RT keys wave: every rt legacy config lives in the stores; the legacy rung dies#7
m4ttheweric merged 12 commits into
mainfrom
goodwinmattheweric/rt-50-keys-wave

Conversation

@m4ttheweric

Copy link
Copy Markdown
Collaborator

The rt keys wave (spec: docs/superpowers/specs/2026-08-20-suite-settings-migration.md): notifications/cron/repoTracking/runaway/workspacePrefs/sync/variations/presets/dopplerTemplate migrated to their ruled scopes with fail-open loaders; team tracking intent (mattstack.tracking) merges under machine grants with durable off-markers and a machine-only forge-token gate; the llm chain, repo-config, the resolver's legacy rung, and siblingCommand are deleted; seven test fixtures converted to store seeding; docs swept + reference regenerated.

Gates: tsc 0; lib/commands/packages 1595+ green; full e2e 74/0 on a fresh compiled binary; check-docs clean. Whole-branch review (with quantified daemon read-amplification analysis: 3-12ms/min, accepted) + fix wave applied.

🤖 Generated with Claude Code

m4tthewericand others added 12 commits August 20, 2026 22:55
Ports rt.notifications, rt.cron, rt.repoTracking, rt.runaway, and
rt.workspacePrefs off their legacy ~/.mattstack/rt/*.json[c] files and onto
the settings resolver (getSetting/setSetting), flipping all five registry
rows to migrated:true with legacyFile/siblingCommand dropped. No fallback
reads remain.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review fix wave for the five global-singleton loaders/writers: getSetting
calls now live inside each loader's existing try/catch (an unexpandable
${...} variable degrades exactly like today's missing/corrupt-file case
instead of crashing daemon boot), and loadRepoTracking warns loudly and
auto-unwraps a versioned {version, repos} envelope instead of silently
dropping every grant. Plus a stale local rename and a registry test
invariant.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…te is a key
Ports rt.sync, rt.variations, rt.presets, rt.dopplerTemplate off the legacy
repos/<repo>/ files onto the settings resolver, and flips rt.branchNaming's
registry row (rt has no reader for it). rt.presets moves from a directory of
per-preset files to one { "<name>": {entries} } object; rt.dopplerTemplate's
registry type corrects from object to array (merge: replace) to match its
actual shape. saveSyncConfig, saveTemplate, and captureFromActualConfig are
deleted (zero production callers).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…m cleanup
savePreset/saveVariation now return a SaveResult instead of silently
no-op'ing or swallowing setSetting refusals; rt run prints a checkmark only
on an actual write, otherwise one honest line (no repo identity, or the
refusal's own message for a missing team store). Adds lib/__tests__/sync-
config.test.ts (previously untested): defaults, wrong-shape degrade, null-
identity degrade, unexpandable-variable degrade, and a team.repo happy path.
Drops classifyDirtyAsync's dead repoName param everywhere (including a
worktree.ts call site missed in the prior pass) and adds a doppler-sync test
seeding at team.repo scope, the scope the cutover actually writes. Fixes
three stale comments naming files these keys no longer read from disk.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
reportSave (commands/run.ts) — the only place that renders "✓ saved" vs
the failure lines for a preset/variation save — had no direct coverage;
savePreset/saveVariation's SaveResult was only verified at the lib layer.
Exports a __test__ seam (same convention as lib/notifier.ts,
lib/repo-index.ts, commands/code.ts) and adds
commands/__tests__/run-report-save.test.ts, driving reportSave directly
with a process.stderr.write spy across all three outcomes: ok:true, a
null-identity refusal, and a write-failed refusal surfacing the real
setSetting message verbatim.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-prime
Splits loadRepoTracking into a machine-only loadMachineRepoTracking (the
only safe base for read-modify-write and for the forge-token grant gate)
and the merged view; machine-wins now checks the raw pre-normalization
machine map so a typo'd or explicit {mode:"off"} entry blocks team intent
and gives repos a real local opt-out; wires the identity-map re-prime into
the 60s hooks-scan poller (the reliable mechanism, not the best-effort
repos.json watch).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deletes the resolver's legacy per-repo config.json rung (Scope union,
collectSlots slot, all five caller opt sites), the whole llm.ts/rt.llm
chain, and the dead lib/repo-config.ts. Registry hygiene: siblingCommand
field dies (zero defs carried it); rt.hooks remains the sole
migrated:false row.
Converts every test fixture that rode the legacy config.json path
(worktree reconciler/handlers, endpoint config/shim/intercept-run) to
seed the same data through the settings stores, pinning bare-clone test
origins via rt.repoIdentityOverrides where needed.
Rider: `rt daemon track <repo> off` now writes an explicit {mode:"off"}
machine entry instead of deleting when the team layer still names that
repo, so team intent can't resurrect tracking on the next merged read.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…coverage
The rider's off-marker survived being planted but not a SUBSEQUENT
unrelated write: manageTracking rebuilt the whole rt.repoTracking value
from the normalized (marker-dropping) view. Adds
loadMachineRepoTrackingRaw/saveRepoTrackingRaw so the write path
preserves every untouched repo's raw entry, marker included.
Fixes two converted test files (intercept-run, shim) that leaked the
claimview team store into the shared preload HOME with no per-test
isolation.
Restores coverage dropped during the legacy-rung conversion: an e2e
migrated:false case (retargeted to rt.hooks), two worktree-config
scenarios, and resolve.test.ts's multi-scope listSettings provenance
proof. Fixes three stale doc comments referencing the deleted legacy
rung/siblingCommand. Deletes the now-dead reposDir/repoDataDir
duplicate in packages/rt-client's path layout. Adds a CLI-wiring test
driving manageTracking's off-branch through its real seams.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Regenerates the command reference: rt settings llm's page is gone
(verb deleted in Task 4) and unrelated pre-existing generator drift
(home/secrets pages, rebrand description text) is caught up in the
same run. Live docs (README, website guides, docs/) never described
any of the migrated/deleted keys or files, so no prose changes were
needed — grep swept every dead filename and verb across all in-scope
files with zero hits.
Full wave gates: tsc 0, lib/commands/packages unit suites green,
docs:check clean. Full e2e has 8 pre-existing failures in
e2e/tests/endpoint.test.ts, traced to Task 4's legacy config.json
rung removal (that test still seeds repo config through the dead
file); reported, not fixed here, per scope.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
e2e/tests/endpoint.test.ts seeded rt.roles/rt.intercepts via the dead
per-repo repos/<repo>/config.json path (invisible to the settings-only
e2e gate my task ran). Seventh conversion of the same pattern: writes
into the machine store instead, keyed by the identity both fixture
repos' shared real remote normalizes to directly (no override pinning
needed here, unlike the local-bare-clone conversions).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… flap guard, doppler single resolve, naming/description cleanup
- commands/code.ts: savePrefs degrades to a warning on a malformed machine
store instead of throwing, matching loadPrefs and the wave's honest-save
doctrine; saveNotificationPrefs is unaffected (verb-only, stays throwing).
- lib/repo-tracking.ts: primeTeamTrackingIdentityMap no longer replaces a
non-empty identity map with an empty one, so a transient repos.json read
failure can't flap every team-tracked watcher.
- lib/daemon/doppler-sync.ts + lib/doppler-template.ts: resolve
rt.dopplerTemplate once per repo per tick — loadTemplate now takes the
already-resolved value instead of re-fetching it itself.
- commands/daemon.ts: rename the merged-view local at the interactive-editor
call site from rawTracking to displayTracking (pure rename; the raw-machine
binding elsewhere keeps its name).
- registry-defs.ts: rt.branchNaming's description now says rt has no readers
of the key yet and the VS Code extension's branch-naming.json file remains
authoritative until it ports over.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@m4ttheweric
m4ttheweric merged commit 71474d6 into mainAug 21, 2026
m4ttheweric added a commit that referenced this pull request Aug 22, 2026
…DME drift, escaping, log collision)
#1: walkthrough.sh's cleanup() defaulted a missing phases.jsonl to success
via ${f:-0}, so dying before the first vm_phase_end (e.g. no tart on a
fresh machine) exited 0 with an empty report. Dropped the default so a
missing ledger fails the `[ -eq 0 ]` test and falls through to exit 1,
matching xcuitest.sh's existing fail-closed form. Pre-existing on main;
reproduced the before/after with the review's no-tart repro.
#2/#9: README described ax.sh/drive-setup.sh/trigger-update.sh as not yet
in the tree and misattributed the screens-phase failure to an unstaged
guest script; all three are staged into $GUEST_BIN by walkthrough.sh today.
Corrected the Status/Layout prose to state what's actually gating
`--scenario create/join` (L3's setup screens) and the update phase (L3's
MATTSTACK_APPCAST_URL hook). Also corrected the disk-footprint line: the
~60 GB figure is cleanroom-only, and an --xcode golden needs substantially
more (full Xcode install on top of the base OS).
#3: check-vm-scripts.sh's ax.sh syntax-error net only matched "script
error"/"Expected " literally, missing other osascript compile-failure
shapes (e.g. "syntax error: A property can't go after..."). Widened to a
bare "syntax error" alternative, which osascript writes for every compile
failure and never for a runtime error.
#4: ax_click_button_named defaulted its process arg to the already-escaped
$AX_APP, then ran ax_esc on it again, double-escaping any AX_APP containing
a quote or backslash. Now only escapes when an explicit (raw) $2 is given.
#6: build-golden.sh's tart boot log was named golden-$VER-tart.log for both
flavours, so an --xcode build silently overwrote the cleanroom golden's
boot log. Named it after $GOLDEN instead, which already carries the -xcode
suffix.
Findings #5 (VM_APPCAST_PORT default duplication), #7 (--ver not
version-validated), #8 (xcuitest.sh's guest-staging convention), and #10
(PAT/password on guest ssh argv) are parked per the reviewer's ruling —
not touched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
m4ttheweric added a commit that referenced this pull request Aug 22, 2026
R-T7-a (#1): tool.daemon's launchd/worktrees sub-facts are real negative
signals now, not folded into a "ready" detail — either failing flips the
row to "invalid" with the specific fact named.
R-T7-b (#4): the legacy split-state branch (required, invalid) carries a
{type:"steps"} merge-by-hand remedy instead of action:null; the detail also
gets verify's plural handling back.
R-T7-c (#6): fixes the bundle-memo hazard at its source. appBundleRoot()
(lib/bundle-layout.ts) now memoizes only the true default
(exists === existsSync); an injected exists (every Probes-driven caller)
never reads or writes it. Validator tests drop the reset ceremony this made
unnecessary.
R-T7-d (#12): tool.rt-link's needs-you branch carries a {type:"run"} action
to fix the link in one step.
#2/#3: tool.fzf and tool.rt now distinguish "genuinely absent" (127) from
"resolved but won't run" (any other exit) — the latter is "error", never
"ready"/"missing".
#5: tool.daemon and tool.app get recheck:"on-activate" (Task 6's convention
for out-of-band, leave-the-app-and-come-back rows).
#7: the five optional rows carry real optionalNotes.
#8: tool.app's legacy note names the exact hit path(s), matching verify's
phrasing.
#9: interceptsRow wraps shimReport()/staleIntercepts() so a throw degrades
to an "error" row instead of rejecting the whole plan.
#10: tool.daemon's Login Items action is imported from permissions.ts
(now exported as LOGIN_ITEMS_SETTINGS_ACTION) instead of a duplicate
literal.
#11: lib/shell-integration.ts gains detectShellFrom()/shellRcPathFor(),
pure functions the real detectShell()/shellRcPath() now delegate to and
tool.shell reuses over Probes; an unrecognized shell gets an honest
"can't write automatically" detail instead of "Install writes it".
#13: the tool.daemon describe saves/restores DAEMON_CONFIG_PATH's
pre-existing content around the whole block instead of only deleting it,
so status-fallback.test.ts's absence assumption can't be poisoned.
#14/#15: header comment no longer cites the brief's table, the rt-link
"no app" test asserts its reason string, and commands/verify.ts's docblock
is trimmed to the one load-bearing line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
m4ttheweric added a commit that referenced this pull request Aug 24, 2026
RT keys wave: every rt legacy config lives in the stores; the legacy rung dies
m4ttheweric added a commit that referenced this pull request Aug 24, 2026
…DME drift, escaping, log collision)
#1: walkthrough.sh's cleanup() defaulted a missing phases.jsonl to success
via ${f:-0}, so dying before the first vm_phase_end (e.g. no tart on a
fresh machine) exited 0 with an empty report. Dropped the default so a
missing ledger fails the `[ -eq 0 ]` test and falls through to exit 1,
matching xcuitest.sh's existing fail-closed form. Pre-existing on main;
reproduced the before/after with the review's no-tart repro.
#2/#9: README described ax.sh/drive-setup.sh/trigger-update.sh as not yet
in the tree and misattributed the screens-phase failure to an unstaged
guest script; all three are staged into $GUEST_BIN by walkthrough.sh today.
Corrected the Status/Layout prose to state what's actually gating
`--scenario create/join` (L3's setup screens) and the update phase (L3's
MATTSTACK_APPCAST_URL hook). Also corrected the disk-footprint line: the
~60 GB figure is cleanroom-only, and an --xcode golden needs substantially
more (full Xcode install on top of the base OS).
#3: check-vm-scripts.sh's ax.sh syntax-error net only matched "script
error"/"Expected " literally, missing other osascript compile-failure
shapes (e.g. "syntax error: A property can't go after..."). Widened to a
bare "syntax error" alternative, which osascript writes for every compile
failure and never for a runtime error.
#4: ax_click_button_named defaulted its process arg to the already-escaped
$AX_APP, then ran ax_esc on it again, double-escaping any AX_APP containing
a quote or backslash. Now only escapes when an explicit (raw) $2 is given.
#6: build-golden.sh's tart boot log was named golden-$VER-tart.log for both
flavours, so an --xcode build silently overwrote the cleanroom golden's
boot log. Named it after $GOLDEN instead, which already carries the -xcode
suffix.
Findings #5 (VM_APPCAST_PORT default duplication), #7 (--ver not
version-validated), #8 (xcuitest.sh's guest-staging convention), and #10
(PAT/password on guest ssh argv) are parked per the reviewer's ruling —
not touched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
m4ttheweric added a commit that referenced this pull request Aug 24, 2026
R-T7-a (#1): tool.daemon's launchd/worktrees sub-facts are real negative
signals now, not folded into a "ready" detail — either failing flips the
row to "invalid" with the specific fact named.
R-T7-b (#4): the legacy split-state branch (required, invalid) carries a
{type:"steps"} merge-by-hand remedy instead of action:null; the detail also
gets verify's plural handling back.
R-T7-c (#6): fixes the bundle-memo hazard at its source. appBundleRoot()
(lib/bundle-layout.ts) now memoizes only the true default
(exists === existsSync); an injected exists (every Probes-driven caller)
never reads or writes it. Validator tests drop the reset ceremony this made
unnecessary.
R-T7-d (#12): tool.rt-link's needs-you branch carries a {type:"run"} action
to fix the link in one step.
#2/#3: tool.fzf and tool.rt now distinguish "genuinely absent" (127) from
"resolved but won't run" (any other exit) — the latter is "error", never
"ready"/"missing".
#5: tool.daemon and tool.app get recheck:"on-activate" (Task 6's convention
for out-of-band, leave-the-app-and-come-back rows).
#7: the five optional rows carry real optionalNotes.
#8: tool.app's legacy note names the exact hit path(s), matching verify's
phrasing.
#9: interceptsRow wraps shimReport()/staleIntercepts() so a throw degrades
to an "error" row instead of rejecting the whole plan.
#10: tool.daemon's Login Items action is imported from permissions.ts
(now exported as LOGIN_ITEMS_SETTINGS_ACTION) instead of a duplicate
literal.
#11: lib/shell-integration.ts gains detectShellFrom()/shellRcPathFor(),
pure functions the real detectShell()/shellRcPath() now delegate to and
tool.shell reuses over Probes; an unrecognized shell gets an honest
"can't write automatically" detail instead of "Install writes it".
#13: the tool.daemon describe saves/restores DAEMON_CONFIG_PATH's
pre-existing content around the whole block instead of only deleting it,
so status-fallback.test.ts's absence assumption can't be poisoned.
#14/#15: header comment no longer cites the brief's table, the rt-link
"no app" test asserts its reason string, and commands/verify.ts's docblock
is trimmed to the one load-bearing line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto 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

@m4ttheweric