hstack 0.16.0 → 0.18.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 (134) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +76 -163
  3. package/VERSION +1 -1
  4. package/dist/commands/doctor.js +18 -8
  5. package/dist/commands/doctor.js.map +1 -1
  6. package/dist/commands/init.js +7 -3
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/update.js +9 -2
  9. package/dist/commands/update.js.map +1 -1
  10. package/dist/lib/descriptions.js +10 -17
  11. package/dist/lib/descriptions.js.map +1 -1
  12. package/dist/lib/wire.js +166 -138
  13. package/dist/lib/wire.js.map +1 -1
  14. package/dist/manifest.js +41 -29
  15. package/dist/manifest.js.map +1 -1
  16. package/package.json +3 -4
  17. package/template/.claude/agents/adversarial-reviewer.md +44 -50
  18. package/template/.claude/agents/app-architect.md +44 -96
  19. package/template/.claude/agents/data-architect.md +46 -89
  20. package/template/.claude/agents/test-strategist.md +39 -68
  21. package/template/.claude/skills/hstack-adr-new/SKILL.md +23 -73
  22. package/template/.claude/skills/hstack-adversarial-review/SKILL.md +46 -152
  23. package/template/.claude/skills/hstack-adversarial-review/references/finding-categories.md +89 -103
  24. package/template/.claude/skills/hstack-app-architecture/SKILL.md +43 -68
  25. package/template/.claude/skills/hstack-commit/SKILL.md +27 -68
  26. package/template/.claude/skills/hstack-data-architecture/SKILL.md +34 -56
  27. package/template/.claude/skills/hstack-promote/SKILL.md +55 -0
  28. package/template/.claude/skills/hstack-story/SKILL.md +58 -0
  29. package/template/.claude/skills/hstack-test-audit/SKILL.md +64 -0
  30. package/template/.claude/skills/hstack-wrap/SKILL.md +50 -0
  31. package/template/.claude/skills/hstack-wrap/references/pr-description.md +45 -0
  32. package/template/KERNEL.md +75 -318
  33. package/template/templates/adr.md +2 -18
  34. package/template/templates/app-architecture.md +38 -50
  35. package/template/templates/code-standards.md +107 -0
  36. package/template/templates/data-architecture.md +38 -89
  37. package/template/templates/eslint-clean-code.mjs +322 -0
  38. package/template/templates/infrastructure.md +54 -148
  39. package/template/templates/roadmap.md +6 -12
  40. package/template/templates/story.md +7 -13
  41. package/template/templates/tech-debt.md +2 -37
  42. package/template/templates/tech-stack.md +2 -12
  43. package/template/.claude/agents/data-specialist.md +0 -81
  44. package/template/.claude/agents/implementer.md +0 -97
  45. package/template/.claude/agents/kernel-fit-analyst.md +0 -129
  46. package/template/.claude/agents/planner.md +0 -75
  47. package/template/.claude/agents/product-discovery.md +0 -129
  48. package/template/.claude/agents/product-manager.md +0 -76
  49. package/template/.claude/agents/researcher.md +0 -87
  50. package/template/.claude/agents/security-reviewer.md +0 -88
  51. package/template/.claude/agents/spec-author.md +0 -89
  52. package/template/.claude/agents/stack-architect.md +0 -108
  53. package/template/.claude/agents/ui-ux-briefer.md +0 -75
  54. package/template/.claude/agents/verifier.md +0 -81
  55. package/template/.claude/skills/hstack-branch/SKILL.md +0 -76
  56. package/template/.claude/skills/hstack-brownfield-init/SKILL.md +0 -131
  57. package/template/.claude/skills/hstack-change-new/SKILL.md +0 -84
  58. package/template/.claude/skills/hstack-change-plan/SKILL.md +0 -108
  59. package/template/.claude/skills/hstack-configure/SKILL.md +0 -99
  60. package/template/.claude/skills/hstack-coord/SKILL.md +0 -95
  61. package/template/.claude/skills/hstack-data-review/SKILL.md +0 -93
  62. package/template/.claude/skills/hstack-finalize/SKILL.md +0 -140
  63. package/template/.claude/skills/hstack-flag/SKILL.md +0 -99
  64. package/template/.claude/skills/hstack-greenfield-init/SKILL.md +0 -148
  65. package/template/.claude/skills/hstack-help/SKILL.md +0 -153
  66. package/template/.claude/skills/hstack-implement/SKILL.md +0 -155
  67. package/template/.claude/skills/hstack-kernel-fit-promote/SKILL.md +0 -125
  68. package/template/.claude/skills/hstack-kernel-fit-scan/SKILL.md +0 -142
  69. package/template/.claude/skills/hstack-kernel-fit-scan/references/slack-setup.md +0 -42
  70. package/template/.claude/skills/hstack-kernel-fit-triage/SKILL.md +0 -121
  71. package/template/.claude/skills/hstack-module-spec/SKILL.md +0 -78
  72. package/template/.claude/skills/hstack-product-discovery/SKILL.md +0 -75
  73. package/template/.claude/skills/hstack-research/SKILL.md +0 -115
  74. package/template/.claude/skills/hstack-scaffold/SKILL.md +0 -113
  75. package/template/.claude/skills/hstack-security-review/SKILL.md +0 -95
  76. package/template/.claude/skills/hstack-ship/SKILL.md +0 -119
  77. package/template/.claude/skills/hstack-stack-decide/SKILL.md +0 -81
  78. package/template/.claude/skills/hstack-story-draft/SKILL.md +0 -92
  79. package/template/.claude/skills/hstack-tech-debt-new/SKILL.md +0 -95
  80. package/template/.claude/skills/hstack-tech-debt-resolve/SKILL.md +0 -123
  81. package/template/.claude/skills/hstack-tech-debt-stale/SKILL.md +0 -86
  82. package/template/.claude/skills/hstack-tech-debt-wontfix/SKILL.md +0 -77
  83. package/template/.claude/skills/hstack-telemetry/SKILL.md +0 -73
  84. package/template/.claude/skills/hstack-test-plan/SKILL.md +0 -159
  85. package/template/.claude/skills/hstack-ui-brief/SKILL.md +0 -81
  86. package/template/.claude/skills/hstack-verify/SKILL.md +0 -128
  87. package/template/scripts/compute-merge-readiness.mjs +0 -780
  88. package/template/scripts/coord/coord_scan.py +0 -681
  89. package/template/scripts/run-gates.sh +0 -388
  90. package/template/scripts/telemetry/__init__.py +0 -6
  91. package/template/scripts/telemetry/insights/__init__.py +0 -0
  92. package/template/scripts/telemetry/insights/contract_drift.py +0 -137
  93. package/template/scripts/telemetry/insights/kernel_fit.py +0 -438
  94. package/template/scripts/telemetry/insights/overengineering.py +0 -115
  95. package/template/scripts/telemetry/insights/quality_outcomes.py +0 -131
  96. package/template/scripts/telemetry/insights/token_economics.py +0 -302
  97. package/template/scripts/telemetry/insights/workflow_shape.py +0 -198
  98. package/template/scripts/telemetry/parsers/__init__.py +0 -0
  99. package/template/scripts/telemetry/parsers/bodies.py +0 -87
  100. package/template/scripts/telemetry/parsers/commits.py +0 -219
  101. package/template/scripts/telemetry/parsers/frontmatter.py +0 -322
  102. package/template/scripts/telemetry/parsers/sidecars.py +0 -61
  103. package/template/scripts/telemetry/parsers/transcripts.py +0 -294
  104. package/template/scripts/telemetry/render.py +0 -460
  105. package/template/scripts/telemetry/report.py +0 -150
  106. package/template/scripts/telemetry/run_kernel_fit.py +0 -95
  107. package/template/scripts/telemetry/session_id.py +0 -139
  108. package/template/scripts/validate-spec.mjs +0 -3303
  109. package/template/templates/adversarial-review.md +0 -54
  110. package/template/templates/bootstrap.md +0 -105
  111. package/template/templates/change-spec.md +0 -82
  112. package/template/templates/ci-cd.md +0 -41
  113. package/template/templates/coord-message.md +0 -56
  114. package/template/templates/data-review.md +0 -54
  115. package/template/templates/discovery/brainstorm.md +0 -69
  116. package/template/templates/discovery/forcing-questions.md +0 -76
  117. package/template/templates/discovery/project-brief.md +0 -53
  118. package/template/templates/figma-handoff.md +0 -38
  119. package/template/templates/glossary.md +0 -20
  120. package/template/templates/hardening-checklist.md +0 -73
  121. package/template/templates/incident-runbook.md +0 -57
  122. package/template/templates/kernel-fit-finding.md +0 -63
  123. package/template/templates/kernel-fit-flag.md +0 -52
  124. package/template/templates/module-spec.md +0 -49
  125. package/template/templates/persona.md +0 -38
  126. package/template/templates/plan.md +0 -53
  127. package/template/templates/product-brief.md +0 -56
  128. package/template/templates/security-review.md +0 -63
  129. package/template/templates/telemetry-sidecar.md +0 -227
  130. package/template/templates/test-plan.md +0 -119
  131. package/template/templates/threat-model.md +0 -54
  132. package/template/templates/ui-brief.md +0 -49
  133. package/template/templates/verification.md +0 -63
  134. package/template/templates/vision.md +0 -34
@@ -1,166 +1,60 @@
1
1
  ---
2
2
  name: hstack-adversarial-review
3
- description: Use only in a fresh Claude Code session — separate from the one that ran the implementeronce `verification.md` is at `passed` and the change is at `ready-for-review`. Orchestrates the `adversarial-reviewer`, which reads the change cold.
4
- tools:
5
- - Read
6
- - Write
7
- - Edit
8
- - Grep
9
- - Glob
10
- - Bash
11
- - Task
12
- - "node hstack/scripts/validate-spec.mjs — validates adversarial-review frontmatter and AR-01..AR-06"
13
- - "{{TODO-OTHER: fresh-session-attestation — in v1, the subagent self-attests the session is fresh; v2 substrate captures and compares Claude Code session ids automatically}}"
3
+ description: "Use in a fresh session — never the one that wrote the changeto review a PR that touches a sensitive surface. Findings land as a PR comment; the author is the one who fixes them."
14
4
  ---
15
5
 
16
6
  ## Purpose
17
7
 
18
- `hstack-adversarial-review` produces `adversarial-review.md` by orchestrating the `adversarial-reviewer` subagent in a Claude Code session separate from the one that ran the implementer. The subagent reads the change cold, and "no problems" is a claim it has to defend rather than a default it may fall into. In v1, fresh-session separation is honor-system; the Skill's first job is to remind the engineer of that.
8
+ `/hstack-adversarial-review <pr-number>` reads an open PR cold and reports what is wrong, missing,
9
+ drifted or weakened. It orchestrates the `adversarial-reviewer` subagent and posts the findings on
10
+ the PR. It writes no file and changes no code.
19
11
 
20
- Per ADR-0014 the review is not scored on its finding count. `findings-floor` stays in frontmatter as the area's expectation and lands in the telemetry sidecar, but nothing gates on it; the one count the artifact must argue for is zero (AR-01).
12
+ Reviews are judgments, not evidence (kernel § Review). An empty findings list means the reviewer
13
+ found nothing, not that nothing is there — which is why an empty result is defended rather than
14
+ returned.
21
15
 
22
16
  ## When to invoke
23
17
 
24
- Invoke after `verification.md` reaches `status: passed`, in a **fresh Claude Code session**. The Skill opens with a clear instruction to the engineer naming the requirement. If the engineer reports they are in the same session as the implementer, halt and ask them to start a new session.
25
-
26
- ## Inputs
27
-
28
- - `<change-id>` (required, positional): the change-spec id.
29
-
30
- ## Preconditions
31
-
32
- Before any work:
33
-
34
- - **Fresh-session attestation.** The Skill's first action is to print: "This Skill must run in a Claude Code session separate from the one that ran `hstack-implement`. The kernel's authoring-and-review-never-share-a-session principle is honor-system in v1; v2 substrate will verify via session-id comparison. Confirm you are in a fresh session before I proceed." Halt until the engineer confirms.
35
- - Verify the change-spec exists and is at `status: ready-for-review`.
36
- - Verify every required upstream artifact is at terminal status:
37
- - test-plan at `passed` or `concerns-acknowledged`
38
- - plan at `completed`
39
- - security-review at `passed` or `concerns-acknowledged`
40
- - data-review at `passed` or `concerns-acknowledged` when applicable
41
- - ui-brief at `drafted` and figma-handoff at `ready` when applicable
42
- - verification at `passed`
43
- - Set `findings-floor`: 3 default; 5 when `change-spec.area` is in {agent, auth, billing} per AR-06. It is recorded, not enforced.
44
-
45
- ## Orchestration steps
46
-
47
- 0. **Open the phase window (mechanical, no LLM turn, no commit).** The moment the preconditions above pass and *before* any subagent invocation, run `python3 hstack/scripts/telemetry/session_id.py` and keep its `session_id` and `now` values — they become `session_id` and `phase_opened_at` in the sidecar below (ADR-0009). On failure or a null session id, hold `null` for both and continue.
48
-
49
- 1. **Open with the fresh-session reminder.** Print the message verbatim; wait for the engineer's confirmation.
50
-
51
- 2. **Invoke `adversarial-reviewer`.** Use the Task tool with `subagent_type: adversarial-reviewer` and context = [kernel, `hstack/templates/adversarial-review.md`, change-spec, plan, test-plan, ui-brief and figma-handoff when present, security-review, data-review when present, verification, full diff, module-spec, threat-model, hardening-checklist, data-architecture, tech-stack]. Explicitly NOT included: any implementer conversation transcript or scratchpad.
52
-
53
- 3. **Findings generation across six categories.** The subagent sweeps security, scope-drift, invariant-breach, spec-compliance, data-integrity, and code-quality and reports what the sweep found — the categories are lenses, not buckets, and a change whose risk genuinely lives in one dimension produces findings in one category. `references/finding-categories.md`, alongside this file, is the calibration rubric (what each category means, what a real finding looks like, what filler looks like); the subagent reads it on demand, not on every run. Test-plan adherence is a first-class lens: missing edge-case tests surface as spec-compliance findings; missing tenant-isolation tests surface as data-integrity findings; unmet performance budgets surface as code-quality or data-integrity findings depending on cause; unmapped invariants in `verification.test-plan-coverage` surface as spec-compliance findings. **Test-immutability audit:** the subagent diffs every pre-existing test file against the branch base; any modification, deletion, or snapshot update without a matching `Ok to change/delete/update/refresh ...` authorization echo in a commit message is a mandatory finding under spec-compliance at minimum `severity: high`. Bulk snapshot-update flags visible in the diff or in CI logs escalate to `severity: critical`. This audit is mandatory and is not subject to the subagent's judgment about whether the finding is worth filing.
54
-
55
- 4. **The empty result is the one the artifact defends.** Per AR-01, a review that reaches `findings-open` or `findings-resolved` with an empty `findings` array must set `findings-fewer-than-floor: true` and write a defended `justification-when-fewer` plus a filled Findings Floor Justification section, enumerating what was looked for and why each sweep came back clean. "The change is small" alone is insufficient. Any count above zero passes AR-01; `findings_count` against `findings_floor` is reported to telemetry and read in aggregate, never as a per-review gate.
56
-
57
- 5. **Resolution discipline.** Each finding's `resolution` is one of:
58
- - `commit:<hash>` — must reference an existing commit on the change's branch (AR-04).
59
- - `tech-debt:<id>` — must reference an existing tech-debt artifact at `open` or `in-progress` (AR-05). When the engineer chooses this path, they invoke `hstack-tech-debt-new` to create the tech-debt artifact before this review terminates.
60
- - `justified-in-prose` — reserved for low-severity findings only. High-severity findings routed to `justified-in-prose` halt the Skill.
61
-
62
- 6. **Fresh-session attestation in frontmatter.** The subagent writes `fresh-session-attestation: "session <id>; opened <timestamp>; no prior implementer context loaded"`. v1 records this as honor-system text; v2 substrate captures the actual session id from Claude Code's session file.
63
-
64
- 7. **Findings-open is non-terminal.** The subagent does not advance `status: findings-resolved` until every finding has `status: resolved` and a `resolution` value.
65
-
66
- 8. **Owner response loop.** For each finding, the engineer (the change owner) responds with a resolution. The Resolution Log section records each response. The Skill walks the engineer through every finding sequentially.
67
-
68
- 9. **Validate.** Run `node hstack/scripts/validate-spec.mjs <path>` — AR-01 through AR-06.
69
-
70
- 10. **Change-spec advance (mechanical, only on `findings-resolved`, Skill-orchestrator write per ADR-0002).** When and only when the subagent returned with `adversarial-review.md` at `status: findings-resolved`, read `hstack/specs/changes/<change-id>/spec.md` and inspect its `status` frontmatter. If `status: ready-for-review`, print a proposed-diff preview of the change-spec edit (`status: ready-for-review → ready-to-ship`; `updated: <today>`) and prompt "Proceed with this change-spec advance? (Y/n)". Default Yes. On confirmation, perform the edit via the `Edit` tool, run `node hstack/scripts/validate-spec.mjs <path>` against the change-spec, then `git add` and commit with message `change-spec(<change-id>): ready-to-ship`. This is a separate commit from the adversarial-review transition commits, matching the verify and finalize precedents. If the change-spec is already at `ready-to-ship` or any downstream status (`shipped`, `archived`), this step is a no-op (idempotent on re-runs). When adversarial-review status is `findings-open` or `in-progress`, this step does not run — the change-spec remains at `ready-for-review` until every finding is resolved. The `adversarial-reviewer` subagent retains its critique-only lane and writes only `adversarial-review.md`; the cross-artifact advance is the Skill orchestrator's own write, per ADR-0002.
71
-
72
- ## Outputs
73
-
74
- - `hstack/specs/changes/<change-id>/adversarial-review.md` at `status: findings-resolved`.
75
- - When `adversarial-review.md` lands at `findings-resolved` and the change-spec was at `ready-for-review`: an edit to `hstack/specs/changes/<change-id>/spec.md` advancing `status: ready-for-review → ready-to-ship` and bumping `updated:` (per ADR-0002, written by the Skill orchestrator).
76
- - Optional new tech-debt artifacts produced via `hstack-tech-debt-new` invocations when findings route to `tech-debt:<id>`.
77
- - Optional new commits on the change's branch when findings route to `commit:<hash>` and the implementer is re-invoked (separately, via `hstack-implement`) to make the fix.
78
-
79
- ## Auto-commit triggers
80
-
81
- - Status transition to `in-progress` after Methodology lands.
82
- - Status transition to `findings-open` after all findings are written.
83
- - Status transition to `findings-resolved` when every finding has `status: resolved`.
84
- - Edits to the `findings` array.
85
- - Edits to any finding's `resolution`.
86
- - **Change-spec status transition `ready-for-review` → `ready-to-ship`** (per ADR-0002, Skill-orchestrator write). When `adversarial-review.md` reaches `findings-resolved`, the Skill orchestrator performs the change-spec advance directly via `Edit` (orchestration step 10), in a separate auto-commit with message `change-spec(<change-id>): ready-to-ship`. The change-spec becomes eligible for `hstack-ship` only after this commit lands. `hstack-ship` itself remains read-only across artifact statuses — it reads the already-written `ready-to-ship` and computes the merge-readiness scorecard. The `adversarial-reviewer` subagent does not write this transition; it stays in its critique-only lane.
87
-
88
- ## Telemetry sidecar
89
-
90
- At the change-spec advance commit (only when adversarial-review status is `findings-resolved`), write `hstack/specs/changes/<change-id>/.telemetry/adversarial-review.json` in the same `git add && git commit` as the change-spec advance. The sidecar is derivative of git + frontmatter (see `hstack/templates/telemetry-sidecar.md`). Schema:
91
-
92
- ```json
93
- {
94
- "schema_version": 2,
95
- "skill": "hstack-adversarial-review",
96
- "change_id": "<change-id>",
97
- "session_id": "<session id from step 0, or null>",
98
- "phase_opened_at": "<ISO-8601 from step 0, or null>",
99
- "phase_closed_at": "<ISO-8601, now — same write as this sidecar, or null>",
100
- "reviewed_at": "<ISO-8601, when status reached findings-resolved>",
101
- "findings_floor": <int, 3 or 5 per AR-06>,
102
- "findings_count": <int, length of frontmatter findings array>,
103
- "findings_fewer_than_floor": <bool>,
104
- "category_counts": {
105
- "security": <int>,
106
- "scope-drift": <int>,
107
- "invariant-breach": <int>,
108
- "spec-compliance": <int>,
109
- "data-integrity": <int>,
110
- "code-quality": <int>
111
- },
112
- "severity_counts": {
113
- "critical": <int>,
114
- "high": <int>,
115
- "medium": <int>,
116
- "low": <int>
117
- },
118
- "resolution_mix": {
119
- "commit": <int>,
120
- "tech-debt": <int>,
121
- "justified-in-prose": <int>
122
- },
123
- "fresh_session_attestation": "<verbatim copy of frontmatter field>",
124
- "halt_reasons": [<kernel halt-sentinel enum values, if any>]
125
- }
126
- ```
127
-
128
- When the review ends at `findings-open` or `in-progress` (no change-spec advance), the sidecar still lands with the same shape on whichever transition commit terminates the current run; `findings_fewer_than_floor` reflects the current value. `.telemetry/` is git-ignored. If the sidecar write fails, log and continue; the canonical commit must still land. Since ADR-0014 removed the quota this sidecar stopped being a fraud detector and became a description: `findings_count` against `findings_floor`, `category_counts`, `severity_counts` and `resolution_mix` describe what reviews are finding, and shifts in the joint distribution are the instrument for judging whether the judgment-based framing reads changes better or worse than the count did.
129
-
130
- The three phase-window fields (`session_id`, `phase_opened_at`, `phase_closed_at`) come from step 0 and from this write. Their rules — best-effort, unmeasured rather than zero, never a halt — are stated once in `hstack/templates/telemetry-sidecar.md` § The phase window, which is the canonical schema and wins over any Skill.
131
-
132
- ## Session boundary
133
-
134
- `adversarial-review` is a natural session cut: the auto-commit above left `adversarial-review.md` at its terminal status on disk, so the conversation holds nothing the next phase needs. The cut-notice format, the kickoff-prompt template and the context-block rules are in `KERNEL.md` § Session boundaries; this Skill's two variables are:
135
-
136
- ```
137
- HSTACK-CUT: adversarial-review complete — cut recommended before ship.
138
- ```
139
-
140
- and the next command, `/hstack:ship <change-id>`.
141
-
142
- ## Idempotency contract
143
-
144
- - Re-running on a `findings-resolved` review: the subagent reads the existing artifact and produces a no-op aside from `updated` timestamps, unless new code or artifacts have landed since the prior run (in which case new findings may be generated and the status drops back to `findings-open`).
145
- - Re-running mid-resolution after a halt: the subagent reads the partial artifact and resumes with the first finding still at `status: open`.
146
- - The change-spec advance step (step 10) is idempotent: a re-run against a change-spec already at `ready-to-ship` (or `shipped`, `archived`) produces a no-op for that step. The Skill does not re-advance and does not regress.
18
+ On a PR touching one of the sensitive surfaces the kernel § Review names. Every PR already gets
19
+ `/review` and `/security-review` through `/wrap`; this is the deep pass on top, and its whole value
20
+ is that the session running it never saw the change being written.
21
+
22
+ **In a fresh session.** State it in one sentence before starting — "this session has not seen the
23
+ implementation conversation" — and if that is not true, stop and open a new one. This is
24
+ honor-system, as the kernel says; a sentence is the whole protocol.
25
+
26
+ ## Steps
27
+
28
+ 1. **Load the change.** `gh pr view <n>` for the description, `gh pr diff <n>` for the diff, plus
29
+ the base commit so pre-existing files can be diffed. Read the living docs the diff touches,
30
+ `hstack/context/invariants.md`, and the frozen `threat-model.md`. Do not load, ask for, or
31
+ reconstruct the conversation that produced the change.
32
+ 2. **Invoke `adversarial-reviewer`** with that material. The subagent sweeps six lenses and returns
33
+ findings; it does not resolve them and does not touch the code.
34
+ 3. **The test-immutability audit is mandatory** and is not subject to anyone's judgment about
35
+ whether it is worth filing. Every test file that existed at the base is diffed; a modification
36
+ or deletion without its canonical authorization echo — `Ok to change test <name>` /
37
+ `Ok to delete test <name>`, in a commit message or the PR description is a finding at `high`
38
+ minimum. A bulk snapshot update is `critical`.
39
+ 4. **Post the findings** with `gh pr comment <n>`, or as a GitHub review when they are anchored to
40
+ lines. Each finding carries a severity, a category, the evidence in the diff, and what would
41
+ resolve it.
42
+ 5. **Resolution belongs to the author**: a corrective commit on the branch, or a tech-debt file
43
+ written in the same PR (kernel § Tech-debt). The reviewer never pushes the fix.
44
+
45
+ ## Output
46
+
47
+ One PR comment. No artifact, no status, no file in the repo.
147
48
 
148
49
  ## Stop conditions
149
50
 
150
- Beyond the kernel's general stop conditions:
151
-
152
- - Engineer has not confirmed they are in a fresh Claude Code session.
153
- - A required upstream artifact is non-terminal.
154
- - A high-severity security or tenant-isolation finding would route to `justified-in-prose`. Halt.
155
- - A `commit:<hash>` resolution would reference a commit not on the change's branch.
156
- - A `tech-debt:<id>` resolution would reference a non-existent tech-debt artifact (the engineer must invoke `hstack-tech-debt-new` first).
157
- - The review found nothing and the empty-result defence cannot be written honestly. Halt and surface; a defence nobody believes is worse than an open review.
158
- - The diff includes changes outside `change-spec.in-scope` that CI did not catch — surface a scope-drift finding and halt the CI gap as a separate concern.
159
- - An implementer transcript or scratchpad is visible in the session.
160
-
161
- ## Failure modes
51
+ Beyond the kernel's:
162
52
 
163
- - **Engineer claims fresh session but conversation shows prior implementer transcripts.** Halt; ask the engineer to truly start a new session.
164
- - **The review comes back empty and the defence feels thin.** Walk the six categories against `references/finding-categories.md` once more; if the sweep is still clean, the empty result is defended explicitly and on the record, not waved through.
165
- - **A finding routes to `tech-debt:<id>` but the engineer hasn't created the tech-debt artifact.** The Skill prompts to invoke `hstack-tech-debt-new`; the review does not terminate until the artifact exists.
166
- - **A commit hash named in `resolution` does not exist on the change's branch.** Halt — the engineer either re-references the correct commit or the resolution is reconsidered.
53
+ - The session has seen the implementation conversation. Halt and ask for a fresh one.
54
+ - The PR cannot be read, or its diff is unavailable.
55
+ - A living doc the review depends on is missing or stale. Say so in the findings; never invent its
56
+ content (kernel § Context docs).
57
+ - The sweep came back empty and the defence cannot be written honestly. Halt and surface it — a
58
+ defence nobody believes is worse than an open review.
59
+ - A high-severity finding is waved away without a fix or a tech-debt file. Do not silently retract:
60
+ restate it with the evidence, and leave it in the comment.
@@ -1,157 +1,143 @@
1
1
  # The six finding categories — a calibration rubric
2
2
 
3
- Reference file for `hstack-adversarial-review` and the `adversarial-reviewer`
4
- subagent. Read it when a category is unfamiliar, when a finding feels thin and
5
- you want to know whether it is real, or when calibrating severity against
6
- precedent. It is **not** a checklist: nothing here says how many findings a
7
- review should produce, and a review that lands entirely in one category is a
8
- correct outcome when the change carries its risk in one dimension (ADR-0014).
9
-
10
- The `category` value in a finding record is a controlled enum — the six names
11
- below, exactly — and AR-02 rejects anything else.
3
+ Reference file for `hstack-adversarial-review` and the `adversarial-reviewer` subagent. Read it
4
+ when a category is unfamiliar, when a finding feels thin and you want to know whether it is real,
5
+ or when calibrating a severity. It is **not** a checklist: nothing here says how many findings a
6
+ review should produce, and a review landing entirely in one category is the correct outcome when
7
+ the change carries its risk in one dimension (ADR-0014).
12
8
 
13
9
  ---
14
10
 
15
11
  ## security
16
12
 
17
- **What it means.** The change creates or widens a path an attacker can use, or
18
- weakens a control that was closing one. Distinct from `data-integrity`: this is
19
- about an adversary, not about accidental corruption.
13
+ **What it means.** The change creates or widens a path an attacker can use, or weakens a control
14
+ that was closing one. Distinct from `data-integrity`: this is about an adversary, not about
15
+ accidental corruption.
20
16
 
21
- **Real findings look like.** A new endpoint that reads a user-supplied id and
22
- queries by it without re-deriving the caller's scope. A prompt that
23
- concatenates retrieved document text into a system message. A secret moved from
24
- an env read to a literal. An auth check that runs after the side effect. A
25
- dependency bump that pulls a package with a known CVE the security-review did
26
- not see because the lockfile changed outside `in-scope`.
17
+ **Real findings look like.** A new endpoint that reads a user-supplied id and queries by it without
18
+ re-deriving the caller's scope. A prompt that concatenates retrieved document text into a system
19
+ message. A secret moved from an env read to a literal. An auth check that runs after the side
20
+ effect. A dependency bump that pulls a package with a known CVE.
27
21
 
28
- **Filler looks like.** "Consider adding rate limiting" on a change that touches
29
- no network surface. Restating a hardening-checklist item the security-review
30
- already scored `pass`, with no evidence from the diff that the score is wrong.
22
+ **Filler looks like.** "Consider adding rate limiting" on a change that touches no network surface.
23
+ Restating an item of the kernel's security checklist with no evidence from the diff that it was
24
+ missed.
31
25
 
32
- **Severity.** Anything exploitable by a non-authenticated caller, or that
33
- crosses a tenant boundary, is `critical` or `high` — never `medium` because it
34
- is unlikely. Likelihood belongs in the severity rationale, not in the level.
26
+ **Severity.** Anything exploitable by an unauthenticated caller, or that crosses a tenant boundary,
27
+ is `critical` or `high` — never `medium` because it is unlikely. Likelihood belongs in the severity
28
+ rationale, not in the level.
35
29
 
36
30
  ---
37
31
 
38
32
  ## scope-drift
39
33
 
40
- **What it means.** The diff touches things `change-spec.in-scope` does not
41
- name, or the change quietly grew a second purpose.
34
+ **What it means.** The diff touches things the PR description's announced perimeter does not name
35
+ (kernel § Scope rules), or the change quietly grew a second purpose.
42
36
 
43
- **Real findings look like.** A refactor of a shared util that no phase in
44
- `plan.md` asked for. A migration that alters a table outside the change's
45
- module. A "while I was in there" rename that makes the diff unreviewable. A new
46
- dependency added to satisfy a convenience the spec never asked for.
37
+ **Real findings look like.** A refactor of a shared util nothing in the change asked for. A
38
+ migration altering a table outside the change's module. A "while I was in there" rename that makes
39
+ the diff unreviewable. A new dependency satisfying a convenience nobody asked for.
47
40
 
48
- **Filler looks like.** Flagging a file the change-spec's globs do cover on a
49
- literal reading. Flagging generated files, lockfiles, or formatter output that
50
- the repo's conventions produce automatically.
41
+ **Filler looks like.** Flagging a file the announced perimeter does cover. Flagging generated
42
+ files, lockfiles or formatter output the repo's conventions produce automatically.
51
43
 
52
- **Severity.** Usually `medium`. It escalates when the drift lands in a module
53
- with its own module-spec invariants, because then it is also `invariant-breach`
54
- and CI's scope gate did not catch it.
44
+ **Severity.** Usually `medium`. It escalates when the drift lands on a path `invariants.md` covers,
45
+ because then it is also `invariant-breach`.
55
46
 
56
47
  ---
57
48
 
58
49
  ## invariant-breach
59
50
 
60
- **What it means.** Something the change-spec or the relevant module-spec
61
- declares as always-true is no longer always-true after this diff.
51
+ **What it means.** Something `hstack/context/invariants.md` or a living doc declares as always-true
52
+ is no longer always-true after this diff.
62
53
 
63
- **Real findings look like.** A module-spec that says "no direct SQL outside this
64
- module" and a new query in an adjacent file. A change-spec invariant about
65
- ordering that the new code path can violate under concurrency. An invariant
66
- that is still true but is now enforced by convention where it used to be
67
- enforced by a type or a constraint.
54
+ **Real findings look like.** An invariant about ordering that the new code path can violate under
55
+ concurrency. An invariant still true but now enforced by convention where it used to be enforced by
56
+ a type or a database constraint. A boundary a living doc describes — "no direct SQL outside this
57
+ module" and a new query in an adjacent file.
68
58
 
69
- **Filler looks like.** Paraphrasing an invariant back and calling it a risk.
70
- Naming an invariant the diff does not touch.
59
+ **Filler looks like.** Paraphrasing an invariant back and calling it a risk. Naming an invariant the
60
+ diff does not touch.
71
61
 
72
- **Severity.** `high` by default — an invariant that can break silently is worse
73
- than a bug that throws. Drop to `medium` only when the breach is caught by an
74
- existing test that will fail loudly.
62
+ **Severity.** `high` by default — an invariant that breaks silently is worse than a bug that throws.
63
+ Drop to `medium` only when an existing test fails loudly on the breach.
75
64
 
76
65
  ---
77
66
 
78
- ## spec-compliance
67
+ ## intent-compliance
79
68
 
80
- **What it means.** The diff and the artifacts disagree. This is the category
81
- with the widest surface and the one most often under-used.
69
+ **What it means.** The diff and what the PR says it does disagree. The widest category and the one
70
+ most often under-used. The PR description is the contract here: it names the perimeter, the Notion
71
+ feature, the shortcuts taken, the living docs updated.
82
72
 
83
- **Real findings look like.** An acceptance criterion in the change-spec with no
84
- corresponding behaviour in the diff. An edge case the `test-plan` promised and
85
- the diff did not land. A tenant-isolation test named in the test-plan and
86
- absent from the branch. An invariant in the change-spec that
87
- `verification.test-plan-coverage` maps to no observed test. Behaviour the
88
- implementation added that no artifact anticipated undeclared scope is a
89
- compliance gap in the other direction. **Any test-file modification without its
90
- canonical authorization echo** (see `KERNEL.md` § Test immutability); this one
91
- is mandatory and never subject to judgment about whether it is worth filing.
92
- When `resolves-tech-debt` is non-empty, any Acceptance bullet the diff leaves
93
- `partial` or `not-satisfied` (AR-07).
73
+ **Real findings look like.** Behaviour the description promises and the diff does not land.
74
+ Behaviour the diff adds that no line of the description anticipated — undeclared scope is a
75
+ compliance gap in the other direction. A living doc the change invalidated and left untouched
76
+ (kernel § Context docs). A conscious shortcut visible in the code and named nowhere. **Any
77
+ test-file modification without its canonical authorization echo** (`KERNEL.md` § Test immutability);
78
+ this one is mandatory and never subject to judgment about whether it is worth filing.
94
79
 
95
- **Filler looks like.** "The spec could have been clearer." Style disagreements
96
- with the plan's phase decomposition.
80
+ **Filler looks like.** "The description could have been clearer." Style disagreements with how the
81
+ work was sequenced.
97
82
 
98
- **Severity.** Unauthorized test changes: `high` minimum, `critical` for bulk
99
- snapshot updates. Unmet Acceptance bullets: `high`, `critical` once the change
100
- is at `ready-to-ship`. Everything else: judgment.
83
+ **Severity.** Unauthorized test changes: `high` minimum, `critical` for a bulk snapshot update. A
84
+ stale living doc: `high`, because the next session will read it and believe it. Everything else:
85
+ judgment.
101
86
 
102
87
  ---
103
88
 
104
89
  ## data-integrity
105
90
 
106
- **What it means.** Data can end up wrong, lost, or visible to the wrong tenant
107
- without anybody attacking anything.
91
+ **What it means.** Data can end up wrong, lost, or visible to the wrong tenant without anybody
92
+ attacking anything.
108
93
 
109
- **Real findings look like.** A migration that adds a NOT NULL column without a
110
- default or a backfill. A destructive DDL with no stated rollback. An RLS policy
111
- whose predicate does not match the tenancy model in `data-architecture.md`. A
112
- tenant-scoped RPC missing its `tenant_id` filter. A write path that is
113
- not idempotent under retry. A pgvector retrieval that filters after the
114
- similarity search rather than inside it.
94
+ **Real findings look like.** A migration adding a NOT NULL column with no default and no backfill.
95
+ A destructive DDL with no stated rollback. An RLS policy whose predicate does not match the tenancy
96
+ model in `data-architecture.md`. A tenant-scoped RPC missing its tenant filter. A write path that
97
+ is not idempotent under retry. A pgvector retrieval filtering after the similarity search rather
98
+ than inside it.
115
99
 
116
- **Filler looks like.** Speculating about scale on a table with a bounded row
117
- count. Recommending an index with no query to justify it.
100
+ **Filler looks like.** Speculating about scale on a table with a bounded row count. Recommending an
101
+ index with no query to justify it.
118
102
 
119
- **Severity.** Cross-tenant leakage is `critical` — always, including when the
120
- leak needs an unlikely sequence to trigger. Irreversible data loss is
121
- `critical`. Recoverable inconsistency is `high`.
103
+ **Severity.** Cross-tenant leakage is `critical` — always, including when the leak needs an unlikely
104
+ sequence to trigger. Irreversible data loss is `critical`. Recoverable inconsistency is `high`.
122
105
 
123
106
  ---
124
107
 
125
108
  ## code-quality
126
109
 
127
- **What it means.** The change works and will cost more than it should to live
128
- with. The weakest category and the easiest to pad, which is why it is worth
129
- being strict about what belongs here.
110
+ **What it means.** The change works and will cost more than it should to live with. The rubric is
111
+ `hstack/context/code-standards.md`: a finding here names the rule it breaks, and a rule the file
112
+ does not hold is not a finding. The easiest category to pad, which is why the rule number is
113
+ required.
130
114
 
131
- **Real findings look like.** A third copy of logic that already exists twice,
132
- where the copies have started to disagree. Error handling that swallows a
133
- failure the caller needs. A function whose behaviour depends on call order with
134
- nothing that documents or enforces it. A performance budget in the test-plan
135
- that the implementation cannot meet as written.
115
+ **Real findings look like.** A second implementation of something the repo already had — a
116
+ client, a parser, a retry — written beside the first instead of found (rule 2). A function that
117
+ orchestrates and also does the steps, so the next phase starts at a comment (rule 3). A component
118
+ that fetches or decodes a protocol (rule 4). A file whose name stopped describing its contents in
119
+ this diff (rule 5). A `get*` that writes (rule 6). A result carrying `error` that nothing reads,
120
+ or a `catch` that continues with no justification (rule 7). A new path wired beside the old one
121
+ with the old one still reachable (rule 8). Code this diff orphaned and left in place (rule 9).
136
122
 
137
- **Filler looks like.** Naming preferences. Suggested comments. Requests to
138
- extract a function that is used once. Anything a formatter or a linter would
139
- have said, since `run-gates.sh` already ran.
123
+ **Filler looks like.** Naming preferences that do not make a name lie. Suggested comments.
124
+ Requests to extract a function used once. Anything the repo's linter already fails on — size,
125
+ `any`, console, `process.env` when the linter is wired; when it is not, one finding says so
126
+ instead of listing what it would have caught.
140
127
 
141
- **Severity.** `low` or `medium`. A `code-quality` finding at `high` is usually
142
- mis-categorized look again at whether it is really `invariant-breach` or
143
- `data-integrity`.
128
+ **Severity.** `low` or `medium`. Rule 7 escalates on a write path: an unread error after an
129
+ `update` or `delete` is `data-integrity`, not `code-quality`. Any other `high` here is usually
130
+ mis-categorized — look again at `invariant-breach` or `data-integrity`.
144
131
 
145
132
  ---
146
133
 
147
- ## Resolution routing
134
+ ## Resolution
148
135
 
149
- Independent of category:
136
+ Independent of category, a finding names what would resolve it:
150
137
 
151
- - `commit:<hash>` fixed on the branch. The hash must exist there (AR-04).
152
- - `tech-debt:<id>`acknowledged and deferred, against a tech-debt artifact
153
- that exists at `open` or `in-progress` at write time (AR-05).
154
- - `justified-in-prose` — the finding is real and the right answer is to explain
155
- why nothing changes. Reserved for `low` severity. A `high`-severity finding
156
- routed here is a halt, and a security or tenant-isolation finding routed here
157
- is a halt with escalation.
138
+ - **A corrective commit on the branch** the author fixes it before the merge.
139
+ - **A tech-debt file in the same PR** the finding is real and is being lived with, on the record
140
+ and grep-able by `related-modules` (kernel § Tech-debt).
141
+ - **An argument in the comment thread** — the finding is real and the right answer is to explain
142
+ why nothing changes. Fine for a `low`; a `high` answered this way stays open, and a security or
143
+ tenant-isolation finding answered this way is escalated, not closed.