projectstore-claude 0.30.9 โ†’ 0.30.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/node_modules/projectstore/.claude-plugin/marketplace.json +1 -1
  2. package/node_modules/projectstore/.claude-plugin/plugin.json +1 -1
  3. package/node_modules/projectstore/README.md +4 -3
  4. package/node_modules/projectstore/agents/archaeologist.md +1 -1
  5. package/node_modules/projectstore/agents/critic.md +26 -3
  6. package/node_modules/projectstore/agents/librarian.md +1 -1
  7. package/node_modules/projectstore/agents/planner.md +7 -1
  8. package/node_modules/projectstore/agents/reviewer.md +8 -1
  9. package/node_modules/projectstore/commands/adr.md +10 -0
  10. package/node_modules/projectstore/commands/bind.md +4 -3
  11. package/node_modules/projectstore/commands/concept.md +9 -0
  12. package/node_modules/projectstore/commands/doctor.md +17 -4
  13. package/node_modules/projectstore/commands/epic.md +10 -0
  14. package/node_modules/projectstore/commands/meeting.md +9 -0
  15. package/node_modules/projectstore/commands/research.md +9 -0
  16. package/node_modules/projectstore/commands/review.md +11 -7
  17. package/node_modules/projectstore/commands/runbook.md +9 -0
  18. package/node_modules/projectstore/commands/spec.md +10 -0
  19. package/node_modules/projectstore/commands/story.md +45 -6
  20. package/node_modules/projectstore/docs/contracts-and-tests.md +74 -3
  21. package/node_modules/projectstore/docs/extending.md +44 -5
  22. package/node_modules/projectstore/package.json +1 -1
  23. package/node_modules/projectstore/scaffold/guides/adr.md +42 -0
  24. package/node_modules/projectstore/scaffold/guides/concept.md +10 -0
  25. package/node_modules/projectstore/scaffold/guides/epic.md +36 -0
  26. package/node_modules/projectstore/scaffold/guides/meeting.md +11 -0
  27. package/node_modules/projectstore/scaffold/guides/research.md +16 -0
  28. package/node_modules/projectstore/scaffold/guides/runbook.md +12 -0
  29. package/node_modules/projectstore/scaffold/guides/spec.md +39 -0
  30. package/node_modules/projectstore/scaffold/guides/story.md +34 -0
  31. package/node_modules/projectstore/scaffold/guides/story.test.md +34 -0
  32. package/node_modules/projectstore/scripts/cli.mjs +55 -1
  33. package/node_modules/projectstore/scripts/configure-menu.mjs +2 -1
  34. package/node_modules/projectstore/scripts/configure.mjs +12 -2
  35. package/node_modules/projectstore/scripts/doctor.mjs +340 -41
  36. package/node_modules/projectstore/scripts/guides.mjs +217 -0
  37. package/node_modules/projectstore/scripts/harness.mjs +2 -0
  38. package/node_modules/projectstore/scripts/lib.mjs +134 -1
  39. package/node_modules/projectstore/scripts/mcp.mjs +30 -3
  40. package/node_modules/projectstore/scripts/read-verbs.mjs +59 -3
  41. package/node_modules/projectstore/scripts/scaffold.mjs +1 -1
  42. package/node_modules/projectstore/scripts/story-section.mjs +16 -1
  43. package/node_modules/projectstore/scripts/verbs.mjs +33 -1
  44. package/node_modules/projectstore/skills/projectstore-peer-reviewer/SKILL.md +9 -3
  45. package/node_modules/projectstore/templates/de/story.md.tmpl +2 -0
  46. package/node_modules/projectstore/templates/en/story.md.tmpl +2 -0
  47. package/node_modules/projectstore/templates/es/story.md.tmpl +2 -0
  48. package/node_modules/projectstore/templates/fr/story.md.tmpl +2 -0
  49. package/node_modules/projectstore/templates/ru/story.md.tmpl +2 -0
  50. package/node_modules/projectstore/templates/zh/story.md.tmpl +2 -0
  51. package/package.json +2 -2
  52. package/node_modules/projectstore/scaffold/checklists.json +0 -88
@@ -12,7 +12,7 @@
12
12
  "name": "projectstore",
13
13
  "displayName": "projectstore",
14
14
  "description": "๐Ÿ“š Your agent runs the project through a verified loop: task โ†’ artifact (ADR ยท spec ยท epic ยท story) โ†’ adversarial critic โ†’ backlog โ†’ planner โ†’ reviewer โ†’ done. Plain markdown in an Obsidian-friendly vault, every write approved by you โ€” and any model can pick the project up tomorrow.",
15
- "version": "0.30.9",
15
+ "version": "0.30.11",
16
16
  "author": {
17
17
  "name": "Evgenii Konev",
18
18
  "email": "ekonev@smartandpoint.com",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "projectstore",
3
3
  "displayName": "projectstore",
4
- "version": "0.30.9",
4
+ "version": "0.30.11",
5
5
  "description": "Your agent runs the project through a verified loop: task โ†’ artifact (ADR / spec / epic / story) โ†’ adversarial critic โ†’ backlog โ†’ planner โ†’ reviewer โ†’ done. Plain markdown in git โ€” any model can pick the project up tomorrow.",
6
6
  "author": {
7
7
  "name": "Evgenii Konev @ SmartAndPoint",
@@ -178,9 +178,10 @@ npx projectstore search "entry rule" --kind spec
178
178
  npx projectstore show adr/README.md --section index
179
179
  npx projectstore graph neighbors epics/PS-CORE/epic.md
180
180
  npx projectstore codemap --for scripts/lib.mjs
181
+ npx projectstore guide spec --section Must
181
182
  ```
182
183
 
183
- The same eight reads are an MCP server. The plugin registers it through its own `.mcp.json`, so a Claude Code session has `status`, `search`, `get_artifact`, `neighbors`, `lineage`, `code_refs`, `orientation` and `doctor` as tools with no shell; every tool result is the CLI's `--json` for the same arguments. Elsewhere:
184
+ The same nine reads are an MCP server. The plugin registers it through its own `.mcp.json`, so a Claude Code session has `status`, `search`, `get_artifact`, `neighbors`, `lineage`, `code_refs`, `orientation`, `doctor` and `guide` as tools with no shell; every tool result is the CLI's `--json` for the same arguments. Elsewhere:
184
185
 
185
186
  ```
186
187
  npx projectstore mcp --project .
@@ -240,7 +241,7 @@ Each setting has exactly one writer, and the plan says which file it changes:
240
241
 
241
242
  - **The agents' models and efforts** live in `.projectstore/harness/<harness>.json`. That file is committed, so a change there is a team change.
242
243
  - **The status line, the band, the language and the other binding keys** live in `.projectstore/projectstore.json`, which stays on this machine.
243
- - **The spec policy and the lifecycle gates** live in the vault's `.projectstore.json`, which commits with the vault. Setting `spec_policy=required` records when it took effect; stories closed before then are exempt. A spec's contracts can carry WHEN/THEN scenarios, and a test can cite a contract, so doctor can report the contracts no test covers: see [`docs/contracts-and-tests.md`](./docs/contracts-and-tests.md).
244
+ - **The spec policy and the lifecycle gates** live in the vault's `.projectstore.json`, which commits with the vault. Setting `spec_policy=required` records when it took effect; stories closed before then are exempt. A story whose work needs no spec can say why in `no_spec`, and `doctor --vault --policy required` shows what the policy would report before you switch it on. A spec's contracts can carry WHEN/THEN scenarios, and a test can cite a contract, so doctor can report the contracts no test covers: see [`docs/contracts-and-tests.md`](./docs/contracts-and-tests.md).
244
245
 
245
246
  The vault itself is changed by `bind --rebind`, which configure names when asked. In a Claude Code session, `/projectstore:statusline` and `/projectstore:agents configure` run the same writers.
246
247
 
@@ -411,7 +412,7 @@ The package also ships `scripts/version-guard.mjs`, which runs `npm pack --dry-r
411
412
  Opening a project that is not bound writes nothing into it: the first-run welcome is remembered in the user cache below. Every other write in a project comes from a command you run, or from the hooks and the status line once the project is bound.
412
413
 
413
414
  - **In a bound project**: `.projectstore/`, with the binding (`projectstore.json`, machine-local and git-ignored), the agents' models (`harness/`, meant to be committed), `state/` (each session's state, the band's heartbeat, the welcome marker and the status line's launcher, machine-local) and its own `.gitignore`; the agents block between the `projectstore:agents` markers in `AGENTS.md` and `CLAUDE.md`; and `.claude/settings.local.json`, which gets the status line only when you turn it on, and this checkout's plugin registration when setup or install registers the npm copy, or turns the git-marketplace copy off here, through Claude Code's own CLI.
414
- - **In the vault**: the artifacts, each one after you approve it; the views generated from them (the kanban, the folder indexes, the code map and the graph); `.projectstore.json`, the vault's own settings; and `.projectstore/sessions/`, one small git-ignored file per session with its id, start time, project path, host name, process id and the vault files it read or edited last, with the tool and the time. A session's file is deleted at the next session start once it has been inactive for 24 hours. A new vault also gets its own git repository.
415
+ - **In the vault**: the artifacts, each one after you approve it; the views generated from them (the kanban, the folder indexes, the code map and the graph); `.projectstore.json`, the vault's own settings; `guides/`, only when you run `guide eject --write` to override a kind's authoring guide; and `.projectstore/sessions/`, one small git-ignored file per session with its id, start time, project path, host name, process id and the vault files it read or edited last, with the tool and the time. A session's file is deleted at the next session start once it has been inactive for 24 hours. A new vault also gets its own git repository.
415
416
  - **In your home directory**: `~/.cache/projectstore/`, or `$XDG_CACHE_HOME/projectstore/` when that is set. It holds the newest version the npm registry named (`registry.json`, kept for 24 hours), the model lists (`models/`, kept for a day: model names, labels, descriptions and families, never a key), which agent has shown its first-run welcome in a project that is not bound (`welcomed/`, one marker per agent for the machine), and the Codex package while a run installs it (`fetch/`, removed when the run ends). Setup and install from npm also write a folder of their own, `projectstore/`, under Claude Code's home (`~/.claude`, or `$CLAUDE_CONFIG_DIR`) or Codex's (`~/.codex`, or `$CODEX_HOME`), holding the marketplace the agent installs ProjectStore from, and the agent's own CLI records the plugin in that agent's plugin registry.
416
417
 
417
418
  ProjectStore never changes Claude Code's or Codex's permission settings.
@@ -26,7 +26,7 @@ Locate the vault (`.projectstore/projectstore.json` โ†’ `vault_path`). Read `adr
26
26
  `concepts/` titles + frontmatter first. Never propose an artifact that already
27
27
  exists โ€” extend or supersede it instead, and say so.
28
28
 
29
- **Evidence through the MCP tools when they are available.** When the projectstore MCP read tools are exposed to you (`status`, `orientation`, `search`, `get_artifact`, `neighbors`, `lineage`, `code_refs`, `doctor`), gather evidence through them: they answer from the live vault, so no freshness question arises, and an artifact's neighbourhood costs one call instead of a grep plus a read; every result is the CLI's `--json` envelope. When they are not โ€” a host without MCP, or an install older than 0.28 โ€” the derived views below are the fallback, under the rule that follows. `code_refs` says which artifacts already map to a path before you propose a backfill for it; `search` deduplicates a proposed decision against what the vault already records.
29
+ **Evidence through the MCP tools when they are available.** When the projectstore MCP read tools are exposed to you (`status`, `orientation`, `search`, `get_artifact`, `neighbors`, `lineage`, `code_refs`, `doctor`, `guide`), gather evidence through them: they answer from the live vault, so no freshness question arises, and an artifact's neighbourhood costs one call instead of a grep plus a read; every result is the CLI's `--json` envelope. When they are not โ€” a host without MCP, or an install older than 0.28 โ€” the derived views below are the fallback, under the rule that follows. `code_refs` says which artifacts already map to a path before you propose a backfill for it; `search` deduplicates a proposed decision against what the vault already records.
30
30
 
31
31
  Derived views (kanban.md, code-map.md, graph.md) are precomputed vault indexes โ€”
32
32
  prefer them for orientation, but fall back to a frontmatter sweep when a view is
@@ -17,7 +17,7 @@ Read the file and follow its load-bearing links (a referenced research note, ADR
17
17
  or the actual code/data behind a claim). **Verify every technical claim against
18
18
  the real source** โ€” don't trust an assertion because it's written confidently.
19
19
 
20
- **Evidence through the MCP tools when they are available.** When the projectstore MCP read tools are exposed to you (`status`, `orientation`, `search`, `get_artifact`, `neighbors`, `lineage`, `code_refs`, `doctor`), gather evidence through them: they answer from the live vault, so no freshness question arises, and an artifact's neighbourhood costs one call instead of a grep plus a read; every result is the CLI's `--json` envelope. When they are not โ€” a host without MCP, or an install older than 0.28 โ€” the derived views below are the fallback, under the rule that follows. `neighbors` and `lineage` are how you follow an artifact's load-bearing links; `get_artifact` with `section` reads one section without the whole file.
20
+ **Evidence through the MCP tools when they are available.** When the projectstore MCP read tools are exposed to you (`status`, `orientation`, `search`, `get_artifact`, `neighbors`, `lineage`, `code_refs`, `doctor`, `guide`), gather evidence through them: they answer from the live vault, so no freshness question arises, and an artifact's neighbourhood costs one call instead of a grep plus a read; every result is the CLI's `--json` envelope. When they are not โ€” a host without MCP, or an install older than 0.28 โ€” the derived views below are the fallback, under the rule that follows. `neighbors` and `lineage` are how you follow an artifact's load-bearing links; `get_artifact` with `section` reads one section without the whole file.
21
21
 
22
22
  Derived views (kanban.md, code-map.md, graph.md) are precomputed vault indexes โ€”
23
23
  prefer them for orientation, but fall back to a frontmatter sweep when a view is
@@ -31,12 +31,30 @@ implementation), issue them together; go sequential only when a result genuinely
31
31
  decides what to look at next. Quote paths with spaces (vaults often live under
32
32
  iCloud paths).
33
33
 
34
+ **The kind's guide is your checklist.** When the artifact under review has a
35
+ projectstore kind (frontmatter `type:`), read its authoring guide, with the
36
+ story's `variant` when it has one (`<kind>.<variant>`, such as `story.test`):
37
+ the MCP tool `guide` when it is exposed to you, otherwise
38
+
39
+ ```bash
40
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" guide <kind> --json --project "${CLAUDE_PROJECT_DIR}"
41
+ ```
42
+
43
+ A vault override wins over the package default, so this is the project's own
44
+ rule set, the same one the author read before the draft. When the caller's
45
+ prompt already carries the kind's checklist, it is this guide's `## Must`.
46
+ Exit 1 means the kind has no guide: say in your verdict that the review ran
47
+ without a kind checklist, and apply no other kind's items.
48
+
34
49
  ## Phase 0 โ€” Pre-commitment (before reading in detail)
35
50
  From the artifact's type + domain, predict the 3-5 most likely problem areas ("a
36
51
  caching fix here probably ignores eviction"; "these acceptance criteria are
37
- probably not measurable"). Write them, then investigate each.
52
+ probably not measurable"). Take the guide's `## Common mistakes` among them.
53
+ Write them, then investigate each.
38
54
 
39
55
  ## Phase 1 โ€” Verify & stress-test
56
+ - **The guide's `## Must`** โ€” check every item against the artifact, and
57
+ report each one that fails by its text.
40
58
  - **Technical correctness** โ€” does the mechanism actually WORK? Systems gotchas:
41
59
  caching (prefix/KV-cache invalidation, eviction, hit-rate), concurrency /
42
60
  ordering / idempotency, retries, timeouts, partial failure, data-loss, protocol
@@ -52,6 +70,10 @@ probably not measurable"). Write them, then investigate each.
52
70
  - **Internal consistency & testability** โ€” does the decomposition deliver the
53
71
  stated goal? Are the acceptance criteria objectively verifiable, and do they
54
72
  cover the failure modes the problem statement raised?
73
+ - **A story that opts out of a spec** (`no_spec: "<reason>"`) โ€” does the
74
+ reason hold? Non-trivial "how", or work across several source files, needs
75
+ a spec. A research spike takes a light spec, not a reason. A reason such as
76
+ "n/a" or "small" is a finding.
55
77
 
56
78
  ## Phase 2 โ€” Gap analysis ("What's Missing") โ€” highest-leverage step
57
79
  Standard reviews evaluate what IS present; explicitly hunt what ISN'T: "What would
@@ -80,7 +102,8 @@ by: โ€ฆ" โ€” but NEVER downgrade data-loss, security, or a wrong core claim. Don
80
102
  manufacture findings; if an aspect is genuinely solid, one sentence and move on.
81
103
 
82
104
  ## Output โ€” your LAST message IS the deliverable returned to the caller
83
- 1. **Verdict** โ€” `ship` / `revise` / `rethink` + the single most important reason.
105
+ 1. **Verdict** โ€” `ship` / `revise` / `rethink` + the single most important reason;
106
+ for a kind with no guide, add that the review ran without a kind checklist.
84
107
  2. **Findings** โ€” severity-rated, highest first: `๐Ÿ”ด blocker` / `๐ŸŸก should-fix` /
85
108
  `๐ŸŸข nice`. Each: problem in one sentence (cite the exact claim / line /
86
109
  acceptance-criterion), confidence, *why it matters* (concrete consequence),
@@ -18,7 +18,7 @@ Locate the vault via `.projectstore/projectstore.json` โ†’ `vault_path`. Read th
18
18
  READMEs for orientation, then the artifacts themselves (frontmatter + content),
19
19
  prioritizing accepted ADRs and active epics.
20
20
 
21
- **Evidence through the MCP tools when they are available.** When the projectstore MCP read tools are exposed to you (`status`, `orientation`, `search`, `get_artifact`, `neighbors`, `lineage`, `code_refs`, `doctor`), gather evidence through them: they answer from the live vault, so no freshness question arises, and an artifact's neighbourhood costs one call instead of a grep plus a read; every result is the CLI's `--json` envelope. When they are not โ€” a host without MCP, or an install older than 0.28 โ€” the derived views below are the fallback, under the rule that follows. Your baseline is the whole edge set, which is one read of the `projectstore://graph` resource (or `graph.md`), never one `neighbors` call per artifact; `neighbors` is for confirming a candidate pair.
21
+ **Evidence through the MCP tools when they are available.** When the projectstore MCP read tools are exposed to you (`status`, `orientation`, `search`, `get_artifact`, `neighbors`, `lineage`, `code_refs`, `doctor`, `guide`), gather evidence through them: they answer from the live vault, so no freshness question arises, and an artifact's neighbourhood costs one call instead of a grep plus a read; every result is the CLI's `--json` envelope. When they are not โ€” a host without MCP, or an install older than 0.28 โ€” the derived views below are the fallback, under the rule that follows. Your baseline is the whole edge set, which is one read of the `projectstore://graph` resource (or `graph.md`), never one `neighbors` call per artifact; `neighbors` is for confirming a candidate pair.
22
22
 
23
23
  Derived views (kanban.md, code-map.md, graph.md) are precomputed vault indexes โ€”
24
24
  prefer them for orientation, but fall back to a frontmatter sweep when a view is
@@ -19,7 +19,7 @@ epics' `code_refs`, and the modules they point at don't depend on each other โ€”
19
19
  read them together; go sequential only when a result genuinely decides what to
20
20
  look at next. Quote paths with spaces (vaults often live under iCloud paths).
21
21
 
22
- **Evidence through the MCP tools when they are available.** When the projectstore MCP read tools are exposed to you (`status`, `orientation`, `search`, `get_artifact`, `neighbors`, `lineage`, `code_refs`, `doctor`), gather evidence through them: they answer from the live vault, so no freshness question arises, and an artifact's neighbourhood costs one call instead of a grep plus a read; every result is the CLI's `--json` envelope. `code_refs` with an epic id is the epicโ†”code mapping Phase 0 asks for, in one call. When they are not โ€” a host without MCP, or an install older than 0.28 โ€” the derived views below are the fallback, under the rule that follows.
22
+ **Evidence through the MCP tools when they are available.** When the projectstore MCP read tools are exposed to you (`status`, `orientation`, `search`, `get_artifact`, `neighbors`, `lineage`, `code_refs`, `doctor`, `guide`), gather evidence through them: they answer from the live vault, so no freshness question arises, and an artifact's neighbourhood costs one call instead of a grep plus a read; every result is the CLI's `--json` envelope. `code_refs` with an epic id is the epicโ†”code mapping Phase 0 asks for, in one call. When they are not โ€” a host without MCP, or an install older than 0.28 โ€” the derived views below are the fallback, under the rule that follows.
23
23
 
24
24
  Derived views (kanban.md, code-map.md, graph.md) are precomputed vault indexes โ€” prefer them for orientation, but fall back to a frontmatter sweep when a view is missing or its `generated_at` predates recent artifact changes (compare file mtimes; a false-stale just costs a sweep).
25
25
 
@@ -46,6 +46,12 @@ spec contracts = durable how; the story's `## Implementation Plan` = per-story
46
46
  route (your output feeds it via `/projectstore:story plan`); `## Technical
47
47
  Notes` = incidental constraints discovered during work.
48
48
 
49
+ **Spec or no spec.** When the story has no covering spec, say whether it
50
+ needs one, and why. Work whose "how" is non-trivial, or that will touch three
51
+ or more source files, needs a spec. A release, a text or site change, or a
52
+ small fix may instead declare `no_spec: "<reason>"` at the plan gate, which
53
+ the story command writes. A research spike takes a light spec, not a reason.
54
+
49
55
  ## Phase 1 โ€” Explore the codebase
50
56
 
51
57
  Use Grep / Glob / Read / Bash to find: the module(s) that own this concern, the
@@ -18,7 +18,7 @@ its Description, Decomposition, and **Acceptance Criteria** โ€” plus the parent
18
18
  epic and the plan if one was produced. If the caller named no story, ask the diff
19
19
  which story it serves (grep the vault) before falling back to a plain code review.
20
20
 
21
- **Evidence through the MCP tools when they are available.** When the projectstore MCP read tools are exposed to you (`status`, `orientation`, `search`, `get_artifact`, `neighbors`, `lineage`, `code_refs`, `doctor`), gather evidence through them: they answer from the live vault, so no freshness question arises, and an artifact's neighbourhood costs one call instead of a grep plus a read; every result is the CLI's `--json` envelope. When they are not โ€” a host without MCP, or an install older than 0.28 โ€” the derived views below are the fallback, under the rule that follows. `lineage` on the story returns its covering specs and their ADRs in one call; `code_refs` answers whether the parent epic's footprint needs widening; `search` locates the story and its acceptance text.
21
+ **Evidence through the MCP tools when they are available.** When the projectstore MCP read tools are exposed to you (`status`, `orientation`, `search`, `get_artifact`, `neighbors`, `lineage`, `code_refs`, `doctor`, `guide`), gather evidence through them: they answer from the live vault, so no freshness question arises, and an artifact's neighbourhood costs one call instead of a grep plus a read; every result is the CLI's `--json` envelope. When they are not โ€” a host without MCP, or an install older than 0.28 โ€” the derived views below are the fallback, under the rule that follows. `lineage` on the story returns its covering specs and their ADRs in one call; `code_refs` answers whether the parent epic's footprint needs widening; `search` locates the story and its acceptance text.
22
22
 
23
23
  Derived views (kanban.md, code-map.md, graph.md) are precomputed vault indexes โ€”
24
24
  prefer them for orientation, but fall back to a frontmatter sweep when a view is
@@ -39,6 +39,13 @@ both sets are green and every covering spec is `active`. Report a covering
39
39
  spec still in `draft` as a blocker under `spec_policy: required` (vault's
40
40
  `.projectstore.json`).
41
41
 
42
+ **A declared opt-out, at close.** A story with `no_spec: "<reason>"` has no
43
+ covering spec on purpose. Compute its files (Output 4). If it touches three
44
+ or more source files (tests do not count; a directory counts as several),
45
+ that is a ๐Ÿ”ด finding: the story is covered by a spec, new or existing, and
46
+ `no_spec` is removed before it closes. There is no way to silence this.
47
+ Otherwise check that the reason still matches what the diff did.
48
+
42
49
  ## Phase 0 โ€” Pre-commitment
43
50
  From the story + file list, predict the 3-5 most likely gaps ("AC #3 needs an
44
51
  error path the diff doesn't touch"; "touches a cache โ€” invalidation risk"). Write
@@ -9,6 +9,16 @@ Steps:
9
9
 
10
10
  1. **Check config**: `test -f .projectstore/projectstore.json` โ€” if missing, tell user to run `/projectstore:bind <path>` and stop.
11
11
 
12
+ 1a. **Read the guide** for this kind before writing anything:
13
+
14
+ ```bash
15
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" guide adr --project "${CLAUDE_PROJECT_DIR}"
16
+ ```
17
+
18
+ Write the draft to its `## Must`, `## Common mistakes`, `## Do not write`
19
+ and `## Length`: the critic checks the same `## Must` items. Exit 1 means
20
+ this kind has no guide; say so and go on.
21
+
12
22
  2. **Render draft** by running:
13
23
 
14
24
  ```bash
@@ -95,7 +95,7 @@ Steps:
95
95
 
96
96
  7.5. **Vault policy** (v0.14, ADR-007 โ€” vault-side, survives clones): check `<vault>/.projectstore.json`.
97
97
  - If it already exists with a `spec_policy` key โ€” respect it, print the current policy, do not re-ask.
98
- - **New bind into a vault with no artifacts** (a vault `init` just made counts: its folders and README indexes are not artifacts): ask via AskUserQuestion โ€” "Enable spec-first policy for this vault (every story must be covered by a spec; doctor enforces it)?" with options **Yes, `spec_policy: required` (Recommended)** / **Not yet, `optional`**. Second question: "Enable lifecycle gates (plan/close sections + evidence checks on stories)?" โ€” **Yes, `lifecycle_gates: on` (Recommended)** / **Off for now**.
98
+ - **New bind into a vault with no artifacts** (a vault `init` just made counts: its folders and README indexes are not artifacts): ask via AskUserQuestion โ€” "Enable spec-first policy for this vault (every story is covered by a spec, or says at its plan gate why it needs none; doctor enforces it)?" with options **Yes, `spec_policy: required` (Recommended)** / **Not yet, `optional`**. Second question: "Enable lifecycle gates (plan/close sections + evidence checks on stories)?" โ€” **Yes, `lifecycle_gates: on` (Recommended)** / **Off for now**.
99
99
  - **Bind to an existing vault with artifacts**: default to `spec_policy: optional`, `lifecycle_gates: off` and say doctor will suggest enabling once specs appear. Do not impose the gate on an existing backlog.
100
100
  - On any choice, run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" configure --set spec_policy=<required|optional> --set lifecycle_gates=<on|off> --dry-run --project "${CLAUDE_PROJECT_DIR}"` and show its PLAN, then ask via AskUserQuestion: "Record this policy in the vault? [Yes / No]". On **Yes**, run the same command without `--dry-run`; a non-zero exit is a refusal โ€” relay it and go on to step 8 (the binding is already written). It writes `<vault>/.projectstore.json` โ€” vault ROOT, deliberately not inside `<vault>/.projectstore/`, whose .gitignore would keep the policy out of git โ€” and keeps any other key in it:
101
101
 
@@ -103,11 +103,12 @@ Steps:
103
103
  {
104
104
  "spec_policy": "required",
105
105
  "lifecycle_gates": "on",
106
- "spec_policy_since": "<current ISO-8601 timestamp>"
106
+ "spec_policy_since": "<current ISO-8601 timestamp>",
107
+ "gates_since": "<current ISO-8601 timestamp>"
107
108
  }
108
109
  ```
109
110
 
110
- configure stamps `spec_policy_since` whenever spec_policy becomes `required` โ€” it anchors the legacy exemption (stories done before it stay exempt; stories in progress/review at enable time are in scope).
111
+ configure stamps `spec_policy_since` whenever spec_policy becomes `required` โ€” it anchors the legacy exemption (stories done before it stay exempt; stories in progress/review at enable time are in scope). It stamps `gates_since` when the lifecycle gates turn on, so the gates check stories closed after that date under either policy.
111
112
 
112
113
  8. **Agent registration** (v0.13, ADR-002): ask via AskUserQuestion โ€” "Register projectstore's agents in CLAUDE.md/AGENTS.md so every session routes to them (critic after authoring artifacts, planner before implementing, reviewer before commit)? [Yes (Recommended) / No]". On Yes, run `node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" install --harness claude-code --surface agents_block --project "${CLAUDE_PROJECT_DIR}"` and print its output (it renders from the layout's roster, migrates rather than duplicates, previews every write, and applies because the harness is named). On a rebind where a block already exists the verb reports it current or replaces it in place โ€” do not re-ask blindly.
113
114
 
@@ -8,6 +8,15 @@ You are creating a concept note.
8
8
  Steps:
9
9
 
10
10
  1. Check config; stop if missing.
11
+ 1a. **Read the guide** for this kind before writing anything:
12
+
13
+ ```bash
14
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" guide concept --project "${CLAUDE_PROJECT_DIR}"
15
+ ```
16
+
17
+ Write the draft to its `## Must`, `## Common mistakes`, `## Do not write`
18
+ and `## Length`: the critic checks the same `## Must` items. Exit 1 means
19
+ this kind has no guide; say so and go on.
11
20
  2. Run `node "${CLAUDE_PLUGIN_ROOT}/scripts/draft.mjs" concept "$ARGUMENTS"`.
12
21
  3. Preview path + first ~15 lines. When `index` is non-null, print `index.line` too โ€” the exact row that will appear in the folder index, unless the index step reports a failure and no row lands at all.
13
22
  4. AskUserQuestion: Yes / Edit / No. This is the only gate: **Yes** covers the artifact and its index row. Disclose in the question that the folder's whole managed index table is regenerated from vault state at write time, so the update may also repair a stale row for another artifact.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Diagnose the projectstore installation (config, vault, hooks, statusline, agents wiring) and the vault's consistency (status โ†” kanban โ†” indexes, acceptance, links). Read-only by default; --fix offers approval-gated install-side repairs.
3
- argument-hint: "[--install | --vault] [--fix]"
3
+ argument-hint: "[--install | --vault] [--policy required[@<date>]] [--fix]"
4
4
  ---
5
5
 
6
6
  You are running projectstore diagnostics (ADR-005: umbrella doctor).
@@ -13,7 +13,7 @@ You are running projectstore diagnostics (ADR-005: umbrella doctor).
13
13
  node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" doctor $ARGUMENTS_WITHOUT_FIX
14
14
  ```
15
15
 
16
- Forward only `--install` / `--vault` from the arguments: the bin's parser is strict, and any other flag is a usage error (exit 2) rather than the shrug the bare script gave. Exit 1 means findings were reported, not that the check failed (exit 2 is usage, 3 not bound) โ€” read the report, never the exit code, as the verdict. (The bare script always exited 0; through the bin the exit code carries the verdict, so a Bash tool that colours non-zero red is colouring findings, not a crash.)
16
+ Forward only `--install` / `--vault` / `--policy <rule>` from the arguments. `--policy required` (or `required@<date>`) is a dry run of the vault section as if the spec policy were required since that date: it writes nothing, and the report opens with a `dry-run` note. The bin's parser is strict, and any other flag is a usage error (exit 2) rather than the shrug the bare script gave. Exit 1 means findings were reported, not that the check failed (exit 2 is usage, 3 not bound) โ€” read the report, never the exit code, as the verdict. (The bare script always exited 0; through the bin the exit code carries the verdict, so a Bash tool that colours non-zero red is colouring findings, not a crash.)
17
17
 
18
18
  Default (no flags) runs both sections: `--install` (wiring/config) and
19
19
  `--vault` (consistency). Print the report **verbatim**.
@@ -186,5 +186,18 @@ You are running projectstore diagnostics (ADR-005: umbrella doctor).
186
186
  gates (`evidence`, `plan-gate`, `final-summary`) key off the VAULT-side
187
187
  policy file `<vault>/.projectstore.json` (`spec_policy` / `lifecycle_gates`,
188
188
  ADR-007), never the machine-local config. `spec-links` integrity runs
189
- whenever specs exist. Legacy stories (done before `spec_policy_since`, or
190
- done with no `closed_at`) are exempt by design.
189
+ whenever specs exist. Legacy stories (done before `spec_policy_since`, else
190
+ `gates_since`, or done with no `closed_at`) are exempt by design.
191
+ - The opt-out checks run under every policy: `no-spec` (an empty reason,
192
+ `no_spec` beside `specs:`, or three or more source files), `no-spec-share`
193
+ (opt-outs against covered stories). `gates-since` suggests the stamp for
194
+ gates that have no date, `review-by` names an ADR due for review, and
195
+ `dry-run` heads a `--policy` report. None of them is repairable by `--fix`:
196
+ each is a judgement, or a `configure` step its message names.
197
+ - The guide checks read the vault's `guides/` folder, the per-kind overrides
198
+ of the authoring guides: `guide-shape` (an override that does not parse, so
199
+ readers fall back to the package default), `guide-unknown` (a guide for a
200
+ kind the layout does not have) and `guide-stale` (an override made from an
201
+ older package default; the message names the command that reads the new
202
+ one). None of them is repairable by `--fix`: the override is the user's
203
+ file, and merging a newer default into it is a judgement.
@@ -11,6 +11,16 @@ Steps:
11
11
 
12
12
  2. **Validate args**: `$ARGUMENTS` must contain at least an ID and a title. ID is a short uppercase token (e.g. `AUTH-001`, `RECPLAT-269`). If only one word was given, ask user for the title via AskUserQuestion.
13
13
 
14
+ 2a. **Read the guide** for this kind before writing anything:
15
+
16
+ ```bash
17
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" guide epic --project "${CLAUDE_PROJECT_DIR}"
18
+ ```
19
+
20
+ Write the draft to its `## Must`, `## Common mistakes`, `## Do not write`
21
+ and `## Length`: the critic checks the same `## Must` items. Exit 1 means
22
+ this kind has no guide; say so and go on.
23
+
14
24
  3. **Render draft**:
15
25
 
16
26
  ```bash
@@ -8,6 +8,15 @@ You are creating a meeting note. Today's date is auto-prefixed.
8
8
  Steps:
9
9
 
10
10
  1. Check config; stop if missing.
11
+ 1a. **Read the guide** for this kind before writing anything:
12
+
13
+ ```bash
14
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" guide meeting --project "${CLAUDE_PROJECT_DIR}"
15
+ ```
16
+
17
+ Write the draft to its `## Must`, `## Common mistakes`, `## Do not write`
18
+ and `## Length`: the critic checks the same `## Must` items. Exit 1 means
19
+ this kind has no guide; say so and go on.
11
20
  2. Run `node "${CLAUDE_PLUGIN_ROOT}/scripts/draft.mjs" meeting "$ARGUMENTS"`.
12
21
  3. Preview path + first ~15 lines. When `index` is non-null, print `index.line` too โ€” the exact row that will appear in the folder index, unless the index step reports a failure and no row lands at all. (In the step-5 **Append to existing** branch no new row appears: the existing note already has one, rendered from its own frontmatter.)
13
22
  4. AskUserQuestion: Yes / Edit / No. When proposing "Edit", offer to seed `Attendees` and `Agenda` from the conversation context if relevant. This is the only gate: **Yes** covers the artifact and its index row. Disclose in the question that the folder's whole managed index table is regenerated from vault state at write time, so the update may also repair a stale row for another artifact.
@@ -8,6 +8,15 @@ You are creating a research note (deep investigation, comparison, benchmark).
8
8
  Steps:
9
9
 
10
10
  1. Check config; stop if missing.
11
+ 1a. **Read the guide** for this kind before writing anything:
12
+
13
+ ```bash
14
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" guide research --project "${CLAUDE_PROJECT_DIR}"
15
+ ```
16
+
17
+ Write the draft to its `## Must`, `## Common mistakes`, `## Do not write`
18
+ and `## Length`: the critic checks the same `## Must` items. Exit 1 means
19
+ this kind has no guide; say so and go on.
11
20
  2. Run `node "${CLAUDE_PLUGIN_ROOT}/scripts/draft.mjs" research "$ARGUMENTS"`.
12
21
  3. Preview path + first ~20 lines. When `index` is non-null, print `index.line` too โ€” the exact row that will appear in the folder index, unless the index step reports a failure and no row lands at all.
13
22
  4. AskUserQuestion: Yes / Edit / No. This is the only gate: **Yes** covers the artifact and its index row. Disclose in the question that the folder's whole managed index table is regenerated from vault state at write time, so the update may also repair a stale row for another artifact.
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Peer-review an existing artifact (ADR / research / epic / etc.) using a fresh critic-mode agent with a structural checklist. Returns concrete improvements, no sycophancy.
2
+ description: Peer-review an existing artifact (ADR / research / epic / etc.) using a fresh critic-mode agent with the kind's authoring guide as its checklist. Returns concrete improvements, no sycophancy.
3
3
  argument-hint: <path-to-artifact>
4
4
  ---
5
5
 
@@ -13,13 +13,13 @@ You are running a peer review on a projectstore artifact.
13
13
 
14
14
  3. **Identify the kind**: parse the YAML frontmatter for `type:`. If missing, try to infer from the file path (`adr/` โ†’ adr, `epics/<id>/epic.md` โ†’ epic, `epics/<id>/stories/*` โ†’ story, `research/` โ†’ research, etc.). If still unknown, ask the user via AskUserQuestion which kind to apply.
15
15
 
16
- 4. **Load the checklist**:
16
+ 4. **Load the guide**: read the kind's authoring guide (the kind from step 3; for a story whose frontmatter has `variant:`, use `<kind>.<variant>`):
17
17
 
18
18
  ```bash
19
- cat "${CLAUDE_PLUGIN_ROOT}/scaffold/checklists.json"
19
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" guide <kind> --json --project "${CLAUDE_PROJECT_DIR}"
20
20
  ```
21
21
 
22
- Parse JSON, pick the entry by kind. If the kind has no entry, use the `adr` checklist as a generic fallback and note this to the user.
22
+ Its `result.sections.Must` items are the checklist, and `result.sections["Common mistakes"]` the likely problem areas; a vault override wins over the package default, so this is the project's own rule set. Exit 1 means the kind has no guide: the review runs without a kind checklist, and the report says so. No other kind's items stand in for it.
23
23
 
24
24
  5. **Gather domain context**: read the vault's top-level `README.md` and the folder README of the artifact's parent (e.g. `adr/README.md`). Keep both short โ€” they're context for the critic, not the focus.
25
25
 
@@ -40,9 +40,13 @@ You are running a peer review on a projectstore artifact.
40
40
  <the vault's README excerpt>
41
41
  <the folder's README excerpt>
42
42
 
43
- ## Structural checklist
43
+ ## Structural checklist (the guide's ## Must)
44
44
 
45
- <bullet list of checklist.items>
45
+ <bullet list of result.sections.Must, verbatim; or "none: reviewed without a kind checklist">
46
+
47
+ ## Common mistakes for this kind
48
+
49
+ <bullet list of result.sections["Common mistakes"], when present>
46
50
 
47
51
  ## Report format (strict)
48
52
 
@@ -86,4 +90,4 @@ You are running a peer review on a projectstore artifact.
86
90
 
87
91
  - Critic agent MUST NOT see the conversation that produced the artifact. Only the artifact + minimal context. That fresh framing is the whole point.
88
92
  - If the critic returns suspiciously sycophantic findings ("good overall, minor nit:"), retry once with an explicit `NO PRAISE, NO HEDGING.` injected into the prompt.
89
- - Selective default: if user invoked `/projectstore:review` on a kind whose `default_review` is `false` in checklists.json (e.g. meeting), still run โ€” they asked explicitly. Just don't auto-trigger via skill.
93
+ - Selective default: if user invoked `/projectstore:review` on a kind whose guide has `default_review: false` (e.g. meeting), still run โ€” they asked explicitly. Just don't auto-trigger via skill.
@@ -8,6 +8,15 @@ You are creating an ops runbook.
8
8
  Steps:
9
9
 
10
10
  1. Check config; stop if missing.
11
+ 1a. **Read the guide** for this kind before writing anything:
12
+
13
+ ```bash
14
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" guide runbook --project "${CLAUDE_PROJECT_DIR}"
15
+ ```
16
+
17
+ Write the draft to its `## Must`, `## Common mistakes`, `## Do not write`
18
+ and `## Length`: the critic checks the same `## Must` items. Exit 1 means
19
+ this kind has no guide; say so and go on.
11
20
  2. Run `node "${CLAUDE_PLUGIN_ROOT}/scripts/draft.mjs" runbook "$ARGUMENTS"`.
12
21
  3. Preview path + first ~20 lines. When `index` is non-null, print `index.line` too โ€” the exact row that will appear in the folder index, unless the index step reports a failure and no row lands at all.
13
22
  4. AskUserQuestion: Yes / Edit / No. This is the only gate: **Yes** covers the artifact and its index row. Disclose in the question that the folder's whole managed index table is regenerated from vault state at write time, so the update may also repair a stale row for another artifact.
@@ -17,6 +17,16 @@ Dispatch on the first argument:
17
17
 
18
18
  1. **Check config**: stop if `.projectstore/projectstore.json` missing.
19
19
 
20
+ 1a. **Read the guide** for this kind before writing anything:
21
+
22
+ ```bash
23
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" guide spec --project "${CLAUDE_PROJECT_DIR}"
24
+ ```
25
+
26
+ Write the draft to its `## Must`, `## Common mistakes`, `## Do not write`
27
+ and `## Length`: the critic checks the same `## Must` items. Exit 1 means
28
+ this kind has no guide; say so and go on.
29
+
20
30
  2. **Render draft**:
21
31
 
22
32
  ```bash
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Create a new story inside an existing epic, or run its lifecycle gates (plan / close).
3
- argument-hint: <epic-id> <title> [--spec SPEC-ID] | plan <story> | close <story>
3
+ argument-hint: <epic-id> <title> [--spec SPEC-ID] [--variant test] | plan <story> | close <story>
4
4
  ---
5
5
 
6
6
  You are managing a story: creating one, or running its lifecycle gates.
@@ -16,15 +16,39 @@ the two cannot collide).
16
16
 
17
17
  1. **Check config**: stop if `.projectstore/projectstore.json` missing.
18
18
 
19
- 2. **Validate args**: epic-id (positional 1) + title (rest). If only one word, ask for the title. An optional `--spec SPEC-ID` names the covering spec โ€” put it into the rendered draft's `specs:` list (inline flow: `specs: ["SPEC-001"]`). Under `spec_policy: required` (vault's `.projectstore.json`), remind that every story needs a covering spec before implementation starts.
19
+ 2. **Validate args**: epic-id (positional 1) + title (rest). If only one word, ask for the title. An optional `--spec SPEC-ID` names the covering spec โ€” put it into the rendered draft's `specs:` list (inline flow: `specs: ["SPEC-001"]`). Under `spec_policy: required` (vault's `.projectstore.json`), remind that a story needs a covering spec before implementation starts, or a `no_spec` reason declared at the plan gate.
20
+
21
+ An optional `--variant test` makes a **test story**: one that plans the
22
+ tests for a spec's contracts, written to the `story.test` guide. Only
23
+ `test` is defined: refuse another value and name `test`. Remove `--variant test` and `--spec SPEC-ID` with its
24
+ value from the arguments before any `draft.mjs` call, in step 3 and in the
25
+ re-run of step 6: the script reads every remaining word as the title, so a
26
+ flag left in would end up in the title and the slug.
27
+
28
+ 2a. **Read the guide** for this kind before writing anything:
29
+
30
+ ```bash
31
+ node "${CLAUDE_PLUGIN_ROOT}/bin/projectstore.mjs" guide story --project "${CLAUDE_PROJECT_DIR}"
32
+ ```
33
+
34
+ For a test story read `guide story.test` instead, in the same form.
35
+
36
+ Write the draft to its `## Must`, `## Common mistakes`, `## Do not write`
37
+ and `## Length`: the critic checks the same `## Must` items. Exit 1 means
38
+ this kind has no guide; say so and go on.
20
39
 
21
40
  3. **Render draft**:
22
41
 
23
42
  ```bash
24
- node "${CLAUDE_PLUGIN_ROOT}/scripts/draft.mjs" story "$ARGUMENTS"
43
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/draft.mjs" story <epic-id> "<title>"
25
44
  ```
26
45
 
27
- The script fails if the epic folder does not exist. Surface the error and suggest `/projectstore:epic <id> "<title>"` first.
46
+ The epic id and the title only, with the flags of step 2 removed. The
47
+ script fails if the epic folder does not exist. Surface the error and suggest `/projectstore:epic <id> "<title>"` first.
48
+
49
+ 3a. **For a test story**, replace the draft's commented `# variant: test โ€ฆ`
50
+ line with `variant: test` before the preview, the way `--spec` fills
51
+ `specs:`. The critic then reviews the story against `story.test`.
28
52
 
29
53
  4. **Preview**: path + first ~25 lines.
30
54
 
@@ -32,9 +56,10 @@ the two cannot collide).
32
56
 
33
57
  When prompting "Edit", note that the story template has a `Decomposition` checklist โ€” if the user wants to seed it with concrete tasks from the current conversation, regenerate with those tasks pre-filled in place of the empty checkboxes.
34
58
 
35
- 6. **Post-approval race re-check** (Layer 1): re-run `draft.mjs story "$ARGUMENTS"` and re-read its `collision` field โ€” an exact-name `test -e` cannot see normalized cross-era collisions (`story-006-foo.md` vs `story-foo.md`). If `collision` is non-null, surface it as a topic collision (`"<identity>" already exists as <with>`), and ask: extend the existing story, pick a different slug (`-2` is a deliberate distinct identity), or cancel. Render `warnings` entries as `โš ๏ธ` lines in the preview too.
59
+ 6. **Post-approval race re-check** (Layer 1): re-run `draft.mjs story <epic-id> "<title>"` (the same stripped arguments as step 3) and re-read its `collision` field โ€” an exact-name `test -e` cannot see normalized cross-era collisions (`story-006-foo.md` vs `story-foo.md`). If `collision` is non-null, surface it as a topic collision (`"<identity>" already exists as <with>`), and ask: extend the existing story, pick a different slug (`-2` is a deliberate distinct identity), or cancel. Render `warnings` entries as `โš ๏ธ` lines in the preview too.
36
60
 
37
- 7. **On Yes** (path free): Write file.
61
+ 7. **On Yes** (path free): Write the file you previewed, with the step-2 and
62
+ step-3a edits (`specs:`, `variant: test`), not the re-run's raw draft.
38
63
 
39
64
  8. **Suggest next**: "Now decompose the work in the `Decomposition` section, or run `/projectstore:kanban` to refresh the board. Before implementation: `/projectstore:story plan <story>`."
40
65
 
@@ -42,12 +67,26 @@ the two cannot collide).
42
67
 
43
68
  1. **Resolve the story file** (second argument). Ambiguous โ†’ list candidates and ask.
44
69
 
70
+ 1a. **(plan only) A spec, or a reason.** When the vault's policy is
71
+ `required` and the story has neither a `specs:` entry nor a `no_spec`
72
+ reason, ask the user once: name the covering spec, or say in one sentence
73
+ why this story needs no spec (a release, a text or site change, work with
74
+ no non-trivial "how"). A reason becomes `--no-spec '<reason>'` in step 2 and
75
+ in the re-run of step 5, single-quoted (write an apostrophe inside it as
76
+ `'\''`). Research spikes take a light spec,
77
+ not a reason. A story that will touch three or more source files needs a
78
+ spec: the reviewer flags an opt-out like that at close.
79
+
45
80
  2. **Run the compute script** (pure โ€” writes nothing):
46
81
 
47
82
  ```bash
48
83
  node "${CLAUDE_PLUGIN_ROOT}/scripts/story-section.mjs" <plan|close> "<story-path>"
49
84
  ```
50
85
 
86
+ On a plan with a reason from step 1a, add `--no-spec '<reason>'` to that
87
+ command. It writes `no_spec` into the returned frontmatter, and it refuses
88
+ a story that already lists specs.
89
+
51
90
  It returns `{ path, changed, notes, content }`: section inserted when
52
91
  absent, status transition, lifecycle timestamps (`started_at` /
53
92
  `plan_updated_at` / `closed_at` โ€” stamped unconditionally; the
@@ -4,7 +4,10 @@ A spec's behavioral contracts are numbered and testable. This page shows how
4
4
  to write a contract so a test follows from it, how a test cites the contract
5
5
  it covers, and what doctor reports. It describes Part A of the ADR *Spec
6
6
  policy, revised: contract scenarios and test citations that doctor counts,
7
- and a declared per-story opt-out from a spec*.
7
+ and a declared per-story opt-out from a spec*, and decisions 6 and 7 of the
8
+ ADR *One authoring guide per artifact kind, read by the author before the
9
+ draft and by the critic after, overridable from the vault* (edge and failure
10
+ marks, and test stories).
8
11
 
9
12
  All of it is optional. A spec without scenarios, and a test without a
10
13
  citation, stay valid.
@@ -31,8 +34,75 @@ The items are a list, so Markdown keeps one step per line. The keywords stay
31
34
  in English in every language, like `โ€” stories:`: a tool matches them
32
35
  literally.
33
36
 
34
- Doctor reads scenarios for one thing only. If a contract's scenario has no
35
- `WHEN` (or `GIVEN`), or no `THEN`, it reports an info.
37
+ Doctor reads scenarios for two things. If a contract's scenario has no
38
+ `WHEN` (or `GIVEN`), or no `THEN`, it reports an info. And it counts the
39
+ scenarios marked as an edge or a failure case, below.
40
+
41
+ An item may wrap: a line indented deeper than its dash, before a blank line,
42
+ belongs to the item above it.
43
+
44
+ ## Marking an edge or a failure case
45
+
46
+ A scenario's `WHEN` or `GIVEN` item may end with `(edge)` or `(failure)`:
47
+
48
+ ```markdown
49
+ 3. **A stale index is reported.** Doctor compares each folder index with the
50
+ artifacts on disk and reports a row that no longer matches.
51
+ - GIVEN an index row whose status differs from the artifact's frontmatter
52
+ - WHEN doctor runs with --vault
53
+ - THEN it reports an index finding that names the folder
54
+ - GIVEN a folder whose README is missing (edge)
55
+ - WHEN doctor runs with --vault
56
+ - THEN it reports the missing index, and nothing else in that folder
57
+ ```
58
+
59
+ `(edge)` is for a case that comes from the input or the state: boundary
60
+ values, invalid input, a state transition, an upgrade from an older state.
61
+ `(failure)` is for a case where something else fails: a dependency, a retry
62
+ or a concurrent run, a partial failure, a rollback. A happy-path scenario
63
+ has no mark.
64
+
65
+ The mark is lowercase English in ASCII parentheses, at the very end of the
66
+ item (on its last line when the item wraps). A mark on an `AND` or `THEN`
67
+ item, in the contract's prose, inside backticks, or followed by more text
68
+ does not count.
69
+
70
+ For each active spec, doctor lists the contracts that carry scenarios and
71
+ have none marked: their scenarios show only the happy path. It counts the
72
+ marks and does not judge them. Whether a marked scenario is a real edge case
73
+ is the critic's question.
74
+
75
+ ## Writing a test story
76
+
77
+ A test story plans the tests for one or more contracts. Create it with the
78
+ variant flag, and its draft is written to the test lead's guide, `story.test`:
79
+
80
+ ```
81
+ /projectstore:story PS-X "Tests for the stale-index contract" --variant test
82
+ ```
83
+
84
+ The guide asks the story to name the contracts it covers by token, to list
85
+ the cases that apply to each (boundary values, invalid input, state
86
+ transitions, failure of a dependency, retry and concurrency, partial failure,
87
+ upgrade from an older state, rollback), to say which cases it leaves untested
88
+ and why, and to require a citation on every test it adds. For example:
89
+
90
+ ```markdown
91
+ ## Description
92
+
93
+ Covers [example#3]. The scenario shows the happy path; the cases below are
94
+ the ones a production vault hits.
95
+
96
+ ## Decomposition
97
+
98
+ - [ ] Boundary: an index with no rows, and one with a row per artifact.
99
+ - [ ] Invalid input: a row whose link points at no file.
100
+ - [ ] Partial failure: one folder's README unreadable, the others fine.
101
+ - [ ] Not tested: concurrency. Doctor is read-only, so two runs cannot race.
102
+ ```
103
+
104
+ The story has `variant: test` in its frontmatter and follows every other
105
+ story rule: the plan and close gates, evidence, the board.
36
106
 
37
107
  ## A contract no test can cover
38
108
 
@@ -97,6 +167,7 @@ skipped. Tests outside the bound project, or in a submodule, are not seen.
97
167
  | `citation-unknown` | warn | A token whose key is no spec's id or alias, or whose number is not a contract of that spec |
98
168
  | `citation-superseded` | info | A token that cites a superseded spec |
99
169
  | `scenario-shape` | info | A scenario without a WHEN/GIVEN or a THEN |
170
+ | `contract-happy-path-only` | info | One line per active spec: the contracts that carry scenarios and have none marked `(edge)` or `(failure)` |
100
171
  | `spec-alias` | issue | A duplicate alias, an alias equal to another spec's id, or the reserved `example` |
101
172
  | `evidence-citation` | warn | Under `lifecycle_gates: on`: a story's evidence names a token that no file in the project carries |
102
173