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.
Files changed (101) hide show
  1. package/assets/commands/thrum-_deviations-protocol.md +87 -0
  2. package/assets/commands/thrum-_generator-idempotency-protocol.md +15 -0
  3. package/assets/commands/thrum-_project-rules-protocol.md +18 -0
  4. package/assets/commands/thrum-_snapshot-protocol.md +265 -0
  5. package/assets/commands/thrum-_stamp-protocol.md +112 -0
  6. package/assets/commands/thrum-_verify-before-write-protocol.md +27 -0
  7. package/assets/commands/thrum-inbox.md +22 -0
  8. package/assets/commands/thrum-load-context.md +17 -0
  9. package/assets/commands/thrum-overview.md +17 -0
  10. package/assets/commands/thrum-prime.md +30 -0
  11. package/assets/commands/thrum-quickstart.md +14 -0
  12. package/assets/commands/thrum-reply.md +28 -0
  13. package/assets/commands/thrum-restart-extended.md +195 -0
  14. package/assets/commands/thrum-restart.md +293 -0
  15. package/assets/commands/thrum-send.md +31 -0
  16. package/assets/commands/thrum-sleep-extended.md +186 -0
  17. package/assets/commands/thrum-sleep.md +212 -0
  18. package/assets/commands/thrum-team.md +12 -0
  19. package/assets/commands/thrum-update-project.md +259 -0
  20. package/assets/commands/thrum-wait.md +14 -0
  21. package/assets/skills/adversarial-critique/SKILL.md +242 -0
  22. package/assets/skills/brainstorm-queue-aware/SKILL.md +167 -0
  23. package/assets/skills/brainstorm-steward/SKILL.md +181 -0
  24. package/assets/skills/choosing-subagent-models/SKILL.md +244 -0
  25. package/assets/skills/closing-findings-while-warm/SKILL.md +104 -0
  26. package/assets/skills/configure-roles/SKILL.md +229 -0
  27. package/assets/skills/coordinator-assessing-agent-completion/SKILL.md +205 -0
  28. package/assets/skills/coordinator-assessing-agent-completion/scan.py +117 -0
  29. package/assets/skills/coordinator-branch-split-on-block/SKILL.md +168 -0
  30. package/assets/skills/coordinator-context-monitoring/SKILL.md +674 -0
  31. package/assets/skills/coordinator-dispatching-work/SKILL.md +288 -0
  32. package/assets/skills/coordinator-hotpath-merge-gate/SKILL.md +522 -0
  33. package/assets/skills/coordinator-interacting-with-the-owner/SKILL.md +171 -0
  34. package/assets/skills/coordinator-maintaining-memory/SKILL.md +89 -0
  35. package/assets/skills/coordinator-managing-state-and-lifecycle/SKILL.md +192 -0
  36. package/assets/skills/coordinator-merging-code/SKILL.md +331 -0
  37. package/assets/skills/coordinator-philosophy-merge-gate/SKILL.md +442 -0
  38. package/assets/skills/coordinator-plan-reconcile-gate/SKILL.md +198 -0
  39. package/assets/skills/coordinator-post-restart-sweep/SKILL.md +135 -0
  40. package/assets/skills/coordinator-running-autonomous-feature-development/SKILL.md +199 -0
  41. package/assets/skills/coordinator-running-brainstorm-cycles/SKILL.md +654 -0
  42. package/assets/skills/coordinator-running-review-cycles/SKILL.md +153 -0
  43. package/assets/skills/coordinator-single-responsibility-merge-gate/SKILL.md +14 -0
  44. package/assets/skills/diagnosing-fleet-and-daemon/SKILL.md +255 -0
  45. package/assets/skills/efficient-multi-agent-research/SKILL.md +177 -0
  46. package/assets/skills/fixing-documentation-errors/SKILL.md +258 -0
  47. package/assets/skills/implementer-maintaining-memory/SKILL.md +84 -0
  48. package/assets/skills/implementer-orchestrating-execution/SKILL.md +125 -0
  49. package/assets/skills/implementer-receiving-dispatch/SKILL.md +127 -0
  50. package/assets/skills/implementer-receiving-review-feedback/SKILL.md +125 -0
  51. package/assets/skills/implementer-status-and-handoff/SKILL.md +150 -0
  52. package/assets/skills/implementer-tdd-and-quality/SKILL.md +99 -0
  53. package/assets/skills/memory-audit-recover/SKILL.md +153 -0
  54. package/assets/skills/memory-curate/SKILL.md +139 -0
  55. package/assets/skills/memory-maintenance/SKILL.md +87 -0
  56. package/assets/skills/memory-read-discipline/SKILL.md +164 -0
  57. package/assets/skills/memory-search-advanced/SKILL.md +217 -0
  58. package/assets/skills/memory-write-discipline/SKILL.md +135 -0
  59. package/assets/skills/orchestrate/SKILL.md +795 -0
  60. package/assets/skills/persistent-watcher-archetype/SKILL.md +225 -0
  61. package/assets/skills/prime-agent/SKILL.md +92 -0
  62. package/assets/skills/project-hotpath-gate/SKILL.md +255 -0
  63. package/assets/skills/project-philosophy/SKILL.md +418 -0
  64. package/assets/skills/project-philosophy/resources/philosophy-template.md +155 -0
  65. package/assets/skills/project-philosophy/resources/reliability-class-library.md +653 -0
  66. package/assets/skills/project-setup/SKILL.md +1007 -0
  67. package/assets/skills/project-setup/resources/implementation-agent.md +826 -0
  68. package/assets/skills/researcher-answering-queries/SKILL.md +100 -0
  69. package/assets/skills/researcher-investigating/SKILL.md +152 -0
  70. package/assets/skills/researcher-maintaining-memory/SKILL.md +176 -0
  71. package/assets/skills/state-migration/SKILL.md +54 -0
  72. package/assets/skills/thrum/SKILL.md +161 -0
  73. package/assets/skills/thrum/resources/ANTI_PATTERNS.md +132 -0
  74. package/assets/skills/thrum/resources/BOUNDARIES.md +56 -0
  75. package/assets/skills/thrum/resources/CLI_REFERENCE.md +1066 -0
  76. package/assets/skills/thrum/resources/IDENTITY.md +49 -0
  77. package/assets/skills/thrum/resources/LISTENER_PATTERN.md +64 -0
  78. package/assets/skills/thrum/resources/MESSAGING.md +163 -0
  79. package/assets/skills/thrum/resources/TMUX_SESSIONS.md +118 -0
  80. package/assets/skills/thrum/resources/WORKTREES.md +117 -0
  81. package/assets/skills/thrum-memory/SKILL.md +138 -0
  82. package/assets/skills/trace-spec-to-plan/SKILL.md +104 -0
  83. package/assets/skills/trace-spec-to-plan/resources/sweep-agent-prompt.md +57 -0
  84. package/assets/skills/update-queue/SKILL.md +149 -0
  85. package/assets/skills/using-the-queue/SKILL.md +172 -0
  86. package/assets/skills/using-thrum-state/SKILL.md +104 -0
  87. package/assets/skills/verify-against-plan/SKILL.md +323 -0
  88. package/assets/skills/verify-against-source/SKILL.md +237 -0
  89. package/assets/skills/watcher-archetype/SKILL.md +84 -0
  90. package/assets/skills/writing-durable-markdown/SKILL.md +66 -0
  91. package/dist/hooks/block-sync-cd.d.ts +9 -0
  92. package/dist/hooks/block-sync-cd.js +71 -0
  93. package/dist/hooks/block-sync-cd.test.d.ts +1 -0
  94. package/dist/hooks/block-sync-cd.test.js +61 -0
  95. package/dist/hooks/shell-env.d.ts +8 -0
  96. package/dist/hooks/shell-env.js +22 -0
  97. package/dist/index.d.ts +6 -0
  98. package/dist/index.js +25 -0
  99. package/dist/installer.d.ts +2 -0
  100. package/dist/installer.js +86 -0
  101. package/package.json +49 -0
@@ -0,0 +1,653 @@
1
+ # Reliability Class Library
2
+
3
+ Shared reference loaded by `project-philosophy` (all 7 classes) and
4
+ `project-hotpath-gate` (classes tagged `hotpath` below, via their hot-path
5
+ facet). Distilled from thrum's own anti-patterns and SQLite crash-recovery lessons.
6
+ Each class is a generalizable
7
+ failure SHAPE, not a thrum-specific rule — adapt the probes to the target
8
+ repo's detected language before writing anything into a generated doc.
9
+
10
+ For each class found in the target repo, render it as a BAD/GOOD anti-pattern
11
+ using the repo's own language and idioms — never paste thrum's Go examples
12
+ into a non-Go repo's philosophy.md.
13
+
14
+ ## Class 1 — Injectable fault seam
15
+
16
+ **Consumers:** philosophy, hotpath (hot-path facet: per-request expensive-call)
17
+ **thrum source:** the VFS lesson: SQLite's OS layer is a swappable driver, so
18
+ every I/O failure mode is testable without touching a real disk.
19
+
20
+ **Definition:** A call into the OS, filesystem, or network that can fail
21
+ (process exec, file open/read/write, socket dial, DNS) is made directly from
22
+ business logic, with no seam through which a test can inject failure.
23
+ Production and test share one code path with zero swap point.
24
+
25
+ **Why it's expensive:** The only tested failure mode is "call succeeds."
26
+ Real failures (ENOSPC, EMFILE, a hung subprocess, a network partition) are
27
+ exercised for the first time in production, and the fix usually lands as an
28
+ ad hoc special case rather than a reusable fault-injection seam.
29
+
30
+ **Detection heuristic:** grep the language's process-exec, file-open, and
31
+ network-dial primitives; a hit directly inside a request-handler or
32
+ business-logic file (not an isolated adapter/driver/VFS-shaped module) is a
33
+ finding.
34
+
35
+ **Per-language probes:**
36
+
37
+ - Go: `grep -rn 'exec\.Command\|exec\.CommandContext\|os\.Open\|net\.Dial'
38
+ --include='*.go'`, excluding `*_test.go` and any package with
39
+ `driver`/`fault`/`vfs` in its path.
40
+ - Python: `grep -rn 'subprocess\.\(run\|Popen\|call\)\|open(\|socket\.\(connect\|create_connection\)'
41
+ --include='*.py'`
42
+ - JS/TS: `grep -rn 'child_process\.\(exec\|spawn\)\|fs\.\(readFile\|writeFile\)Sync\?\|net\.connect\|http\.request'
43
+ --include='*.ts' --include='*.js'`
44
+ - Rust: `grep -rn 'std::process::Command\|std::fs::File::open\|TcpStream::connect'
45
+ --include='*.rs'`
46
+ - Fallback: search the language's canonical process-spawn and low-level
47
+ file/socket primitives; a hit inside business logic rather than an
48
+ adapter module is the finding.
49
+
50
+ ## Class 2 — Unrecovered async failure kills the host process
51
+
52
+ **Consumers:** philosophy, hotpath (hot-path facet: unrecovered-async-crash)
53
+ **thrum source:** new I/O work added inside a daemon boot stage or dispatch
54
+ handler with no recovery if that work panics/throws.
55
+
56
+ **Definition:** Work is moved onto a background thread/goroutine/async task
57
+ for latency reasons, but a panic, unhandled rejection, or unrecovered
58
+ exception on that path is not caught — it kills (or silently wedges) the
59
+ whole host process instead of failing just that one unit of work.
60
+
61
+ **Why it's expensive:** The failure is invisible until the specific input
62
+ that trips it arrives in production; the symptom (daemon down, service
63
+ restarted) points nowhere near the async call site that caused it.
64
+
65
+ **Detection heuristic:** every `go func`/async-task/background-thread spawn
66
+ on a request or boot path needs a recover/catch immediately inside it. A
67
+ spawn with no enclosing recover/catch in the same function is a finding.
68
+
69
+ **Per-language probes:**
70
+
71
+ - Go: `grep -rn 'go func' --include='*.go' -A3 | grep -B3 -L 'recover()'`
72
+ (spawns not immediately followed by a deferred recover)
73
+ - Python: `grep -rn 'asyncio\.create_task\|Thread(target=' --include='*.py'`
74
+ then check the target/coroutine body for a bare `try/except`
75
+ - JS/TS: `grep -rn 'setTimeout\|setImmediate\|\.then(\|async function'
76
+ --include='*.ts' --include='*.js'` then check for an unhandled-rejection
77
+ or `.catch()` immediately at the call site
78
+ - Rust: `grep -rn 'tokio::spawn\|std::thread::spawn' --include='*.rs'` then
79
+ check for `catch_unwind` or a supervised-restart wrapper
80
+ - Fallback: find the language's background-task/thread-spawn primitive; a
81
+ spawn with no local recovery wrapper is the finding.
82
+
83
+ ## Class 3 — Destructive reconcile on fresh install (empty canonical is a wipe)
84
+
85
+ **Consumers:** philosophy only
86
+
87
+ **Definition:** A reconcile/sync/cleanup routine treats an EMPTY canonical
88
+ source (first boot, no state yet) the same as a canonical source that says
89
+ "delete everything" — so the very first run of the tool wipes whatever
90
+ pre-existing data it finds, because "nothing here yet" and "delete
91
+ everything" are indistinguishable to the code.
92
+
93
+ **Why it's expensive:** The bug only fires once per install, on the very
94
+ first run, against whatever real data happens to already be present — by
95
+ the time anyone notices, the data is gone and the repro is hard to
96
+ reconstruct.
97
+
98
+ **Detection heuristic:** find any routine that deletes/prunes/reconciles a
99
+ directory or table against a canonical list, and check whether an empty
100
+ canonical list is special-cased (hold/no-op) or falls through to "delete
101
+ everything not in the list."
102
+
103
+ **Per-language probes:**
104
+
105
+ - Go: `grep -rn 'os\.RemoveAll\|DROP TABLE\|DELETE FROM.*WHERE.*NOT IN'
106
+ --include='*.go'`
107
+ - Python: `grep -rn 'shutil\.rmtree\|os\.remove\|DELETE FROM.*NOT IN'
108
+ --include='*.py'`
109
+ - JS/TS: `grep -rn 'fs\.rm\(Sync\)\?\|rimraf\|DELETE FROM.*NOT IN'
110
+ --include='*.ts' --include='*.js'`
111
+ - Fallback: find the language's recursive-delete primitive and any
112
+ "reconcile against canonical list" SQL/logic; check for an explicit
113
+ empty-canonical guard.
114
+
115
+ ## Class 4 — Guard-adequacy: presence verified, capability not
116
+
117
+ **Consumers:** philosophy only
118
+
119
+ **Definition:** A guard checks that something EXISTS (a file, a flag, a
120
+ config key, a permission record) but never checks that it actually WORKS or
121
+ grants the capability the caller assumes it grants. The guard passes on a
122
+ present-but-broken/present-but-insufficient state.
123
+
124
+ **Why it's expensive:** Code downstream of the guard trusts it fully, so a
125
+ present-but-inadequate state produces a confident wrong action instead of a
126
+ loud failure — the guard is worse than no guard because it suppresses the
127
+ obvious symptom.
128
+
129
+ **Detection heuristic:** find `if <thing> exists/present/!= nil` checks
130
+ immediately gating a privileged or destructive action; check whether the
131
+ check verifies capability (a successful no-op call, a real permission
132
+ check) or only presence.
133
+
134
+ **Per-language probes:**
135
+
136
+ - Go: `grep -rn 'if.*!= nil {' --include='*.go' -B2` near privileged
137
+ actions, cross-checked against whether the referenced value is ever
138
+ exercised (called) before use
139
+ - Python: `grep -rn 'if os\.path\.exists\|if.*is not None' --include='*.py'`
140
+ near privileged actions
141
+ - JS/TS: `grep -rn 'if\s*(\w+)\s*{' --include='*.ts' --include='*.js'` near
142
+ privileged actions
143
+ - Fallback: find presence-only guards (existence/non-null checks)
144
+ immediately preceding a privileged or destructive call, with no
145
+ accompanying capability check.
146
+
147
+ ## Class 5 — Synchronous palliative vs. bounded async queue
148
+
149
+ **Consumers:** philosophy, hotpath (hot-path facets: shared-lock-across-I/O, unbounded-wait)
150
+ **thrum source:** the Hipp/SQLite lesson: remove a slow component rather than
151
+ patching around it with more synchronous work.
152
+
153
+ **Definition:** A shared serialization point (a global lock, a single
154
+ writer connection, a single dispatch queue) is under contention, and the
155
+ fix adds MORE synchronous work inside that same critical section (a retry
156
+ loop, a longer timeout, a synchronous fan-out call) instead of moving the
157
+ work off the serialization point onto a bounded async queue.
158
+
159
+ **Why it's expensive:** Each palliative fix narrows the failure window
160
+ without removing the root cause, so contention resurfaces under slightly
161
+ higher load, and the critical section keeps growing — eventually turning a
162
+ brief lock hold into an unbounded wait that stalls every caller behind it.
163
+
164
+ **Detection heuristic:** find a lock/mutex/single-connection acquisition
165
+ immediately followed by I/O (network call, subprocess, blocking file op)
166
+ inside the same critical section, or a synchronous call on a
167
+ request/dispatch path with no timeout/circuit breaker.
168
+
169
+ **Per-language probes:**
170
+
171
+ - Go: `grep -rn '\.Lock()\|\.RLock()' --include='*.go' -A10` then check
172
+ whether a network/exec/blocking call appears before the matching
173
+ `Unlock()`; separately `grep -rn 'context\.WithTimeout\|context\.WithDeadline'
174
+ --include='*.go'` to check whether peer/network calls on a dispatch path
175
+ have one
176
+ - Python: `grep -rn 'with.*[Ll]ock' --include='*.py' -A10` for I/O inside
177
+ the block; `grep -rn 'requests\.\(get\|post\)\|socket\.' --include='*.py'`
178
+ for missing `timeout=`
179
+ - JS/TS: `grep -rn 'await mutex\.\|\.acquire()' --include='*.ts'
180
+ --include='*.js' -A10` for I/O inside the held span
181
+ - Fallback: find the language's lock-acquisition primitive; check whether
182
+ I/O happens while held, and whether outbound calls on a hot path carry an
183
+ explicit timeout.
184
+
185
+ ## Class 6 — Controlled-zero: a green check that cannot come back negative
186
+
187
+ **Consumers:** philosophy only (universal review discipline, not a hot-path lens)
188
+ **thrum source:** universal review discipline, generalized from thrum's own
189
+ merge-gate meta-checks.
190
+
191
+ **Definition:** A test, health check, or CI gate that reports "clean" or
192
+ "zero findings" whether or not it actually ran — an empty result set is
193
+ indistinguishable from "nothing wrong" and "the check silently didn't
194
+ execute" (wrong filter, empty fixture, mocked-away dependency, a
195
+ `--dry-run` flag left on).
196
+
197
+ **Why it's expensive:** Confidence in the check compounds — a green check
198
+ that cannot come back negative is worse than no check, because it is relied
199
+ upon precisely where a real problem would otherwise have been caught.
200
+
201
+ **Detection heuristic:** for any assertion-free or count-based check (a
202
+ test asserting only "no error," a CI step asserting only exit code 0), ask
203
+ whether there is a companion negative control proving the check COULD have
204
+ failed (a deliberately broken fixture, an invented-symbol probe).
205
+
206
+ **Per-language probes:**
207
+
208
+ - Go: `grep -rln 'require\.NoError(t, err)$\|assert\.NoError(t, err)$'
209
+ --include='*_test.go'` (assertion-free tests: NoError with no
210
+ accompanying state/equality assertion)
211
+ - Python: `grep -rn 'assert.*is None\|# no assert' --include='test_*.py'`
212
+ - JS/TS: `grep -rn 'expect(.*\.not\.toThrow()' --include='*.test.ts'`
213
+ - Fallback: find tests/checks whose only assertion is "no error raised,"
214
+ with no accompanying positive assertion on state, and no adjacent
215
+ negative-control test.
216
+
217
+ ## Class 7 — Crash/power-loss recovery and migration against real old data
218
+
219
+ **Consumers:** philosophy only
220
+ **thrum source:** the SQLite core disciplines (Hipp/SQLite talk).
221
+
222
+ **Definition:** A durable store's crash-recovery path (WAL replay, journal
223
+ recovery, migration-on-boot) is tested only against synthetic in-memory
224
+ fixtures created by the current code version — never against a real
225
+ on-disk snapshot from an OLDER schema version, and never by actually
226
+ killing the process mid-write and restarting it.
227
+
228
+ **Why it's expensive:** The disciplines that matter (does recovery
229
+ converge on a truly random torn write? does a migration handle a customer's
230
+ real months-old on-disk state, not a freshly-created one?) are exactly the
231
+ ones a synthetic in-code fixture cannot exercise — bugs here surface only
232
+ against a real customer's real old data, in production.
233
+
234
+ **Detection heuristic:** find the migration/recovery entrypoint (schema
235
+ version check, WAL/journal replay on boot) and check whether any test kills
236
+ the process mid-write (not just simulates a corrupt file) and whether any
237
+ test runs a migration against a captured real on-disk snapshot rather than
238
+ a freshly-created fixture.
239
+
240
+ **Per-language probes:**
241
+
242
+ - Go: `grep -rn 'CurrentVersion\|migrat\|wal_checkpoint\|journal_mode'
243
+ --include='*.go'`, then `grep -rln 'os\.Kill\|SIGKILL\|process\.Kill'
244
+ --include='*_test.go'` for mid-write kill tests
245
+ - Python: `grep -rn 'alembic\|migration' --include='*.py'`, then check test
246
+ fixtures for a captured real DB snapshot vs. a freshly-created one
247
+ - Node/TS: `grep -rn 'migrate\|knex\.' --include='*.ts'`, same fixture check
248
+ - Fallback: find the migration/recovery entrypoint; check for a
249
+ mid-write-kill test and a real-old-snapshot migration test, not just
250
+ synthetic fixtures.
251
+
252
+ ## Class 8 — Silent fail-open
253
+
254
+ **Consumers:** hotpath
255
+ **thrum source:** hotpath lens `silent_fail_open` (Step 5,
256
+ `project-hotpath-gate/SKILL.md`) — fallback/default-return patterns that
257
+ mask a missing or invalid dependency instead of failing loudly.
258
+
259
+ **Definition:** A code path that should fail when a required dependency,
260
+ credential, or lookup is missing instead falls back to a default value (a
261
+ default credential, a default user, an empty-but-valid-looking result) with
262
+ no log line or error surfaced to the caller.
263
+
264
+ **Why it's expensive:** The failure never announces itself — the system
265
+ keeps running on a silently-substituted default, and the divergence between
266
+ "the real thing" and "the fallback" only becomes visible once its
267
+ downstream effects (wrong data, wrong permissions) are noticed far from the
268
+ fallback site.
269
+
270
+ **Detection heuristic:** find `fallback`/`default`-shaped branches
271
+ immediately following a lookup, existence check, or dependency-load
272
+ attempt; a branch that returns a default value with no accompanying log/
273
+ error/metric emission is a finding.
274
+
275
+ **Per-language probes:**
276
+
277
+ - Go: `grep -rn 'fallback\|FallBack\|if !exists\|default.*return'
278
+ --include='*.go'`
279
+ - Python: `grep -rn 'except:\s*pass\|\.get(\w+,\s*default_' --include='*.py'`
280
+ (bare `except: pass` swallowing an error, or a `.get(k, default_creds)`
281
+ shaped silent substitution)
282
+ - JS/TS: `grep -rn 'catch\s*{\s*}\|??\s*default' --include='*.ts'
283
+ --include='*.js'` (an empty catch block, or a `??` fallback onto a
284
+ default-shaped value with no logging)
285
+ - Fallback: find lookup/dependency-load call sites; check whether the
286
+ failure branch logs/surfaces the failure or silently substitutes a
287
+ default.
288
+
289
+ ## Class 9 — Unconditional write on a dual-source path
290
+
291
+ **Consumers:** hotpath
292
+ **thrum source:** hotpath lens for dual-source write paths (Step 6,
293
+ `project-hotpath-gate/SKILL.md`) — unconditional writes with no
294
+ last-writer-wins or version guard.
295
+
296
+ **Definition:** A shared record is writable from two or more independent
297
+ sources (an API path and a webhook/sync path, a UI edit and a background
298
+ reconciler), and at least one of those write paths performs an
299
+ unconditional upsert/replace with no last-writer-wins timestamp check or
300
+ version guard — so whichever source writes last silently wins, even when
301
+ it holds stale data.
302
+
303
+ **Why it's expensive:** The two write paths race under real concurrent
304
+ load, and the bug only manifests as an occasional stale overwrite —
305
+ intermittent, hard to reproduce, and easy to misdiagnose as a caching issue
306
+ rather than a missing guard.
307
+
308
+ **Detection heuristic:** find upsert/replace statements on a path reachable
309
+ from more than one caller/trigger, and check whether a timestamp or version
310
+ comparison gates the write (vs. an unconditional `INSERT OR REPLACE`-shaped
311
+ statement).
312
+
313
+ **Per-language probes:**
314
+
315
+ - Go: `grep -rn 'INSERT OR REPLACE\|INSERT OR IGNORE' --include='*.go'` for
316
+ the unconditional write; cross-check against `grep -rn
317
+ 'lww\.\|GuardSQL\|GuardTarget' --include='*.go'` for an adjacent guard —
318
+ a write-site hit with no guard hit nearby is the finding.
319
+ - Python: `grep -rn 'ON CONFLICT DO UPDATE\|session\.merge(' --include='*.py'`
320
+ with no accompanying version/timestamp comparison in the same
321
+ transaction.
322
+ - JS/TS: `grep -rn 'upsert(' --include='*.ts' --include='*.js'` on a route
323
+ reachable from both an API handler and a webhook handler, with no
324
+ `updatedAt`/version guard in the upsert's `where`/conflict clause.
325
+ - Fallback: find upsert/replace call sites reachable from more than one
326
+ caller; check for a timestamp or version guard gating the write.
327
+
328
+ ## Class 10 — Shared-resource poisoning
329
+
330
+ **Consumers:** hotpath
331
+ **thrum source:** hotpath lens `shared_resource_poisoning` (Step 7,
332
+ `project-hotpath-gate/SKILL.md`) — a read-only worker or side process
333
+ performing writes/maintenance against a resource other callers assume is
334
+ read-only or externally managed.
335
+
336
+ **Definition:** A process or code path documented or assumed to be
337
+ read-only (a read replica, a reporting worker, a "just reads" script)
338
+ actually performs writes, schema changes, or maintenance operations (a
339
+ checkpoint, a VACUUM, a lock-escalating write) against the shared resource
340
+ — poisoning it for every other consumer that assumed read-only access was
341
+ safe to run concurrently.
342
+
343
+ **Why it's expensive:** Every other caller's concurrency assumptions were
344
+ built on that resource being safely shareable for reads; a write or
345
+ maintenance op from the "read-only" side blows up those assumptions
346
+ without warning, producing lock contention or corruption that shows up in
347
+ an unrelated caller.
348
+
349
+ **Detection heuristic:** find DB/file-open calls in code paths labeled or
350
+ assumed read-only, and check whether any write or maintenance statement
351
+ (checkpoint, VACUUM, PRAGMA, write query) appears in the same process.
352
+
353
+ **Per-language probes:**
354
+
355
+ - Go: `grep -rn 'OpenDB\|OpenReadDB\|sql\.Open\|sql\.OpenDB'
356
+ --include='*.go'` for the open call, cross-checked against `grep -rn
357
+ 'wal_checkpoint\|PRAGMA\|checkpoint\|Checkpoint' --include='*.go'` in the
358
+ same file/package for a write/maintenance op reachable from a
359
+ read-labeled path.
360
+ - Python: `grep -rn 'sqlite3\.connect\|open(.*[\'"]r[\'"]' --include='*.py'`
361
+ in a worker/script documented as read-only, cross-checked for `.execute(
362
+ ' *(INSERT|UPDATE|DELETE|VACUUM)` in the same module.
363
+ - JS/TS: `grep -rn 'fs\.open\|db\.prepare' --include='*.ts' --include='*.js'`
364
+ in a script/worker documented as read-only, cross-checked for a write
365
+ call (`fs.write`, an `INSERT`/`UPDATE`/`DELETE`/`VACUUM` statement) in the
366
+ same file.
367
+ - Fallback: find the resource-open call in a read-only-labeled process;
368
+ check whether any write or maintenance statement is reachable from the
369
+ same process.
370
+
371
+ ## Class 11 — Pattern divergence from the repo's own reference implementation
372
+
373
+ **Consumers:** hotpath
374
+ **thrum source:** hotpath lens for reference-pattern detection (Step 8,
375
+ `project-hotpath-gate/SKILL.md`) — the repo already has an established,
376
+ correct way to do something; some call sites diverge from it.
377
+
378
+ **Definition:** The repo has an established/reference implementation of a
379
+ shared pattern (e.g. thrum's `net.Listen`-followed-by-`Serve()` vs. a
380
+ listener never served, `OpenReadDB` vs. raw `sql.Open`, a typed
381
+ `safehandler.SafeHandler` vs. legacy `json.RawMessage` handling) — and one
382
+ or more call sites use an older/legacy/ad hoc variant of the same operation
383
+ instead of the current pattern, usually because the legacy variant predates
384
+ the reference implementation and was never migrated.
385
+
386
+ **Why it's expensive:** The legacy variant misses whatever correctness or
387
+ safety property motivated the reference implementation in the first place
388
+ (a missed `Serve()` call, a missing typed-validation layer, a bypassed
389
+ guard) — and because it still compiles and runs, nothing forces the
390
+ migration; the divergence persists indefinitely as a live footgun sitting
391
+ next to its own fix.
392
+
393
+ **Detection heuristic:** identify the established/reference implementation
394
+ of a shared pattern in the repo (the version most call sites use, or the
395
+ one with a tripwire test enforcing it), then find call sites performing the
396
+ same operation via a different, non-canonical route. Go: illustrative
397
+ categories from `project-hotpath-gate/SKILL.md` Step 8 — listener-serve
398
+ pairing, read-only-DB access, LWW guard usage, canonical liveness
399
+ predicate, typed vs. raw handler dispatch — are examples of the pattern
400
+ class, not a single literal grep; identify the repo's own reference
401
+ pattern for each category before searching for divergent call sites.
402
+
403
+ **Per-language probes:**
404
+
405
+ - Go: no single grep — per `project-hotpath-gate/SKILL.md` Step 8, identify
406
+ the repo's reference pattern per category (e.g. `grep -rn 'net\.Listen'
407
+ --include='*.go'` cross-checked for a following `Serve()`/`Accept()`
408
+ call; `grep -rn 'OpenReadDB\|sql\.Open' --include='*.go'` to find both
409
+ the canonical and legacy DB-open routes) and diff call sites against it.
410
+ - Python: repo idiom probe — find the repo's own established retry
411
+ decorator (e.g. `grep -rn '@retry' --include='*.py'`), then `grep -rn
412
+ 'while True:.*try:\|for _ in range(' --include='*.py'` for raw/ad hoc
413
+ retry loops that should have used the decorator instead.
414
+ - JS/TS: apiClient vs. raw fetch — find the repo's established API-client
415
+ wrapper (e.g. `grep -rln 'class ApiClient\|export.*apiClient'
416
+ --include='*.ts'`), then `grep -rn 'fetch(\|axios\.' --include='*.ts'
417
+ --include='*.js'` for call sites bypassing it with a raw `fetch`/`axios`
418
+ call.
419
+ - Fallback: identify the repo's own reference implementation for a shared
420
+ operation (the version most call sites use, or the one with a tripwire
421
+ test); grep for call sites performing the same operation via a different
422
+ route.
423
+
424
+ ## Class 12 — Coincidence-detector tests on the hot-path test suite
425
+
426
+ **Consumers:** hotpath
427
+ **thrum source:** hotpath lens `assertion_free_patterns` (Step 9,
428
+ `project-hotpath-gate/SKILL.md`) — same underlying shape as Class 6
429
+ ("Controlled-zero") in this library, applied specifically to the hot-path
430
+ test suite rather than as a general review discipline.
431
+
432
+ **Definition:** A test on the hot-path test suite asserts only "no error
433
+ raised" (`require.NoError`/`assert.NoError` with no accompanying
434
+ state/equality assertion, an `assert-free` test body, a sole `.not.toThrow()`
435
+ expectation) with no assertion on the actual resulting state — see Class 6
436
+ for the general shape; this entry targets hot-path-adjacent tests
437
+ specifically, since a coincidence detector guarding a request-handling or
438
+ concurrency-sensitive path is more expensive to leave undetected than one
439
+ guarding an unrelated code path.
440
+
441
+ **Why it's expensive:** A hot-path regression (a race, a silent fallback, a
442
+ dropped write) passes the suite because the test never checked the state
443
+ the regression would have corrupted — the team's confidence that the hot
444
+ path is covered is unearned exactly where the cost of being wrong is
445
+ highest.
446
+
447
+ **Detection heuristic:** for each test file touching a hot-path
448
+ handler/lens area, check whether its assertions include a state/equality
449
+ check or only a bare no-error check.
450
+
451
+ **Per-language probes:**
452
+
453
+ - Go: `grep -rn 'require\.NoError\|assert\.NoError' --include='*_test.go'`
454
+ scoped to hot-path test files, then check whether the same test function
455
+ has any accompanying state/equality assertion.
456
+ - Python: `grep -rln 'assert-free' 'test_*.py'` — a Python test file with
457
+ no `assert` beyond error-absence checks (e.g. no `assertEqual`/`assert
458
+ result ==`), scoped to hot-path-adjacent test modules.
459
+ - JS/TS: `grep -rn 'expect(.*\.not\.toThrow()' --include='*.test.ts'` as
460
+ the sole assertion in a hot-path-adjacent test.
461
+ - Fallback: find tests covering hot-path handlers/lenses whose only
462
+ assertion is "no error raised," with no accompanying state assertion.
463
+
464
+ ## Class 13 — Incomplete class fix: sibling writers left unfixed
465
+
466
+ **Consumers:** hotpath
467
+ **thrum source:** hotpath lens for sibling-resource enumeration (Step 10,
468
+ `project-hotpath-gate/SKILL.md`) — a fix applied to one writer/handler of a
469
+ shared resource while sibling writers of the same resource type were never
470
+ enumerated or checked.
471
+
472
+ **Definition:** A bug fix (a guard added, a race closed, a validation
473
+ tightened) is applied to one call site that writes a shared resource type
474
+ (a projection writer, a vault/identity file, a network listener, a DB open
475
+ call) — but the codebase has other call sites writing the same resource
476
+ type that were never enumerated during the fix, and so never received the
477
+ equivalent fix.
478
+
479
+ **Why it's expensive:** The class of bug is not actually closed — only the
480
+ one instance that happened to be noticed is. The sibling call sites carry
481
+ the identical defect and will surface it later, independently, looking
482
+ like a "new" bug rather than the same one recurring, wasting a second
483
+ investigation on a problem already solved once.
484
+
485
+ **Detection heuristic:** when reviewing a fix to a shared-resource writer,
486
+ enumerate every other call site of the same resource type (via the
487
+ resource's canonical open/write primitive) and check whether each one
488
+ received the equivalent guard/fix.
489
+
490
+ **Per-language probes:**
491
+
492
+ - Go: `grep -rn 'func apply.*Tx' --include='*.go'` (projection writers),
493
+ `grep -rn 'vault\.\|Vault\|loadIdentity' --include='*.go'`
494
+ (vault/identity writers), `grep -rn 'net\.Listen\|net\.FileListener'
495
+ --include='*.go'` (listeners), `grep -rn
496
+ 'schema\.OpenDB\|schema\.OpenReadDB\|sql\.Open' --include='*.go'` (DB
497
+ opens) — enumerate all hits per resource type and diff against which
498
+ ones received the fix.
499
+ - Python: enumerate all writers across `*.py` — `grep -rn
500
+ '\.execute(\|\.commit(\|session\.add(' --include='*.py'` scoped to the
501
+ same resource/table the fix targeted, then check each hit for the
502
+ equivalent fix.
503
+ - JS/TS: enumerate all save/write across `*.ts` — `grep -rn
504
+ '\.save(\|\.update(\|\.write(' --include='*.ts' --include='*.js'` scoped
505
+ to the same resource the fix targeted, then check each hit for the
506
+ equivalent fix.
507
+ - Fallback: find the resource's canonical open/write primitive; enumerate
508
+ every call site; check each one for the fix that was applied to the
509
+ originally-reported site.
510
+
511
+ ## Class 14 — Dead-row pre-filter: a weak liveness proxy feeding per-row cost
512
+
513
+ **Consumers:** hotpath
514
+ **thrum source:** hotpath lens `dead_row_prefilter` (Step 10a,
515
+ `project-hotpath-gate/SKILL.md`) — a candidate query using a weak liveness
516
+ proxy instead of the canonical liveness predicate, feeding dead rows into a
517
+ per-row-expensive operation.
518
+
519
+ **Definition:** A query selecting candidate rows for a per-row-expensive
520
+ operation (an N+1 lookup, a per-row filesystem/subprocess check) filters on
521
+ a weak proxy for "is this row still live" (a nullable timestamp column, a
522
+ loosely-named status flag) instead of the repo's canonical liveness
523
+ predicate — so rows that are actually dead by the canonical definition
524
+ still pass the pre-filter and pay the expensive per-row cost anyway.
525
+
526
+ **Why it's expensive:** The per-row cost this pre-filter exists to avoid
527
+ still gets paid, just for a population that should have been excluded —
528
+ the pre-filter creates a false sense that the expensive path is already
529
+ bounded, when it is only bounded by an approximation that under-filters.
530
+
531
+ **Detection heuristic:** find queries selecting candidates for a per-row
532
+ loop and check whether the WHERE/filter clause uses the canonical liveness
533
+ predicate (a function or well-defined phase set) or a weaker ad hoc proxy
534
+ (nullable-timestamp check, loosely-named boolean).
535
+
536
+ **Per-language probes:**
537
+
538
+ - Go: `grep -rn 'ended_at IS NULL\|session.*not.*closed\|phase IS NULL'
539
+ --include='*.go'`
540
+ - Python: N+1 ORM loop without `select_related`/`prefetch_related` — `grep
541
+ -rn 'for \w+ in \w+\.objects\.\(all\|filter\)(' --include='*.py'` with no
542
+ accompanying `select_related(`/`prefetch_related(` on the same
543
+ queryset.
544
+ - JS/TS: N+1 for-loop issuing per-item queries — `grep -rn 'for\s*(.*of.*)\s*{'
545
+ --include='*.ts' --include='*.js' -A5` checked for an `await db.query(`
546
+ or equivalent per-row call inside the loop body instead of a single
547
+ batched query.
548
+ - Fallback: find the candidate-selection query feeding a per-row-expensive
549
+ loop; check whether its filter uses the repo's canonical liveness
550
+ predicate or a weaker ad hoc proxy.
551
+
552
+ ## Class 15 — Frozen identity key: a shared primitive whose output is persisted
553
+
554
+ **Consumers:** hotpath
555
+ **thrum source:** hotpath lens `frozen_identity_key` (Step 10c,
556
+ `project-hotpath-gate/SKILL.md`) — a shared normalizer/hash primitive whose
557
+ output is persisted or compared as a licensing/identity key, so changing
558
+ the primitive silently breaks every previously-persisted key.
559
+
560
+ **Definition:** A shared normalization or hashing primitive (a URL
561
+ normalizer, a stable-ID generator, a `sha256.Sum`-shaped function) has its
562
+ output persisted to disk, embedded in a cache/DB key, or compared for
563
+ exact equality against a stored licensing/identity value downstream. The
564
+ finding is the PAIR — the primitive plus a persisted/licensing consumer of
565
+ its output — not the primitive alone; a normalizer with no persisted
566
+ consumer is not a candidate for this class.
567
+
568
+ **Why it's expensive:** Once a primitive's output is persisted anywhere,
569
+ the primitive is effectively frozen — any change to its normalization
570
+ logic (a bug fix, a new edge case handled) silently invalidates every
571
+ previously-persisted key, and the failure mode (a returning user's license
572
+ no longer matching, a stale identity mismatch) surfaces far from the
573
+ primitive that changed and long after the change shipped.
574
+
575
+ **Detection heuristic:** find normalizer/hash primitives whose result
576
+ feeds a persisted value (a saved file, a DB column, a cache key, a JWT
577
+ claim) or an exact-equality comparison against a stored value; check
578
+ whether the primitive's contract is documented as frozen/versioned, and
579
+ whether any test pins its output against a fixed input to catch accidental
580
+ drift.
581
+
582
+ **Per-language probes:**
583
+
584
+ - Go: `grep -rn 'GenerateRepoID\|NormalizeGitURL\|stableRepoAccount\|sha256\.Sum'
585
+ --include='*.go'` for the primitive, cross-checked against `grep -rn
586
+ 'SaveIdentityFile\|identities/.*\.json\|license\.\|GrantsOSS'
587
+ --include='*.go'` for a persisted/licensing consumer downstream.
588
+ - Python: normalizer → disk/cache/DB key — `grep -rn 'def normalize_\|
589
+ hashlib\.sha256' --include='*.py'` for the primitive, cross-checked
590
+ against `grep -rn 'pickle\.dump\|redis\.set\|\.save(' --include='*.py'`
591
+ for a persisted consumer of its output.
592
+ - JS/TS: hash → localStorage/DB key/JWT — `grep -rn
593
+ 'crypto\.createHash\|normalize' --include='*.ts' --include='*.js'` for
594
+ the primitive, cross-checked against `grep -rn
595
+ 'localStorage\.setItem\|jwt\.sign\|\.save(' --include='*.ts'
596
+ --include='*.js'` for a persisted consumer.
597
+ - Fallback: find normalizer/hash primitives; check whether their output
598
+ feeds a persisted value or licensing comparison downstream, and whether
599
+ a pinned-output test guards against accidental drift.
600
+
601
+ ## Class 16 — Unauthenticated hot-path route
602
+
603
+ **Consumers:** hotpath
604
+
605
+ **Definition:** A request-handling route on a hot path — one reachable by an external, unauthenticated caller off the box (a customer-facing HTTP/RPC endpoint) — has no authentication or authorization check in its call chain before it touches business logic or data.
606
+
607
+ **Why it's expensive:** An externally-reachable handler with no auth check is a direct path to data or actions the caller was never granted. This is scoped narrowly on purpose: it applies only to a route that is actually reachable by an unauthenticated caller off the box — an internal-only route (behind internal-network middleware, admin-only binding, loopback-only listener), or a deliberately open endpoint (health check, static asset, login/signup route itself), is not a finding. A local/internal-trust surface is not the same threat as an externally-reachable one. This distinction is also why thrum's own hot-path handlers get **no probe for this class in Go** (see below) — thrum's daemon RPC surface sits behind an mTLS + pairing perimeter that already authenticates every non-loopback caller, so "route lacking auth" is not a coherent finding against thrum's own hot path. Do not import that exemption into a customer repo: a typical Flask/Express/Go web service has no equivalent perimeter, and a route handler in its public API is presumptively externally reachable unless there is clear evidence of an internal-only guard (internal-network middleware, admin-only bind address, an explicit auth-exempt allowlist).
608
+
609
+ **Detection heuristic:** find route/handler registrations on the hot path (per the target repo's routing framework) and check whether an auth decorator/middleware/dependency guard appears in the handler's own chain (not just declared somewhere in the app and never wired to this route). A route with no such guard, and no adjacent evidence that it is internal-only or intentionally public, is a finding.
610
+
611
+ **Per-language probes:**
612
+
613
+ - Go: none — thrum's own hot-path handlers sit behind an mTLS perimeter that already authenticates every non-loopback caller; this concept targets repos with no equivalent perimeter. Emit no Go probe.
614
+ - Python: `grep -rn '@app\.\(route\|get\|post\|put\|delete\|patch\)\|@router\.\(get\|post\|put\|delete\|patch\)' --include='*.py'`, then for each match check the surrounding function/decorator stack for `@requires_auth`, `@login_required`, or a `Depends(verify_token)`/`Depends(get_current_user)`-shaped FastAPI dependency; a route with none of these, and no `# public`/`# internal-only` marker, is a finding.
615
+ - JS/TS: `grep -rn "app\.\(get\|post\|put\|delete\|patch\)(\|router\.\(get\|post\|put\|delete\|patch\)(" --include='*.ts' --include='*.js'`, then check whether an auth middleware (e.g. `requireAuth`, `passport.authenticate`, `verifyToken`) appears in the same handler's middleware chain before the handler body.
616
+ - Rust: no probe defined for this concept yet.
617
+ - Fallback: find the target language's route/handler registration primitive; check whether an auth guard (middleware, decorator, dependency-injection check) sits in that specific handler's chain, and treat internal-only-bound or explicitly-public routes as out of scope rather than findings.
618
+
619
+ ## Class 17 — Secret or token value flows into a log
620
+
621
+ **Consumers:** hotpath
622
+
623
+ **Definition:** A hot-path handler logs or prints a request object, auth header, bearer token, API key, or other secret-shaped value — directly or via a wholesale dump of headers/request state — rather than a redacted or field-scoped log line.
624
+
625
+ **Why it's expensive:** Logs are typically retained far longer than the request, read by a wider audience (log aggregators, on-call engineers, third-party log-shipping services) than the original caller intended, and rarely treated with the same access control as the primary datastore. A token or secret that lands in a log is effectively broadcast to every downstream consumer of that log stream, and the leak is invisible until someone greps the logs.
626
+
627
+ **Detection heuristic:** find log/print calls on the hot path and check whether their arguments include a whole request/headers object, or a variable named/typed like a token, secret, password, or API key, without an intervening redaction step.
628
+
629
+ **Per-language probes:**
630
+
631
+ - Go: none — whether thrum's own daemon logging should get a probe for this pattern is left for a future pass. Emit no Go probe.
632
+ - Python: `grep -rn 'log\(ger\)\?\.\(info\|debug\|warning\|error\)(.*\(token\|request\.headers\|authorization\|api_key\|secret\)\|print(.*\(token\|request\.headers\|authorization\)' --include='*.py' -i`
633
+ - JS/TS: `grep -rn 'console\.\(log\|error\|warn\|info\)(.*\(req\.headers\|token\|authorization\|apiKey\|secret\)' --include='*.ts' --include='*.js' -i`
634
+ - Rust: no probe defined for this concept yet.
635
+ - Fallback: find the language's logging/print primitives on the hot path; check whether any call site passes a whole headers/request object or a token/secret/password/api-key-named variable without a redaction step first.
636
+
637
+ ## Class 18 — Hot-path handler or proxy loop with no concurrency cap
638
+
639
+ **Consumers:** hotpath
640
+
641
+ **Definition:** A hot-path handler or proxy/fan-out loop issues unbounded concurrent work (unbounded `Promise.all`, an unguarded per-request loop dialing out to N downstream calls, a proxy relay with no semaphore/limiter) with no cap on in-flight concurrency and no rate limiter protecting the entry point.
642
+
643
+ **Why it's expensive:** Without a concurrency cap, load on this path scales directly with caller-controlled fan-out (request volume, or the size of a caller-supplied list/batch) rather than with any server-chosen bound. A burst of legitimate traffic — or a single caller sending a large batch — can exhaust downstream connections, memory, or file descriptors, causing backpressure collapse for every other caller on the same process. This is a request-shape and resource-exhaustion concern, distinct from an out-of-scope on-path network adversary (ARP poisoning, packet drops): sizing a concurrency cap or rate limiter against ordinary caller-controlled load is in scope even where sizing against a network-level adversary is not.
644
+
645
+ **Detection heuristic:** find the hot-path handler or proxy/relay loop and check for (a) a rate limiter or throttle guarding the entry point, and (b) a concurrency cap (semaphore, worker pool, bounded queue) around any per-request fan-out to downstream calls. A loop or `Promise.all`-shaped fan-out with neither is a finding; a rate-limiter decorator/middleware that was present and has since been removed (a diff-visible regression) is also a finding.
646
+
647
+ **Per-language probes:**
648
+
649
+ - Go: none. Emit no Go probe.
650
+ - Python: `grep -rn 'for .* in .*:\s*$' --include='*.py' -A5` in proxy/relay-shaped modules, checked for an absent `Semaphore`/`BoundedSemaphore` around the loop body; separately `grep -rn '@limiter\.\(limit\|exempt\)\|@ratelimit' --include='*.py'` cross-checked via `git log -p` for a removed `@limiter` decorator on a hot-path route.
651
+ - JS/TS: `grep -rn 'Promise\.all(' --include='*.ts' --include='*.js'`, checked for whether the mapped array length is caller-controlled (request body/query param) and no chunking/`p-limit`/semaphore wraps it; separately `grep -rn 'rateLimit\|express-rate-limit\|limiter' --include='*.ts' --include='*.js'` to confirm a limiter exists on the entry point.
652
+ - Rust: no probe defined for this concept yet.
653
+ - Fallback: find the hot-path handler or proxy/fan-out loop; check for a rate limiter at the entry point and a concurrency cap (semaphore, bounded worker pool) around any per-request fan-out, and check version history for a removed limiter on that route.