@pareto4/pp-core 1.19.0 → 1.21.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 (126) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/agents/pp-nyquist-auditor.md +19 -14
  3. package/agents/pp-phase-researcher.md +10 -0
  4. package/agents/pp-plan-checker.md +59 -36
  5. package/agents/pp-planner.md +49 -53
  6. package/agents/pp-vault-reviewer.md +2 -0
  7. package/agents/pp-verifier.md +15 -60
  8. package/commands/pp-autonomous.md +2 -1
  9. package/commands/pp-discovery.md +3 -2
  10. package/commands/pp-plan-phase.md +2 -1
  11. package/commands/pp-plan-review-convergence.md +2 -1
  12. package/gemini-extension.json +1 -1
  13. package/package.json +6 -3
  14. package/pareto-skills/_shared/pp-claude-md-protocol.md +1 -1
  15. package/pareto-skills/pp-project-setup/SKILL.md +18 -343
  16. package/pp-core/bin/lib/capability-activation.cjs +77 -0
  17. package/pp-core/bin/lib/capability-registry.cjs +15 -15
  18. package/pp-core/bin/lib/capability-state.cjs +8 -18
  19. package/pp-core/bin/lib/ceremony.cjs +1342 -0
  20. package/pp-core/bin/lib/check-command-router.cjs +62 -1
  21. package/pp-core/bin/lib/commands.cjs +29 -3
  22. package/pp-core/bin/lib/config.cjs +5 -0
  23. package/pp-core/bin/lib/discovery-access.cjs +276 -0
  24. package/pp-core/bin/lib/discovery-charter.cjs +664 -0
  25. package/pp-core/bin/lib/discovery-deviations.cjs +264 -0
  26. package/pp-core/bin/lib/discovery-entities.cjs +323 -0
  27. package/pp-core/bin/lib/discovery-for-phase.cjs +628 -0
  28. package/pp-core/bin/lib/discovery-integrations.cjs +286 -0
  29. package/pp-core/bin/lib/discovery-migration.cjs +246 -0
  30. package/pp-core/bin/lib/discovery-phases.cjs +233 -0
  31. package/pp-core/bin/lib/discovery-processes.cjs +355 -0
  32. package/pp-core/bin/lib/discovery-research-track.cjs +5 -4
  33. package/pp-core/bin/lib/discovery-rollup.cjs +8 -7
  34. package/pp-core/bin/lib/discovery-rules.cjs +216 -0
  35. package/pp-core/bin/lib/discovery-screens.cjs +1 -1
  36. package/pp-core/bin/lib/discovery-session-check.cjs +264 -0
  37. package/pp-core/bin/lib/discovery-stories.cjs +273 -0
  38. package/pp-core/bin/lib/discovery-sweep.cjs +1 -1
  39. package/pp-core/bin/lib/discovery-table.cjs +55 -0
  40. package/pp-core/bin/lib/init.cjs +50 -1
  41. package/pp-core/bin/lib/io.cjs +24 -0
  42. package/pp-core/bin/lib/loop-resolver.cjs +26 -12
  43. package/pp-core/bin/lib/phase.cjs +39 -3
  44. package/pp-core/bin/lib/plan-sizing.cjs +346 -0
  45. package/pp-core/bin/lib/test-substance.cjs +3190 -0
  46. package/pp-core/bin/lib/timeline.cjs +605 -0
  47. package/pp-core/bin/lib/vault-standards-review.cjs +50 -2
  48. package/pp-core/bin/pp-tools.cjs +214 -5
  49. package/pp-core/bin/shared/ceremony-gates.json +17 -0
  50. package/pp-core/bin/shared/config-schema.manifest.json +1 -0
  51. package/pp-core/references/ceremony.md +81 -0
  52. package/pp-core/references/discovery-access.md +112 -0
  53. package/pp-core/references/discovery-build-consumption.md +256 -0
  54. package/pp-core/references/discovery-charter.md +127 -0
  55. package/pp-core/references/discovery-data-model.md +145 -0
  56. package/pp-core/references/discovery-id-conventions.md +50 -14
  57. package/pp-core/references/discovery-integrations.md +151 -0
  58. package/pp-core/references/discovery-processes.md +190 -0
  59. package/pp-core/references/discovery-rebaseline.md +2 -2
  60. package/pp-core/references/discovery-research-track.md +5 -6
  61. package/pp-core/references/discovery-session-output.md +70 -0
  62. package/pp-core/references/discovery-standards.md +107 -0
  63. package/pp-core/references/discovery-traceability.md +2 -2
  64. package/pp-core/references/few-shot-examples/plan-checker.md +8 -8
  65. package/pp-core/references/phase-timeline.md +107 -0
  66. package/pp-core/references/planner-antipatterns.md +32 -0
  67. package/pp-core/references/planner-discovery-extract.md +35 -0
  68. package/pp-core/references/planner-guidance.md +17 -14
  69. package/pp-core/references/planner-revision.md +1 -1
  70. package/pp-core/references/planning-config.md +3 -2
  71. package/pp-core/references/test-substance.md +324 -0
  72. package/pp-core/references/verifier-discovery-conformance.md +36 -0
  73. package/pp-core/references/verifier-stub-patterns.md +51 -0
  74. package/pp-core/templates/VALIDATION.md +1 -0
  75. package/pp-core/templates/phase-prompt.md +19 -7
  76. package/pp-core/templates/project-charter.md +161 -100
  77. package/pp-core/templates/project.md +3 -3
  78. package/pp-core/templates/requirements.md +18 -0
  79. package/pp-core/templates/roadmap.md +1 -1
  80. package/pp-core/templates/verification-report.md +17 -1
  81. package/pp-core/workflows/audit-milestone.md +4 -1
  82. package/pp-core/workflows/autonomous.md +11 -8
  83. package/pp-core/workflows/code-review.md +15 -6
  84. package/pp-core/workflows/discovery-sprint/charter.md +114 -0
  85. package/pp-core/workflows/discovery-sprint/prefill.md +1 -1
  86. package/pp-core/workflows/discovery-sprint/prototype.md +4 -4
  87. package/pp-core/workflows/discovery-sprint/session-13-gates.md +10 -0
  88. package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +5 -2
  89. package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +27 -5
  90. package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +56 -31
  91. package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +1 -1
  92. package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +42 -19
  93. package/pp-core/workflows/discovery-sprint/sessions/06-security.md +27 -12
  94. package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +41 -23
  95. package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +50 -23
  96. package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +26 -11
  97. package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +28 -9
  98. package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +21 -0
  99. package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +24 -9
  100. package/pp-core/workflows/discovery-sprint.md +12 -15
  101. package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +80 -29
  102. package/pp-core/workflows/discovery-to-build/steps/{screen-inventory-gate.md → handoff-gates.md} +111 -3
  103. package/pp-core/workflows/discovery-to-build/templates/discovery-references.md +12 -9
  104. package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +27 -26
  105. package/pp-core/workflows/discovery-to-build.md +70 -34
  106. package/pp-core/workflows/discuss-phase/discovery.md +83 -0
  107. package/pp-core/workflows/discuss-phase/templates/context.md +4 -0
  108. package/pp-core/workflows/discuss-phase.md +10 -7
  109. package/pp-core/workflows/execute-phase/steps/check-query-gate.md +7 -7
  110. package/pp-core/workflows/execute-phase/steps/codebase-drift-gate.md +3 -2
  111. package/pp-core/workflows/execute-phase.md +14 -3
  112. package/pp-core/workflows/new-project.md +3 -3
  113. package/pp-core/workflows/plan-phase/steps/chunked-planning.md +7 -3
  114. package/pp-core/workflows/plan-phase/steps/discovery-extract.md +41 -0
  115. package/pp-core/workflows/plan-phase/steps/prd-express.md +104 -0
  116. package/pp-core/workflows/plan-phase.md +62 -124
  117. package/pp-core/workflows/plan-review-convergence.md +6 -3
  118. package/pp-core/workflows/ship.md +2 -2
  119. package/pp-core/workflows/stats.md +19 -4
  120. package/pp-core/workflows/validate-phase.md +19 -4
  121. package/pp-core/workflows/vault-review.md +5 -0
  122. package/pp-core/workflows/verify-phase.md +1 -1
  123. package/pp-core/workflows/verify-work.md +1 -1
  124. package/scripts/gen-capability-registry.cjs +43 -45
  125. package/scripts/run-tests.cjs +54 -30
  126. 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>`.
@@ -54,13 +54,13 @@ old numbers, which is how 05-13 shifted three rows ~200 lines into a different f
54
54
 
55
55
  | Query | Handler branch / function | Emits boolean `block` on every path? | Emission site(s) |
56
56
  |-------|---------------------------|--------------------------------------|------------------|
57
- | `gap-analysis.plan-post` | `gap-analysis-plan-post` branch (`cmdGapAnalysisPlanPost`) | yes — always `false` (advisory by design) | `src/check-command-router.cts:1096` |
58
- | `ship.platform-drift` | `ship-platform-drift` branch (`cmdShipPlatformDrift`) | yes — the only producer that can emit `block: true` from a threshold comparison | `src/check-command-router.cts:1198,1208,1217,1234,1276,1285,1299` |
59
- | `tdd.review-checkpoint` | `tdd-review-checkpoint` branch | yes — `block = violations > 0`, advisory in the capability | `src/check-command-router.cts:977,1051` |
60
- | `ui.plan-gate` | `ui-plan-gate` branch (`computeUiPlanGate`) | yes — `block = frontend && !hasUiSpec` | `src/check-command-router.cts:703` (emitted at `:727`) |
61
- | `ui.safety-gate` | `ui-safety-gate` branch (`computeUiSafetyGate`) | yes — `block = frontend && hasUiFiles && !hasUiSpec` | `src/check-command-router.cts:830` (emitted at `:856`) |
62
- | `vault.status` | `vault-status` branch (`cmdVaultStatus`) | yes — COMPUTED, not constant: `block` is the `vault.required` policy applied to the shared tier-keyed verdict leaf (`computeVaultVerdict`, GATE-01 / D-VH-4). It is `false` with the policy off (STRICT-01's byte-identical promise), on the inert path (`.platform-bindings.json` absent — that branch runs FIRST by requirement, T-02-28, because `tier !== 'client'` is true of `undefined` and would otherwise block every non-Pareto project), and for a present, fresh, client-tier vault; it is `true` on a required miss, on a fallback-tier load, on a stale client vault whatever its source (D-08-01; the block skips staleness only when `vault.cache_ttl_hours` is 0, D-08-28), and on a client cache fetched from a ref the project no longer configures (D-08-23). The attributed override (`applyVaultOverride`, GATE-07) then gets the last word on every blocking path, and that overwrite is the last emission site cited; and on a passing required-on verdict the envelope now carries a `message` (the success line, D-08-20) — the enforcer's every-run passthrough prints it. | `src/check-command-router.cts:1655,1670,1709,1736,1797` (02-11: CHECKED by the same two-directional probe as the other rows — every cited line lies inside `cmdVaultStatus` and emits a block, and every emission site is cited. This was the one row the probe did NOT cover, so it is the row that rotted: wave 1 wrote the claim before 02-06 computed the block, and 05-13 shifted the citations arithmetically into the manifest-sanitiser, ~200 lines outside the handler) 14-06: + the envelope always carries `reason`, `status` may be `degraded` (index missing / unparseable / empty / unresolvable / unchecked, D-12), the flat index fields follow the override keys, and the healthy message is the one-line standards card (D-15); a degraded index blocks exactly when `vault.required` is on, through the same override (D-13), so it adds no emission site of its own. |
63
- | `vault.trace` | `vault-trace` branch (`cmdVaultTrace`) — declared by the `vault` capability (`when: vault.enabled`) at **four** points, `plan:post`, `execute:post`, `ship:pre` and `verify:post`, all `blocking: true` / `onError: halt`, and once more at `ship:pre` as a seal gate (`onRecordedArtifacts: true`) that renders with `vault.enabled` off over a phase holding vault records (16-08). It judges each PLAN's `<vault_standards>` block and each SUMMARY's `## Standards Consulted` section through `src/vault-standards.cts` and fails closed on the `standards_*` kinds (`standards_block_absent`, `standards_block_duplicate`, `standards_block_unterminated`, `standards_block_malformed`, `standards_reason_invalid`, `standards_document_duplicate`, `standards_degraded_mixed`, `standards_none_without_reason`, `standards_path_not_resolved`, `standards_pin_mismatch`, `standards_cache_unreadable`, `standards_degraded_untrue`, `standards_consulted_absent`, `standards_consulted_mismatch`, `standards_plan_id_mismatch`, `standards_pair_missing`, `standards_orphan_summary`, `standards_anchor_malformed`). Reads `--stage` (04-03) and `--unpaired` (04-07, D-10); `ship:pre` sets `GATE_UNPAIRED=strict` unconditionally, `verify:post` sets it only on a full-phase run and leaves it unset when **either** partial-execution mode is active — the host's `WAVE_FILTER` set, or `--gaps-only` (04-12, CR-04; 04-18, WR-01) — and the other two leave the tolerant default | yes — `false` before any policy is read (inert), `false` with status `inactive` when `vault.enabled` is off and the phase holds no vault records, `true` once a standards record fails to validate; an agreeing degraded record with `vault.required` off is `false` with a message (D-29), and a recorded override is `false` at the tolerant points and `true` at the strict ones; `true` with status `disabled_with_artifacts` when `vault.enabled` is off and the positional's phase (or plan file) holds engine-written vault records (16-09, SEAL-02, D-21) — the answer the `ship:pre` seal gate dispatches for | `src/check-command-router.cts:3011,3023,3026,3058,3089,3114,3144,3170,3445` (04-16: CHECKED — a test asserts every line cited here lies inside `cmdVaultTrace` and carries a `block` emission, because four plans in this pass moved these numbers and nothing noticed). 16-07 (SEAL-01): at the strict points only, `appendSealProblems` compares the phase's recorded end anchors with `HEAD` through bounded git and adds `uncovered_source_commit` (a source commit after the ends that no record's start-end range covers), `anchor_missing`, `anchor_start_missing`, `anchor_unknown`, `anchor_not_ancestor` and `seal_could_not_check` (all blocking) and the `anchor_backfilled` note; it pushes problems into `checked` and owns no emission site and no status. 16-09 (SEAL-02): + the `disabled_with_artifacts` emission inside the switch-off guard. Standards-only vault: re-derived with the probe's own `handlerRange`/`emitsBlock` after the second record family, the invalid-config refusal and the envelope's mode tag left the handler. |
57
+ | `gap-analysis.plan-post` | `gap-analysis-plan-post` branch (`cmdGapAnalysisPlanPost`) | yes — always `false` (advisory by design) | `src/check-command-router.cts:1151` |
58
+ | `ship.platform-drift` | `ship-platform-drift` branch (`cmdShipPlatformDrift`) | yes — the only producer that can emit `block: true` from a threshold comparison | `src/check-command-router.cts:1253,1263,1272,1289,1331,1340,1354` |
59
+ | `tdd.review-checkpoint` | `tdd-review-checkpoint` branch | yes — `block = violations > 0`, advisory in the capability | `src/check-command-router.cts:1032,1106` |
60
+ | `ui.plan-gate` | `ui-plan-gate` branch (`computeUiPlanGate`) | yes — `block = frontend && !hasUiSpec` | `src/check-command-router.cts:705` (emitted at `:729`) |
61
+ | `ui.safety-gate` | `ui-safety-gate` branch (`computeUiSafetyGate`) | yes — `block = frontend && hasUiFiles && !hasUiSpec` | `src/check-command-router.cts:885` (emitted at `:911`) |
62
+ | `vault.status` | `vault-status` branch (`cmdVaultStatus`) | yes — COMPUTED, not constant: `block` is the `vault.required` policy applied to the shared tier-keyed verdict leaf (`computeVaultVerdict`, GATE-01 / D-VH-4). It is `false` with the policy off (STRICT-01's byte-identical promise), on the inert path (`.platform-bindings.json` absent — that branch runs FIRST by requirement, T-02-28, because `tier !== 'client'` is true of `undefined` and would otherwise block every non-Pareto project), and for a present, fresh, client-tier vault; it is `true` on a required miss, on a fallback-tier load, on a stale client vault whatever its source (D-08-01; the block skips staleness only when `vault.cache_ttl_hours` is 0, D-08-28), and on a client cache fetched from a ref the project no longer configures (D-08-23). The attributed override (`applyVaultOverride`, GATE-07) then gets the last word on every blocking path, and that overwrite is the last emission site cited; and on a passing required-on verdict the envelope now carries a `message` (the success line, D-08-20) — the enforcer's every-run passthrough prints it. | `src/check-command-router.cts:1710,1725,1764,1791,1852` (02-11: CHECKED by the same two-directional probe as the other rows — every cited line lies inside `cmdVaultStatus` and emits a block, and every emission site is cited. This was the one row the probe did NOT cover, so it is the row that rotted: wave 1 wrote the claim before 02-06 computed the block, and 05-13 shifted the citations arithmetically into the manifest-sanitiser, ~200 lines outside the handler) 14-06: + the envelope always carries `reason`, `status` may be `degraded` (index missing / unparseable / empty / unresolvable / unchecked, D-12), the flat index fields follow the override keys, and the healthy message is the one-line standards card (D-15); a degraded index blocks exactly when `vault.required` is on, through the same override (D-13), so it adds no emission site of its own. |
63
+ | `vault.trace` | `vault-trace` branch (`cmdVaultTrace`) — declared by the `vault` capability (`when: vault.enabled`) at **four** points, `plan:post`, `execute:post`, `ship:pre` and `verify:post`, all `blocking: true` / `onError: halt`, and once more at `ship:pre` as a seal gate (`onRecordedArtifacts: true`) that renders with `vault.enabled` off over a phase holding vault records (16-08). It judges each PLAN's `<vault_standards>` block and each SUMMARY's `## Standards Consulted` section through `src/vault-standards.cts` and fails closed on the `standards_*` kinds (`standards_block_absent`, `standards_block_duplicate`, `standards_block_unterminated`, `standards_block_malformed`, `standards_reason_invalid`, `standards_document_duplicate`, `standards_degraded_mixed`, `standards_none_without_reason`, `standards_path_not_resolved`, `standards_pin_mismatch`, `standards_cache_unreadable`, `standards_degraded_untrue`, `standards_consulted_absent`, `standards_consulted_mismatch`, `standards_plan_id_mismatch`, `standards_pair_missing`, `standards_orphan_summary`, `standards_anchor_malformed`). Reads `--stage` (04-03) and `--unpaired` (04-07, D-10); `ship:pre` sets `GATE_UNPAIRED=strict` unconditionally, `verify:post` sets it only on a full-phase run and leaves it unset when **either** partial-execution mode is active — the host's `WAVE_FILTER` set, or `--gaps-only` (04-12, CR-04; 04-18, WR-01) — and the other two leave the tolerant default | yes — `false` before any policy is read (inert), `false` with status `inactive` when `vault.enabled` is off and the phase holds no vault records, `true` once a standards record fails to validate; an agreeing degraded record with `vault.required` off is `false` with a message (D-29), and a recorded override is `false` at the tolerant points and `true` at the strict ones; `true` with status `disabled_with_artifacts` when `vault.enabled` is off and the positional's phase (or plan file) holds engine-written vault records (16-09, SEAL-02, D-21) — the answer the `ship:pre` seal gate dispatches for | `src/check-command-router.cts:3066,3078,3081,3113,3144,3169,3199,3225,3500` (04-16: CHECKED — a test asserts every line cited here lies inside `cmdVaultTrace` and carries a `block` emission, because four plans in this pass moved these numbers and nothing noticed). 16-07 (SEAL-01): at the strict points only, `appendSealProblems` compares the phase's recorded end anchors with `HEAD` through bounded git and adds `uncovered_source_commit` (a source commit after the ends that no record's start-end range covers), `anchor_missing`, `anchor_start_missing`, `anchor_unknown`, `anchor_not_ancestor` and `seal_could_not_check` (all blocking) and the `anchor_backfilled` note; it pushes problems into `checked` and owns no emission site and no status. 16-09 (SEAL-02): + the `disabled_with_artifacts` emission inside the switch-off guard. Standards-only vault: re-derived with the probe's own `handlerRange`/`emitsBlock` after the second record family, the invalid-config refusal and the envelope's mode tag left the handler. |
64
64
  | `verify.codebase-drift` | `verify-codebase-drift` branch (`verify.cmdVerifyCodebaseDrift`) | yes — `block = action_required` | `src/verify.cts:2134,2149,2164,2186,2231,2246` |
65
65
  | `verify.schema-drift` | `verify-schema-drift` branch (`verify.cmdVerifySchemaDrift`) | yes — `block = !skipped && driftDetected` | `src/verify.cts:2051,2071,2108` |
66
66
 
@@ -60,6 +60,7 @@ from step `init_context` is for `pp-executor`, not the mapper):
60
60
  # with the single-canonical-preamble parity invariant (#619). This block only runs on the
61
61
  # `auto-remap` directive, which is always reached after the drift check above has run.
62
62
  AGENT_SKILLS_MAPPER=$(pp_run query agent-skills pp-codebase-mapper)
63
+ pp_run timeline start other "${PHASE_NUMBER}" --agent pp-codebase-mapper --source execute-phase --model inherit || true
63
64
  ```
64
65
 
65
66
  Then spawn `pp-codebase-mapper` agents with the `--paths` hint (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):
@@ -80,11 +81,11 @@ ${AGENT_SKILLS_MAPPER}"
80
81
 
81
82
  > **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.
82
83
 
83
- If the spawn fails or the agent reports an error: log `Codebase drift
84
+ If the spawn fails or the agent reports an error: run `pp_run timeline end other "${PHASE_NUMBER}" failed || true`, then log `Codebase drift
84
85
  auto-remap failed: {reason}` and continue to `verify_phase_goal`. The phase
85
86
  is NOT failed by a remap failure.
86
87
 
87
- If the remap succeeds: log `Codebase drift auto-remap completed for paths:
88
+ If the remap succeeds: run `pp_run timeline end other "${PHASE_NUMBER}" complete || true`, then log `Codebase drift auto-remap completed for paths:
88
89
  {affected_paths}` and continue to `verify_phase_goal`.
89
90
 
90
91
  The two relevant config keys (continue on error / failure if either is invalid):