@pareto4/pp-core 1.19.0 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/agents/pp-phase-researcher.md +10 -0
  3. package/agents/pp-planner.md +15 -0
  4. package/agents/pp-vault-reviewer.md +2 -0
  5. package/agents/pp-verifier.md +12 -8
  6. package/commands/pp-discovery.md +3 -2
  7. package/gemini-extension.json +1 -1
  8. package/package.json +6 -3
  9. package/pareto-skills/_shared/pp-claude-md-protocol.md +1 -1
  10. package/pareto-skills/pp-project-setup/SKILL.md +18 -343
  11. package/pp-core/bin/lib/capability-registry.cjs +1 -1
  12. package/pp-core/bin/lib/discovery-access.cjs +276 -0
  13. package/pp-core/bin/lib/discovery-charter.cjs +664 -0
  14. package/pp-core/bin/lib/discovery-deviations.cjs +264 -0
  15. package/pp-core/bin/lib/discovery-entities.cjs +323 -0
  16. package/pp-core/bin/lib/discovery-for-phase.cjs +628 -0
  17. package/pp-core/bin/lib/discovery-integrations.cjs +286 -0
  18. package/pp-core/bin/lib/discovery-migration.cjs +246 -0
  19. package/pp-core/bin/lib/discovery-phases.cjs +233 -0
  20. package/pp-core/bin/lib/discovery-processes.cjs +355 -0
  21. package/pp-core/bin/lib/discovery-research-track.cjs +5 -4
  22. package/pp-core/bin/lib/discovery-rollup.cjs +8 -7
  23. package/pp-core/bin/lib/discovery-rules.cjs +216 -0
  24. package/pp-core/bin/lib/discovery-screens.cjs +1 -1
  25. package/pp-core/bin/lib/discovery-session-check.cjs +264 -0
  26. package/pp-core/bin/lib/discovery-stories.cjs +273 -0
  27. package/pp-core/bin/lib/discovery-sweep.cjs +1 -1
  28. package/pp-core/bin/lib/discovery-table.cjs +55 -0
  29. package/pp-core/bin/lib/io.cjs +22 -0
  30. package/pp-core/bin/lib/vault-standards-review.cjs +50 -2
  31. package/pp-core/bin/pp-tools.cjs +143 -1
  32. package/pp-core/references/discovery-access.md +112 -0
  33. package/pp-core/references/discovery-build-consumption.md +256 -0
  34. package/pp-core/references/discovery-charter.md +127 -0
  35. package/pp-core/references/discovery-data-model.md +145 -0
  36. package/pp-core/references/discovery-id-conventions.md +50 -14
  37. package/pp-core/references/discovery-integrations.md +151 -0
  38. package/pp-core/references/discovery-processes.md +190 -0
  39. package/pp-core/references/discovery-rebaseline.md +2 -2
  40. package/pp-core/references/discovery-research-track.md +5 -6
  41. package/pp-core/references/discovery-session-output.md +70 -0
  42. package/pp-core/references/discovery-standards.md +107 -0
  43. package/pp-core/references/discovery-traceability.md +2 -2
  44. package/pp-core/references/planner-discovery-extract.md +35 -0
  45. package/pp-core/references/verifier-discovery-conformance.md +36 -0
  46. package/pp-core/templates/project-charter.md +161 -100
  47. package/pp-core/templates/project.md +3 -3
  48. package/pp-core/templates/requirements.md +18 -0
  49. package/pp-core/templates/verification-report.md +16 -0
  50. package/pp-core/workflows/discovery-sprint/charter.md +114 -0
  51. package/pp-core/workflows/discovery-sprint/prefill.md +1 -1
  52. package/pp-core/workflows/discovery-sprint/prototype.md +4 -4
  53. package/pp-core/workflows/discovery-sprint/session-13-gates.md +10 -0
  54. package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +5 -2
  55. package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +27 -5
  56. package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +56 -31
  57. package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +1 -1
  58. package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +42 -19
  59. package/pp-core/workflows/discovery-sprint/sessions/06-security.md +27 -12
  60. package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +41 -23
  61. package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +50 -23
  62. package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +26 -11
  63. package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +28 -9
  64. package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +21 -0
  65. package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +24 -9
  66. package/pp-core/workflows/discovery-sprint.md +12 -15
  67. package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +80 -29
  68. package/pp-core/workflows/discovery-to-build/steps/{screen-inventory-gate.md → handoff-gates.md} +111 -3
  69. package/pp-core/workflows/discovery-to-build/templates/discovery-references.md +12 -9
  70. package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +27 -26
  71. package/pp-core/workflows/discovery-to-build.md +70 -34
  72. package/pp-core/workflows/discuss-phase/discovery.md +83 -0
  73. package/pp-core/workflows/discuss-phase/templates/context.md +4 -0
  74. package/pp-core/workflows/discuss-phase.md +10 -7
  75. package/pp-core/workflows/new-project.md +3 -3
  76. package/pp-core/workflows/plan-phase/steps/discovery-extract.md +41 -0
  77. package/pp-core/workflows/plan-phase.md +15 -10
  78. package/pp-core/workflows/vault-review.md +5 -0
  79. package/pp-core/workflows/discovery-sprint/templates/context-template.md +0 -272
@@ -8,7 +8,7 @@
8
8
  # Discovery Sprint Synthesis — pp-core Handoff
9
9
 
10
10
  > Auto-generated from {completed_count}/13 completed Discovery Sprint sessions.
11
- > Source: .planning/discovery/_context.md + individual session files
11
+ > Source: the session files and the registers under .planning/discovery/
12
12
  > Generated: {date}
13
13
 
14
14
  ---
@@ -50,32 +50,31 @@ application — what it does, who it's for, why it matters}
50
50
  {From Session 3: EPICs and user stories, structured for requirements generation. When
51
51
  `_requirements.md` exists it is the requirement source — it holds what prototype feedback and the
52
52
  element sweep added: carry every `MVP` and `Later` row, and list each `Dropped` row under Out of
53
- Scope with its decision}
53
+ Scope with its decision. IDs are the ones discovery minted — `references/discovery-id-conventions.md`:
54
+ `<PREFIX>-nn`/`N-nn`/`T-nn` requirements, `E-nn` EPICs, `US-nn` stories — never a `FR-`/`NFR-`/`EPIC-`
55
+ ID of this document's own}
54
56
 
55
57
  ### EPIC Registry
56
58
  | ID | Title | Priority | Phase | Stories |
57
59
  |----|-------|----------|-------|---------|
58
- | {epic-id} | {title} | {must/should/could} | {phase} | {count} |
60
+ | {E-nn} | {title} | {must/should/could} | {phase} | {count} |
59
61
 
60
62
  ### Requirements by EPIC
61
63
 
62
- #### {EPIC-001}: {Title}
64
+ #### {E-nn}: {Title}
63
65
  {Brief EPIC description}
64
66
 
67
+ **Requirements:** {the `_requirements.md` IDs this EPIC groups — `<PREFIX>-nn`, `N-nn`, `T-nn`}
68
+
65
69
  **User Stories:**
66
70
  | ID | Story | Priority | Acceptance Criteria Summary |
67
71
  |----|-------|----------|---------------------------|
68
- | {us-id} | As a {role}, I want {goal} so that {benefit} | {priority} | {brief AC} |
72
+ | {US-nn} | As a {role}, I want {goal} so that {benefit} | {priority} | {brief AC} |
69
73
 
70
74
  ### Non-Functional Requirements
71
75
  | ID | Category | Requirement | Target |
72
76
  |----|----------|-------------|--------|
73
- | {nfr-id} | {Performance/Security/Usability/Availability} | {requirement} | {target} |
74
-
75
- ### Business Rules
76
- | ID | Rule | Applies To |
77
- |----|------|------------|
78
- | {br-id} | {rule} | {module/scope} |
77
+ | {N-nn} | {Performance/Security/Usability/Availability} | {requirement} | {target} |
79
78
 
80
79
  ---
81
80
 
@@ -138,14 +137,14 @@ row for row — never summarise them. Without a screen inventory or prototype, w
138
137
  {From Session 6: data classification, compliance, encryption, auth, audit, SLA}
139
138
 
140
139
  ## User Roles & Identity
141
- {From Session 7: RBAC roles + permissions, identity provider}
140
+ {From `.planning/discovery/_roles.md` (§ Roles, § Permissions, § Screens) when it exists, else Session 7's RBAC Matrix; identity provider from Session 7 § IdP Integration Design}
142
141
 
143
142
  | Role | Description | Key Permissions |
144
143
  |------|-------------|-----------------|
145
144
  | {role} | {description} | {permissions} |
146
145
 
147
146
  ## Integrations
148
- {From Session 8: external systems, direction, protocol, data, phase}
147
+ {From `.planning/discovery/_integrations.md` § Interfaces when it exists (one row per `IF-nn`: system, direction, protocol, format), else Session 8's Integration Design Register; phase from `_phases.md`. Migration from `.planning/discovery/_migration.md` when it exists}
149
148
 
150
149
  | System | Direction | Protocol | Data | Phase |
151
150
  |--------|-----------|----------|------|-------|
@@ -207,20 +206,22 @@ list each parked question verbatim, honestly, as a known gap — never silently
207
206
 
208
207
  | Topic | Primary Source | Secondary Sources |
209
208
  |-------|---------------|-------------------|
210
- | Business context & vision | `.planning/discovery/session-01.md` | `.planning/discovery/_context.md` §1 |
211
- | Current state & pain points | `.planning/discovery/session-02.md` | `.planning/discovery/_context.md` §2 |
212
- | Requirements & user stories | `.planning/discovery/session-03.md` | `.planning/discovery/_context.md` §3 |
213
- | UX design principles | `.planning/discovery/session-04.md` | `.planning/discovery/_context.md` §4 |
209
+ | Business context & vision | `.planning/discovery/session-01.md` | `.planning/discovery/_requirements.md` § Prefix Registry |
210
+ | Current state & pain points | `.planning/discovery/session-02.md` | `.planning/discovery/_processes.md`, `_entities.md`, `_glossary.md` |
211
+ | Requirements & user stories | `.planning/discovery/session-03.md` | `.planning/discovery/_requirements.md`, `_stories.md`, `_rules.md` |
212
+ | UX design principles | `.planning/discovery/session-04.md` | `.planning/discovery/_screens.md` |
214
213
  | Requirement register | `.planning/discovery/_requirements.md` | `.planning/discovery/session-03.md` |
215
214
  | Screens | `.planning/discovery/_screens.md` | `.planning/discovery/session-04.md` |
216
215
  | Prototype | `.planning/discovery/prototype/` | `.planning/discovery/_feedback.md`, `.planning/discovery/_sweep.md` |
217
- | Architecture & tech stack | `.planning/discovery/session-05.md` | `.planning/discovery/_context.md` §5 |
218
- | Security & compliance | `.planning/discovery/session-06.md` | `.planning/discovery/_context.md` §6 |
219
- | Roles & identity | `.planning/discovery/session-07.md` | `.planning/discovery/_context.md` §7 |
220
- | Integrations | `.planning/discovery/session-08.md` | `.planning/discovery/_context.md` §8 |
221
- | QA & testing | `.planning/discovery/session-09.md` | `.planning/discovery/_context.md` §9 |
222
- | Infrastructure & deployment | `.planning/discovery/session-10.md` | `.planning/discovery/_context.md` §10 |
223
- | Roadmap & release plan | `.planning/discovery/session-11.md` | `.planning/discovery/_context.md` §11 |
224
- | Team & delivery model | `.planning/discovery/session-12.md` | `.planning/discovery/_context.md` §12 |
225
- | Wrap-up & go/no-go | `.planning/discovery/session-13.md` | `.planning/discovery/_context.md` §13 |
216
+ | Architecture & tech stack | `.planning/discovery/session-05.md` | `.planning/discovery/_entities.md`, `_integrations.md`, `_deviations.md` |
217
+ | Security & compliance | `.planning/discovery/session-06.md` | `.planning/discovery/_entities.md` (classification, retention), `_deviations.md` |
218
+ | Roles & identity | `.planning/discovery/_roles.md` | `.planning/discovery/session-07.md` |
219
+ | Integrations | `.planning/discovery/_integrations.md` | `.planning/discovery/session-08.md` |
220
+ | Migration | `.planning/discovery/_migration.md` | `.planning/discovery/session-02.md`, `session-08.md` |
221
+ | Deviations from standards | `.planning/discovery/_deviations.md` | the sessions' **Standards Applied** tables |
222
+ | QA & testing | `.planning/discovery/session-09.md` | the **Standards Applied** table |
223
+ | Infrastructure & deployment | `.planning/discovery/session-10.md` | the **Standards Applied** table |
224
+ | Roadmap & release plan | `.planning/discovery/session-11.md` | `.planning/discovery/_phases.md` |
225
+ | Team & delivery model | `.planning/discovery/session-12.md` | `.planning/discovery/session-01.md` **Sprint Logistics** |
226
+ | Wrap-up & go/no-go | `.planning/discovery/session-13.md` | `docs/discovery/PROJECT-CHARTER.md` |
226
227
  ```
@@ -21,6 +21,7 @@ Valid pp-core subagent types (use exact names — do not fall back to 'general-p
21
21
  <context>
22
22
  **Flags (parse from `$ARGUMENTS`):**
23
23
  - `--skip-validation` — Skip the Discovery completion check (use when sessions are intentionally incomplete). Does NOT skip the screen-inventory gate, which hard-blocks on structural faults (D-53).
24
+ - `--unsigned` — Start the build although `docs/discovery/PROJECT-CHARTER.md` is not `Signed` or `Signed with conditions`, or does not exist (an engagement that predates the charter). The gap is recorded in PROJECT.md's Key Decisions, STATE.md's Blockers/Concerns and the handoff summary. A charter with structural faults still blocks.
24
25
  - `--scaffold` — After initialization, also scaffold lightweight application structure from the Session 5 tech stack
25
26
  - `--text` — Text mode: render every interactive prompt as a plain-text numbered list (for non-Claude runtimes)
26
27
 
@@ -102,8 +103,8 @@ write `.planning/discovery/session-NN.md`: <!-- legacy-read-target -->
102
103
  - Preserve `status`, `completed_date`, and `completeness_score` frontmatter fields where
103
104
  present in the legacy file; normalize any missing fields to the current session
104
105
  template's defaults (do not blind-copy — read what exists, fill gaps honestly).
105
- - Copy the legacy progress and context files to `.planning/discovery/_context.md` and
106
- `.planning/discovery/_progress.md` respectively <!-- legacy-read-target -->, adding a
106
+ - Copy the legacy progress file to `.planning/discovery/_progress.md` <!-- legacy-read-target -->
107
+ (a legacy context file is a copy of the session tables — leave it, it is not read), adding a
107
108
  `Parked` column to the progress table (default 0) if the legacy schema predates it.
108
109
 
109
110
  **Path safety (T-04-03, reused verbatim):** Reject any source or destination path that is
@@ -132,10 +133,11 @@ Or use /pp-progress to continue where you left off.
132
133
 
133
134
  **Step 2: Validate Discovery completion**
134
135
 
135
- **Screen-inventory contract gate (D-53), with the feedback and element-sweep gates.**
136
- `Read(workflows/discovery-to-build/steps/screen-inventory-gate.md)` and run it end-to-end before
136
+ **Screen-inventory contract gate (D-53), with the feedback, element-sweep and signed-charter gates.**
137
+ `Read(workflows/discovery-to-build/steps/handoff-gates.md)` and run it end-to-end before
137
138
  anything else in this step. These are hard stops: report what the gate prints and do not continue.
138
- `--skip-validation` does not cover them. Only when every gate passes, go on with the completion check
139
+ `--skip-validation` does not cover them; `--unsigned` covers only the signature requirement of the
140
+ charter gate and records the gap. Only when every gate passes, go on with the completion check
139
141
  below.
140
142
 
141
143
  Read `.planning/discovery/_progress.md` and parse the Session Progress table. Count sessions by
@@ -213,13 +215,20 @@ them into a single document optimized for the pp-core new-project generators.
213
215
 
214
216
  Read these files (skip any that don't exist):
215
217
 
216
- 1. `.planning/discovery/_context.md` — accumulated cross-session context (primary source)
218
+ 1. All 13 session files in `.planning/discovery/session-NN.md` — their Notes Template sections are the primary source; the session-output gate in `steps/handoff-gates.md` proves each present and filled
217
219
  2. `.planning/discovery/_progress.md` — session completion status
218
- 3. All 13 session files in `.planning/discovery/session-NN.md` — for detail not captured in `_context.md`
219
- 4. The Project Definition document (glob for `*-Project-Definition.md` in root)
220
+ 3. The registers under item 6 — the canonical rows the session tables point at
221
+ 4. Legacy only: a `*-Project-Definition.md` in the repository root, left by the pre-charter
222
+ `pareto-project-setup` scaffold — projects set up since have none
220
223
  5. `.planning/discovery/prototype/README.md` — if a prototype exists (built by `/pp-discovery prototype`), note its state
221
224
  6. `.planning/discovery/_requirements.md`, `.planning/discovery/_screens.md`,
222
225
  `.planning/discovery/_feedback.md` and `.planning/discovery/_sweep.md`
226
+ 7. `.planning/discovery/_stories.md`, `.planning/discovery/_phases.md`,
227
+ `.planning/discovery/_entities.md`, `.planning/discovery/_processes.md`,
228
+ `.planning/discovery/_rules.md`, `.planning/discovery/_roles.md`,
229
+ `.planning/discovery/_integrations.md`, `.planning/discovery/_migration.md` and
230
+ `.planning/discovery/_deviations.md` — the registers Steps 5e and 5f copy from
231
+ (`references/discovery-build-consumption.md`)
223
232
 
224
233
  **Spawn an Explore agent to read all session files in parallel** and extract every
225
234
  populated Notes Template table, all Key Decisions tables, all Action Items, and any
@@ -236,9 +245,11 @@ those generators expect.
236
245
  **Synthesis rules:**
237
246
  - Use actual content from the session files, never placeholders
238
247
  - If a session is incomplete, note `[Session N incomplete — content pending]` in that section
239
- - Preserve requirement IDs (FR-xxx, NFR-xxx, US-xxx, EPIC-xxx) exactly as defined
248
+ - Preserve IDs exactly as discovery minted them — `<PREFIX>-nn` domain rows and `N-`/`T-`
249
+ rows from `_requirements.md`, `E-nn` EPICs and `US-nn` stories from Session 3
250
+ (`references/discovery-id-conventions.md`); never mint `FR-`/`NFR-`/`EPIC-` IDs
240
251
  - Preserve role names (Session 7) and technology choices (Session 5) exactly
241
- - If the Project Definition document has content not in `_context.md`, merge it in
252
+ - If a legacy Project Definition document has content the session files lack, merge it in
242
253
  - Keep it factual — no interpretation or recommendations, just structured outputs
243
254
  - List every unresolved parked question from Step 2's D-12 scan verbatim in the Parked
244
255
  Questions (Unresolved) table — never inflate completeness by omitting them
@@ -251,7 +262,7 @@ those generators expect.
251
262
  AskUserQuestion([
252
263
  {
253
264
  header: "Handoff Ready",
254
- question: "I've synthesized your Discovery Sprint into .planning/discovery/_pp-handoff.md.\n\nSummary:\n- {epic_count} EPICs, {story_count} user stories\n- {fr_count} functional / {nfr_count} non-functional requirements\n- Tech stack: {stack_summary}\n- {role_count} user roles, {integration_count} integrations, {phase_count} phases\n- {incomplete_sessions} incomplete sessions (if any)\n\nReview the file and confirm to proceed with pp-core initialization.",
265
+ question: "I've synthesized your Discovery Sprint into .planning/discovery/_pp-handoff.md.\n\nSummary:\n- {epic_count} EPICs (E-), {story_count} user stories (US-)\n- {req_count} requirements by prefix: {one count per registered prefix, e.g. K- 12 · N- 4 · T- 3}\n- Tech stack: {stack_summary}\n- {role_count} user roles, {integration_count} integrations, {phase_count} phases\n- {incomplete_sessions} incomplete sessions (if any)\n\nReview the file and confirm to proceed with pp-core initialization.",
255
266
  multiSelect: false,
256
267
  options: [
257
268
  { label: "Initialize pp-core", description: "Generate .planning/ from this handoff document (Recommended)" },
@@ -336,9 +347,15 @@ pp_run commit "chore: add project config" --files .planning/config.json
336
347
 
337
348
  Read `.planning/discovery/_pp-handoff.md` and synthesize `.planning/PROJECT.md` using the pp-core
338
349
  project template structure: use "What We're Building" as the description, include all
339
- Key Decisions, list requirements in Validated/Active/Out-of-Scope form, and reference
350
+ Key Decisions with their `D-<ss>-<n>` in the table's **ID** column, list requirements in
351
+ Validated/Active/Out-of-Scope form, and reference
340
352
  Discovery artifacts (the section is added in Step 6a).
341
353
 
354
+ **Unsigned charter (`--unsigned`).** When the charter gate passed on `--unsigned`, add one Key
355
+ Decisions row: `| — | Build started on an unsigned Project Charter (status: {CHARTER_STATE}) |
356
+ --unsigned passed to /pp-discovery-to-build; sign-off still owed | ⚠️ Revisit |`. Nothing in
357
+ PROJECT.md may read as if the charter were signed.
358
+
342
359
  **Init deferral (D-07-03, OD-2).** Before writing the file, Read
343
360
  `pp-core/workflows/init/steps/project-md-deferral-narration.md` and follow it — the single
344
361
  rendering of the reachability-proof deferral `/pp-init` recorded, silent when none is on
@@ -358,16 +375,24 @@ pp_run commit "docs: initialize project from Discovery Sprint" --files .planning
358
375
 
359
376
  ### 5e. Generate REQUIREMENTS.md
360
377
 
361
- From the Functional Requirements section: map EPICs to requirement groups, user stories
362
- to individual requirements, include NFRs and Business Rules, preserve all original IDs
363
- (FR-xxx, NFR-xxx, US-xxx), and mark all requirements active.
378
+ From the Functional Requirements section: map EPICs (`E-nn`) to requirement groups, carry
379
+ every `_requirements.md` row under its EPIC with its own ID (`<PREFIX>-nn`, `N-nn`, `T-nn`)
380
+ and the `US-nn` stories from `_stories.md` that realise it, preserve every ID as minted — never
381
+ renumber, never invent `FR-`/`NFR-`/`EPIC-` IDs — and mark all requirements active.
382
+
383
+ **Discovery row shape (F-1):** a requirement line keeps what the sprint recorded. Use the
384
+ discovery variant of `pp-core/templates/requirements.md`: the description is followed by
385
+ ` — <MoSCoW> · <Disposition> · <Provenance>` copied from the `_requirements.md` row, and the
386
+ acceptance criteria follow on an indented `- AC:` line, verbatim. `MVP` rows go under
387
+ `## v1 Requirements`, `Later` rows under `## v2 Requirements`, `Dropped (…)` rows under
388
+ `## Out of Scope` with the killing decision as the reason. Nothing is summarised.
364
389
 
365
- **Inline source refs (D-05):** Every generated requirement line — FR/NFR/EPIC/US — carries
366
- a trailing `(source: session-NN §Section)` ref at point of use, e.g. `FR-012: User can
390
+ **Inline source refs (D-05):** Every generated line — requirement, EPIC or story — carries
391
+ a trailing `(source: session-NN §Section)` ref at point of use, e.g. `K-12: User can
367
392
  export a report as CSV (source: session-03 §Order Intake)`, naming the canonical
368
393
  `.planning/discovery/session-NN.md` file and section it was derived from. Then append one
369
394
  `## Discovery Traceability` table (same shape as Step 3b's table) mapping each requirement
370
- category (Authentication, EPIC group, NFRs, Business Rules, …) to its canonical
395
+ group (registered prefix, EPIC, `N-` rows, …) to its canonical
371
396
  `.planning/discovery/session-NN.md` source(s) — the file-level map that complements the
372
397
  per-item inline refs above.
373
398
 
@@ -377,29 +402,37 @@ pp_run commit "docs: requirements from Discovery Sprint" --files .planning/REQUI
377
402
 
378
403
  ### 5f. Generate ROADMAP.md
379
404
 
380
- From the Roadmap & Phasing section: map Discovery phases to pp-core phases, derive phase
381
- goals from EPIC scope, set dependencies from build-order preferences, and include the
382
- milestone name (Session 11, or default "v1.0 — MVP").
383
-
384
- **Canonical refs producer (D-06):** For every generated phase entry, emit a
385
- `**Canonical refs:** .planning/discovery/session-NN.md, ...` line listing every canonical
386
- session file that fed that phase's requirements — placed immediately after the
387
- `**Requirements**:` line and before `**Success Criteria**`, per `pp-core/templates/roadmap.md`'s
388
- phase-entry field order:
405
+ **From `_phases.md`, verbatim (F-5):** when `.planning/discovery/_phases.md` exists (every
406
+ engagement since Session 11's Closing Step wrote one — the handoff gate has already run
407
+ `phases-check` on it), each row IS one pp-core phase: `Phase` → the phase number, `Goal` →
408
+ `**Goal**:` verbatim, `Depends on` → `**Depends on**:` (`—` → `Nothing (first phase)`),
409
+ `Requirement IDs` → `**Requirements**:` verbatim, each ` · `-separated success criterion → one
410
+ numbered `**Success Criteria**` line. Derive nothing: a phase the table does not have does not
411
+ exist. Only without `_phases.md` (a legacy engagement) fall back to the Roadmap & Phasing
412
+ section: map Discovery phases to pp-core phases, derive goals from EPIC scope and dependencies
413
+ from build-order preferences. Either way include the milestone name (Session 11, or default
414
+ "v1.0 — MVP").
415
+
416
+ **Canonical refs producer (D-06, artifact paths — R1):** for every phase entry run
417
+ `pp_run query discovery.for-phase <N> --raw` and emit a `**Canonical refs:**` line listing the
418
+ payload's `artifacts` — the discovery registers that carry a row for this phase — placed
419
+ immediately after the `**Requirements**:` line and before `**Success Criteria**`, per
420
+ `pp-core/templates/roadmap.md`'s phase-entry field order:
389
421
 
390
422
  ```markdown
391
423
  ### Phase [N]: [Name]
392
424
  **Goal**: [What this phase delivers]
393
425
  **Depends on**: [...]
394
426
  **Requirements**: [REQ-01, REQ-02]
395
- **Canonical refs:** .planning/discovery/session-03.md, .planning/discovery/session-05.md
427
+ **Canonical refs:** .planning/discovery/_requirements.md, .planning/discovery/_processes.md
396
428
  **Success Criteria** (what must be TRUE):
397
429
  ```
398
430
 
399
- Use the exact label string `Canonical refs:` — the existing `discuss-phase.md:313` consumer
400
- already copies this line unchanged into `CONTEXT.md`'s canonical refs accumulator. Do not
401
- modify `discuss-phase.md`, the researcher, or the planner — this workflow is the first
402
- *producer* of a line those consumers already read.
431
+ Use the exact label string `Canonical refs:` — `discuss-phase.md` copies this line into
432
+ `CONTEXT.md`'s canonical refs accumulator. Never name a `session-NN.md` here: the build reads
433
+ the registers through `for-phase`, not the facilitation record
434
+ (`references/discovery-build-consumption.md`). When the payload's `artifacts` is empty, write
435
+ `**Canonical refs:** none — no discovery row cites this phase` so the gap is visible.
403
436
 
404
437
  ```bash
405
438
  pp_run commit "docs: roadmap from Discovery Sprint" --files .planning/ROADMAP.md
@@ -417,7 +450,8 @@ roadmapper agent uses). Populate it from what Step 5f already established:
417
450
  - **Current Position:** Phase 1 of N, "Ready to plan", today's date, 0% progress bar
418
451
  - **Accumulated Context › Decisions:** none yet (fresh project)
419
452
  - **Accumulated Context › Blockers/Concerns:** any unresolved parked questions carried
420
- forward from Step 2's D-12 confirmation (see below), so they stay visible after handoff
453
+ forward from Step 2's D-12 confirmation (see below), so they stay visible after handoff; and,
454
+ when the charter gate passed on `--unsigned`, `Project Charter not signed (status: {CHARTER_STATE})`
421
455
  - **Session Continuity:** last session = now, stopped at "Discovery handoff complete", no
422
456
  resume file
423
457
 
@@ -533,9 +567,11 @@ Created:
533
567
  .planning/github-issues.json Requirement → GitHub issue mapping (if pushed)
534
568
  CLAUDE.md Updated with Discovery references
535
569
 
570
+ Project Charter: docs/discovery/PROJECT-CHARTER.md — {CHARTER_STATE}{, started on --unsigned: sign-off still owed}
571
+
536
572
  Discovery Traceability:
537
573
  Discovery sessions → _pp-handoff.md → pp-core artifacts → (optional) GitHub issues
538
- Requirement IDs (FR-xxx, US-xxx) carry through the full chain
574
+ Requirement IDs (<PREFIX>-nn, N-, E-, US-) carry through the full chain unchanged
539
575
 
540
576
  Next steps:
541
577
  1. Run /pp-plan-phase 1 to create the first phase plan
@@ -0,0 +1,83 @@
1
+ # Discuss-phase — Discovery extract and the R2 amend rule
2
+
3
+ > Lazy-loaded from `workflows/discuss-phase.md` (`analyze_phase` 1b, `discuss_areas`, `write_context`).
4
+ > Inert on a project without `.planning/discovery/`: every command below exits 0 with nothing to
5
+ > inject, and nothing in this file runs. Contract: `references/discovery-build-consumption.md`.
6
+
7
+ ## A. Render the extract (analyze_phase, before 1b)
8
+
9
+ ```bash
10
+ _PP_SHIM_NAME="pp-tools.cjs"; _pp_root() { ( for _v in $(env | sed -n 's/^\(GIT_[A-Za-z0-9_]*\)=.*/\1/p'); do unset "$_v"; done; _c=$(git rev-parse --git-common-dir 2>/dev/null); if [ "${_c##*/}" = .git ] && cd "$_c/.." 2>/dev/null; then pwd -P; else git rev-parse --show-toplevel 2>/dev/null || pwd; fi ); }; pp_run() { case "$PP_TOOLS" in *.cjs) node "$PP_TOOLS" "$@";; *) "$PP_TOOLS" "$@";; esac; }; _PP_RUNTIME_ROOT="${RUNTIME_DIR:-$(_pp_root)}"; PP_TOOLS="${_PP_RUNTIME_ROOT}/pp-core/bin/${_PP_SHIM_NAME}"; if [ -f "$PP_TOOLS" ]; then :; elif [ -f "${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}"; elif command -v pp-tools >/dev/null 2>&1; then PP_TOOLS="$(command -v pp-tools)"; else echo "ERROR: pp-tools.cjs not found at $PP_TOOLS and pp-tools is not on PATH. Run: npx -y @pareto4/pp-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${PP_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${PP_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
11
+ DISCOVERY_JSON=$(pp_run query discovery.for-phase "${PHASE}" 2>/dev/null || true)
12
+ if [[ "$DISCOVERY_JSON" == @file:* ]]; then DISCOVERY_JSON=$(cat "${DISCOVERY_JSON#@file:}"); fi
13
+ DISCOVERY_PRESENT=$(printf '%s' "$DISCOVERY_JSON" | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{try{const o=JSON.parse(s);console.log(o.present===true&&o.ok===true?'true':'false')}catch{console.log('false')}})")
14
+ if [ "$DISCOVERY_PRESENT" = true ]; then
15
+ DISCOVERY_EXTRACT=$(pp_run query discovery.for-phase "${PHASE}" --markdown)
16
+ DISCOVERY_ARTIFACTS=$(printf '%s' "$DISCOVERY_JSON" | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const o=JSON.parse(s);console.log((o.artifacts||[]).join(', '))})")
17
+ echo "DISCOVERY_ARTIFACTS=${DISCOVERY_ARTIFACTS}"
18
+ fi
19
+ ```
20
+
21
+ A non-zero exit here is a structural fault in a discovery artifact (`discovery_for_phase_failed`):
22
+ print the fault list and stop — the sprint's own check names the row to fix; planning on a
23
+ malformed register copies the malformation into the build.
24
+
25
+ When `DISCOVERY_PRESENT` is `true` (the project ran the sprint — even when the extract says
26
+ `Requirement IDs: none resolved`, which tells the planner that ROADMAP.md names no requirement
27
+ IDs for this phase and is worth seeing):
28
+
29
+ - **Canonical refs are artifact paths.** Add every path in `DISCOVERY_ARTIFACTS` to the canonical
30
+ refs accumulator. Never add a `.planning/discovery/session-NN.md`: if ROADMAP.md's
31
+ `Canonical refs:` line names one (a pre-Batch-4 roadmap), replace it with the artifact paths.
32
+ - **Answered by Discovery.** Before proposing a gray area, read the extract. A question the extract
33
+ answers — a field, a rule, a role, a flow step, a screen, an acceptance criterion — is
34
+ pre-answered: list it under **Answered by Discovery** in `present_gray_areas` with the row key
35
+ (`_rules.md BR-02`), and do not ask it. The test project's "the assistant asked what Discovery
36
+ had answered" finding is the defect this closes.
37
+ - Gray areas are the gaps the extract leaves (an implementation choice no row decides) and the
38
+ rows that contradict each other or the codebase.
39
+
40
+ ## B. Write the extract into CONTEXT.md (write_context)
41
+
42
+ When `DISCOVERY_PRESENT` is `true`, add this section after `<canonical_refs>`, the extract pasted
43
+ byte for byte — markers included, nothing edited:
44
+
45
+ ```markdown
46
+ <discovery_extract>
47
+ ## Discovery Extract
48
+
49
+ **Rows of the Discovery registers that cite this phase's requirement IDs. Downstream agents read
50
+ these before planning; the acceptance criteria are the UAT.**
51
+
52
+ ${DISCOVERY_EXTRACT}
53
+
54
+ </discovery_extract>
55
+ ```
56
+
57
+ The extract is a render, not a record: a later `/pp-plan-phase` renders it again from the
58
+ registers, so a hand edit here is lost by design (R2 — the register is the source).
59
+
60
+ ## C. R2 — a decision that changes a discovery fact
61
+
62
+ When a decision taken in `discuss_areas` changes something a register records (a field, a rule, a
63
+ role, a flow step, a screen, an acceptance criterion, a phase's requirement set):
64
+
65
+ 1. **Amend the register row in place.** Edit the cell in the artifact (`_entities.md`,
66
+ `_rules.md`, `_processes.md`, `_screens.md`, `_stories.md`, `_requirements.md`, `_phases.md`,
67
+ `_roles.md`, `_integrations.md`, `_migration.md`, `_deviations.md`)
68
+ and append `→ amended by D-P${PADDED_PHASE}-<n>` to it, `<n>` being the decision's sequence in
69
+ this CONTEXT.md. Never add a second row for the new fact, never strike the old cell: one row,
70
+ amended.
71
+ 2. **Re-run the artifact's check** — `pp_run query discovery.entity-check`, `process-check`,
72
+ `rules-check`, `screen-check`, `stories-check`, `phases-check`, `roles-check`,
73
+ `integrations-check`, `migration-check`, `deviations-check`, or `rollup --check` for
74
+ `_requirements.md` — exit 0 before continuing. A build decision that departs from a vault
75
+ standard is a new `DEV-` row of `_deviations.md` with `Decision` = `D-P${PADDED_PHASE}-<n>`.
76
+ 3. **Bump the charter.** In `docs/discovery/PROJECT-CHARTER.md` raise `version` and add a § 20
77
+ Version history row naming `D-P${PADDED_PHASE}-<n>` and the row amended; run
78
+ `pp_run query discovery.charter-check`. A signed charter is not silently superseded.
79
+ 4. **Re-render.** Run step A again so `DISCOVERY_EXTRACT` carries the amended cell; the decision
80
+ itself is recorded in `<decisions>` as usual, with the row key it amended.
81
+
82
+ CONTEXT.md and PLAN.md hold the extract, never an override: a decision written only in
83
+ `<decisions>` while the register says otherwise is the drift this rule exists to prevent.
@@ -91,6 +91,10 @@ Every entry needs a full relative path — not just a name.]
91
91
 
92
92
  </canonical_refs>
93
93
 
94
+ [Include `<discovery_extract>` only when `DISCOVERY_PRESENT` is true (workflows/discuss-phase/discovery.md § B):
95
+ the `pp_run query discovery.for-phase` render pasted byte for byte between its `<!-- discovery:auto -->` markers.
96
+ Omit the whole block on a project without .planning/discovery/.]
97
+
94
98
  <code_context>
95
99
  ## Existing Code Insights
96
100
 
@@ -229,7 +229,7 @@ If a checkpoint file exists:
229
229
 
230
230
  **If `--auto`:** Auto-select "Resume" — load checkpoint and continue from last completed area.
231
231
 
232
- **Otherwise:** AskUserQuestion (header: "Resume"; question: "Found interrupted discussion checkpoint ({N} areas completed out of {M}). Resume from where you left off?"; options: "Resume" / "Start fresh"). On "Resume", parse the checkpoint JSON, load `decisions` into the internal accumulator, set `areas_completed` to skip those areas, continue to `present_gray_areas` with only the remaining areas. On "Start fresh", delete the checkpoint and continue.
232
+ **Otherwise:** AskUserQuestion (header: "Resume"; question: "Found interrupted discussion checkpoint ({N} areas completed out of {M}). Resume from where you left off?"; options: "Resume" / "Start fresh"). On "Resume", parse the checkpoint JSON, load `decisions` into the accumulator, skip the `areas_completed` areas, continue to `present_gray_areas` with the rest. On "Start fresh", delete the checkpoint and continue.
233
233
 
234
234
  Check `has_plans` and `plan_count` from init. **If `has_plans` is true:**
235
235
 
@@ -314,8 +314,10 @@ Analyze the phase to identify gray areas. Use both `prior_decisions` and `codeba
314
314
 
315
315
  1. **Domain boundary** — What capability is this phase delivering? State it clearly.
316
316
 
317
+ 1a. **Discovery extract** — Read and run `workflows/discuss-phase/discovery.md` § A: it renders the discovery register rows citing this phase's requirement IDs; questions they answer are pre-answered. Inert without `.planning/discovery/`.
318
+
317
319
  1b. **Initialize canonical refs accumulator** — Start building `<canonical_refs>` for CONTEXT.md. Sources:
318
- - **Now:** Copy `Canonical refs:` from ROADMAP.md for this phase. Expand each to a full relative path. Check REQUIREMENTS.md and PROJECT.md for specs/ADRs referenced.
320
+ - **Now:** Copy `Canonical refs:` from ROADMAP.md for this phase (artifact paths, not session files). Expand each to a full relative path. Check REQUIREMENTS.md and PROJECT.md for specs/ADRs referenced.
319
321
  - **`scout_codebase`:** If existing code references docs (e.g., comments citing ADRs), add those.
320
322
  - **`discuss_areas`:** When the user says "read X", "check Y", or references any doc/spec/ADR — add it immediately. These are often the MOST important refs.
321
323
 
@@ -329,7 +331,7 @@ Analyze the phase to identify gray areas. Use both `prior_decisions` and `codeba
329
331
 
330
332
  4. **Skip assessment** — If no meaningful gray areas exist (pure infrastructure, clear-cut implementation, all already decided), the phase may not need discussion.
331
333
 
332
- **Advisor mode hand-off:** If `ADVISOR_MODE` is true, follow `workflows/discuss-phase/modes/advisor.md` for the rest of analyze/discuss flow (it adds an `advisor_research` substep and replaces the standard `discuss_areas` with table-first selection). The detection block (USER-PROFILE.md existence + non-technical-owner signals + calibration tier resolution) lives in that file — read it once when ADVISOR_MODE is true and follow its rules.
334
+ **Advisor mode hand-off:** If `ADVISOR_MODE` is true, follow `workflows/discuss-phase/modes/advisor.md` for the rest of the analyze/discuss flow (adds an `advisor_research` substep; table-first selection replaces `discuss_areas`). Its detection block (USER-PROFILE.md, non-technical-owner signals, calibration tier) lives there — read it once.
333
335
  </step>
334
336
 
335
337
  <step name="present_gray_areas">
@@ -377,15 +379,16 @@ Overlays (combine with the active mode):
377
379
  - `--batch` → `workflows/discuss-phase/modes/batch.md` (group 2–5 questions per turn)
378
380
  - `--analyze` → `workflows/discuss-phase/modes/analyze.md` (trade-off table before each question)
379
381
 
380
- **Overlay stacking:** overlays combine and apply outer→inner in fixed order `--analyze` → `--batch` → `--text` (e.g., `--batch --analyze` = trade-off table per question group; add `--text` for plain-text rendering). Mode-specific precedence (e.g., `--auto --power`) is documented in each overlay file's "Combination rules" section.
382
+ **Overlay stacking:** overlays combine outer→inner in fixed order `--analyze` → `--batch` → `--text` (`--batch --analyze` = trade-off table per question group; add `--text` for plain-text rendering). Mode-specific precedence (e.g., `--auto --power`) is documented in each overlay file's "Combination rules" section.
381
383
 
382
384
  All modes preserve the universal rules below.
383
385
 
384
386
  **Universal rules (apply to every mode):**
385
387
 
386
- - **Canonical ref accumulation** — when the user references a doc/spec/ADR during any answer, immediately Read it (or confirm it exists) and add it to the canonical refs accumulator with full relative path. Use what you learned to inform subsequent questions. These docs are often MORE important than ROADMAP.md refs because the user specifically wants downstream agents to follow them.
388
+ - **Canonical ref accumulation** — when the user references a doc/spec/ADR during any answer, immediately Read it (or confirm it exists) and add it to the accumulator with full relative path; use it to inform later questions. These often matter MORE than ROADMAP.md refs.
389
+ - **Discovery amend (R2)** — a decision changing a discovery register fact follows `discovery.md` § C: amend the row in place, re-run its check, bump the charter.
387
390
  - **Scope creep** — if user mentions something outside the phase domain, capture as deferred idea and redirect.
388
- - **Incremental checkpoint** — after each area completes, write `${phase_dir}/${padded_phase}-DISCUSS-CHECKPOINT.json`. Read `workflows/discuss-phase/templates/checkpoint.json` for the schema. The checkpoint is structured state, not the canonical CONTEXT.md (`write_context` produces the canonical output). On session resume, the parent's `check_existing` step detects the checkpoint and offers to resume.
391
+ - **Incremental checkpoint** — after each area completes, write `${phase_dir}/${padded_phase}-DISCUSS-CHECKPOINT.json` (schema: `workflows/discuss-phase/templates/checkpoint.json`). It is structured state, not CONTEXT.md (`write_context` writes the canonical output); `check_existing` detects it on resume.
389
392
  - **Discussion log accumulation** — for each question asked, accumulate area name, options presented, user's selection, follow-up notes. Used by `git_commit` to write DISCUSSION-LOG.md.
390
393
  </step>
391
394
 
@@ -410,7 +413,7 @@ Set `phase_dir="${expected_phase_dir}"` after creation.
410
413
  Read(workflows/discuss-phase/templates/context.md)
411
414
  ```
412
415
 
413
- The template documents variable substitutions and conditional sections. Substitute live values for `[X]`, `[Name]`, `[date]`, `${padded_phase}`, `{N}`. Include `<spec_lock>` only when `spec_loaded = true`. Include "Folded Todos" / "Reviewed Todos" subsections only when the `cross_reference_todos` step folded or reviewed todos.
416
+ The template documents variable substitutions and conditional sections. Substitute live values for `[X]`, `[Name]`, `[date]`, `${padded_phase}`, `{N}`. Include `<spec_lock>` only when `spec_loaded = true`; `<discovery_extract>` only when `DISCOVERY_PRESENT` is true (`discovery.md` § B); "Folded Todos" / "Reviewed Todos" only when `cross_reference_todos` folded or reviewed todos.
414
417
 
415
418
  **SPEC.md integration** — If `spec_loaded = true`:
416
419
  - Add the `<spec_lock>` section immediately after `<domain>`.
@@ -501,9 +501,9 @@ Initialize with any decisions made during questioning:
501
501
  ```markdown
502
502
  ## Key Decisions
503
503
 
504
- | Decision | Rationale | Outcome |
505
- |----------|-----------|---------|
506
- | [Choice from questioning] | [Why] | — Pending |
504
+ | ID | Decision | Rationale | Outcome |
505
+ |----|----------|-----------|---------|
506
+ | — | [Choice from questioning] | [Why] | — Pending |
507
507
  ```
508
508
 
509
509
  **Last updated footer:**
@@ -0,0 +1,41 @@
1
+ # Plan-phase step — Discovery extract (R1)
2
+
3
+ > Read and executed from `workflows/plan-phase.md` §7 after the context paths are extracted and
4
+ > before the researcher (§5.1) and planner (§8) prompts are built. Inert on a project without
5
+ > `.planning/discovery/`. Contract: `references/discovery-build-consumption.md`.
6
+
7
+ Render the phase's discovery rows fresh — the registers may have been amended since
8
+ `/pp-discuss-phase` wrote CONTEXT.md — into one file the researcher and the planner read:
9
+
10
+ ```bash
11
+ _PP_SHIM_NAME="pp-tools.cjs"; _pp_root() { ( for _v in $(env | sed -n 's/^\(GIT_[A-Za-z0-9_]*\)=.*/\1/p'); do unset "$_v"; done; _c=$(git rev-parse --git-common-dir 2>/dev/null); if [ "${_c##*/}" = .git ] && cd "$_c/.." 2>/dev/null; then pwd -P; else git rev-parse --show-toplevel 2>/dev/null || pwd; fi ); }; pp_run() { case "$PP_TOOLS" in *.cjs) node "$PP_TOOLS" "$@";; *) "$PP_TOOLS" "$@";; esac; }; _PP_RUNTIME_ROOT="${RUNTIME_DIR:-$(_pp_root)}"; PP_TOOLS="${_PP_RUNTIME_ROOT}/pp-core/bin/${_PP_SHIM_NAME}"; if [ -f "$PP_TOOLS" ]; then :; elif [ -f "${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}"; elif command -v pp-tools >/dev/null 2>&1; then PP_TOOLS="$(command -v pp-tools)"; else echo "ERROR: pp-tools.cjs not found at $PP_TOOLS and pp-tools is not on PATH. Run: npx -y @pareto4/pp-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${PP_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${PP_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
12
+ DISCOVERY_EXTRACT_PATH=""
13
+ _DX_JSON=$(pp_run query discovery.for-phase "${PHASE_NUMBER}" 2>/dev/null || true)
14
+ if [[ "$_DX_JSON" == @file:* ]]; then _DX_JSON=$(cat "${_DX_JSON#@file:}"); fi
15
+ _DX_PRESENT=$(printf '%s' "$_DX_JSON" | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{try{const o=JSON.parse(s);console.log(o.present===true&&o.ok===true?'true':'false')}catch{console.log('false')}})")
16
+ if [ "$_DX_PRESENT" = true ]; then
17
+ DISCOVERY_EXTRACT_PATH="${PHASE_DIR}/${PADDED_PHASE}-DISCOVERY-EXTRACT.md"
18
+ pp_run query discovery.for-phase "${PHASE_NUMBER}" --markdown > "${DISCOVERY_EXTRACT_PATH}"
19
+ echo "DISCOVERY_EXTRACT_PATH=${DISCOVERY_EXTRACT_PATH}"
20
+ else
21
+ rm -f "${PHASE_DIR}/${PADDED_PHASE}-DISCOVERY-EXTRACT.md"
22
+ fi
23
+ ```
24
+
25
+ A non-zero exit from the first command is a structural fault in a discovery artifact
26
+ (`discovery_for_phase_failed`): print the fault list and stop. Planning on a malformed register
27
+ copies the malformation into the build; the sprint's own check names the row to fix.
28
+
29
+ When `DISCOVERY_EXTRACT_PATH` is non-empty:
30
+
31
+ - add `- {DISCOVERY_EXTRACT_PATH} (Discovery extract — register rows citing this phase's
32
+ requirement IDs; required reading, never open a session-NN.md)` to the `<files_to_read>` of
33
+ the researcher prompt (§5.1) and the planner prompt (§8);
34
+ - the planner embeds the file's content verbatim — markers included — as the `<discovery_extract>`
35
+ block of every PLAN.md it writes, after `<context>` (and after `<vault_standards>` when present)
36
+ and before `<tasks>`;
37
+ - the file is a render and is never committed: it is regenerated on every planning run and
38
+ `*-DISCOVERY-EXTRACT.md` is not a phase artifact.
39
+
40
+ The name is deliberate: `{padded}-DISCOVERY.md` already belongs to the planner's library
41
+ discovery protocol and is a different thing.