@pareto4/pp-core 1.20.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.
- package/.claude-plugin/plugin.json +1 -1
- package/agents/pp-nyquist-auditor.md +19 -14
- package/agents/pp-plan-checker.md +59 -36
- package/agents/pp-planner.md +34 -53
- package/agents/pp-verifier.md +3 -52
- package/commands/pp-autonomous.md +2 -1
- package/commands/pp-plan-phase.md +2 -1
- package/commands/pp-plan-review-convergence.md +2 -1
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/pp-core/bin/lib/capability-activation.cjs +77 -0
- package/pp-core/bin/lib/capability-registry.cjs +14 -14
- package/pp-core/bin/lib/capability-state.cjs +8 -18
- package/pp-core/bin/lib/ceremony.cjs +1342 -0
- package/pp-core/bin/lib/check-command-router.cjs +62 -1
- package/pp-core/bin/lib/commands.cjs +29 -3
- package/pp-core/bin/lib/config.cjs +5 -0
- package/pp-core/bin/lib/init.cjs +50 -1
- package/pp-core/bin/lib/io.cjs +2 -0
- package/pp-core/bin/lib/loop-resolver.cjs +26 -12
- package/pp-core/bin/lib/phase.cjs +39 -3
- package/pp-core/bin/lib/plan-sizing.cjs +346 -0
- package/pp-core/bin/lib/test-substance.cjs +3190 -0
- package/pp-core/bin/lib/timeline.cjs +605 -0
- package/pp-core/bin/pp-tools.cjs +71 -4
- package/pp-core/bin/shared/ceremony-gates.json +17 -0
- package/pp-core/bin/shared/config-schema.manifest.json +1 -0
- package/pp-core/references/ceremony.md +81 -0
- package/pp-core/references/few-shot-examples/plan-checker.md +8 -8
- package/pp-core/references/phase-timeline.md +107 -0
- package/pp-core/references/planner-antipatterns.md +32 -0
- package/pp-core/references/planner-guidance.md +17 -14
- package/pp-core/references/planner-revision.md +1 -1
- package/pp-core/references/planning-config.md +3 -2
- package/pp-core/references/test-substance.md +324 -0
- package/pp-core/references/verifier-stub-patterns.md +51 -0
- package/pp-core/templates/VALIDATION.md +1 -0
- package/pp-core/templates/phase-prompt.md +19 -7
- package/pp-core/templates/roadmap.md +1 -1
- package/pp-core/templates/verification-report.md +1 -1
- package/pp-core/workflows/audit-milestone.md +4 -1
- package/pp-core/workflows/autonomous.md +11 -8
- package/pp-core/workflows/code-review.md +15 -6
- package/pp-core/workflows/execute-phase/steps/check-query-gate.md +7 -7
- package/pp-core/workflows/execute-phase/steps/codebase-drift-gate.md +3 -2
- package/pp-core/workflows/execute-phase.md +14 -3
- package/pp-core/workflows/plan-phase/steps/chunked-planning.md +7 -3
- package/pp-core/workflows/plan-phase/steps/prd-express.md +104 -0
- package/pp-core/workflows/plan-phase.md +47 -114
- package/pp-core/workflows/plan-review-convergence.md +6 -3
- package/pp-core/workflows/ship.md +2 -2
- package/pp-core/workflows/stats.md +19 -4
- package/pp-core/workflows/validate-phase.md +19 -4
- package/pp-core/workflows/verify-phase.md +1 -1
- package/pp-core/workflows/verify-work.md +1 -1
- package/scripts/gen-capability-registry.cjs +43 -45
- package/scripts/run-tests.cjs +54 -30
package/pp-core/bin/pp-tools.cjs
CHANGED
|
@@ -64,6 +64,19 @@
|
|
|
64
64
|
* Returns JSON { valid, errors[], slots: {role,capability,outcome} | null }
|
|
65
65
|
* --pick valid Emit bare boolean (for workflow boolean checks)
|
|
66
66
|
*
|
|
67
|
+
* Timeline (Phase 35):
|
|
68
|
+
* timeline start <role> <phase> Append a run record before an Agent() spawn; prints the run id
|
|
69
|
+
* [--plan P] [--agent A] [--model M] [--source S]
|
|
70
|
+
* timeline end <role> <phase> <outcome> Close the most recent open run of that role (and plan)
|
|
71
|
+
* [--plan P] [--id ID]
|
|
72
|
+
* timeline summary <phase> [--banner] Fold a phase's runs: wall-clock, agent time, longest
|
|
73
|
+
*
|
|
74
|
+
* Ceremony (Phase 37):
|
|
75
|
+
* ceremony classify <phase> [--full] [--research] [--skip-research] [--skip-verify] [--write]
|
|
76
|
+
* Classify a phase (trust boundary, codebase to match, single-concern), print the
|
|
77
|
+
* verdict table; --write records it as {padded}-CEREMONY.md
|
|
78
|
+
* ceremony get <phase> Read the recorded verdict; full when none is recorded
|
|
79
|
+
*
|
|
67
80
|
* Drift Guard (ADR-22):
|
|
68
81
|
* drift-guard authority Resolve effective source-grounding authority
|
|
69
82
|
* (reads plan_review.source_grounding_authority + intel.enabled from config)
|
|
@@ -177,7 +190,7 @@
|
|
|
177
190
|
* learnings delete <id> Delete a learning by ID
|
|
178
191
|
*
|
|
179
192
|
* Loop Extension Point Queries (ADR-857 phase 3c):
|
|
180
|
-
* loop render-hooks <point>
|
|
193
|
+
* loop render-hooks <point> [--phase <N>] Resolve + render active Capability hooks at a loop point
|
|
181
194
|
* Returns JSON envelope { point, activeHooks, rendered }
|
|
182
195
|
* Valid points: discuss:pre/post, plan:pre/post,
|
|
183
196
|
* execute:pre/wave:pre/wave:post/post, verify:pre/post, ship:pre/post
|
|
@@ -212,6 +225,7 @@ const roadmap = require('./lib/roadmap.cjs');
|
|
|
212
225
|
const verify = require('./lib/verify.cjs');
|
|
213
226
|
const config = require('./lib/config.cjs');
|
|
214
227
|
const platformBindings = require('./lib/platform-bindings.cjs');
|
|
228
|
+
const timeline = require('./lib/timeline.cjs');
|
|
215
229
|
const composeBindings = require('./lib/compose-bindings.cjs');
|
|
216
230
|
const initContract = require('./lib/init-contract.cjs');
|
|
217
231
|
const initInteractive = require('./lib/init-interactive.cjs');
|
|
@@ -529,9 +543,9 @@ async function main() {
|
|
|
529
543
|
'current-timestamp, detect-custom-files, discovery, docs-init, drift-guard, effort, extract-messages, find-phase, ' +
|
|
530
544
|
'from-gsd2, frontmatter, gap-analysis, generate-claude-md, generate-claude-profile, ' +
|
|
531
545
|
'generate-client-context, generate-dev-preferences, generate-slug, graphify, history-digest, init, init-contract, intel, ' +
|
|
532
|
-
'capability, classify-confidence, git, learnings, list-todos, loop, milestone, package-legitimacy, phase, phase-plan-index, phases, platform-bindings, platform-latest-tag, profile-questionnaire, ' +
|
|
546
|
+
'capability, ceremony, classify-confidence, git, learnings, list-todos, loop, milestone, package-legitimacy, phase, phase-plan-index, phases, platform-bindings, platform-latest-tag, profile-questionnaire, ' +
|
|
533
547
|
'profile-sample, progress, prompt-budget, requirements, research-plan, research-store, resolve-granularity, resolve-model, roadmap, scaffold, state, ' +
|
|
534
|
-
'task, template, user-story, validate, validate-bindings, verify, verify-path-exists, verify-summary, workstream, worktree\n\n' +
|
|
548
|
+
'task, template, timeline, user-story, validate, validate-bindings, verify, verify-path-exists, verify-summary, workstream, worktree\n\n' +
|
|
535
549
|
'Global flags:\n' +
|
|
536
550
|
' --raw Emit raw output without post-processing\n' +
|
|
537
551
|
' --pick <field> Extract a single field from JSON output (dot/bracket notation)\n' +
|
|
@@ -788,6 +802,32 @@ function makePlatformBindingsPresentResolver(cwd) {
|
|
|
788
802
|
};
|
|
789
803
|
}
|
|
790
804
|
|
|
805
|
+
/**
|
|
806
|
+
* Phase 37 D-14: the ceremony verdict `loop render-hooks --phase <N>` injects,
|
|
807
|
+
* built here at the CLI entry so the pure resolver imports no ceremony code.
|
|
808
|
+
* Returns `(phase) => gateFn`; gateFn reads the phase's recorded verdict once
|
|
809
|
+
* (any throw is a null verdict) and answers `ceremonyGateOpen(verdict, gate)`.
|
|
810
|
+
* Every failure answers true (T-37-13): a missing, unreadable or unknown-phase
|
|
811
|
+
* verdict leaves the hook rendered, so a doubt never lowers ceremony.
|
|
812
|
+
*/
|
|
813
|
+
function makeCeremonyGateResolver(cwd) {
|
|
814
|
+
return (phase) => {
|
|
815
|
+
let verdict = null;
|
|
816
|
+
try {
|
|
817
|
+
verdict = require('./lib/ceremony.cjs').readRecordedVerdict(cwd, phase);
|
|
818
|
+
} catch {
|
|
819
|
+
verdict = null;
|
|
820
|
+
}
|
|
821
|
+
return (gate) => {
|
|
822
|
+
try {
|
|
823
|
+
return require('./lib/ceremony.cjs').ceremonyGateOpen(verdict, gate) !== false;
|
|
824
|
+
} catch {
|
|
825
|
+
return true;
|
|
826
|
+
}
|
|
827
|
+
};
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
|
|
791
831
|
async function runCommand(command, args, cwd, raw, defaultValue, originalCommand, workstreamContext = null) {
|
|
792
832
|
switch (command) {
|
|
793
833
|
case 'agent': {
|
|
@@ -821,6 +861,18 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
821
861
|
break;
|
|
822
862
|
}
|
|
823
863
|
|
|
864
|
+
case 'timeline': {
|
|
865
|
+
timeline.cmdTimeline(cwd, args.slice(1), raw);
|
|
866
|
+
break;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
case 'ceremony': {
|
|
870
|
+
// WR-04: loaded here, not at the top, so a missing ceremony-gates.json fails
|
|
871
|
+
// only the ceremony command, never every pp-tools command.
|
|
872
|
+
require('./lib/ceremony.cjs').cmdCeremony(cwd, args.slice(1), raw);
|
|
873
|
+
break;
|
|
874
|
+
}
|
|
875
|
+
|
|
824
876
|
case 'platform-latest-tag': {
|
|
825
877
|
// quick 261003-my0: the init.md / new-project.md preflights read
|
|
826
878
|
// `--pick latest` from here instead of composing the platform URL in
|
|
@@ -1655,7 +1707,7 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1655
1707
|
}
|
|
1656
1708
|
|
|
1657
1709
|
case 'loop': {
|
|
1658
|
-
// loop render-hooks <point> [--config-dir <dir>] [--active-cap <capId>] [--into <role>]
|
|
1710
|
+
// loop render-hooks <point> [--config-dir <dir>] [--active-cap <capId>] [--into <role>] [--phase <N>]
|
|
1659
1711
|
const loopSubcommand = args[1];
|
|
1660
1712
|
if (loopSubcommand === 'render-hooks') {
|
|
1661
1713
|
let loopConfigDir = null;
|
|
@@ -1703,10 +1755,25 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
|
|
|
1703
1755
|
}
|
|
1704
1756
|
loopInto = value;
|
|
1705
1757
|
}
|
|
1758
|
+
// --phase <N>: read the phase's recorded ceremony verdict (Phase 37 D-14).
|
|
1759
|
+
// Unlike the flags above, a missing, empty or `--`-prefixed value is NOT an
|
|
1760
|
+
// error: a workflow whose phase variable is unset must keep today's hooks (T-37-13).
|
|
1761
|
+
let loopPhase = undefined;
|
|
1762
|
+
const phaseEqArg = args.find(arg => arg.startsWith('--phase='));
|
|
1763
|
+
const phaseIdx = args.indexOf('--phase');
|
|
1764
|
+
if (phaseEqArg) {
|
|
1765
|
+
const value = phaseEqArg.slice('--phase='.length).trim();
|
|
1766
|
+
if (value) loopPhase = value;
|
|
1767
|
+
} else if (phaseIdx !== -1) {
|
|
1768
|
+
const value = (args[phaseIdx + 1] || '').trim();
|
|
1769
|
+
if (value && !value.startsWith('--')) loopPhase = value;
|
|
1770
|
+
}
|
|
1706
1771
|
loopResolver.cmdLoopRenderHooks(cwd, args[2], raw, {
|
|
1707
1772
|
configDir: loopConfigDir ? path.resolve(loopConfigDir) : undefined,
|
|
1708
1773
|
activeCap: loopActiveCap,
|
|
1709
1774
|
into: loopInto,
|
|
1775
|
+
phase: loopPhase,
|
|
1776
|
+
resolveCeremonyGate: makeCeremonyGateResolver(cwd),
|
|
1710
1777
|
resolveRecordedArtifacts: makeRecordedArtifactsResolver(cwd),
|
|
1711
1778
|
resolvePlatformBindingsPresent: makePlatformBindingsPresentResolver(cwd),
|
|
1712
1779
|
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "The single gate vocabulary for per-phase ceremony (Phase 37). Read by src/ceremony.cts (table order), src/capability-activation.cts and scripts/gen-capability-registry.cjs (validation of `ceremony.<gate>` conjuncts). Keys are in verdict-table order; add a gate here and nowhere else.",
|
|
3
|
+
"schema_version": 1,
|
|
4
|
+
"gates": [
|
|
5
|
+
{ "key": "research", "label": "Researcher" },
|
|
6
|
+
{ "key": "pattern_mapper", "label": "Pattern mapper" },
|
|
7
|
+
{ "key": "threat_model", "label": "Threat model" },
|
|
8
|
+
{ "key": "plan_check", "label": "Plan checker" },
|
|
9
|
+
{ "key": "code_review", "label": "Code review" },
|
|
10
|
+
{ "key": "verifier", "label": "Verifier" },
|
|
11
|
+
{ "key": "security_review", "label": "Security review" },
|
|
12
|
+
{ "key": "nyquist", "label": "Nyquist audit" },
|
|
13
|
+
{ "key": "ui_review", "label": "UI review" },
|
|
14
|
+
{ "key": "ui", "label": "UI contract" },
|
|
15
|
+
{ "key": "vault", "label": "Vault" }
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Phase Ceremony
|
|
2
|
+
|
|
3
|
+
Before any agent runs, plan-phase classifies the phase from what it touches (`/pp-plan-phase` writes the verdict in the classify step, ahead of research). Only `pp_run ceremony classify` computes a verdict; every other workflow, hook and agent reads the recorded one. The verdict is a pure function of the phase's ROADMAP section, its mapped REQUIREMENTS lines, its CONTEXT.md, the git file inventory, the completion state of other phases and the gate keys in `.planning/config.json`. No model judgment and no client identity is involved. It is recorded as `{padded}-CEREMONY.md`, and the same table is printed by the CLI.
|
|
4
|
+
|
|
5
|
+
The verdict only ever lowers ceremony relative to config. A gate that config turns off stays `off (config)`. The full gate stack is one flag (`--full`), one config key (`workflow.ceremony: full`) or one ROADMAP line (`**Ceremony:** full`, or `**Ceremony**: full`, anywhere in the phase section) away, and full mode runs every gate exactly as config says today. A `**Ceremony**` line with any other value is ignored with a warning line.
|
|
6
|
+
|
|
7
|
+
## The three questions
|
|
8
|
+
|
|
9
|
+
1. **Trust boundary crossed?** The ROADMAP section (up to its Plans list), the mapped REQUIREMENTS lines and CONTEXT.md (without its `<deferred>` block) are matched, case-insensitively on word boundaries, against four conservative term sets: authentication and authorization, secrets and crypto, personal and payment data, untrusted input. The security verbs also match their inflections and negations (encrypted, unencrypted, authenticated, unauthorized, uploaded, deserialization). "Log in" and "sign in" match only in their authentication sense (users log in, can sign in, allow log in, log in with, a logged-in or logged in user, not signed in, the login page, a sign in page, the log in screen), so logging prose such as "write the logs in JSON" or "structured logging" does not. Any match is "crossed", and the matched terms with their source are the evidence. A bare "token" does not match, because pp-core's own phases talk about context tokens. Over-match is accepted where it only adds ceremony: "logged in" or "signed in" followed by anything but a place or format word (the, a, its, CI, JSON, …), such as "decisions logged in STATE.md", reads as authentication. Detection only pushes a phase up. The residual risk is a phase worded without any trigger term, which reads as no trust boundary; `--full`, `workflow.ceremony: full` or a `**Ceremony:** full` ROADMAP line restore the full stack.
|
|
10
|
+
2. **Codebase to match?** Yes when the repository tracks at least 20 source files outside `.planning/` (vendored and generated directories excluded), or another roadmap phase or an archived milestone is complete. No git means yes (fails toward ceremony). A freshly generated scaffold stays below the threshold. The counts are the evidence.
|
|
11
|
+
3. **Serial single-concern?** Yes when the phase maps at most 3 requirement IDs sharing one category prefix, lists at most 4 success criteria, and does not span a UI surface plus a non-UI surface. `**UI:** none` counts as no UI. Requirement IDs and success criteria are read from the same line or from a numbered or bulleted list under the header. Only ID-shaped tokens (`SLUG-01`) count; other words on the line are dropped, and a range (`DATA-01 – DATA-03`, `to`, `through`) expands into every ID in it, up to 50.
|
|
12
|
+
|
|
13
|
+
Input the classifier cannot read fails toward ceremony and is named in a warning line. A missing ROADMAP section, no parseable requirement IDs (including `TBD` and `None`), a requirement ID with no REQUIREMENTS.md line, no parseable success criteria or a failed frontend check make the phase not single-concern, so it plans at least standard. An explicit `TBD`/`None`/`N/A` claims nothing; a ROADMAP section that is missing or unreadable, or a mapped requirement ID with no REQUIREMENTS.md line (REQUIREMENTS.md missing included), cannot rule out a trust boundary, so the answer is yes (`phase section unreadable — failing toward ceremony`, `requirement text unread for <IDs> — failing toward ceremony`) and the phase plans heavy. So a phase created by `/pp-phase add` or `insert` (`**Requirements**: TBD`) plans standard until its requirements are mapped, and heavy only when its wording names a trust term.
|
|
14
|
+
|
|
15
|
+
## Tiers
|
|
16
|
+
|
|
17
|
+
| Tier | When | Effect |
|
|
18
|
+
|------|------|--------|
|
|
19
|
+
| light | serial single-concern and no trust boundary | one blockers-only checker round, light verifier, quick code review, Nyquist audit and UI review skipped |
|
|
20
|
+
| heavy | not single-concern and a trust boundary crossed | up to 3 checker rounds, full verifier, configured review depth |
|
|
21
|
+
| standard | everything else | same as heavy |
|
|
22
|
+
|
|
23
|
+
"Codebase to match" never changes the tier; it gates the researcher and the pattern mapper directly. The tier names are the routing tiers' light, standard and heavy vocabulary, and the verdict has no effect on model routing.
|
|
24
|
+
|
|
25
|
+
## Gate rules
|
|
26
|
+
|
|
27
|
+
Every gate appears in the verdict with a decision (`run`, `skip` or `off`) and a reason. The hook conjunct is the `ceremony.<gate>` term a capability `when` may carry; it is false only for a `skip` in proportional mode.
|
|
28
|
+
|
|
29
|
+
| Gate key | Proportional rule | Full mode | Hook conjunct |
|
|
30
|
+
|----------|-------------------|-----------|---------------|
|
|
31
|
+
| `research` | runs only with a codebase to match; `--research` forces, `--skip-research` skips | runs if config enables it | `research` hook |
|
|
32
|
+
| `pattern_mapper` | runs only with a codebase to match | runs if config enables it | `pattern-mapper` hook |
|
|
33
|
+
| `threat_model` | runs only when a trust boundary is crossed, at any tier | runs if config enables it | `security` hook (threat-model contribution) |
|
|
34
|
+
| `plan_check` | light: one blockers-only round; standard and heavy: up to 3 rounds; `--skip-verify` skips | up to 3 rounds | none (read as `plan_check_rounds`, `plan_check_mode`) |
|
|
35
|
+
| `code_review` | light: `quick` depth; otherwise the configured depth, read live (a recorded depth never lowers review below current config) | configured depth | none (read as `code_review_depth`) |
|
|
36
|
+
| `verifier` | light and no trust boundary: `light` depth; otherwise `full` | `full` | none (read as `verifier_depth`) |
|
|
37
|
+
| `security_review` | runs only when a trust boundary is crossed | runs if config enables it | `security` hook (`secure-phase`, ship gate) |
|
|
38
|
+
| `nyquist` | skipped at light; runs at standard and heavy | runs if config enables it | `nyquist` hook |
|
|
39
|
+
| `ui_review` | skipped at light; runs otherwise | runs if config enables it | `ui` hook (`ui-review` step only) |
|
|
40
|
+
| `ui` | follows frontend detection exactly as today | same | none |
|
|
41
|
+
| `vault` | always runs when the vault is enabled | same | none |
|
|
42
|
+
|
|
43
|
+
A gate that config turns off is listed `off (config)` in every mode. If `workflow.security_enforcement` is off on a trust-boundary phase, the verdict adds a warning line. Deterministic checks (requirements coverage, decision coverage, plan-sizing, test substance, schema and codebase drift) always run. The vault gates and the UI design-contract gates (`ui-phase`, the UI plan gate and the UI safety gate) never depend on the tier. Plan-time VALIDATION.md is built from RESEARCH.md's Validation Architecture section, so when the verdict skips research (no codebase to match) it skips with it, and the research row's reason says so. The checker's Nyquist dimension (Dimension 8) runs with or without RESEARCH.md at every tier, light included, through `check test-substance`; only its VALIDATION.md check (8e) needs the Validation Architecture section. The post-execution Nyquist audit follows its own `nyquist` row.
|
|
44
|
+
|
|
45
|
+
## Verifier depth
|
|
46
|
+
|
|
47
|
+
`full` is today's verifier. `light` skips Step 4b (the data-flow trace, Level 4) and the Step 7b behavioural spot-check sweep. Must-haves, artifacts at levels 1-3, key links, requirements coverage, the Step 7 anti-pattern scan and the Step 7c probes always run. A behaviour-dependent truth still needs Step 3's single named passing test or routes to human verification: light depth never turns presence into VERIFIED. Light depth is reachable only at light tier, which has no trust boundary, so a trust-boundary phase is always verified at full depth.
|
|
48
|
+
|
|
49
|
+
## Blockers-only checker mode
|
|
50
|
+
|
|
51
|
+
`plan_check_mode: blockers-only` is used for the single light-tier round. The checker runs every dimension but reports only BLOCKER issues, never warnings or info, and returns `## VERIFICATION PASSED` when there is no blocker. If it returns blockers, the orchestrator runs one targeted revision for those blockers and does not re-check. Requirements coverage, decision coverage, plan-sizing and test substance still run deterministically in the planner's own validation. Every `check test-substance` finding is a BLOCKER, so it survives the single blockers-only round. `plan_check_mode: standard` is today's loop of up to 3 iterations.
|
|
52
|
+
|
|
53
|
+
## Lifecycle
|
|
54
|
+
|
|
55
|
+
The verdict is rewritten on every plan-phase run until the phase has its first SUMMARY.md, then reused: `--gaps` replans and execute-phase read the recorded verdict, so the phase's own code never flips "codebase to match" between planning and gap closure. `--full` always rewrites the verdict as full. `--skip-research` and `--skip-verify` decide only the run that passes them: the printed table shows them, the recorded verdict never does, and a recorded verdict that carries either reason does not parse. A phase with no CEREMONY.md, or one that does not parse, is treated as full, which is today's behaviour; this covers phases planned before this release and phases that skipped plan-phase.
|
|
56
|
+
|
|
57
|
+
`/pp-execute-phase` has no `--full`: re-plan with it. A `--full` verdict lasts only until the next plan-phase run without `--full` before the first SUMMARY. That run, a `--reviews` replan included, re-classifies the phase proportionally. Pass `--full` on every re-plan that should stay full; `/pp-autonomous --full` and `/pp-plan-review-convergence --full` forward it to every plan-phase call they make.
|
|
58
|
+
|
|
59
|
+
## Reading the verdict
|
|
60
|
+
|
|
61
|
+
No workflow parses CEREMONY.md or evaluates the verdict itself.
|
|
62
|
+
|
|
63
|
+
- **Init keys.** `pp_run query init.plan-phase` and `pp_run query init.execute-phase` return `ceremony_tier`, `ceremony_mode`, `plan_check_rounds` (1 or 3), `plan_check_mode` (`blockers-only` or `standard`), `verifier_depth` (`light` or `full`) and `code_review_depth`; `init.plan-phase` also returns `research_enabled` already folded through the verdict. `code-review` resolves its depth in the order `--depth` flag, then the verdict, then config. In proportional mode a gate the verdict skips is skipped without prompting; plan-phase's interactive research question is not asked. `--research` and `--full` are the overrides.
|
|
64
|
+
- **Hooks.** `pp_run loop render-hooks <point> --phase <N>` supplies the phase to the `when` evaluator. An empty or unknown phase, or no recorded file, leaves every `ceremony.*` conjunct true, so callers without a phase (`/pp-quick`, `/pp-debug`) are unchanged.
|
|
65
|
+
- **Direct read.** `pp_run ceremony get <N> [--pick <field>]` returns the recorded verdict, else the full default. Each gate carries a `report` string: `run`, `off (config)` or `skipped (ceremony: <reason>)`.
|
|
66
|
+
- **Ship and milestone audit** report a skipped gate as `skipped (ceremony: <reason>)`, never as missing and never as a ship block. Hand-invoked `/pp-secure-phase` and `/pp-validate-phase` always run, since that is an explicit request.
|
|
67
|
+
- A failed read falls back to full, never to less ceremony.
|
|
68
|
+
|
|
69
|
+
## CEREMONY.md
|
|
70
|
+
|
|
71
|
+
`{phase_dir}/{padded}-CEREMONY.md` is committed with the phase's planning docs. The YAML frontmatter is the machine contract; the body is the table the CLI printed. A frontmatter whose rows do not follow from its own answers, tier and mode (a hand edit or a half-resolved merge that skips a gate the rules would run) does not parse, so it reads as full. `ceremony get` and a reused `classify` print the table rendered from the frontmatter, not the stored body. There is no timestamp, so identical inputs give a byte-identical file.
|
|
72
|
+
|
|
73
|
+
| Field | Meaning |
|
|
74
|
+
|-------|---------|
|
|
75
|
+
| `schema_version` | `1` |
|
|
76
|
+
| `phase` | the padded phase token |
|
|
77
|
+
| `mode` | `proportional` or `full` |
|
|
78
|
+
| `forced_by` | `flag`, `config` or `roadmap` when full was forced; `none` otherwise |
|
|
79
|
+
| `tier` | `light`, `standard` or `heavy` |
|
|
80
|
+
| `answers` | `trust_boundary`, `codebase_to_match`, `serial_single_concern`, each `{ value, evidence }` |
|
|
81
|
+
| `gates` | one key per gate in the Gate rules table, each `{ decision: run\|skip\|off, depth?, rounds?, mode?, reason }` |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: plan-checker
|
|
3
|
-
version:
|
|
4
|
-
last_calibrated: 2026-
|
|
3
|
+
version: 2
|
|
4
|
+
last_calibrated: 2026-10-27
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Plan-Checker Few-Shot Examples
|
|
@@ -55,19 +55,19 @@ last_calibrated: 2026-03-24
|
|
|
55
55
|
|
|
56
56
|
**Why this is bad:** The checker missed two violations. verification_derivation requires verify commands to be runnable and test actual output -- an empty verify block is a BLOCKER. Verify commands must distinguish pass from fail -- `echo "done"` always returns 0 regardless of implementation state. Both should have been flagged.
|
|
57
57
|
|
|
58
|
-
### Example 2: False positive
|
|
58
|
+
### Example 2: False positive on a 6-task plan within limits, missed serial over-split
|
|
59
59
|
|
|
60
|
-
**Input:** Plan
|
|
60
|
+
**Input:** Phase at `context_window: 1000000` (`plan_budget_tokens` 500000). Plan 01 has 6 tasks, 14 files, `context_estimate: 240000`, wave 1. Plan 02 (2 tasks, `context_estimate: 60000`) is alone in wave 2 and depends on 01. Plan 03 (3 tasks, `context_estimate: 70000`) is alone in wave 3 and depends on 02. `check plan-sizing` reports `over_ceiling: []` and `unjustified_splits: [02, 03]`.
|
|
61
61
|
|
|
62
62
|
**Output:**
|
|
63
63
|
|
|
64
64
|
> ```yaml
|
|
65
65
|
> issues:
|
|
66
66
|
> - dimension: scope_sanity
|
|
67
|
-
> severity:
|
|
68
|
-
> finding: "Plan has
|
|
67
|
+
> severity: WARNING
|
|
68
|
+
> finding: "Plan 01 has 6 tasks -- consider splitting into smaller plans"
|
|
69
69
|
> affected_field: "task count"
|
|
70
|
-
> suggested_fix: "Split
|
|
70
|
+
> suggested_fix: "Split plan 01 into separate plans"
|
|
71
71
|
> ```
|
|
72
72
|
|
|
73
|
-
**Why this is bad:**
|
|
73
|
+
**Why this is bad:** Both calls are wrong. 6 tasks is within the ceiling and 240000 fits the 500000 budget, so plan 01 has no issue (01 and 02 merged would be 8 tasks, so that split is justified). Plans 02 and 03 are a serial split with neither reason (merged 5 tasks / 130000 tokens), so a correct check raises one scope_sanity blocker for that pair with fix "merge 03 into 02" and nothing for plan 01.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Phase Timeline
|
|
2
|
+
|
|
3
|
+
Every `Agent()` run that plan-phase, execute-phase and code-review spawn is recorded in `{phase_dir}/{padded}-TIMELINE.jsonl`, one JSON object per line, append-only. Only the orchestrator writes, on its own checkout, before and after each spawn. An executor never receives a timeline instruction, so a worktree executor is recorded like any other run and nothing is lost when its worktree is removed. The file is committed with the existing planning commits (plan-phase 13d, execute-phase `update_roadmap` and code-review `commit_review`), never per run. When `.planning/` is gitignored that commit reports `skipped_gitignored` by design and the file stays on disk.
|
|
4
|
+
|
|
5
|
+
## Record
|
|
6
|
+
|
|
7
|
+
| Field | Type | Meaning |
|
|
8
|
+
|-------|------|---------|
|
|
9
|
+
| `id` | string | `{phase}-{role}[-{plan}]-{n}`, minted by `start` |
|
|
10
|
+
| `phase` | string | padded phase token, for example `35` |
|
|
11
|
+
| `agent` | string | agent name, defaulted from the role table |
|
|
12
|
+
| `role` | enum | `researcher`, `pattern-mapper`, `planner`, `plan-checker`, `executor`, `code-reviewer`, `verifier`, `other` |
|
|
13
|
+
| `model` | string | the model the orchestrator passed to `Agent()`; `inherit` is recorded literally |
|
|
14
|
+
| `plan` | string or null | plan id for executors, `null` for every other role |
|
|
15
|
+
| `started_at` | string | ISO-8601 UTC |
|
|
16
|
+
| `ended_at` | string or null | ISO-8601 UTC; `null` while the run is open |
|
|
17
|
+
| `duration_ms` | number or null | `ended_at - started_at`, recomputed on read |
|
|
18
|
+
| `outcome` | string or null | return marker mapped in Outcomes; `null` while open |
|
|
19
|
+
| `source` | enum | `plan-phase`, `execute-phase` or `code-review` |
|
|
20
|
+
|
|
21
|
+
`start` appends a full record with null end fields. `end` appends a second complete line with the same `id`. Readers keep the last line per `id`, sort by `started_at` and skip lines that do not parse, so a torn write loses at most one line. A record with `ended_at: null` is incomplete: it is shown as `incomplete` and excluded from wall-clock and agent time.
|
|
22
|
+
|
|
23
|
+
## Commands
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
pp_run timeline start <role> <phase> [--plan P] [--agent A] [--model M] [--source S]
|
|
27
|
+
pp_run timeline end <role> <phase> <outcome> [--plan P] [--id ID]
|
|
28
|
+
pp_run timeline summary <phase> [--banner]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- `start` prints the new id. `end` closes the most recent open record with that role, and that plan when `--plan` is given, and prints the closed record.
|
|
32
|
+
- Synonyms: `--phase`, `--role`, `--outcome` replace the positionals, and `end` takes `--id ID`, or an id positional together with `--outcome`, in place of the role.
|
|
33
|
+
- Defaults: `agent` comes from the role table (`pp-phase-researcher`, `pp-pattern-mapper`, `pp-planner`, `pp-plan-checker`, `pp-executor`, `pp-code-reviewer`, `pp-verifier`); `model` comes from the model-profile resolver when `--model` is omitted; `source` is inferred from the role. Role `other` requires both `--agent` and `--source`.
|
|
34
|
+
- `end` with nothing open exits 1 with reason `timeline_no_open_run`; an unknown or archived phase exits 1 with `phase_not_found`; bad flags exit 1 with `usage`. A failed call never changes the file.
|
|
35
|
+
- Free text (outcome, agent, model) is sanitized and capped at 80 characters before it is written.
|
|
36
|
+
- The clock comes from the CLI. Workflows never compute a duration with `date`.
|
|
37
|
+
- `summary` reads live and archived phases. Plain `summary` prints JSON (or the footer line with `--raw`); `--banner` prints the two completion-block lines.
|
|
38
|
+
|
|
39
|
+
## Call-site rules
|
|
40
|
+
|
|
41
|
+
- Put `start` on the line before the `Agent()` fence and `end` where the return is handled.
|
|
42
|
+
- Every call ends with `|| true`, so a timing failure can never break a phase, and carries no stderr redirection.
|
|
43
|
+
- Key by role (and `--plan {plan_id}` for executors), never by an id held in a shell variable: each fenced block runs in its own shell (issue #381) and `Agent()` is not bash.
|
|
44
|
+
- Pass `--model` only where the `Agent()` model differs from the resolver default: `"{researcher_model}"` for the pattern mapper, `"{executor_model}"` for executors, `inherit` where `Agent()` receives no `model=` (code reviewer, drift-gate mapper).
|
|
45
|
+
- Worktree executors are dispatched in the background, so the executor `end` rides the plan-complete heartbeat in step 4, not the line after the fence.
|
|
46
|
+
- Never put a timeline call inside an agent prompt.
|
|
47
|
+
- Workflows reference this file by plain path, never with an `@` import, so it is read only when a rule is needed.
|
|
48
|
+
|
|
49
|
+
## Sites
|
|
50
|
+
|
|
51
|
+
| Workflow | Section | Role | Flags | End location |
|
|
52
|
+
|----------|---------|------|-------|--------------|
|
|
53
|
+
| plan-phase.md | 5.1 researcher | `researcher` | none | first line under `### Handle Researcher Return` |
|
|
54
|
+
| plan-phase.md | 5.6 capability `ref.agent` dispatch | `other` | `--agent {capId} --source plan-phase` | after the dispatched agent returns |
|
|
55
|
+
| plan-phase.md | 7.8 pattern mapper | `pattern-mapper` | `--model "{researcher_model}"` | under `**Handle return:**` |
|
|
56
|
+
| plan-phase.md | 8 planner | `planner` | none | first line of `## 9. Handle Planner Return` |
|
|
57
|
+
| plan-phase.md | 10 plan checker | `plan-checker` | none | first line of `## 11. Handle Checker Return` |
|
|
58
|
+
| plan-phase.md | 12 revision planner | `planner` | none | on the `After planner returns` line |
|
|
59
|
+
| chunked-planning.md | 8.5.1 outline planner | `planner` | none | under `Handle return:` |
|
|
60
|
+
| chunked-planning.md | 8.5.2 per-plan planner | `planner` | none | step 4 `Verify disk`, before the Retry/Stop offer |
|
|
61
|
+
| execute-phase.md | step 3/4 executor, worktree and sequential mode | `executor` | `--plan {plan_id} --model "{executor_model}"` | start after the plan-start heartbeat; end with the plan-complete heartbeat |
|
|
62
|
+
| execute-phase.md | `verify_phase_goal` verifier | `verifier` | none | start in the `VERIFIER_SKILLS` fence; end in the `verification.status` fence with `"${STATUS:-failed}"` |
|
|
63
|
+
| execute-phase/steps/codebase-drift-gate.md | optional mapper | `other` | `--agent pp-codebase-mapper --source execute-phase --model inherit` | after the mapper returns |
|
|
64
|
+
| code-review.md | `pp-code-reviewer` | `code-reviewer` | `--model inherit` | last line of `commit_review`: `complete` only when REVIEW.md exists with valid frontmatter, else `failed`; `failed` on the agent-failure path |
|
|
65
|
+
|
|
66
|
+
Chunked return path: chunked-planning.md hands `## PLANNING COMPLETE` to step 9 but skips step 9's planner `end` — both chunked runs are already closed, and a third `end` would only print `timeline_no_open_run`.
|
|
67
|
+
|
|
68
|
+
Commit sites: plan-phase 13d, execute-phase `update_roadmap` and code-review `commit_review` add `{phase_dir}/*-TIMELINE.jsonl` to the existing planning commit, so a standalone `/pp-code-review` (or a `--fix` re-run) does not leave the reviewer's lines uncommitted. `cmdCommit` skips the glob when it matches nothing.
|
|
69
|
+
|
|
70
|
+
Banner site: execute-phase `update_roadmap` runs `pp_run timeline summary {phase} --banner`, and the three completion blocks (`## PHASE COMPLETE` on the `--no-transition` path and both `## ✓ Phase {X}: {Name} Complete` blocks) print its stdout verbatim.
|
|
71
|
+
|
|
72
|
+
## Outcomes
|
|
73
|
+
|
|
74
|
+
| Run | Return | Outcome |
|
|
75
|
+
|-----|--------|---------|
|
|
76
|
+
| researcher | `## RESEARCH COMPLETE` | `complete` |
|
|
77
|
+
| researcher | `## RESEARCH BLOCKED` | `blocked` |
|
|
78
|
+
| pattern mapper | `## PATTERN MAPPING COMPLETE` | `complete` |
|
|
79
|
+
| pattern mapper | error or empty | `failed` |
|
|
80
|
+
| planner | `## PLANNING COMPLETE` | `complete` |
|
|
81
|
+
| planner | `## PLANNING INCONCLUSIVE` | `inconclusive` |
|
|
82
|
+
| planner | `## CHECKPOINT REACHED` | `checkpoint` |
|
|
83
|
+
| planner | `## PHASE SPLIT RECOMMENDED` | `split_recommended` |
|
|
84
|
+
| planner | `## ⚠ Source Audit` | `source_audit_gaps` |
|
|
85
|
+
| planner | no marker (filesystem fallback) | `fallback` |
|
|
86
|
+
| plan checker | `## VERIFICATION PASSED` | `passed` |
|
|
87
|
+
| plan checker | `## ISSUES FOUND` | `issues_found` |
|
|
88
|
+
| plan checker | no marker | `fallback` |
|
|
89
|
+
| chunked outline | `## OUTLINE COMPLETE` | `complete`, otherwise `failed` |
|
|
90
|
+
| chunked per-plan | plan file on disk | `complete`; missing: `failed` |
|
|
91
|
+
| executor | plan-complete heartbeat word | `complete`, `failed` or `checkpoint`; `fallback` when the spot-check confirmed completion |
|
|
92
|
+
| verifier | `$STATUS` verbatim | `passed`, `gaps_found`, `human_needed`, `missing` or `unknown`; empty: `failed` |
|
|
93
|
+
| code reviewer, drift-gate mapper, capability agents | agent result | `complete` or `failed` |
|
|
94
|
+
|
|
95
|
+
Free text is accepted and shown verbatim after sanitizing.
|
|
96
|
+
|
|
97
|
+
## Wall-clock
|
|
98
|
+
|
|
99
|
+
- Each source (`plan-phase`, `execute-phase`, `code-review`) gets one span: the latest `ended_at` minus the earliest `started_at` over that source's completed runs, so parallel executors count once.
|
|
100
|
+
- Total wall-clock is the length of the union of those spans. It equals the plain sum when the spans are disjoint, so idle days between planning and executing are excluded, and a code review that runs inside the execute span counts once.
|
|
101
|
+
- `elapsed` is the first start to the last end. It appears in the footer only when it differs from the total.
|
|
102
|
+
- Agent time is the sum of completed run durations.
|
|
103
|
+
- Durations are compact: `38s`, `45m 10s`, `1h 12m`, `3h 02m`. `Started` is local time `HH:MM`, with the date shown once per table (a run on another day carries `MM-DD HH:MM`).
|
|
104
|
+
- Footer: `Total wall-clock: 2h 14m · agent time 3h 02m · 12 runs (1 incomplete)`, plus `· elapsed {duration}` when it differs.
|
|
105
|
+
- Banner (two lines): `Wall-clock: 2h 14m (12 runs)` and `Longest: executor 35-03 (claude-opus-4-7) 41m · planner (opus) 22m · verifier (sonnet) 17m`. Each longest entry is `{role}[ {plan}][ ({model})] {duration}`; the model is omitted only when it is `inherit`. With fewer than three completed runs there are fewer entries.
|
|
106
|
+
- No records (every phase executed before the timeline existed): pp-stats has no timeline section for the phase, the Wall-clock column shows `—`, plain `summary` prints `no recorded runs`, and `--banner` prints nothing and exits 0.
|
|
107
|
+
- Known limit: a source whose runs are days apart (for example a re-plan after execution) forms one span and counts the idle gap.
|
|
@@ -88,6 +88,38 @@ A plan should not interleave multiple checkpoint types with implementation tasks
|
|
|
88
88
|
|
|
89
89
|
If a decision from CONTEXT.md says "display cost calculated from billing table in impulses", the plan must deliver exactly that. Not "static label /min" as a "v1". If the phase is too complex, recommend a phase split instead of silently reducing scope.
|
|
90
90
|
|
|
91
|
+
## Plan-Split Anti-Patterns
|
|
92
|
+
|
|
93
|
+
A plan is split for exactly two reasons: **parallelism** (independent subsystems, disjoint `files_modified`, same wave) or **budget** (merged, the work exceeds `plan_budget_tokens` or 6 tasks). Anything else is over-splitting: every extra plan pays its own executor, review and verification run.
|
|
94
|
+
|
|
95
|
+
### Bad — Serial single-concern work split to fit a task count
|
|
96
|
+
|
|
97
|
+
"Add authentication" on an empty repository, `context_window: 200000` (`plan_budget_tokens` 100000), planned as three plans each alone in its wave:
|
|
98
|
+
|
|
99
|
+
```yaml
|
|
100
|
+
# 01-01 wave 1 schema 2 tasks context_estimate: 35000
|
|
101
|
+
# 01-02 wave 2 endpoints 2 tasks context_estimate: 35000 depends_on: [01-01]
|
|
102
|
+
# 01-03 wave 3 middleware 2 tasks context_estimate: 35000 depends_on: [01-02]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Why bad:** nothing runs in parallel and no plan is near the budget. 01-01 and 01-02 merge to 4 tasks / 70000 tokens, within both limits. `check plan-sizing` flags both pairs and reports `min_plans: 2`.
|
|
106
|
+
|
|
107
|
+
### Good — Merge while the estimate fits; split only with a visible reason
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
# One plan: 5 tasks, context_estimate: 90000 (fits 100000)
|
|
111
|
+
# Honest estimate 105000 -> two plans, the budget reason is visible:
|
|
112
|
+
# 01-01 4 tasks context_estimate: 70000
|
|
113
|
+
# 01-02 2 tasks context_estimate: 35000 depends_on: [01-01]
|
|
114
|
+
# At context_window: 1000000 the same 105000 fits one plan.
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Two plans on independent subsystems with disjoint `files_modified` in the same wave are the parallelism reason.
|
|
118
|
+
|
|
119
|
+
### Merging a flagged pair
|
|
120
|
+
|
|
121
|
+
Merge one pair at a time: the first `unjustified_splits` pair in wave order. Fold the later plan's tasks, `files_modified`, `requirements`, `must_haves` and estimate into the earlier plan; delete the later PLAN.md; renumber later plans and fix every `depends_on` and `wave`; re-run `pp_run check plan-sizing <phase> --raw` and `pp_run query verify.plan-structure` on every renumbered or merged PLAN.md, check that every `depends_on` names a plan that still exists (neither command catches a dangling one), and repeat until `block` is false and no plan reports errors. Overlapping pairs share a plan (01→02→03 reports both (01, 02) and (02, 03)), so merging every reported pair at once can overshoot the budget; one at a time ends at `min_plans` plans. Plans in the same wave with disjoint files, and pairs whose merge exceeds 6 tasks or `plan_budget_tokens`, stay split. Gap-closure plans and phase splits (`## PHASE SPLIT RECOMMENDED`) are separate mechanisms.
|
|
122
|
+
|
|
91
123
|
## Comment-Text Discipline (HARD GATE)
|
|
92
124
|
|
|
93
125
|
> Enforced at plan-write time by `verify.plan-structure` (the `validate_plan` step). Issue #429.
|
|
@@ -24,7 +24,7 @@ PLAN.md IS the prompt (not a document that becomes one). Contains:
|
|
|
24
24
|
| 50-70% | DEGRADING | Efficiency mode begins |
|
|
25
25
|
| 70%+ | POOR | Rushed, minimal |
|
|
26
26
|
|
|
27
|
-
**Rule:** Plans should complete within ~50% context.
|
|
27
|
+
**Rule:** Plans should complete within ~50% context. Each plan: up to 6 tasks while its summed estimate stays within `plan_budget_tokens` (50% of the configured `context_window`); the task count follows the estimate, never a target. Split only for parallelism or budget.
|
|
28
28
|
|
|
29
29
|
## Ship Fast
|
|
30
30
|
|
|
@@ -47,19 +47,20 @@ Plan -> Execute -> Ship -> Learn -> Repeat
|
|
|
47
47
|
|
|
48
48
|
## Task Sizing
|
|
49
49
|
|
|
50
|
-
Each task targets **10–30% context consumption
|
|
50
|
+
Each task targets **10–30% context consumption** at the 200k calibration — ~20-60k tokens, a band stated in tokens so it holds at every `context_window` (a larger window fits more tasks per plan, not larger tasks).
|
|
51
51
|
|
|
52
52
|
| Context Cost | Action |
|
|
53
53
|
|--------------|--------|
|
|
54
|
-
| < 10%
|
|
55
|
-
| 10-30%
|
|
56
|
-
| > 30%
|
|
54
|
+
| < 10% (< ~20k tokens) | Too small — combine with a related task |
|
|
55
|
+
| 10-30% (~20-60k tokens) | Right size — proceed |
|
|
56
|
+
| > 30% (> ~60k tokens) | Too large — split into two tasks |
|
|
57
57
|
|
|
58
58
|
**Context cost signals (use these, not time estimates):**
|
|
59
|
-
- Files modified: 0-3 = ~
|
|
60
|
-
- New subsystem: ~
|
|
61
|
-
- Migration + data transform: ~
|
|
62
|
-
- Pure config/wiring: ~
|
|
59
|
+
- Files modified: 0-3 = ~20-30k tokens, 4-6 = ~40-60k, 7+ = ~80k+ (split the task)
|
|
60
|
+
- New subsystem: ~50-70k tokens
|
|
61
|
+
- Migration + data transform: ~60-80k tokens
|
|
62
|
+
- Pure config/wiring: ~10-20k tokens
|
|
63
|
+
- A plan's `context_estimate` is the sum of its task estimates.
|
|
63
64
|
|
|
64
65
|
**Too large signals:** Touches >3-5 files, multiple distinct chunks, action section >1 paragraph.
|
|
65
66
|
|
|
@@ -125,11 +126,13 @@ No overlap → can run parallel. File in multiple plans → later plan depends o
|
|
|
125
126
|
|
|
126
127
|
The resolved granularity is provided in the planning context as `**Granularity:** <value>`. Read that value and apply the corresponding row below. When no explicit value is present, default to Standard.
|
|
127
128
|
|
|
128
|
-
| Granularity | Typical Plans/Phase |
|
|
129
|
-
|
|
130
|
-
| Coarse | 1-3 |
|
|
131
|
-
| Standard | 3-5 |
|
|
132
|
-
| Fine | 5-10 |
|
|
129
|
+
| Granularity | Typical Plans/Phase |
|
|
130
|
+
|-------------|---------------------|
|
|
131
|
+
| Coarse | 1-3 |
|
|
132
|
+
| Standard | 3-5 |
|
|
133
|
+
| Fine | 5-10 |
|
|
134
|
+
|
|
135
|
+
Plans/Phase is typical for phases with several independent subsystems. Granularity never splits serial single-concern work: such a phase is 1-2 plans at every granularity.
|
|
133
136
|
|
|
134
137
|
Derive plans from actual work. Granularity determines compression tolerance, not a target.
|
|
135
138
|
|
|
@@ -36,7 +36,7 @@ Group by plan, dimension, severity.
|
|
|
36
36
|
| task_completeness | Add missing elements to existing task |
|
|
37
37
|
| dependency_correctness | Fix depends_on, recompute waves |
|
|
38
38
|
| key_links_planned | Add wiring task or update action |
|
|
39
|
-
| scope_sanity | Split
|
|
39
|
+
| scope_sanity | Over the 6-task ceiling or `plan_budget_tokens` (`over_ceiling` / `over_budget`): split the unexecuted plan; an executed plan (`has_summary` true) is reported only. Flagged serial split (`unjustified_splits`): merge the pair (planner-antipatterns.md "Plan-Split Anti-Patterns"). Serial pair without an estimate (`unestimated_serial`): add `context_estimate` (an `unparseable_estimate` value: rewrite as a bare integer or `60k`), then merge or keep the split as the check reports |
|
|
40
40
|
| must_haves_derivation | Derive and add must_haves to frontmatter |
|
|
41
41
|
|
|
42
42
|
### Step 4: Make Targeted Updates
|
|
@@ -236,7 +236,7 @@ Generated from `CONFIG_DEFAULTS` (configuration.cjs) and `VALID_CONFIG_KEYS` (co
|
|
|
236
236
|
| `phase_naming` | string | `"sequential"` | `"sequential"`, `"custom"` | Phase numbering: auto-increment or arbitrary string IDs |
|
|
237
237
|
| `project_code` | string\|null | `null` | Any short string | Prefix for phase dirs (e.g., `"CK"` produces `CK-01-foundation`) |
|
|
238
238
|
| `response_language` | string\|null | `null` | Any language name | Language for user-facing prompts (e.g., `"Portuguese"`, `"Japanese"`) |
|
|
239
|
-
| `context_window` | number | `200000` | `200000`, `1000000` | Context window size; set `1000000` for 1M-context models |
|
|
239
|
+
| `context_window` | number | `200000` | `200000`, `1000000` | Context window size; set `1000000` for 1M-context models. Also sets the per-plan budget (`plan_budget_tokens` = 50% of the window), which the planner sizes plans to and `check plan-sizing` reads |
|
|
240
240
|
| `resolve_model_ids` | boolean\|string | `false` | `false`, `true`, `"omit"` | Map model aliases to full Claude IDs; `"omit"` returns empty string |
|
|
241
241
|
| `context` | string\|null | `null` | `"dev"`, `"research"`, `"review"` | Execution context profile that adjusts agent behavior: `"dev"` for development tasks, `"research"` for investigation/exploration, `"review"` for code review workflows |
|
|
242
242
|
| `review.models.<cli>` | string\|null | `null` | Any model ID string | Per-CLI model override for /pp:review (e.g., `review.models.gemini`). Falls back to CLI default when null. |
|
|
@@ -268,7 +268,8 @@ Set via `workflow.*` namespace in config.json (e.g., `"workflow": { "research":
|
|
|
268
268
|
| `workflow.build_command` | string\|null | `null` | Any shell command | Build gate command run by the post-merge gate. Unset → build step auto-detected/skipped. |
|
|
269
269
|
| `workflow.inline_plan_threshold` | number | `2` | `0`–`10` | Plans with ≤N tasks execute inline instead of spawning a subagent |
|
|
270
270
|
| `workflow.code_review` | boolean | `true` | `true`, `false` | Enable built-in code review step in the ship workflow |
|
|
271
|
-
| `workflow.code_review_depth` | string | `"standard"` | `"
|
|
271
|
+
| `workflow.code_review_depth` | string | `"standard"` | `"quick"`, `"standard"`, `"deep"` | Depth level for code review analysis in the ship workflow |
|
|
272
|
+
| `workflow.ceremony` | string | `"proportional"` | `"proportional"`, `"full"` | `proportional` classifies each phase at plan-phase time and skips gates the verdict does not need; `full` runs the whole gate stack as before. Override per phase with `--full` or a `**Ceremony:** full` ROADMAP line. See references/ceremony.md |
|
|
272
273
|
| `workflow._auto_chain_active` | boolean | `false` | `true`, `false` | Internal: tracks whether autonomous chaining is active |
|
|
273
274
|
| `workflow.security_enforcement` | boolean | `true` | `true`, `false` | Enable threat-model-anchored security verification via `/pp:secure-phase`. When `false`, security checks are skipped entirely |
|
|
274
275
|
| `workflow.security_asvs_level` | number | `1` | `1`, `2`, `3` | OWASP ASVS verification level. Level 1 = opportunistic, Level 2 = standard, Level 3 = comprehensive |
|