@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.
- package/.agents/plugins/marketplace.json +2 -2
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor/rules/build-loop-surface.mdc +12 -11
- package/.cursor/rules/skill-index.mdc +33 -0
- package/AGENTS.md +213 -34
- package/README.md +99 -31
- package/agents/advisor.md +4 -4
- package/agents/alignment-checker.md +2 -2
- package/agents/architecture-scout.md +4 -4
- package/agents/build-orchestrator.md +38 -36
- package/agents/database-assessor.md +11 -5
- package/agents/design-contract-specialist.md +8 -8
- package/agents/fact-checker.md +13 -3
- package/agents/fix-critique.md +2 -2
- package/agents/independent-auditor.md +60 -7
- package/agents/leak-scanner.md +82 -0
- package/agents/overfitting-reviewer.md +2 -2
- package/agents/plan-critic.md +1 -1
- package/agents/promotion-reviewer.md +5 -5
- package/agents/retrospective-synthesizer.md +138 -35
- package/agents/scope-auditor.md +82 -11
- package/agents/security-reviewer.md +56 -2
- package/agents/self-improvement-architect.md +17 -3
- package/agents/transcript-pattern-miner.md +5 -5
- package/agents/ui-validator.md +1 -1
- package/bin/build-loop-debugger.js +143 -0
- package/bin/build-loop-install.js +1 -4
- package/bin/build-loop-load-probe.js +345 -0
- package/codex-skills/build-loop/SKILL.md +28 -6
- package/commands/feedback.md +37 -0
- package/dist/src/interactive-verifier.d.ts +1 -14
- package/dist/src/interactive-verifier.d.ts.map +1 -1
- package/dist/src/interactive-verifier.js +6 -113
- package/dist/src/interactive-verifier.js.map +1 -1
- package/dist/src/quality.d.ts +5 -0
- package/dist/src/quality.d.ts.map +1 -0
- package/dist/src/quality.js +81 -0
- package/dist/src/quality.js.map +1 -0
- package/dist/src/storage.d.ts.map +1 -1
- package/dist/src/storage.js +37 -3
- package/dist/src/storage.js.map +1 -1
- package/docs/agent-surface-policy.md +35 -31
- package/docs/memory-setup.md +19 -0
- package/hooks/git/pre-push +65 -4
- package/hooks/hooks.json +95 -38
- package/hooks/pre-commit +20 -1
- package/hooks/pre-edit-rally-point.sh +10 -3
- package/hooks/session-start-codex-hook-trust.sh +30 -0
- package/hooks/session-start-git-hooks.sh +3 -1
- package/hooks/session-start-rally-point.sh +52 -4
- package/hooks/session-start-worktree-gc.sh +47 -94
- package/hooks/stop-transcript-sweep.sh +173 -0
- package/hooks/test_closeout.sh +14 -2
- package/package.json +8 -7
- package/scripts/README.md +1 -1
- package/scripts/_paths.py +65 -0
- package/scripts/groundwork_exchange.py +1012 -0
- package/scripts/install_memory.py +33 -1
- package/scripts/lessons_index/ingest.py +13 -2
- package/scripts/lessons_index/query.py +36 -13
- package/scripts/memory_context/__init__.py +108 -14
- package/scripts/memory_graph/__init__.py +5 -1
- package/scripts/project_resolver.py +42 -36
- package/scripts/sync_plugin_cache.py +37 -2
- package/skills/agent-rally-point/SKILL.md +46 -0
- package/skills/api-registry-bridge/SKILL.md +1 -1
- package/skills/architecture/dead/SKILL.md +1 -1
- package/skills/architecture/impact/SKILL.md +1 -1
- package/skills/architecture/review/SKILL.md +1 -1
- package/skills/architecture/rules/SKILL.md +3 -3
- package/skills/architecture/scan/SKILL.md +1 -1
- package/skills/architecture/trace/SKILL.md +1 -1
- package/skills/attribution-standard/SKILL.md +6 -6
- package/skills/auto-decision-capture/SKILL.md +31 -2
- package/skills/auto-finding-capture/SKILL.md +28 -1
- package/skills/build-loop/SKILL.md +131 -23
- package/skills/build-loop/fallbacks.md +16 -21
- package/skills/build-loop/phases/ui-validation.md +2 -2
- package/skills/build-loop/references/advisor-dispatch-ladder.md +1 -1
- package/skills/build-loop/references/apple-native-planning.md +1 -1
- package/skills/build-loop/references/autonomous-and-per-commit-modes.md +11 -5
- package/skills/build-loop/references/autonomy-dashboard.md +115 -0
- package/skills/build-loop/references/capability-routing.md +24 -2
- package/skills/build-loop/references/coordination.md +24 -6
- package/skills/build-loop/references/experiment-results-template.md +15 -3
- package/skills/build-loop/references/leadership.md +1 -1
- package/skills/build-loop/references/memory.md +14 -3
- package/skills/build-loop/references/modular-systems-pack.md +8 -0
- package/skills/build-loop/references/output-style.md +86 -0
- package/skills/build-loop/references/phase-1-assess.md +102 -2
- package/skills/build-loop/references/phase-2-plan.md +9 -1
- package/skills/build-loop/references/phase-3-execute.md +5 -2
- package/skills/build-loop/references/phase-4-review.md +85 -8
- package/skills/build-loop/references/phase-5-iterate.md +76 -8
- package/skills/build-loop/references/phase-6-learn.md +10 -17
- package/skills/build-loop/references/privileged-request-broker.md +254 -0
- package/skills/build-loop/references/resource-aware-execution.md +183 -0
- package/skills/build-loop/references/self-recursive-dev.md +2 -2
- package/skills/build-loop/references/status-output-format.md +207 -0
- package/skills/build-loop/references/verify-dispatch.md +56 -2
- package/skills/building-with-deepagents/SKILL.md +1 -1
- package/skills/claim-scope/SKILL.md +185 -0
- package/skills/color-engine/SKILL.md +103 -0
- package/skills/color-engine/_core.py +464 -0
- package/skills/color-engine/color_engine.py +175 -0
- package/skills/cost-rca/SKILL.md +61 -0
- package/skills/data-plane-worktrees/SKILL.md +139 -0
- package/skills/data-plane-worktrees/agents/openai.yaml +4 -0
- package/skills/database-practice/SKILL.md +200 -0
- package/skills/database-practice/references/diagnostic-queries.sql +126 -0
- package/skills/database-practice/references/vector-and-graph-tuning.md +208 -0
- package/skills/database-practice/scripts/db_table_map.py +1244 -0
- package/skills/database-practice/scripts/test_db_table_map.py +514 -0
- package/skills/debug-loop/SKILL.md +36 -6
- package/skills/debugging-memory/SKILL.md +32 -430
- package/skills/debugging-memory/references/pattern-extraction.md +4 -4
- package/skills/debugging-memory/references/search.md +32 -120
- package/skills/debugging-memory/references/store.md +32 -126
- package/skills/debugging-memory/references/subagent-integration.md +1 -1
- package/skills/decision-queue/SKILL.md +251 -0
- package/skills/decision-queue/assets/template.html +1242 -0
- package/skills/decision-queue/references/example-large-queue-batching.md +164 -0
- package/skills/decision-queue/scripts/regen_template_constants.py +160 -0
- package/skills/defenseclaw-bridge/SKILL.md +2 -2
- package/skills/defenseclaw-bridge/references/dc-config-mapping.md +2 -9
- package/skills/drain-proposals/SKILL.md +53 -0
- package/skills/focused-loop-builder/SKILL.md +31 -0
- package/skills/focused-loop-builder/references/spec-format.md +27 -0
- package/skills/handoff/SKILL.md +169 -8
- package/skills/ibr-bridge/SKILL.md +4 -1
- package/skills/knowledge/SKILL.md +26 -14
- package/skills/knowledge/references/review-mode.md +2 -3
- package/skills/knowledge/templates/madr-minimal.md +1 -1
- package/skills/mcp-builder/SKILL.md +1 -1
- package/skills/model-bakeoff/SKILL.md +48 -10
- package/skills/model-tiering/SKILL.md +92 -31
- package/skills/native-ax-driver/SKILL.md +38 -5
- package/skills/native-ax-driver/scripts/native_driver.py +278 -22
- package/skills/native-ax-driver/scripts/test_native_driver.py +227 -0
- package/skills/optimize/SKILL.md +1 -1
- package/skills/plugin-builder/SKILL.md +48 -1
- package/skills/plugin-builder/references/build-loop-phase-guidance.md +3 -4
- package/skills/plugin-builder/references/distribution.md +13 -2
- package/skills/plugin-builder/references/plugin-hygiene-lessons.md +2 -2
- package/skills/plugin-tests/SKILL.md +2 -2
- package/skills/recursive-retrospective/SKILL.md +1 -1
- package/skills/repo-closeout/SKILL.md +17 -0
- package/skills/repo-closeout/agents/openai.yaml +4 -0
- package/skills/repo-maintenance/SKILL.md +179 -0
- package/skills/repo-maintenance/agents/openai.yaml +4 -0
- package/skills/repo-maintenance/references/pre-public-hygiene.md +134 -0
- package/skills/repo-maintenance/references/repository-taxonomy.md +161 -0
- package/skills/repo-maintenance/references/safety-protocol.md +106 -0
- package/skills/repo-maintenance/references/stack-profiles.md +138 -0
- package/skills/repo-maintenance/scripts/audit_repo_maintenance.py +1198 -0
- package/skills/repo-maintenance/scripts/test_audit_repo_maintenance.py +506 -0
- package/skills/repository-intelligence/SKILL.md +189 -0
- package/skills/repository-intelligence/agents/openai.yaml +4 -0
- package/skills/repository-intelligence/references/assessment-rubric.md +88 -0
- package/skills/repository-intelligence/scripts/repository_inventory.py +347 -0
- package/skills/research/SKILL.md +12 -2
- package/skills/root-cause-analysis/SKILL.md +1 -1
- package/skills/runtime-parity-verification/SKILL.md +36 -1
- package/skills/security-methodology/SKILL.md +23 -10
- package/skills/security-methodology/references/agentic-handoff-templates.md +220 -0
- package/skills/security-methodology/references/cross-source-matrix.md +1 -1
- package/skills/security-methodology/references/owasp-agentic-top-10.md +1 -1
- package/skills/security-scan/SKILL.md +55 -15
- package/skills/self-improve/SKILL.md +70 -50
- package/skills/silent-assumptions/SKILL.md +341 -0
- package/skills/silent-assumptions/references/elicitation-detectors.md +342 -0
- package/skills/spec-writing/SKILL.md +128 -24
- package/skills/spec-writing/scripts/check_checklist.py +114 -15
- package/skills/ui-design/SKILL.md +6 -4
- package/skills/ui-design/references/color-engine.md +132 -0
- package/skills/ui-design/references/design-preferences-from-owned-apps.md +8 -8
- package/skills/ui-design/references/ui-guidance-sources.md +1 -1
- package/skills/ui-design/references/universal-design-principles.alt.md +2 -2
- package/plugin-artifacts/codex/.codex-plugin/plugin.json +0 -41
- package/plugin-artifacts/codex/AGENTS.md +0 -560
- package/plugin-artifacts/codex/BUILD-ARTIFACT.md +0 -5
- package/plugin-artifacts/codex/LICENSE +0 -202
- package/plugin-artifacts/codex/README.md +0 -313
- package/plugin-artifacts/codex/assets/build-loop-plugin-icon.png +0 -0
- package/plugin-artifacts/codex/docs/agent-surface-policy.md +0 -63
- package/plugin-artifacts/codex/references/advisor-dispatch-ladder.md +0 -62
- package/plugin-artifacts/codex/references/agent-role-taxonomy.md +0 -135
- package/plugin-artifacts/codex/references/autonomous-and-per-commit-modes.md +0 -161
- package/plugin-artifacts/codex/references/autonomy-config.md +0 -231
- package/plugin-artifacts/codex/references/backlog-system.md +0 -285
- package/plugin-artifacts/codex/references/capability-routing.md +0 -231
- package/plugin-artifacts/codex/references/codex-subagents.md +0 -106
- package/plugin-artifacts/codex/references/coordination-file-template.md +0 -181
- package/plugin-artifacts/codex/references/coordination-rules.md +0 -552
- package/plugin-artifacts/codex/references/dogfood-reload-checkpoint.md +0 -112
- package/plugin-artifacts/codex/references/halt-and-ask-protocol.md +0 -102
- package/plugin-artifacts/codex/references/implementer-envelope-schema.md +0 -302
- package/plugin-artifacts/codex/references/intent-capability-pack.md +0 -257
- package/plugin-artifacts/codex/references/intent-exploration-prompts.md +0 -96
- package/plugin-artifacts/codex/references/leadership.md +0 -72
- package/plugin-artifacts/codex/references/memory-systems.md +0 -261
- package/plugin-artifacts/codex/references/memory.md +0 -313
- package/plugin-artifacts/codex/references/model-tier-mapping.md +0 -296
- package/plugin-artifacts/codex/references/modular-systems-pack.md +0 -96
- package/plugin-artifacts/codex/references/phase-1-assess.md +0 -249
- package/plugin-artifacts/codex/references/phase-2-plan.md +0 -86
- package/plugin-artifacts/codex/references/phase-3-execute.md +0 -49
- package/plugin-artifacts/codex/references/phase-4-review.md +0 -341
- package/plugin-artifacts/codex/references/phase-5-iterate.md +0 -72
- package/plugin-artifacts/codex/references/phase-6-learn.md +0 -58
- package/plugin-artifacts/codex/references/recent-design-structures.md +0 -274
- package/plugin-artifacts/codex/references/research-trigger-policy.md +0 -140
- package/plugin-artifacts/codex/references/runtime-smoke-triggers.md +0 -42
- package/plugin-artifacts/codex/references/self-review.md +0 -234
- package/plugin-artifacts/codex/references/single-writer-commit-protocol.md +0 -90
- package/plugin-artifacts/codex/references/task-capture-policy.md +0 -68
- package/plugin-artifacts/codex/references/ui-io-contract.md +0 -116
- package/plugin-artifacts/codex/references/ui-spotcheck-protocol.md +0 -65
- package/plugin-artifacts/codex/references/verify-dispatch.md +0 -85
- package/plugin-artifacts/codex/skills/build-loop/SKILL.md +0 -381
- package/plugin-artifacts/codex/skills/build-loop/detect-plugins.mjs +0 -82
- package/plugin-artifacts/codex/skills/build-loop/eval-guide.md +0 -65
- package/plugin-artifacts/codex/skills/build-loop/fallbacks.md +0 -549
- package/plugin-artifacts/codex/skills/build-loop/phases/fact-check.md +0 -42
- package/plugin-artifacts/codex/skills/build-loop/phases/ui-validation.md +0 -267
- package/plugin-artifacts/codex/skills/build-loop/references/advisor-dispatch-ladder.md +0 -62
- package/plugin-artifacts/codex/skills/build-loop/references/apple-native-planning.md +0 -439
- package/plugin-artifacts/codex/skills/build-loop/references/autonomous-and-per-commit-modes.md +0 -161
- package/plugin-artifacts/codex/skills/build-loop/references/capability-routing.md +0 -231
- package/plugin-artifacts/codex/skills/build-loop/references/codex-subagents.md +0 -106
- package/plugin-artifacts/codex/skills/build-loop/references/coordination.md +0 -161
- package/plugin-artifacts/codex/skills/build-loop/references/correction-aware-capture.md +0 -177
- package/plugin-artifacts/codex/skills/build-loop/references/experiment-results-template.md +0 -101
- package/plugin-artifacts/codex/skills/build-loop/references/independent-auditor.md +0 -72
- package/plugin-artifacts/codex/skills/build-loop/references/intent-capability-pack.md +0 -257
- package/plugin-artifacts/codex/skills/build-loop/references/intent-exploration-prompts.md +0 -96
- package/plugin-artifacts/codex/skills/build-loop/references/leadership.md +0 -72
- package/plugin-artifacts/codex/skills/build-loop/references/memory.md +0 -313
- package/plugin-artifacts/codex/skills/build-loop/references/modular-systems-pack.md +0 -96
- package/plugin-artifacts/codex/skills/build-loop/references/output-style.md +0 -222
- package/plugin-artifacts/codex/skills/build-loop/references/pay-it-forward-arch.md +0 -98
- package/plugin-artifacts/codex/skills/build-loop/references/phase-1-assess.md +0 -249
- package/plugin-artifacts/codex/skills/build-loop/references/phase-2-plan.md +0 -86
- package/plugin-artifacts/codex/skills/build-loop/references/phase-3-execute.md +0 -49
- package/plugin-artifacts/codex/skills/build-loop/references/phase-4-review.md +0 -341
- package/plugin-artifacts/codex/skills/build-loop/references/phase-5-iterate.md +0 -72
- package/plugin-artifacts/codex/skills/build-loop/references/phase-6-learn.md +0 -58
- package/plugin-artifacts/codex/skills/build-loop/references/recent-design-structures.md +0 -274
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/ASSESSMENT.md +0 -85
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/STANDALONE_TEST_RUN.md +0 -149
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/01-simple-bugfix.md +0 -32
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/02-ui-build-with-iteration.md +0 -48
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/03-multi-failure-escalation.md +0 -60
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/04-ui-build-ibr-absent.md +0 -51
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/05-refactor-navgator-absent.md +0 -71
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/06-recurring-bug-debugger-absent.md +0 -52
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/trace-comparison.md +0 -202
- package/plugin-artifacts/codex/skills/build-loop/references/self-recursive-dev.md +0 -77
- package/plugin-artifacts/codex/skills/build-loop/references/self-review.md +0 -234
- package/plugin-artifacts/codex/skills/build-loop/references/ui-io-contract.md +0 -116
- package/plugin-artifacts/codex/skills/build-loop/references/verify-dispatch.md +0 -85
- package/plugin-artifacts/codex/skills/build-loop/scanners/audit-design-rules.mjs +0 -476
- package/plugin-artifacts/codex/skills/build-loop/scanners/require-visual-evidence.mjs +0 -239
- package/plugin-artifacts/codex/skills/build-loop/templates/backlog-item.md +0 -35
- package/plugin-artifacts/codex/skills/build-loop/templates/codex-worker-prompt.md +0 -100
- package/plugin-artifacts/codex/skills/build-loop/templates/ui-subagent-prompt.md +0 -179
- package/plugin-artifacts/codex/skills/build-loop/templates/ux-fix-plan.md +0 -40
- package/scripts/build_codex_plugin_artifact.py +0 -321
package/agents/scope-auditor.md
CHANGED
|
@@ -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:
|
|
5
|
-
tier:
|
|
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
|
|
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`**,
|
|
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
|
-
|
|
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
|
-
- **
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
- **
|
|
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
|
|
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:
|
|
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 (
|
|
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. **
|
|
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
|
|
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
|
|
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
|
|
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
|
|
152
|
-
- Memory: `~/.claude/projects
|
|
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
|
|
package/agents/ui-validator.md
CHANGED
|
@@ -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
|
-
-
|
|
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
|
|