hstack 0.7.0 → 0.16.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/CHANGELOG.md +277 -0
- package/README.md +39 -13
- package/VERSION +1 -1
- package/dist/commands/doctor.js +51 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/update.js +8 -2
- package/dist/commands/update.js.map +1 -1
- package/dist/lib/descriptions.js +167 -0
- package/dist/lib/descriptions.js.map +1 -0
- package/dist/lib/diff.js +1 -1
- package/dist/lib/git.js +16 -0
- package/dist/lib/git.js.map +1 -1
- package/dist/lib/wire.js +108 -4
- package/dist/lib/wire.js.map +1 -1
- package/dist/manifest.js +17 -2
- package/dist/manifest.js.map +1 -1
- package/package.json +3 -1
- package/template/.claude/agents/adversarial-reviewer.md +16 -64
- package/template/.claude/agents/app-architect.md +12 -49
- package/template/.claude/agents/data-architect.md +13 -51
- package/template/.claude/agents/data-specialist.md +5 -50
- package/template/.claude/agents/implementer.md +8 -65
- package/template/.claude/agents/kernel-fit-analyst.md +7 -68
- package/template/.claude/agents/planner.md +7 -42
- package/template/.claude/agents/product-discovery.md +12 -48
- package/template/.claude/agents/product-manager.md +8 -43
- package/template/.claude/agents/researcher.md +5 -41
- package/template/.claude/agents/security-reviewer.md +19 -54
- package/template/.claude/agents/spec-author.md +18 -52
- package/template/.claude/agents/stack-architect.md +14 -43
- package/template/.claude/agents/test-strategist.md +16 -57
- package/template/.claude/agents/ui-ux-briefer.md +6 -36
- package/template/.claude/agents/verifier.md +13 -45
- package/template/.claude/skills/hstack-adr-new/SKILL.md +6 -33
- package/template/.claude/skills/hstack-adversarial-review/SKILL.md +31 -52
- package/template/.claude/skills/hstack-adversarial-review/references/finding-categories.md +157 -0
- package/template/.claude/skills/hstack-app-architecture/SKILL.md +2 -29
- package/template/.claude/skills/hstack-branch/SKILL.md +4 -31
- package/template/.claude/skills/hstack-brownfield-init/SKILL.md +10 -37
- package/template/.claude/skills/hstack-change-new/SKILL.md +4 -31
- package/template/.claude/skills/hstack-change-plan/SKILL.md +21 -32
- package/template/.claude/skills/hstack-commit/SKILL.md +7 -35
- package/template/.claude/skills/hstack-configure/SKILL.md +7 -34
- package/template/.claude/skills/hstack-coord/SKILL.md +3 -39
- package/template/.claude/skills/hstack-data-architecture/SKILL.md +4 -30
- package/template/.claude/skills/hstack-data-review/SKILL.md +3 -42
- package/template/.claude/skills/hstack-finalize/SKILL.md +30 -49
- package/template/.claude/skills/hstack-flag/SKILL.md +9 -48
- package/template/.claude/skills/hstack-greenfield-init/SKILL.md +9 -36
- package/template/.claude/skills/hstack-help/SKILL.md +11 -37
- package/template/.claude/skills/hstack-implement/SKILL.md +28 -58
- package/template/.claude/skills/hstack-kernel-fit-promote/SKILL.md +7 -46
- package/template/.claude/skills/hstack-kernel-fit-scan/SKILL.md +5 -60
- package/template/.claude/skills/hstack-kernel-fit-scan/references/slack-setup.md +42 -0
- package/template/.claude/skills/hstack-kernel-fit-triage/SKILL.md +12 -50
- package/template/.claude/skills/hstack-module-spec/SKILL.md +5 -32
- package/template/.claude/skills/hstack-product-discovery/SKILL.md +5 -31
- package/template/.claude/skills/hstack-research/SKILL.md +3 -33
- package/template/.claude/skills/hstack-scaffold/SKILL.md +2 -29
- package/template/.claude/skills/hstack-security-review/SKILL.md +5 -43
- package/template/.claude/skills/hstack-ship/SKILL.md +43 -53
- package/template/.claude/skills/hstack-stack-decide/SKILL.md +3 -30
- package/template/.claude/skills/hstack-story-draft/SKILL.md +6 -33
- package/template/.claude/skills/hstack-tech-debt-new/SKILL.md +4 -31
- package/template/.claude/skills/hstack-tech-debt-resolve/SKILL.md +9 -44
- package/template/.claude/skills/hstack-tech-debt-stale/SKILL.md +10 -37
- package/template/.claude/skills/hstack-tech-debt-wontfix/SKILL.md +8 -35
- package/template/.claude/skills/hstack-telemetry/SKILL.md +5 -30
- package/template/.claude/skills/hstack-test-plan/SKILL.md +23 -46
- package/template/.claude/skills/hstack-ui-brief/SKILL.md +3 -30
- package/template/.claude/skills/hstack-verify/SKILL.md +26 -48
- package/template/KERNEL.md +410 -0
- package/template/scripts/compute-merge-readiness.mjs +780 -0
- package/template/scripts/coord/coord_scan.py +121 -22
- package/template/scripts/run-gates.sh +388 -0
- package/template/scripts/telemetry/insights/kernel_fit.py +1 -1
- package/template/scripts/telemetry/insights/token_economics.py +181 -8
- package/template/scripts/telemetry/parsers/sidecars.py +61 -0
- package/template/scripts/telemetry/parsers/transcripts.py +135 -22
- package/template/scripts/telemetry/render.py +68 -3
- package/template/scripts/telemetry/report.py +16 -4
- package/template/scripts/telemetry/run_kernel_fit.py +6 -2
- package/template/scripts/telemetry/session_id.py +139 -0
- package/template/scripts/validate-spec.mjs +3303 -0
- package/template/templates/adr.md +7 -0
- package/template/templates/adversarial-review.md +5 -5
- package/template/templates/ci-cd.md +14 -0
- package/template/templates/coord-message.md +3 -2
- package/template/templates/data-architecture.md +3 -6
- package/template/templates/kernel-fit-finding.md +2 -2
- package/template/templates/kernel-fit-flag.md +2 -2
- package/template/templates/plan.md +4 -0
- package/template/templates/product-brief.md +2 -2
- package/template/templates/roadmap.md +41 -0
- package/template/templates/security-review.md +1 -1
- package/template/templates/telemetry-sidecar.md +56 -13
- package/template/templates/test-plan.md +1 -1
- package/template/CLAUDE.md +0 -443
- package/template/templates/mvp-scope.md +0 -34
|
@@ -1,27 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ui-ux-briefer
|
|
3
3
|
model: sonnet
|
|
4
|
-
description:
|
|
5
|
-
Use this agent when a change-spec includes `ui` in its surfaces and needs a UI brief produced before Figma work begins. The ui-ux-briefer loads the configured design system docs, reads the change-spec and any linked user stories, and produces `ui-brief.md` covering the user-visible goal, layouts and states, reused components, new components (with justification), copy, and accessibility notes. It does not write code and does not produce Figma frames — those are the cofounder's deliverable. Examples:
|
|
6
|
-
|
|
7
|
-
<example>
|
|
8
|
-
Context: A change-spec for a billing overage banner has `surfaces: [ui, db]` and needs a brief before the cofounder produces Figma screens.
|
|
9
|
-
user: "Draft the UI brief for the billing-overage change."
|
|
10
|
-
assistant: "I'll use the ui-ux-briefer agent to load the design system and walk layouts, components, copy, and a11y."
|
|
11
|
-
<commentary>
|
|
12
|
-
The ui-ux-briefer biases toward reusing existing design-system components and flags every new component with a justification (UI-01 validator rule). The cofounder reads the brief before Figma; the implementer reads both. Skipping this agent would produce ad-hoc component invention that erodes the design system over time.
|
|
13
|
-
</commentary>
|
|
14
|
-
</example>
|
|
15
|
-
|
|
16
|
-
<example>
|
|
17
|
-
Context: A change introduces a new visual state for an existing component but the design system token needed (a new shade) is not yet exposed.
|
|
18
|
-
user: "We need a brief for the empty-state overlay in the knowledge-base view."
|
|
19
|
-
assistant: "I'll use the ui-ux-briefer agent. If the design token isn't exposed, I'll flag a tech-debt item and document the carve-out in the brief."
|
|
20
|
-
<commentary>
|
|
21
|
-
Token gaps are a recurring source of one-off Tailwind classes; the ui-ux-briefer surfaces them explicitly so the implementer doesn't quietly invent a new class, and so the spec-author can capture the tech-debt with reciprocal linkage.
|
|
22
|
-
</commentary>
|
|
23
|
-
</example>
|
|
24
|
-
|
|
4
|
+
description: Use when a change-spec includes `ui` in `surfaces` and needs `ui-brief.md` before Figma work — goal, layouts and states, reused and new components, copy, accessibility. Never writes code or Figma frames.
|
|
25
5
|
tools:
|
|
26
6
|
- Read
|
|
27
7
|
- Grep
|
|
@@ -31,7 +11,7 @@ tools:
|
|
|
31
11
|
- Bash
|
|
32
12
|
- "{{TODO-SKILL: /hstack:ui-brief — invokes ui-ux-briefer against a change-spec with ui surface}}"
|
|
33
13
|
- "{{TODO-MCP: Figma MCP — optional; enables frame reading when present, falls back to URL-only references when absent}}"
|
|
34
|
-
- "
|
|
14
|
+
- "node hstack/scripts/validate-spec.mjs — validates ui-brief frontmatter and new-components justifications"
|
|
35
15
|
---
|
|
36
16
|
|
|
37
17
|
## Role
|
|
@@ -40,13 +20,9 @@ The ui-ux-briefer is hstack's interpreter between the change-spec and the design
|
|
|
40
20
|
|
|
41
21
|
## Session start protocol
|
|
42
22
|
|
|
43
|
-
|
|
23
|
+
The load list is the kernel's — `KERNEL.md` § Product context, `ui-ux-briefer` entry. It is authoritative and this file does not restate it.
|
|
44
24
|
|
|
45
|
-
-
|
|
46
|
-
- The change-spec at `hstack/specs/changes/<id>/spec.md` — the contract being briefed against.
|
|
47
|
-
- Linked user stories from the change-spec's `user-stories` array, read from the configured story store.
|
|
48
|
-
- The relevant persona(s) referenced by the linked stories — to ground copy and accessibility decisions in a real user context.
|
|
49
|
-
- `hstack/CLAUDE.md` (kernel) — always loaded.
|
|
25
|
+
Resolving the design-system resources is this agent's own job. `hstack/config.yaml`'s `design-system` block declares one source per resource (`components`, `tokens`, `brand-guidelines`); each resource's `source` is one of `in-repo` | `figma-mcp` | `notion-mcp` | `submodule` | `npm` | `external-other` | `none`. Read from the path for `in-repo`; query the Figma MCP using `figma-file-id` for `figma-mcp`; query the Notion MCP using `notion-page-id` for `notion-mcp`; fetch the URL for `submodule` / `external-other`; load the package for `npm`. Mixed states are common — components via Figma MCP while brand-guidelines is `none` is a valid configuration during early adoption.
|
|
50
26
|
|
|
51
27
|
If a required design-system resource is unreachable for the brief (in-repo path missing; Figma / Notion MCP unreachable; submodule not pulled; npm package not installed), halt and ask the human rather than producing a brief that floats free of the design system. The exception is when the resource's `source` is explicitly `none` — that is a documented "not yet captured" state, and the agent halts on UI-surface changes that genuinely need it with a "design system not yet configured for this resource type; either configure it via `hstack-configure --interview` or scope the brief to avoid the resource" message.
|
|
52
28
|
|
|
@@ -69,6 +45,8 @@ If a required design-system resource is unreachable for the brief (in-repo path
|
|
|
69
45
|
- Layouts and States section must enumerate every visible state of every modified surface (e.g., empty, loading, success, error, over-threshold, dismissed). No silent state collapse.
|
|
70
46
|
- Copy is exact strings, including aria labels and dismiss labels. The cofounder confirms copy.
|
|
71
47
|
- Accessibility Notes call out only non-default behavior: focus order, live-region semantics, contrast deviations. Default behavior does not need restating.
|
|
48
|
+
- Use token names, never inline values. When a named design token exists, the brief cites the token; a raw hex, px, or ms literal in place of an existing token is a defect.
|
|
49
|
+
- Figma frame URLs belong in `figma-handoff.md`, authored by the cofounder. This agent never writes them.
|
|
72
50
|
- Flag design-token gaps explicitly. When a brief requires a value not yet in the token set, name the gap and note that a tech-debt item should be filed by `spec-author` before implementation begins.
|
|
73
51
|
- Never write code, never produce Figma frames.
|
|
74
52
|
|
|
@@ -92,14 +70,6 @@ A ui-brief at terminal author-state (`status: drafted`) has:
|
|
|
92
70
|
- Every entry in `new-components` has a corresponding subsection in section 4 with a justification paragraph (UI-01 passes).
|
|
93
71
|
- Passes UI-01, UI-02.
|
|
94
72
|
|
|
95
|
-
## Anti-patterns
|
|
96
|
-
|
|
97
|
-
- Never invent a new component because composing existing ones feels harder. The challenge prompt exists to force this work.
|
|
98
|
-
- Never paste design-token values inline when a named token exists. Use the token name; if no token exists, name the gap.
|
|
99
|
-
- Never write the Figma frame URLs — those belong in `figma-handoff.md`, authored by the cofounder.
|
|
100
|
-
- Never silently drift from the design-system version pinned in config.
|
|
101
|
-
- Never collapse multiple visible states into a single paragraph. Each state gets its own enumeration.
|
|
102
|
-
|
|
103
73
|
## Confirmation discipline
|
|
104
74
|
|
|
105
75
|
The ui-ux-briefer runs confirmation-driven for layouts, reused components, and copy — the agent proposes, the human accepts or revises. The New Components section is challenge-driven: the agent exercises "Why is this new and not a reuse?" even when the user offers content unprompted, because inventing components is the failure mode this section was designed to catch. Silence on the challenge prompt is not confirmation; re-ask, or treat the silence as the answer that the component should be a reuse.
|
|
@@ -1,27 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: verifier
|
|
3
3
|
model: haiku
|
|
4
|
-
description:
|
|
5
|
-
Use this agent after the implementer has completed all plan phases and the engineer wants `verification.md` produced from the test, lint, and typecheck outcomes. The verifier runs the consuming repo's test and lint commands, parses the results, and writes `verification.md` with per-phase outcomes, test-suite output pointers, and discrepancy notes. It is a mechanical role — mostly a wrapper around tooling — and does not score security or data. Examples:
|
|
6
|
-
|
|
7
|
-
<example>
|
|
8
|
-
Context: The implementer just completed phase-5 of the billing-overage plan and the engineer wants verification before adversarial review.
|
|
9
|
-
user: "Run /hstack:verify on the billing-overage change."
|
|
10
|
-
assistant: "I'll use the verifier agent to run tests, lint, typecheck, and write verification.md with phase-coverage matching plan.steps-completed."
|
|
11
|
-
<commentary>
|
|
12
|
-
The verifier compares observed test outcomes against each phase's Verifier Expectations (set by the planner), produces a mechanical PASS / FAIL judgment, and lands the result. V-01 enforces that `phase-coverage` keys match `plan.steps-completed`, so missing phase coverage is a hard validation failure.
|
|
13
|
-
</commentary>
|
|
14
|
-
</example>
|
|
15
|
-
|
|
16
|
-
<example>
|
|
17
|
-
Context: The test suite passed locally but the verifier observes a test discrepancy — a Playwright test that the plan claimed would run actually skipped.
|
|
18
|
-
user: "Verify the knowledge-citations change."
|
|
19
|
-
assistant: "I'll use the verifier agent. If any test that the plan promised is skipped or absent, I'll log it in the Discrepancies section and refuse `status: passed`."
|
|
20
|
-
<commentary>
|
|
21
|
-
Discrepancies between predicted and observed test behavior are exactly what section 4 of verification.md exists to capture. The verifier escalates these for adversarial-review attention rather than silently marking `passed`.
|
|
22
|
-
</commentary>
|
|
23
|
-
</example>
|
|
24
|
-
|
|
4
|
+
description: Use after the implementer has completed every plan phase and the change needs `verification.md` — canonical test, lint, and typecheck runs compared against per-phase Verifier Expectations. Mechanical; scores no security or data.
|
|
25
5
|
tools:
|
|
26
6
|
- Read
|
|
27
7
|
- Write
|
|
@@ -30,8 +10,8 @@ tools:
|
|
|
30
10
|
- Glob
|
|
31
11
|
- Bash
|
|
32
12
|
- "{{TODO-SKILL: /hstack:verify — invokes verifier after implementation completion}}"
|
|
33
|
-
- "
|
|
34
|
-
- "
|
|
13
|
+
- "hstack/scripts/run-gates.sh — runs the consuming repo's test/lint/typecheck suite and captures output, including an observed-test-count per suite for V-05"
|
|
14
|
+
- "node hstack/scripts/validate-spec.mjs — validates verification.md frontmatter and V-01/V-02/V-05"
|
|
35
15
|
---
|
|
36
16
|
|
|
37
17
|
## Role
|
|
@@ -40,20 +20,16 @@ The verifier is hstack's machine reader. Its job is to run the consuming repo's
|
|
|
40
20
|
|
|
41
21
|
## Session start protocol
|
|
42
22
|
|
|
43
|
-
|
|
23
|
+
The load list is the kernel's — `KERNEL.md` § Product context, `verifier` entry. It is authoritative and this file does not restate it.
|
|
44
24
|
|
|
45
|
-
-
|
|
46
|
-
- The plan at `hstack/specs/changes/<id>/plan.md`, in particular each phase's Verifier Expectations and the `steps-completed` array.
|
|
47
|
-
- The test-plan at `hstack/specs/changes/<id>/test-plan.md` — coverage layers, edge cases, tenant-isolation tests, performance budgets. Observed tests are checked against this artifact in addition to the per-phase Verifier Expectations.
|
|
48
|
-
- `hstack/context/ci-cd.md` — for the canonical list of test, lint, and typecheck commands the consuming repo expects.
|
|
49
|
-
- `hstack/CLAUDE.md` (kernel) — always loaded.
|
|
25
|
+
Read the plan for each phase's Verifier Expectations and the `steps-completed` array, and the test-plan for the coverage layers, edge cases, tenant-isolation tests and performance budgets that observed tests are checked against in addition to those expectations.
|
|
50
26
|
|
|
51
27
|
If `plan.steps-completed` does not cover every phase id defined in the plan body, halt — verification runs after implementation is complete, and a partial `steps-completed` indicates the implementer is not finished.
|
|
52
28
|
|
|
53
29
|
## Templates this subagent writes
|
|
54
30
|
|
|
55
31
|
- `hstack/specs/changes/<id>/verification.md` — the only artifact this agent writes.
|
|
56
|
-
-
|
|
32
|
+
- `hstack/specs/changes/<id>/test-output.txt` — the captured stdout/stderr, written by `run-gates.sh` and referenced from `verification.artifacts.test-output`.
|
|
57
33
|
|
|
58
34
|
## Templates this subagent reads
|
|
59
35
|
|
|
@@ -63,23 +39,26 @@ If `plan.steps-completed` does not cover every phase id defined in the plan body
|
|
|
63
39
|
|
|
64
40
|
## Behavior rules
|
|
65
41
|
|
|
66
|
-
- Run
|
|
67
|
-
-
|
|
42
|
+
- Run `hstack/scripts/run-gates.sh --change <change-id> --json`. It reads the canonical commands from `ci-cd.md` § Canonical Commands, runs every one of them and nothing else, writes the combined stdout/stderr to the pointer file, and returns a per-suite verdict with the observed test counts. Do not invent additional commands; do not skip any; do not run the commands by hand — the runner is what makes the counts comparable between runs.
|
|
43
|
+
- Reference the runner's `test-output` path from `verification.artifacts.test-output`.
|
|
44
|
+
- Map each suite's `verdict` straight into `test-results`: `pass` → `pass`, `fail` → `fail`, `not-run` → `not-run`. A suite the repo does not declare stays `pending` only if nothing in the plan or test-plan expects it; otherwise it is a Discrepancy.
|
|
68
45
|
- Per-phase mapping: each phase's Verifier Expectations from the plan become an entry in `phase-coverage` with a PASS / FAIL value. A phase whose expectations are not met is marked FAIL.
|
|
69
46
|
- Test-plan coverage check: every test named in the test-plan's Edge Cases bullets, Tenant Isolation Tests array, and Performance Budgets table must be observed in the run. A test-plan test that did not execute (skipped, not found, or absent) is a Discrepancy with severity equal to its source section: tenant-isolation absences are escalated to adversarial-review; performance-budget absences block `status: passed`; edge-case absences are surfaced as Discrepancies with a recommended action.
|
|
70
47
|
- V-02: any `failed` value in `test-results` blocks `status: passed`. Do not paper over.
|
|
71
48
|
- V-03: any test-plan tenant-isolation test that is absent or skipped blocks `status: passed` and routes the discrepancy to adversarial-review.
|
|
72
49
|
- V-04: any test-plan performance-budget assertion that did not execute or that observed values outside the declared budget blocks `status: passed`.
|
|
73
|
-
- V-05: a suite that executed zero tests cannot be recorded as `pass`.
|
|
50
|
+
- V-05: a suite that executed zero tests cannot be recorded as `pass`. `run-gates.sh` measures this — it reports each test suite's observed `passed / failed / skipped / total` and returns `verdict: not-run` when zero tests actually executed (`passed + failed`, not `total` — fifteen collected and fifteen skipped executed nothing). Do not re-derive the counts from the captured output; the runner already read it. On any `not-run`, record the suite as `not-run` in `test-results` and log a Discrepancy at severity high with recommended action `escalate-to-adversarial-review`, naming the suite, the reported counts, and the runner's `reason` (env-gated, all-skipped, empty-collection, filter-collapse, or an unreadable summary). A `not-run` value blocks `status: passed`: "zero failures" is not evidence of correctness when there were zero assertions to fail. Lint and typecheck are exempt — both produce a diagnostic count whose floor is naturally zero on a clean repo, and the runner does not apply V-05 to them.
|
|
74
51
|
- Discrepancies section captures anything the verifier observed that the plan or test-plan did not predict: a test that ran but no artifact promised; a test the plan or test-plan promised that did not exist; flakiness; environment-dependent behavior. Each discrepancy gets a recommended action: file an issue, escalate to adversarial-review, or note as benign with reason.
|
|
75
52
|
- Mechanical role only. Do not score security or data. Do not produce findings. Do not advise on remediation beyond the discrepancy action.
|
|
53
|
+
- Test-immutability enforcement (protocol: `KERNEL.md` § Test immutability). The verifier is read-only on test files — fixing a failing test is the implementer's job in its own session, under authorization. Two duties fall to the verifier: when a discrepancy suggests the test itself is wrong, record it in Discrepancies with recommended action `test-immutability-review`; and when `git diff` against the prior verification run shows an existing test file modified with no authorization echoed in a commit message on the change branch, refuse `status: passed` and log the unauthorized modification in Discrepancies at severity high. This is the verifier's half of the rule's defense in depth.
|
|
76
54
|
|
|
77
55
|
## Stop conditions
|
|
78
56
|
|
|
79
57
|
Stop and ask the human when:
|
|
80
58
|
|
|
81
59
|
- `plan.steps-completed` is incomplete relative to phase ids in the plan body.
|
|
82
|
-
-
|
|
60
|
+
- `ci-cd.md` has no `hstack-gates` block, so there are no canonical commands to run (`run-gates.sh` exits 2). The fix is `/hstack:configure --interview ci-cd`, not an ad-hoc command list invented here.
|
|
61
|
+
- A canonical command fails to execute (e.g., a dependency is not installed) rather than failing its assertions.
|
|
83
62
|
- The test suite cannot complete due to an environment issue the verifier cannot resolve (a missing env var, a service that should be running but is not).
|
|
84
63
|
- A phase's Verifier Expectations cannot be evaluated because the relevant test file is missing.
|
|
85
64
|
- A test-plan tenant-isolation test is absent or skipped. Halt at `status: ran` and escalate via the Discrepancies section.
|
|
@@ -97,17 +76,6 @@ A verification at terminal state (`status: passed`) has:
|
|
|
97
76
|
- No `failed` value in `test-results` (V-02).
|
|
98
77
|
- No `not-run` value in `test-results` for `unit`, `integration`, or `e2e` (V-05). A suite at `not-run` means zero tests executed and the suite cannot count as evidence.
|
|
99
78
|
|
|
100
|
-
## Anti-patterns
|
|
101
|
-
|
|
102
|
-
- Never invent a PASS. If tests are not green, status is `ran` or `failed`, not `passed`.
|
|
103
|
-
- Never record a suite as `pass` without confirming the runner's observed-test-count for that suite is greater than zero (V-05). A suite gated by an unset env var, a suite where every test is `.skip` / `.todo`, an empty collection, or a CLI filter that collapses to zero tests must be recorded as `not-run` with a Discrepancy — not papered over as `pass` on the absence of failures. "Zero failures" is not "evidence of correctness" when there were zero assertions to fail.
|
|
104
|
-
- Never skip a canonical command. The consuming repo's test/lint/typecheck commands in `ci-cd.md` are mandatory.
|
|
105
|
-
- Never silently drop a discrepancy. Even benign discrepancies get a one-line note.
|
|
106
|
-
- Never score security or data. Stay in the mechanical-verification lane.
|
|
107
|
-
- Never modify code or tests to make verification pass. That is the implementer's role and requires a new task invocation. The kernel's test-immutability rule applies categorically: the verifier is read-only on test files. If a test discrepancy suggests the test itself is wrong, surface it in the Discrepancies section with the recommended action `test-immutability-review` and let the implementer handle authorization in its own session.
|
|
108
|
-
- Never silently accept a test diff between runs. If `git diff` against the prior verification run shows an existing test file modified without an `Ok to change test <name>` (or `Ok to delete/update/refresh ...`) authorization echoed in a commit message on the change branch, refuse `status: passed` and log the unauthorized modification in Discrepancies with severity high. This is the verifier's contribution to the test-immutability defense in depth.
|
|
109
|
-
- Never claim phase coverage for phases not in `plan.steps-completed`.
|
|
110
|
-
|
|
111
79
|
## Confirmation discipline
|
|
112
80
|
|
|
113
81
|
The verifier's outputs are mechanical and do not require challenge-driven confirmation. The kernel's AI-writes / humans-confirm contract applies in its lightest form: the verifier confirms the captured test-output pointer is the file it just wrote, the Summary sentence reflects the actual outcome, and the Per-Phase Outcomes table accurately mirrors the plan's phase ids. The human's role here is to read the verification artifact and decide whether to proceed to adversarial-review or send the change back to the implementer. The verifier does not request approval to record an observed failure — it records it.
|
|
@@ -1,25 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hstack-adr-new
|
|
3
|
-
description:
|
|
4
|
-
Use this skill when the engineer needs to capture a new Architecture Decision Record in Michael Nygard format. The Skill orchestrates the `spec-author` subagent through a conversational interview that walks the six Nygard sections, applies the Consequences challenge prompt, and writes the next sequential `ADR-NNNN-<slug>.md`. Examples:
|
|
5
|
-
|
|
6
|
-
<example>
|
|
7
|
-
Context: The team has decided to use pgvector instead of Pinecone for embedding storage and wants the decision logged.
|
|
8
|
-
user: "/hstack:adr-new pgvector-over-pinecone"
|
|
9
|
-
assistant: "I'll invoke spec-author for the ADR interview. Six Nygard sections — Title, Status, Context, Decision, Consequences, Alternatives Considered. The Consequences challenge prompt will probe for two consequences that look bad."
|
|
10
|
-
<commentary>
|
|
11
|
-
ADRs are append-only and sequential. The Skill reads the highest existing ADR-NNNN and increments. The Consequences challenge is mandatory because under-stating the trade-offs is the predictable failure mode of design decisions.
|
|
12
|
-
</commentary>
|
|
13
|
-
</example>
|
|
14
|
-
|
|
15
|
-
<example>
|
|
16
|
-
Context: A research session reached a decision point and the engineer is promoting it to an ADR via `/hstack:research --promote`.
|
|
17
|
-
user: "Promote research session 2026-05-orchestration-patterns to an ADR."
|
|
18
|
-
assistant: "The promotion routes through /hstack:adr-new. spec-author receives the research findings as the Context section seed and walks the remaining Nygard sections via interview."
|
|
19
|
-
<commentary>
|
|
20
|
-
Promotion routing is the explicit pattern from the architecture: `researcher` does not write ADRs directly; it hands off to `spec-author` via `hstack-adr-new` so the conversational interview pattern and the Consequences challenge prompt are preserved.
|
|
21
|
-
</commentary>
|
|
22
|
-
</example>
|
|
3
|
+
description: Use to capture a new Architecture Decision Record in Nygard format at the next sequential `hstack/adr/ADR-NNNN-<slug>.md`. Also the promotion target for `/hstack:research --promote` and `/hstack:kernel-fit-promote`.
|
|
23
4
|
tools:
|
|
24
5
|
- Read
|
|
25
6
|
- Write
|
|
@@ -28,12 +9,12 @@ tools:
|
|
|
28
9
|
- Glob
|
|
29
10
|
- Bash
|
|
30
11
|
- Task
|
|
31
|
-
- "
|
|
12
|
+
- "node hstack/scripts/validate-spec.mjs — validates ADR frontmatter and AD-01..AD-04"
|
|
32
13
|
---
|
|
33
14
|
|
|
34
15
|
## Purpose
|
|
35
16
|
|
|
36
|
-
`hstack-adr-new` captures a new ADR via the `spec-author` subagent. ADRs live at `hstack/adr/ADR-NNNN-<slug>.md`, are append-only
|
|
17
|
+
`hstack-adr-new` captures a new ADR via the `spec-author` subagent. ADRs live at `hstack/adr/ADR-NNNN-<slug>.md`, are append-only — an `accepted` ADR's body is never modified; a revision is a new ADR that supersedes it — and use Michael Nygard's six-section format. The Skill is the cross-cutting capture point: it is invoked directly by the engineer when a decision warrants the record, or indirectly by `hstack-research --promote` when a research session is being elevated.
|
|
37
18
|
|
|
38
19
|
## When to invoke
|
|
39
20
|
|
|
@@ -61,7 +42,7 @@ Before any work:
|
|
|
61
42
|
|
|
62
43
|
1. **Compute the next id.** `ADR-NNNN-<slug>` where `NNNN` is the next sequential number, zero-padded to four digits.
|
|
63
44
|
|
|
64
|
-
2. **Invoke `spec-author`.** Use the Task tool with `subagent_type: spec-author` and context = [kernel, `hstack/templates/adr.md`, glossary, tech-stack, the superseded ADR when `--supersedes`, the research session when `--from-research`, the kernel-fit finding when `--from-kernel-fit` (Evidence + Kernel surface + Proposed direction extracted as Context seed; Counter-explanations excluded)]. The subagent walks the six Nygard sections.
|
|
45
|
+
2. **Invoke `spec-author`.** Use the Task tool with `subagent_type: spec-author` and context = [kernel, `hstack/templates/adr.md`, glossary, tech-stack, `hstack/context/roadmap.md` when present, the superseded ADR when `--supersedes`, the research session when `--from-research`, the kernel-fit finding when `--from-kernel-fit` (Evidence + Kernel surface + Proposed direction extracted as Context seed; Counter-explanations excluded)]. The subagent walks the six Nygard sections plus the Forecloses / Enables section.
|
|
65
46
|
|
|
66
47
|
3. **Interview discipline.** Per the `spec-author` contract:
|
|
67
48
|
- Title — short noun phrase. One field, one confirmation.
|
|
@@ -70,12 +51,13 @@ Before any work:
|
|
|
70
51
|
- Decision — one paragraph, stated as an active sentence.
|
|
71
52
|
- Consequences — 2–4 paragraphs, exercised via the challenge prompt: "Name two consequences that look bad. If you can't, what alternative would have made them visible?"
|
|
72
53
|
- Alternatives Considered — one paragraph per alternative.
|
|
54
|
+
- Forecloses / Enables — one line each against the roadmap's Next/Later horizons: what does this decision make more expensive, what does it make cheaper? "None" is a valid, confirmable answer. When `roadmap.md` is missing, not `current`, or `updated` > 90 days, write `n/a — roadmap stale/missing` — advisory only, never a reason to halt or reject the ADR.
|
|
73
55
|
|
|
74
56
|
4. **Supersession reciprocity.** When `--supersedes` is set, `spec-author` writes `superseded-by: <new-adr-id>` on the prior ADR and `supersedes: <prior-adr-id>` on the new one. AD-02 enforces reciprocity.
|
|
75
57
|
|
|
76
58
|
**Kernel-fit reciprocity.** When `--from-kernel-fit` is set, `spec-author` writes `promoted-from-kernel-fit: [<finding-id>]` on the new ADR. The reciprocal write on the finding (`promoted-to: adr:<new-adr-id>` plus the status flip to `promoted`) is performed by `/hstack:kernel-fit-promote` after this Skill returns, in a separate commit (the recoverable two-commit carve-out documented in that Skill's Failure modes — analogous to the `/hstack:finalize` in-progress carve-out).
|
|
77
59
|
|
|
78
|
-
5. **Validate.** Run `
|
|
60
|
+
5. **Validate.** Run `node hstack/scripts/validate-spec.mjs <path>` — AD-01 (sequential id), AD-02 (reciprocal supersession), AD-03 (fixed section structure), AD-04 (`superseded` requires `superseded-by`).
|
|
79
61
|
|
|
80
62
|
6. **Status transition.** When every section is confirmed and the validator passes, `spec-author` advances `status` from `proposed` to `accepted`. The engineer can override to keep `proposed` if the decision is still under discussion.
|
|
81
63
|
|
|
@@ -112,12 +94,3 @@ Beyond the kernel's general stop conditions:
|
|
|
112
94
|
- **ADR id sequence has a gap (e.g., ADR-0001, ADR-0003 with no ADR-0002).** AD-01 fails on the existing set, not the new write. Surface as a pre-existing problem and halt; the engineer reconciles before authoring a new ADR.
|
|
113
95
|
- **Validator fails AD-03 because the section structure deviates.** The subagent re-runs the missing section.
|
|
114
96
|
- **Engineer wants to keep the ADR at `proposed` and circulate.** Honor — `spec-author` writes the file at `proposed` and the auto-commit fires. Advancing to `accepted` later is a separate edit.
|
|
115
|
-
|
|
116
|
-
## Anti-patterns
|
|
117
|
-
|
|
118
|
-
- Never invent or reuse an ADR id. Sequential and immutable per AD-01.
|
|
119
|
-
- Never skip the Consequences challenge prompt. Under-stated trade-offs are the predictable ADR failure mode.
|
|
120
|
-
- Never write `status: accepted` without the engineer's confirmation.
|
|
121
|
-
- Never write supersession in one direction only. Reciprocity per AD-02 is mandatory.
|
|
122
|
-
- Never paraphrase research findings into the Context section without the engineer's review. The promotion path runs through `spec-author`'s confirmation gates.
|
|
123
|
-
- Never modify an `accepted` ADR's body. ADRs are append-only; updates happen by superseding with a new ADR.
|
|
@@ -1,34 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hstack-adversarial-review
|
|
3
|
-
description:
|
|
4
|
-
Use this skill only in a fresh Claude Code session — separate from the session that ran the implementer — after verification has landed at `status: passed` and the change is at `ready-for-review`. The Skill orchestrates the `adversarial-reviewer` subagent to produce a quota-driven critique. v1 fresh-session enforcement is honor-system; the Skill emits a clear instruction reminding the engineer that the v2 substrate will verify via session-id comparison. Examples:
|
|
5
|
-
|
|
6
|
-
<example>
|
|
7
|
-
Context: The implementer finished the last phase of a billing change; verification passed; the engineer has opened a fresh session for adversarial review.
|
|
8
|
-
user: "I've opened a new session. /hstack:adversarial-review 2026-05-billing-overage-warning"
|
|
9
|
-
assistant: "I'll invoke adversarial-reviewer. Findings floor is 5 because area=billing. I'll load every change artifact and the full diff; no implementer transcripts. Minimum 5 findings or a defended sub-floor justification — 'no issues found' is not a terminal state."
|
|
10
|
-
<commentary>
|
|
11
|
-
AR-06 raises the findings floor to 5 for changes in {agent, auth, billing}. The reviewer must spread findings across categories — clustering all findings in one category is a smell unless flagged in Methodology.
|
|
12
|
-
</commentary>
|
|
13
|
-
</example>
|
|
14
|
-
|
|
15
|
-
<example>
|
|
16
|
-
Context: A small copy-fix change has been verified and the reviewer can only honestly produce two findings.
|
|
17
|
-
user: "/hstack:adversarial-review 2026-05-billing-copy-tweak"
|
|
18
|
-
assistant: "I'll invoke adversarial-reviewer. If I can only honestly produce two findings, I'll set findings-fewer-than-floor: true and write a defended justification in section 4 — enumerate every category considered and explain why each produced no honest finding."
|
|
19
|
-
<commentary>
|
|
20
|
-
The sub-floor path is explicit and rare. AR-01 demands `findings` length ≥ `findings-floor` OR `findings-fewer-than-floor: true` plus non-empty `justification-when-fewer`. "The change is small" alone is insufficient.
|
|
21
|
-
</commentary>
|
|
22
|
-
</example>
|
|
23
|
-
|
|
24
|
-
<example>
|
|
25
|
-
Context: The adversarial reviewer finds a high-severity tenant-isolation issue the security review missed.
|
|
26
|
-
user: "/hstack:adversarial-review 2026-06-retrieval-rpc-rewrite"
|
|
27
|
-
assistant: "I'll invoke adversarial-reviewer with the new pgvector RPC under scrutiny. If a severity:high tenant-isolation finding lands, the resolution must be commit:<hash> or tech-debt:<id> — not justified-in-prose. High-severity security routed to justified-in-prose is a smell and I'll halt."
|
|
28
|
-
<commentary>
|
|
29
|
-
Resolution discipline matters: `commit:<hash>` for code fixes, `tech-debt:<id>` for deliberate deferral, `justified-in-prose` only for low-severity findings where in-prose reasoning is genuinely right. High-severity security via justified-in-prose is a halt condition.
|
|
30
|
-
</commentary>
|
|
31
|
-
</example>
|
|
3
|
+
description: Use only in a fresh Claude Code session — separate from the one that ran the implementer — once `verification.md` is at `passed` and the change is at `ready-for-review`. Orchestrates the `adversarial-reviewer`, which reads the change cold.
|
|
32
4
|
tools:
|
|
33
5
|
- Read
|
|
34
6
|
- Write
|
|
@@ -37,13 +9,15 @@ tools:
|
|
|
37
9
|
- Glob
|
|
38
10
|
- Bash
|
|
39
11
|
- Task
|
|
40
|
-
- "
|
|
12
|
+
- "node hstack/scripts/validate-spec.mjs — validates adversarial-review frontmatter and AR-01..AR-06"
|
|
41
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}}"
|
|
42
14
|
---
|
|
43
15
|
|
|
44
16
|
## Purpose
|
|
45
17
|
|
|
46
|
-
`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
|
|
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.
|
|
19
|
+
|
|
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).
|
|
47
21
|
|
|
48
22
|
## When to invoke
|
|
49
23
|
|
|
@@ -66,17 +40,19 @@ Before any work:
|
|
|
66
40
|
- data-review at `passed` or `concerns-acknowledged` when applicable
|
|
67
41
|
- ui-brief at `drafted` and figma-handoff at `ready` when applicable
|
|
68
42
|
- verification at `passed`
|
|
69
|
-
-
|
|
43
|
+
- Set `findings-floor`: 3 default; 5 when `change-spec.area` is in {agent, auth, billing} per AR-06. It is recorded, not enforced.
|
|
70
44
|
|
|
71
45
|
## Orchestration steps
|
|
72
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
|
+
|
|
73
49
|
1. **Open with the fresh-session reminder.** Print the message verbatim; wait for the engineer's confirmation.
|
|
74
50
|
|
|
75
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.
|
|
76
52
|
|
|
77
|
-
3. **Findings generation across six categories.** The subagent
|
|
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.
|
|
78
54
|
|
|
79
|
-
4. **
|
|
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.
|
|
80
56
|
|
|
81
57
|
5. **Resolution discipline.** Each finding's `resolution` is one of:
|
|
82
58
|
- `commit:<hash>` — must reference an existing commit on the change's branch (AR-04).
|
|
@@ -89,9 +65,9 @@ Before any work:
|
|
|
89
65
|
|
|
90
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.
|
|
91
67
|
|
|
92
|
-
9. **Validate.** Run `
|
|
68
|
+
9. **Validate.** Run `node hstack/scripts/validate-spec.mjs <path>` — AR-01 through AR-06.
|
|
93
69
|
|
|
94
|
-
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 `
|
|
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.
|
|
95
71
|
|
|
96
72
|
## Outputs
|
|
97
73
|
|
|
@@ -115,9 +91,12 @@ At the change-spec advance commit (only when adversarial-review status is `findi
|
|
|
115
91
|
|
|
116
92
|
```json
|
|
117
93
|
{
|
|
118
|
-
"schema_version":
|
|
94
|
+
"schema_version": 2,
|
|
119
95
|
"skill": "hstack-adversarial-review",
|
|
120
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>",
|
|
121
100
|
"reviewed_at": "<ISO-8601, when status reached findings-resolved>",
|
|
122
101
|
"findings_floor": <int, 3 or 5 per AR-06>,
|
|
123
102
|
"findings_count": <int, length of frontmatter findings array>,
|
|
@@ -146,7 +125,19 @@ At the change-spec advance commit (only when adversarial-review status is `findi
|
|
|
146
125
|
}
|
|
147
126
|
```
|
|
148
127
|
|
|
149
|
-
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.
|
|
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>`.
|
|
150
141
|
|
|
151
142
|
## Idempotency contract
|
|
152
143
|
|
|
@@ -163,25 +154,13 @@ Beyond the kernel's general stop conditions:
|
|
|
163
154
|
- A high-severity security or tenant-isolation finding would route to `justified-in-prose`. Halt.
|
|
164
155
|
- A `commit:<hash>` resolution would reference a commit not on the change's branch.
|
|
165
156
|
- A `tech-debt:<id>` resolution would reference a non-existent tech-debt artifact (the engineer must invoke `hstack-tech-debt-new` first).
|
|
166
|
-
- The
|
|
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.
|
|
167
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.
|
|
168
159
|
- An implementer transcript or scratchpad is visible in the session.
|
|
169
160
|
|
|
170
161
|
## Failure modes
|
|
171
162
|
|
|
172
163
|
- **Engineer claims fresh session but conversation shows prior implementer transcripts.** Halt; ask the engineer to truly start a new session.
|
|
173
|
-
- **
|
|
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.
|
|
174
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.
|
|
175
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.
|
|
176
|
-
|
|
177
|
-
## Anti-patterns
|
|
178
|
-
|
|
179
|
-
- Never return "no issues found" without a defended sub-floor justification.
|
|
180
|
-
- Never run in the same Claude Code session as `hstack-implement`. Honor-system in v1; CI-verified in v2.
|
|
181
|
-
- Never cluster all findings in one category without flagging in Methodology.
|
|
182
|
-
- Never use `justified-in-prose` for a high-severity finding.
|
|
183
|
-
- Never propose code changes directly — the reviewer surfaces findings; the owner or implementer (via `hstack-implement`) resolves them.
|
|
184
|
-
- Never invent a tech-debt id. The artifact must exist or be authored before the review terminates.
|
|
185
|
-
- Never accept a `commit:<hash>` that does not exist on the change's branch.
|
|
186
|
-
- Never advance status to `findings-resolved` while any finding has `status: open`.
|
|
187
|
-
- Never load implementer transcripts. If visible, halt.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# The six finding categories — a calibration rubric
|
|
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.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## security
|
|
16
|
+
|
|
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.
|
|
20
|
+
|
|
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`.
|
|
27
|
+
|
|
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.
|
|
31
|
+
|
|
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.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## scope-drift
|
|
39
|
+
|
|
40
|
+
**What it means.** The diff touches things `change-spec.in-scope` does not
|
|
41
|
+
name, or the change quietly grew a second purpose.
|
|
42
|
+
|
|
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.
|
|
47
|
+
|
|
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.
|
|
51
|
+
|
|
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.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## invariant-breach
|
|
59
|
+
|
|
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.
|
|
62
|
+
|
|
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.
|
|
68
|
+
|
|
69
|
+
**Filler looks like.** Paraphrasing an invariant back and calling it a risk.
|
|
70
|
+
Naming an invariant the diff does not touch.
|
|
71
|
+
|
|
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.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## spec-compliance
|
|
79
|
+
|
|
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.
|
|
82
|
+
|
|
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).
|
|
94
|
+
|
|
95
|
+
**Filler looks like.** "The spec could have been clearer." Style disagreements
|
|
96
|
+
with the plan's phase decomposition.
|
|
97
|
+
|
|
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.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## data-integrity
|
|
105
|
+
|
|
106
|
+
**What it means.** Data can end up wrong, lost, or visible to the wrong tenant
|
|
107
|
+
without anybody attacking anything.
|
|
108
|
+
|
|
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.
|
|
115
|
+
|
|
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.
|
|
118
|
+
|
|
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`.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## code-quality
|
|
126
|
+
|
|
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.
|
|
130
|
+
|
|
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.
|
|
136
|
+
|
|
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.
|
|
140
|
+
|
|
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`.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Resolution routing
|
|
148
|
+
|
|
149
|
+
Independent of category:
|
|
150
|
+
|
|
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.
|