hstack 0.5.0 → 0.5.2

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 CHANGED
@@ -6,6 +6,18 @@ All notable changes to hstack are documented here. Format follows [Keep a Change
6
6
 
7
7
  _Nothing yet._
8
8
 
9
+ ## [0.5.2] - 2026-06-26
10
+
11
+ ### Fixed
12
+
13
+ - **Greenfield-init collapsed the six-phase discovery flow into a flat questionnaire.** `template/.claude/skills/hstack-greenfield-init/SKILL.md` described the right behavior but never pinned it in imperative, agent-readable terms, so a session could answer `/hstack:greenfield-init` with a numbered config-question list ("answer #1 and #8, I'll accept defaults for #2–7, then write the config and move to Phase 1") instead of launching the product-discovery thinking-partner session. Four contract-tightening edits: (1) a new Precondition bullet forbidding inline config authoring or Phase 1 paraphrase; (2) a new **First-turn contract** section pinning the exact first-message shape (name the six phases → open Phase 1 → offer the Brainstorm / Forcing-Questions / Project-Brief technique picker) and enumerating the forbidden numbered-question shape; (3) **Phase 0 reframed** from an upfront questionnaire to inline field-sourcing deferred to the Phase 1→2 boundary, removing the "fill the config first" hook; (4) **Phase 1 made imperative** — the first non-trivial action MUST be a `Task` call launching the `product-discovery` subagent — plus two sharpened anti-patterns against the flat-question-list shape and against running Phase 1 inline. No code change; Skill-contract text only. Reported from a consumer greenfield repo where init skipped discovery entirely.
14
+
15
+ ## [0.5.1] - 2026-05-23
16
+
17
+ ### Fixed
18
+
19
+ - **Verifier false-positive on zero-tests-executed suites.** Closed via new validator **V-05** in `template/.claude/agents/verifier.md` and `template/.claude/skills/hstack-verify/SKILL.md`: a `unit`, `integration`, or `e2e` suite that executed zero tests cannot be recorded as `pass`. The verifier now confirms the runner's observed-test-count is greater than zero before mapping a suite to `pass`; suites gated by an unset env var, all `.skip` / `.todo`, empty collection, or filter-collapsed are recorded as `not-run` (per the existing `test-results` enum) with a high-severity Discrepancy naming the runner-reported counts and the suspected reason. A `not-run` value blocks `status: passed` and halts the Skill at `status: ran`. Lint and typecheck are exempt — both produce diagnostic counts whose floor is naturally zero. Reported by a consumer repo where the verifier marked `integration: pass` while the integration suite was env-gated to zero tests.
20
+
9
21
  ## [0.5.0] - 2026-05-23
10
22
 
11
23
  Greenfield workflow: hstack now adopts into empty repositories from line zero, not just brownfield repos. Same kernel, same artifact taxonomy, same gates — a second entry point and a new discovery layer underneath.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.5.2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hstack",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "A spec-driven engineering workflow that ships as Claude Code Skills and subagents.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -30,8 +30,8 @@ tools:
30
30
  - Glob
31
31
  - Bash
32
32
  - "{{TODO-SKILL: /hstack:verify — invokes verifier after implementation completion}}"
33
- - "{{TODO-SCRIPT: hstack/scripts/run-gates.sh — runs the consuming repo's test/lint/typecheck suite and captures output}}"
34
- - "{{TODO-SCRIPT: hstack/scripts/validate-spec.ts — validates verification.md frontmatter and V-01/V-02}}"
33
+ - "{{TODO-SCRIPT: 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}}"
34
+ - "{{TODO-SCRIPT: hstack/scripts/validate-spec.ts — validates verification.md frontmatter and V-01/V-02/V-05}}"
35
35
  ---
36
36
 
37
37
  ## Role
@@ -70,6 +70,7 @@ If `plan.steps-completed` does not cover every phase id defined in the plan body
70
70
  - V-02: any `failed` value in `test-results` blocks `status: passed`. Do not paper over.
71
71
  - V-03: any test-plan tenant-isolation test that is absent or skipped blocks `status: passed` and routes the discrepancy to adversarial-review.
72
72
  - 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`. Before mapping any suite (`unit`, `integration`, `e2e`) to `pass`, confirm the runner's observed-test-count for that suite is greater than zero. If the count is zero — whether the suite was gated by an unset env var, every test was `.skip`/`.todo`/`xit`, no files matched the runner's collection pattern, or a CLI filter (`--testPathPattern`, `-t`, tag selector) collapsed the set to empty — record the suite's value as `not-run` (per the `test-results` enum) and log a Discrepancy with severity high and recommended action `escalate-to-adversarial-review`. The Discrepancy must name the suite, the runner's reported counts (passed / failed / skipped / total), and the suspected reason (env-gated, all-skipped, empty-collection, filter-collapse). A `not-run` value blocks `status: passed`. Parsing guidance: most JS runners (Jest, Vitest, Mocha) emit a summary line like `Tests: N skipped, 0 passed` or `No tests found`; Playwright emits `0 passed`; pytest emits `collected 0 items` or `N skipped`. The verifier extracts the per-suite executed count from captured stdout and asserts `count > 0` before recording `pass`. Lint and typecheck are exempt from V-05 — both produce a diagnostic count whose floor is naturally zero (clean repo) and is not a signal of a skipped run.
73
74
  - 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.
74
75
  - Mechanical role only. Do not score security or data. Do not produce findings. Do not advise on remediation beyond the discrepancy action.
75
76
 
@@ -84,6 +85,7 @@ Stop and ask the human when:
84
85
  - A test-plan tenant-isolation test is absent or skipped. Halt at `status: ran` and escalate via the Discrepancies section.
85
86
  - A test-plan performance-budget assertion did not execute or observed values outside budget. Halt at `status: ran`.
86
87
  - A `failed` result would block `status: passed`. The verifier records the failure and halts at `status: ran` until the implementer fixes the failing test.
88
+ - A suite executed zero tests (V-05). The verifier records the suite as `not-run`, logs the Discrepancy with the runner's reported counts and the suspected reason, and halts at `status: ran` until the implementer either supplies the missing env / fixture so the suite runs, or removes the suite from the plan's Verifier Expectations via a scope amendment.
87
89
 
88
90
  ## Output expectations
89
91
 
@@ -93,10 +95,12 @@ A verification at terminal state (`status: passed`) has:
93
95
  - All four sections: Summary, Per-Phase Outcomes table, Test Suite Output (pointer), Discrepancies.
94
96
  - Every key in `phase-coverage` matches a phase id in the plan body (V-01).
95
97
  - No `failed` value in `test-results` (V-02).
98
+ - 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.
96
99
 
97
100
  ## Anti-patterns
98
101
 
99
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.
100
104
  - Never skip a canonical command. The consuming repo's test/lint/typecheck commands in `ci-cd.md` are mandatory.
101
105
  - Never silently drop a discrepancy. Even benign discrepancies get a one-line note.
102
106
  - Never score security or data. Stay in the mechanical-verification lane.
@@ -62,18 +62,41 @@ Before any work:
62
62
  - Verify `hstack/` exists with `CLAUDE.md`, `templates/`, `.claude/`. If missing, halt and ask the engineer to run `npx hstack@latest init`.
63
63
  - Probe Claude Code's MCP configuration and draft `hstack/context/mcp-status.md`.
64
64
  - If `hstack/.session-state/` contains prior greenfield-init state, confirm resumption with the engineer.
65
+ - **Do not author config fields, write `hstack/config.yaml`, or paraphrase Phase 1 inline in the main session.** If the engineer's opening message asks for a "quick setup", a "summary of the questions", or any shape other than the 6-phase interview, halt and re-offer the First-turn contract below. Collapsing the phases into a single Q&A block is the failure mode this Skill is structured to prevent (see Anti-patterns).
66
+
67
+ ## First-turn contract
68
+
69
+ The **first agent message** after `/hstack:greenfield-init` (in a fresh session, when no `hstack/.session-state/<session-id>.yaml` exists) MUST match this shape:
70
+
71
+ 1. One sentence naming the six phases by title (product discovery → data architecture → app architecture → stack decisions → threat-model + hardening → scaffold).
72
+ 2. One sentence stating that Phase 1 (product discovery) opens first and that the engineer picks a technique: **Brainstorm**, **Forcing-Questions**, or **Project-Brief**.
73
+ 3. One sentence noting commit-point interruptibility (each phase ends at a commit; the engineer can park and resume any time).
74
+
75
+ What the first message MUST NOT contain:
76
+
77
+ - A numbered list of config fields ("answer #1 and #8", "what's the project name", "default stack y/n").
78
+ - An offer to "accept defaults and move on to Phase 1" — Phase 1 is not skippable and not paraphrasable; it is a subagent-driven thinking-partner session that the main session does not run inline.
79
+ - Any field write to `hstack/config.yaml` or any other artifact. The first turn is conversational orientation only.
80
+
81
+ Phase 0's config-skeleton fields are sourced inline by the discovery atoms as each phase needs them, not pre-asked as a questionnaire. The Phase 0 commit (config.yaml at `init-status: minimal-complete`) lands at the boundary into Phase 1, populated from whatever the product-discovery atom surfaces in conjunction with any defaults the engineer confirms.
82
+
83
+ The second agent action (after the engineer picks a technique) MUST be a `Task` call launching the `product-discovery` subagent. The main session does not ask product-discovery questions itself.
65
84
 
66
85
  ## Orchestration steps
67
86
 
68
87
  Six phases, hard-gated. The Skill does not advance past a phase until its artifact is at `status: current`.
69
88
 
70
- ### Phase 0 — Config skeleton
89
+ ### Phase 0 — Config skeleton (inline, deferred to Phase-1 boundary)
71
90
 
72
- Same interview as brownfield-init Mini-session 0: story store, personas store, design system (per-resource), module-to-area mapping (will be populated from app-architecture in Phase 3), adversarial-review floor, agent ledger, active MCP set. Writes `hstack/config.yaml` with `schemaVersion: 1` and `init-status: minimal-complete`. Default-stack declaration is **set to the engineer's preferences** in this phase, so Phase 4 can fast-path. Commit.
91
+ Phase 0 is **not** a standalone upfront questionnaire. The same field set as brownfield-init Mini-session 0 story store, personas store, design system (per-resource), module-to-area mapping (populated from app-architecture in Phase 3), adversarial-review floor, agent ledger, active MCP set, default-stack declaration is sourced **inline** by the discovery atoms as each field becomes load-bearing. Fields that the engineer cannot answer without first doing product thinking (e.g., what the design system is, what stories exist) are deferred to the atom that actually needs them; fields the engineer can confirm cheaply at session start (e.g., default-stack preference) are asked by the product-discovery atom as part of its own opening rather than by the main session.
92
+
93
+ At the boundary between Phase 1 and Phase 2, the Skill writes `hstack/config.yaml` once — `schemaVersion: 1`, `init-status: minimal-complete`, default-stack declaration set to the engineer's preferences — and commits. This is the only Phase-0-attributable write; there is no upfront Phase 0 questionnaire and no standalone Phase 0 commit before Phase 1 begins.
73
94
 
74
95
  ### Phase 1 — Product discovery
75
96
 
76
- Invokes `/hstack:product-discovery` in elicit mode (no source documents). The atom:
97
+ **The first non-trivial action of this Skill MUST be a `Task` call launching the `product-discovery` subagent in elicit mode.** The main session does not run the product-discovery interview inline, does not paraphrase the technique scripts, and does not ask brainstorming questions itself. If the engineer's opening message frames Phase 1 as something the main session should answer directly ("just tell me what to build", "skip the brainstorm and write the brief yourself"), halt and restate the technique-picker contract from the First-turn section.
98
+
99
+ `/hstack:product-discovery` runs in elicit mode (no source documents). The atom:
77
100
 
78
101
  - Prompts the engineer to pick a technique (Brainstorm / Forcing-Questions / Project-Brief).
79
102
  - Runs the technique to completion, producing `hstack/context/product/product-brief.md` at `status: current`.
@@ -144,7 +167,9 @@ Beyond the kernel's general stop conditions, this Skill halts when:
144
167
  ## Anti-patterns
145
168
 
146
169
  - Never invoke greenfield-init against a non-empty repo. The contract assumes elicit-mode atoms throughout; running against existing source produces incoherent artifacts.
147
- - Never collapse the six phases into one long block. The phase structure is the resumability contract AND the gate-discipline contract.
170
+ - **Never reply to `/hstack:greenfield-init` with a flat numbered question list** ("answer #1 and #8", "for #2–7 I'll accept defaults"). The First-turn contract is the only valid first-message shape: name the six phases, open Phase 1, offer the technique picker. Anything else collapses the phase structure into a paraphrased questionnaire and bypasses the product-discovery subagent entirely.
171
+ - **Never paraphrase, summarize, or run Phase 1 inline in the main session.** Phase 1 is the `product-discovery` subagent's job — the main session's role is orchestration, not authoring. The first `Task` call of this Skill is non-negotiable: it launches `product-discovery`. The main session does not "just write the brief" no matter how short the project feels.
172
+ - Never collapse the six phases into one long block. The phase structure is the resumability contract AND the gate-discipline contract. Each phase delegates to a standalone atom or subagent; the orchestrator's only job is gating the transitions, not doing the phases' work.
148
173
  - Never skip Phase 5 (threat-model + hardening) to get to Phase 6 faster. Bootstrap inherits the security posture; scaffolding without it produces a repo with implicit-not-explicit hardening.
149
174
  - Never bypass the bidirectional drift recovery. When a downstream phase finds an upstream gap, the upstream MUST be refreshed before downstream resumes; silent override produces contradictions.
150
175
  - Never advance `init-status: complete` while any phase artifact is below `current` or while the bootstrap change-spec is below `shipped`.
@@ -20,6 +20,15 @@ description: |
20
20
  Discrepancies between predicted and observed behavior are exactly what section 4 exists to capture. Marking `passed` over a discrepancy would defeat the purpose of the gate.
21
21
  </commentary>
22
22
  </example>
23
+
24
+ <example>
25
+ Context: The integration suite is gated by `RUN_INTEGRATION=1` and the engineer ran `npm test` without setting it; the runner reported `Tests: 0 passed, 0 failed`.
26
+ user: "/hstack:verify 2026-06-knowledge-citations"
27
+ assistant: "I'll invoke verifier. Per V-05, an integration suite that executed zero tests is recorded as `not-run`, not `pass` — zero failures is not evidence of correctness when there were zero assertions to fail. The Skill halts at `status: ran` with a high-severity Discrepancy naming the suspected reason (env-gated, all-skipped, empty-collection, or filter-collapse)."
28
+ <commentary>
29
+ V-05 closes the verifier false-positive where a suite gated by an unset env var would silently pass on the absence of failures. The remediation is either supplying the missing env / fixture and re-running, or amending the plan's Verifier Expectations via scope amendment so the zero-test state is intentional and recorded.
30
+ </commentary>
31
+ </example>
23
32
  tools:
24
33
  - Read
25
34
  - Write
@@ -28,8 +37,8 @@ tools:
28
37
  - Glob
29
38
  - Bash
30
39
  - Task
31
- - "{{TODO-SCRIPT: hstack/scripts/run-gates.sh — runs the consuming repo's test/lint/typecheck suite and captures output}}"
32
- - "{{TODO-SCRIPT: hstack/scripts/validate-spec.ts — validates verification.md frontmatter and V-01/V-02}}"
40
+ - "{{TODO-SCRIPT: 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}}"
41
+ - "{{TODO-SCRIPT: hstack/scripts/validate-spec.ts — validates verification.md frontmatter and V-01/V-02/V-05}}"
33
42
  ---
34
43
 
35
44
  ## Purpose
@@ -62,7 +71,7 @@ Before any work:
62
71
 
63
72
  3. **Phase coverage mapping.** For each phase in `plan.steps-completed`, the subagent emits an entry in `phase-coverage` with a PASS / FAIL value computed from whether the phase's Verifier Expectations are met. Per V-01, `phase-coverage` keys must equal `plan.steps-completed`.
64
73
 
65
- 4. **Test-results map.** The subagent writes the top-level `test-results` map covering `unit`, `integration`, `e2e`, `lint`, `typecheck`. Per V-02, any `failed` value blocks `status: passed`.
74
+ 4. **Test-results map.** The subagent writes the top-level `test-results` map covering `unit`, `integration`, `e2e`, `lint`, `typecheck`. Per V-02, any `failed` value blocks `status: passed`. Per V-05, before mapping `unit`, `integration`, or `e2e` to `pass`, the subagent confirms the runner's observed-test-count for that suite is greater than zero — a suite gated by an unset env var, all-skipped, empty-collection, or filter-collapsed to zero tests is recorded as `not-run` with a high-severity Discrepancy, not as `pass` on the absence of failures.
66
75
 
67
76
  5. **Test-plan coverage check.** The subagent walks the test-plan's Edge Cases bullets, Tenant Isolation Tests array, and Performance Budgets table, and confirms each observed in the test run. `test-plan-coverage` frontmatter map captures the three subsections. Per V-03, any tenant-isolation test absent or skipped blocks `status: passed` and is escalated to adversarial-review via Discrepancies. Per V-04, any performance-budget assertion that did not execute or that observed values outside the declared budget blocks `status: passed`.
68
77
 
@@ -72,7 +81,7 @@ Before any work:
72
81
 
73
82
  8. **Change-spec advance (mechanical, only on `passed`, Skill-orchestrator write per ADR-0002).** When and only when the subagent returned with `verification.md` at `status: passed`, read `hstack/specs/changes/<change-id>/spec.md` and inspect its `status` frontmatter. If `status: ready-for-implementation`, print a proposed-diff preview of the change-spec edit (`status: ready-for-implementation → ready-for-review`; `updated: <today>`) and prompt "Proceed with this change-spec advance? (Y/n)". Default Yes. On confirmation, perform the edit via the `Edit` tool, run `{{TODO-SCRIPT: hstack/scripts/validate-spec.ts}}` against the change-spec, then `git add` and commit with message `change-spec(<change-id>): ready-for-review`. This is a separate commit from the `verification(<change-id>): passed` commit — one commit per status transition, matching the finalize precedent. If the change-spec is already at `ready-for-review` or any downstream status, this step is a no-op (idempotent on re-runs). When verification status is `ran` or `failed`, this step does not run — the change-spec remains at `ready-for-implementation` until a subsequent re-run lands `passed`. Do NOT invoke `spec-author` for this write; per the kernel's Mechanical operations section, the value to write is fully determined by the verification postcondition and the change-spec's current status, so the Skill writes directly.
74
83
 
75
- 9. **Validate.** Run `{{TODO-SCRIPT: hstack/scripts/validate-spec.ts}}` — V-01, V-02, V-03, V-04.
84
+ 9. **Validate.** Run `{{TODO-SCRIPT: hstack/scripts/validate-spec.ts}}` — V-01, V-02, V-03, V-04, V-05.
76
85
 
77
86
  ## Outputs
78
87
 
@@ -121,6 +130,7 @@ Beyond the kernel's general stop conditions:
121
130
  - A canonical command in `ci-cd.md` is missing or cannot execute (missing dependency, missing env var).
122
131
  - A phase's Verifier Expectations cannot be evaluated because the relevant test file is missing.
123
132
  - A test failure blocks `status: passed`. The Skill halts at `status: ran` (or `failed`) until the implementer fixes the failing test via a new `hstack-implement` invocation.
133
+ - A `unit`, `integration`, or `e2e` suite executed zero tests (V-05). The Skill halts at `status: ran`; the subagent records the suite as `not-run` and logs the Discrepancy. Remediation is either (a) the implementer supplies the missing env / fixture so the suite collects and runs, or (b) a scope amendment removes the suite from the plan's Verifier Expectations so the zero-test state is intentional and recorded.
124
134
 
125
135
  ## Failure modes
126
136
 
@@ -131,6 +141,7 @@ Beyond the kernel's general stop conditions:
131
141
  ## Anti-patterns
132
142
 
133
143
  - Never invent a PASS. If tests are not green, status is `ran` or `failed`, not `passed`.
144
+ - Never record a suite as `pass` on the absence of failures alone (V-05). A suite that ran zero tests — gated by an unset env var, all `.skip` / `.todo`, empty collection, or filter-collapsed — is `not-run`, not `pass`. The Skill propagates the zero-tests-ran signal from the runner output into the subagent context so the rule is enforceable rather than inferred.
134
145
  - Never skip a canonical command. The consuming repo's commands in `ci-cd.md` are mandatory.
135
146
  - Never silently drop a discrepancy. Even benign discrepancies get a one-line note.
136
147
  - Never score security or data. Stay in the mechanical-verification lane.