diff --git a/README.md b/README.md index 1325eb0..f63666b 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,9 @@ cd /path/to/project && pi # Start coding /workflow tri-dispatch "compare caching strategies" /workflow tri-debug "TypeError in handleAuth after upgrading passport" /workflow tri-security "audit src/api/ for vulnerabilities" +/workflow autoloop "Goal: increase coverage to 90% Metric: npx vitest --coverage Guard: npm run build" +/workflow predict "security and reliability gaps in src/api/" +/workflow reason "Should we use event sourcing for order management? Domain: software" /workflow self-improve "--target src/ --metric 'npm test' --objective 'fix failing tests'" /workflow self-test "npm test" /workflow self-lint "npx eslint src/" @@ -52,6 +55,9 @@ cd /path/to/project && pi # Start coding | `tri-dispatch` | 3 models in parallel → Compare | all tiers | | `tri-debug` | 3 models diagnose in parallel → Compare theories | all tiers | | `tri-security` | 3 parallel audits (injection, auth, config) → Report | all tiers | +| `predict` | Recon → 3 analysts (parallel) → Devil's advocate debate → Rank → Report | all tiers | +| `reason` | Generate A → Critique → Generate B → Synthesize → 3 blind judges (parallel) → Converge (loop) → Report | all tiers | +| `autoloop` | Baseline → Audit (git history) → Fix → Commit → Measure → Guard → Keep/Revert (loop) → Report | fast + smart | | `self-improve` | Baseline → Improve (loop) → Report | fast + smart | | `self-test` | Run tests → Fix failures (loop) → Summary | fast + smart | | `self-lint` | Run linter → Fix violations (loop) → Summary | fast + smart | diff --git a/workflows/autoloop.yml b/workflows/autoloop.yml index fd83092..ad00af4 100644 --- a/workflows/autoloop.yml +++ b/workflows/autoloop.yml @@ -1,5 +1,5 @@ name: Autoloop -description: Autonomous improvement loop — audit, fix, measure, keep or revert, repeat +description: Autonomous improvement loop — measure, change, verify, guard, keep or revert budget: limit: 500000 @@ -9,50 +9,73 @@ steps: - id: baseline model: fast prompt: | - Run the user's metric command to establish a baseline measurement. + Establish a baseline measurement for the autoloop. User input: {{input}} Extract the metric command from the input and run it via Bash. - Report the raw output and extract a single numeric score. + If none provided, detect the stack and use: + - Go: go test -cover ./... (higher-is-better) + - TypeScript: npx vitest --coverage (higher-is-better) + - Python: pytest --cov --cov-report term-missing (higher-is-better) + - Rust: cargo test (higher-is-better) + - Lint: error count (lower-is-better) - You MUST output these two lines exactly: + If the user specified `Guard:` in their input, extract the guard command + and run it now to establish a guard baseline. Report its output. + + If the user specified `Runs:` (a number), note it. Default is 1. + If Runs > 1, run the metric command that many times and report the MEDIAN. + + You MUST output these lines exactly: + METRIC_CMD: SCORE: - DIRECTION: higher-is-better (or: DIRECTION: lower-is-better) + DIRECTION: higher-is-better (or: lower-is-better) + GUARD_CMD: + GUARD_BASELINE: + RUNS: + + If the command fails, say "AUTOLOOP_ERROR: metric command failed" and stop. + + - id: history + model: fast + prompt: | + Read iteration history from git, not a scratchpad file. + + Run these commands: + 1. git log --oneline -20 + 2. git log --oneline -20 | grep -E "autoloop:|Revert" + 3. If the last commit message starts with "autoloop:", run git diff HEAD~1 --stat - If no metric command was provided, detect the stack and use the appropriate default: - - Go: go test -cover ./... (higher-is-better: coverage %) - - TypeScript: npx vitest --coverage (higher-is-better: coverage %) - - Python: pytest --cov --cov-report term-missing (higher-is-better: coverage %) - - Rust: cargo test (higher-is-better: pass count) - - Lint: count of errors (lower-is-better) + Summarize: + - How many autoloop commits exist? + - Which were kept (autoloop: prefix, not reverted)? + - Which were reverted? + - What pattern do the kept changes share? + - What approaches were tried and failed? - If the command fails or produces no numeric output, say "AUTOLOOP_ERROR: metric command failed" - and do NOT proceed. + If this is the first iteration (no autoloop commits), say "FIRST_ITERATION". - id: audit model: smart prompt: | - Analyze the codebase and pick the SINGLE highest-impact improvement to make. - - User objective: {{input}} - Current baseline: {{baseline}} + Pick the SINGLE highest-impact change to make. - Read .pikit/scratchpads/current.md if it exists — it contains what was already tried. - Do NOT repeat any approach listed as "reverted" in the scratchpad. + Objective: {{input}} + Baseline: {{baseline}} + Git history: {{history}} - Measure what's relevant to the objective: - - If coverage objective: find the lowest-coverage package/file - - If lint objective: find the most common lint error category - - If performance objective: identify the hottest path - - If security objective: find the most critical vulnerability + Rules: + - Do NOT repeat any approach visible in reverted commits from git history. + - If history shows a pattern of success (e.g., touching file X improved the metric), exploit it. + - If 5+ consecutive reverts are visible, try a fundamentally different strategy. - Output exactly ONE hypothesis to test: + Output exactly: - HYPOTHESIS: - - TARGET: + - TARGET: - EXPECTED IMPACT: - Do NOT make any changes yet. Only analyze and recommend. + Do NOT make changes yet. - id: fix model: smart @@ -63,124 +86,155 @@ steps: Hypothesis: {{audit}} Rules: - - Only change what the hypothesis recommends - - Do NOT refactor unrelated code - - Do NOT change tests to make them pass (fix the code, not the tests) - - Keep changes minimal and focused - - Check .pikit/scratchpads/current.md to avoid repeating failed approaches - - Track which files you modify — list them at the end + - Only change what the hypothesis recommends. + - Do NOT refactor unrelated code. + - Do NOT change tests to make them pass. + - Keep changes minimal and focused. After making changes, output: - What you changed and why - - MODIFIED FILES: + - MODIFIED_FILES: + + - id: commit + model: fast + prompt: | + Commit the changes BEFORE measuring. This enables clean revert if it fails. + + Modified files from fix step: {{fix}} + + Run: + git add + git diff --cached --quiet + + If exit code 0 (nothing staged): say "NO_CHANGES" and stop. + Otherwise: + git commit -m "autoloop: " + + Output the commit hash. + branch: + - when: "NO_CHANGES" + goto: audit - id: measure model: fast prompt: | - Run the EXACT same metric command from the baseline to measure the result. + Run the EXACT metric command from the baseline to measure the result. - Baseline step output: {{baseline}} + Baseline: {{baseline}} - Extract the metric command that was used in the baseline step and run it again via Bash. - Report the raw output and extract the numeric score. + Extract METRIC_CMD and RUNS from the baseline. + If RUNS > 1, run the command that many times. + Sort the results numerically and take the median (middle value). - You MUST output this line exactly: - SCORE: + You MUST output: SCORE: - - id: compare + - id: guard model: fast prompt: | - Compare the baseline to the current measurement. + Check the guard command if one was configured. + + Baseline: {{baseline}} + Current measurement: {{measure}} + + Extract GUARD_CMD from the baseline. + If GUARD_CMD is NONE, output on the FIRST line: GUARD_PASSED + + Otherwise run the guard command. + If GUARD_BASELINE is a number, extract the guard metric from the output. + If it regressed more than 5% from GUARD_BASELINE, output on the FIRST line: GUARD_FAILED + Then on following lines, include the error output. + If GUARD_BASELINE is NONE (pass/fail mode): + exit 0 → output on the FIRST line: GUARD_PASSED + exit non-zero → output on the FIRST line: GUARD_FAILED + Then on following lines, include the error output. - Baseline output: - {{baseline}} + The FIRST line of your output MUST be exactly GUARD_PASSED or GUARD_FAILED. - Current measurement: - {{measure}} + - id: compare + model: fast + prompt: | + Compare baseline to current measurement and check the guard. + + Baseline: {{baseline}} + Measurement: {{measure}} + Guard result: {{guard}} - Extract the SCORE from the baseline and the SCORE from the measurement. - Extract the DIRECTION from the baseline. + Extract SCORE from baseline and measurement. Extract DIRECTION from baseline. - Rules — follow these exactly: - - If DIRECTION is higher-is-better: current SCORE > baseline SCORE means IMPROVED - - If DIRECTION is lower-is-better: current SCORE < baseline SCORE means IMPROVED - - If scores are equal: REGRESSED (no change counts as failure) - - If either SCORE is missing or non-numeric: REGRESSED + Decision matrix (follow exactly): + 1. If GUARD_FAILED: output "REVERT" regardless of metric. + 2. If DIRECTION is higher-is-better AND current > baseline: output "IMPROVED". + 3. If DIRECTION is lower-is-better AND current < baseline: output "IMPROVED". + 4. Otherwise: output "REVERT". - Output exactly one word on the first line: IMPROVED or REGRESSED - Then explain: "baseline SCORE was X, current SCORE is Y, direction is Z" + Then explain: "baseline was X, current is Y, direction is Z, guard is P" branch: - when: "IMPROVED" goto: keep - - when: "REGRESSED" + - when: "REVERT" goto: revert - id: keep model: fast prompt: | - The change IMPROVED the metric. Keep it. + The change improved the metric and passed the guard. Keep it. - What was changed: {{fix}} + Audit: {{audit}} Measurement: {{measure}} Comparison: {{compare}} - 1. Stage and commit only the modified files listed in the fix step: - git add && git commit -m "autoloop: " - Do NOT use git add -A (it stages untracked files that may not be yours). - 2. Update .pikit/scratchpads/current.md — append: - --- - Iteration: kept - Hypothesis: {{audit}} - Result: {{compare}} - 3. The baseline SCORE for the next cycle is now the current SCORE from {{measure}}. - - Count the iterations in the scratchpad. Extract the iteration limit from the user input: {{input}} - If the iteration count >= the limit (default 10), say "AUTOLOOP_COMPLETE". - Otherwise say "CONTINUE" to trigger the next audit cycle. + The commit already exists from the commit step. Nothing to stage. + + All future comparisons are against the ORIGINAL baseline from {{baseline}}. + This tracks cumulative progress across the full session. + + Count iterations (each autoloop: commit is one iteration, kept or not): + git log --oneline | grep -c "autoloop:" + Extract the iteration limit from user input: {{input}} (default 10). + + If count >= limit, say "AUTOLOOP_COMPLETE". + Otherwise say "CONTINUE". branch: - when: "AUTOLOOP_COMPLETE" goto: report - when: "CONTINUE" - goto: audit + goto: history - id: revert model: fast prompt: | - The change REGRESSED or had no effect. Revert it. + The change regressed or the guard failed. Revert. - What was attempted: {{fix}} + Audit: {{audit}} Measurement: {{measure}} Comparison: {{compare}} - 1. Revert only the modified files from the fix step: - git checkout -- - If you cannot determine the files, use: git checkout -- . (but do NOT run git clean -fd) - 2. Update .pikit/scratchpads/current.md — append: - --- - Iteration: reverted - Hypothesis: {{audit}} - Result: {{compare}} - Reason: - - Count the iterations in the scratchpad. Extract the iteration limit from the user input: {{input}} - If the iteration count >= the limit (default 10), say "AUTOLOOP_COMPLETE". - Otherwise say "CONTINUE" to try the next hypothesis. + Run: git revert HEAD --no-edit + If that fails (conflict): git revert --abort && git reset --hard HEAD~1 + + Count iterations (each autoloop: commit is one iteration, kept or not): + git log --oneline | grep -c "autoloop:" + Extract the iteration limit from user input: {{input}} (default 10). + + If count >= limit, say "AUTOLOOP_COMPLETE". + Otherwise say "CONTINUE". branch: - when: "AUTOLOOP_COMPLETE" goto: report - when: "CONTINUE" - goto: audit + goto: history - id: report model: smart prompt: | - The autoloop session is complete. Write a final report. + The autoloop is complete. Write a final report. - Original objective: {{input}} + Objective: {{input}} Starting baseline: {{baseline}} - Final measurement: {{measure}} + Last measurement: {{measure}} - Read .pikit/scratchpads/current.md for the full iteration history. + Read git history for the full record: + git log --oneline | grep -E "autoloop:|Revert" Report: ## Autoloop Report @@ -190,19 +244,17 @@ steps: ### Results - Starting metric: {baseline SCORE} - - Final metric: {final SCORE} + - Final metric: {last SCORE} - Net change: {delta} - - Iterations: {count kept + count reverted} - - Kept: {count} - - Reverted: {count} + - Iterations: {total autoloop + revert commits / 2 for reverts} + - Kept: {count of autoloop: commits not followed by a Revert} + - Reverted: {count of Revert commits} ### Changes Made (kept) - {list each kept change with what it improved} + {each kept autoloop commit message} ### Failed Attempts (reverted) - {list each reverted attempt with why it failed} + {each reverted commit message with why} ### Recommendation {what to do next} - - Clean up: delete .pikit/scratchpads/current.md diff --git a/workflows/predict.yml b/workflows/predict.yml new file mode 100644 index 0000000..038ba0c --- /dev/null +++ b/workflows/predict.yml @@ -0,0 +1,190 @@ +name: Predict +description: Multi-persona swarm analysis — independent experts analyze, debate, converge on ranked findings + +budget: + limit: 400000 + downgrade: fast + +steps: + - id: recon + model: fast + prompt: | + Scan the codebase for the predict analysis: {{input}} + + Build a concise knowledge summary (NOT raw file contents): + + If the user specified a scope in their input, use it as the find path. + Otherwise default to the current directory. + + 1. Run: find -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' -o -name '*.go' -o -name '*.py' -o -name '*.rs' -o -name '*.java' -o -name '*.rb' -o -name '*.php' \) | grep -v node_modules | grep -v vendor | head -50 + 2. For each file in scope, extract: exports, public functions/methods with signatures, key types + 3. Map imports between files (who depends on whom) + 4. Identify entry points (main, routes, handlers, exports) + + Output THREE sections, each as compact as possible: + + ## Entities + | File | Name | Kind | Signature | + (functions, classes, types — one row each, no descriptions) + + ## Dependencies + | File | Imports From | Symbols | + (one row per import edge) + + ## Clusters + | Cluster | Files | Risk | + (group related files, note risky areas in 3 words max) + + Keep the total output under 3000 chars. This is reference material, not analysis. + + - id: analyst-arch + model: smart + prompt: | + You are an Architecture Reviewer. Analyze this codebase independently. + + Goal: {{input}} + Codebase: {{recon}} + + Focus: scalability, coupling, design patterns, module boundaries. + Bias: prefer separation of concerns; skeptical of god objects. + + Rules: + - Every finding MUST include file:line or file reference. + - Max 6 findings. Prioritize by severity. + - Confidence: HIGH (certain from code), MEDIUM (likely), LOW (theoretical). + + Format each finding as: + [CRITICAL|HIGH|MEDIUM|LOW] [HIGH|MEDIUM|LOW confidence] file:location — title + Evidence: {what you see in the code} + Recommendation: {concrete action} + + - id: analyst-security + model: smart + prompt: | + You are a Security Analyst. Analyze this codebase independently. + + Goal: {{input}} + Codebase: {{recon}} + + Focus: OWASP Top 10, injection, auth failures, data exposure, crypto misuse. + Bias: assume hostile inputs; trust nothing from outside trust boundaries. + + Rules: + - Every finding MUST include file:line or file reference. + - Max 6 findings. Prioritize by severity. + - Confidence: HIGH (certain from code), MEDIUM (likely), LOW (theoretical). + + Format each finding as: + [CRITICAL|HIGH|MEDIUM|LOW] [HIGH|MEDIUM|LOW confidence] file:location — title + Evidence: {what you see in the code} + Recommendation: {concrete action} + + - id: analyst-reliability + model: smart + prompt: | + You are a Reliability Engineer. Analyze this codebase independently. + + Goal: {{input}} + Codebase: {{recon}} + + Focus: error handling, retry logic, race conditions, edge cases, observability. + Bias: assume failure; ask "what happens when X is nil or the network drops?" + + Rules: + - Every finding MUST include file:line or file reference. + - Max 6 findings. Prioritize by severity. + - Confidence: HIGH (certain from code), MEDIUM (likely), LOW (theoretical). + + Format each finding as: + [CRITICAL|HIGH|MEDIUM|LOW] [HIGH|MEDIUM|LOW confidence] file:location — title + Evidence: {what you see in the code} + Recommendation: {concrete action} + + - id: dispatch-analysts + parallel: [analyst-arch, analyst-security, analyst-reliability] + + - id: debate + model: smart + prompt: | + You are a Devil's Advocate reviewing three independent analyses. + + Architecture findings: {{analyst-arch}} + Security findings: {{analyst-security}} + Reliability findings: {{analyst-reliability}} + + Your job: + 1. Challenge at least HALF of the findings across all three analysts. + For each challenge: quote the finding, explain why it's wrong or overstated. + 2. Identify at least ONE non-code hypothesis (config, infrastructure, environment). + 3. Identify findings that multiple analysts agree on — these are CONFIRMED. + 4. Identify findings only one analyst raised — these need scrutiny. + + Format: + ## Confirmed (2+ analysts agree) + {list with evidence from both} + + ## Challenged + {finding} — {why it's wrong or overstated} + + ## Non-Code Hypotheses + {infrastructure, config, or environment issues} + + ## Revised Findings + {the final curated list after challenges — each with severity, confidence, location} + + - id: rank + model: fast + prompt: | + Produce the final ranked findings from the debate. + + Debate result: {{debate}} + + For each finding in "Revised Findings" and "Confirmed", compute: + priority = severity_weight * 0.4 + confidence_boost * 0.2 + consensus * 0.4 + where: CRITICAL=4, HIGH=3, MEDIUM=2, LOW=1 + HIGH_conf=1.0, MEDIUM_conf=0.6, LOW_conf=0.3 + consensus = analysts_who_agree / 3 + + Output a numbered list sorted by priority descending: + + ## Ranked Findings + + 1. [SEVERITY] [CONFIDENCE] (N/3 consensus) file:location — title + Evidence: ... + Action: ... + + 2. ... + + ## Summary + - Total findings: {count} + - Confirmed (2+ agree): {count} + - Single-analyst: {count} + - Challenged and removed: {count} + + - id: report + model: fast + prompt: | + Produce the final predict report. + + Goal: {{input}} + Ranked findings: {{rank}} + + ## Predict Analysis + + ### Goal + {what was analyzed} + + ### Top Findings + {top 5 from ranked list — one line each with severity and location} + + ### Full Findings + {complete ranked list from rank step} + + ### Analyst Agreement + {where did all three agree vs disagree} + + ### Recommended Next Steps + {prioritized action items — which findings to address first and how} + + ### Caveats + {low-confidence findings, challenged items, anything the devil's advocate flagged} diff --git a/workflows/reason.yml b/workflows/reason.yml new file mode 100644 index 0000000..ff82a6b --- /dev/null +++ b/workflows/reason.yml @@ -0,0 +1,281 @@ +name: Adversarial Reason +description: Generate, critique, counter, synthesize, blind-judge — converge subjective decisions through adversarial refinement + +budget: + limit: 600000 + downgrade: fast + +steps: + - id: setup + model: fast + prompt: | + Parse the user's reason request: {{input}} + + Extract: + - TASK: the question, proposal, or decision to reason about + - DOMAIN: software | product | business | security | research | content + - MODE: convergent (default) | creative | debate + - JUDGES: 3 (default), 5, or 7 — must be odd + - CONVERGENCE: consecutive wins to stop (default 3) + - MAX_ROUNDS: iteration limit (default 8) + + If TASK is missing, use ask_user to get it. + If DOMAIN is unclear, infer from context. + + Output each field on its own line, exactly as labeled above. + + - id: generate-a + model: smart + prompt: | + Config: {{setup}} + Previous round winner (if any): {{tally}} + + You are Author-A. Produce a thorough response to the TASK. + + If there is a previous round winner above (between WINNER_TEXT_START and + WINNER_TEXT_END), BUILD ON IT. Identify its weaknesses and produce a + stronger version. Do NOT reproduce it verbatim. + + If there is no previous winner (first round), this is a cold start. + + Rules: + - No hedging ("perhaps", "maybe", "it depends") unless genuinely uncertain. + - Every claim must have supporting reasoning. + - For design/architecture: specify components, interfaces, tradeoffs. + - For decisions/arguments: state position clearly, then defend it. + + - id: critique + model: smart + prompt: | + You are an adversarial critic. Attack this candidate ruthlessly. + You do NOT know the original task — judge the text on its own merits. + + Candidate: + {{generate-a}} + + Rules: + - Find MINIMUM 3 weaknesses. More is better. + - Each weakness must quote or reference the exact claim you attack. + - Rate each: FATAL (invalidates argument), MAJOR (significant gap), MINOR (improvable). + - Do NOT offer fixes. Only attack. + + Format: + WEAKNESS-1 [FATAL|MAJOR|MINOR]: {claim} — {critique} + WEAKNESS-2 [FATAL|MAJOR|MINOR]: ... + VERDICT: {one line — the weakest point overall} + + - id: generate-b + model: smart + prompt: | + Config: {{setup}} + + You are Author-B. You see a previous attempt and its critique. + Produce a BETTER candidate that addresses the critique weaknesses. + + Previous attempt: + {{generate-a}} + + Critique: + {{critique}} + + Rules: + - Address all FATAL and MAJOR weaknesses. + - Do NOT reproduce the previous attempt verbatim. + - Do NOT reference the critique explicitly — integrate improvements naturally. + - Rethink structure where the critique reveals deeper issues. + + - id: synthesize + model: smart + prompt: | + Config: {{setup}} + + Extract MODE from config. If MODE is "debate", output only: + "SKIPPED: debate mode — no synthesis" + and stop. + + Otherwise: you see two candidates for the same task. Produce a synthesis + that is superior to both by combining their strongest elements. + + Candidate A: + {{generate-a}} + + Candidate B: + {{generate-b}} + + Rules: + - Identify what A does better than B, and vice versa. + - Combine strengths — do NOT average into mediocrity. + - Resolve contradictions by picking the better-supported position. + - The result must read as one coherent response, not a patchwork. + - Do NOT invent claims that neither A nor B supports. + + - id: judge-1 + model: general + prompt: | + Config: {{setup}} + Extract DOMAIN from config. + + You are a blind judge. Evaluate these candidates. + Labels are RANDOMIZED — X/Y/Z do not indicate order or quality. + + Candidate X: + {{generate-b}} + + Candidate Y: + {{synthesize}} + + Candidate Z: + {{generate-a}} + + Evaluation criteria for this DOMAIN: + - software: correctness, feasibility, edge cases, maintainability + - product: user value, feasibility, prioritization, metrics + - business: ROI, risk, stakeholders, actionability + - security: threat coverage, defense-in-depth, attack realism + - research: hypothesis clarity, falsifiability, methodology, novelty + - content: clarity, audience fit, argument strength, accuracy + + Rules: + - You MUST pick a winner. No ties. + - Cite SPECIFIC text from the candidates. + - Longer is not better. Substance wins. + + Output: + WINNER: X | Y | Z + REASONING: {2-4 sentences with specific evidence} + + - id: judge-2 + model: general + prompt: | + Config: {{setup}} + Extract DOMAIN from config. + + You are a blind judge. Labels are RANDOMIZED. + + Candidate X: + {{synthesize}} + + Candidate Y: + {{generate-a}} + + Candidate Z: + {{generate-b}} + + Same evaluation criteria as DOMAIN dictates (see judge-1 prompt for list). + You MUST pick a winner. Cite specific text. No ties. + + Output: + WINNER: X | Y | Z + REASONING: {2-4 sentences} + + - id: judge-3 + model: general + prompt: | + Config: {{setup}} + Extract DOMAIN from config. + + You are a blind judge. Labels are RANDOMIZED. + + Candidate X: + {{generate-a}} + + Candidate Y: + {{generate-b}} + + Candidate Z: + {{synthesize}} + + Same evaluation criteria as DOMAIN dictates (see judge-1 prompt for list). + You MUST pick a winner. Cite specific text. No ties. + + Output: + WINNER: X | Y | Z + REASONING: {2-4 sentences} + + - id: dispatch-judges + parallel: [judge-1, judge-2, judge-3] + + - id: tally + model: fast + prompt: | + Tally the blind judge votes. + + Judge 1 (label map: X=B, Y=AB, Z=A): {{judge-1}} + Judge 2 (label map: X=AB, Y=A, Z=B): {{judge-2}} + Judge 3 (label map: X=A, Y=B, Z=AB): {{judge-3}} + + For each judge: + 1. Extract their WINNER label (X, Y, or Z). + 2. Decode it to the real candidate (A, B, or AB) using the label map above. + 3. Tally votes per candidate. + + Output exactly: + VOTES_A: + VOTES_B: + VOTES_AB: + ROUND_WINNER: (plurality wins; ties go to A as incumbent) + + Then output the full text of the winning candidate — copy it from: + - If A won: {{generate-a}} + - If B won: {{generate-b}} + - If AB won: {{synthesize}} + + Prefix the winner text with: WINNER_TEXT_START + Suffix with: WINNER_TEXT_END + + - id: converge + model: fast + prompt: | + Config: {{setup}} + Tally: {{tally}} + + Extract ROUND_WINNER from tally. + + This step loops. The loop max (from the loop config below) enforces + MAX_ROUNDS. You do not need to count rounds. + + Output exactly one of: + - "NEXT_ROUND" to continue refining + - "REASON_COMPLETE" to stop (only if MODE is not "creative" and + you see the same ROUND_WINNER as the previous round in the + conversation — but prefer NEXT_ROUND when uncertain) + loop: + max: 8 + until: REASON_COMPLETE + branch: + - when: "REASON_COMPLETE" + goto: report + - when: "NEXT_ROUND" + goto: generate-a + + - id: report + model: smart + prompt: | + The adversarial reason loop is complete. + + Config: {{setup}} + Final tally (contains winning text and vote breakdown): {{tally}} + Critique of initial candidate: {{critique}} + + Write the final report: + + ## Adversarial Reason: {TASK from config} + + ### Winner + {which candidate won (A, B, or AB) and vote margin from tally} + + ### Winning Response + {full text between WINNER_TEXT_START and WINNER_TEXT_END from tally} + + ### How It Evolved + - Initial weaknesses identified by critique + - How they were addressed (or not) in the winning candidate + + ### Judge Consensus + {vote breakdown from tally: VOTES_A, VOTES_B, VOTES_AB} + + ### Unresolved Tensions + {any FATAL weaknesses from critique that the winner still exhibits} + + ### Confidence + {3-0 unanimous = high, 2-1 = moderate}