marketplace/bundles/plan-marshall/skills/phase-3-outline/SKILL.md
Two-lane solution outline creation - light lane for bounded localized changes, deep lane for codebase-wide discovery
npx skillsauth add cuioss/plan-marshall phase-3-outlineInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Role: Two-lane workflow skill for creating solution outlines. Routes on the planning lane resolved by the phase-1-init lane router (status.metadata.planning_lane).
Prerequisite: Request must be refined (phase-2-refine completed); the planning lane (light/deep) is set by the phase-1-init lane router.
Skill: plan-marshall:persona-plan-marshall-agent
Shared lifecycle patterns: See phase-lifecycle.md for entry protocol, completion protocol, and error handling convention.
Execution mode: Follow workflow steps sequentially. Each step that invokes a script has an explicit bash code block.
Prohibited actions:
.plan/ files directly — all access must go through python3 .plan/execute-script.py manage-* scriptsmanage-status transition.plan/local/plans/{plan_id}/ during outline. The outline phase is strictly analytical: it discovers, classifies, and writes solution documents into the plan workspace. Edits to any path under marketplace/, target/, .claude/, test/, doc/, or any other repository directory are categorically forbidden — those mutations are the responsibility of phase-5-execute. If a recipe or domain workflow proposes a fix, capture it as a deliverable in solution_outline.md rather than applying it directly.*-doctor tool (e.g., plugin-doctor, plan-doctor) carrying fix, apply, --apply, or --fix during outline. Doctor tools may only be invoked in their read-only modes (verify, check, no flags) to surface findings. The apply/fix/--fix/--apply surfaces mutate source files and bypass the per-plan workspace boundary above — they are reserved for phase-5-execute task bodies that the planner explicitly authorized via a deliverable. This applies equally to Bash, Skill:, and SlashCommand: invocation shapes.Constraints:
This phase dispatches under one role key: phase-3-outline (resolves through phase-3-outline.default; track={simple|complex} is a runtime input — both tracks share the envelope and resolver lookup). The Complex Track bundles Steps 9c (per-deliverable design-intent classification) and 10 (the heavyweight design body) into one phase-3-outline envelope — the per-deliverable loop iterates inside the dispatch. Mechanical sub-procedures stay inline: Step 4 detect-change-type uses manage-status:change-type-heuristic (heuristic-first, dispatches via effort read --default when ambiguous); Simple Track Step 6 target validation is a Bash one-liner; Complex Track Step 9 domain-resolution and Step 10 consumer-sweep run as scripts. Step 11 Q-Gate validation activation is signaled by setting qgate_validation_required: true in the phase return TOON; the orchestrator (plan-marshall:plan-marshall/workflow/planning-outline.md) reads that flag and issues q-gate-validation as a sibling top-level Task: plan-marshall:{target} dispatch — the phase body cannot spawn it directly because the Task tool is unavailable inside an execution-context-{level} subagent. The flag is set to false (no orchestrator dispatch) when the operator's plan.phase-3-outline.q_gate_validation knob resolves to off, or when the surgical-bypass predicate holds (scope_estimate == surgical AND change_type ∈ {bug_fix, tech_debt, verification} AND deliverable_count == 1). For the rationale see dispatch-granularity.md § 3–4 (bundle when steps share context; per-iteration only when models differ or parallel).
The Complex Track per-deliverable loop (Steps 9c + 10) iterates over the deliverable list — but the inputs feeding the per-deliverable design body are loop-invariant: they are written before the loop begins (phase-2-refine, phase-3-outline entry, Step 9 domain-resolution) and are not mutated by the loop body. The dispatched agent MUST read each of the following inputs ONCE at phase entry and reference the cached values throughout every per-deliverable iteration:
manage-plan-documents request read --plan-id {plan_id} --section clarified_request).domains and compatibility (read via manage-files read --plan-id {plan_id} --file references.json).module_mapping.toon if present at .plan/local/plans/{plan_id}/module_mapping.toon.manage-architecture overview at phase entry).manage-adr scan progressive-disclosure surface. Run manage-adr scan --affects {module} (and/or --tag {topic}) for each declared module, and load the returned summary fields into context so deliverable authoring aligns with established decisions and surfaces superseded/deprecated ADRs as constraints. The metadata that makes this scan cheap is authored per the manage-adr skill — see marketplace/bundles/plan-marshall/skills/manage-adr/SKILL.md for the scan subcommand contract; do not restate it here. The detailed consultation procedure (which filters to use, how to fold summaries into authoring, the contradiction-is-a-design-signal expectation) lives in standards/outline-workflow-detail.md § ADR consultation.Prohibited actions:
See extension-api/standards/dispatch-granularity.md § 5.1 (Heuristic 2 — bundle when steps share context) for the granularity rationale.
outline_prompt envelopeA dispatched phase-3-outline leaf cannot fire AskUserQuestion — operator input is unreachable inside a dispatched execution-context envelope (see ref-workflow-architecture/standards/agents.md § Leaf cannot fire AskUserQuestion). When outline authoring surfaces operator-facing design uncertainties or open questions, the leaf MUST NOT prompt in-leaf and MUST NOT silently guess. Instead it completes the outline fully — writing solution_outline.md with its best-judgment resolution of every open point — and returns ALL open questions together in ONE outline_prompt prompt-required envelope on the return TOON (the persist-and-continue envelope shape from agents.md).
The orchestrator (plan-marshall:plan-marshall/workflow/planning-outline.md) reads the outline_prompt envelope, fires ONE batched AskUserQuestion covering every question, and re-dispatches phase-3-outline at most once with all answers baked in. Batching the questions this way bounds a normal outline to a single answer-laden feedback re-dispatch — never a per-question round-trip.
The envelope rides back on an otherwise-complete status: success return; emit it only when at least one genuine open question remains, and omit it entirely when the outline resolved cleanly. Envelope shape:
outline_prompt:
questions[N]{id,question,header,options,recommended}:
...
.plan/execute-script.py calls
manage-*scripts resolve.plan/via the uniform cwd walk-up (ADR-002) — the nearest ancestor of cwd containing.plan/local. Phase-3-outline runs on the main checkout, so they resolve to main's.plan/; do NOT pin cwd, do NOT pass routing flags, and never useenv -C. Build / CI / Sonar scripts accept--plan-id {plan_id}(preferred — auto-resolves the worktree viamanage-status get-worktree-path) or--project-dir {worktree_path}(explicit override / escape hatch); the two flags are mutually exclusive. Seeplan-marshall:tools-script-executor/standards/cwd-policy.md.
manage-* script callsEvery manage-* script call documented below carries the following exit-code contract unless a step explicitly states otherwise:
exit_code == 0: parse the returned TOON and use the value as the step describes. exit 0 does NOT imply the operation succeeded — the manage-* scripts follow the canonical output contract (pm-plugin-development:plugin-script-architecture/standards/output-contract.md), under which an operation failure (file_not_found, field_not_found, plan_not_found, validation rejection, already-exists, etc.) exits 0 and carries the verdict in the stdout TOON status: error payload. Branch on the TOON status / value field to detect operation failures; never infer "the field was present" or "the plan exists" from a zero exit code.exit_code != 0: STOP the phase and return an error TOON to the orchestrator carrying the script's stderr verbatim. A non-zero exit is reserved for a genuine script crash (exit 1 — uncaught exception, corrupt/non-dict payload, missing required file) or an argparse_rejection (exit 2 — silent swallowing of wrong_parameters rejections is the prohibited anti-pattern). The phase MUST NOT proceed on a non-zero exit; "log and continue" is equally forbidden.Step-level exceptions to this default — calls whose non-zero exit is itself the signal (e.g., manage-files exists returning exists: false, or manage-status get-worktree-path returning an empty worktree_path) — are documented inline in the step that issues them. Treat the absence of an inline exception as the default "hard-stop" behaviour above.
Operation-failure carve-out (manage-* read verbs): Because operation failures exit 0, a step that reads a manage-* read verb (get, read, get-context, set-list, and the like) to discover whether a field/plan/file is present MUST detect the not-found / validation outcome by inspecting the TOON status (status: error plus the precise error code) — NOT by testing exit_code != 0. Reserving exit_code != 0 for crash/argparse detection and reading the TOON for operation-failure detection are two distinct branches; conflating them (treating any non-zero exit as "field absent") regresses the contract and is forbidden.
The outline runs one of two lanes, selected by status.metadata.planning_lane (resolved by the phase-1-init lane router — see Step 4c below). Each lane reuses one of the two deliverable-authoring procedures:
| Lane | Procedure reused | Approach | |------|------------------|----------| | light | Simple-Track authoring (Steps 6–8) | Bounded-discovery deliverable creation in the collapsed light-lane envelope — refine-no-loop + Simple-outline + deliverable-derivation folded into one dispatch | | deep | Complex-Track authoring (Steps 9–11) | Load domain skill for discovery/analysis; full Complex-Track outline + q-gate-validation |
Lane determined by: the phase-1-init lane router (manage-status planning-lane route), persisted to status.metadata.planning_lane. There is no separate refine-time track-selection classifier — the lane decision is the sole selector, and references.json:track is derived from it (deep ⇒ complex, light ⇒ simple).
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| plan_id | string | Yes | Plan identifier |
The Phase Entry Protocol's phase_handshake verify --phase 2-refine --strict call (see ref-workflow-architecture/standards/phase-lifecycle.md) asserts the worktree-resolution contract before any phase-3-outline work begins. Phase-3-outline runs on the main checkout — the worktree directory and feature branch are not created until phase-5-execute Step 2.5. An empty worktree_path while metadata.use_worktree==true is ALWAYS worktree_unresolved (there is no deferred-window carve-out): a use_worktree==true plan carries a real worktree_path only once phase-5 materializes the worktree, so an empty path is a metadata defect, not a legitimate transitional state. The strict path-not-found / path-stale failures also fire when worktree_path is set but does not resolve cleanly. Plans with metadata.use_worktree==false skip the assertion (main-checkout flow). See workflow-integration-git/standards/worktree-handling.md for the canonical lifecycle contract.
Step 2: Load Inputs → Step 3: Recipe Detection → Step 4: Detect Change Type → Step 4c: Route by Planning Lane → Step 5: Select Authoring Procedure → {light/Simple: Steps 6-8 | deep/Complex: Steps 9-11} → Step 12: Return
Purpose: On re-entry (after Q-Gate or user review flagged issues), address unresolved findings before re-running the outline.
Query pending findings for phase 3-outline. For each finding: analyze context, verify file paths exist on disk, create assessments or update deliverables as needed, then resolve the finding with taken_into_account. Continue with normal Steps 2..12 after corrections are applied. When a finding scopes to one peer of a symmetric data structure (ladder, parallel-array, peer-set, matrix), apply the symmetric-peer-audit rule: audit every peer in the same structure for the same defect and apply the same fix in the same outline revision — see standards/outline-workflow-detail.md § symmetric-peer-audit.
For detailed procedures (query commands, finding-type handling, resolution logging), see standards/outline-workflow-detail.md.
Purpose: Load track, request, compatibility, and context from phase-2-refine output and sinks.
Note: This skill receives track, track_reasoning, scope_estimate, compatibility, and compatibility_description from the phase-2-refine return output. These values are passed as input parameters.
The track value (simple | complex) is received from the phase-2-refine return output, not read from references.json.
If track not provided in input, extract from decision.log:
python3 .plan/execute-script.py plan-marshall:manage-logging:manage-logging \
read --plan-id {plan_id} --type decision | grep "(plan-marshall:phase-2-refine) Track:"
Parse the output to extract track value from: (plan-marshall:phase-2-refine) Track: {track} - {reasoning}
Read request (clarified_request falls back to original_input automatically):
python3 .plan/execute-script.py plan-marshall:manage-plan-documents:manage-plan-documents request read \
--plan-id {plan_id} \
--section clarified_request
Check existence first (file is created by phase-2-refine and may not exist):
python3 .plan/execute-script.py plan-marshall:manage-files:manage-files exists \
--plan-id {plan_id} \
--file work/module_mapping.toon
If exists: true, read it:
python3 .plan/execute-script.py plan-marshall:manage-files:manage-files read \
--plan-id {plan_id} \
--file work/module_mapping.toon
If exists: false, continue without module mapping — downstream steps will use discovery or request context instead.
python3 .plan/execute-script.py plan-marshall:manage-references:manage-references get \
--plan-id {plan_id} --field domains
The compatibility and compatibility_description values are received from the phase-2-refine return output.
If compatibility not provided in input, read from marshal.json:
python3 .plan/execute-script.py plan-marshall:manage-config:manage-config \
plan phase-2-refine get --field compatibility --audit-plan-id {plan_id}
Store as compatibility and derive compatibility_description from the value:
breaking → "Clean-slate approach, no deprecation nor transitionary comments"deprecation → "Add deprecation markers to old code, provide migration path"smart_and_ask → "Assess impact and ask user when backward compatibility is uncertain"The simplicity and simplicity_description values are received from the phase-2-refine return output.
If simplicity not provided in input, read from marshal.json (default lean when unconfigured):
python3 .plan/execute-script.py plan-marshall:manage-config:manage-config \
plan phase-2-refine get --field simplicity --audit-plan-id {plan_id}
Store as simplicity and derive simplicity_description from the value:
lean → "Implement the strict minimum; remove or inline surplus structure"pragmatic → "Prefer minimal, but keep low-risk structure that aids readability"defensive → "Retain belt-and-suspenders structure (guards, abstraction seams) where uncertain"python3 .plan/execute-script.py plan-marshall:manage-logging:manage-logging \
work --plan-id {plan_id} --level INFO --message "[STATUS] (plan-marshall:phase-3-outline) Starting outline: track={track}, domains={domains}, compatibility={compatibility}"
Purpose: Recipe-sourced plans skip change-type detection and use the recipe skill directly for discovery, analysis, and deliverable creation.
Check plan_source metadata. If recipe: read recipe metadata (recipe_key, recipe_skill, and built-in-only fields), resolve default_change_type from recipe config, load the recipe skill with input parameters, then skip Steps 4-11 and jump directly to Step 12. Recipe deliverables are deterministic architecture-to-deliverable mappings — Q-Gate is skipped.
If plan_source != recipe or field not found: continue with normal Step 4.
For detailed procedures (metadata reads, recipe resolution, skill loading), see standards/outline-workflow-detail.md.
Purpose: Determine the change type for agent routing.
Run the deterministic classifier first; only dispatch the LLM workflow on the ambiguous branch.
Step 4a — Heuristic classifier (deterministic, no envelope):
python3 .plan/execute-script.py plan-marshall:manage-status:manage-status \
change-type-heuristic --plan-id {plan_id} --persist
The script reads clarified_request (falling back to original_input) from request.md, scores it against the fixed keyword tables, applies the compound-intent guard and the bug-fix-vs-tech-debt object disambiguation, and either:
feature / bug_fix / tech_debt / enhancement / verification / analysis with ambiguous=false (and persists to status.metadata.change_type with --persist), ORambiguous=true when no keyword fires, the top two scores tie, or confidence falls below 0.7.Step 4b — LLM fallback (only when ambiguous=true):
Dispatch the detect-change-type workflow (plan-marshall:phase-3-outline/workflow/detect-change-type.md via execution-context-{level} resolved from effort). The workflow persists change_type to status.json metadata itself. Skip this dispatch when Step 4a resolved without ambiguity — the heuristic already wrote the value.
For detailed procedures (agent spawning, metadata read, post-check override logic), see standards/outline-workflow-detail.md.
The planning lane (resolved by the phase-1-init lane router — status.metadata.planning_lane) is the structural lane selector that subsumes the legacy Simple/Complex track classifier. Read it once at phase entry:
python3 .plan/execute-script.py plan-marshall:manage-status:manage-status metadata \
--plan-id {plan_id} --get --field planning_lane
planning_lane == light → the orchestrator dispatches the light-lane collapsed scoping workflow (plan-marshall:phase-3-outline/workflow/light-lane.md), which folds refine-no-loop + Simple-outline + deliverable-derivation into ONE envelope with discovery bounded to the declared affected files + their one-hop neighbours (cap 25). That doc owns the full light-lane flow including the DQ3 one-way escalation ratchet (manage-status planning-lane escalate) that self-promotes to deep when evidence contradicts the cheap classification. The inline Steps 5–12 below are NOT run for a light-lane plan.planning_lane == deep (or absent / unresolved) → run today's Complex-Track flow inline (Step 5 → Step 9 → Step 11 → Step 12). The deep lane is the refine-loop + Complex-outline + q-gate-validation pipeline, unchanged.The lane decision replaces the Simple/Complex track-selection classifier — on an escalation the light-lane envelope returns outcome: escalate_to_deep and the orchestrator re-dispatches the deep lane fresh. See workflow/light-lane.md and manage-status Canonical invocations → planning-lane.
The planning lane (Step 4c) determines which deliverable-authoring procedure runs — there is no separate refine-time track classifier:
light-lane.md invokes the Simple-Track authoring rules (File-type classifier, deliverable template, Step 9c design-notes) directly. The Steps 6–8 procedure below is the authoritative source those rules reference.The references.json:track value (deep ⇒ complex, light ⇒ simple) is the persisted record of this selection; the lane is the live selector.
For localized changes where targets are already known from module_mapping. The light lane reuses this procedure inside its collapsed envelope (bounded discovery); the deep lane does not run it (deep ⇒ Complex-Track).
| Step | Purpose | Key Action |
|------|---------|------------|
| 6. Validate Targets | Verify target files/modules exist | ls -la {target_path} for each target |
| 7. Create Deliverables | Map module_mapping to deliverables | MUST classify each deliverable's affected_files against the File-type classifier (six buckets: production_only / test_only / documentation_only / mixed_code / mixed_with_docs / unknown) BEFORE assigning profiles[]. For any deliverable that touches an existing skill, MUST also run the Step 9c design-intent classification and emit the resulting **Design notes:** block — this is track-agnostic and applies on the Simple Track too, so the deliverable self-satisfies §2.17 (Architecture-Mismatch) on the first validation pass. Use deliverable template, resolve verification commands via architecture resolve. The resolved bucket MUST be recorded as a comment in the **Profiles:** block (see Deliverable Template below). |
| 8. Simple Q-Gate | Lightweight verification (with surgical bypass) | Bypass when surgical+bug_fix/tech_debt/verification+1 deliverable; otherwise check target existence + request alignment |
Before assigning profiles[] to any deliverable, every author MUST classify the deliverable's **Affected files:** list against the six-bucket file-type classifier. The buckets, predicates, and profile assignments are documented in standards/outline-workflow-detail.md § File-type classifier. The rule is normative — a documentation_only deliverable MUST carry the implementation profile only and never module_testing. The aggregator that produces the bucket lives in manage-execution-manifest._classify_paths_via_extensions; per-domain predicates are owned by each bundle's ExtensionBase.classify_paths() override.
This rule is track-agnostic — it applies to deliverable authoring on both the Simple Track (Step 7) and the Complex Track (Step 10).
When a deliverable changes a default value, a constant, or an enum member, the author MUST identify and enumerate every existing test that asserts the old value, add those test files to the deliverable's **Affected files:**, and describe the required test update in **Change per file:**. The existing-test sweep is a first-class part of the deliverable — it is NOT deferred to any new test file the plan introduces.
To enumerate the affected tests, sweep the test tree by identifier first, literal value only as a fallback:
Grep with \b{identifier}\b (or architecture find --pattern '*{identifier}*' for the structured inventory) across test/. Anchoring on the symbol name finds every test that references the changed member regardless of how it asserts the value, and the word boundary prevents substring false hits (e.g. MAX matching MAX_RETRIES).False, True, 0, 1, None, "") on their own — they produce overwhelming false positives. Pair the literal with the surrounding assertion or key context (e.g. {field_name}.*1) to keep the match precise.The deliverable's resolved file-type bucket reflects the added test files: a documentation_only or production_only deliverable that now enumerates existing tests becomes mixed_code (production + test) or test_only, so module_testing becomes a valid profile per the File-type classifier.
The downstream phase-4-plan value-change rule carries these enumerated existing-test targets into the module_testing task's steps[] and anchors the obligation into the task description, so the executing agent updates every existing test asserting the old value.
Step 6 may also refine scope_estimate: After deliverables crystalize and the concrete Affected files lists are known, phase-3-outline MAY downgrade scope_estimate (e.g., single_module → surgical) when the final deliverable composition narrows the actual scope. Persist any change via manage-references set --field scope_estimate. Refinement happens BEFORE Step 8 so the bypass rule sees the refined value.
Coverage contract: deliverable composition is where a per-deliverable scope × thoroughness cell would be declared —
scope_estimateis the scope dial; thoroughness (coverage breadth + relation-tracing depth) is its orthogonal partner. The coupling constraintreject thoroughness ≥ T4 ∧ scope < componentmeans a relation-tracing deliverable forces scope ≥component. See the two-dial ladders, the grade-to-the-floor rule, and the coupling constraint inpersona-plan-marshall-agent/standards/thoroughness.md.
Step 8 — Q-Gate surgical bypass rule (evaluated BEFORE dispatching the lightweight Q-Gate checks):
Bypass Q-Gate when ALL of the following are true:
scope_estimate == surgical, ANDchange_type ∈ {bug_fix, tech_debt, verification}, ANDdeliverable_count == 1 (exactly one deliverable was created in Step 7)When bypass fires, log the decision and skip directly to Step 12:
python3 .plan/execute-script.py plan-marshall:manage-logging:manage-logging \
decision --plan-id {plan_id} --level INFO --message "(plan-marshall:phase-3-outline:qgate-bypass) Q-Gate skipped — scope_estimate=surgical, change_type={change_type}, 1 deliverable"
Otherwise, run the Simple Q-Gate checks documented in the detail standards. After Step 8, proceed to Step 12.
For detailed procedures (validation commands, deliverable template, verification resolution, Q-Gate checks, bypass rule examples), see standards/outline-workflow-detail.md.
For codebase-wide changes requiring discovery and analysis.
| Step | Purpose | Key Action |
|------|---------|------------|
| 9. Resolve Domain Skill | Route to domain-specific or generic instructions | resolve-outline-skill --domain {domain}, then load change-{change_type}.md |
| 9c. Read Target Skill Design Intent (track-agnostic — also runs from Simple Track Step 7) | For each deliverable that touches an existing skill, classify the skill's design model and record it on the deliverable | Read the target skill's SKILL.md and design-intent docs; classify as script-deterministic, LLM-driven, or hybrid; record the classification in the deliverable's **Design notes:** block; reroute or justify when the proposed implementation contradicts the model. This classification is NOT Complex-Track-only — the Simple Track runs the same procedure from Step 7 when a deliverable touches an existing skill, so the resulting **Design notes:** block lets the deliverable self-satisfy §2.17 on the first pass. Detailed procedure: standards/outline-workflow-detail.md. |
| 10. Execute Workflow | Run discovery, analysis, write solution | Follow change-type instructions, resolve verification commands, write solution_outline.md. For each composed deliverable, MUST apply the File-type classifier to its affected_files BEFORE assigning profiles[] — the resolved bucket MUST be recorded as a comment in the **Profiles:** block (see Deliverable Template below). Step 10 includes a consumer-sweep when the deliverable deletes/renames a public symbol — see consumer-sweep.md. |
| 11. Q-Gate Verification | Signal q-gate-validation requirement (with surgical bypass) | Bypass when surgical+bug_fix/tech_debt/verification+1 deliverable → set qgate_validation_required: false; otherwise set qgate_validation_required: true in the return TOON so the orchestrator dispatches plan-marshall:plan-marshall/workflow/q-gate-validation.md as a sibling top-level Task after the phase returns (see standards/outline-workflow-detail.md for the activation contract). The orchestrator-dispatched workflow runs phase-3-applicable validators: existing checks 2.1-2.7, consumer-sweep §2.9, argparse-validator §2.10, tier-delta-validator §2.13, architecture-mismatch-validator §2.17. |
Step 10 deliverable authoring MUST apply the Value-change test-sweep rule: any deliverable that changes a default value, constant, or enum member enumerates every existing test asserting the old value into its **Affected files:**.
Step 10 may also refine scope_estimate: After Complex Track discovery and deliverable composition, the concrete Affected files lists may narrow the actual scope. Phase-3-outline MAY downgrade scope_estimate (e.g., multi_module → single_module, or single_module → surgical) and persist via manage-references set --field scope_estimate. Refinement happens BEFORE Step 11 so the bypass rule sees the refined value.
Step 11 — q_gate_validation knob consult (evaluated FIRST, before the surgical bypass): read the operator's planning-time Q-Gate knob:
python3 .plan/execute-script.py plan-marshall:manage-config:manage-config \
plan phase-3-outline get --field q_gate_validation --audit-plan-id {plan_id}
The value is one of off | once | until_clean (default once; consult the central standard ../manage-config/standards/data-model.md for the enum semantics — do NOT inline-copy them). When the value is off, set qgate_validation_required: false in the return TOON and skip directly to Step 12 — Q-Gate validation is opted out entirely, so no orchestrator dispatch happens. When the value is once or until_clean, proceed to the surgical bypass rule below (the once vs until_clean re-run distinction is applied by the orchestrator's auto-loop, not by this phase).
Step 11 — Q-Gate surgical bypass rule (evaluated after the knob consult, only when q_gate_validation != off, BEFORE signaling the Q-Gate validation requirement):
Bypass Q-Gate when ALL of the following are true:
scope_estimate == surgical, ANDchange_type ∈ {bug_fix, tech_debt, verification}, ANDdeliverable_count == 1 (exactly one deliverable was created in Step 10)When bypass fires, log the decision, set qgate_validation_required: false in the return TOON, and skip directly to Step 12:
python3 .plan/execute-script.py plan-marshall:manage-logging:manage-logging \
decision --plan-id {plan_id} --level INFO --message "(plan-marshall:phase-3-outline:qgate-bypass) Q-Gate skipped — scope_estimate=surgical, change_type={change_type}, 1 deliverable"
Otherwise, set qgate_validation_required: true in the return TOON. The orchestrator (plan-marshall:plan-marshall/workflow/planning-outline.md) reads that flag after the phase returns and dispatches plan-marshall:plan-marshall/workflow/q-gate-validation.md as a sibling top-level Task. The orchestrator aggregates the validator's qgate_pending_count into the phase's running count before re-evaluating the existing 3-iteration auto-loop predicate.
When a deliverable being authored carries change_type: verification, the outline MUST recognize that the deliverable is read-only by definition and verify that every entry in its **Affected files:** list carries intent read. A verification deliverable that also carries any affected file with intent write-new, write-replace, or delete is self-inconsistent and constitutes an outline authoring error — re-classify it to bug_fix, feature/enhancement, or tech_debt (or split out the write-intent files into a separate non-verification deliverable). This rule fires on both tracks — Simple Track Step 7 and Complex Track Step 10. The read-intent-only invariant, the full inconsistency definition, and the corrective-action procedure live once in standards/change-verification.md § Read-Intent-Only Invariant — do NOT restate the invariant or the corrective action here or on the deliverable.
Five deliverable classes carry a recurring engineering hazard that the outline MUST recognize at authoring time and route to its canonical home. These rules fire on both tracks — Simple Track Step 7 and Complex Track Step 10 — when a deliverable being authored matches the trigger. They are recognition triggers ONLY: the substance (mitigation menu, enumeration procedure, decision checklist, field-declaration semantics, domain-specific classification predicate) lives once in its canonical home — a dev-general-* standard, this skill's detail standard for the clean-break and survey-scope rules, or the resolved domain outline implementor for the human-gated harness-config rule — and MUST NOT be restated here or in the deliverable.
Cooperative-lock deliverable class — Trigger: the deliverable's narrative introduces or modifies a cooperative cross-process lock or shared-state coordination primitive (merge locks, worktree allocation, plan-id reservation, leader election, any "claim a shared resource" flow). Required authoring action: emit a **Concurrency-correctness note:** block on the deliverable that names the check-then-act / TOCTOU window and points to the chosen mitigation. The note MUST cross-reference the TOCTOU / check-then-act mitigation menu in ref-code-quality/standards/code-organization.md — do NOT duplicate the mitigation menu.
Value-change deliverable class — Trigger: the deliverable changes a default value, constant, or enum member that tests may assert against. Required authoring action: scope the old-value test assertions into the deliverable's **Affected files:** so the production change and its test-consumer updates form one atomic deliverable. The note MUST cross-reference the enumeration discipline in persona-module-tester/standards/testing-methodology.md — do NOT duplicate the enumeration procedure.
Clean-break vs migration-shim deliverable class — Trigger: the deliverable's narrative (Change per file: / Refactoring: / summary) removes an internal code path — a function, method, parameter, branch, or script notation that is NOT a published cross-bundle public surface. Required authoring action: apply the four-condition clean-break checklist — (1) are all callers of the removed path in-plan? (2) is there no external / cross-bundle consumer? (3) can the removal land atomically in a single PR? (4) are the old-path tests removed or rewritten in the same plan? — and choose the shape: prefer the clean-break shape (remove the path outright, no shim) when ALL four conditions hold; otherwise default to a deprecation shim with a documented removal window. Cross-reference the checklist body, per-condition rationale, and the clean-break-vs-shim decision table in standards/outline-workflow-detail.md — do NOT duplicate the checklist here or on the deliverable.
Survey-scope deliverable class — Trigger: the deliverable's description mentions survey, discover, classify, or case-by-case (a discovery-style deliverable whose exact mutation set is not fully known at authoring time). Required authoring action: declare two disjoint fields on the deliverable — **Files to survey:** (the candidate-pool / analysis scope) and **Files expected to mutate:** (the mutation-scope upper bound) — and note that the retrospective affected_files_recall check runs against the expected-to-mutate subset, NOT the survey scope. Cross-reference the field semantics, the worked example, and the survey_vs_mutation_scope_declared outline check in standards/outline-workflow-detail.md — do NOT restate the field semantics or the check here.
Human-gated harness-config deliverable class (domain-routed) — Trigger: the deliverable's Affected files (or its narrative's described writes) touch the Claude Code harness-configuration surface — .claude/settings.json, .claude/settings.local.json, a hooks block, a .claude/hooks/** script, or a permissions.allow/permissions.deny array. Required authoring action: route to the resolved domain outline implementor (via Step 9 resolve-outline-skill) for the predicate and required action, which classifies the surface as human-gated and splits the unattended authoring from the human-gated activation step. The substance — the permission-prompt + startup-reload activation-latency predicate and the split-vs-annotate required action — lives in the domain implementor; for the plan-marshall-plugin-dev domain it is the Human-Gated Harness-Config Classification section. Do NOT restate the predicate or the required action here. When the resolved domain has no outline implementor that documents the dimension (generic fallback), the deliverable is not auto-classified — note the harness-config touch in the deliverable narrative so the human reviewer can apply the split manually.
The matching trigger predicates and authoring actions are documented as track-agnostic siblings to the Step 9c procedure in standards/outline-workflow-detail.md.
When a plan or deliverable originates from a retrospective lesson — a lesson whose corrective fix has already shipped, but whose body carries a forward-looking / ## Generalisation rule, with the target component source still editable — the outline MUST emit the apply-the-wisdom / documentation-port shape: a documentation_only deliverable that lifts the forward-looking rule into the component's canonical docs (its SKILL.md or a standards/*.md) and cross-references the originating lesson. Do NOT emit a code-change deliverable that re-applies the already-shipped fix — the fix is done; the lesson's residual value is the generalizable wisdom.
This rule fires on both tracks. The retrospective-vs-prospective signals, the documentation-port deliverable template, and the required lesson cross-reference are defined once in standards/outline-workflow-detail.md § Retrospective-vs-prospective lesson classification — the same shared definition recipe-lesson-cleanup Step 2c consumes (the two skills stay in lockstep by reading one source). Do NOT restate the signals or the template here.
Before writing solution_outline.md, the outline MUST scan every composed deliverable body — **Success Criteria:**, **Change per file:**, and any narrative field — for YYYY-MM-DD-HH-NNN-shaped lesson-ID tokens, and validate each token against the live manage-lessons inventory. A token that does not resolve to a registered lesson MUST NOT be written as a bare citation: on a not-found result the outline MUST either (a) reword to omit the bare ID and reference the lesson by its logical role, or (b) confine the ID to the deliverable's plan-internal fields only. The outline MUST NOT register the plan's own plan-source lesson to make a citation resolve — under the three-gate lesson-creation policy, Gate 2 would find the current plan IS the covering active plan and direct a fold-into-plan, not a create.
This rule fires on both tracks. The trigger predicate, the manage-lessons get/list validation mechanism, and the drop-and-reword vs confine-to-plan-internal-fields resolutions are defined once in standards/outline-workflow-detail.md § Validate cited lesson-ID tokens against the live inventory before writing the outline. Do NOT restate the mechanism here. The rule content above is captured directly: the wisdom has a plan-internal provenance, but its raw lesson-ID token MUST NOT appear in this SKILL.md prose (no-lesson-id-in-skill-prose would flag it).
CRITICAL: If Complex Track skill workflow fails, do NOT fall back to grep/search. Fail clearly.
**Intent gloss:** per the deliverable template when a deliverable title contains a compound word whose head morpheme is a planning-domain verb (review, check, validate, approve, merge, …). The gloss is a single sentence (≤15 words) that restates the deliverable's goal using the tail morpheme's meaning, and phase-4-plan copies it verbatim into every derived task.description.For detailed procedures (skill resolution, change-type loading, solution writing, Q-Gate agent interaction), see standards/outline-workflow-detail.md.
Each deliverable in solution_outline.md MUST follow this field order. The authoritative schema is in manage-solution-outline/templates/deliverable-template.md:
### {N}. {Deliverable Title}
**Metadata:**
- change_type: {feature|enhancement|tech_debt|bug_fix|analysis|verification}
- execution_mode: {automated|manual|mixed}
- domain: {domain}
- module: {module}
- depends: {none|N|N,M}
**Intent gloss:** {one-sentence disambiguation, max ~15 words — required when title head morpheme is a planning-domain verb (review, check, validate, approve, merge, …)}
**Design notes:** {required on BOTH the Simple and Complex Tracks for any deliverable that touches an existing skill — names the target skill's design model — `script-deterministic`, `LLM-driven`, or `hybrid` — and a one-sentence rationale showing the proposed implementation extends, not contradicts, that model. The track does NOT gate emission: a Simple-Track deliverable touching an existing skill MUST emit this block just as a Complex-Track one does, so the deliverable self-satisfies the §2.17 Architecture-Mismatch validator on the first validation pass. See Step 9c (Read Target Skill Design Intent), which applies to Simple Track Step 7 as well as Complex Track, and [`standards/outline-workflow-detail.md`](standards/outline-workflow-detail.md#step-9c-read-target-skill-design-intent) for the procedure. Omit only when the deliverable does not touch an existing skill (e.g., docs-only with no skill target, brand-new skill).}
**Profiles:** <!-- bucket: {production_only|test_only|documentation_only|mixed_code|mixed_with_docs|unknown} -->
- implementation
- {module_testing - only if the resolved bucket is production_only, test_only, mixed_code, or mixed_with_docs; never for documentation_only; unknown BLOCKS the deliverable}
**Affected files:**
- `{explicit/path/to/new-file}` (write-new)
- `{explicit/path/to/existing-file}` (write-replace)
**Change per file:** {what changes}
**Verification:**
- Command: `{resolved command}`
- Criteria: {criteria}
**Success Criteria:**
- {criterion 1}
**Intent gloss:** is copied verbatim by phase-4-plan into every derived task.description, so the sentence must stand alone without relying on the surrounding deliverable context.
The <!-- bucket: ... --> comment on the **Profiles:** line is REQUIRED as the profile audit trail and records the resolved file-type bucket from the File-type classifier. The bucket determines which profiles are valid for the deliverable:
documentation_only → implementation only; never paired with module_testing. When the changed paths include marketplace skill .md bodies (marketplace/bundles/**/skills/**/*.md), the Verification command MUST use the rule-complete scoped form: pm-plugin-development:plugin-doctor:doctor-marketplace quality-gate --paths {skill-dir} --marketplace-root {worktree_path}/marketplace — NOT the rule-less list-components or bare scan --paths, because those enumerate without running quality-gate rules and are not CI-equivalent gates. See standards/outline-workflow-detail.md for the complete verification procedure.production_only → implementation + module_testing.test_only → module_testing only (test-only deliverable).mixed_code → implementation + module_testing (production + test paths, no documentation).mixed_with_docs → implementation + module_testing, with module_testing scope narrowed to the production/test paths only (declare the narrowed scope in a **Module_testing scope:** block above **Affected files:**).unknown → BLOCKS the deliverable. Phase-4-plan emits a Q-Gate finding requiring the user to add a domain-extension claim for the unclaimed path(s) or correct the affected-files list. Never silently route to documentation_only.Every **Affected files:** entry MUST carry a trailing (intent) marker — a backticked path, one space, then the intent in parentheses: - `path/to/file.ext` (write-new). The marker is required and enum-validated by manage-solution-outline validate; an entry without a valid marker fails outline validation.
Classify each affected file's intent from its **Change per file:** description:
| Change per file description | Intent |
|-------------------------------|--------|
| File is consulted/read but NOT modified by this deliverable | read |
| File is created fresh (does not exist yet) | write-new |
| File is modified in place (already exists) | write-replace |
| File is removed by this deliverable | delete |
The intent authoritatively drives the downstream files_exist Q-Gate: read/delete require the file to exist pre-execution, write-new requires it to be ABSENT (the gate flags a declared-new file that already exists), and write-replace skips the existence check. Classify honestly — a write-new marker on a file that already exists, or a read marker on a file that does not, surfaces as a Q-Gate finding at plan time.
For Simple Track, write solution_outline.md. Use write on first entry, update on re-entry (Q-Gate loop):
python3 .plan/execute-script.py plan-marshall:manage-solution-outline:manage-solution-outline exists \
--plan-id {plan_id}
If exists: false (first entry):
# 1. Get target path
python3 .plan/execute-script.py plan-marshall:manage-solution-outline:manage-solution-outline \
resolve-path --plan-id {plan_id}
# 2. Write content directly via Write tool
Write({resolved_path}) with solution outline content including title, plan_id,
compatibility header, Summary, Overview, and Deliverables from Step 6
# 3. Validate
python3 .plan/execute-script.py plan-marshall:manage-solution-outline:manage-solution-outline \
write --plan-id {plan_id}
If exists: true (Q-Gate re-entry):
# 1. Update content via Write tool to the same path
# 2. Validate
python3 .plan/execute-script.py plan-marshall:manage-solution-outline:manage-solution-outline \
update --plan-id {plan_id}
Note: Complex Track - skill already wrote solution_outline.md in Step 10.
python3 .plan/execute-script.py plan-marshall:manage-logging:manage-logging \
work --plan-id {plan_id} --level INFO --message "[ARTIFACT] (plan-marshall:phase-3-outline) Created solution_outline.md"
python3 .plan/execute-script.py plan-marshall:manage-logging:manage-logging \
decision --plan-id {plan_id} --level INFO --message "(plan-marshall:phase-3-outline) Complete: {N} deliverables, Q-Gate: {pass/fail}"
python3 .plan/execute-script.py plan-marshall:manage-logging:manage-logging \
work --plan-id {plan_id} --level INFO --message "[STATUS] (plan-marshall:phase-3-outline) Outline phase complete - {N} deliverables, Q-Gate: {pass/fail}"
Add visual separator after END log:
python3 .plan/execute-script.py plan-marshall:manage-logging:manage-logging \
separator --plan-id {plan_id} --type work
python3 .plan/execute-script.py plan-marshall:manage-status:manage-status transition \
--plan-id {plan_id} \
--completed 3-outline
Return minimal status - all data is in sinks:
status: success
plan_id: {plan_id}
track: {simple|complex}
deliverable_count: {N}
qgate_passed: {true|false}
qgate_pending_count: {0 if no findings}
qgate_validation_required: {true|false}
outline_prompt: {optional — present only when the leaf has open operator questions; see § Operator-input contract}
outline_prompt is the batched prompt-required envelope described in § "Operator-input contract" — the leaf emits it (alongside an otherwise-complete status: success) only when outline authoring surfaced open operator design questions, and omits it entirely when the outline resolved cleanly. The orchestrator fires ONE batched AskUserQuestion over it and re-dispatches phase-3-outline at most once with the answers baked in.
qgate_validation_required is true when the phase decided q-gate-validation must run (plan.phase-3-outline.q_gate_validation != off AND the surgical-bypass predicate did NOT fire), and false otherwise (q_gate_validation == off, bypass fired, or recipe path short-circuited at Step 3). The orchestrator (plan-marshall:plan-marshall/workflow/planning-outline.md) reads this flag after the phase returns and dispatches q-gate-validation as a sibling top-level Task when it is true.
The "Return Results" block above (under Step 12) is the single source of truth for the return TOON. The minimum contract every workflow doc that implements ext-point-execution-context-workflow MUST return is:
status: success | error
display_detail: "<track {track}, {deliverable_count} deliverables, {qgate_pending_count} pending>"
qgate_validation_required: {true|false}
display_detail shape on success: "track {track}, {deliverable_count} deliverables, {qgate_pending_count} pending" (e.g. "track complex, 5 deliverables, 0 pending"); ≤80 chars, ASCII, no trailing period. On error, carries the short error label from § Error Handling.
All other fields (plan_id, track, deliverable_count, qgate_passed, qgate_pending_count, qgate_validation_required, and the optional outline_prompt batched-question envelope) are documented in "Return Results" above.
| Scenario | Action |
|----------|--------|
| Track not set | Return {status: error, message: "phase-2-refine incomplete - track not set"} |
| Target not found (Simple) | Return error with invalid target |
| Change type not detected | Return {status: error, message: "detect-change-type workflow failed to determine change type"} |
| Skill workflow fails (Complex) | Return error, do not fall back |
| Q-Gate fails | Return with qgate_passed: false and findings |
| Request not found | Return {status: error, message: "Request not found"} |
CRITICAL: If Complex Track skill workflow fails, do NOT fall back to grep/search. Fail clearly.
Invoked by: plan-marshall:plan-marshall skill (loaded directly in main context)
Script Notations (use EXACTLY as shown):
plan-marshall:manage-files:manage-files - Read module_mapping from work/module_mapping.toonplan-marshall:manage-plan-documents:manage-plan-documents - Read requestplan-marshall:manage-references:manage-references - Read domainsplan-marshall:manage-solution-outline:manage-solution-outline - Write solution documentplan-marshall:manage-findings:manage-findings - Q-Gate findings (qgate add/query/resolve)plan-marshall:manage-status:manage-status - Read/write change_type metadataplan-marshall:manage-logging:manage-logging - Decision and work loggingplan-marshall:manage-config:manage-config - Resolve outline skill, read compatibilityplan-marshall:manage-architecture:architecture - Resolve verification commandsplan-marshall:manage-findings:manage-findings assessment - Log assessments (domain skills)Spawns (Complex Track):
plan-marshall:phase-3-outline/workflow/detect-change-type.md workflow (Step 4 — change type detection)Signals to orchestrator (Complex Track):
qgate_validation_required: true|false in the return TOON. The orchestrator (plan-marshall:plan-marshall/workflow/planning-outline.md) dispatches plan-marshall:plan-marshall/workflow/q-gate-validation.md as a sibling top-level Task when the flag is true (Step 11 — Q-Gate verification).Loads Skills (Recipe path):
{recipe_skill} (Step 3 - recipe skill with input parameters, built-in or custom)Loads Skills (Complex Track):
resolve-outline-skill (Step 9a, e.g., pm-plugin-development:ext-outline-workflow)standards/change-{change_type}.md (Step 9b, generic fallback)Consumed By:
plan-marshall:phase-4-plan skill (reads deliverables for task creation)phase-3-outline dispatch rather than dispatching per-deliverableThis skill does not invoke manage-metrics itself. The orchestrator
(plan-marshall:plan-marshall workflows) records the 3-outline → 4-plan
boundary via the fused manage-metrics phase-boundary call — see
marketplace/bundles/plan-marshall/skills/manage-metrics/SKILL.md §
phase-boundary for the API.
development
Domain-owned OpenRewrite log-line finding parser for the java-cui domain — parses the
development
Domain-owned OpenRewrite marker detection for the java-cui domain — scans Java/Kotlin sources for cui-rewrite TODO markers, categorizes them by recipe, and fails the gate on any detected marker
development
Operator control surface for the marshalld build server — enrol/drop a project in the machine-global registry (the opt-in enable signal and anti-laundering wall), manage the daemon lifecycle (start, stop, drain, status, install, upgrade) version-pinned to the verified bundle copy, and inspect the daemon's per-project interaction-audit log (read-only)
tools
The tiny build-consumption client for the marshalld build server — submit a build job, bounded long-poll for its result, ping the daemon identity, and preflight registry-plus-liveness in one call; consumption only, never provisioning or enrolment