@tyroneross/build-loop 0.36.0 → 0.43.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 (270) hide show
  1. package/.agents/plugins/marketplace.json +2 -2
  2. package/.claude-plugin/marketplace.json +3 -3
  3. package/.claude-plugin/plugin.json +1 -1
  4. package/.codex-plugin/plugin.json +1 -1
  5. package/.cursor/rules/build-loop-surface.mdc +12 -11
  6. package/.cursor/rules/skill-index.mdc +33 -0
  7. package/AGENTS.md +213 -34
  8. package/README.md +99 -31
  9. package/agents/advisor.md +4 -4
  10. package/agents/alignment-checker.md +2 -2
  11. package/agents/architecture-scout.md +4 -4
  12. package/agents/build-orchestrator.md +38 -36
  13. package/agents/database-assessor.md +11 -5
  14. package/agents/design-contract-specialist.md +8 -8
  15. package/agents/fact-checker.md +13 -3
  16. package/agents/fix-critique.md +2 -2
  17. package/agents/independent-auditor.md +60 -7
  18. package/agents/leak-scanner.md +82 -0
  19. package/agents/overfitting-reviewer.md +2 -2
  20. package/agents/plan-critic.md +1 -1
  21. package/agents/promotion-reviewer.md +5 -5
  22. package/agents/retrospective-synthesizer.md +138 -35
  23. package/agents/scope-auditor.md +82 -11
  24. package/agents/security-reviewer.md +56 -2
  25. package/agents/self-improvement-architect.md +17 -3
  26. package/agents/transcript-pattern-miner.md +5 -5
  27. package/agents/ui-validator.md +1 -1
  28. package/bin/build-loop-debugger.js +143 -0
  29. package/bin/build-loop-install.js +1 -4
  30. package/bin/build-loop-load-probe.js +345 -0
  31. package/codex-skills/build-loop/SKILL.md +28 -6
  32. package/commands/feedback.md +37 -0
  33. package/dist/src/interactive-verifier.d.ts +1 -14
  34. package/dist/src/interactive-verifier.d.ts.map +1 -1
  35. package/dist/src/interactive-verifier.js +6 -113
  36. package/dist/src/interactive-verifier.js.map +1 -1
  37. package/dist/src/quality.d.ts +5 -0
  38. package/dist/src/quality.d.ts.map +1 -0
  39. package/dist/src/quality.js +81 -0
  40. package/dist/src/quality.js.map +1 -0
  41. package/dist/src/storage.d.ts.map +1 -1
  42. package/dist/src/storage.js +37 -3
  43. package/dist/src/storage.js.map +1 -1
  44. package/docs/agent-surface-policy.md +35 -31
  45. package/docs/memory-setup.md +19 -0
  46. package/hooks/git/pre-push +65 -4
  47. package/hooks/hooks.json +95 -38
  48. package/hooks/pre-commit +20 -1
  49. package/hooks/pre-edit-rally-point.sh +10 -3
  50. package/hooks/session-start-codex-hook-trust.sh +30 -0
  51. package/hooks/session-start-git-hooks.sh +3 -1
  52. package/hooks/session-start-rally-point.sh +52 -4
  53. package/hooks/session-start-worktree-gc.sh +47 -94
  54. package/hooks/stop-transcript-sweep.sh +173 -0
  55. package/hooks/test_closeout.sh +14 -2
  56. package/package.json +8 -7
  57. package/scripts/README.md +1 -1
  58. package/scripts/_paths.py +65 -0
  59. package/scripts/groundwork_exchange.py +1012 -0
  60. package/scripts/install_memory.py +33 -1
  61. package/scripts/lessons_index/ingest.py +13 -2
  62. package/scripts/lessons_index/query.py +36 -13
  63. package/scripts/memory_context/__init__.py +108 -14
  64. package/scripts/memory_graph/__init__.py +5 -1
  65. package/scripts/project_resolver.py +42 -36
  66. package/scripts/sync_plugin_cache.py +37 -2
  67. package/skills/agent-rally-point/SKILL.md +46 -0
  68. package/skills/api-registry-bridge/SKILL.md +1 -1
  69. package/skills/architecture/dead/SKILL.md +1 -1
  70. package/skills/architecture/impact/SKILL.md +1 -1
  71. package/skills/architecture/review/SKILL.md +1 -1
  72. package/skills/architecture/rules/SKILL.md +3 -3
  73. package/skills/architecture/scan/SKILL.md +1 -1
  74. package/skills/architecture/trace/SKILL.md +1 -1
  75. package/skills/attribution-standard/SKILL.md +6 -6
  76. package/skills/auto-decision-capture/SKILL.md +31 -2
  77. package/skills/auto-finding-capture/SKILL.md +28 -1
  78. package/skills/build-loop/SKILL.md +131 -23
  79. package/skills/build-loop/fallbacks.md +16 -21
  80. package/skills/build-loop/phases/ui-validation.md +2 -2
  81. package/skills/build-loop/references/advisor-dispatch-ladder.md +1 -1
  82. package/skills/build-loop/references/apple-native-planning.md +1 -1
  83. package/skills/build-loop/references/autonomous-and-per-commit-modes.md +11 -5
  84. package/skills/build-loop/references/autonomy-dashboard.md +115 -0
  85. package/skills/build-loop/references/capability-routing.md +24 -2
  86. package/skills/build-loop/references/coordination.md +24 -6
  87. package/skills/build-loop/references/experiment-results-template.md +15 -3
  88. package/skills/build-loop/references/leadership.md +1 -1
  89. package/skills/build-loop/references/memory.md +14 -3
  90. package/skills/build-loop/references/modular-systems-pack.md +8 -0
  91. package/skills/build-loop/references/output-style.md +86 -0
  92. package/skills/build-loop/references/phase-1-assess.md +102 -2
  93. package/skills/build-loop/references/phase-2-plan.md +9 -1
  94. package/skills/build-loop/references/phase-3-execute.md +5 -2
  95. package/skills/build-loop/references/phase-4-review.md +85 -8
  96. package/skills/build-loop/references/phase-5-iterate.md +76 -8
  97. package/skills/build-loop/references/phase-6-learn.md +10 -17
  98. package/skills/build-loop/references/privileged-request-broker.md +254 -0
  99. package/skills/build-loop/references/resource-aware-execution.md +183 -0
  100. package/skills/build-loop/references/self-recursive-dev.md +2 -2
  101. package/skills/build-loop/references/status-output-format.md +207 -0
  102. package/skills/build-loop/references/verify-dispatch.md +56 -2
  103. package/skills/building-with-deepagents/SKILL.md +1 -1
  104. package/skills/claim-scope/SKILL.md +185 -0
  105. package/skills/color-engine/SKILL.md +103 -0
  106. package/skills/color-engine/_core.py +464 -0
  107. package/skills/color-engine/color_engine.py +175 -0
  108. package/skills/cost-rca/SKILL.md +61 -0
  109. package/skills/data-plane-worktrees/SKILL.md +139 -0
  110. package/skills/data-plane-worktrees/agents/openai.yaml +4 -0
  111. package/skills/database-practice/SKILL.md +200 -0
  112. package/skills/database-practice/references/diagnostic-queries.sql +126 -0
  113. package/skills/database-practice/references/vector-and-graph-tuning.md +208 -0
  114. package/skills/database-practice/scripts/db_table_map.py +1244 -0
  115. package/skills/database-practice/scripts/test_db_table_map.py +514 -0
  116. package/skills/debug-loop/SKILL.md +36 -6
  117. package/skills/debugging-memory/SKILL.md +32 -430
  118. package/skills/debugging-memory/references/pattern-extraction.md +4 -4
  119. package/skills/debugging-memory/references/search.md +32 -120
  120. package/skills/debugging-memory/references/store.md +32 -126
  121. package/skills/debugging-memory/references/subagent-integration.md +1 -1
  122. package/skills/decision-queue/SKILL.md +251 -0
  123. package/skills/decision-queue/assets/template.html +1242 -0
  124. package/skills/decision-queue/references/example-large-queue-batching.md +164 -0
  125. package/skills/decision-queue/scripts/regen_template_constants.py +160 -0
  126. package/skills/defenseclaw-bridge/SKILL.md +2 -2
  127. package/skills/defenseclaw-bridge/references/dc-config-mapping.md +2 -9
  128. package/skills/drain-proposals/SKILL.md +53 -0
  129. package/skills/focused-loop-builder/SKILL.md +31 -0
  130. package/skills/focused-loop-builder/references/spec-format.md +27 -0
  131. package/skills/handoff/SKILL.md +169 -8
  132. package/skills/ibr-bridge/SKILL.md +4 -1
  133. package/skills/knowledge/SKILL.md +26 -14
  134. package/skills/knowledge/references/review-mode.md +2 -3
  135. package/skills/knowledge/templates/madr-minimal.md +1 -1
  136. package/skills/mcp-builder/SKILL.md +1 -1
  137. package/skills/model-bakeoff/SKILL.md +48 -10
  138. package/skills/model-tiering/SKILL.md +92 -31
  139. package/skills/native-ax-driver/SKILL.md +38 -5
  140. package/skills/native-ax-driver/scripts/native_driver.py +278 -22
  141. package/skills/native-ax-driver/scripts/test_native_driver.py +227 -0
  142. package/skills/optimize/SKILL.md +1 -1
  143. package/skills/plugin-builder/SKILL.md +48 -1
  144. package/skills/plugin-builder/references/build-loop-phase-guidance.md +3 -4
  145. package/skills/plugin-builder/references/distribution.md +13 -2
  146. package/skills/plugin-builder/references/plugin-hygiene-lessons.md +2 -2
  147. package/skills/plugin-tests/SKILL.md +2 -2
  148. package/skills/recursive-retrospective/SKILL.md +1 -1
  149. package/skills/repo-closeout/SKILL.md +17 -0
  150. package/skills/repo-closeout/agents/openai.yaml +4 -0
  151. package/skills/repo-maintenance/SKILL.md +179 -0
  152. package/skills/repo-maintenance/agents/openai.yaml +4 -0
  153. package/skills/repo-maintenance/references/pre-public-hygiene.md +134 -0
  154. package/skills/repo-maintenance/references/repository-taxonomy.md +161 -0
  155. package/skills/repo-maintenance/references/safety-protocol.md +106 -0
  156. package/skills/repo-maintenance/references/stack-profiles.md +138 -0
  157. package/skills/repo-maintenance/scripts/audit_repo_maintenance.py +1198 -0
  158. package/skills/repo-maintenance/scripts/test_audit_repo_maintenance.py +506 -0
  159. package/skills/repository-intelligence/SKILL.md +189 -0
  160. package/skills/repository-intelligence/agents/openai.yaml +4 -0
  161. package/skills/repository-intelligence/references/assessment-rubric.md +88 -0
  162. package/skills/repository-intelligence/scripts/repository_inventory.py +347 -0
  163. package/skills/research/SKILL.md +12 -2
  164. package/skills/root-cause-analysis/SKILL.md +1 -1
  165. package/skills/runtime-parity-verification/SKILL.md +36 -1
  166. package/skills/security-methodology/SKILL.md +23 -10
  167. package/skills/security-methodology/references/agentic-handoff-templates.md +220 -0
  168. package/skills/security-methodology/references/cross-source-matrix.md +1 -1
  169. package/skills/security-methodology/references/owasp-agentic-top-10.md +1 -1
  170. package/skills/security-scan/SKILL.md +55 -15
  171. package/skills/self-improve/SKILL.md +70 -50
  172. package/skills/silent-assumptions/SKILL.md +341 -0
  173. package/skills/silent-assumptions/references/elicitation-detectors.md +342 -0
  174. package/skills/spec-writing/SKILL.md +128 -24
  175. package/skills/spec-writing/scripts/check_checklist.py +114 -15
  176. package/skills/ui-design/SKILL.md +6 -4
  177. package/skills/ui-design/references/color-engine.md +132 -0
  178. package/skills/ui-design/references/design-preferences-from-owned-apps.md +8 -8
  179. package/skills/ui-design/references/ui-guidance-sources.md +1 -1
  180. package/skills/ui-design/references/universal-design-principles.alt.md +2 -2
  181. package/plugin-artifacts/codex/.codex-plugin/plugin.json +0 -41
  182. package/plugin-artifacts/codex/AGENTS.md +0 -560
  183. package/plugin-artifacts/codex/BUILD-ARTIFACT.md +0 -5
  184. package/plugin-artifacts/codex/LICENSE +0 -202
  185. package/plugin-artifacts/codex/README.md +0 -313
  186. package/plugin-artifacts/codex/assets/build-loop-plugin-icon.png +0 -0
  187. package/plugin-artifacts/codex/docs/agent-surface-policy.md +0 -63
  188. package/plugin-artifacts/codex/references/advisor-dispatch-ladder.md +0 -62
  189. package/plugin-artifacts/codex/references/agent-role-taxonomy.md +0 -135
  190. package/plugin-artifacts/codex/references/autonomous-and-per-commit-modes.md +0 -161
  191. package/plugin-artifacts/codex/references/autonomy-config.md +0 -231
  192. package/plugin-artifacts/codex/references/backlog-system.md +0 -285
  193. package/plugin-artifacts/codex/references/capability-routing.md +0 -231
  194. package/plugin-artifacts/codex/references/codex-subagents.md +0 -106
  195. package/plugin-artifacts/codex/references/coordination-file-template.md +0 -181
  196. package/plugin-artifacts/codex/references/coordination-rules.md +0 -552
  197. package/plugin-artifacts/codex/references/dogfood-reload-checkpoint.md +0 -112
  198. package/plugin-artifacts/codex/references/halt-and-ask-protocol.md +0 -102
  199. package/plugin-artifacts/codex/references/implementer-envelope-schema.md +0 -302
  200. package/plugin-artifacts/codex/references/intent-capability-pack.md +0 -257
  201. package/plugin-artifacts/codex/references/intent-exploration-prompts.md +0 -96
  202. package/plugin-artifacts/codex/references/leadership.md +0 -72
  203. package/plugin-artifacts/codex/references/memory-systems.md +0 -261
  204. package/plugin-artifacts/codex/references/memory.md +0 -313
  205. package/plugin-artifacts/codex/references/model-tier-mapping.md +0 -296
  206. package/plugin-artifacts/codex/references/modular-systems-pack.md +0 -96
  207. package/plugin-artifacts/codex/references/phase-1-assess.md +0 -249
  208. package/plugin-artifacts/codex/references/phase-2-plan.md +0 -86
  209. package/plugin-artifacts/codex/references/phase-3-execute.md +0 -49
  210. package/plugin-artifacts/codex/references/phase-4-review.md +0 -341
  211. package/plugin-artifacts/codex/references/phase-5-iterate.md +0 -72
  212. package/plugin-artifacts/codex/references/phase-6-learn.md +0 -58
  213. package/plugin-artifacts/codex/references/recent-design-structures.md +0 -274
  214. package/plugin-artifacts/codex/references/research-trigger-policy.md +0 -140
  215. package/plugin-artifacts/codex/references/runtime-smoke-triggers.md +0 -42
  216. package/plugin-artifacts/codex/references/self-review.md +0 -234
  217. package/plugin-artifacts/codex/references/single-writer-commit-protocol.md +0 -90
  218. package/plugin-artifacts/codex/references/task-capture-policy.md +0 -68
  219. package/plugin-artifacts/codex/references/ui-io-contract.md +0 -116
  220. package/plugin-artifacts/codex/references/ui-spotcheck-protocol.md +0 -65
  221. package/plugin-artifacts/codex/references/verify-dispatch.md +0 -85
  222. package/plugin-artifacts/codex/skills/build-loop/SKILL.md +0 -381
  223. package/plugin-artifacts/codex/skills/build-loop/detect-plugins.mjs +0 -82
  224. package/plugin-artifacts/codex/skills/build-loop/eval-guide.md +0 -65
  225. package/plugin-artifacts/codex/skills/build-loop/fallbacks.md +0 -549
  226. package/plugin-artifacts/codex/skills/build-loop/phases/fact-check.md +0 -42
  227. package/plugin-artifacts/codex/skills/build-loop/phases/ui-validation.md +0 -267
  228. package/plugin-artifacts/codex/skills/build-loop/references/advisor-dispatch-ladder.md +0 -62
  229. package/plugin-artifacts/codex/skills/build-loop/references/apple-native-planning.md +0 -439
  230. package/plugin-artifacts/codex/skills/build-loop/references/autonomous-and-per-commit-modes.md +0 -161
  231. package/plugin-artifacts/codex/skills/build-loop/references/capability-routing.md +0 -231
  232. package/plugin-artifacts/codex/skills/build-loop/references/codex-subagents.md +0 -106
  233. package/plugin-artifacts/codex/skills/build-loop/references/coordination.md +0 -161
  234. package/plugin-artifacts/codex/skills/build-loop/references/correction-aware-capture.md +0 -177
  235. package/plugin-artifacts/codex/skills/build-loop/references/experiment-results-template.md +0 -101
  236. package/plugin-artifacts/codex/skills/build-loop/references/independent-auditor.md +0 -72
  237. package/plugin-artifacts/codex/skills/build-loop/references/intent-capability-pack.md +0 -257
  238. package/plugin-artifacts/codex/skills/build-loop/references/intent-exploration-prompts.md +0 -96
  239. package/plugin-artifacts/codex/skills/build-loop/references/leadership.md +0 -72
  240. package/plugin-artifacts/codex/skills/build-loop/references/memory.md +0 -313
  241. package/plugin-artifacts/codex/skills/build-loop/references/modular-systems-pack.md +0 -96
  242. package/plugin-artifacts/codex/skills/build-loop/references/output-style.md +0 -222
  243. package/plugin-artifacts/codex/skills/build-loop/references/pay-it-forward-arch.md +0 -98
  244. package/plugin-artifacts/codex/skills/build-loop/references/phase-1-assess.md +0 -249
  245. package/plugin-artifacts/codex/skills/build-loop/references/phase-2-plan.md +0 -86
  246. package/plugin-artifacts/codex/skills/build-loop/references/phase-3-execute.md +0 -49
  247. package/plugin-artifacts/codex/skills/build-loop/references/phase-4-review.md +0 -341
  248. package/plugin-artifacts/codex/skills/build-loop/references/phase-5-iterate.md +0 -72
  249. package/plugin-artifacts/codex/skills/build-loop/references/phase-6-learn.md +0 -58
  250. package/plugin-artifacts/codex/skills/build-loop/references/recent-design-structures.md +0 -274
  251. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/ASSESSMENT.md +0 -85
  252. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/STANDALONE_TEST_RUN.md +0 -149
  253. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/01-simple-bugfix.md +0 -32
  254. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/02-ui-build-with-iteration.md +0 -48
  255. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/03-multi-failure-escalation.md +0 -60
  256. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/04-ui-build-ibr-absent.md +0 -51
  257. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/05-refactor-navgator-absent.md +0 -71
  258. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/06-recurring-bug-debugger-absent.md +0 -52
  259. package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/trace-comparison.md +0 -202
  260. package/plugin-artifacts/codex/skills/build-loop/references/self-recursive-dev.md +0 -77
  261. package/plugin-artifacts/codex/skills/build-loop/references/self-review.md +0 -234
  262. package/plugin-artifacts/codex/skills/build-loop/references/ui-io-contract.md +0 -116
  263. package/plugin-artifacts/codex/skills/build-loop/references/verify-dispatch.md +0 -85
  264. package/plugin-artifacts/codex/skills/build-loop/scanners/audit-design-rules.mjs +0 -476
  265. package/plugin-artifacts/codex/skills/build-loop/scanners/require-visual-evidence.mjs +0 -239
  266. package/plugin-artifacts/codex/skills/build-loop/templates/backlog-item.md +0 -35
  267. package/plugin-artifacts/codex/skills/build-loop/templates/codex-worker-prompt.md +0 -100
  268. package/plugin-artifacts/codex/skills/build-loop/templates/ui-subagent-prompt.md +0 -179
  269. package/plugin-artifacts/codex/skills/build-loop/templates/ux-fix-plan.md +0 -40
  270. package/scripts/build_codex_plugin_artifact.py +0 -321
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: scope-auditor
3
3
  description: Read-only Plan→Execute boundary check. For every commit that changes a public function/component/type signature, traces every caller-site outside the commit's owned-files, then either confirms `internal_only: true` or appends the missing caller files to the appropriate commit's owned-files list. Prevents the "fan-out scope-blindness" defect class observed in round-2 of dispatch-pattern testing (example-app 2026-05-07).
4
- model: fable
5
- tier: frontier
4
+ model: opus
5
+ tier: thinking
6
6
  segment: governance_evaluation
7
7
  tools: ["Read", "Grep", "Glob"]
8
8
  ---
@@ -18,7 +18,7 @@ The orchestrator dispatches you after Phase 2 Plan completes (plan-verify clean,
18
18
  ## Input
19
19
 
20
20
  ```
21
- plan_path: <absolute path to docs/plans/<feature>.md>
21
+ plan_path: <absolute path to .build-loop/plans/<feature>.md>
22
22
  workdir: <absolute path to project root>
23
23
  commit_table: [
24
24
  { id: "C1", subject: "...", files_owned: ["..."], modifies_api: ["functionA", "ComponentB", "TypeC"] | null },
@@ -32,20 +32,80 @@ The orchestrator extracts `modifies_api` per commit by parsing the spec's "Six-C
32
32
 
33
33
  For each commit with `modifies_api` non-empty:
34
34
 
35
- 1. **For each symbol in `modifies_api`**, run a project-wide grep:
35
+ 1. **For each symbol in `modifies_api`**, resolve its callers. Try the language
36
+ server first; fall back to grep only when you must, and record which you used.
37
+
38
+ The caller-resolution tool is the `code-intel` CLI below — **never the host's
39
+ built-in `LSP` tool**. The built-in answers from whichever servers a host
40
+ happens to have registered and **degrades silently**: on a language with no
41
+ registered server it returns a confident, incomplete result with no error and
42
+ no readiness signal. Observed 2026-08-29 (Claude Code, Python-only server
43
+ registered): `findReferences` on an exported TypeScript function returned 1
44
+ hit — the declaration — where `code-intel refs` returned 4, including both
45
+ real importers. A declaration-only result is the signature of this failure.
46
+
47
+ Judge readiness **only** from the query response's `ready` field, never from
48
+ `code-intel doctor`. `doctor` answers globally while `typescript-language-server`
49
+ resolves `typescript` per workspace, so it can report a language NOT READY
50
+ whose queries in an actual project succeed.
51
+
52
+ ```bash
53
+ code-intel refs "<file>::<symbol-name>"
54
+ ```
55
+
56
+ Returns compact JSON: one `{"at": "src/x.ts:107", "in": "containingSymbol"}`
57
+ per real reference, plus a top-level `"ready"` boolean. The declaration is
58
+ already excluded.
59
+
60
+ Decide by these rules, in order:
61
+
62
+ - **If the command succeeds and `ready` is `true`** → use those hits.
63
+ Set `method: "lsp"`. This is the accurate path.
64
+ - **If `ready` is `false`** → the result is **UNKNOWN, not empty**. The server
65
+ was still indexing. Set `method: "lsp-unready"` and
66
+ `caller_audit_complete: false`. **Never** report "no callers" from an
67
+ unready result — that is a false clean bill of health.
68
+ - **If `code-intel` is not on PATH, or it reports no registered server for
69
+ that file's language** → fall back to the grep below. Set
70
+ `method: "grep-fallback"` and name the reason in `fallback_reason`.
71
+ - **If the symbol name is ambiguous** (`code-intel` returns an "ambiguous"
72
+ error listing candidates) → re-run qualified, e.g.
73
+ `"<file>::ParentType/<symbol-name>"`. Do not pick a candidate yourself.
74
+
75
+ Grep fallback, unchanged, for when the rules above send you here:
36
76
  ```bash
37
- # function/component name (excluding test files and the file that DEFINES it)
38
77
  grep -rn --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" \
39
78
  "<symbol-name>" "${workdir}" \
40
79
  | grep -v "/test" | grep -v ".test." | grep -v ".spec."
41
80
  ```
42
- Use ripgrep if available; fall back to `grep -rn`.
81
+
82
+ Why this order, measured on a real 13.08M-line codebase — do not treat it as
83
+ a style preference:
84
+
85
+ - That grep pattern covers `.ts/.tsx/.js/.jsx` only, which is **33.5%** of the
86
+ code. Python (40.3%), Swift (12.1%), Rust (10.7%) and C (1.4%) get **no
87
+ caller check at all** and the audit returns clean. `method` exists so a
88
+ reader can tell "no callers" from "never looked".
89
+ - Grep's error rate scales with how common the name is. Symbol `which`: 15
90
+ grep hits, **2** real calls, 12 comments and strings. Symbol `tests`: 9 grep
91
+ hits, **0** real references. Symbol `scan`: **458** grep hits in one repo.
92
+ - For distinctive names grep is already accurate — `resolveComponent`: grep
93
+ 24, language server 22, the difference being the declaration and an import
94
+ line. The language server earns its place on the ambiguous names, not all
95
+ of them.
43
96
 
44
97
  2. **Classify each hit** as one of:
45
- - **Definition site** — the file that exports/declares the symbol (typically inside `files_owned`)
46
- - **Caller site** imports + calls the symbol from another file
47
- - **Reference / type-only** — type imports, JSDoc references usually safe to ignore unless the type changed shape
48
- - **Test site** — already excluded by the grep filter above
98
+ - **Caller site** — calls the symbol from another file. On the `lsp` path
99
+ every returned hit is one of these; the `in` field names the enclosing
100
+ symbol, so use it in your rationale rather than a bare line number.
101
+ - **Reference / type-only** — type imports, JSDoc references usually safe to
102
+ ignore unless the type changed shape
103
+ - **Definition site** — the file that exports/declares the symbol (typically
104
+ inside `files_owned`). Excluded automatically on the `lsp` path; on the
105
+ `grep-fallback` path you must exclude it yourself.
106
+ - **Test site** — excluded by the grep filter on the fallback path only.
107
+ `code-intel` returns test callers, and a test that breaks is still a caller
108
+ that breaks: classify it, do not drop it.
49
109
 
50
110
  3. **For each caller site outside the commit's `files_owned`**:
51
111
  - Determine if the caller needs an update to honor the new contract:
@@ -67,11 +127,15 @@ For each commit with `modifies_api` non-empty:
67
127
  {
68
128
  "id": "C2",
69
129
  "modifies_api": ["synthesizeSpeech", "TTSResult"],
130
+ "method": "lsp | lsp-unready | grep-fallback",
131
+ "fallback_reason": "<why, or null when method is lsp>",
132
+ "caller_audit_complete": true,
70
133
  "callers_found": [
71
134
  {
72
135
  "file": "app/api/podcast/generate/route.ts",
73
136
  "symbol": "synthesizeSpeech",
74
137
  "in_owned_files": false,
138
+ "in_symbol": "handlePost",
75
139
  "caller_needs_update": true,
76
140
  "recommendation": "Add to C3's files_owned (consumer of new contract); already in plan."
77
141
  }
@@ -87,6 +151,13 @@ For each commit with `modifies_api` non-empty:
87
151
  ```
88
152
 
89
153
  5. **Verdict semantics**:
154
+
155
+ `caller_audit_complete: false` (method `lsp-unready`, or `grep-fallback` on a
156
+ language the fallback grep does not cover) means the audit did not establish
157
+ the caller set. Report `scope_gap_found` with the reason, never
158
+ `scope_complete` — an audit that could not look must not read as an audit
159
+ that looked and found nothing.
160
+
90
161
  - `scope_complete`: every caller site is either inside the commit's owned-files, listed in a downstream commit's owned-files, or explicitly justified as not-requiring-update.
91
162
  - `scope_gap_found`: ≥1 caller site is outside scope and needs update — the orchestrator MUST revise the plan before Execute, OR explicitly accept the gap and flag it for Iterate.
92
163
 
@@ -107,7 +178,7 @@ For each commit with `modifies_api` non-empty:
107
178
 
108
179
  ## Edge cases
109
180
 
110
- - **Symbol shadowed in multiple files** (e.g., `Article` type defined in 3 modules): grep returns false positives. Resolve by following the import statement at each caller site to the actual definition.
181
+ - **Symbol shadowed in multiple files** (e.g., `Article` type defined in 3 modules): only a concern on the `grep-fallback` path, where it produces false positives. On the `lsp` path the server resolves the symbol, so shadowing is already handled.
111
182
  - **Re-exports**: `lib/index.ts` re-exports a symbol from `lib/foo.ts`. Treat the re-export point as a transparent forwarder — the canonical caller analysis is at the consumer of the re-export.
112
183
  - **Dynamic imports** (`import('...')`): grep won't find them naturally. Add a secondary pass:
113
184
  ```bash
@@ -14,7 +14,7 @@ description: |
14
14
  user: "Security check on the auth changes"
15
15
  assistant: "I'll use the security-reviewer agent — diff vs OWASP Web A01/A03 + LLM06 + ASI03 — and emit a structured findings report."
16
16
  </example>
17
- model: fable
17
+ model: opus
18
18
  tier: frontier
19
19
  segment: governance_evaluation
20
20
  color: red
@@ -31,6 +31,26 @@ You are a build-time security reviewer. You have no ability to fix files — onl
31
31
  - **Exclude**: code style, naming, performance, generic test coverage, business correctness — those belong to `independent-auditor` (build scope) and `fact-checker`. You only flag security-relevant findings.
32
32
  - **Build-time, not runtime**. You do not generate guardrail enforcement code, do not propose runtime fixes, and do not assert that any control "blocks" anything in production. That's the bridge skill's territory (`build-loop:defenseclaw-bridge`) plus whatever runtime layer the project actually deploys.
33
33
 
34
+ ## Run the deterministic scanner FIRST
35
+
36
+ `scripts/security_scan.py` already grades the greppable structure — secrets, injection, missing owner predicates, fail-open auth guards, client-exposed keys, token hygiene, CORS, mass assignment, uncapped model calls, unfiltered retrieval, ungated tool dispatch. Run it and read its output before you start reading files:
37
+
38
+ ```
39
+ python3 "${CLAUDE_PLUGIN_ROOT}/scripts/security_scan.py" --path . --json --diff HEAD~1 --spot-check
40
+ ```
41
+
42
+ Then spend your budget on what it structurally cannot answer:
43
+
44
+ - Whether the owner predicate it found is the **correct** one for this data model (scanner sees `userId` present; it cannot see that the resource is owned by an org, not a user).
45
+ - **Property-level** authorization — which fields this caller may read or write, not merely whether the row is theirs.
46
+ - Whether the **tenant boundary** is coherent across the request path, versus scoped in one query and lost in the next.
47
+ - Whether a tool's granted **permission tier matches its actual task need**, and whether the approval policy fits the blast radius.
48
+ - **Workflow authorization**: may this caller perform this business action, in this state, at this velocity.
49
+ - Whether **RAG corpus partitioning** reflects real entitlements, versus a filter that exists but selects the wrong set.
50
+ - Agent **goal-drift** and cascading trust across chained model calls.
51
+
52
+ Do not re-report a finding the scanner already emitted with the same file and line unless you are **raising** its severity with reasoning the scanner could not have. Say so explicitly when you do.
53
+
34
54
  ## Inputs
35
55
 
36
56
  1. The diff for the current chunk (use `git diff HEAD~1 -- <files>` against the file list provided by the orchestrator).
@@ -62,6 +82,13 @@ Each finding maps to one or more risk IDs from the canonical matrix in `skills/s
62
82
  | Code execution | `eval`, `exec`, `Function(...)`, dynamic `import`, deserialization of untrusted data, shell composition | ASI05, A03 |
63
83
  | HTTP boundary | New endpoint without auth, authz check, rate limit, or input validation; SSRF-prone outbound fetch | A01, A03, A10 |
64
84
  | HTTP boundary | Outbound URL constructed from user input or LLM output without allowlist | A10, ASI05 |
85
+ | Object authz | Query scoped to a principal, but the WRONG principal for this data model (user-scoped where the resource is org-owned, or vice versa) | A01 |
86
+ | Property authz | Caller may access the row but not every field on it — no field-level read/write separation | A01, A04 |
87
+ | Tenant boundary | Tenant scoping enforced in one query and dropped in a downstream call on the same request path | A01 |
88
+ | Workflow authz | Business action permitted by role and ownership but not valid in the current state, or not rate-limited as a business flow (bulk account creation, repeated inventory holds) | A01, LLM10 |
89
+ | Client boundary | Capability exposed to the browser or mobile binary that assumes a client-side check is a security boundary | A01, A07 |
90
+ | Credential lifetime | Long-lived static credential where a short-lived workload identity is available; no rotation or revocation path | A07 |
91
+ | Error surface | Client-facing error carrying a stack trace, SQL message, internal hostname, or framework version | A05 |
65
92
  | Cost / DoS | New external API or LLM call without budget cap, timeout, or retry ceiling | LLM04 |
66
93
  | Code execution | Dropping validation, type checks, or auth gates as a "simplification" | LLM07, LLM08, ASI03 |
67
94
 
@@ -93,7 +120,7 @@ Severity rules:
93
120
  1. Read `.build-loop/state.json.triggers`. If `riskSurfaceChange` is not true, emit `{"findings": [], "skipped_reason": "..."}` and stop.
94
121
  2. Read `.build-loop/goal.md` and `.build-loop/intent.md` — orient on what was supposed to change.
95
122
  3. Load `Skill("build-loop:security-methodology")`. Read the cross-source matrix and the detection-pattern files for the OWASP layer that applies (LLM Top 10 always; Agentic Top 10 when an agent or tool was added; Web Top 10 when an HTTP endpoint changed).
96
- 3b. **Required route-auth enumeration (LO-5, A01).** When any HTTP endpoint changed, do not sample — **walk every** `app/api/**/route.ts` (or framework equivalent) mutating/DDL handler and confirm each has an auth guard that **fails closed** when its secret env is unset (the `token !== process.env.X` bypass: if `X` is undefined the check passes). This access-control sweep is the counterpart to `database-assessor`'s destructive-FK sweep — neither lens is a superset (atomize-ai 2026-06-30: 8 A/B runs here missed a destructive cascade; a DB-RCA missed 4 unauth routes). Lead findings with a blast-radius verdict per the methodology's SC-1 default.
123
+ 3b. **Required route-auth enumeration (LO-5, A01).** When any HTTP endpoint changed, do not sample — **walk every** `app/api/**/route.ts` (or framework equivalent) mutating/DDL handler and confirm each has an auth guard that **fails closed** when its secret env is unset (the `token !== process.env.X` bypass: if `X` is undefined the check passes). This access-control sweep is the counterpart to `database-assessor`'s destructive-FK sweep — neither lens is a superset (private-app stress test on 2026-06-30: 8 A/B runs here missed a destructive cascade; a DB-RCA missed 4 unauth routes). Lead findings with a blast-radius verdict per the methodology's SC-1 default.
97
124
  4. Get the file list from the orchestrator's dispatch packet. Read each changed file; do not scan files outside the chunk.
98
125
  5. For each change, walk the table above. When a row matches, draft a finding with mandatory fields below.
99
126
  6. Cross-reference each finding against `skills/security-methodology/references/cross-source-matrix.md` to assign `mapped_risks`. If no row in the matrix applies, the finding is not security — drop it (other agents handle non-security drift).
@@ -115,6 +142,7 @@ Severity rules:
115
142
  "snippet": "<≤120 chars from the diff or file>",
116
143
  "minimal_patch_shape": "<smallest change that closes it — validation, allowlist, sandbox, boundary>",
117
144
  "recommendation": "<concrete next step — what change in code / config / boundary would close this>",
145
+ "hostile_input": "<MANDATORY — the LITERAL input an attacker types to exercise this. The exact argv, path, header, payload, or call, verbatim. Not a description of the class.>",
118
146
  "closure_proof": "<the regression check that proves it's closed (test/assertion/probe); null until closed>"
119
147
  }
120
148
  ],
@@ -131,6 +159,32 @@ Severity rules:
131
159
 
132
160
  **Severity normalization (QM v0.13.0).** These `CRITICAL|HIGH|MEDIUM|LOW` values are the normalized gating scale; `review_finding_gate.py` reads them case-insensitively and treats `critical`/`high` as blocking (clears only on `closed` + `closure_proof`). The `*_count` fields above are also consumed by the gate as a fallback signal. A CRITICAL/HIGH finding therefore blocks final Review exit until closed with `closure_proof` — consistent with `independent-auditor`'s normalized findings.
133
161
 
162
+ ## `hostile_input` — write the attack, not the class
163
+
164
+ `hostile_input` is mandatory on every finding, and it must be the **literal thing an attacker types**: the exact argv, path, header, payload, URL, or function call — verbatim, copy-pasteable. `"a path outside the repo"` is a class. `resolve_target("/Users/x/Library/App/store.db")` is a hostile input. Only the second can be pasted into a test.
165
+
166
+ The field exists because a test written by reading the implementation enumerates the branches that exist, while a test written from the threat asks what the attacker types — and those differ exactly where the bug lives. Observed 2026-08-07: a guard written to refuse writing to a live store shipped with a test asserting three things (in-repo target refused, default-with-flag-absent refused, outside path returns absolute). All three passed. None of them called the function with the live store as an explicit argument — the attack the finding named. The guard checked its flag only on the branch where the path was omitted, so naming the path explicitly walked straight past it, and the shipped code wrote 49 entries into the user's real store.
167
+
168
+ ## Closure gate — the test must contain the attack
169
+
170
+ A finding is `closed` only when BOTH hold, verified by execution:
171
+
172
+ 1. **The hostile input is present in the test.**
173
+ ```bash
174
+ python3 "${CLAUDE_PLUGIN_ROOT:-.}/scripts/hostile_input_gate.py" check \
175
+ --hostile-input "<the literal hostile_input>" --test-file <test path> --json
176
+ ```
177
+ Exit 1 = the test does not contain the attack it was written to close (`hostile_input_absent`), **or** it contains only a weak token match (`hostile_input_weak_match_only`). Either way that is not a closed finding; it is an untested guard with a green suite. `matched_via` names which tier matched — `literal`, `normalized`, or `distinctive_token` — and only the first two close a finding. `--accept-weak-match` exists as an explicit, off-by-default override; using it is a judgment you must state, not a default. The weak tier is gated because a path-segment match is how the original incident's own test would have scored as covered.
178
+
179
+ 2. **A mutant that disables the guard turns those tests red.**
180
+ ```bash
181
+ python3 "${CLAUDE_PLUGIN_ROOT:-.}/scripts/hostile_input_gate.py" mutate \
182
+ --guard-file <path> --guard-symbol <fn> --test-cmd "<test command>" --json
183
+ ```
184
+ Exit 1 = `mutant_survived`: the tests stay green with the guard disabled, so they never exercised it. The script always restores the original file.
185
+
186
+ Record both results in `closure_proof`. A `closure_proof` that names a test which passes the `check` but fails the `mutate` arm is false confidence — say so rather than marking the finding closed.
187
+
134
188
  ## Inline rubric (fallback when `security-methodology` skill is absent)
135
189
 
136
190
  If the methodology skill cannot be loaded, use this condensed rubric. It covers the same ground at lower fidelity.
@@ -18,7 +18,7 @@ model: sonnet
18
18
  tier: code
19
19
  segment: generative_reasoning
20
20
  color: cyan
21
- tools: ["Read", "Write", "Edit", "Glob", "Grep", "Skill"]
21
+ tools: ["Read", "Write", "Edit", "Glob", "Grep", "Skill", "Bash"]
22
22
  ---
23
23
 
24
24
  <!-- SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com> | SPDX-License-Identifier: Apache-2.0 -->
@@ -58,7 +58,8 @@ Plus the target artifact type (`skill` or `agent`) decided by the caller.
58
58
 
59
59
  3. **Draft the artifact**
60
60
  For a skill, the SKILL.md must have:
61
- - Frontmatter: `name` (kebab-case, scoped `build-loop:experimental-<name>`), `description` with specific triggers extracted from evidence, `experimental: true` flag, `created: <ISO date>`, `promoted: false`
61
+ - Frontmatter: `name` (kebab-case, scoped `build-loop:experimental-<name>`), `description` with specific triggers extracted from evidence, `user-invocable: false`, `experimental: true` flag, `created: <ISO date>`, `promoted: false`
62
+ - `user-invocable: false` is the DEFAULT for every skill you draft. The Claude Code harness computes `userInvocable ?? true`, so a SKILL.md with no field is PUBLIC — a machine-drafted, unreviewed skill would land in the user's slash menu. You never write `user-invocable: true`; if a pattern genuinely warrants a direct human entrypoint, say so in your synthesis output and let promotion decide.
62
63
  - Body: ONE short paragraph on when to use, ONE section with the concrete steps (copy-paste-able), ONE section with "how to know it worked" (measurable signal)
63
64
  - Length: 40-120 lines. No more. Experimental skills must be cheap to read.
64
65
 
@@ -69,7 +70,19 @@ Plus the target artifact type (`skill` or `agent`) decided by the caller.
69
70
  - Do NOT write to the plugin repo. Never modify `~/.claude/plugins/build-loop/`.
70
71
  - Create the directory if missing.
71
72
 
72
- 5. **Produce a concise user synthesis**
73
+ 5. **Stamp the surface default (deterministic — run it, do not eyeball the frontmatter)**
74
+
75
+ Immediately after the Write tool returns, on the path you just wrote:
76
+
77
+ ```bash
78
+ python3 "${CLAUDE_PLUGIN_ROOT:-.}/scripts/stamp_skill_frontmatter.py" --apply .build-loop/skills/experimental/<name>/SKILL.md
79
+ ```
80
+
81
+ Expected output: `compliant` (you wrote the field yourself) or `stamped` (the script inserted it). Exit 0 either way.
82
+
83
+ If the script prints `violation` or `malformed`, you emitted a bad frontmatter block — fix the file and re-run until it exits 0. Do not report the artifact as created while the stamper is non-zero; a red stamper means the skill you just drafted is publicly invocable or unparseable.
84
+
85
+ 6. **Produce a concise user synthesis**
73
86
  Output to stdout (not the file) a 3-4 line summary:
74
87
 
75
88
  ```
@@ -77,6 +90,7 @@ Plus the target artifact type (`skill` or `agent`) decided by the caller.
77
90
  Type: skill
78
91
  Name: build-loop:experimental-middleware-typegen
79
92
  Path: .build-loop/skills/experimental/middleware-typegen/SKILL.md
93
+ Surface: user-invocable: false (stamper: <compliant|stamped>)
80
94
  Triggers on: <extracted trigger>
81
95
  A/B baseline: <metric to compare, see §A/B Experiment>
82
96
  Remove with: rm -rf .build-loop/skills/experimental/<name>/
@@ -46,7 +46,7 @@ You are a deterministic pipeline that runs the local pattern-mining script, dedu
46
46
  ## Step 1 — Run the miner
47
47
 
48
48
  ```bash
49
- python3 ~/dev/git-folder/build-loop/scripts/transcript-pattern-miner.py --days <N>
49
+ python3 "${CLAUDE_PLUGIN_ROOT}/scripts/transcript-pattern-miner.py" --days <N>
50
50
  ```
51
51
 
52
52
  Default window: 7 days. Use `--days 30` for monthly review, `--all` for full history, `--force` to bypass the `.processed.json` cache. Stdout summarizes counts; non-zero exit only on a missing sessions directory.
@@ -54,7 +54,7 @@ Default window: 7 days. Use `--days 30` for monthly review, `--all` for full his
54
54
  ## Step 2 — Build the memory map
55
55
 
56
56
  ```bash
57
- ls ~/.claude/projects/-Users-tyroneross/memory/feedback_*.md
57
+ ls ~/.claude/projects/*/memory/feedback_*.md
58
58
  ```
59
59
 
60
60
  For each file, read ONLY lines 1–10 (frontmatter window). Extract `name:` and `description:` fields. If frontmatter is malformed (no `---` open/close, missing fields), record the filename with `name=<filename>` and `description=(unparseable)` and continue — never abort.
@@ -142,14 +142,14 @@ Output exactly this schema in markdown. Sections you don't have signal for: writ
142
142
  # Edge cases
143
143
 
144
144
  - **No clusters at all** → emit the schema with `(none in this window)` under each section. Don't fabricate.
145
- - **Memory dir missing or empty** → mark every cluster as `novel` and add a top-of-output note: `⚠️ no feedback memory found at ~/.claude/projects/-Users-tyroneross/memory/`.
145
+ - **Memory dir missing or empty** → mark every cluster as `novel` and add a top-of-output note: `⚠️ no feedback memory found at ~/.claude/projects/*/memory/`.
146
146
  - **Frontmatter malformed for some files** → still classify against the parseable ones. List unparseable files at the end of the summary under `Memory files skipped (malformed): <list>`.
147
147
  - **Miner script missing or errors** → report the error verbatim and stop. Do not run extraction yourself.
148
148
 
149
149
  # Data layout reference
150
150
 
151
- - Sessions: `~/.claude/projects/-Users-tyroneross/<session-uuid>.jsonl` (one file per Claude Code session, not in a `sessions/` subdir).
152
- - Memory: `~/.claude/projects/-Users-tyroneross/memory/feedback_*.md` (frontmatter only).
151
+ - Sessions: `~/.claude/projects/<home-slug>/<session-uuid>.jsonl`, where `<home-slug>` is `$HOME` with every `/` replaced by `-` (see `default_sessions_dir()` in `scripts/transcript_pattern_miner/__main__.py`). One file per Claude Code session, not in a `sessions/` subdir.
152
+ - Memory: `~/.claude/projects/<home-slug>/memory/feedback_*.md` (frontmatter only).
153
153
  - Miner output: `~/.build-loop/transcript-patterns/<YYYY-MM-DD>.md` + `.candidates.json`.
154
154
  - Idempotency cache: `~/.build-loop/transcript-patterns/.processed.json`.
155
155
 
@@ -169,7 +169,7 @@ One failing assertion per envelope. If multiple signals trip, pick the highest-s
169
169
  ## What you do NOT do
170
170
 
171
171
  - Open a viewer/dashboard or any GUI surface intended for human browsing. You are headless and silent.
172
- - Invoke IBR by default. IBR is explicit-only and outside the normal ui-validator path.
172
+ - Do not invoke IBR recursively from inside this agent. The orchestrator runs `build-loop:ibr-bridge` as the primary verifier under `references/ibr-ui-verification-policy.md` and passes the evidence into this validation path.
173
173
  - Propose code changes. Your envelope is signal-only.
174
174
  - Mark a finding `fail` if the visual SSIM is below threshold but no functional signal tripped — that's a warn, not a block.
175
175
  - Persist baselines without an explicit `priorBaselineDir` input. Baselines are caller-managed.
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env node
2
+ // SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com>
3
+ // SPDX-License-Identifier: Apache-2.0
4
+
5
+ "use strict";
6
+
7
+ const fs = require("node:fs");
8
+ const path = require("node:path");
9
+
10
+ const CORE_VERSION = "1.9.0";
11
+
12
+ function usage() {
13
+ return [
14
+ "Usage:",
15
+ " build-loop-debugger search <symptom> [--threshold 0.6] [--workdir PATH]",
16
+ " build-loop-debugger store --input FILE [--workdir PATH]",
17
+ " build-loop-debugger detail <INC_ID> [--workdir PATH]",
18
+ " build-loop-debugger status [--workdir PATH]",
19
+ ].join("\n");
20
+ }
21
+
22
+ function parseArgs(argv) {
23
+ const command = argv.shift();
24
+ const positional = [];
25
+ const options = { threshold: 0.5, workdir: process.cwd(), input: null };
26
+ while (argv.length) {
27
+ const arg = argv.shift();
28
+ if (arg === "--threshold") options.threshold = Number(argv.shift());
29
+ else if (arg === "--workdir") options.workdir = path.resolve(argv.shift());
30
+ else if (arg === "--input") options.input = argv.shift();
31
+ else if (arg.startsWith("--")) throw new Error(`unknown option: ${arg}`);
32
+ else positional.push(arg);
33
+ }
34
+ if (!command) throw new Error(usage());
35
+ if (!Number.isFinite(options.threshold) || options.threshold < 0 || options.threshold > 1) {
36
+ throw new Error("--threshold must be between 0 and 1");
37
+ }
38
+ return { command, positional, options };
39
+ }
40
+
41
+ function normalizeIncident(payload, api) {
42
+ if (!payload.symptom || !payload.root_cause || !payload.fix) {
43
+ throw new Error("store input requires symptom, root_cause, and fix");
44
+ }
45
+ const files = Array.isArray(payload.files_changed) ? payload.files_changed : [];
46
+ const rootCause = typeof payload.root_cause === "string"
47
+ ? { description: payload.root_cause, category: payload.category || "unknown", confidence: payload.confidence ?? 0.8 }
48
+ : {
49
+ ...payload.root_cause,
50
+ category: payload.root_cause.category || payload.category || "unknown",
51
+ confidence: payload.root_cause.confidence ?? payload.confidence ?? 0.8,
52
+ };
53
+ const fix = typeof payload.fix === "string"
54
+ ? {
55
+ approach: payload.fix,
56
+ changes: files.map((file) => ({ file, lines_changed: 0, change_type: "modify", summary: payload.fix })),
57
+ }
58
+ : payload.fix;
59
+ const verification = typeof payload.verification === "string"
60
+ ? {
61
+ status: payload.verification === "verified" ? "verified" : "unverified",
62
+ regression_tests_passed: payload.verification === "verified",
63
+ user_journey_tested: false,
64
+ success_criteria_met: payload.verification === "verified",
65
+ }
66
+ : (payload.verification || {
67
+ status: "unverified",
68
+ regression_tests_passed: false,
69
+ user_journey_tested: false,
70
+ success_criteria_met: false,
71
+ });
72
+
73
+ return {
74
+ incident_id: api.generateIncidentId(rootCause.category),
75
+ timestamp: Date.now(),
76
+ symptom: payload.symptom,
77
+ session_id: `BUILD_LOOP_${Date.now()}`,
78
+ root_cause: rootCause,
79
+ fix,
80
+ verification,
81
+ tags: Array.isArray(payload.tags) ? payload.tags : ["build-loop"],
82
+ files_changed: files,
83
+ agent_used: payload.agent_used || "build-loop",
84
+ quality_gates: payload.quality_gates || {
85
+ guardian_validated: false,
86
+ tested_e2e: false,
87
+ tested_from_ui: false,
88
+ security_reviewed: false,
89
+ architect_reviewed: false,
90
+ },
91
+ };
92
+ }
93
+
94
+ async function main() {
95
+ const { command, positional, options } = parseArgs(process.argv.slice(2));
96
+ process.chdir(options.workdir);
97
+ // Plugin caches do not ship node_modules. Load only dependency-free debugger
98
+ // modules instead of the package index, which also exports interactive
99
+ // helpers backed by the optional `prompts` package.
100
+ const retrieval = require(path.resolve(__dirname, "../dist/src/retrieval.js"));
101
+ const storage = require(path.resolve(__dirname, "../dist/src/storage.js"));
102
+ const config = require(path.resolve(__dirname, "../dist/src/config.js"));
103
+ const api = { ...retrieval, ...storage };
104
+ const memoryRoot = config.getMemoryPaths().root;
105
+ const originalLog = console.log;
106
+ console.log = (...items) => console.error(...items);
107
+ try {
108
+ if (command === "search") {
109
+ const symptom = positional.join(" ").trim();
110
+ if (!symptom) throw new Error("search requires a symptom");
111
+ const verdict = await api.checkMemoryWithVerdict(symptom, { similarity_threshold: options.threshold });
112
+ return { ok: true, command, debugger_core_version: CORE_VERSION, memory_root: memoryRoot, verdict };
113
+ }
114
+ if (command === "store") {
115
+ if (!options.input) throw new Error("store requires --input FILE");
116
+ const input = options.input === "-" ? fs.readFileSync(0, "utf8") : fs.readFileSync(path.resolve(options.input), "utf8");
117
+ const incident = normalizeIncident(JSON.parse(input), api);
118
+ const stored = await api.storeIncident(incident, { validate_schema: true });
119
+ return { ok: true, command, debugger_core_version: CORE_VERSION, memory_root: memoryRoot, incident_id: stored.incident_id, file_path: stored.file_path };
120
+ }
121
+ if (command === "detail") {
122
+ const id = positional[0];
123
+ if (!id) throw new Error("detail requires an incident ID");
124
+ const incident = await api.loadIncident(id);
125
+ if (!incident) throw new Error(`incident not found: ${id}`);
126
+ return { ok: true, command, debugger_core_version: CORE_VERSION, memory_root: memoryRoot, incident };
127
+ }
128
+ if (command === "status") {
129
+ const status = await api.getMemoryStats();
130
+ return { ok: true, command, debugger_core_version: CORE_VERSION, memory_root: memoryRoot, status };
131
+ }
132
+ throw new Error(`unknown command: ${command}\n${usage()}`);
133
+ } finally {
134
+ console.log = originalLog;
135
+ }
136
+ }
137
+
138
+ main()
139
+ .then((payload) => process.stdout.write(`${JSON.stringify(payload)}\n`))
140
+ .catch((error) => {
141
+ process.stdout.write(`${JSON.stringify({ ok: false, error: error.message })}\n`);
142
+ process.exitCode = 1;
143
+ });
@@ -5,7 +5,6 @@
5
5
  "use strict";
6
6
 
7
7
  const { spawnSync } = require("node:child_process");
8
- const fs = require("node:fs");
9
8
  const path = require("node:path");
10
9
 
11
10
  const root = path.resolve(__dirname, "..");
@@ -189,7 +188,6 @@ function main() {
189
188
 
190
189
  const python = findPython();
191
190
  const steps = [];
192
- const codexArtifact = path.join(root, "plugin-artifacts", "codex");
193
191
 
194
192
  if (process.platform !== "darwin" && !args.allowNonMac && !args.json) {
195
193
  process.stderr.write(
@@ -198,9 +196,8 @@ function main() {
198
196
  }
199
197
 
200
198
  for (const host of hostsFor(args.host)) {
201
- const source = host === "codex" && fs.existsSync(codexArtifact) ? codexArtifact : root;
202
199
  steps.push(
203
- runStep(`sync ${host} plugin cache`, python, syncArgs({ host, source, args }), args)
200
+ runStep(`sync ${host} plugin cache`, python, syncArgs({ host, source: root, args }), args)
204
201
  );
205
202
  }
206
203