AI orchestrator — coordinates Phase 2 (solution design + delivery slicing). Dispatches N parallel `solution-designer` (B1) calls with varied parameters, ranks them via an Opus selector, post-verifies the ranking via /double-check (class `check`), then auto-selects the verified top-ranked candidate and elaborates it to full requirement coverage (coverage-gated via /double-check (class `check`) until 0 gaps), presents the coverage-complete design in the topic's `<base>_DESIGN.md` (status pending-approval) for the operator to approve, invokes `solution-slicer` (B2) on approval, final-verifies via /double-check (class `gate`), and flips the Design to `chosen`. On ESCALATE at any post-verify seam, surfaces a two-option choice — (a) one more round, (b) proceed as is. Stateless skills, orchestrator-owns-persistence (C5).
Resources
2Install
npx skillscat add dmitrydf/q/solution-design Install via the SkillsCat registry.
/solution-design — Phase 2 Orchestrator
Coordinate Phase 2 (solution design + delivery slicing) in a single command. Dispatches solution-designer (B1) calls in parallel with varied parameters, ranks and post-verifies them, auto-selects the verified top-ranked candidate and elaborates it to full requirement coverage (coverage-gated by /double-check), presents the coverage-complete design for the operator to approve, dispatches solution-slicer (B2) once on the approved design, final-verifies the assembled output, and writes a durable ### Solution Alternative N block into the topic's <base>_DESIGN.md (spine carries a pointer).
This skill is a stateless orchestrator that mirrors B2's pattern (parallel dispatch → consolidator → post-verify → user-on-PASS-only) and follows the AI-adapter hexagonal pattern: deterministic flow in code-style execution steps, AI judgment behind named ports (B1, Opus selector, B2, /double-check). Persistence is centralized — only B3 writes _thought. Producer-never-verifies is preserved by topology.
Main-session-only. Cannot be invoked from inside a subagent.
Trigger
Activate when user says:
/solution-design/solution-design --help- "run solution design"
- "design a solution from my discovery"
- "phase 2"
- "design and slice"
- "I've finished clarification, what's next"
When to Use
Activate in one situation:
After /clarification completes and the # Discovery section has all 4 locked fields — the user wants to design candidate solutions, have the verified-best auto-selected and elaborated to full requirement coverage, approve the finished design, get a delivery-slicing recommendation, and end with a durable record in their topic file.
Do NOT activate if # Discovery is absent or its 4 locked fields are missing — hard-fail at Step 1 with "Run /clarification first to lock the 4 Discovery fields."
Do NOT activate from inside a subagent — see Edge Case E12.
Invariants
Stateless skills. B1 and B2 are never modified. B3 wraps them but does not edit their contracts. Only B3 writes
_thought. (C5 of S-H-v2-A;~/.claude/rules/code_first_architecture.md:81–102.)Producer-never-verifies (external). B3 does not verify its own ranking, coverage elaboration, or assembled output.
/double-checkis the external verifier at three code-defined seams (Step 4 ranking, Step 5.3 coverage, Step 9 final). (~/.claude/rules/code_first_architecture.md:112.)User sees only PASS results. On ESCALATE at Step 4, Step 5.3, or Step 9, B3 surfaces the discrepancies verbatim and gives the user the (a) one-more-round / (b) proceed-as-is choice — it never presents an unverified result as final on its own, and does NOT write a
chosenDesign without resolving the seam.Two mandatory hard-gate triples. At the design-approval gate (Step 5.4 — approve / request-changes / re-roll) and after slicing (Step 7), the user MUST make an explicit (a)/(b)/(c) choice. B3 cannot proceed past either gate without one. Step 5 no longer asks the user to pick a candidate — selection is automatic (5.1); the user approves the finished, coverage-complete design.
Monotonic Alternative N. Each B3 run that reaches Step 10 appends
### Solution Alternative Nwhere N = max(prior K)+1 (or 1 on first run). Prior alternatives are marked "superseded by Alternative N+1". N never decreases.B1 and B2 contracts unchanged. B3 produces inputs that conform to B1's Input Contract and B2's Input Artifact. It consumes their outputs as-is. No contract changes to B1 or B2.
Parameters
All optional (defaults shown):
| Flag | Default | Description |
|---|---|---|
--sonnet N |
1 | Number of Sonnet-model B1 candidate dispatches |
--opus N |
1 | Number of Opus-model B1 candidate dispatches |
--candidates N |
2 | Total candidate count override (overrides --sonnet+--opus if specified; default splits 1+1) |
--thought <path> |
(active topic state) | Path to _thought file containing locked # Discovery |
--against TEXT |
(auto-generated from desired outcome) | Additional --against text passed to /double-check at Steps 4 and 9 |
--rounds N |
1 | Max convergence rounds passed to /double-check at both post-verify steps |
--help |
— | Print this Parameters table and stop |
--sonnet + --opus must be ≥ 1. If --candidates N is given, distribute as: floor(N/2) Opus + remainder Sonnet (e.g. N=3 → 1 Opus + 2 Sonnet; N=2 → 1 Opus + 1 Sonnet default).
The candidate count is capped by the rigor dial (class panel — B1 dispatches generate alternatives; they verify nothing). Resolve the ceiling before dispatching, passing the total the flags above produced:
python3 ${KIT_HOOKS_DIR}/rigor.py cap <total candidates> --count-onlyAt thorough and standard the default two candidates survive; at light and minimal the run designs one alternative, so there is nothing to rank — say that in the record rather than presenting a single candidate as a selection. An operator naming --candidates/--sonnet/--opus explicitly overrides the cap.
The three /double-check seams (Steps 4, 5.3, 9) are a different dial class and are resolved separately — see Verification.
Input Contract
Schema (primary surface — Surface 1)
{
"thought_path": "<optional: absolute path to the topic _thought file>",
"sonnet_agents": 1,
"opus_agents": 1,
"rounds": 1,
"against_supplement": "<optional free-text appended to the auto-generated --against string>"
}The skill resolves the # Discovery section by reading thought_path (or the active topic state). All B1 dispatches receive the same locked fields; only design_context_override and model vary per dispatch.
Field rules
| Field | Required | Semantics |
|---|---|---|
thought_path |
no | Absolute path to _thought file. If absent, skill reads from active topic state (pre_plan_gates.py phase-show). If neither resolves, hard-fail. |
sonnet_agents |
no (default 1) | Number of Sonnet B1 dispatches. |
opus_agents |
no (default 1) | Number of Opus B1 dispatches. |
rounds |
no (default 1) | Passed to /double-check --rounds at Steps 4 and 9. |
against_supplement |
no | Free-text appended to the auto-generated --against string for both post-verify calls. |
Deterministic errors
If # Discovery is absent or any of the 4 locked fields is missing/placeholder, the skill returns:
{
"error": "<one of: discovery_section_absent, guiding_policy_missing, desired_outcome_missing, desired_solution_missing, metrics_omtm_missing>",
"alternative_n": null
}Output Contract
Assembled JSON (rendered into the _DESIGN.md at Step 10)
{
"alternative_n": 1,
"date": "YYYY-MM-DD",
"status": "chosen",
"discovery_src_hash": "<12-hex SHA-256 prefix>",
"selector_ranking_summary": "<one-line summary of rank with brief reasoning>",
"chosen_candidate_id": "c1",
"chosen_candidate": {
"agreed_solution_description": "<markdown body, plain business words first>",
"architecture_decisions": [
{
"area": "<noun phrase>",
"choice": "<chosen approach>",
"rationale": "<1–3 sentences>",
"discovery_anchor": "<verbatim excerpt from locked Discovery>"
}
],
"ux_decisions": [],
"cockburn_gate_results": {
"abstraction_test": { "passed": true, "reasoning": "..." },
"responsibility_alignment_test": { "passed": true, "reasoning": "..." },
"evolution_test": { "notes": "..." },
"communications_patterns_test": { "notes": "..." },
"data_connectedness_test": { "notes": "..." },
"data_variations_test": { "notes": "..." }
},
"confidence": "high",
"assumptions": [],
"discovery_anchors": [
{ "field": "guiding_policy", "excerpt": "<verbatim>" }
],
"model_used": "opus"
},
"slices": [
{
"id": "S1",
"name": "<noun phrase>",
"description": "<plain business words>",
"type": "implementation",
"cohesion_rationale": "...",
"single_reason_for_change": "...",
"slicing_idea_applied": "walking_skeleton",
"agent_choice": "routine",
"agent_justification": "",
"context_fit_assessment": "...",
"depends_on": []
},
{
"id": "S-final",
"name": "Implementation verification",
"description": "Confirm the whole plan shipped against the desired outcome.",
"type": "implementation_verification",
"cohesion_rationale": "Validation-V closing step.",
"single_reason_for_change": "Desired outcome or aggregate scope changes.",
"slicing_idea_applied": "knowledge_vs_implementation",
"agent_choice": "routine",
"agent_justification": "",
"context_fit_assessment": "Verification work is lightweight; fits routine model.",
"depends_on": ["S1"]
}
],
"verification_metadata": {
"selector_ranking": {
"double_check_verdict": "PASS",
"claims_checked": 12,
"rounds_run": 1,
"against": "<the --against string used>"
},
"coverage": {
"double_check_verdict": "PASS",
"claims_checked": 14,
"rounds_run": 1,
"gaps_remaining": 0,
"against": "<the Step-5.3 coverage --against string>"
},
"final_output": {
"double_check_verdict": "PASS",
"claims_checked": 25,
"rounds_run": 1,
"against": "<the --against string used>"
}
},
"aggregation_metadata": {
"candidates_evaluated": 2,
"design_rounds": 1,
"slice_rounds": 1,
"auto_selected_candidate_id": "c1",
"coverage_rounds": 1,
"design_approved": true,
"reclarification_gate_counts": {
"category_i": 0,
"category_ii": 0,
"category_iii": 0
}
},
"supersession_marker_written": false
}### Solution Alternative N markdown block (written into the _DESIGN.md)
### Solution Alternative N
**Date:** YYYY-MM-DD
**Status:** pending-approval | chosen | superseded by Alternative N+1
**discovery_src_hash:** <12-hex>
**Selector ranking:** <one-line summary>
#### Chosen Solution Description
<agreed_solution_description from chosen B1 candidate, verbatim>
#### Architecture Decisions
<list from chosen B1 candidate>
#### UX Decisions
<list from chosen B1 candidate>
#### Coverage Map
<coverage_map: each Tier-1/2/3 requirement → covered / pulled-from-candidate-N / added-from-Discovery>
#### Change Log
<change_log: what the coverage step (Step 5.2) added or changed, and from which candidate or Discovery excerpt>
#### Slices (from B2)
<slices[] from B2 output rendered as the CANONICAL slice register — a pipe-table with the exact 7-column header below, one row per slice INCLUDING the closing implementation-verification slice (S-final). This canonical shape is what `/execute-plan`'s register reader parses most cleanly (A4 drift-prevention):>
| ID | Name | Type | Slicing idea | Model | Depends on | Write targets |
|----|------|------|--------------|-------|------------|---------------|
| S1 | <name> | implementation | <slicing_idea_applied> | routine | — | <comma-joined repo-relative paths> |
| ... | ... | ... | ... | ... | ... | ... |
| S-final | Implementation verification | implementation_verification | knowledge_vs_implementation | routine | S1, ... | — |
#### Verification
- Selector ranking: /double-check check (<flags as dispatched>) — PASS (claims_checked: N)
- Coverage (Step 5.3): /double-check check (<flags as dispatched>) — PASS, 0 gaps (claims_checked: K)
- Final Phase-2 output: /double-check gate (<flags as dispatched>) — PASS (claims_checked: M)
- Rigor tier: <tier, and where it came from — `rigor.py get`>
Record the flags the dial actually resolved, not the class alone: a reader months
later needs to know whether that PASS was a three-checker vote or one isolated
opinion, and the class name does not say.
#### Audit Trail
- Selector evaluated N candidates: <list of candidate IDs + brief per-candidate rationale>
- Design rounds (Step 5): <R_design> rounds total — per-round summary: round 1 → approve / request-changes / re-roll with feedback "<text>" or N/A; ...
- Auto-selected: rank-1 candidate <id>; coverage rounds: <R_cov>; design approved at round <R_design>
- Slice rounds (Step 7): <R_slice> rounds total — per-round summary: round 1 → user picked (a)/(b)/(c) with feedback "<text>" or N/A; ...
- Re-clarification gate: 0 (i), 0 (ii), 0 (iii) — or detailField rules
| Field | Rules |
|---|---|
alternative_n |
Positive integer. Must be max(prior_K)+1, or 1 on first run. Never decreases across runs. |
status |
Enum: "pending-approval", "chosen", or "superseded by Alternative N+1". Written as pending-approval at Step 5.4 (the coverage-complete design draft, before the operator approves); flipped to chosen at Step 10 after approval; updated to superseded when a future run writes N+1. |
discovery_src_hash |
The 12-hex SHA-256 prefix computed by _discovery_locked_fields_hash at Step 1. Must match the hash echoed by the chosen B1 candidate's input. |
chosen_candidate |
The full B1 output JSON for the auto-selected, coverage-complete design (Step 5). Field names MUST match B1's Output Contract verbatim (agreed_solution_description, architecture_decisions, ux_decisions, cockburn_gate_results, confidence, assumptions, discovery_anchors, model_used). No renaming. |
slices |
The full B2 slices[] output for the chosen solution. Field names MUST match B2's Output Contract verbatim. When B2 returns slicing_needed: false, slices: []. |
verification_metadata.selector_ranking |
Records the /double-check result from Step 4. double_check_verdict enum: "PASS" or "ESCALATE". Only PASS results proceed past Step 4. |
verification_metadata.final_output |
Records the /double-check result from Step 9. Only PASS results proceed to Step 10. |
supersession_marker_written |
Boolean. true when Step 10 marked a prior alternative as "superseded". false on first run (N=1). |
Execution
Twelve internal steps (Steps 0–11 + Step 7b sub-step). Run in order; no step is skipped except the assess-first short-circuit at Step 0.
Step 0 — Help
If invoked with --help or no locked Discovery is available in session context, output the Parameters table and stop. Do not proceed to Step 1.
Step 1 — Identify and load
- Resolve the
_thoughtfile: use--thought <path>if provided; otherwise read active topic state frompre_plan_gates.py phase-show. If neither resolves, hard-fail witherror: discovery_section_absent. - Read the
# Discoverysection. Locate and verify the 4 locked fields:## Guiding Policy(locked 🔒)## Desired Outcome(locked 🔒)## Desired Solution(locked 🔒)## Metricswith OMTM sub-line (locked 🔒)
- If any field is absent, empty, or a placeholder (
TODO, empty body), return the deterministic error envelope and stop. The skill MUST NOT proceed without all 4 locked fields. - Compute
discovery_src_hash: call_discovery_locked_fields_hashfrompre_plan_gates.py(12-hex SHA-256 prefix of the concatenated locked field bodies). - Scan for existing
### Solution Alternative Kheaders in the topic's<base>_DESIGN.mdif it exists, else (legacy) in the spine's# Solution Designsection. Record max(K) asprior_n(0 if neither holds an Alternative — first run).
Worktree auto-placement (S7 A14, --worktree-opt-in). When /solution-design --worktree is used on a harness topic, place the session into the topic's worktree after the _thought resolves (step 1) and before the Step-2 B1 dispatch, so the <base>_DESIGN.md is authored inside the topic's isolated workspace. Because /solution-design runs downstream of /clarification, the worktree usually already exists — place is idempotent (a resume returns it, never a duplicate). Same two-step form as work-start/SKILL.md:255-259 (retrieve the path from place, then guarded cd):
REPO="$(the configured source path)"
DEST="$(${KIT_HOOKS_DIR}/worktree-helper.sh place --repo "$REPO" --topic "<topic-slug>")" \
|| { echo "[solution-design] worktree placement did not complete" >&2; exit 1; }
cd "$DEST" || { echo "[solution-design] cannot cd into worktree $DEST" >&2; exit 1; }Without --worktree, no placement (default unchanged). Projects-side binding activates with S9.
Step 2 — Dispatch N parallel B1 calls
- Determine N =
--sonnet+--opus(default 2: 1 Sonnet + 1 Opus). - Build N distinct
design_context_overridestrings, one per candidate. Starter library (pick N, no repeats):- "favor explicit user gates over implicit automation"
- "optimize for fewest moving parts — minimize new abstractions"
- "explore a synchronous step-by-step design with no background agents"
- "minimize new abstractions — reuse existing code patterns wherever possible"
Ifdesign_feedbackis set (from a prior Step 5 round-trip (a)), append it to every variation string:"<variation>; user feedback: <design_feedback>". This preserves per-candidate diversity while adding user steering.
- Invoke B1 (
/solution-designer) via Agent tool, all N calls in parallel (single message, multiple Agent tool calls). Per call:subagent_type: general-purposemodel: "sonnet"or"opus"per the allocation- Pass B1 Input Contract JSON:
guiding_policy,desired_outcome,desired_solution,metrics,discovery_src_hash,design_context_override,model.
- Collect N candidate JSONs. Any error envelope returned by B1 is collected as-is (the selector handles all-error cases at Step 3).
Step 3 — Synthesize ranking (Opus selector)
- Write a ranking bundle to
~/.claude/state/solution_design/adhoc/draft_<sid8>_<ts>.md:- The N candidate JSONs (full B1 output)
- The locked Discovery fields (for grounding verification)
- The selector rubric (verbatim below)
- Invoke one Opus Agent call with
subagent_type: readonly-checkerthat reads the artifact and emits a ranked recommendation per the schema below.
Selector rubric (written into the artifact and into the Opus agent prompt):
You are an independent Opus selector. Read the candidate solutions and the locked Discovery section at the artifact path provided.
Rank the N candidates using these criteria, in priority order:
1. Cockburn hard gates (DOMINANT): prefer candidates where both abstraction_test.passed and responsibility_alignment_test.passed are true. A failing candidate is ranked last unless ALL candidates fail.
2. Discovery anchor coverage: prefer candidates where all architecture and UX decisions cite a verbatim Discovery anchor (discovery_anchors[] covers all decisions).
3. Assumption parsimony: prefer candidates with fewer assumptions[] entries. Each assumption is a gap between Discovery and the design.
4. Discovery fit: prefer candidates whose agreed_solution_description addresses the desired_outcome and desired_solution without adding unrequested scope.
Produce a ranked list (rank 1 = best). For each candidate:
- rank (integer, 1 = best)
- candidate_id
- strongest_on: one phrase naming the rubric dimension this candidate leads on
- trade_offs: 1–2 sentences on what this candidate sacrifices vs. rank-1
- per_criterion_notes: one sentence per criterion (cockburn_gates, anchor_coverage, assumption_parsimony, discovery_fit)
Produce an overall_argument: 2–3 sentences explaining why rank-1 is the best choice given Discovery.
If all candidates have errors (B1 error envelopes), report: error: "all_candidates_failed", no ranking.
Return JSON only. No prose before or after.Selector output schema:
{
"ranked_candidates": [
{
"rank": 1,
"candidate_id": "c1",
"strongest_on": "cockburn_gates",
"trade_offs": "...",
"per_criterion_notes": {
"cockburn_gates": "...",
"anchor_coverage": "...",
"assumption_parsimony": "...",
"discovery_fit": "..."
}
}
],
"overall_argument": "...",
"error": null
}If selector.error == "all_candidates_failed": surface the error to the user, do NOT proceed to Step 4. Run ends without writing any Alternative.
Step 4 — Post-verify ranking
Build the --against string:
<desired_outcome>; ranking rubric: Cockburn hard gates dominant + Discovery anchor coverage + assumption parsimony + Discovery fitAppend against_supplement if provided.
Invoke:
/double-check --class check --rounds 2 --against "[against_string]"- PASS (0 discrepancies): Record in
verification_metadata.selector_ranking. Proceed to Step 5. - ESCALATE (
max_roundsreached with unresolved discrepancies): Surface the discrepancies verbatim and present the user a two-option choice (do NOT default-proceed):- (a) One more round — re-invoke
/double-checkwith the same--againststring; round counter increments pastmax_rounds; fresh isolated checkers. - (b) Proceed as is — accept the unresolved discrepancies. Record
verification_metadata.selector_ranking.double_check_verdict = "ESCALATE"and the discrepancy list, proceed to Step 5. - No
override_reasoncapture — the user's pick is recorded.
- (a) One more round — re-invoke
Step 5 — Auto-select, ensure coverage, design-approval gate
The selector ranking (Step 3) is post-verified (Step 4). B3 does not ask the user to pick a candidate. Instead it auto-takes the verified top-ranked candidate, elaborates it to full requirement coverage, and gates the finished design for approval. The user's judgment moves from picking a raw candidate to approving a coverage-complete design.
5.1 Auto-select. Take the verified rank-1 candidate as chosen_candidate; record auto_selected_candidate_id. There is no user override of rank — the operator judges the finished, coverage-complete design at 5.4, not the raw ranking.
5.2 Ensure coverage (producer step — does NOT self-verify). Elaborate the chosen candidate so it covers every requirement the locked Discovery imposes:
- Requirement checklist: Tier 1 = the 4 locked fields (Desired Outcome, Desired Solution, Guiding Policy, OMTM); Tier 2 = Problem (under
# Idea), Scope in/out, surfaced rules; Tier 3 = resolved Q&A. - For each requirement the chosen candidate does not fully cover, close the gap — prefer pulling the relevant decision from one of the other candidates over inventing one; anchor every pulled/added decision to a verbatim Discovery excerpt. If no candidate covers it, fill from Discovery, anchored, and flag it as added.
- Apply the Guiding Policy as a hard gate on every change; keep both Cockburn hard gates passing.
- Emit the elaborated design in the B1 Output Contract verbatim, plus
coverage_map(each requirement →covered/pulled-from-candidate-N/added-from-Discovery) andchange_log.
5.3 Coverage verify (external evaluator — producer-never-verifies). Invoke:
/double-check --class check --rounds 2 --against "the design covers every Tier 1/2/3 requirement from the _thought, stays within the Guiding Policy, anchors every decision to a verbatim Discovery excerpt, and passes both Cockburn hard gates"- PASS (0 gaps): record in
verification_metadata.coverage. This PASS is the pre-approval gate. Proceed to 5.4. - ESCALATE: surface the gaps verbatim; two-option choice — (a) one more round (the coverage producer revises in 5.2, then re-verify) / (b) proceed as is (record
verification_metadata.coverage.double_check_verdict = "ESCALATE"). Never loop 5.2/5.3 without this user gate.
5.4 Present for approval (single approve gate). Write the coverage-complete design to the topic's _DESIGN.md with status: pending-approval using the Step-10 write mechanics (Parent line + spine pointer), including coverage_map + change_log, no Slices yet. Show the operator: agreed_solution_description (first paragraph), confidence, hard-gate booleans, and the coverage_map. Present three explicit choices (B3 CANNOT proceed without one):
(a) Approve — accept the coverage-complete design. Proceed to slicing (Step 6); Step 10 flips
statustochosen.(b) Request changes — provide steering text. B3 re-dispatches N B1 agents with your feedback injected into every
design_context_override(loop to Step 2); thepending-approvaldraft is replaced on the next pass.design_roundincrements.(c) Re-roll — fresh N B1 agents, no feedback, fresh isolated context (loop to Step 2).
design_roundincrements.
On (a): record approval. Proceed to Step 6.
On (b): record design_feedback; increment design_round; loop to Step 2.
On (c): increment design_round; loop to Step 2 (clean re-roll).
No cap on design rounds. The user gates approval, not candidate selection.
Step 6 — Dispatch B2 once
Invoke /solution-slicer via the Skill tool with:
plan_path_or_content: the chosen candidate'sagreed_solution_description(inline markdown)desired_outcome: the locked## Desired Outcomefield body
B2 internally post-verifies its own recommendation via its built-in /double-check --class gate. B3 consumes B2's Output Contract as-is (assessment, slices[], aggregation_metadata, verification_metadata, confidence, assumptions).
If B2 returns an error envelope: surface the error, do NOT proceed to Step 7.
If B2 returns assessment.slicing_needed: false: note this for the user at Step 7; slices: [] will be recorded.
Step 7 — Slice-approval hard gate
Present the slice recommendation to the user:
- Show
assessment.rationale(why slicing is or is not recommended). - If
slicing_needed: true: show theslices[]table (id, name, description, type, agent_choice). - Show
verification_metadata.double_check_verdictfrom B2. - Present three explicit choices (B3 CANNOT proceed without one):
(a) Feedback — revise the slicing
Provide steering text for a new slicing round. B3 will re-invoke B2 with your feedback appended todesired_outcome. Slicing-round counter increments.(b) Approve — accept the slices
Proceed to assemble the Phase-2 output (Step 8).(c) Try another slicing round — fresh independent B2 agents
Fresh re-invocation of B2 with the same inputs, no feedback injected. B2's internal multi-perspective dispatch ensures isolated context. Slicing-round counter increments.
On (a): Append feedback to desired_outcome for next B2 call (concatenated: "<original desired_outcome>; slicing feedback: <slice_feedback>"). Increment slice_round counter. Loop back to Step 6.
On (b): Proceed to Step 7b (re-clarification gate), then Step 8.
On (c): Fresh B2 re-invocation with same inputs. Increment slice_round counter. Loop back to Step 6.
No cap on slicing rounds. The user gates each loop.
Step 7b — Re-clarification gate (orthogonal, triggered by content inspection)
After user approves at Step 7 (b), inspect the chosen B1 candidate output + B2 output for Discovery gaps. This step triggers only if inspection reveals gaps:
Inspect gaps: For each
assumptions[]entry in the chosen candidate, and for each B2 assessor note that references a missing Discovery element, classify:- (i) Q&A new info — new factual content not in Discovery (e.g. an external constraint the user knows): write to
## Q&Awith[origin: solution-design SID:<sid8>]tag. No re-clarification. Proceed. - (ii) Scope refinement — a clarification of scope boundaries already implicit in Discovery: write to
## Q&Awith same origin tag. No re-clarification. Proceed. - (iii) Locked-field conflict — an assumption that contradicts a locked field (e.g. "assumes Desired Solution allows X" but Desired Solution explicitly forbids X): surface the tension to the user with:
- The conflicting assumption quoted verbatim
- The locked field excerpt quoted verbatim
- Three choices: Revise (invoke
/clarification --from <thought-path>, B3 stops) / Reject (discard this assumption, proceed treating the locked field as authoritative) / Override (note the override explicitly inaggregation_metadata, proceed)
- (i) Q&A new info — new factual content not in Discovery (e.g. an external constraint the user knows): write to
Re-clarification counter: each category-(iii) surface increments the counter. Hard-stop on 3rd surface (counter==2 + new attempt): "Re-clarification gate hard-stopped after 2 round-trips. Please run
/clarification --from <path>directly to revise the locked fields, then re-invoke/solution-design."If user picks Revise at any category-(iii) surface: invoke
/clarification --from <thought-path>, do NOT write any Alternative, stop.If no gaps detected: proceed directly to Step 8.
Step 8 — Assemble the slices + verification additions
The design body — the ### Solution Alternative N header (N computed at Step 5.4 / Step-10 Stage 1), **Status:** pending-approval, discovery_src_hash, Chosen Solution Description, Architecture/UX Decisions, Coverage Map, Change Log — was already written to <base>_DESIGN.md at Step 5.4. Step 8 assembles only the remaining sections, to be merged in at Step 10 Stage 2:
selector_ranking_summary= one-line from the selector'soverall_argument.Slices (from B2)= B2'sslices[]rendered as the canonical 7-column#### Slicespipe-table (A4 drift-prevention — so/execute-plan's reader parses new registers cleanly). Use the exact header| ID | Name | Type | Slicing idea | Model | Depends on | Write targets |with a separator row, mapping each slice's JSON fields verbatim:id→ID,name→Name,type→Type (implementation/implementation_verification),slicing_idea_applied→Slicing idea,agent_choice→Model (routine/more_capable),depends_on→Depends on (comma-joined,—when empty),write_targets→Write targets (comma-joined repo-relative paths,—when empty). Always include the closing S-final row withtype: implementation_verificationso the reader's non-closing count is correct.Both halves of this hop must stay in step.
/solution-sliceremits the per-slicewrite_targetsfield; this step renders the column. Extending only one leaves the column unrendered andwrite_targetsresolving to()in/execute-plan's register reader — a functional no-op that looks like a working feature. The column is what/execute-plan's entry gate narrows an in-flight block to, so an omitted path silently stops being gated rather than failing loudly.Verification= all three/double-checkverdicts (coverage at 5.3, B2 slicing, Step-9 final) withclaims_checked.Audit Trail= full round-by-round summary.If N > 1, prepare the supersession edit: locate
### Solution Alternative N-1in<base>_DESIGN.mdand change its**Status:**line tosuperseded by Alternative N(applied at Step 10). Setsupersession_marker_written: truein aggregation_metadata.
Step 9 — Final post-verify
Build the --against string:
<desired_outcome>; the assembled Phase-2 output (chosen B1 candidate + B2 slices) should coherently address the Discovery locked fields without contradicting them; verification_metadata must record both /double-check verdictsAppend against_supplement if provided.
Invoke:
/double-check --class gate --rounds 1 --against "[against_string]"(Per S-H-v2-A spec — the heavier budget for the durable record.)
- PASS: Record in
verification_metadata.final_output. Proceed to Step 10. - ESCALATE (
max_roundsreached with unresolved discrepancies): Surface the discrepancies verbatim and present the user a two-option choice (do NOT default-proceed):- (a) One more round — re-invoke
/double-checkwith the same--againststring; round counter increments pastmax_rounds; fresh isolated checkers. - (b) Proceed as is — accept the unresolved discrepancies. Record
verification_metadata.final_output.double_check_verdict = "ESCALATE"and the discrepancy list, proceed to Step 10. The Alternative is written with the ESCALATE disposition embedded in the Verification audit trail. - No
override_reasoncapture — the user's pick is recorded.
- (a) One more round — re-invoke
Step 10 — Two-stage write of the Agreed Solution to _DESIGN.md + spine pointer
Per the bookkeeping model (OQ18 pointer-manifest; ~/.claude/rules/bookkeeping-model.md §4 / §8), the Agreed Solution lives in a separate _DESIGN.md file and the spine's # Solution Design is a pointer manifest — wikilinks to the Design, no inline body.
Resolve design_path = <spine_dir>/<base>_DESIGN.md, where <base> is the spine filename minus _THOUGHT.md (reuses the spine's slug + any timestamp); its wikilink stem is <base>_DESIGN. Let <spine_stem> be the spine filename minus .md.
Stage 1 — at Step 5.4 (the pending-approval draft; "Step-10 write mechanics" referenced there). Create design_path if absent as a coordinated single Write — read → compose → one Write call:
- First line
Parent: [[<spine_stem>]]— the bidirectional contract requires it (G3); without it the bookkeeping hook flags the Design. ## Agreed Solution Descriptionwith the chosen candidate'sagreed_solution_description.- Compute
alternative_n(scandesign_pathfor### Solution Alternative K;n = max(K)+1, or 1 if none) and append the### Solution Alternative Nblock with**Status:** pending-approval, Chosen Solution Description, Architecture/UX Decisions, Coverage Map, Change Log — no Slices, no final Verification yet. - Spine pointer: ensure
- [[<base>_DESIGN]]exists under the spine's# Solution Design(create the header before# Implementation Details, or at end of file if absent — pointer manifest, no inline body). The spine must wikilink the Design (G4).
Stage 2 — here, after approval (Step 5.4a) + slicing (Steps 6–7) + Step-9 PASS. Update the same design_path (read → edit):
- Flip the Alternative N
**Status:**linepending-approval → chosen. - Append
#### Slices (from B2)and the final#### Verification(coverage + B2 slicing + Step-9 verdicts) +#### Audit Trailassembled at Step 8. - Mark prior alternative superseded (if N > 1): Edit the
**Status:**line of### Solution Alternative N-1withindesign_path. - The spine pointer from Stage 1 already exists — ensure it is present (idempotent).
Backward-compat: existing spines that carry an inline ### Solution Alternative N are still consumed by /plan Mode A via its dual-read (DESIGN-or-inline). This file-based persistence applies to new /solution-design runs; a topic already holding an inline Alternative is left as-is unless re-run.
Step 11 — Handoff
Present the user-facing summary:
- Alternative N written:
### Solution Alternative N(date, hash, candidates evaluated, rounds) - Selector ranking:
/double-check --class check() — PASS - Coverage (Step 5.3):
/double-check --class check() — PASS, 0 gaps - Final output:
/double-check --class gate() — PASS - B2 assessment:
slicing_needed: true/false,slices: N - Suggest next step: Run
/planto enter plan mode with the chosen Agreed Solution Description and slices as Coherent Actions input.
If user chose Revise at Step 7b: suggest /clarification --from <thought-path> instead.
Invocation Surfaces
The skill is invokable from three surfaces. All three resolve the same locked Discovery, dispatch the same B1/B2 calls, and produce the same JSON output. The surface layer is the only changing locus when adding a new caller (Cockburn Evolution Test — single-locus change).
Surface 1 — Primary CLI (/solution-design)
The user runs /solution-design directly after /clarification. B3 reads the active topic state or --thought <path>. Full 12-step Execution. Writes ### Solution Alternative N to the <base>_DESIGN.md (+ spine pointer under # Solution Design).
Surface 2 — /plan Slice I fallback
When the user runs /plan directly and Phase 2 was skipped, Slice I (the /plan enhancement) invokes /solution-design --inline as a fallback to fill the Coherent Actions input. In --inline mode:
- B3 runs the full Execution (Steps 1–9)
- At Step 10, B3 writes the
<base>_DESIGN.md(+ spine pointer) AND returns the assembled output JSON to the caller (Slice I) - Slice I records time + tokens to
Stats.md— that instrumentation belongs to Slice I, NOT to B3
Surface 3 — Standalone CLI
/solution-design --thought <path-to-_thought> [--sonnet N] [--opus N] [--rounds N]For one-off iteration outside the normal flow — e.g., debugging a Discovery, testing the selector, iterating on fixtures. In standalone mode:
- B3 runs the full Execution (Steps 1–9)
- At Step 10: outputs the assembled Alternative JSON to stdout ONLY — no
_thoughtwrite (no topic context guaranteed) - Confirmed editorial: E14 = JSON to stdout, no write.
Optionality Boundary
This skill does NOT decide whether Phase 2 should be run at all. That decision belongs to the user. When invoked, B3 always executes (subject to the deterministic Step 1 hard-fail on missing/unlocked Discovery).
When Phase 2 is optional (e.g., a trivial change where the solution is obvious), the user simply skips /solution-design and runs /plan directly. Slice I may invoke B3 as a fallback (Surface 2), but Slice I decides whether to invoke it.
Edge Cases
| # | Condition | Handling |
|---|---|---|
| E1 | # Discovery absent or unlocked |
Hard-fail at Step 1 with deterministic error envelope. Do not proceed. |
| E2 | discovery_src_hash from a B1 candidate doesn't match Step 1 hash |
Stale candidate. Surface to user: "Candidate hash mismatch — re-dispatching." Re-dispatch that candidate (one retry). If still mismatch: reject and exclude from selector ranking. Note in aggregation_metadata. |
| E3 | All N B1 candidates return error envelopes | Selector Step 3 detects error: "all_candidates_failed". Surface error. No Alternative written. Run ends. |
| E4 | User keeps choosing request-changes / re-roll at Step 5.4 | No cap; each loops to Step 2 (request-changes injects feedback; re-roll is clean). No Alternative is written until the user approves at 5.4 (a). |
| E5 | Selector post-verify ESCALATE (Step 4) | Surface discrepancies verbatim; user picks (a) one more round or (b) proceed-as-is (records ESCALATE, continues to Step 5). No chosen Design until resolved. |
| E6 | B2 returns error envelope | Surface error to user. Do NOT proceed to Step 7. Run ends. |
| E7 | Final post-verify ESCALATE (Step 9) | Surface discrepancies verbatim; user picks (a) one more round or (b) proceed-as-is (records ESCALATE in verification_metadata.final_output, proceeds to Step 10 with the ESCALATE disposition embedded). |
| E8 | User picks Revise at Step 7b category-(iii) | Invoke /clarification --from <thought-path>. Do NOT write Alternative. Stop. |
| E9 | First run on a topic (no _DESIGN.md yet) |
Step 10 creates the <base>_DESIGN.md (with Parent: line) + the spine # Solution Design pointer + writes Alternative 1. supersession_marker_written: false. |
| E10 | N-th run (N ≥ 2) | Step 10 appends Alternative N + marks Alternative N-1 superseded. supersession_marker_written: true. |
| E11 | Re-clarification counter at 2; user attempts 3rd category-(iii) surface | Hard-stop. Tell user to run /clarification --from <path> directly and then re-invoke /solution-design. Counter resets on fresh invocation. |
| E12 | Invoked from inside a subagent | Reject: "solution-design is main-session-only — cannot be invoked from inside a subagent." |
| E13 | /plan Slice I fallback (Surface 2, --inline) |
B3 runs end-to-end and both writes _thought AND returns the Alternative JSON to Slice I. Slice I records time + tokens. |
| E14 | Standalone CLI (Surface 3) | End-to-end run; output is the Alternative JSON to stdout. No _thought write. Confirmed editorial. |
| E15 | Coverage gate (Step 5.3) cannot reach 0 gaps within rounds | ESCALATE: surface the remaining gaps verbatim; user picks (a) one more round or (b) proceed-as-is. Record in verification_metadata.coverage. No silent pass. |
| E16 | User picks (b) Request changes at Step 5.4 | design_feedback injected into every B1 dispatch's design_context_override (appended); loop to Step 2; the pending-approval draft is replaced next pass. design_round increments. |
| E17 | User picks (c) Re-roll at Step 5.4 | No feedback injection. Same design_context_override variation library. Fresh isolated B1 agents via Agent tool. design_round increments. |
| E18 | User picks (a) Feedback at Step 7 | Feedback concatenated to desired_outcome for B2 re-invocation. B2 sees the augmented outcome. Slicing-round counter increments. |
| E19 | User picks (c) Try another slicing round at Step 7 | Fresh B2 re-invocation with same original inputs. No feedback injection. Round counter increments. |
| E20 | User approves design (Step 5) then rejects slices (Step 7) multiple times | Step 7 hard gate stays in place per round. No special handling. User can use (a) feedback to steer B2 ("regenerate slices for the same approved design with constraint X"). |
Eval Harness
This skill ships a Python eval companion (eval.py). The harness is hybrid by design, following B1/B2 precedent:
| Layer | Mechanism | Lives in |
|---|---|---|
| Deterministic checks | Python script — input fixture schema validation, output schema validation, cross-field checks, SHA-256 change-impact diff | ~/.claude/skills/solution-design/eval.py |
| Judgment-quality eval | /double-check invocations against fixtures |
Caller's responsibility (not bundled into eval.py) |
Fixtures
~/.claude/skills/solution-design/fixtures/ holds 3 starter fixtures:
| File | Shape |
|---|---|
sample-pass.json |
2 candidates (1 Sonnet + 1 Opus), PASS on both post-verifications, first run (prior_alternative_n: null) |
sample-escalate-on-verify.json |
2 candidates, ESCALATE on final post-verify — exercises E7 path |
sample-reclarification.json |
1 candidate with a locked-field conflict assumption — exercises E8 / Step 7b category-(iii) path |
Running the deterministic eval
# Validate one fixture + a captured skill output against the schema, and diff against a baseline:
python3 ~/.claude/skills/solution-design/eval.py \
--fixture ~/.claude/skills/solution-design/fixtures/sample-pass.json \
--skill-output /tmp/b3-run-2026-05-22.json \
[--baseline /tmp/b3-run-prior.json]The script emits a JSON report to stdout with:
fixture_schema_valid: true | falseoutput_schema_valid: true | falsecross_field_errors: list of cross-field check failures (empty = clean)change_impact:{sha256: "<hex>", diff: "<unified-diff>" | null}
Exits 0 if both schemas valid and no cross-field errors. Exits 1 otherwise.
Cross-field checks (deterministic)
| Check | Error |
|---|---|
output.discovery_src_hash absent or empty |
"output.discovery_src_hash is required" |
output.discovery_src_hash != fixture.discovery_src_hash |
"output.discovery_src_hash mismatch — chosen candidate was dispatched against a different Discovery state" |
fixture.prior_alternative_n > 0 AND output.alternative_n <= fixture.prior_alternative_n |
"monotonic-N rule violated: output.alternative_n must be greater than prior_alternative_n" |
fixture.prior_alternative_n > 0 AND output.supersession_marker_written != true |
"prior alternative not marked superseded — supersession_marker_written must be true when prior_alternative_n > 0" |
output.verification_metadata.selector_ranking absent |
"verification_metadata.selector_ranking is required (Step 4 /double-check result)" |
output.verification_metadata.final_output absent |
"verification_metadata.final_output is required (Step 9 /double-check result)" |
Source
~/.claude/rules/code_first_architecture.mdlines 81–102 — AI Adapter / judgment-port pattern.~/.claude/rules/code_first_architecture.md:112— Producer-never-verifies invariant.${KIT_HOOKS_DIR}/pre_plan_gates.py:153-158—DISCOVERY_LOCKED_FIELDS(the four locked field names).${KIT_HOOKS_DIR}/pre_plan_gates.py:178-189—_discovery_locked_fields_hash(12-hex SHA-256 prefix).~/.claude/skills/solution-designer/SKILL.md— B1 Input Contract + Output Contract (ports B3 consumes).~/.claude/skills/solution-slicer/SKILL.md— B2 Input Artifact + Output Contract (ports B3 consumes).~/.claude/skills/double-check/SKILL.md— post-verification pattern (multi-agent dispatch + PASS-only user-facing results).~/.claude/rules/factcheck-convergence.md§2 — independence / isolated context.~/.claude/rules/plan-gates.mdGate 0a OQ19 — Plain business words first.Thoughts/workflow-phases-redesign_THOUGHT.mdS-H-v2-A entry — 3-skill split + V1 hybrid selector + C1–C5 constraints.Thoughts/workflow-phases-redesign_H_v2_B3_PLAN.md— locked plan this skill implements.
Non-goals
- This skill does not modify B1 or B2 contracts. Ports are consumed as-is.
- It does not decide whether Phase 2 should run (Optionality Boundary).
- It does not select among candidates by formula. An Opus selector ranks qualitatively and B3 auto-takes the verified rank-1 (Step 5.1); the user gate owns approval of the finished, coverage-complete design (Step 5.4), not candidate selection.
- It does not verify its own output. Producer-never-verifies via
/double-checkat Steps 4, 5.3, and 9. - It does not write a
chosen(final) Design until Step 9 post-verify PASSes. Apending-approvaldraft is written at Step 5.4 only after the coverage gate (Step 5.3) PASSes, and is flipped tochosenonly at Step 10. ESCALATE at any seam = no advance past it without the user's (a)/(b) choice. - It does not produce more than one
### Solution Alternative Nper invocation. - It does not change the
# Discoverysection. Discovery is the input;# Solution Designis the output. - It does not bypass the re-clarification counter cap. Hard-stop at round-trip 3.