From 11f18a7b3b1117d48279477264d7bb7fc78dcf93 Mon Sep 17 00:00:00 2001 From: Yoichiro Hara Date: Fri, 2 Oct 2026 04:53:01 +0900 Subject: [PATCH 1/2] fix: continue in smaller waves when a teammate spawn is refused (v3.2.1) Why: in a trial run a machine-local cap of three concurrent subagents refused Stage 1's fourth writer, and the lead stopped the unattended run to ask whether to wait or write the files itself. Caps, rate limits, usage limits and hooks can all refuse a spawn. The lead now runs the remaining teammates in smaller waves, down to one at a time, keeps their separate contexts, and writes files itself only as a recorded last resort. The rule is in the pipeline agent and in the project CLAUDE.md template so stages invoked directly follow it too; conformance checks both. Co-Authored-By: Claude Opus 5.5 --- .claude-plugin/plugin.json | 2 +- README.md | 4 ++++ agents/transmute-pipeline.md | 2 ++ scripts/conformance.sh | 1 + templates/CLAUDE.md | 1 + 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index ec64c7e..9cee322 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "transmuter", "description": "Transmute Framework — AI-driven pipeline that transforms a business plan into a fully deployed product through 25 stages (23 automated, 2 manual)", - "version": "3.2.0", + "version": "3.2.1", "author": { "name": "Transmute", "url": "https://github.com/VoxTechnologies/transmute-framework" diff --git a/README.md b/README.md index d919f5e..73ae8ed 100644 --- a/README.md +++ b/README.md @@ -304,6 +304,10 @@ Contributors: run `scripts/conformance.sh` before a release (`--live` also loads ## Changelog +### v3.2.1 + +- A lead whose teammate spawn is refused (concurrency cap, rate or usage limit, a hook) now continues in smaller waves instead of stopping to ask the operator. Found in a trial run where a machine-local cap of three concurrent subagents stopped Stage 1 with a question. The rule is in the pipeline agent's Execution Model and in the generated project's `CLAUDE.md` § Safety-Critical Rules, so stages invoked directly follow it too + ### v3.2.0 **Pipeline flow** — nine changes to how the stages run, in the order they pay off. diff --git a/agents/transmute-pipeline.md b/agents/transmute-pipeline.md index b045ef9..6aacdb2 100644 --- a/agents/transmute-pipeline.md +++ b/agents/transmute-pipeline.md @@ -51,6 +51,8 @@ Report outcomes faithfully. Before writing a stage's status to `plancasting/_pro Stage skills spawn "teammates". In this plugin a teammate is a subagent started with the Agent tool (`subagent_type` = the agent name under `agents/`, or `general-purpose` with the spawn prompt from the stage's detailed guide). Its final message is its completion message to you. Start independent teammates in one message so they run concurrently, and keep working while they run; give a long-lived teammate a `name` so follow-up instructions go through `SendMessage` instead of re-spawning it with the context rebuilt. The messaging vocabulary in the detailed guides ("message the lead", "shared task list") also maps onto Claude Code's experimental Agent Teams when `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` is set; the Agent-tool mapping above is the default. Do not end your turn while teammates are still running on the assumption that their completion will wake you: wait for them (or start them in the foreground) before reporting a stage complete — in a non-interactive (`claude -p`) run the harness terminates background subagents after 600 seconds unless `CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=0` is set, and a stage that ends its turn early is reported as finished with its files missing. + +**When a spawn is refused.** When a teammate cannot be started — the Agent tool refuses the spawn because of a concurrency cap, a rate limit, a usage limit, or a hook — do not stop to ask the operator. Run the teammates you could not start in smaller waves, starting each wave as the previous one finishes, down to one at a time. Keep each teammate's scope and its separate context, since the stage's review steps depend on them; writing a teammate's files yourself is the last resort, used only when not even one teammate can be started, and recorded in the stage report. Pass this rule on in every stage skill you invoke. ## Pipeline Overview ``` diff --git a/scripts/conformance.sh b/scripts/conformance.sh index 01192e6..b60c288 100755 --- a/scripts/conformance.sh +++ b/scripts/conformance.sh @@ -68,6 +68,7 @@ check "no current-generation model ID carries a date suffix" bash -c '! rg -q "c check "hook script syntax" bash -n hooks/scripts/check-prerequisites.sh check "cast.md knows the attended mode and the early-verify (5V) alias" bash -c 'grep -q "attended" commands/cast.md && grep -q "early-verify" commands/cast.md' check "progress template carries Duration and Usage columns and the 5V row" bash -c 'grep -q "| Duration | Usage |" templates/progress.md && grep -q "^| 5V |" templates/progress.md' +check "spawn-refusal rule present in the pipeline agent and the project CLAUDE.md" bash -c 'grep -q "When a spawn is refused" agents/transmute-pipeline.md && grep -q "Teammate spawn refused" templates/CLAUDE.md' check "pipeline agent defines the Stage 1 and 5V gates" bash -c 'grep -q "### Stage 1 Gate" agents/transmute-pipeline.md && grep -q "### 5V Gate" agents/transmute-pipeline.md' echo "== Gate hook behaviour (fixtures) ==" diff --git a/templates/CLAUDE.md b/templates/CLAUDE.md index 105f563..b52c629 100644 --- a/templates/CLAUDE.md +++ b/templates/CLAUDE.md @@ -26,6 +26,7 @@ All stages follow the **Transmute Full-Build Approach**: every feature in the Bu ### Safety-Critical Rules +- **Teammate spawn refused**: When a teammate cannot be started — the Agent tool refuses the spawn because of a concurrency cap, a rate limit, a usage limit, or a hook — do not stop to ask the operator. Run the teammates you could not start in smaller waves, starting each wave as the previous one finishes, down to one at a time. Keep each teammate's scope and its separate context, since the stage's review steps depend on them; writing a teammate's files yourself is the last resort, used only when not even one teammate can be started, and recorded in the stage report. - **Never skip** 5B, 5V, 6V, 6P/6P-R, or 7V. Always run exactly one of 6P or 6P-R (default: 6P). (5V is the 6V prompt in `MODE: critical`, run right after 5B so a product that does not start is sent back to Stage 5 before the Stage 6 audits.) (5B catches the #1 cause of Stage 6 failures — frontend stubs and duplication that slip through late-queue quality gates.) Note: 5B uses four outcomes (PASS, CONDITIONAL PASS, FAIL-RETRY, FAIL-ESCALATE) — see execution-guide.md § "Gate Decision Outcomes" for thresholds and recovery actions. - **6P / 6P-R mutual exclusivity**: Run exactly one, never both. To switch: commit 6P work, `git revert` the 6P commit, then run 6P-R in a new session. - **6R skip conditions**: Skip 6R only if 6V returns PASS (zero issues) or CONDITIONAL PASS with only 6V-C issues (human-judgment items — architectural decisions, design trade-offs — that 6R cannot auto-fix). If 6V returns FAIL, resolve critical blocking issues (manually or by re-running relevant Stage 5/6 steps) and re-run 6V until it achieves PASS or CONDITIONAL PASS before proceeding to 6R. If skipped, 6P/6P-R uses the 6V report as input. From 007e84961e804b159ffa06b3662078fe222c35dc Mon Sep 17 00:00:00 2001 From: Yoichiro Hara Date: Fri, 2 Oct 2026 06:49:11 +0900 Subject: [PATCH 2/2] fix: enforce the Stage 1 assumption gate in the hook A trial on the sample plan produced a BRD that was 60% assumptions. The pipeline agent stops there, but stages invoked directly did not: Stage 2 ran for 51 minutes and Stage 2B could only return FAIL. The hook now blocks prd and validate-specs until the operator marks the assumptions reviewed, matching the bold marker the review log actually writes. trial-run.sh gains ACCEPT_ASSUMPTIONS=1 for fixture plans. Co-Authored-By: Claude Opus 5.5 --- README.md | 1 + agents/transmute-pipeline.md | 2 +- examples/sample-plan/README.md | 4 +++- hooks/scripts/check-prerequisites.sh | 15 +++++++++++++++ scripts/conformance.sh | 4 ++++ scripts/trial-run.sh | 11 ++++++++++- templates/execution-guide.md | 2 +- 7 files changed, 35 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 73ae8ed..e4a04ca 100644 --- a/README.md +++ b/README.md @@ -307,6 +307,7 @@ Contributors: run `scripts/conformance.sh` before a release (`--live` also loads ### v3.2.1 - A lead whose teammate spawn is refused (concurrency cap, rate or usage limit, a hook) now continues in smaller waves instead of stopping to ask the operator. Found in a trial run where a machine-local cap of three concurrent subagents stopped Stage 1 with a question. The rule is in the pipeline agent's Execution Model and in the generated project's `CLAUDE.md` § Safety-Critical Rules, so stages invoked directly follow it too +- The gate hook now enforces the Stage 1 stop condition: `prd` and `validate-specs` are blocked while the BRD is 30% or more assumptions and `_review-log.md` does not say `Operator reviewed: YES`. In the 2026-10-02 trial the sample plan came out at 60% assumptions, Stage 2 ran for 51 minutes anyway, and Stage 2B could only end in FAIL. `scripts/trial-run.sh` gains `ACCEPT_ASSUMPTIONS=1` for fixture plans ### v3.2.0 diff --git a/agents/transmute-pipeline.md b/agents/transmute-pipeline.md index 6aacdb2..3b65d7e 100644 --- a/agents/transmute-pipeline.md +++ b/agents/transmute-pipeline.md @@ -118,7 +118,7 @@ For each stage: ### Stage 1 Gate (assumption volume) -Stage 1 has no PASS/FAIL gate on requirement quality, but it has one stop condition: if `plancasting/brd/_review-log.md` § "Assumption Review Status" reports an assumption volume ≥ 30% and `Operator reviewed: YES` is not set, the business plan is too thin to build from. Mark Stage 1 `⏸ Awaiting operator review (assumptions ≥ 30%)` in `plancasting/_progress.md`, print the assumption percentage and the list of assumed requirements, and stop — do not run Stage 2 (Stage 2B would FAIL on the same marker anyway). The operator either revises the business plan and re-runs Stage 1, or reviews the assumptions and sets the marker, then runs `/transmuter:cast resume`. +Stage 1 has no PASS/FAIL gate on requirement quality, but it has one stop condition: if `plancasting/brd/_review-log.md` § "Assumption Review Status" reports an assumption volume ≥ 30% and `Operator reviewed: YES` is not set, the business plan is too thin to build from. Mark Stage 1 `⏸ Awaiting operator review (assumptions ≥ 30%)` in `plancasting/_progress.md`, print the assumption percentage and the list of assumed requirements, and stop — do not run Stage 2 (Stage 2B would FAIL on the same marker anyway). The operator either revises the business plan and re-runs Stage 1, or reviews the assumptions and sets the marker, then runs `/transmuter:cast resume`. The gate hook enforces the same condition when `prd` or `validate-specs` is invoked directly. ### 5B Gate - **PASS** (zero remaining issues AND all tests pass — no regressions from 5B fixes) → proceed to Stage 6 diff --git a/examples/sample-plan/README.md b/examples/sample-plan/README.md index 73d55b1..733ae89 100644 --- a/examples/sample-plan/README.md +++ b/examples/sample-plan/README.md @@ -18,11 +18,13 @@ Operator answers for Stage 0 (use these instead of asking; if a question is not - Deployment: manual. Credentials: write placeholder values (YOUR_*_HERE) into .env.local; do not validate keys. ``` +The plan is thin on purpose, so Stage 1 marks well over 30% of the BRD as assumptions (60% in the 2026-10-02 trial) and the Stage 1 gate stops the pipeline before Stage 2 until an operator reviews them. For a trial on this fixture, set `ACCEPT_ASSUMPTIONS=1`: the runner then sets `Operator reviewed: YES` in `plancasting/brd/_review-log.md` after Stage 1. Never use it on a real plan. + Example: ```bash mkdir -p ~/trial && cp -R examples/sample-plan/plancasting ~/trial/ && cd ~/trial && git init -q -EXTRA_PROMPT="$(sed -n '/^```text$/,/^```$/p' ~/transmute-framework/examples/sample-plan/README.md | sed '1d;$d')" \ +ACCEPT_ASSUMPTIONS=1 EXTRA_PROMPT="$(sed -n '/^```text$/,/^```$/p' ~/transmute-framework/examples/sample-plan/README.md | sed '1d;$d')" \ ~/transmute-framework/scripts/trial-run.sh ~/trial tech-stack brd prd validate-specs scaffold ``` diff --git a/hooks/scripts/check-prerequisites.sh b/hooks/scripts/check-prerequisites.sh index b201a53..9737407 100755 --- a/hooks/scripts/check-prerequisites.sh +++ b/hooks/scripts/check-prerequisites.sh @@ -41,6 +41,19 @@ block() { exit 2 } +# Stage 1 stop condition (agents/transmute-pipeline.md § Stage 1 Gate). A plan whose BRD is +# >= 30% assumptions fails Stage 2B unless the operator has reviewed them, so block Stage 2 +# up front instead of spending a PRD run on it. The marker is matched loosely because the +# review log writes it as a bold list item ("- **Operator reviewed**: YES"). +assumption_gate() { + local log="./plancasting/brd/_review-log.md" pct + [[ -f "$log" ]] || return 0 + pct=$(sed -n 's/.*Assumption volume[*]*:[*[:space:]]*\([0-9][0-9]*\)\(\.[0-9]*\)\{0,1\}%.*/\1/p' "$log" | head -1) + [[ -n "$pct" && "$pct" -ge 30 ]] || return 0 + grep -qiE 'Operator reviewed[*]*:[*[:space:]]*YES' "$log" && return 0 + block "$1 is stopped by the Stage 1 gate: the BRD is ${pct}% assumptions and $log does not say 'Operator reviewed: YES'. Revise the business plan and re-run Stage 1, or review the assumptions and set the marker." +} + # Define prerequisite checks for each stage case "$SKILL_NAME" in tech-stack) @@ -65,6 +78,7 @@ case "$SKILL_NAME" in if [[ ! -d "./plancasting/brd" ]]; then block "Stage 2 (PRD) requires ./plancasting/brd/ from Stage 1. Run '/transmuter:cast brd' first." fi + assumption_gate "Stage 2 (PRD)" ;; validate-specs) @@ -72,6 +86,7 @@ case "$SKILL_NAME" in if [[ ! -d "./plancasting/brd" ]] || [[ ! -d "./plancasting/prd" ]]; then block "Stage 2B (Spec Validation) requires both ./plancasting/brd/ and ./plancasting/prd/. Run Stages 1 and 2 first." fi + assumption_gate "Stage 2B (Spec Validation)" ;; scaffold) diff --git a/scripts/conformance.sh b/scripts/conformance.sh index b60c288..bdeade5 100755 --- a/scripts/conformance.sh +++ b/scripts/conformance.sh @@ -82,6 +82,10 @@ run_hook() { echo "$1" | bash "$HOOK" >/dev/null 2>&1; echo $?; } [[ "$(run_hook '{"tool_name":"Skill","tool_input":{"skill":"feedback"}}')" == 0 ]] && pass "feedback (no prerequisites) passes" || fail "feedback should pass" mkdir -p plancasting/businessplan plancasting/_audits/spec-validation && touch plancasting/businessplan/plan.md plancasting/_audits/spec-validation/report.md plancasting/tech-stack.md [[ "$(run_hook '{"tool_name":"Skill","tool_input":{"skill":"brd"}}')" == 0 ]] && pass "brd passes with business plan + tech-stack.md" || fail "brd should pass once prerequisites exist" +mkdir -p plancasting/brd && printf -- '- **Assumption volume**: 60.1%% (193 / 321)\n- **Operator reviewed**: NO\n' > plancasting/brd/_review-log.md +[[ "$(run_hook '{"tool_name":"Skill","tool_input":{"skill":"prd"}}')" == 2 ]] && pass "prd blocked by the Stage 1 gate (assumptions >= 30%, not reviewed)" || fail "prd should block on unreviewed assumptions" +sed -i.bak 's/\*\*Operator reviewed\*\*: NO/**Operator reviewed**: YES/' plancasting/brd/_review-log.md +[[ "$(run_hook '{"tool_name":"Skill","tool_input":{"skill":"prd"}}')" == 0 ]] && pass "prd passes once the operator marks the assumptions reviewed" || fail "prd should pass with Operator reviewed: YES" printf 'TRANSMUTER_ANTHROPIC_API_KEY=YOUR_KEY_HERE\nRESEND_API_KEY=CHANGE_ME\n' > .env.local [[ "$(run_hook '{"tool_name":"Skill","tool_input":{"skill":"scaffold"}}')" == 2 ]] && pass "scaffold blocked on placeholder pipeline-infrastructure credential (red tier)" || fail "scaffold should block on red-tier placeholder" printf 'TRANSMUTER_ANTHROPIC_API_KEY=sk-ant-real\nRESEND_API_KEY=CHANGE_ME\n' > .env.local diff --git a/scripts/trial-run.sh b/scripts/trial-run.sh index e7753e4..6925aa2 100755 --- a/scripts/trial-run.sh +++ b/scripts/trial-run.sh @@ -14,6 +14,10 @@ # MAX_TURNS per stage (default: 300) # EXTRA_PROMPT text appended to every stage invocation (operator answers, # dry-run instructions, etc.) +# ACCEPT_ASSUMPTIONS=1 after Stage 1, mark the BRD assumptions as reviewed +# (`Operator reviewed: YES`). Only for fixture plans such as +# examples/sample-plan, which are deliberately thin: without it +# the Stage 1 gate stops the trial before Stage 2. # # Output: /plancasting/_trial/.json (full result), # /plancasting/_trial/usage.tsv (one row per stage). @@ -28,6 +32,7 @@ PLUGIN_DIR="${PLUGIN_DIR:-$ROOT}" MODEL="${MODEL:-claude-opus-5-5}" MAX_TURNS="${MAX_TURNS:-300}" EXTRA_PROMPT="${EXTRA_PROMPT:-}" +ACCEPT_ASSUMPTIONS="${ACCEPT_ASSUMPTIONS:-0}" export PATH="$HOME/.local/bin:$PATH" # In print mode Claude Code terminates background subagents (the stage teammates) after # 600 s unless this is 0 — measured 2026-10-02: Stage 1 lost 3 of 5 writers and ended with @@ -85,8 +90,12 @@ EOF if [[ $rc -ne 0 ]]; then result="claude-exit-$rc" elif [[ -n "$exp" && ! -e "$exp" ]]; then result="missing:$exp" else result="ok"; fi + if [[ "$stage" == brd && "$result" == ok && "$ACCEPT_ASSUMPTIONS" == 1 ]]; then + sed -i.bak -E 's/(Operator reviewed[*]*:[*[:space:]]*)NO/\1YES/' plancasting/brd/_review-log.md && rm -f plancasting/brd/_review-log.md.bak + result="ok (assumptions accepted by ACCEPT_ASSUMPTIONS)" + fi printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' "$stage" "$started" "$dur" "$turns" "$inp" "$out" "$cr" "$cc" "$result" >> "$TSV" echo " $result ${dur} min turns=$turns out=$out cache_read=$cr" - [[ "$result" == "ok" ]] || { echo "stopping at $stage ($result); see plancasting/_trial/$stage.err" >&2; exit 1; } + [[ "$result" == ok* ]] || { echo "stopping at $stage ($result); see plancasting/_trial/$stage.err" >&2; exit 1; } done echo "trial complete"; column -t -s $'\t' "$TSV" diff --git a/templates/execution-guide.md b/templates/execution-guide.md index 5f5c8b7..031a54f 100644 --- a/templates/execution-guide.md +++ b/templates/execution-guide.md @@ -287,7 +287,7 @@ Before proceeding to Stage 2, review: - `./plancasting/brd/06-business-requirements.md` — Are the business requirements accurate? - `./plancasting/brd/07-functional-requirements.md` — Are ALL features captured as FRs? - Any items marked with `> ⚠️ ASSUMPTION:` — Correct or confirm these. -- **Assumption review timing**: Read `./plancasting/brd/_review-log.md` § "Assumption Review Status" (generated by Stage 1). If assumption volume ≥30%, operator must review and confirm assumptions in the BRD files and update the review status to `Operator reviewed: YES` before running Stage 2 (so the PRD uses corrected assumptions). If <30%, proceed directly. **Where to mark**: Set the review status in `./plancasting/brd/_review-log.md` by adding the line: `Assumption Review Status: Operator reviewed: YES`. **Assumption volume** = (number of requirements with `⚠️ ASSUMPTION` markers) / (total number of requirements across all BRD files) × 100%. **Consequence if skipped**: Stage 2B gate rule 2 checks this marker — if assumption volume ≥30% and the marker is not set to `Operator reviewed: YES`, Stage 2B will return FAIL. You must review and set the marker, then re-run Stage 2B. See `prompt_validate_specs.md` for the full decision tree. +- **Assumption review timing**: Read `./plancasting/brd/_review-log.md` § "Assumption Review Status" (generated by Stage 1). If assumption volume ≥30%, operator must review and confirm assumptions in the BRD files and update the review status to `Operator reviewed: YES` before running Stage 2 (so the PRD uses corrected assumptions). If <30%, proceed directly. **Where to mark**: In `./plancasting/brd/_review-log.md` § "Assumption Review Status", change `- **Operator reviewed**: NO` to `- **Operator reviewed**: YES` and fill in the date. The gate hook also blocks `/transmuter:cast prd` and `validate-specs` until this is set. **Assumption volume** = (number of requirements with `⚠️ ASSUMPTION` markers) / (total number of requirements across all BRD files) × 100%. **Consequence if skipped**: Stage 2B gate rule 2 checks this marker — if assumption volume ≥30% and the marker is not set to `Operator reviewed: YES`, Stage 2B will return FAIL. You must review and set the marker, then re-run Stage 2B. See `prompt_validate_specs.md` for the full decision tree. Commit the generated files before making edits so you can review your changes with `git diff`. Make edits directly to the BRD files if needed. The PRD stage reads from these files.