opencode-thrum-pro 0.1.0
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.
- package/assets/commands/thrum-_deviations-protocol.md +87 -0
- package/assets/commands/thrum-_generator-idempotency-protocol.md +15 -0
- package/assets/commands/thrum-_project-rules-protocol.md +18 -0
- package/assets/commands/thrum-_snapshot-protocol.md +265 -0
- package/assets/commands/thrum-_stamp-protocol.md +112 -0
- package/assets/commands/thrum-_verify-before-write-protocol.md +27 -0
- package/assets/commands/thrum-inbox.md +22 -0
- package/assets/commands/thrum-load-context.md +17 -0
- package/assets/commands/thrum-overview.md +17 -0
- package/assets/commands/thrum-prime.md +30 -0
- package/assets/commands/thrum-quickstart.md +14 -0
- package/assets/commands/thrum-reply.md +28 -0
- package/assets/commands/thrum-restart-extended.md +195 -0
- package/assets/commands/thrum-restart.md +293 -0
- package/assets/commands/thrum-send.md +31 -0
- package/assets/commands/thrum-sleep-extended.md +186 -0
- package/assets/commands/thrum-sleep.md +212 -0
- package/assets/commands/thrum-team.md +12 -0
- package/assets/commands/thrum-update-project.md +259 -0
- package/assets/commands/thrum-wait.md +14 -0
- package/assets/skills/adversarial-critique/SKILL.md +242 -0
- package/assets/skills/brainstorm-queue-aware/SKILL.md +167 -0
- package/assets/skills/brainstorm-steward/SKILL.md +181 -0
- package/assets/skills/choosing-subagent-models/SKILL.md +244 -0
- package/assets/skills/closing-findings-while-warm/SKILL.md +104 -0
- package/assets/skills/configure-roles/SKILL.md +229 -0
- package/assets/skills/coordinator-assessing-agent-completion/SKILL.md +205 -0
- package/assets/skills/coordinator-assessing-agent-completion/scan.py +117 -0
- package/assets/skills/coordinator-branch-split-on-block/SKILL.md +168 -0
- package/assets/skills/coordinator-context-monitoring/SKILL.md +674 -0
- package/assets/skills/coordinator-dispatching-work/SKILL.md +288 -0
- package/assets/skills/coordinator-hotpath-merge-gate/SKILL.md +522 -0
- package/assets/skills/coordinator-interacting-with-the-owner/SKILL.md +171 -0
- package/assets/skills/coordinator-maintaining-memory/SKILL.md +89 -0
- package/assets/skills/coordinator-managing-state-and-lifecycle/SKILL.md +192 -0
- package/assets/skills/coordinator-merging-code/SKILL.md +331 -0
- package/assets/skills/coordinator-philosophy-merge-gate/SKILL.md +442 -0
- package/assets/skills/coordinator-plan-reconcile-gate/SKILL.md +198 -0
- package/assets/skills/coordinator-post-restart-sweep/SKILL.md +135 -0
- package/assets/skills/coordinator-running-autonomous-feature-development/SKILL.md +199 -0
- package/assets/skills/coordinator-running-brainstorm-cycles/SKILL.md +654 -0
- package/assets/skills/coordinator-running-review-cycles/SKILL.md +153 -0
- package/assets/skills/coordinator-single-responsibility-merge-gate/SKILL.md +14 -0
- package/assets/skills/diagnosing-fleet-and-daemon/SKILL.md +255 -0
- package/assets/skills/efficient-multi-agent-research/SKILL.md +177 -0
- package/assets/skills/fixing-documentation-errors/SKILL.md +258 -0
- package/assets/skills/implementer-maintaining-memory/SKILL.md +84 -0
- package/assets/skills/implementer-orchestrating-execution/SKILL.md +125 -0
- package/assets/skills/implementer-receiving-dispatch/SKILL.md +127 -0
- package/assets/skills/implementer-receiving-review-feedback/SKILL.md +125 -0
- package/assets/skills/implementer-status-and-handoff/SKILL.md +150 -0
- package/assets/skills/implementer-tdd-and-quality/SKILL.md +99 -0
- package/assets/skills/memory-audit-recover/SKILL.md +153 -0
- package/assets/skills/memory-curate/SKILL.md +139 -0
- package/assets/skills/memory-maintenance/SKILL.md +87 -0
- package/assets/skills/memory-read-discipline/SKILL.md +164 -0
- package/assets/skills/memory-search-advanced/SKILL.md +217 -0
- package/assets/skills/memory-write-discipline/SKILL.md +135 -0
- package/assets/skills/orchestrate/SKILL.md +795 -0
- package/assets/skills/persistent-watcher-archetype/SKILL.md +225 -0
- package/assets/skills/prime-agent/SKILL.md +92 -0
- package/assets/skills/project-hotpath-gate/SKILL.md +255 -0
- package/assets/skills/project-philosophy/SKILL.md +418 -0
- package/assets/skills/project-philosophy/resources/philosophy-template.md +155 -0
- package/assets/skills/project-philosophy/resources/reliability-class-library.md +653 -0
- package/assets/skills/project-setup/SKILL.md +1007 -0
- package/assets/skills/project-setup/resources/implementation-agent.md +826 -0
- package/assets/skills/researcher-answering-queries/SKILL.md +100 -0
- package/assets/skills/researcher-investigating/SKILL.md +152 -0
- package/assets/skills/researcher-maintaining-memory/SKILL.md +176 -0
- package/assets/skills/state-migration/SKILL.md +54 -0
- package/assets/skills/thrum/SKILL.md +161 -0
- package/assets/skills/thrum/resources/ANTI_PATTERNS.md +132 -0
- package/assets/skills/thrum/resources/BOUNDARIES.md +56 -0
- package/assets/skills/thrum/resources/CLI_REFERENCE.md +1066 -0
- package/assets/skills/thrum/resources/IDENTITY.md +49 -0
- package/assets/skills/thrum/resources/LISTENER_PATTERN.md +64 -0
- package/assets/skills/thrum/resources/MESSAGING.md +163 -0
- package/assets/skills/thrum/resources/TMUX_SESSIONS.md +118 -0
- package/assets/skills/thrum/resources/WORKTREES.md +117 -0
- package/assets/skills/thrum-memory/SKILL.md +138 -0
- package/assets/skills/trace-spec-to-plan/SKILL.md +104 -0
- package/assets/skills/trace-spec-to-plan/resources/sweep-agent-prompt.md +57 -0
- package/assets/skills/update-queue/SKILL.md +149 -0
- package/assets/skills/using-the-queue/SKILL.md +172 -0
- package/assets/skills/using-thrum-state/SKILL.md +104 -0
- package/assets/skills/verify-against-plan/SKILL.md +323 -0
- package/assets/skills/verify-against-source/SKILL.md +237 -0
- package/assets/skills/watcher-archetype/SKILL.md +84 -0
- package/assets/skills/writing-durable-markdown/SKILL.md +66 -0
- package/dist/hooks/block-sync-cd.d.ts +9 -0
- package/dist/hooks/block-sync-cd.js +71 -0
- package/dist/hooks/block-sync-cd.test.d.ts +1 -0
- package/dist/hooks/block-sync-cd.test.js +61 -0
- package/dist/hooks/shell-env.d.ts +8 -0
- package/dist/hooks/shell-env.js +22 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +25 -0
- package/dist/installer.d.ts +2 -0
- package/dist/installer.js +86 -0
- package/package.json +49 -0
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: coordinator-hotpath-merge-gate
|
|
3
|
+
description: "Use when ABOUT TO START a hot-path Pass-3 gate - a gate has been dispatched to you, you are picking up a queued gate, you are the Gate Runner beginning a gate, you are about to walk hot-path lenses - and when a coordinator is about to run git merge after dual review came back clean. Loads the gate-runner restart rule (restart at ~50 percent, at a seam BETWEEN gates) plus the hot-path and perf lenses read from .thrum/hotpath-gate.json. Trigger-scoped lenses skip on a mechanical zero-match against the configured trigger directories, paired with a firing positive control, for branches touching RPC handlers, projection writers, storage openers, sync code, peer dial paths, or daemon boot paths - not CLI helpers, tests-only, docs, or website. Any lens flagged always_run in the config runs on EVERY commit regardless of directory, including the master-giant-process batch-decomposition lens."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Coordinator: Hot-Path Merge Gate
|
|
7
|
+
|
|
8
|
+
## Before you start this gate — restart if you cannot finish it
|
|
9
|
+
|
|
10
|
+
**Finish the gate you are in. Never restart mid-gate.** A finding that exists only
|
|
11
|
+
in your context is one restart from gone.
|
|
12
|
+
|
|
13
|
+
**Then restart at the seam — after the report is delivered, before taking anything
|
|
14
|
+
else.** Do not carry context across a gate boundary.
|
|
15
|
+
|
|
16
|
+
**Do not START a new gate above ~50% context.** A full dual gate costs roughly 14%.
|
|
17
|
+
Starting one you cannot finish is how a gate ends thin on its own verdict.
|
|
18
|
+
|
|
19
|
+
**Why the boundary is the gate and not a number - a gate runner is static.** Each gate
|
|
20
|
+
is scoped, evidenced, and delivered self-contained; State.md carries what must persist.
|
|
21
|
+
Nothing accumulates across gates, so context held past a gate boundary buys nothing and
|
|
22
|
+
costs money.
|
|
23
|
+
|
|
24
|
+
**This is NOT the orchestrator rule.** An orchestrator is building something and its
|
|
25
|
+
context is the work - it pushes through until its current plan is implemented and
|
|
26
|
+
restarts then, at 30% or at 60%. Interrupting an implementation to hit a number is the
|
|
27
|
+
wrong move. A gate is short and self-contained, so its boundary comes often and costs
|
|
28
|
+
nothing to take.
|
|
29
|
+
|
|
30
|
+
**The coordinator may overrule either rule for a sustained campaign** - a push to get trunk
|
|
31
|
+
green, an incident, a release cutover - where continuity across many units is worth more than
|
|
32
|
+
a clean seam. That is an explicit decision, stated at the time. It is never drift.
|
|
33
|
+
|
|
34
|
+
**Measure by pane, in the same command block that reports the number.** A figure carried
|
|
35
|
+
forward from earlier in the session is a memory, not a measurement.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## Why this is a separate pass, not a philosophy-gate lens
|
|
40
|
+
|
|
41
|
+
`coordinator-philosophy-merge-gate` catches general structural anti-patterns
|
|
42
|
+
(raw `exec.Command`, shell passthrough, SRP violations). This gate catches
|
|
43
|
+
**hot-path/perf-specific** anti-patterns — silent fail-open, unconditional
|
|
44
|
+
writes in dual-source paths, shared-resource poisoning, pattern divergence,
|
|
45
|
+
coincidence- detector tests, incomplete-class-fixes, dead-row pre-filter gaps,
|
|
46
|
+
and peer-dial circuit-breaker gaps — that the philosophy gate does not cover.
|
|
47
|
+
See the config's per-lens `context` prose for the project's incident history and
|
|
48
|
+
what the philosophy gate caught vs. missed.
|
|
49
|
+
|
|
50
|
+
Where the two gates overlap (subprocess-in-hot-path,
|
|
51
|
+
dispatch-goroutine-blocking, pattern divergence, coincidence-tests), this gate
|
|
52
|
+
goes deeper with specific detection rules. If the philosophy gate already
|
|
53
|
+
flagged a finding, this gate should **upgrade** it with the deeper analysis, not
|
|
54
|
+
duplicate it. The coordinator consolidates findings from both gates into one
|
|
55
|
+
numbered list.
|
|
56
|
+
|
|
57
|
+
## Config-driven design
|
|
58
|
+
|
|
59
|
+
This skill reads `.thrum/hotpath-gate.json` at invocation time. The config
|
|
60
|
+
provides:
|
|
61
|
+
|
|
62
|
+
- **Trigger directories** — which directories in the diff activate this gate
|
|
63
|
+
- **Pattern fields** — grep strings, function names for automated triage
|
|
64
|
+
- **Reference patterns** — established working patterns to check divergence
|
|
65
|
+
against
|
|
66
|
+
- **Context prose** — incident descriptions, fix patterns for the LLM reviewer's
|
|
67
|
+
judgment
|
|
68
|
+
|
|
69
|
+
The lenses below are codebase-agnostic. All project-specific values come from
|
|
70
|
+
the config. The companion `project-hotpath-gate` skill generates/updates the
|
|
71
|
+
config from codebase inspection (like `project-philosophy` generates
|
|
72
|
+
`.thrum/philosophy.md`). If no config exists, fail with guidance to run
|
|
73
|
+
`project-hotpath-gate` first.
|
|
74
|
+
|
|
75
|
+
**How to apply: DISPATCH THIS GATE TO THE GATE RUNNER. Do not walk the lenses in
|
|
76
|
+
your own context.**
|
|
77
|
+
|
|
78
|
+
The gate runner is a standing agent whose entire purpose is to hold gate work
|
|
79
|
+
OUTSIDE the coordinator's context — resolve the current one from `thrum team` by
|
|
80
|
+
its `gate` ROLE, never by a remembered name. It runs the lenses in an ephemeral worktree, produces
|
|
81
|
+
a verdict, and tears the worktree down. **You read `.thrum/hotpath-gate.json` to
|
|
82
|
+
build the dispatch, then you consolidate the verdict and decide. You do not run
|
|
83
|
+
the lenses.**
|
|
84
|
+
|
|
85
|
+
**This is the default for EVERY diff size.** Diff size changes what you ask for;
|
|
86
|
+
it never changes who runs it. A coordinator that walks the lenses inline burns
|
|
87
|
+
the one resource it cannot replace and leaves no durable verdict artifact.
|
|
88
|
+
|
|
89
|
+
**Only run it yourself when there is NO gate-role agent available**, and say so
|
|
90
|
+
explicitly in the merge record so the gap is visible rather than invisible.
|
|
91
|
+
|
|
92
|
+
**Verdicts are artifacts:** the runner saves them to
|
|
93
|
+
`dev-docs/gate-reports/<ISO-week>/<date>/<gate-slug>/` and commits them BEFORE
|
|
94
|
+
removing any worktree. A verdict that exists only in a message cannot be audited
|
|
95
|
+
later.
|
|
96
|
+
|
|
97
|
+
## Gate dispatch preamble
|
|
98
|
+
|
|
99
|
+
Mandatory checklist handed to the GATE RUNNER (and to any sub-agent it spawns in
|
|
100
|
+
turn) at dispatch time. Each
|
|
101
|
+
rule below currently lives only as prose warnings scattered through
|
|
102
|
+
`dev-docs/hotpath-gate-efficacy.md` and gets re-learned per session — hand this
|
|
103
|
+
list to the sub-agent verbatim at dispatch time instead of relying on it
|
|
104
|
+
rediscovering these the hard way:
|
|
105
|
+
|
|
106
|
+
1. Read code via `git show <target-sha>:<path>`, NEVER the working tree — tree
|
|
107
|
+
state != the SHA under review.
|
|
108
|
+
2. Build/test ONLY in a throwaway detached worktree
|
|
109
|
+
(`git worktree add <tmp> <sha> --detach`), never the shared checkout.
|
|
110
|
+
3. RUN any test you make a claim about — never judge from reading it.
|
|
111
|
+
4. Diff against `merge-base`, never two-dot against tip — a two-dot diff
|
|
112
|
+
against tip pulls in unrelated lines from sibling branches and
|
|
113
|
+
manufactures a false regression signal.
|
|
114
|
+
5. Run `git merge-base --is-ancestor` as an explicit gate condition (the
|
|
115
|
+
fast-forward check) — git silently deduplicates content-identical commits
|
|
116
|
+
on both sides of a rebase, so a tree that "builds clean" can still be
|
|
117
|
+
carrying dupes instead of the real content.
|
|
118
|
+
6. Run full-package `-race`, not targeted `-run` — a targeted race run misses
|
|
119
|
+
cross-test races.
|
|
120
|
+
7. Build+test the MERGED-tree result as a SEPARATE condition — neither gate
|
|
121
|
+
currently runs a build of the actual post-merge tree; a clean pre-merge
|
|
122
|
+
build/test does not prove the merged result compiles or passes.
|
|
123
|
+
8. Use `rm -r`, NEVER `rm -rf`, and use `git worktree remove --force` to drop a
|
|
124
|
+
worktree. A broad `ask` rule on `rm -rf *` outranks any narrow `/tmp` allow,
|
|
125
|
+
so `rm -rf` raises a human permission prompt EVERY time regardless of path —
|
|
126
|
+
it stalls gate sub-agents mid-run waiting on a keystroke. `rm -r` runs free. Do NOT widen the ask rule
|
|
127
|
+
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.
|
|
135
|
+
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
|
|
137
|
+
mutation in the SHARED repo.** Do read-only inspection there (`git show
|
|
138
|
+
<sha>:<path>`, `git log`, `git diff`) and do every build/test in a throwaway
|
|
139
|
+
detached worktree. `git stash` is a SINGLE SHARED STACK across every
|
|
140
|
+
worktree of a repo, so "cleaning up after myself" can strand or clobber
|
|
141
|
+
another agent's live work; and the shared repo is POPULATED — live agents
|
|
142
|
+
hold uncommitted `State.md` they are actively re-authoring.
|
|
143
|
+
If you believe you must mutate the shared tree, STOP and report instead —
|
|
144
|
+
that is always a finding, never a step.
|
|
145
|
+
12. **TEAR DOWN YOUR THROWAWAY WORKTREE WHEN THE GATE ENDS — after two checks,
|
|
146
|
+
in this order.** A required final step, not cleanup etiquette. Each
|
|
147
|
+
abandoned worktree pins its HEAD commit against `gc` and adds a
|
|
148
|
+
`.git/worktrees` admin entry, so the object store grows monotonically.
|
|
149
|
+
Before removing:
|
|
150
|
+
(a) `git -C <wt> status --porcelain` — if NON-EMPTY, **STOP and report it
|
|
151
|
+
instead of removing.** Uncommitted work in a throwaway worktree exists
|
|
152
|
+
NOWHERE else; this is the category that actually loses work.
|
|
153
|
+
(b) `git branch -a --contains $(git -C <wt> rev-parse HEAD)` — if EMPTY,
|
|
154
|
+
HEAD is a gate-produced merge reachable from no ref and removal orphans
|
|
155
|
+
it. Usually fine (a gate merge is reproducible by redoing it) but say so
|
|
156
|
+
in your report rather than doing it silently.
|
|
157
|
+
Then `git worktree remove --force <wt>`.
|
|
158
|
+
|
|
159
|
+
## Trigger-directory skip logic
|
|
160
|
+
|
|
161
|
+
Before walking the lenses, check if the diff touches any directory in
|
|
162
|
+
`config.trigger_directories`. If not, skip the trigger-scoped lenses and run
|
|
163
|
+
only the philosophy gate — EXCEPT any lens carrying `"always_run": true` in its
|
|
164
|
+
config entry (see `lens_scope_semantics` in the config), which still runs on
|
|
165
|
+
every diff regardless of trigger directories. If the config has no
|
|
166
|
+
`trigger_directories`, fail with guidance to run `project-hotpath-gate`.
|
|
167
|
+
|
|
168
|
+
## Delta re-gate continuity — walk the whole branch, read the whole function
|
|
169
|
+
|
|
170
|
+
**Why:** A commit introducing a lock can be an ancestor of a delta-re-gate's
|
|
171
|
+
base and never appear in any walked diff, even when a later commit edits the
|
|
172
|
+
gating condition on that call. Root cause: the gate is delta-scoped. The diff
|
|
173
|
+
hunk showing the edited condition never revealed the enclosing locked span
|
|
174
|
+
above it.
|
|
175
|
+
|
|
176
|
+
**Rules:**
|
|
177
|
+
|
|
178
|
+
- The FIRST gate run on a branch walks `merge-base(target, tip)..tip`, NOT a
|
|
179
|
+
recent delta.
|
|
180
|
+
- A delta re-gate MUST state the prior gated SHA and assert continuity:
|
|
181
|
+
`prior-gated-sha == delta-base`, verified via `git merge-base --is-ancestor`
|
|
182
|
+
or direct SHA equality. If the prior-gated SHA is NOT the delta base,
|
|
183
|
+
re-walk from `merge-base` — there is unwalked history between the two.
|
|
184
|
+
- Lens 1 (subprocess hot path) and Lens 2 (dispatch-blocking) greps run at
|
|
185
|
+
changed-FILE scope, then READ THE FULL ENCLOSING FUNCTION — a diff hunk
|
|
186
|
+
inside a locked span cannot show you the `Lock()` above it. A changed line
|
|
187
|
+
whose semantics depend on a lock/defer/subprocess further up the function is
|
|
188
|
+
only visible at function scope, never at hunk scope.
|
|
189
|
+
|
|
190
|
+
## Lens 1 — Subprocess in the per-request hot path
|
|
191
|
+
|
|
192
|
+
**Why:** The single most recurring wedge class. Per-request or per-heartbeat
|
|
193
|
+
work that forks a subprocess, compounding under fleet scale.
|
|
194
|
+
|
|
195
|
+
**Relationship to philosophy gate:** Cross-refs Philosophy Lens 1 (raw
|
|
196
|
+
`exec.Command` in daemon code) — goes deeper by checking per-RPC path membership
|
|
197
|
+
and mitigation patterns.
|
|
198
|
+
|
|
199
|
+
**How to apply:** Read `config.lenses.subprocess_hot_path`. Grep changed files
|
|
200
|
+
for `subprocess_patterns`. For each hit, check if the calling function is
|
|
201
|
+
reachable from a `hot_path_indicators` function in a `hot_path_files` path —
|
|
202
|
+
follow one call-level into changed helpers (subprocess calls may live one call
|
|
203
|
+
below the handler). If yes, verify three mitigations: (1)
|
|
204
|
+
`pre_flight_guard_pattern` before the fork, (2) `non_blocking_read_pattern`
|
|
205
|
+
before blocking extraction, (3) consider `native_alternatives`. Read the
|
|
206
|
+
`context` prose.
|
|
207
|
+
|
|
208
|
+
**Severity:** Missing all three mitigations on a new hot-path subprocess call —
|
|
209
|
+
**BLOCKING**.
|
|
210
|
+
|
|
211
|
+
**Triage:**
|
|
212
|
+
`git diff main...HEAD --name-only | xargs grep -ln '{subprocess_patterns}'`
|
|
213
|
+
|
|
214
|
+
## Lens 2 — Dispatch-goroutine-blocking on expensive work
|
|
215
|
+
|
|
216
|
+
**Why:** Blocking the request-dispatch goroutine on expensive I/O starves other
|
|
217
|
+
requests. A shared lock held across I/O is the overarching contention point.
|
|
218
|
+
|
|
219
|
+
**Relationship to philosophy gate:** Cross-refs Philosophy Lens 10d (cost gate:
|
|
220
|
+
shared lock across I/O or drain) — goes deeper by checking
|
|
221
|
+
Peek+background-refresh and lock-hold-time minimization.
|
|
222
|
+
|
|
223
|
+
**How to apply:** Read `config.lenses.dispatch_blocking`. For any new/changed
|
|
224
|
+
handler: does it acquire a `lock_patterns` lock? Is I/O performed under the
|
|
225
|
+
lock? Is the lock released before `post_commit_pattern` work? For new caches: is
|
|
226
|
+
there a `cache_peek_pattern`? Is extraction moved to
|
|
227
|
+
`background_detach_pattern`? Is there `singleflight_pattern` coalescing? For
|
|
228
|
+
per-item loops: batched or per-item lock? Also check: does a new scheduler/cron
|
|
229
|
+
job emit durable-lane events at a rate that could saturate the write pool? Read
|
|
230
|
+
the `context` prose.
|
|
231
|
+
|
|
232
|
+
**Severity:** New handler holds lock across I/O, or lacks Peek+background for
|
|
233
|
+
expensive cacheable data — **BLOCKING**.
|
|
234
|
+
|
|
235
|
+
**Triage:** `git diff main...HEAD --name-only | xargs grep -n '{lock_patterns}'`
|
|
236
|
+
|
|
237
|
+
## Lens 3 — Silent fail-open instead of fail-closed
|
|
238
|
+
|
|
239
|
+
**Why:** Missing/mismatched data silently falls through to wrong-but-plausible
|
|
240
|
+
data instead of erroring. The second most common wedge class.
|
|
241
|
+
|
|
242
|
+
**Relationship to philosophy gate:** No philosophy.md equivalent — new pattern.
|
|
243
|
+
|
|
244
|
+
**How to apply:** Read `config.lenses.silent_fail_open`. For any function
|
|
245
|
+
resolving identity/path/state: does it have a fallback when the target is
|
|
246
|
+
missing? Does the fallback return a _different_ identity/path than requested?
|
|
247
|
+
For identity resolution: does it hard-error on mismatch (check
|
|
248
|
+
`identity_validation_patterns`)? For liveness computation: does it use
|
|
249
|
+
`canonical_predicate` or compute ad-hoc? For file writes to shared resources:
|
|
250
|
+
does it use `append_patterns` instead of truncate-with-guard? Read the `context`
|
|
251
|
+
prose.
|
|
252
|
+
|
|
253
|
+
**Severity:** Silently adopts wrong data on missing/mismatched input —
|
|
254
|
+
**BLOCKING**. Falls back to default without erroring — **IMPORTANT**.
|
|
255
|
+
|
|
256
|
+
**Triage:**
|
|
257
|
+
`git diff main...HEAD --name-only | xargs grep -n '{fallback_patterns}'`
|
|
258
|
+
|
|
259
|
+
## Lens 4 — Unconditional write in a shared dual-source path
|
|
260
|
+
|
|
261
|
+
**Why:** A shared apply path handling both local writes AND sync-merged events.
|
|
262
|
+
Writers without timestamp guards allow older sync events to clobber newer local
|
|
263
|
+
edits.
|
|
264
|
+
|
|
265
|
+
**Relationship to philosophy gate:** No philosophy.md equivalent — new pattern.
|
|
266
|
+
|
|
267
|
+
**How to apply:** Read `config.lenses.unconditional_write_dual_source`. For any
|
|
268
|
+
new/changed writer in `shared_apply_path`: does it use
|
|
269
|
+
`unconditional_write_patterns` (e.g. `INSERT OR REPLACE`, bare
|
|
270
|
+
`UPDATE`/`DELETE`)? Must use `conflict_guard_patterns`. Are side effects gated
|
|
271
|
+
on `side_effect_gating_pattern` (e.g. `RowsAffected() > 0`)? Does it mirror
|
|
272
|
+
`reference_guarded_writers`? Read the `context` prose.
|
|
273
|
+
|
|
274
|
+
**Severity:** Writer in shared apply path lacks conflict guards — **BLOCKING**.
|
|
275
|
+
Side effects not gated on RowsAffected — **BLOCKING**.
|
|
276
|
+
|
|
277
|
+
**Triage:**
|
|
278
|
+
`git diff main...HEAD --name-only | xargs grep -n '{unconditional_write_patterns}'`
|
|
279
|
+
|
|
280
|
+
## Lens 5 — Shared-resource poisoning by an auxiliary code path
|
|
281
|
+
|
|
282
|
+
**Why:** A secondary code path (backup, CLI helper, hook) mutates a shared
|
|
283
|
+
resource in a way that corrupts the primary path's state. Looks correct in
|
|
284
|
+
isolation.
|
|
285
|
+
|
|
286
|
+
**Relationship to philosophy gate:** No philosophy.md equivalent — new pattern.
|
|
287
|
+
|
|
288
|
+
**How to apply:** Read `config.lenses.shared_resource_poisoning`. For any
|
|
289
|
+
resource open in a non-primary path: does it use `read_write_db_open_patterns`
|
|
290
|
+
when the consumer only reads? Must use `read_only_db_open`. Follow
|
|
291
|
+
`reference_read_only` pattern. Check `wal_checkpoint_patterns` — any
|
|
292
|
+
`PRAGMA wal_checkpoint` or explicit checkpoint call on the daemon path. Check
|
|
293
|
+
`raw_sql_patterns` — raw `db.Query`/`db.Exec` bypasses `safedb_wrapper`'s 522/
|
|
294
|
+
malformed retry. For file writes to shared resources: does it use
|
|
295
|
+
`append_patterns`? Must use truncate-with-ownership-guard or
|
|
296
|
+
`atomic_write_patterns`. Read the `context` prose.
|
|
297
|
+
|
|
298
|
+
**Severity:** Auxiliary path opens shared resource read-write when read-only
|
|
299
|
+
suffices — **BLOCKING**. Raw `sql.DB` on daemon path bypassing safedb —
|
|
300
|
+
**BLOCKING**. Writes to shared file without ownership guard — **BLOCKING**.
|
|
301
|
+
|
|
302
|
+
**Triage:**
|
|
303
|
+
`git diff main...HEAD --name-only | xargs grep -n '{read_write_db_open_patterns}|{wal_checkpoint_patterns}|{raw_sql_patterns}'`
|
|
304
|
+
|
|
305
|
+
## Lens 6 — Pattern divergence from established working pattern
|
|
306
|
+
|
|
307
|
+
**Why:** A new feature introduces a code path that omits a pattern the existing
|
|
308
|
+
code already got right — because the pattern wasn't enforced structurally.
|
|
309
|
+
|
|
310
|
+
**Relationship to philosophy gate:** Partial thematic overlap with Philosophy
|
|
311
|
+
Lenses 10b (naming test) and 10d (cost gate) — but this lens is about structural
|
|
312
|
+
pattern mirroring, not naming or cost. No duplication risk.
|
|
313
|
+
|
|
314
|
+
**How to apply:** Read `config.lenses.pattern_divergence.reference_patterns`.
|
|
315
|
+
For each reference pattern, check if the diff introduces a new code path that
|
|
316
|
+
should follow it. Does the new code match the `check` description? Does it use
|
|
317
|
+
`current_pattern` (not `legacy_pattern` where one is specified)? Is there a
|
|
318
|
+
`tripwire_test`? Read each pattern's `context` prose.
|
|
319
|
+
|
|
320
|
+
**Severity:** Divergence from a proven-incident reference pattern (in the
|
|
321
|
+
config's `reference_patterns` list) — **BLOCKING**. Divergence from a convention
|
|
322
|
+
not in the proven-incident list — **IMPORTANT**.
|
|
323
|
+
|
|
324
|
+
**Triage:** For each reference pattern, grep changed files for its
|
|
325
|
+
`legacy_pattern` (if present) or its `current_pattern` to verify usage.
|
|
326
|
+
|
|
327
|
+
## Lens 7 — Coincidence-detector test
|
|
328
|
+
|
|
329
|
+
**Why:** Green tests that don't assert the actual invariant provide false
|
|
330
|
+
confidence at merge time — worse than no tests.
|
|
331
|
+
|
|
332
|
+
**Relationship to philosophy gate:** Partial thematic overlap with Philosophy
|
|
333
|
+
Lens 6 (trusting documented behavior) — but this lens is about trusting
|
|
334
|
+
**tests** that pass without proving the invariant, not trusting comments/docs.
|
|
335
|
+
No duplication risk.
|
|
336
|
+
|
|
337
|
+
**How to apply:** Read `config.lenses.coincidence_detector_tests`. For any new
|
|
338
|
+
test (files matching `test_file_pattern`): does it assert the actual invariant
|
|
339
|
+
(not just "no error")? Would it fail if the behavior were wrong? Does it rely on
|
|
340
|
+
ambient shell state? For regression tests: does it assert the specific fix? Is
|
|
341
|
+
it a tripwire (check `tripwire_patterns`)? For tests using only
|
|
342
|
+
`assertion_free_patterns`: flag as potentially coincidence-detecting. For
|
|
343
|
+
modified tests: was an assertion weakened? Read the `context` prose.
|
|
344
|
+
|
|
345
|
+
**Severity:** Test would pass even if the behavior it claims to test were broken
|
|
346
|
+
— **IMPORTANT**. A regression test that doesn't assert the specific anti-pattern
|
|
347
|
+
is prevented — **IMPORTANT**. A coincidence-detector test that is the **sole
|
|
348
|
+
regression guard** for a previously-fixed Category A–F wedge — **BLOCKING**.
|
|
349
|
+
|
|
350
|
+
**Triage:**
|
|
351
|
+
`git diff main...HEAD --name-only | grep '{test_file_pattern}' | xargs grep -l '{tripwire_patterns}'`
|
|
352
|
+
|
|
353
|
+
## Lens 8 — Incomplete-class-fix: enumerate-all-siblings
|
|
354
|
+
|
|
355
|
+
**Why:** A fix that guards a SUBSET of writers to a shared resource, leaving
|
|
356
|
+
siblings via other code paths unguarded. The unguarded sibling silently retains
|
|
357
|
+
the bug.
|
|
358
|
+
|
|
359
|
+
**Relationship to philosophy gate:** No philosophy.md equivalent — new pattern.
|
|
360
|
+
|
|
361
|
+
**How to apply:** Read `config.lenses.incomplete_class_fix.shared_resources`.
|
|
362
|
+
For any fix touching a shared-resource writer: does the fix NAME the sites it
|
|
363
|
+
touches? Does it PROVE there is no N+1? Run the `grep` pattern in `directory` to
|
|
364
|
+
enumerate ALL write sites. Diff against what the fix touched — any gap is a
|
|
365
|
+
sibling. Acceptable proof: grep enumeration with each site accounted for,
|
|
366
|
+
compile-time tripwire, or cited enumeration comment. Read the `context` prose.
|
|
367
|
+
|
|
368
|
+
**Severity:** Fix touches a shared-resource writer without enumerating all
|
|
369
|
+
siblings — **BLOCKING**.
|
|
370
|
+
|
|
371
|
+
**Triage:** For each shared_resource, run its `grep` in its `directory` to
|
|
372
|
+
enumerate all write sites; diff against what the fix touched.
|
|
373
|
+
|
|
374
|
+
## Lens 9 — Dead-row pre-filter before per-row cost
|
|
375
|
+
|
|
376
|
+
**Why:** A per-row-expensive hot-path loop (subprocess / DB / IO per candidate)
|
|
377
|
+
that admits dead/retired/non-live rows into the candidate set. Dead rows incur
|
|
378
|
+
the full per-row cost (which fails anyway), starving the dispatch goroutine.
|
|
379
|
+
This was the ACTUAL root cause of the gitctx cold-cache fork-storm.
|
|
380
|
+
|
|
381
|
+
**Relationship to philosophy gate:** No philosophy.md equivalent — new pattern.
|
|
382
|
+
|
|
383
|
+
**How to apply:** Read `config.lenses.dead_row_prefilter`. For any new/changed
|
|
384
|
+
candidate query or per-row loop in a hot path: does the candidate selection use
|
|
385
|
+
`candidate_query_patterns` (e.g. `ended_at IS NULL`, open-session alone) as the
|
|
386
|
+
liveness proxy? This is WEAKER than the `canonical_predicate`
|
|
387
|
+
(`phaseFor`/`PhaseOf`). The candidate set MUST be pre-filtered to live agents
|
|
388
|
+
(phases in `live_phases`) with existing worktrees (`worktree_exists_check`)
|
|
389
|
+
BEFORE any per-row cost. A candidate query selecting on open-session alone,
|
|
390
|
+
feeding a per-row-expensive loop, is this anti-pattern. Read the `context`
|
|
391
|
+
prose.
|
|
392
|
+
|
|
393
|
+
**Severity:** Candidate query uses a weaker liveness proxy than the canonical
|
|
394
|
+
predicate, feeding a per-row-expensive loop — **BLOCKING**.
|
|
395
|
+
|
|
396
|
+
**Triage:**
|
|
397
|
+
`git diff main...HEAD --name-only | xargs grep -n '{candidate_query_patterns}'`
|
|
398
|
+
|
|
399
|
+
## Lens 10 — Peer-dial circuit-breaker for dispatch-reachable network calls
|
|
400
|
+
|
|
401
|
+
**Why:** A synchronous peer/network call (peer dial, cross-daemon RPC,
|
|
402
|
+
wait_pairing) reachable from a dispatch/fanout handler with no deadline AND no
|
|
403
|
+
circuit-breaker stalls the dispatch goroutine when the peer is unreachable or
|
|
404
|
+
stale.
|
|
405
|
+
|
|
406
|
+
**Relationship to philosophy gate:** No philosophy.md equivalent — new pattern.
|
|
407
|
+
|
|
408
|
+
**How to apply:** Read `config.lenses.peer_dial_circuit_breaker`. For any
|
|
409
|
+
new/changed peer call matching `peer_call_patterns`: is it reachable from a
|
|
410
|
+
`dispatch_handler_patterns` function? If yes, verify two mitigations: (1)
|
|
411
|
+
deadline- bounded via `timeout_patterns` (`context.WithTimeout`/`WithDeadline`),
|
|
412
|
+
AND (2) circuit-broken via `circuit_breaker_patterns` so an unreachable/stale
|
|
413
|
+
peer never stalls dispatch. A timeout alone is insufficient — a dead peer still
|
|
414
|
+
occupies a slot until the timeout fires. Read the `context` prose.
|
|
415
|
+
|
|
416
|
+
**Severity:** Peer call reachable from dispatch with no timeout AND no
|
|
417
|
+
circuit-breaker — **BLOCKING**. Peer call with timeout but no circuit-breaker —
|
|
418
|
+
**IMPORTANT**.
|
|
419
|
+
|
|
420
|
+
**Triage:**
|
|
421
|
+
`git diff main...HEAD --name-only | xargs grep -n '{peer_call_patterns}'`
|
|
422
|
+
|
|
423
|
+
## Cross-gate consolidation with the philosophy gate
|
|
424
|
+
|
|
425
|
+
This gate runs **in parallel** with `coordinator-philosophy-merge-gate` (both
|
|
426
|
+
are Pass 3, after dual review is clean, before `git merge`). The coordinator
|
|
427
|
+
runs both independently and consolidates findings from both into one numbered
|
|
428
|
+
list.
|
|
429
|
+
|
|
430
|
+
**Overlap rule:** If the philosophy gate already flagged a finding (e.g., raw
|
|
431
|
+
`exec.Command` in daemon code), this gate should **upgrade** it with the deeper
|
|
432
|
+
hot-path-specific analysis (is it in a per-RPC path? Is there a pre-flight
|
|
433
|
+
guard? Is there a Peek+background-refresh?), not duplicate it.
|
|
434
|
+
|
|
435
|
+
**Skip rule:** Skip the trigger-scoped lenses if the diff touches no configured
|
|
436
|
+
trigger directories — but any lens with `"always_run": true` in the config
|
|
437
|
+
still runs regardless of directories touched. Never skip the philosophy gate.
|
|
438
|
+
Skip everything, including always-run lenses, only for trivial diffs (one-line
|
|
439
|
+
config, typo, test-only).
|
|
440
|
+
|
|
441
|
+
## Scope discipline (gate-wide)
|
|
442
|
+
|
|
443
|
+
This gate governs NEW work unconditionally and EXISTING code only on a
|
|
444
|
+
fix-on-contact basis — don't carve out an unrelated existing violation because
|
|
445
|
+
you noticed it while reviewing an adjacent change. Note incidental finds in the
|
|
446
|
+
merge report as "touch-soon" candidates if they are actively wedging something;
|
|
447
|
+
otherwise leave them.
|
|
448
|
+
|
|
449
|
+
## If it fails
|
|
450
|
+
|
|
451
|
+
Send it back as a normal review finding — same channel as dual-review output,
|
|
452
|
+
folded into the same numbered list if dual review is still open, or as its own
|
|
453
|
+
short reply if dual review already passed. Cite the offending function/file,
|
|
454
|
+
which lens it failed, and the config value that triggered the finding.
|
|
455
|
+
|
|
456
|
+
## Efficacy tracking (v1 acceptance requirement)
|
|
457
|
+
|
|
458
|
+
After every gate run, record the outcome in `dev-docs/hotpath-gate-efficacy.md`
|
|
459
|
+
(created lazily on first run). This is a durable, committed, grep-queryable log
|
|
460
|
+
that measures v1's real-world efficacy so we can iterate to v2 with data.
|
|
461
|
+
|
|
462
|
+
**Format (structured header):** a structured header line, with
|
|
463
|
+
essay content moved to an indented notes block underneath it:
|
|
464
|
+
|
|
465
|
+
```
|
|
466
|
+
- YYYY-MM-DD | lens=<hpN,phN,...> | bead=<id> | merged=<sha> | gate=<hotpath|philosophy|both> | outcome=<OUTCOME>
|
|
467
|
+
notes: branch=<branch>, lenses_run=10, findings=B:N I:N M:N, FALSE_POSITIVE=<0|N>. <brief prose>
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
`lens=<hpN,phN,...>` names the specific lens numbers that were load-bearing for
|
|
471
|
+
the outcome (not just "10"), each prefixed by its gate — `hp<n>` for a
|
|
472
|
+
hotpath-gate.json lens, `ph<n>` for a philosophy.md anti-pattern.
|
|
473
|
+
`FALSE_POSITIVE=0` is recorded explicitly even on a clean/uneventful run ("no
|
|
474
|
+
findings overturned on pushback this run") so the zero is a measurement, not an
|
|
475
|
+
absence.
|
|
476
|
+
|
|
477
|
+
**Coverage mandate:** a row is required for EVERY trigger-dir merge — not just
|
|
478
|
+
gates the coordinator itself runs. This includes SKIPPED-with-evidence rows and
|
|
479
|
+
orchestrator-run merges; the log measures gate COVERAGE, not just
|
|
480
|
+
coordinator-run outcomes. Do not fabricate a per-merge outcome you cannot
|
|
481
|
+
verify — if a past merge is missing a row and the outcome can't be
|
|
482
|
+
reconstructed, record a single honest coverage-gap note instead of inventing
|
|
483
|
+
rows.
|
|
484
|
+
|
|
485
|
+
**Outcomes:**
|
|
486
|
+
|
|
487
|
+
| Outcome | Meaning |
|
|
488
|
+
| ----------------------- | ---------------------------------------------------------- |
|
|
489
|
+
| `CLEAN` | Gate ran, zero findings, merge proceeded |
|
|
490
|
+
| `REAL_DEFECT` | Gate caught a genuine hot-path/perf anti-pattern |
|
|
491
|
+
| `FALSE_POSITIVE` | Gate flagged something correct — record which lens and why |
|
|
492
|
+
| `SLIPPED` | A wedge occurred AFTER merge that the gate did not catch |
|
|
493
|
+
| `SKIPPED_WITH_EVIDENCE` | Gate deliberately skipped (no trigger dirs), evidence cited |
|
|
494
|
+
|
|
495
|
+
**Retrospective reclassification:** When triaging a new wedge or incident, grep
|
|
496
|
+
`dev-docs/hotpath-gate-efficacy.md` for the merged branch/date. If the gate
|
|
497
|
+
previously logged `CLEAN` for that branch, append a follow-up line referencing
|
|
498
|
+
the original entry:
|
|
499
|
+
`- YYYY-MM-DD | branch=<branch> | RECLASSIFIED: CLEAN->SLIPPED | notes=<what the gate missed + which lens should have caught it>`.
|
|
500
|
+
This closes the feedback loop — a `CLEAN` that later becomes `SLIPPED` is the
|
|
501
|
+
most valuable data point for v2 lens improvement.
|
|
502
|
+
|
|
503
|
+
Review the log quarterly (or after any `SLIPPED` outcome) to identify config
|
|
504
|
+
gaps and lens improvements for the next version.
|
|
505
|
+
|
|
506
|
+
## Reference
|
|
507
|
+
|
|
508
|
+
- `.thrum/hotpath-gate.json` — project-specific config (trigger directories,
|
|
509
|
+
patterns, reference functions, incident prose)
|
|
510
|
+
- `project-hotpath-gate` — the companion builder skill that generates/reconciles
|
|
511
|
+
the config (analog of `project-philosophy`)
|
|
512
|
+
- `dev-docs/brainstorms/hotpath-merge-gate/` — the locked brainstorm (evidence,
|
|
513
|
+
gap analysis, lens details, decisions)
|
|
514
|
+
- `coordinator-philosophy-merge-gate` — the companion general-structural gate
|
|
515
|
+
(runs in parallel)
|
|
516
|
+
- `.thrum/philosophy.md` — canonical source for general anti-patterns (cross-
|
|
517
|
+
referenced by Lenses 1–2, 6–7 where they overlap)
|
|
518
|
+
- `dev-docs/hotpath-gate-efficacy.md` — running efficacy log (created lazily on
|
|
519
|
+
first gate run, appended after each run)
|
|
520
|
+
|
|
521
|
+
<!-- THRUM-GATE: stage=skill next=review -->
|
|
522
|
+
<!-- THRUM-REVIEW: stage=skill verdict=Ready:Yes cycle=2 date=2026-07-10 -->
|