opencode-thrum-pro 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/assets/commands/thrum-_compact-runtime-commands.md +61 -0
  2. package/assets/commands/thrum-_snapshot-protocol.md +17 -6
  3. package/assets/commands/thrum-_stamp-protocol.md +9 -2
  4. package/assets/commands/thrum-compact-extended.md +352 -0
  5. package/assets/commands/thrum-compact.md +300 -0
  6. package/assets/commands/thrum-inbox.md +1 -1
  7. package/assets/commands/thrum-restart-extended.md +84 -11
  8. package/assets/commands/thrum-restart.md +105 -13
  9. package/assets/commands/thrum-send.md +4 -1
  10. package/assets/commands/thrum-sleep-extended.md +67 -46
  11. package/assets/commands/thrum-sleep.md +67 -58
  12. package/assets/skills/adversarial-critique/SKILL.md +5 -8
  13. package/assets/skills/brainstorm-steward/SKILL.md +65 -11
  14. package/assets/skills/brainstormer-staying-current/SKILL.md +1 -4
  15. package/assets/skills/choosing-subagent-models/SKILL.md +14 -0
  16. package/assets/skills/conversation-only-context/SKILL.md +11 -11
  17. package/assets/skills/conversation-only-context/resources/driver-subagent-pattern.md +1 -1
  18. package/assets/skills/conversation-only-context/resources/remote-environment-scenarios.md +1 -1
  19. package/assets/skills/coordinator-assessing-agent-completion/SKILL.md +98 -6
  20. package/assets/skills/coordinator-context-monitoring/SKILL.md +29 -19
  21. package/assets/skills/coordinator-deploying-a-node/SKILL.md +124 -0
  22. package/assets/skills/coordinator-dispatching-work/SKILL.md +24 -11
  23. package/assets/skills/coordinator-hotpath-merge-gate/SKILL.md +62 -20
  24. package/assets/skills/coordinator-managing-state-and-lifecycle/SKILL.md +6 -6
  25. package/assets/skills/coordinator-merging-code/SKILL.md +25 -11
  26. package/assets/skills/coordinator-philosophy-merge-gate/SKILL.md +28 -7
  27. package/assets/skills/coordinator-plan-reconcile-gate/SKILL.md +3 -3
  28. package/assets/skills/coordinator-rolling-out-to-nodes/SKILL.md +92 -0
  29. package/assets/skills/coordinator-running-autonomous-feature-development/SKILL.md +3 -3
  30. package/assets/skills/coordinator-running-brainstorm-cycles/SKILL.md +21 -20
  31. package/assets/skills/coordinator-running-review-cycles/SKILL.md +15 -4
  32. package/assets/skills/diagnosing-fleet-and-daemon/SKILL.md +0 -2
  33. package/assets/skills/efficient-multi-agent-research/SKILL.md +3 -3
  34. package/assets/skills/implementer-orchestrating-execution/SKILL.md +11 -14
  35. package/assets/skills/orchestrate/SKILL.md +47 -35
  36. package/assets/skills/persistent-watcher-archetype/SKILL.md +172 -25
  37. package/assets/skills/persistent-watcher-archetype/resources/capture_archive.py +618 -0
  38. package/assets/skills/persistent-watcher-archetype/resources/jev_watcher_filter.py +837 -0
  39. package/assets/skills/persistent-watcher-archetype/resources/roster-watch.sh +1140 -0
  40. package/assets/skills/persistent-watcher-archetype/resources/roster-watch_test.sh +291 -0
  41. package/assets/skills/persistent-watcher-archetype/resources/thrum-capture-fallback.sh +2 -2
  42. package/assets/skills/persistent-watcher-archetype/resources/thrum-watch-pane-capture.sh +20 -8
  43. package/assets/skills/prime-agent/SKILL.md +10 -0
  44. package/assets/skills/project-setup/SKILL.md +22 -16
  45. package/assets/skills/project-setup/resources/implementation-agent.md +56 -35
  46. package/assets/skills/researcher-investigating/SKILL.md +2 -5
  47. package/assets/skills/thrum/SKILL.md +14 -7
  48. package/assets/skills/thrum/resources/ANTI_PATTERNS.md +16 -18
  49. package/assets/skills/thrum/resources/CLI_REFERENCE.md +17 -11
  50. package/assets/skills/thrum/resources/LISTENER_PATTERN.md +9 -3
  51. package/assets/skills/thrum/resources/MESSAGING.md +18 -11
  52. package/assets/skills/thrum/resources/WORKTREES.md +1 -1
  53. package/assets/skills/thrum-memory/SKILL.md +1 -1
  54. package/assets/skills/trace-spec-to-plan/resources/sweep-agent-prompt.md +1 -1
  55. package/assets/skills/update-queue/SKILL.md +6 -8
  56. package/assets/skills/using-the-dashboard/SKILL.md +30 -0
  57. package/assets/skills/using-the-queue/SKILL.md +76 -5
  58. package/assets/skills/using-thrum-state/SKILL.md +83 -0
  59. package/assets/skills/verify-against-plan/SKILL.md +120 -5
  60. package/assets/skills/watcher-archetype/SKILL.md +18 -0
  61. package/assets/skills/writing-durable-markdown/SKILL.md +5 -0
  62. package/dist/installer.js +4 -4
  63. package/dist/permission-fixture.integration.test.js +4 -4
  64. package/package.json +1 -1
  65. package/assets/skills/coordinator-deploying-the-fleet/SKILL.md +0 -396
  66. package/dist/allowlist-sync.test.d.ts +0 -1
  67. package/dist/allowlist-sync.test.js +0 -44
@@ -19,6 +19,30 @@ Apply the gate and containment checks below and reach your own
19
19
  conclusion. Destructive steps still follow the standing reap preconditions and
20
20
  pacing rules; nothing here shortcuts them.
21
21
 
22
+ ## Standing reap preconditions — ALL must hold
23
+
24
+ Reaping an agent (removing its worktree) is safe only when every one of these is
25
+ true. It is a gate, not a checklist to rationalize past:
26
+
27
+ 1. **Idle > 48h** — no activity in its transcript for more than two days (rank by
28
+ message CONTENT, not mtime; your own broadcasts reset mtime).
29
+ 2. **No messages exchanged in the last 24h** — nothing sent to it or from it.
30
+ 3. **Task complete AND nobody is waiting on it** — it finished and its
31
+ dispatcher/manager moved on, so a reply it waits for will never come. (A pushed
32
+ branch held on a still-queued merge is the one nuance — see the
33
+ held-pending-merge rule.)
34
+ 4. **Salvage done first** — its only-copy state is copied to a durable location and
35
+ verified (see Containment and the reap steps).
36
+
37
+ **When a needed decision or merge is delayed, ESCALATE — never silently wait.** If an
38
+ agent is parked past the 24h window on something its manager/owner has not acted on,
39
+ raise it explicitly to whoever owns that decision, and re-raise on every subsequent
40
+ run. If the human owner is unresponsive, escalate through your designated escalation
41
+ contact (the human's proxy) rather than leaving the agent parked. A silent park is
42
+ the failure this whole procedure exists to prevent: each run must drive a parked
43
+ agent toward a terminal state — decision made / merge lands (reap-able) or deemed
44
+ orphaned (reap).
45
+
22
46
  ## The instruments, in order of trust
23
47
 
24
48
  | Question | Instrument |
@@ -81,10 +105,42 @@ sentence IS the terminal statement; a working agent's merely contains one.
81
105
  **Name what it is waiting for, then prove that thing is dead or landed.**
82
106
 
83
107
  *"Held pending the coordinator merge"* is finished only if the merge landed or was
84
- abandoned. If the merge is still queued, the agent is **correctly** waiting and
85
- reaping it destroys live context that nobody else holds.
86
-
87
- **If you cannot name the blocker, it is not a candidate.**
108
+ abandoned. If the merge is still queued, whether the agent is *correctly* waiting
109
+ depends on its branch and its idle time — see the held-pending-merge rule below.
110
+
111
+ **If you cannot name the blocker, it is not a candidate.** (This governs the
112
+ *no-transcript* case — absence of evidence — not a named-but-stale merge wait.)
113
+
114
+ ## 🔴 The held-pending-merge case — a PUSHED branch changes the gate
115
+
116
+ An agent parked "pending the merge" is judged by ONE thing first — **is its branch
117
+ pushed?** — because a merge wait only makes sense if the merge king can reach the
118
+ branch.
119
+
120
+ - **Branch NOT pushed — broken at ANY idle age.** The merge king cannot access an
121
+ unpushed branch, so the wait can never resolve, and the agent's commits are also
122
+ the only copy (unsafe to reap). This is not a legitimate wait — it is a stuck one.
123
+ → Get the branch PUSHED (nudge the agent / its orchestrator to push it, or escalate
124
+ that it needs pushing). Never reap an unpushed held-pending-merge agent — pushing
125
+ first is both what unblocks the merge and what makes any later reap safe.
126
+ - **Branch pushed, idle < 24h.** Legitimately waiting its turn in the merge queue.
127
+ Leave it (the pushed branch means the merge king can reach it and nothing is lost).
128
+ - **Branch pushed, idle ≥ 24h.** The wait is no longer legitimate — a pushed branch
129
+ is not the only copy of anything, so any agent could carry the merge. Resolve it to
130
+ one of two clear states:
131
+ - **Merge HAPPENED** (branch is an ancestor of trunk, or was abandoned/superseded)
132
+ → the agent is **ORPHANED**, waiting for a response that will never come → **reap**
133
+ (salvage-first, and still subject to the standing reap preconditions).
134
+ - **Merge still PENDING** (branch not on trunk, not abandoned) → the merge king
135
+ forgot it or the queue is stuck → **ESCALATE** to the merge king (name the branch
136
+ tip + how long it has waited), and **re-escalate on every subsequent skill run**
137
+ until it resolves. Never leave it silently parked.
138
+
139
+ **The escalation is the load-bearing half.** Because each skill run re-checks and
140
+ re-escalates a still-pending merge, the condition is self-correcting: it drives toward
141
+ one of two terminal states — the merge completes (agent then reap-able) or the agent
142
+ is deemed orphaned (reap) — instead of a pushed-branch agent parked forever on a merge
143
+ nobody is tracking. A silent park is exactly the failure this rule prevents.
88
144
 
89
145
  ## Containment, before anything is stood down
90
146
 
@@ -126,8 +182,8 @@ an empty/never-read premise as a match"*). `--force` does NOT bypass it; the gua
126
182
  correct. So the reap that actually frees load is worktree removal — but salvage BEFORE you remove,
127
183
  then remove PLAIN (no `--force`):
128
184
 
129
- 1. Enumerate untracked+ignored `.thrum` content — BOTH flags, one flag alone misses a class
130
- (thrum-j14q3): `git status --untracked-files=all --ignored -- .thrum`
185
+ 1. Enumerate untracked+ignored `.thrum` content — BOTH flags, one flag alone misses a class:
186
+ `git status --untracked-files=all --ignored -- .thrum`
131
187
  2. Salvage BOTH kinds to their canonical redirect paths, and `cmp`-verify each copy is
132
188
  byte-identical to its source:
133
189
  - `?? .thrum/agents/<agent>/sessions/*-restart.md` — the restart snapshot.
@@ -218,6 +274,42 @@ RSS-MB.
218
274
  you decide**. It is read-only and dry-run — it prints a kill-list, it never
219
275
  kills anything.
220
276
 
277
+ ## 🔴 Footguns — never do these (each measured, each cost real time or state)
278
+
279
+ - **Never glob/`cp` `.thrum/context/*.md` when salvaging** — the glob matches the
280
+ shared `project_state.md` and overwrites the canonical copy with a stale worktree
281
+ copy. Salvage the agent-specific `<agent>.md` by exact name only.
282
+ - **A worktree's `.thrum/` holds a redirect file to the main repo AND a physical
283
+ stale local copy of shared files** (e.g. `project_state.md`) — the physical
284
+ worktree copy is NOT canonical; never treat it as the source of truth or copy it
285
+ upward.
286
+ - **Never use shell-specific builtins in a reap loop without checking the shell** —
287
+ `mapfile`/`readarray` are bash-only and silently fail in zsh (`command not
288
+ found`), so the salvage you thought ran did not. Use portable `while read` and
289
+ verify each salvaged file actually landed.
290
+ - **`rm -rf` raises a confirmation modal that blocks the PARENT pane invisibly** —
291
+ use `rm -r` for scratch cleanup (identical deletion, no modal). Never `rm -rf`.
292
+ - **`git worktree remove` (plain) silently deletes gitignored-only content (rc=0)**
293
+ and refuses (rc=128) only on untracked/modified files — salvage is the ONLY
294
+ protection for gitignored only-copy state.
295
+ - **`git worktree remove` refuses while a just-salvaged untracked snapshot still
296
+ sits in the worktree** — remove that salvaged copy from the worktree first, then
297
+ plain-remove.
298
+ - **Never `checkout`/`reset`/`restore`/`stash`/`clean` in a shared tree, even to
299
+ undo** — to restore a file to its committed version, write it with a plain
300
+ redirect from `git show <ref>:<path>`, not a checkout.
301
+ - **Test the reap on ONE agent first and verify the EFFECT** (gone from the worktree
302
+ list AND disk), not just the exit code.
303
+ - **Rank candidates by last-message CONTENT, not elapsed time** — your own
304
+ broadcasts reset every recipient's idle clock.
305
+ - **`--force` on agent-delete does NOT bypass the CAS guard** on a stale agent — the
306
+ reap that frees load is worktree removal, not the delete.
307
+ - **Reap order is `thrum tmux kill <session>` FIRST, THEN `git worktree remove`** —
308
+ removing the worktree alone leaves the agent's tmux session alive with a
309
+ now-deleted cwd, which the fleet flags as recurring "cwd drift" and whose runtime
310
+ process keeps consuming RAM/CPU. Kill the session, verify it's gone, then remove
311
+ the worktree.
312
+
221
313
  ## Why this fails dangerously if you skip the gate
222
314
 
223
315
  The failure direction is **false-GONE**: concluding a live agent is finished. It
@@ -26,40 +26,51 @@ What's forbidden is a script that bypasses this skill and fires
26
26
  `thrum tmux restart --force` unconditionally (that violates
27
27
  `feedback_restart_discipline` — burn the runway, don't restart on schedule).
28
28
 
29
- ## Coordinator self-restart — ALWAYS `/thrum:restart-extended`
29
+ ## Coordinator self-restart — ALWAYS the EXTENDED form, compact-extended FIRST
30
30
 
31
31
  This skill's tier ladder (Steps 3–5) governs how the coordinator restarts
32
32
  **other** agents. When the **coordinator restarts ITSELF**, a different rule
33
- applies and it is absolute:
33
+ applies and it is absolute — but D5 (owner-ruled)
34
+ REVERSES which command that is:
34
35
 
35
- > **The coordinator ALWAYS self-restarts via `/thrum:restart-extended`, NEVER
36
- > `/thrum:restart`.**
36
+ > **The coordinator ALWAYS uses the EXTENDED snapshot grade for itself — never
37
+ > the standard/compact form. Which command carries that grade is
38
+ > runtime-directed: `/thrum:compact-extended` on any runtime with a verified
39
+ > compact-equivalent skill (D6, the default), `/thrum:restart-extended` ONLY
40
+ > as the fallback on a runtime without one (today: muse, copilot).**
41
+
42
+ This is a REVERSAL of the prior absolute rule ("ALWAYS restart-extended, NEVER
43
+ compact") — that rule is retired, not merely relaxed. Do not restore it.
37
44
 
38
45
  Rationale: the coordinator is the nerve center. Its handoff must carry the full
39
46
  16-section snapshot (wire contracts, capability matrix, cycle history, open
40
47
  L-questions, anticipated Q&A, design rationale) so the next session resumes
41
- steady-state coordination without re-deriving fleet state. The standard
42
- `/thrum:restart` compact format drops that load-bearing context and strands the
43
- next session. This holds regardless of which tier the coordinator's own context
44
- sits in — there is no ctx-band at which the coordinator downgrades to the
45
- compact restart.
48
+ steady-state coordination without re-deriving fleet state — that requirement
49
+ is UNCHANGED and is what "EXTENDED" governs; only the compact-vs-restart choice
50
+ changed. Compacting (rather than restarting) additionally keeps the SAME
51
+ process/session alive — sub-agents, background loops, and cron schedules the
52
+ coordinator owns survive the compaction, where a restart would drop them.
53
+ There is no ctx-band at which the coordinator downgrades to the standard/
54
+ compact-grade snapshot — the tier ladder below governs OTHER agents, not this.
46
55
 
47
- Practical trigger points for coordinator self-restart:
56
+ Practical trigger points for coordinator self-restart/compact:
48
57
 
49
58
  - A warn-tier context nudge fires on the coordinator's own pane (e.g. 70%+).
50
59
  - The coordinator hits a clean checkpoint and elects a fresh session.
51
60
  - Rate-limit / stuck-state recovery on the coordinator itself.
52
61
 
53
- In every one of these, run `/thrum:restart-extended`. (Captured as role-rule
54
- `coord-always-restart-extended` /
55
- `Coordinator ALWAYS uses /thrum:restart-extended`; this skill is the
56
- always-loaded home so the rule survives even when memory isn't consulted.)
62
+ In every one of these: run `/thrum:compact-extended` if the coordinator's
63
+ runtime has a compact equivalent (the default); `/thrum:restart-extended` only
64
+ if it does not. (The role-rule `coord-always-restart-extended` — `Coordinator
65
+ ALWAYS uses /thrum:restart-extended` — is RETIRED as of D5; see
66
+ `thrum memory` for its retirement record. This skill is the always-loaded home
67
+ so the CURRENT rule survives even when memory isn't consulted.)
57
68
 
58
69
  Note the distinction from Steps 3–5 below: those steps drive `/thrum:restart`
59
70
  (Step 4) and `/thrum:restart-extended` (Step 5) into
60
71
  **implementer/brainstormer** panes per their ctx tier — that tiering is correct
61
72
  for worker agents. The carve-out here is ONLY about the coordinator's own
62
- restart, which is unconditionally the extended form.
73
+ restart/compact, which is unconditionally the extended grade, compact-first.
63
74
 
64
75
  ## How the scheduled sweep works (v0.10.6+ — thrum monitor)
65
76
 
@@ -274,10 +285,7 @@ brick.
274
285
 
275
286
  ## Subagent model selection
276
287
 
277
- > **Model tiers:** pass an explicit `model:` on every dispatch — `sonnet`
278
- > (low effort) mechanical, `sonnet` (medium effort) judgment, Opus only on
279
- > operator-ask or a skill step that names it. See the
280
- > `choosing-subagent-models` skill for the full policy.
288
+ > **Model tiers:** pass an explicit `model:` on every dispatch; choose model and effort per the `choosing-subagent-models` skill (read `runtime.role_models` at the moment of use). Never let a sub-agent inherit your own model.
281
289
 
282
290
  ## Step 1 — Run the sweep
283
291
 
@@ -464,6 +472,8 @@ by typing the restart command directly into their input field:
464
472
  thrum tmux send <tmux_session_name> '/thrum:restart'
465
473
  ```
466
474
 
475
+ If it exits 3 (Enter WITHHELD, text already typed) or 4 (verdict unknown), do NOT retype it: `thrum tmux capture` the pane and submit with `thrum tmux send <tmux_session_name> --keys Enter` only if no dialog is showing.
476
+
467
477
  (Find the tmux session name in sweep output — it's typically the worktree
468
478
  basename, e.g. `myepic-impl`, NOT the agent_id.)
469
479
 
@@ -0,0 +1,124 @@
1
+ ---
2
+ name: coordinator-deploying-a-node
3
+ description: "Use when deploying a build to a single node, migrating or not — deploying a build, schema-migrating deploy, pro-bundle install plus service restart on a node, roll out a build to a node, ship to a node, single-node canary. Loads the deploy runbook — verifying the artifact actually CONTAINS the fix, install-before-restart ordering, verify-by-effect, and preventing store corruption on migration."
4
+ ---
5
+
6
+ # Coordinator: Deploying a Build to a Single Node — migrating or not
7
+
8
+ > This runbook covers EVERY deploy to a single node, migrating or not. Most sections apply to every deploy; only migration-weight and store-corruption specifics are bump-only.
9
+
10
+ ## 0. Pull-current first (ff-only)
11
+
12
+ The absolute first action before anything else: fetch the control-plane repository and fast-forward to the orchestrator's pin.
13
+
14
+ - Read the project's deployment adapter inside `.thrum/config.json` (`fleet.deployment`; reference at the deployment-adapter reference) to obtain `preflight.pull_command` and `preflight.pin_command`.
15
+ - Run `preflight.pull_command` (must be ff-only; if not fast-forwardable, STOP and surface — never blind-merge in the shared tree).
16
+ - Verify the delivered artifact actually CONTAINS the fix at the pinned SHA (adapter `artifact.commit_file` sidecar).
17
+
18
+ This ensures the node's coordinator reasons from a checkout that is actually current before evaluating backup, install, or migration.
19
+
20
+ > Example — Thrum project: pull via `git fetch origin && git merge --ff-only origin/<branch>` before any backup or install.
21
+
22
+ ## 1. Who executes — resolve the node's local coordinator (via adapter identity)
23
+
24
+ The node's own coordinator drives the deploy locally on its own host. Never drive a node's build/install/restart from another host.
25
+
26
+ - Resolve WHO via `topology.identity_resolution` (adapter `fleet.deployment.thrum.topology.identity_resolution` or `fleet.deployment.products.<id>.topology`) — a `daemon_id` join plus hostname and absence of `.thrum/redirect`, never by agent name or worktree name.
27
+ - When connected-repo daemons share a host, respect the adapter-defined restart order within that host.
28
+
29
+ If the target node has no working coordinator, state why explicitly before using any fallback.
30
+
31
+ ## 2. Back up before touching anything (via adapter backup command + sizing formula)
32
+
33
+ - Run the project's backup command (`fleet.deployment.thrum.backup.command` or `fleet.deployment.products.<id>.backup.command`) and verify per `backup.verify`.
34
+ - Size BEFORE you run it on a bloated node: apply the adapter's `backup.sizing_formula` (`free_at_completion = free_now - zip(stale current/) + size(stale current/) - size(live lane)`) — the stale `current/` is removed before the fresh export, so peak is not double-count. Retention runs last and does not bound the peak.
35
+ - On failure, roll back via `backup.restore_command`; never delete the store.
36
+
37
+ > Example — Thrum project: backup via `thrum backup`, sized per the formula above, verified with `sqlite3 ?mode=ro&immutable=1` read.
38
+
39
+ ## 3. Storage access — through the engine or control-plane CLI, never file-bypass
40
+
41
+ Access the state store only through the engine or the control-plane CLI in read-only mode. Never bypass the storage engine's file ownership.
42
+
43
+ - Via: `storage_access.via` (e.g., CLI or `?mode=ro`).
44
+ - Forbidden: `storage_access.forbidden` (e.g., hand-copy of live `-wal`/`-shm`, concurrent `.backup` on live store).
45
+ - A bare read-write open can fire a checkpoint that truncates the write log out from under live readers → sustained corruption. Always use `?mode=ro` where applicable.
46
+
47
+ If the project has no WAL/SHM, this section is N/A — skip and note.
48
+
49
+ ## 4. Never wrap service start/restart in a blind timeout
50
+
51
+ Run the project's service restart command (`fleet.deployment.thrum.service.restart_command` or product equivalent) without a blind timeout wrapper. A timeout that kills a migrating restart mid-migration manufactures a half-migrated store.
52
+
53
+ - Adapter flag `service.never_timeout` is true.
54
+ - Signal-window rules are adapter data: `migration.signal_rules` (`SIGQUIT` fatal-always, `SIGUSR1` fatal-before-socket). Respect them — do not send fatal signals in the forbidden window.
55
+
56
+ > Example — Thrum project: restart via `thrum daemon restart`, never wrapped in `timeout`; mac path via `scripts/mac-daemon-restart-via-cron.sh`.
57
+
58
+ ## 5. Install from the delivered artifact (never rebuild on the node)
59
+
60
+ Install from the identical bundle the orchestrator built, delivered to `artifact.distribution.drop_path`.
61
+
62
+ - Verify BEFORE unpack that the delivered bundle's version/checksum/commit sidecar equals the orchestrator's pin (adapter `artifact.checksum`, `artifact.version_file`, `artifact.commit_file`).
63
+ - Run `install.command` (from adapter). The node does not compile, sign, or rebuild — it installs.
64
+ - Collect BEFORE readings (current version, state counters, checkpoint counts, health probes) before the install.
65
+
66
+ > Example — Thrum project: install from the adapter's `artifact.distribution.drop_path` via the adapter's `install.command`.
67
+
68
+ ## 6. Measure from the running process, never the checkout
69
+
70
+ Read version/state from the running service, not from the filesystem checkout.
71
+
72
+ - Verify via `install.verify_by_effect` probes: version equals pin, NEW PID, service status reports pin, sidecar equals pin.
73
+ - Do not trust installer exit 0 alone.
74
+
75
+ ## 7. Migrate via service restart — verify by effect
76
+
77
+ Migration is performed by restarting the service after install; the service's own boot migration does the schema/data move.
78
+
79
+ - Calibrate weight via `migration.weight_calibration` (heavy bulk-export vs light add-column) — do not assume a fixed duration.
80
+ - Known signatures that require a cold-restart recovery: `migration.sigbus_signatures` (e.g., WAL-index recover signatures) and `migration.on_sigbus`.
81
+ - Observe that the restarted service reports the new version/state and that health probes have converged (adapter `health.probes`, `health.convergence_wait`).
82
+
83
+ ## 8. Verify post-migration (liveness, health probes, checkpoint counts, agent liveness)
84
+
85
+ Run adapter `health.probes` and compare BEFORE/AFTER:
86
+
87
+ - Service alive and reporting pin.
88
+ - State counters converged per `health.convergence_wait` (mechanism-derived, e.g., `3m`).
89
+ - Crash log empty, expected agents live.
90
+
91
+ For tandem daemons that share a host or depend on each other, verify the coordinated set per adapter.
92
+
93
+ ## 8a. Re-render configuration/templates if the build changes them
94
+
95
+ If the build carries template or role changes, re-render between install and restart:
96
+
97
+ - Commands: `templates.refresh_command` and `templates.deploy_command`.
98
+ - Order: `templates.order` (`refresh→deploy` between `install.sh` and daemon restart).
99
+ - Verify by effect (render output, then service restart).
100
+
101
+ > Example — Thrum project: `thrum roles refresh` then `thrum roles deploy` between install and restart.
102
+
103
+ ## 8b. Plugin/skill refresh if the deploy carries skill changes
104
+
105
+ If the bundle carries skill/plugin changes, refresh the plugin cache:
106
+
107
+ - Refresh driver: `plugin.refresh` (version bump required — cache keyed by version).
108
+ - Manifests: `plugin.manifests` (all skill-carrying manifests bumped in the same commit as the new skills).
109
+
110
+ Do not hand-edit generated marketplace manifests.
111
+
112
+ ## 8c. Reconcile registry/phase after restart
113
+
114
+ Re-verify the daemon registry and agent phases after restart (adapter `health.probes` includes phase reconciliation). Confirm the pinned version is durable across a clean cold-boot probe where applicable.
115
+
116
+ ## Red flags — STOP
117
+
118
+ - Pull not ff-only.
119
+ - Backup skipped or undersized.
120
+ - Storage accessed via forbidden path (`storage_access.forbidden`).
121
+ - Restart wrapped in a blind timeout or killed with `SIGQUIT`/`SIGUSR1` in a fatal window (`migration.signal_rules`).
122
+ - Install rebuilt locally instead of from the delivered artifact.
123
+ - Post-migration health not verified by observed effect.
124
+ - Template re-render skipped when the build changed templates (`templates.order` violated).
@@ -65,10 +65,7 @@ optimization.
65
65
 
66
66
  ## Subagent model selection
67
67
 
68
- > **Model tiers:** pass an explicit `model:` on every dispatch — `sonnet`
69
- > (low effort) mechanical, `sonnet` (medium effort) judgment, Opus only on
70
- > operator-ask or a skill step that names it. See the
71
- > `choosing-subagent-models` skill for the full policy.
68
+ > **Model tiers:** pass an explicit `model:` on every dispatch; choose model and effort per the `choosing-subagent-models` skill (read `runtime.role_models` at the moment of use). Never let a sub-agent inherit your own model.
72
69
 
73
70
  ## Check the target's queue before you dispatch (R3)
74
71
 
@@ -162,13 +159,30 @@ re-dispatch overhead.
162
159
  3. Acceptance criteria as bullets
163
160
  4. The worktree path the work happens in
164
161
  5. An explicit reminder to pass `model:` on any sub-agents the implementer
165
- spawns (sonnet-low for mechanical, sonnet-medium for judgment)
162
+ spawns (model and effort per `choosing-subagent-models`)
166
163
  6. Spec/plan paths to read before starting
167
164
  7. **Adjacent candidate beads** from the adjacency pass above, labeled as
168
165
  CANDIDATES with their validity explicitly unverified — plus the instruction to
169
166
  check them against the merged-forward tip and either fold them in or return
170
167
  them as completed
171
168
 
169
+ ## Anti-pattern-removal epics must ship a ratchet lens
170
+
171
+ **Why:** during a prior owner-bypass remediation, judgment
172
+ review alone let 11 new instances of the exact anti-pattern being removed
173
+ land through the merge gate mid-sprint, because no mechanical check enforced
174
+ a monotonic budget across diffs.
175
+
176
+ **How to apply:** When dispatching an epic whose purpose is removing an
177
+ existing anti-pattern (not just fixing one instance of it), the acceptance
178
+ criteria MUST include a mechanical ratchet lens (see
179
+ `coordinator-hotpath-merge-gate` § "Invariant-ratchet lenses") wired into
180
+ `.thrum/hotpath-gate.json` as `always_run` before the epic is considered
181
+ closeable — not as a follow-up. A judgment-only acceptance ("reviewer
182
+ confirms the count went down") is insufficient; the count must be enforced
183
+ by a standing mechanical budget the gate itself checks on every subsequent
184
+ merge.
185
+
172
186
  ## Execution invariants — carry these in every implementation dispatch
173
187
 
174
188
  **Why:** A plan is a snapshot; trunk moves and reality drifts from it. Sprints
@@ -208,17 +222,16 @@ with a different name — do not rename in place.
208
222
 
209
223
  ## Propagate model-selection discipline downward
210
224
 
211
- **Why:** Sub-agents inherit the parent model by default. A coordinator on Opus
212
- that spawns an unspecified sub-agent gets Opus-cost work for tasks that need
213
- sonnet-low. The same trap repeats inside an implementer's worktree: if the
225
+ **Why:** Sub-agents inherit the parent model by default. A coordinator whose own tier is
226
+ costly that spawns an unspecified sub-agent gets costly work for tasks that need
227
+ a cheap tier. The same trap repeats inside an implementer's worktree: if the
214
228
  implementer doesn't propagate the discipline, their own sub-agents silently
215
229
  inherit too. Cost compounds across a session.
216
230
 
217
231
  **How to apply:** Every dispatch prompt should include the model-selection rule
218
232
  explicitly: "When you spawn your own sub-agents, pass explicit `model:` —
219
- `sonnet` (low effort) for mechanical work (lint, tests, find/replace), `sonnet`
220
- (medium effort) for judgment work (review, complex implementation), `opus`
221
- only when justified. Default to sonnet over opus." Audit the dispatch prompt before sending.
233
+ choose model and effort per the `choosing-subagent-models` skill (read
234
+ `runtime.role_models` at the moment of use); never inherit your own model." Audit the dispatch prompt before sending.
222
235
 
223
236
  ## The impl-prompt review stamp satisfies pre-dispatch review
224
237
 
@@ -117,23 +117,35 @@ rediscovering these the hard way:
117
117
  carrying dupes instead of the real content.
118
118
  6. Run full-package `-race`, not targeted `-run` — a targeted race run misses
119
119
  cross-test races.
120
- 7. Build+test the MERGED-tree result as a SEPARATE condition — neither gate
120
+ 7. **`internal/daemon/rpc` must NEVER be run monolithically at gate time, in
121
+ either lane** — a bare package-level `go test [-race] ./internal/daemon/rpc`
122
+ starves and hits the configured `-timeout` wall in both the race and
123
+ non-race lane. The gate's OUTPUT must show the sharded runner actually
124
+ executed for RPC (`race-shard` / `package-shard --mode norace`, or
125
+ `scripts/test-run.sh race|norace ./internal/daemon/rpc`, or `make gate`
126
+ which shards both lanes automatically) — not just that some RPC test ran.
127
+ A bound-timeout with ZERO test failures is a FALSE RED, not a finding:
128
+ distinguish it from a genuine hang/deadlock via
129
+ `go run ./cmd/testgate classify-timeout --log <file> --shard-config <file>
130
+ --shard <name>` (fails closed — only BOUND-TIMEOUT exits 0; HANG and
131
+ UNCLASSIFIED both exit nonzero) before reporting it as a regression.
132
+ 8. Build+test the MERGED-tree result as a SEPARATE condition — neither gate
121
133
  currently runs a build of the actual post-merge tree; a clean pre-merge
122
134
  build/test does not prove the merged result compiles or passes.
123
- 8. Use `rm -r`, NEVER `rm -rf`; use plain `git worktree remove` to drop a worktree, never
124
- `--force` as the default (see item 12 below). A broad `ask` rule on `rm -rf *` outranks any narrow `/tmp` allow,
135
+ 9. Use `rm -r`, NEVER `rm -rf`; use plain `git worktree remove` to drop a worktree, never
136
+ `--force` as the default (see item 13 below). A broad `ask` rule on `rm -rf *` outranks any narrow `/tmp` allow,
125
137
  so `rm -rf` raises a human permission prompt EVERY time regardless of path —
126
138
  it stalls gate sub-agents mid-run waiting on a keystroke. `rm -r` runs free. Do NOT widen the ask rule
127
139
  to work around this; that entry is the only deletion protection on the box.
128
- 9. Check the discriminator before picking a scratch path, don't assume from
129
- the platform: `[ -L /tmp ]`. macOS (symlink) — create throwaway worktrees
130
- under `/private/tmp`; a worktree under `/tmp` false-FAILs worktree-ancestor
131
- tests via the symlink, producing a confident wrong gate result. Linux (real
132
- dir) — `/tmp` is correct; `/private/tmp` may not exist there and must not
133
- be created.
134
- 10. Your report reaches the coordinator ONLY as your final returned text.
140
+ 10. Check the discriminator before picking a scratch path, don't assume from
141
+ the platform: `[ -L /tmp ]`. macOS (symlink) — create throwaway worktrees
142
+ under `/private/tmp`; a worktree under `/tmp` false-FAILs worktree-ancestor
143
+ tests via the symlink, producing a confident wrong gate result. Linux (real
144
+ dir) — `/tmp` is correct; `/private/tmp` may not exist there and must not
145
+ be created.
146
+ 11. Your report reaches the coordinator ONLY as your final returned text.
135
147
  Side-channel output is discarded. Put the whole verdict in the return value.
136
- 11. **NEVER run `git stash`, `git checkout`, `git reset`, or any working-tree
148
+ 12. **NEVER run `git stash`, `git checkout`, `git reset`, or any working-tree
137
149
  mutation in the SHARED repo.** Do read-only inspection there (`git show
138
150
  <sha>:<path>`, `git log`, `git diff`) and do every build/test in a throwaway
139
151
  detached worktree. `git stash` is a SINGLE SHARED STACK across every
@@ -142,7 +154,7 @@ rediscovering these the hard way:
142
154
  hold uncommitted `State.md` they are actively re-authoring.
143
155
  If you believe you must mutate the shared tree, STOP and report instead —
144
156
  that is always a finding, never a step.
145
- 12. **TEAR DOWN YOUR THROWAWAY WORKTREE WHEN THE GATE ENDS — after two checks,
157
+ 13. **TEAR DOWN YOUR THROWAWAY WORKTREE WHEN THE GATE ENDS — after two checks,
146
158
  in this order.** A required final step, not cleanup etiquette. Each
147
159
  abandoned worktree pins its HEAD commit against `gc` and adds a
148
160
  `.git/worktrees` admin entry, so the object store grows monotonically.
@@ -155,7 +167,7 @@ rediscovering these the hard way:
155
167
  it. Usually fine (a gate merge is reproducible by redoing it) but say so
156
168
  in your report rather than doing it silently.
157
169
  Then `git worktree remove <wt>` — **plain, no `--force`.** Its rc=128 refusal backstops
158
- ONLY untracked/modified content (see rule 8 on `rm -r`) — it does NOT cover gitignored
170
+ ONLY untracked/modified content (see rule 9 on `rm -r`) — it does NOT cover gitignored
159
171
  content, which git removes silently with no refusal; a clean rc=0 is not proof nothing of
160
172
  value was in there (see coordinator-assessing-agent-completion's reap procedure). `--force`
161
173
  is a justified override only, never the default (see coordinator-merging-code §7a).
@@ -169,6 +181,21 @@ config entry (see `lens_scope_semantics` in the config), which still runs on
169
181
  every diff regardless of trigger directories. If the config has no
170
182
  `trigger_directories`, fail with guidance to run `project-hotpath-gate`.
171
183
 
184
+ ## Invariant-ratchet lenses
185
+
186
+ A lens may declare `mandatory_test_command` (see `census_classification_coverage`
187
+ and `write_owner_bypass_ratchet` in `.thrum/hotpath-gate.json`) instead of
188
+ (or alongside) a pattern-match `question`/`required_evidence` pair. When
189
+ present, PASS/FAIL is the command's own exit code — never a judgment call
190
+ from reading the diff. This is the shape for any invariant that already has
191
+ a mechanical detector: wire the detector as an `always_run` lens with a
192
+ monotonic budget (a count that may only decrease, or an explicit
193
+ waiver-tagged exception), so a diff cannot silently re-widen the invariant
194
+ in the same change that appears to narrow it. `write_owner_bypass_ratchet`
195
+ is the reference instance: it fails a merge that bumps a
196
+ ceiling/aggregate in the ledger file without a `RATCHET-WAIVER:` tag, even
197
+ when the ledger-equality test alone would pass.
198
+
172
199
  ## Delta re-gate continuity — walk the whole branch, read the whole function
173
200
 
174
201
  **Why:** A commit introducing a lock can be an ancestor of a delta-re-gate's
@@ -432,7 +459,7 @@ hoc test target nothing routes to. A merge that adds a `state.NewState(...)`
432
459
  call site in an `internal/daemon/rpc/*_test.go` file (test-fixture setup, not a
433
460
  handler) can leave it unclassified and desync the frozen census snapshot with
434
461
  no gate catching it — trunk went RED post-merge on 573mo v87 for exactly this
435
- reason (thrum-ykmly).
462
+ reason.
436
463
 
437
464
  **Relationship to Lenses 1–10:** every other lens in this file is an
438
465
  LLM-judgment pattern check — grep a pattern, read the surrounding code, apply
@@ -476,7 +503,7 @@ diff on `TestCensusRegeneration`'s brittleness with zero added
476
503
  defect-prevention (`ClassificationCoverage` alone already catches the defect
477
504
  this lens exists for). `TestCensusRegeneration`'s own staleness is tracked
478
505
  separately (nd2j1/P1 owns the classification data; the brittle count-snapshot
479
- assertion itself is tracked as **thrum-33zzh** — "make advisory or drop the
506
+ assertion itself is a distinct open question — "make advisory or drop the
480
507
  raw-count assertion"), not by this lens.
481
508
 
482
509
  **Severity:** Trigger fires and `mandatory_test_command` was not run before
@@ -520,10 +547,24 @@ otherwise leave them.
520
547
 
521
548
  ## If it fails
522
549
 
523
- Send it back as a normal review finding — same channel as dual-review output,
524
- folded into the same numbered list if dual review is still open, or as its own
525
- short reply if dual review already passed. Cite the offending function/file,
526
- which lens it failed, and the config value that triggered the finding.
550
+ For a genuine hot-path/perf defect, a production-behaviour change, or a design
551
+ judgment call: send it back as a normal review finding — same channel as
552
+ dual-review output, folded into the same numbered list if dual review is still
553
+ open, or as its own short reply if dual review already passed. Cite the
554
+ offending function/file, which lens it failed, and the config value that
555
+ triggered the finding.
556
+
557
+ For mechanical bookkeeping only (census/shard regen via the tool, line-number
558
+ or key refreshes, ledger totals/ceilings where the arithmetic is derivable, a
559
+ per-entry waiver or citation comment recording a classification already
560
+ established elsewhere (never a new safety judgment of your own), a nosec
561
+ baseline hash for an already-reviewed pattern, comment wording, stale test
562
+ expectations that merely follow a landed change): fix it yourself as a
563
+ `GATE-AUTHORED` commit on your
564
+ `gate/` branch, re-run ONLY the lens(es) the fix affects, and report
565
+ `CLEAN-WITH-GATE-FIXES` listing each fix instead of bouncing it to the owner.
566
+ When unsure which bucket a finding falls in, ask the coordinator with the exact
567
+ diff — don't bounce reflexively.
527
568
 
528
569
  ## Efficacy tracking (v1 acceptance requirement)
529
570
 
@@ -563,6 +604,7 @@ rows.
563
604
  | `FALSE_POSITIVE` | Gate flagged something correct — record which lens and why |
564
605
  | `SLIPPED` | A wedge occurred AFTER merge that the gate did not catch |
565
606
  | `SKIPPED_WITH_EVIDENCE` | Gate deliberately skipped (no trigger dirs), evidence cited |
607
+ | `CLEAN-WITH-GATE-FIXES` | Gate found only mechanical bookkeeping gaps, fixed them itself as a GATE-AUTHORED commit, re-ran only the affected checks, merge proceeded |
566
608
 
567
609
  **Retrospective reclassification:** When triaging a new wedge or incident, grep
568
610
  `dev-docs/hotpath-gate-efficacy.md` for the merged branch/date. If the gate
@@ -591,4 +633,4 @@ gaps and lens improvements for the next version.
591
633
  first gate run, appended after each run)
592
634
 
593
635
  <!-- THRUM-GATE: stage=skill next=review -->
594
- <!-- THRUM-REVIEW: stage=skill verdict=Ready:Yes cycle=2 date=2026-07-10 -->
636
+ <!-- THRUM-REVIEW: stage=skill verdict=Ready:Yes cycle=2 -->
@@ -57,8 +57,11 @@ created from origin, unpushed commits can be lost or inaccessible.
57
57
 
58
58
  **How to apply:** Session close protocol — push the coordination branch every
59
59
  session end. **Read the branch name, never recall it:**
60
- `jq -r '.orchestration.merge_target' .thrum/config.json` (or your project's
61
- CLAUDE.md § Branching Strategy). Push every `feature/*` and `fix/*` branch too.
60
+ `CONFIG=.thrum/config.json; [ -f .thrum/redirect ] && CONFIG="$(cat .thrum/redirect)/config.json"; jq -r '.orchestration.merge_target' "$CONFIG"`
61
+ (a worktree's `.thrum/` holds only a `redirect` file pointing at the main
62
+ repo's `.thrum` dir, so reading `.thrum/config.json` directly there returns
63
+ empty) — or your project's CLAUDE.md § Branching Strategy. Push every
64
+ `feature/*` and `fix/*` branch too.
62
65
  A docs/site branch pushes only when the site is ready to deploy; `main` and
63
66
  `release/*` go through the release flow.
64
67
 
@@ -77,10 +80,7 @@ batch — the visual tree exposes inversion immediately. For bulk epic creation
77
80
  (many tasks at once), spawn parallel sub-agents to issue the `bd create` calls;
78
81
  bd is fully concurrent-safe.
79
82
 
80
- > **Model tiers:** pass an explicit `model:` on every dispatch — `sonnet`
81
- > (low effort) mechanical, `sonnet` (medium effort) judgment, Opus only on
82
- > operator-ask or a skill step that names it. See the
83
- > `choosing-subagent-models` skill for the full policy.
83
+ > **Model tiers:** pass an explicit `model:` on every dispatch; choose model and effort per the `choosing-subagent-models` skill (read `runtime.role_models` at the moment of use). Never let a sub-agent inherit your own model.
84
84
 
85
85
  ## Use `bd close --suggest-next` to surface unblocked work
86
86