@izkac/forgekit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/forge.mjs +100 -0
- package/bin/forgekit.mjs +84 -0
- package/bin/review.mjs +82 -0
- package/package.json +46 -0
- package/scripts/prepack.mjs +78 -0
- package/scripts/run-tests.mjs +43 -0
- package/src/adr.mjs +236 -0
- package/src/adr.test.mjs +170 -0
- package/src/change.mjs +234 -0
- package/src/change.test.mjs +83 -0
- package/src/cleanup-sessions.mjs +70 -0
- package/src/config.mjs +103 -0
- package/src/defer.mjs +75 -0
- package/src/doctor.mjs +341 -0
- package/src/doctor.test.mjs +114 -0
- package/src/init.mjs +575 -0
- package/src/install.mjs +777 -0
- package/src/install.test.mjs +104 -0
- package/src/integrity-check.mjs +58 -0
- package/src/integrity.mjs +317 -0
- package/src/integrity.test.mjs +296 -0
- package/src/lib/workspaces.mjs +55 -0
- package/src/lib.mjs +138 -0
- package/src/models.defaults.json +41 -0
- package/src/new-session.mjs +82 -0
- package/src/openspec-overlays/README.md +19 -0
- package/src/openspec-overlays/openspec-apply-change-footer.md +14 -0
- package/src/openspec-overlays/opsx-apply-completion-step.md +1 -0
- package/src/openspec-overlays/opsx-apply-implement-step.md +11 -0
- package/src/paths.mjs +92 -0
- package/src/plan-engine.mjs +260 -0
- package/src/plan-engine.test.mjs +245 -0
- package/src/preferences.defaults.json +78 -0
- package/src/preferences.mjs +438 -0
- package/src/preferences.test.mjs +174 -0
- package/src/record-evidence.mjs +204 -0
- package/src/record-evidence.test.mjs +260 -0
- package/src/resolve-model.mjs +312 -0
- package/src/resolve-model.test.mjs +194 -0
- package/src/review/carryforward.mjs +413 -0
- package/src/review/carryforward.test.mjs +587 -0
- package/src/review/cli.test.mjs +117 -0
- package/src/review/export.mjs +172 -0
- package/src/review/export.test.mjs +197 -0
- package/src/review/fixtures/valid-review.json +42 -0
- package/src/review/lib.mjs +894 -0
- package/src/review/lib.test.mjs +266 -0
- package/src/review/merge-tentative.mjs +292 -0
- package/src/review/merge-tentative.test.mjs +363 -0
- package/src/review/new-review.mjs +200 -0
- package/src/review/render.mjs +108 -0
- package/src/review/schema-consistency.test.mjs +83 -0
- package/src/review/schema.json +196 -0
- package/src/review/signals.mjs +144 -0
- package/src/review/signals.test.mjs +62 -0
- package/src/score-cli.mjs +68 -0
- package/src/score.mjs +489 -0
- package/src/score.test.mjs +253 -0
- package/src/session-reminder.mjs +168 -0
- package/src/session-status.mjs +70 -0
- package/src/set-models.mjs +186 -0
- package/src/set-phase.mjs +177 -0
- package/src/set-phase.test.mjs +317 -0
- package/src/set-prefs.mjs +294 -0
- package/src/spine.mjs +91 -0
- package/src/triage-prompt.mjs +175 -0
- package/src/triage-prompt.test.mjs +50 -0
- package/src/vendor-openspec-overlays.mjs +176 -0
- package/src/vendor-openspec-overlays.test.mjs +62 -0
- package/vendor/skills/archive-to-adr/SKILL.md +149 -0
- package/vendor/skills/forge/SKILL.md +136 -0
- package/vendor/skills/forge/phases/brainstorm.md +23 -0
- package/vendor/skills/forge/phases/finish.md +87 -0
- package/vendor/skills/forge/phases/implement.md +76 -0
- package/vendor/skills/forge/phases/plan-openspec.md +40 -0
- package/vendor/skills/forge/phases/plan-specs.md +97 -0
- package/vendor/skills/forge/phases/review.md +25 -0
- package/vendor/skills/forge/phases/verify.md +120 -0
- package/vendor/skills/forge/references/forge-layout.md +85 -0
- package/vendor/skills/forge/references/pace.md +115 -0
- package/vendor/skills/forge/references/plan-routing.md +51 -0
- package/vendor/skills/forge/references/runtime-integrity.md +157 -0
- package/vendor/skills/forge/references/substantial-work.md +37 -0
- package/vendor/skills/forge/references/tdd-core.md +29 -0
- package/vendor/skills/forge/references/test-evidence.md +30 -0
- package/vendor/skills/forge/references/test-strategy.md +68 -0
- package/vendor/skills/forge/skills/NOTICE.md +17 -0
- package/vendor/skills/forge/skills/brainstorming/SKILL.md +120 -0
- package/vendor/skills/forge/skills/requesting-code-review/SKILL.md +67 -0
- package/vendor/skills/forge/skills/requesting-code-review/code-reviewer.md +146 -0
- package/vendor/skills/forge/skills/subagent-driven-development/SKILL.md +87 -0
- package/vendor/skills/forge/skills/systematic-debugging/SKILL.md +234 -0
- package/vendor/skills/forge/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/vendor/skills/forge/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/vendor/skills/forge/skills/systematic-debugging/find-polluter.sh +63 -0
- package/vendor/skills/forge/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/vendor/skills/forge/skills/test-driven-development/SKILL.md +290 -0
- package/vendor/skills/forge/skills/test-driven-development/testing-anti-patterns.md +299 -0
- package/vendor/skills/forge/skills/verification-before-completion/SKILL.md +59 -0
- package/vendor/skills/forge/subagents/final-reviewer-prompt.md +53 -0
- package/vendor/skills/forge/subagents/implementer-prompt.md +38 -0
- package/vendor/skills/forge/subagents/task-reviewer-prompt.md +61 -0
- package/vendor/skills/git-resolve-adr-conflict/SKILL.md +132 -0
- package/vendor/skills/thorough-code-review/SKILL.md +290 -0
- package/vendor/skills/thorough-code-review/examples/accepted-risks-janus.md +32 -0
- package/vendor/skills/thorough-code-review/examples.md +133 -0
- package/vendor/skills/thorough-code-review/reference/accepted-risks.md +26 -0
- package/vendor/skills/thorough-code-review/reference/lenses.md +96 -0
- package/vendor/skills/thorough-code-review/reference/phase1-scout.md +62 -0
- package/vendor/skills/thorough-code-review/reference/phase1c-coverage.md +44 -0
- package/vendor/skills/thorough-code-review/reference/phase2-skeptic.md +105 -0
- package/vendor/skills/thorough-code-review/reference/report-schema.json +222 -0
- package/vendor/skills/thorough-code-review/reference/report-template.md +115 -0
- package/vendor/skills/thorough-code-review/reference/severity-rubric.md +49 -0
- package/vendor/skills/thorough-code-review/reference/signals-preflight.md +55 -0
- package/vendor/templates/adr/README.md +7 -0
- package/vendor/templates/adr/decisions.md +141 -0
- package/vendor/templates/adr/hooks/check-pending-adrs.mjs +74 -0
- package/vendor/templates/adr/hooks/check-pending-adrs.sh +3 -0
- package/vendor/templates/adr/hooks/openspec-archive-agent-message.mjs +52 -0
- package/vendor/templates/adr/hooks/openspec-archive-agent-message.sh +3 -0
- package/vendor/templates/project/claude/commands/forge-apply.md +75 -0
- package/vendor/templates/project/claude/commands/forge-brainstorm.md +7 -0
- package/vendor/templates/project/claude/commands/forge-build.md +17 -0
- package/vendor/templates/project/claude/commands/forge-plan.md +12 -0
- package/vendor/templates/project/claude/commands/forge-skip.md +14 -0
- package/vendor/templates/project/claude/commands/forge-status.md +16 -0
- package/vendor/templates/project/claude/commands/forge.md +16 -0
- package/vendor/templates/project/claude/hooks/forge-prompt-hook.mjs +73 -0
- package/vendor/templates/project/claude/hooks/forge-session-start.mjs +19 -0
- package/vendor/templates/project/claude/hooks/forge-triage-hook.mjs +77 -0
- package/vendor/templates/project/claude/rules/forge.md +16 -0
- package/vendor/templates/project/codex/rules/forge.md +10 -0
- package/vendor/templates/project/cursor/commands/forge-apply.md +75 -0
- package/vendor/templates/project/cursor/commands/forge-brainstorm.md +10 -0
- package/vendor/templates/project/cursor/commands/forge-build.md +17 -0
- package/vendor/templates/project/cursor/commands/forge-plan.md +15 -0
- package/vendor/templates/project/cursor/commands/forge-skip.md +14 -0
- package/vendor/templates/project/cursor/commands/forge-status.md +16 -0
- package/vendor/templates/project/cursor/commands/forge.md +16 -0
- package/vendor/templates/project/cursor/hooks/forge-session-start.mjs +30 -0
- package/vendor/templates/project/cursor/hooks/forge-session-start.sh +3 -0
- package/vendor/templates/project/cursor/rules/forge.mdc +21 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Phase 1.5 — Coverage pass (recall)
|
|
2
|
+
|
|
3
|
+
You are the **coverage critic**. The scout and skeptic together make confirmed findings trustworthy (precision); they do nothing about what the scout *missed* (recall). Your job is to close that gap.
|
|
4
|
+
|
|
5
|
+
**This pass normally runs orchestrator-inline** — the orchestrator already holds the scope and the merged tentative list. Dispatch it as a subagent only when the scope was partitioned and the file list is too large to re-check in context.
|
|
6
|
+
|
|
7
|
+
**You receive the scope, the active lenses, and the merged tentative-finding list.**
|
|
8
|
+
|
|
9
|
+
## Inputs
|
|
10
|
+
|
|
11
|
+
- **Scope:** {SCOPE_TYPE} — {SCOPE_DETAIL}
|
|
12
|
+
- **Lenses:** {LENS_LIST}
|
|
13
|
+
- **Tentative findings:** {FINDING_SUMMARY} (ids + locations + lenses)
|
|
14
|
+
- **Signals:** {SIGNALS_SUMMARY} (which grounding tools ran and their status)
|
|
15
|
+
|
|
16
|
+
## Checks
|
|
17
|
+
|
|
18
|
+
1. **File coverage.** List every file in scope. For each that received **zero** tentative findings, decide: genuinely clean (state why — trivial, well-tested, unchanged logic) or **not actually reviewed**. Re-read the latter.
|
|
19
|
+
2. **Lens coverage.** For each active lens that produced **zero** findings, decide: the code truly has no such issue, or the lens was not exercised on this scope. Re-inspect the latter against [lenses.md](lenses.md).
|
|
20
|
+
3. **Blind spots.** Check the kinds of issue a single forward pass tends to miss:
|
|
21
|
+
- error/edge paths and early returns not on the happy path
|
|
22
|
+
- cross-file and cross-service interactions (callers of changed exports)
|
|
23
|
+
- what a change *removed* (deleted guard, dropped test, narrowed type)
|
|
24
|
+
- config, migrations, and generated artifacts in scope but easy to skim past
|
|
25
|
+
4. **Signal gaps.** Any grounding tool `skipped` that should have run for this scope? Flag it.
|
|
26
|
+
|
|
27
|
+
## Output
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
coverage:
|
|
31
|
+
files_reviewed: [list]
|
|
32
|
+
files_skipped: [list] # in scope but deliberately not deep-read (say why in notes)
|
|
33
|
+
lenses_without_findings:
|
|
34
|
+
- lens: performance
|
|
35
|
+
reason: no loops, queries, or allocations introduced
|
|
36
|
+
new_findings: [] # follow-up tentative findings (F-### / dup-###),
|
|
37
|
+
# full scout format; they go through Phase 2 like the rest
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Rules
|
|
41
|
+
|
|
42
|
+
- A zero-finding lens or file is a claim that needs a one-line justification — not a silent gap.
|
|
43
|
+
- New findings you raise are **tentative**; the skeptic still verifies them. Do not confirm anything here.
|
|
44
|
+
- **Hard cap: 10 follow-up findings**, prioritized by severity. If you found more, keep the top 10 and note the overflow count in the coverage ledger notes.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Phase 2 — Skeptic pass
|
|
2
|
+
|
|
3
|
+
You are an **adversarial skeptic**. Your job is to **disprove** the scout's claim unless evidence confirms it.
|
|
4
|
+
|
|
5
|
+
**You receive only this packet — no chat history.** It may contain **one finding** (critical, or an important finding alone in its file) or a **batch of findings sharing a file or module** (important: ≤4, minor: ≤6) — steelman and verdict each finding independently; never let one verdict color another.
|
|
6
|
+
|
|
7
|
+
## Finding(s) under review
|
|
8
|
+
|
|
9
|
+
One block per finding:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
id: {FINDING_ID}
|
|
13
|
+
lens: {LENS}
|
|
14
|
+
location: {LOCATION}
|
|
15
|
+
claim: {CLAIM}
|
|
16
|
+
evidence: {EVIDENCE}
|
|
17
|
+
context: {CONTEXT_EXCERPT} # ±30 lines around the cited location, from the scout
|
|
18
|
+
related: {RELATED} # callers, test files, ADR paths
|
|
19
|
+
tentative_severity: {SEVERITY}
|
|
20
|
+
confidence: {CONFIDENCE}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Start from `context` and `related` — most verdicts need only 1–2 additional reads. Read more files only when the disproof checklist genuinely requires it.
|
|
24
|
+
|
|
25
|
+
## Scope context
|
|
26
|
+
|
|
27
|
+
- **Scope:** {SCOPE_DESCRIPTION}
|
|
28
|
+
- **Mode:** {MODE} <!-- `initial` or `reverify` -->
|
|
29
|
+
- **Accepted risks:** {ACCEPTED_RISKS_DIGEST} <!-- contents of reference/accepted-risks.md -->
|
|
30
|
+
|
|
31
|
+
Check the digest **before** reading `docs/adr/` — if it covers the claim and no re-open trigger fired, the verdict is `false_positive` (cite the ADR id). Read full ADRs only when the digest is silent.
|
|
32
|
+
|
|
33
|
+
## Steelman rule
|
|
34
|
+
|
|
35
|
+
First, restate the **strongest** version of the claim — the worst reasonable interpretation an attacker or failure mode could exploit.
|
|
36
|
+
|
|
37
|
+
## Disproof checklist
|
|
38
|
+
|
|
39
|
+
Attempt each before concluding:
|
|
40
|
+
|
|
41
|
+
1. **Call chain** — trace callers and callees; does the dangerous path actually execute?
|
|
42
|
+
2. **Data flow** — is input attacker-controlled at the sink?
|
|
43
|
+
3. **Tests** — read (or run if feasible) tests covering this path
|
|
44
|
+
4. **Framework mitigations** — middleware, ORM parameterization, framework defaults
|
|
45
|
+
5. **Deployment boundary** — internal-only API, LAN trust model, ADR-accepted risk
|
|
46
|
+
6. **Project docs** — `docs/adr/`, `AGENTS.md`, prior security reviews
|
|
47
|
+
7. **Intent** — comment, type guard, or early return that negates the claim
|
|
48
|
+
|
|
49
|
+
## Verdict (initial review)
|
|
50
|
+
|
|
51
|
+
| Verdict | When |
|
|
52
|
+
| ------- | ---- |
|
|
53
|
+
| `confirmed` | Issue is real at stated or higher severity |
|
|
54
|
+
| `false_positive` | Claim does not hold after investigation |
|
|
55
|
+
| `downgraded` | Real issue but lower severity — set `severity` and `original_severity` |
|
|
56
|
+
| `needs_decision` | Architectural/policy choice; not a clear defect |
|
|
57
|
+
|
|
58
|
+
**Requirements:**
|
|
59
|
+
|
|
60
|
+
- `verdict_reason` must cite specific evidence (file:line, test name, ADR id).
|
|
61
|
+
- "Looks fine" without evidence is invalid.
|
|
62
|
+
- Upgrade severity only with **new** evidence not in the scout packet.
|
|
63
|
+
|
|
64
|
+
## Risk-weighted second opinion
|
|
65
|
+
|
|
66
|
+
A single skeptic returning `false_positive` is itself a single point of failure — it can quietly bury a real bug. The orchestrator dispatches a **second independent skeptic** (no history, blind to the first verdict) when the finding is in the **dangerous quadrant**:
|
|
67
|
+
|
|
68
|
+
- `severity` is `critical`/`important` **and** the first verdict is `false_positive`, or
|
|
69
|
+
- `phase1_confidence: high` **and** the first verdict is `false_positive` (scout/skeptic disagreement), or
|
|
70
|
+
- `phase1_confidence: low` **and** `severity: critical` (high-stakes, low-certainty).
|
|
71
|
+
|
|
72
|
+
If you are the second skeptic, verify independently and return your verdict in the `second_opinion` block. When the two skeptics disagree, the orchestrator keeps the higher-severity outcome or routes to `needs_decision` — a disagreement is never silently resolved in favour of dismissal.
|
|
73
|
+
|
|
74
|
+
## Verdict (reverify mode)
|
|
75
|
+
|
|
76
|
+
When `MODE` is `reverify`, the finding was previously `confirmed` or `downgraded`. Read **current** code at `location`.
|
|
77
|
+
|
|
78
|
+
| Verdict | When |
|
|
79
|
+
| ------- | ---- |
|
|
80
|
+
| `resolved` | Fix fully addresses the issue |
|
|
81
|
+
| `still_open` | Issue persists unchanged |
|
|
82
|
+
| `partially_fixed` | Improved but incomplete |
|
|
83
|
+
| `regressed` | Fix introduced new problem or made it worse |
|
|
84
|
+
|
|
85
|
+
Include `verdict_reason` with before/after comparison.
|
|
86
|
+
|
|
87
|
+
## Output
|
|
88
|
+
|
|
89
|
+
Return one structured block **per finding** for synthesis:
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
id: F-001
|
|
93
|
+
lens: security
|
|
94
|
+
location: path:line
|
|
95
|
+
claim: ...
|
|
96
|
+
severity: critical | important | minor
|
|
97
|
+
original_severity: ... # required if downgraded
|
|
98
|
+
verdict: confirmed | false_positive | downgraded | needs_decision | resolved | still_open | partially_fixed | regressed
|
|
99
|
+
verdict_reason: ...
|
|
100
|
+
evidence: ...
|
|
101
|
+
second_opinion: # only for dangerous-quadrant findings
|
|
102
|
+
verdict: ...
|
|
103
|
+
verdict_reason: ...
|
|
104
|
+
agrees: true | false
|
|
105
|
+
```
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://forgekit.local/schemas/code-review-report.json",
|
|
4
|
+
"title": "ThoroughCodeReviewReport",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["review_id", "kind", "created_at", "scope", "lenses", "summary", "findings"],
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"review_id": { "type": "string", "minLength": 1 },
|
|
10
|
+
"kind": { "type": "string", "enum": ["review", "reverify"] },
|
|
11
|
+
"created_at": { "type": "string", "format": "date-time" },
|
|
12
|
+
"scope": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"required": ["type", "description"],
|
|
15
|
+
"additionalProperties": false,
|
|
16
|
+
"properties": {
|
|
17
|
+
"type": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"enum": ["uncommitted", "branch", "paths", "commit_range", "file"]
|
|
20
|
+
},
|
|
21
|
+
"description": { "type": "string", "minLength": 1 },
|
|
22
|
+
"base_sha": { "type": "string" },
|
|
23
|
+
"head_sha": { "type": "string" },
|
|
24
|
+
"paths": { "type": "array", "items": { "type": "string" } }
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"lenses": {
|
|
28
|
+
"type": "array",
|
|
29
|
+
"minItems": 1,
|
|
30
|
+
"items": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"enum": [
|
|
33
|
+
"security",
|
|
34
|
+
"correctness",
|
|
35
|
+
"smells",
|
|
36
|
+
"architecture",
|
|
37
|
+
"performance",
|
|
38
|
+
"tests",
|
|
39
|
+
"contracts",
|
|
40
|
+
"errors",
|
|
41
|
+
"maintainability"
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"parent_report": { "type": "string" },
|
|
46
|
+
"summary": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"required": ["tentative_count"],
|
|
49
|
+
"additionalProperties": true,
|
|
50
|
+
"properties": {
|
|
51
|
+
"tentative_count": { "type": "integer", "minimum": 0 },
|
|
52
|
+
"headline": { "type": "string" },
|
|
53
|
+
"top_actions": { "type": "array", "items": { "type": "string" } },
|
|
54
|
+
"confirmed": { "type": "integer", "minimum": 0 },
|
|
55
|
+
"downgraded": { "type": "integer", "minimum": 0 },
|
|
56
|
+
"false_positive": { "type": "integer", "minimum": 0 },
|
|
57
|
+
"needs_decision": { "type": "integer", "minimum": 0 },
|
|
58
|
+
"resolved": { "type": "integer", "minimum": 0 },
|
|
59
|
+
"still_open": { "type": "integer", "minimum": 0 },
|
|
60
|
+
"partially_fixed": { "type": "integer", "minimum": 0 },
|
|
61
|
+
"regressed": { "type": "integer", "minimum": 0 }
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"findings": {
|
|
65
|
+
"type": "array",
|
|
66
|
+
"items": { "$ref": "#/$defs/finding" }
|
|
67
|
+
},
|
|
68
|
+
"dedupe_preflight": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"additionalProperties": false,
|
|
71
|
+
"properties": {
|
|
72
|
+
"count": { "type": "integer", "minimum": 0 },
|
|
73
|
+
"items": {
|
|
74
|
+
"type": "array",
|
|
75
|
+
"items": {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"required": ["id", "location", "claim"],
|
|
78
|
+
"properties": {
|
|
79
|
+
"id": { "type": "string" },
|
|
80
|
+
"location": { "type": "string" },
|
|
81
|
+
"claim": { "type": "string" }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"coverage": {
|
|
88
|
+
"type": "object",
|
|
89
|
+
"description": "Recall / completeness pass ledger.",
|
|
90
|
+
"additionalProperties": true,
|
|
91
|
+
"properties": {
|
|
92
|
+
"files_reviewed": { "type": "array", "items": { "type": "string" } },
|
|
93
|
+
"files_skipped": { "type": "array", "items": { "type": "string" } },
|
|
94
|
+
"lenses_without_findings": {
|
|
95
|
+
"type": "array",
|
|
96
|
+
"items": {
|
|
97
|
+
"type": "object",
|
|
98
|
+
"required": ["lens", "reason"],
|
|
99
|
+
"properties": {
|
|
100
|
+
"lens": {
|
|
101
|
+
"type": "string",
|
|
102
|
+
"enum": [
|
|
103
|
+
"security",
|
|
104
|
+
"correctness",
|
|
105
|
+
"smells",
|
|
106
|
+
"architecture",
|
|
107
|
+
"performance",
|
|
108
|
+
"tests",
|
|
109
|
+
"contracts",
|
|
110
|
+
"errors",
|
|
111
|
+
"maintainability"
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
"reason": { "type": "string", "minLength": 1 }
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"signals": {
|
|
121
|
+
"type": "object",
|
|
122
|
+
"description": "Signals pre-flight: deterministic tools run before the scout.",
|
|
123
|
+
"additionalProperties": true,
|
|
124
|
+
"properties": {
|
|
125
|
+
"tools": {
|
|
126
|
+
"type": "array",
|
|
127
|
+
"items": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"required": ["name"],
|
|
130
|
+
"properties": {
|
|
131
|
+
"name": { "type": "string", "minLength": 1 },
|
|
132
|
+
"status": { "type": "string", "enum": ["pass", "fail", "skipped"] },
|
|
133
|
+
"summary": { "type": "string" }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"stats": {
|
|
140
|
+
"type": "object",
|
|
141
|
+
"description": "Pipeline stats: subagent counts and shortcut tallies for the run.",
|
|
142
|
+
"additionalProperties": false,
|
|
143
|
+
"properties": {
|
|
144
|
+
"scouts": { "type": "integer", "minimum": 0 },
|
|
145
|
+
"skeptics_dedicated": { "type": "integer", "minimum": 0 },
|
|
146
|
+
"skeptics_batched": { "type": "integer", "minimum": 0 },
|
|
147
|
+
"inline_verdicts": { "type": "integer", "minimum": 0 },
|
|
148
|
+
"grounded_skips": { "type": "integer", "minimum": 0 },
|
|
149
|
+
"carried_forward": { "type": "integer", "minimum": 0 },
|
|
150
|
+
"second_opinions": { "type": "integer", "minimum": 0 }
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
"$defs": {
|
|
155
|
+
"finding": {
|
|
156
|
+
"type": "object",
|
|
157
|
+
"required": ["id", "lens", "location", "claim", "severity", "verdict", "verdict_reason"],
|
|
158
|
+
"additionalProperties": false,
|
|
159
|
+
"properties": {
|
|
160
|
+
"id": { "type": "string", "pattern": "^(F|dup)-[0-9]{3}$" },
|
|
161
|
+
"title": { "type": "string", "minLength": 1 },
|
|
162
|
+
"lens": {
|
|
163
|
+
"type": "string",
|
|
164
|
+
"enum": [
|
|
165
|
+
"security",
|
|
166
|
+
"correctness",
|
|
167
|
+
"smells",
|
|
168
|
+
"architecture",
|
|
169
|
+
"performance",
|
|
170
|
+
"tests",
|
|
171
|
+
"contracts",
|
|
172
|
+
"errors",
|
|
173
|
+
"maintainability"
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
"location": { "type": "string", "minLength": 1 },
|
|
177
|
+
"claim": { "type": "string", "minLength": 1 },
|
|
178
|
+
"evidence": { "type": "string" },
|
|
179
|
+
"severity": { "type": "string", "enum": ["critical", "important", "minor"] },
|
|
180
|
+
"phase1_confidence": { "type": "string", "enum": ["low", "medium", "high"] },
|
|
181
|
+
"original_severity": { "type": "string", "enum": ["critical", "important", "minor"] },
|
|
182
|
+
"verdict": {
|
|
183
|
+
"type": "string",
|
|
184
|
+
"enum": [
|
|
185
|
+
"confirmed",
|
|
186
|
+
"false_positive",
|
|
187
|
+
"downgraded",
|
|
188
|
+
"needs_decision",
|
|
189
|
+
"resolved",
|
|
190
|
+
"still_open",
|
|
191
|
+
"partially_fixed",
|
|
192
|
+
"regressed"
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
"verdict_reason": { "type": "string", "minLength": 1 },
|
|
196
|
+
"second_opinion": {
|
|
197
|
+
"type": "object",
|
|
198
|
+
"description": "Independent second skeptic for dangerous-quadrant findings.",
|
|
199
|
+
"required": ["verdict", "verdict_reason"],
|
|
200
|
+
"additionalProperties": false,
|
|
201
|
+
"properties": {
|
|
202
|
+
"verdict": {
|
|
203
|
+
"type": "string",
|
|
204
|
+
"enum": [
|
|
205
|
+
"confirmed",
|
|
206
|
+
"false_positive",
|
|
207
|
+
"downgraded",
|
|
208
|
+
"needs_decision",
|
|
209
|
+
"resolved",
|
|
210
|
+
"still_open",
|
|
211
|
+
"partially_fixed",
|
|
212
|
+
"regressed"
|
|
213
|
+
]
|
|
214
|
+
},
|
|
215
|
+
"verdict_reason": { "type": "string", "minLength": 1 },
|
|
216
|
+
"agrees": { "type": "boolean" }
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Code review report template
|
|
2
|
+
|
|
3
|
+
**Generated, not hand-authored.** The JSON sidecar is the single source of truth; the paired markdown is produced from it by `review render --file <json>`. This file documents the structure the renderer emits — edit the JSON (and the renderer in the review CLI `lib.mjs`), never the `.md` directly.
|
|
4
|
+
|
|
5
|
+
Path: `.reviews/<timestamp>-<scope-slug>-review.md` (or `-reverify.md` for fix verification), per [report-schema.json](report-schema.json).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
```markdown
|
|
10
|
+
# Code review — {SCOPE_DESCRIPTION}
|
|
11
|
+
|
|
12
|
+
**Review ID:** {REVIEW_ID}
|
|
13
|
+
**Kind:** review | reverify
|
|
14
|
+
**Created:** {ISO_TIMESTAMP}
|
|
15
|
+
**Scope:** {SCOPE_TYPE} — {SCOPE_DETAIL}
|
|
16
|
+
**Lenses:** {LENS_LIST}
|
|
17
|
+
**Parent report:** {PARENT_REVIEW_ID or —}
|
|
18
|
+
|
|
19
|
+
## Executive summary
|
|
20
|
+
|
|
21
|
+
{TWO_TO_FOUR_SENTENCES: what was reviewed, verdict counts, overall risk posture.}
|
|
22
|
+
|
|
23
|
+
### Verdict counts
|
|
24
|
+
|
|
25
|
+
| Verdict | Count |
|
|
26
|
+
| ------- | ----- |
|
|
27
|
+
| Confirmed | |
|
|
28
|
+
| Downgraded | |
|
|
29
|
+
| False positive | |
|
|
30
|
+
| Needs decision | |
|
|
31
|
+
| Resolved | |
|
|
32
|
+
| Still open | |
|
|
33
|
+
| Partially fixed | |
|
|
34
|
+
| Regressed | |
|
|
35
|
+
|
|
36
|
+
### Top actions
|
|
37
|
+
|
|
38
|
+
1. {Highest priority confirmed/critical item}
|
|
39
|
+
2. {Second}
|
|
40
|
+
3. {Third}
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Critical
|
|
45
|
+
|
|
46
|
+
### {F-001}: {Short title}
|
|
47
|
+
|
|
48
|
+
- **Lens:** security
|
|
49
|
+
- **Location:** `path:line`
|
|
50
|
+
- **Severity:** critical {or `minor (was important)` when downgraded}
|
|
51
|
+
- **Verdict:** confirmed
|
|
52
|
+
- **Claim:** ...
|
|
53
|
+
- **Reason:** ...
|
|
54
|
+
- **Second skeptic:** {only for dangerous-quadrant findings} verdict — reason
|
|
55
|
+
|
|
56
|
+
{Repeat per finding}
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Important
|
|
61
|
+
|
|
62
|
+
{Same structure}
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Minor
|
|
67
|
+
|
|
68
|
+
{Same structure}
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Needs decision
|
|
73
|
+
|
|
74
|
+
{Architectural items with `needs_decision` verdict — link ADRs if applicable}
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Coverage ledger
|
|
79
|
+
|
|
80
|
+
{From the recall pass — files reviewed/skipped and active lenses that produced
|
|
81
|
+
no findings, each with a one-line reason. Omitted when no `coverage` object.}
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Appendix A — Rejected findings (false positives)
|
|
86
|
+
|
|
87
|
+
### {F-00X}: {Short title}
|
|
88
|
+
|
|
89
|
+
- **Claim:** ...
|
|
90
|
+
- **Why rejected:** ...
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Appendix B — Dedupe pre-flight
|
|
95
|
+
|
|
96
|
+
{If smells lens ran; else omit section}
|
|
97
|
+
|
|
98
|
+
| ID | Location | Claim |
|
|
99
|
+
| -- | -------- | ----- |
|
|
100
|
+
| dup-001 | ... | ... |
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Appendix C — Method
|
|
105
|
+
|
|
106
|
+
- Phase 1: Scout pass ({N} tentative findings)
|
|
107
|
+
- Phase 2: Adversarial skeptic verification (severity-routed, budgeted)
|
|
108
|
+
- {If reverify: Re-verification against parent report {PARENT_ID}}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## JSON sidecar
|
|
112
|
+
|
|
113
|
+
Author the `.json` (the source of truth), then `review render` to (re)generate this markdown and `review export` to validate before handing off in CI contexts.
|
|
114
|
+
|
|
115
|
+
Main report body includes only `confirmed` and `downgraded` findings (initial review) or `still_open`, `partially_fixed`, `regressed` (reverify). Render places `false_positive` in Appendix A automatically.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Severity rubric
|
|
2
|
+
|
|
3
|
+
Calibrate severity before Phase 2. Skeptics may **downgrade** with evidence; upgrade only with new evidence.
|
|
4
|
+
|
|
5
|
+
## Critical
|
|
6
|
+
|
|
7
|
+
Must fix before merge or production. Examples:
|
|
8
|
+
|
|
9
|
+
- Exploitable auth bypass or IDOR on production path
|
|
10
|
+
- SQL/command injection with attacker-controlled input reaching sink
|
|
11
|
+
- Secret or credential committed or logged
|
|
12
|
+
- Data loss, corruption, or double-charge on money paths
|
|
13
|
+
- Broken idempotency causing duplicate financial side effects
|
|
14
|
+
|
|
15
|
+
## Important
|
|
16
|
+
|
|
17
|
+
Should fix soon; real defect or serious debt with plausible trigger. Examples:
|
|
18
|
+
|
|
19
|
+
- Logic bug on common edge case (empty input, race under concurrency)
|
|
20
|
+
- Missing authorization on sensitive internal endpoint (if not ADR-accepted)
|
|
21
|
+
- Error responses cached by idempotency middleware
|
|
22
|
+
- Test gap on behaviour-critical path
|
|
23
|
+
- Significant duplication that must stay in sync (rule of three)
|
|
24
|
+
|
|
25
|
+
## Minor
|
|
26
|
+
|
|
27
|
+
Nice to have; low likelihood or defense-in-depth. Examples:
|
|
28
|
+
|
|
29
|
+
- Naming inconsistency
|
|
30
|
+
- Missing progress indicator
|
|
31
|
+
- Unlikely edge case with graceful degradation
|
|
32
|
+
- Style nits not affecting behaviour
|
|
33
|
+
- Pre-existing file size (only flag growth **this change** introduced)
|
|
34
|
+
|
|
35
|
+
## Needs decision (not a severity)
|
|
36
|
+
|
|
37
|
+
Architectural or policy trade-off — route to `NEEDS_DECISION` verdict, not Critical by default.
|
|
38
|
+
|
|
39
|
+
Examples: accepted inter-service trust model per ADR, intentional public surface, documented technical debt.
|
|
40
|
+
|
|
41
|
+
## Project-specific downgrades
|
|
42
|
+
|
|
43
|
+
Before marking Critical/Important on themes covered by the project's accepted-risk digest, read that digest (and ADRs):
|
|
44
|
+
|
|
45
|
+
- Formally accepted trust boundaries (e.g. LAN-only HMAC)
|
|
46
|
+
- Documented intentional broad access patterns
|
|
47
|
+
- Actor/header trust models bound by an upstream session
|
|
48
|
+
|
|
49
|
+
Re-flag only if a listed re-open trigger has fired. See [accepted-risks.md](accepted-risks.md) and [examples/accepted-risks-janus.md](../examples/accepted-risks-janus.md).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Signals pre-flight
|
|
2
|
+
|
|
3
|
+
Ground the scout in real tool output **before** reading code by hand. Tool-confirmed problems are facts, not guesses — they raise recall on the smells / contracts / tests / errors lenses and cut hallucinated findings.
|
|
4
|
+
|
|
5
|
+
## Steps
|
|
6
|
+
|
|
7
|
+
1. **Plan the commands.** Run the planner for the review scope:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
review signals --type branch # detect changed files vs main
|
|
11
|
+
review signals --type uncommitted # working tree + untracked
|
|
12
|
+
review signals --paths services/persona,services/mercury
|
|
13
|
+
review signals --json # machine-readable
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
It maps the scope to the **workspaces that own it** and prints the exact per-workspace grounding commands (this monorepo has no root typecheck — each package owns its scripts).
|
|
17
|
+
|
|
18
|
+
2. **Run the grounding commands** it lists, e.g.:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm run typecheck --workspace=your-workspace
|
|
22
|
+
npm run test --workspace=your-workspace
|
|
23
|
+
npm run lint --workspace=your-workspace
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Add, when available and relevant to the scope:
|
|
27
|
+
|
|
28
|
+
- `npx knip` (or the repo's dead-code script) — unused exports / dead code → **smells**
|
|
29
|
+
- the service's OpenAPI **route-parity** test — mounted routes vs registry → **contracts**
|
|
30
|
+
|
|
31
|
+
3. **Convert real failures to grounded tentative findings.** A type error, failing test, lint error, or dead export becomes an `F-###` (or `dup-###`) tentative finding with `confidence: high` and the tool output as `evidence`. Do **not** invent findings the tools did not support.
|
|
32
|
+
|
|
33
|
+
4. **Record what ran** in the report JSON `signals` object so the grounding is auditable:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
"signals": {
|
|
37
|
+
"tools": [
|
|
38
|
+
{ "name": "typecheck your-workspace", "status": "pass" },
|
|
39
|
+
{ "name": "test your-workspace", "status": "fail", "summary": "1 failing: consent.test.ts" },
|
|
40
|
+
{ "name": "knip", "status": "skipped", "summary": "not in scope" }
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Rules
|
|
46
|
+
|
|
47
|
+
- Read-only. The pre-flight never edits code.
|
|
48
|
+
- Scope-bound. Run tools for the **workspaces in scope**, not the whole repo, unless the scope is repo-wide.
|
|
49
|
+
- A passing tool is signal too — it lets the coverage pass mark a lens genuinely exercised.
|
|
50
|
+
- If a tool can't run (missing script, environment), record it `skipped` with a reason rather than omitting it.
|
|
51
|
+
|
|
52
|
+
## Notes
|
|
53
|
+
|
|
54
|
+
- The **dedupe pre-flight** (smells lens) is the same pattern with the `dedupe` skill as the tool; keep emitting `dup-###` findings and the `dedupe_preflight` summary.
|
|
55
|
+
- Grounded findings at `critical`/`important` still go through Phase 2 — a failing test might be an intentional WIP. Below `important`, skip the skeptic: the tool output is the proof; the orchestrator just checks for intentional-WIP signals (commit message, TODO, user context) and records the verdict directly.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Architecture Decision Records
|
|
2
|
+
|
|
3
|
+
Canonical index of ADRs for this project. See [decisions.md]({{DECISIONS_REL}}) for the full convention (when to write, template, cross-links with OpenSpec).
|
|
4
|
+
|
|
5
|
+
| # | Title | Status | Date |
|
|
6
|
+
| ----- | ----- | ------ | ---- |
|
|
7
|
+
| <!-- add rows as ADRs are written: | NNNN | Title | Status | YYYY-MM-DD | --> |
|