hstack 0.16.0 → 0.17.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 +37 -0
- package/README.md +73 -163
- package/VERSION +1 -1
- package/dist/commands/doctor.js +18 -8
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +7 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.js +9 -2
- package/dist/commands/update.js.map +1 -1
- package/dist/lib/descriptions.js +10 -17
- package/dist/lib/descriptions.js.map +1 -1
- package/dist/lib/wire.js +166 -138
- package/dist/lib/wire.js.map +1 -1
- package/dist/manifest.js +41 -29
- package/dist/manifest.js.map +1 -1
- package/package.json +3 -4
- package/template/.claude/agents/adversarial-reviewer.md +42 -50
- package/template/.claude/agents/app-architect.md +44 -96
- package/template/.claude/agents/data-architect.md +46 -89
- package/template/.claude/agents/test-strategist.md +39 -68
- package/template/.claude/skills/hstack-adr-new/SKILL.md +23 -73
- package/template/.claude/skills/hstack-adversarial-review/SKILL.md +46 -152
- package/template/.claude/skills/hstack-adversarial-review/references/finding-categories.md +80 -103
- package/template/.claude/skills/hstack-app-architecture/SKILL.md +43 -68
- package/template/.claude/skills/hstack-commit/SKILL.md +27 -68
- package/template/.claude/skills/hstack-data-architecture/SKILL.md +34 -56
- package/template/.claude/skills/hstack-promote/SKILL.md +55 -0
- package/template/.claude/skills/hstack-story/SKILL.md +58 -0
- package/template/.claude/skills/hstack-test-audit/SKILL.md +64 -0
- package/template/.claude/skills/hstack-wrap/SKILL.md +48 -0
- package/template/.claude/skills/hstack-wrap/references/pr-description.md +45 -0
- package/template/KERNEL.md +75 -318
- package/template/templates/adr.md +2 -18
- package/template/templates/app-architecture.md +38 -50
- package/template/templates/data-architecture.md +38 -89
- package/template/templates/infrastructure.md +54 -148
- package/template/templates/roadmap.md +6 -12
- package/template/templates/story.md +7 -13
- package/template/templates/tech-debt.md +2 -37
- package/template/templates/tech-stack.md +2 -12
- package/template/.claude/agents/data-specialist.md +0 -81
- package/template/.claude/agents/implementer.md +0 -97
- package/template/.claude/agents/kernel-fit-analyst.md +0 -129
- package/template/.claude/agents/planner.md +0 -75
- package/template/.claude/agents/product-discovery.md +0 -129
- package/template/.claude/agents/product-manager.md +0 -76
- package/template/.claude/agents/researcher.md +0 -87
- package/template/.claude/agents/security-reviewer.md +0 -88
- package/template/.claude/agents/spec-author.md +0 -89
- package/template/.claude/agents/stack-architect.md +0 -108
- package/template/.claude/agents/ui-ux-briefer.md +0 -75
- package/template/.claude/agents/verifier.md +0 -81
- package/template/.claude/skills/hstack-branch/SKILL.md +0 -76
- package/template/.claude/skills/hstack-brownfield-init/SKILL.md +0 -131
- package/template/.claude/skills/hstack-change-new/SKILL.md +0 -84
- package/template/.claude/skills/hstack-change-plan/SKILL.md +0 -108
- package/template/.claude/skills/hstack-configure/SKILL.md +0 -99
- package/template/.claude/skills/hstack-coord/SKILL.md +0 -95
- package/template/.claude/skills/hstack-data-review/SKILL.md +0 -93
- package/template/.claude/skills/hstack-finalize/SKILL.md +0 -140
- package/template/.claude/skills/hstack-flag/SKILL.md +0 -99
- package/template/.claude/skills/hstack-greenfield-init/SKILL.md +0 -148
- package/template/.claude/skills/hstack-help/SKILL.md +0 -153
- package/template/.claude/skills/hstack-implement/SKILL.md +0 -155
- package/template/.claude/skills/hstack-kernel-fit-promote/SKILL.md +0 -125
- package/template/.claude/skills/hstack-kernel-fit-scan/SKILL.md +0 -142
- package/template/.claude/skills/hstack-kernel-fit-scan/references/slack-setup.md +0 -42
- package/template/.claude/skills/hstack-kernel-fit-triage/SKILL.md +0 -121
- package/template/.claude/skills/hstack-module-spec/SKILL.md +0 -78
- package/template/.claude/skills/hstack-product-discovery/SKILL.md +0 -75
- package/template/.claude/skills/hstack-research/SKILL.md +0 -115
- package/template/.claude/skills/hstack-scaffold/SKILL.md +0 -113
- package/template/.claude/skills/hstack-security-review/SKILL.md +0 -95
- package/template/.claude/skills/hstack-ship/SKILL.md +0 -119
- package/template/.claude/skills/hstack-stack-decide/SKILL.md +0 -81
- package/template/.claude/skills/hstack-story-draft/SKILL.md +0 -92
- package/template/.claude/skills/hstack-tech-debt-new/SKILL.md +0 -95
- package/template/.claude/skills/hstack-tech-debt-resolve/SKILL.md +0 -123
- package/template/.claude/skills/hstack-tech-debt-stale/SKILL.md +0 -86
- package/template/.claude/skills/hstack-tech-debt-wontfix/SKILL.md +0 -77
- package/template/.claude/skills/hstack-telemetry/SKILL.md +0 -73
- package/template/.claude/skills/hstack-test-plan/SKILL.md +0 -159
- package/template/.claude/skills/hstack-ui-brief/SKILL.md +0 -81
- package/template/.claude/skills/hstack-verify/SKILL.md +0 -128
- package/template/scripts/compute-merge-readiness.mjs +0 -780
- package/template/scripts/coord/coord_scan.py +0 -681
- package/template/scripts/run-gates.sh +0 -388
- package/template/scripts/telemetry/__init__.py +0 -6
- package/template/scripts/telemetry/insights/__init__.py +0 -0
- package/template/scripts/telemetry/insights/contract_drift.py +0 -137
- package/template/scripts/telemetry/insights/kernel_fit.py +0 -438
- package/template/scripts/telemetry/insights/overengineering.py +0 -115
- package/template/scripts/telemetry/insights/quality_outcomes.py +0 -131
- package/template/scripts/telemetry/insights/token_economics.py +0 -302
- package/template/scripts/telemetry/insights/workflow_shape.py +0 -198
- package/template/scripts/telemetry/parsers/__init__.py +0 -0
- package/template/scripts/telemetry/parsers/bodies.py +0 -87
- package/template/scripts/telemetry/parsers/commits.py +0 -219
- package/template/scripts/telemetry/parsers/frontmatter.py +0 -322
- package/template/scripts/telemetry/parsers/sidecars.py +0 -61
- package/template/scripts/telemetry/parsers/transcripts.py +0 -294
- package/template/scripts/telemetry/render.py +0 -460
- package/template/scripts/telemetry/report.py +0 -150
- package/template/scripts/telemetry/run_kernel_fit.py +0 -95
- package/template/scripts/telemetry/session_id.py +0 -139
- package/template/scripts/validate-spec.mjs +0 -3303
- package/template/templates/adversarial-review.md +0 -54
- package/template/templates/bootstrap.md +0 -105
- package/template/templates/change-spec.md +0 -82
- package/template/templates/ci-cd.md +0 -41
- package/template/templates/coord-message.md +0 -56
- package/template/templates/data-review.md +0 -54
- package/template/templates/discovery/brainstorm.md +0 -69
- package/template/templates/discovery/forcing-questions.md +0 -76
- package/template/templates/discovery/project-brief.md +0 -53
- package/template/templates/figma-handoff.md +0 -38
- package/template/templates/glossary.md +0 -20
- package/template/templates/hardening-checklist.md +0 -73
- package/template/templates/incident-runbook.md +0 -57
- package/template/templates/kernel-fit-finding.md +0 -63
- package/template/templates/kernel-fit-flag.md +0 -52
- package/template/templates/module-spec.md +0 -49
- package/template/templates/persona.md +0 -38
- package/template/templates/plan.md +0 -53
- package/template/templates/product-brief.md +0 -56
- package/template/templates/security-review.md +0 -63
- package/template/templates/telemetry-sidecar.md +0 -227
- package/template/templates/test-plan.md +0 -119
- package/template/templates/threat-model.md +0 -54
- package/template/templates/ui-brief.md +0 -49
- package/template/templates/verification.md +0 -63
- package/template/templates/vision.md +0 -34
|
@@ -1,166 +1,60 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hstack-adversarial-review
|
|
3
|
-
description: Use
|
|
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 change — to 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
|
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
|
-
-
|
|
164
|
-
-
|
|
165
|
-
-
|
|
166
|
-
|
|
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,134 @@
|
|
|
1
1
|
# The six finding categories — a calibration rubric
|
|
2
2
|
|
|
3
|
-
Reference file for `hstack-adversarial-review` and the `adversarial-reviewer`
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
30
|
-
|
|
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
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
41
|
-
|
|
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
|
|
44
|
-
|
|
45
|
-
|
|
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
|
|
49
|
-
|
|
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
|
|
53
|
-
|
|
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
|
|
61
|
-
|
|
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.**
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
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
|
|
73
|
-
|
|
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
|
-
##
|
|
67
|
+
## intent-compliance
|
|
79
68
|
|
|
80
|
-
**What it means.** The diff and the
|
|
81
|
-
|
|
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.**
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
96
|
-
|
|
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
|
-
|
|
100
|
-
|
|
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
|
-
|
|
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
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 weakest
|
|
111
|
+
category and the easiest to pad, which is why it is worth being strict about what belongs here.
|
|
130
112
|
|
|
131
|
-
**Real findings look like.** A third copy of logic that already exists twice,
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
nothing that documents or enforces it. A performance budget in the test-plan
|
|
135
|
-
that the implementation cannot meet as written.
|
|
113
|
+
**Real findings look like.** A third copy of logic that already exists twice, where the copies have
|
|
114
|
+
started to disagree. Error handling that swallows a failure the caller needs. A function whose
|
|
115
|
+
behaviour depends on call order with nothing that documents or enforces it.
|
|
136
116
|
|
|
137
|
-
**Filler looks like.** Naming preferences. Suggested comments. Requests to
|
|
138
|
-
|
|
139
|
-
have said, since `run-gates.sh` already ran.
|
|
117
|
+
**Filler looks like.** Naming preferences. Suggested comments. Requests to extract a function used
|
|
118
|
+
once. Anything a formatter or a linter would have said.
|
|
140
119
|
|
|
141
|
-
**Severity.** `low` or `medium`. A `code-quality` finding at `high` is usually
|
|
142
|
-
|
|
143
|
-
`data-integrity`.
|
|
120
|
+
**Severity.** `low` or `medium`. A `code-quality` finding at `high` is usually mis-categorized —
|
|
121
|
+
look again at whether it is really `invariant-breach` or `data-integrity`.
|
|
144
122
|
|
|
145
123
|
---
|
|
146
124
|
|
|
147
|
-
## Resolution
|
|
125
|
+
## Resolution
|
|
148
126
|
|
|
149
|
-
Independent of category:
|
|
127
|
+
Independent of category, a finding names what would resolve it:
|
|
150
128
|
|
|
151
|
-
-
|
|
152
|
-
-
|
|
153
|
-
|
|
154
|
-
-
|
|
155
|
-
why nothing changes.
|
|
156
|
-
|
|
157
|
-
is a halt with escalation.
|
|
129
|
+
- **A corrective commit on the branch** — the author fixes it before the merge.
|
|
130
|
+
- **A tech-debt file in the same PR** — the finding is real and is being lived with, on the record
|
|
131
|
+
and grep-able by `related-modules` (kernel § Tech-debt).
|
|
132
|
+
- **An argument in the comment thread** — the finding is real and the right answer is to explain
|
|
133
|
+
why nothing changes. Fine for a `low`; a `high` answered this way stays open, and a security or
|
|
134
|
+
tenant-isolation finding answered this way is escalated, not closed.
|
|
@@ -1,82 +1,57 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hstack-app-architecture
|
|
3
|
-
description: Use
|
|
4
|
-
tools:
|
|
5
|
-
- Read
|
|
6
|
-
- Write
|
|
7
|
-
- Edit
|
|
8
|
-
- Grep
|
|
9
|
-
- Glob
|
|
10
|
-
- Bash
|
|
11
|
-
- Task
|
|
12
|
-
- "node hstack/scripts/validate-spec.mjs — frontmatter validator"
|
|
3
|
+
description: "Use when the application architecture really moves — modules, LLM call sites, state ownership, surfaces, or what a user can reach — to write or refresh `hstack/context/app-architecture.md`, exposure map included."
|
|
13
4
|
---
|
|
14
5
|
|
|
15
6
|
## Purpose
|
|
16
7
|
|
|
17
|
-
|
|
8
|
+
`/hstack-app-architecture` writes or refreshes `hstack/context/app-architecture.md`: the module map
|
|
9
|
+
with its exposure column, the agent orchestration model, the deterministic-vs-LLM split, the
|
|
10
|
+
state-ownership map, the surface boundaries. It is what the next session reads to know what exists
|
|
11
|
+
and what a user can reach.
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- Standalone via `/hstack:app-architecture [--mode extract|elicit] [--section <name>]` for refresh or single-section edits.
|
|
24
|
-
- Routed-into-from-downstream when `/hstack:stack-decide` finds a stack constraint that contradicts the architecture (rare).
|
|
13
|
+
It is not how the doc stays current day to day — a change that adds a route updates the map in its
|
|
14
|
+
own PR, which is the kernel's rule and costs nothing. This Skill is for the moves that rule cannot
|
|
15
|
+
absorb: the first write, a module boundary that no longer matches the code, an exposure map that
|
|
16
|
+
has drifted away from the real routes.
|
|
25
17
|
|
|
26
18
|
## Inputs
|
|
27
19
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
##
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- `hstack/config.yaml` with updated `surfaces` enum.
|
|
56
|
-
- `hstack/.session-state/<session-id>.yaml` (transient).
|
|
57
|
-
|
|
58
|
-
## Auto-commit triggers
|
|
59
|
-
|
|
60
|
-
- Each confirmed section writes immediately and auto-commits.
|
|
61
|
-
- Per-flow row in Section 3 commits individually (not full-section batch).
|
|
62
|
-
- Terminal-state side effects (artifact + stubs + config) land in one atomic commit.
|
|
63
|
-
|
|
64
|
-
## Idempotency contract
|
|
65
|
-
|
|
66
|
-
- Artifact at `current` + no `--section` + no `--force`: print summary, exit no-op.
|
|
67
|
-
- Artifact at `draft` or partial: resume at next non-confirmed section.
|
|
68
|
-
- Artifact at `needs-refresh`: walk all sections in confirm-or-revise mode.
|
|
69
|
-
- Module-spec stubs at `status: draft`: the atom does NOT overwrite stubs on re-run; if Section 1 added a module on refresh, the new stub lands additively; if Section 1 removed a module, the orphan stub is flagged for engineer review (the engineer either deletes it or routes the deletion through `/hstack:tech-debt-stale`).
|
|
20
|
+
`--section modules | orchestration | split | state | surfaces`, optional — refreshes one section.
|
|
21
|
+
|
|
22
|
+
## Steps
|
|
23
|
+
|
|
24
|
+
1. **Extract or elicit.** Extract when a source tree exists; elicit when the repo is empty.
|
|
25
|
+
2. **Invoke `app-architect`** with the material. It reads the tree, drafts each section and
|
|
26
|
+
challenges it. The questions and the confirmations happen here, in this session — a subagent
|
|
27
|
+
cannot interview.
|
|
28
|
+
3. **Fill the exposure column in extract mode.** Entry points are enumerable: `app/**/page.tsx` and
|
|
29
|
+
`app/**/route.ts` for the App Router, files carrying `'use server'` for server actions, plus the
|
|
30
|
+
job and webhook registrations. Enumerate them, attach each to the module it serves, and ask the
|
|
31
|
+
engineer for a status per entry point — `live`, `routable` or `off`, as the kernel defines them.
|
|
32
|
+
A module reached only through another module's entry point names that one instead; a module no
|
|
33
|
+
live entry point reaches is `dormant`, which is derived and never a fourth status.
|
|
34
|
+
4. **One line the map carries, not this Skill's to restate:** it grades the **product** severity of
|
|
35
|
+
a finding, never its security severity. Every routable entry point is covered by the kernel's
|
|
36
|
+
security checklist whatever the map says.
|
|
37
|
+
5. **Each section ends with its drift challenge**, and the answer stays in the doc as evidence the
|
|
38
|
+
probe ran. A challenge that surfaces a real contradiction stops the section: the engineer
|
|
39
|
+
revises it, files an ADR, or writes a tech-debt file.
|
|
40
|
+
6. **A section-targeted refresh re-reads the other four challenges** before the PR — a module
|
|
41
|
+
renamed in Section 1 and left standing in Section 4 is the failure this catches.
|
|
42
|
+
|
|
43
|
+
## Output
|
|
44
|
+
|
|
45
|
+
`hstack/context/app-architecture.md`, updated in the PR that changes it. Nothing else: no module
|
|
46
|
+
spec stubs, no config file, no status.
|
|
70
47
|
|
|
71
48
|
## Stop conditions
|
|
72
49
|
|
|
73
|
-
|
|
74
|
-
- A module in Section 1 has no trace to brief or data-architecture entities.
|
|
75
|
-
- A Section 3 flow step has no declared mechanism or no measurable-property rationale.
|
|
76
|
-
- A drift challenge surfaces an unresolved contradiction.
|
|
77
|
-
- Extract mode invoked but no source tree reachable.
|
|
78
|
-
|
|
79
|
-
## Failure modes
|
|
50
|
+
Beyond the kernel's:
|
|
80
51
|
|
|
81
|
-
-
|
|
82
|
-
-
|
|
52
|
+
- Extract mode was asked for and no source tree is reachable.
|
|
53
|
+
- An entry point's status is a guess. Ask; a wrong `off` is how a live surface stops being reviewed.
|
|
54
|
+
- A step of a flow has no declared mechanism, or a rationale that names no property anyone could
|
|
55
|
+
disagree with.
|
|
56
|
+
- A drift challenge surfaces a contradiction with `data-architecture.md` — typically a state class
|
|
57
|
+
with nowhere to live. Surface it; the engineer decides whether the data doc moves.
|