本文へ移動
cccskills
無料GitHub で公開

verify-repair-loop

Use to iterate a change until tests/quality checks pass — bounded run→revise→re-run gated by a numeric threshold, then a judge confirms. Triggers 'iterate to green', 'keep fixing until tests pass'.

インストール方法を見る

含まれるファイル(3)

  • SKILL.md15.4 KB
  • evals/output-schema.yml667 B
  • evals/triggers.json1.7 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

verify-repair-loop

A bounded generate → run → revise → re-run cycle whose pass signal is the executed verdict — the project's real test/quality output, scored against a numeric threshold — escalated to a judge for qualitative confirmation only after the numeric gate passes (staged escalation). The loop is the conversation, not a process: this loop introduces no resident process of its own and no persistent cross-session state. Use it to drive a change to green when the verdict source is runtime execution, not a judge reading a diff.

When to use

  • A change must converge against the project's test runner / quality tools and you want the agent to iterate until checks pass before asking for review.
  • Test/quality coverage is the authoritative signal (high coverage, actionable failures) — not subjective craft.
  • You want bounded auto-repair with a hard stop, not an open-ended fix loop.

Do NOT use when:

  • The verdict is subjective craft (naming, architecture, style) or coverage is incomplete → use do-and-judge in subagent-orchestration (judge reads the diff and is sovereign).
  • You only need a one-shot multi-judge review of a finished diff → use /review-changes.
  • The verdict must come from a live app (Playwright against running services) → deferred (see Scope below); use test/quality verdicts until that trigger fires.

The Iron Law

THE NUMERIC VERDICT IS NEVER SOVEREIGN.
TESTS DECIDE WHEN TO ESCALATE — A JUDGE DECIDES WHETHER TO APPLY.
A REVISION THAT BREAKS A PREVIOUSLY-GREEN CHECK STOPS THE LOOP,
EVEN IF THE OVERALL SCORE ROSE.
GENERATOR NEVER APPROVES ITS OWN CHANGE.

A loop that optimizes for pass_count ≥ N can game the metric — delete tests, skip assertions, weaken checks — and still hit the threshold. The numeric gate only decides when to escalate; a judge with veto confirms the change is real.

Procedure

1. Freeze the contract (spec fingerprint)

Before the first run, capture what "done" means and snapshot it:

  • the task's acceptance criteria / requirement,
  • the set of checks that define the verdict (test files + quality commands),
  • a spec fingerprint = a hash of (requirement text + the check set).

Record the baseline green set — which checks pass before any edit — so regressions are detectable. Pick the verdict commands per the project's toolchain-resolver (PHP / JS-TS / Python / Go / Rust), not a hardcoded runner.

2. Set the gate

KnobDefaultMeaning
thresholdall targeted checks greennumeric pass bar, absolute (fraction of total), not "± N tests"
allow_regressionsfalsea revision breaking a baseline-green check stops the loop
max_attempts3hard cap, this loop's own number (test feedback is more actionable than diff critique → one more than do-and-judge's 2); independent of autonomous-execution's execution.fix_loop_max budget, which now defaults to 10
plateau_window3stop if the last window scores sit within tolerance
tolerancesmall absolute fractionflake jitter that does not count as improvement

3. The loop (multi-turn — the conversation IS the loop)

Each iteration is agent turns, never executing control-flow code:

  1. Read the failure, then revise — before changing a line, inspect what the previous run actually reported: which checks failed, the assertion text, and whether this failure signature matches the last one. Analyze the existing code path the failing check exercises rather than pattern-matching the error string. A revision written without reading the failure is the blind retry both the plateau rule below and autonomous-execution exist to stop — and on attempt 1 there is no previous run, so this is the baseline green set from step 1. Then make the smallest change toward the contract.

  2. Run — execute the verdict commands; parse the structured result (counts green/total, which checks failed). This is one tool call, read in context.

  3. Score + regression check — compute the numeric score; compare failures against the baseline green set.

    • Regression (a baseline-green check now fails) → STOP, hand back with the regression named, even if the score rose. No whack-a-mole.
    • Plateau (last plateau_window scores within tolerance) → STOP; surface suspected flakiness or a stuck point. Do not thrash.
    • attempts == max_attempts → STOP, hand back the best envelope.
  4. Tamper check (deterministic, loop-local) — before the numeric gate is allowed to say anything, run the detector over the diff this attempt produced and over the recorded verdict:

    ./scripts-run src/scripts/detect_verification_tampering \
        --diff <this attempt's diff> --message <this attempt's message> \
        --verdict <the runner's recorded verdict>
    

    It is fail-closed inside the loop: outcome violations or stale_verdict STOPS the loop and hands back with the finding's file:line, whatever the score says. clean changes nothing — an ordinary passing attempt is unaffected, because the detector reports only on shapes the diff introduced.

    The check answers exactly the gap the Iron Law names: assertion-removed, assertion-weakened, verification-skipped (warn), expectation-rewritten, early-exit-injected, test-file-deleted, subject-mocked-away, and stale_verdict for a runner that finished before the last edit. A change that legitimately deletes an obsolete test or relaxes an over-tight assertion declares it in the attempt's message — tamper-allow: <detector-id> — <reason> — scoped to one id, never to all.

    It is not a CI gate and does not become one here. The tree's measured lesson is that reach, not content, is the scarce thing; a new always-on gate is the opposite of that lesson. Promotion owes a measured false-positive rate first.

  5. Numeric gate — score < threshold and attempts remain → back to step 1 (attempts++). Score ≥ threshold, no regression, tamper check clean → escalate (step 4 of the stage).

4. Judge escalation (only after the numeric gate passes)

Dispatch the judge as a subagent with fresh context (the judge-* cluster via subagent-orchestration) that sees only the diff + the executed results — never the generator's reasoning. This is the real generator ≠ judge separation; single-agent persona-switching is theater.

  • judge apply → DONE.
  • judge revise → back to step 3.1 (attempts++; still bounded).
  • judge reject → STOP, hand back; the approach must change.

5. Mid-loop invalidation (user-interrupt-priority)

Re-check the spec fingerprint each iteration. If the user changes the requirement mid-loop (a new instruction in the conversation), the fingerprint changes → abort and hand back per user-interrupt-priority. Never keep iterating against a stale contract.

Scope — what runs, what is deferred

Verify contextIn scopeWhy
Unit / integration tests✅fast, deterministic, sandboxed — runtime-free
Static quality (lint, type-check, format)✅fast, deterministic, no side effects (auto-fixable failures may bypass the revise step)
Live-app Playwright / E2E⛔ deferredneeds running services (DB, API) = a runtime; trigger = a UI-observable mission output + Playwright wired into a consumer CI

State lives in the conversation, optionally mirrored to a re-read working file — never a daemon or persistent cross-session store (honors resident-process-governance).

Validation

Before finalizing, confirm:

  1. The numeric gate escalated to a judge — it did not apply on its own.
  2. No baseline-green check regressed (or the loop stopped and said so).
  3. The tamper check ran on the final attempt and returned clean — or the loop stopped on its finding. A green verdict recorded over a violations or stale_verdict outcome is not a green verdict.
  4. The loop stopped at max_attempts, a plateau, or a judge apply — never ran unbounded.
  5. The judge saw only the diff + results, dispatched in fresh context.
  6. No unsupervised resident process introduced — and none of the four governance conditions in resident-process-governance.md left unmet if a supervised one is. (Amended 2026-08-27, ADR-249: this read "No daemon / persistent runtime introduced" when a daemon was prohibited outright. The check still fires; what it tests moved from existence to governance.)

Output format

verify-repair-loop
Contract:   <one-line requirement> · threshold <X> · allow_regressions false
Attempts:   <k>/<max>  scores: [s1, s2, …]   stop: threshold|plateau|cap|regression|reject
Verdict:    DONE | DONE_WITH_CONCERNS | BLOCKED
run_terminal: success | blocked | exhausted | stagnated
Judge:      <judge skill> → apply|revise|reject
Evidence:   <green/total> · regressions: none | <named checks>

Required fields (ordered):

  1. Contract — the frozen requirement + threshold + allow_regressions.

  2. Attempts — k/max, the score history, and the exact stop reason (threshold / plateau / cap / regression / reject).

  3. Verdict — DONE, DONE_WITH_CONCERNS, or BLOCKED.

  4. run_terminal — this loop's stop in the vocabulary every other loop in this tree reports in. The verdict above is local to this skill; this field is the one a reader can aggregate across the continuation hook, the self-fix lanes and this loop without a per-surface translation table.

    stop reasonrun_terminalwhy
    threshold (judge apply)successthe contract is met
    capexhaustedthe attempt budget ran out — a bigger budget might help
    plateaustagnatedscores stopped moving — a bigger budget will not help
    regressionblockeda baseline-green check broke; the loop must not proceed
    rejectblockedthe judge refused the work

    The value set is RunTerminalState, whose members are success, clean-no-op, blocked, approval-required, exhausted, stagnated and premise-invalidated. It is declared once, at src/scripts/_lib/outcome_vocabularies.ts (RUN_TERMINAL_STATES), and described in terminal-states. Never emit a value outside that set: a sixth stop reason maps onto an existing member or it is not a terminal state.

    exhausted and stagnated are deliberately distinct. Both mean "stopped without a green", and they call for opposite responses — raise the budget against the first, change approach against the second. Collapsing them loses the only part of the stop a reader can act on.

  5. Judge — the dispatched judge skill and its apply / revise / reject verdict (omit only when the loop stopped before escalation).

  6. Evidence — final green/total and any regressed checks by name.

Examples

Good — staged, bounded, judge confirms:

iter1 84/100 (<90) → revise
iter2 93/100 (≥90, no regression) → escalate → judge apply → DONE

Bad — numeric verdict treated as sovereign (rejected by the Iron Law):

iter1 91/100 ≥ threshold → "PASS, done"   ✗ no judge escalation; metric may be gamed
iter2 fixes A, breaks B, 92% → "PASS"      ✗ regression ignored

Gotcha

  • Metric gaming — the agent "passes" by deleting a failing test or weakening an assertion. The numeric gate still cannot catch this, and that is why loop step 3.4 exists: detect_verification_tampering decides the mechanical shapes deterministically, and the fresh-context judge remains the safeguard for everything shape cannot decide. If the diff removes checks, that is a reject, not a pass.
  • Phantom verification — the loop records a green verdict it never re-ran, so the exit code describes a tree that no longer exists. The verdict carries the runner's own timestamp; one that predates the last edit is stale_verdict, its own outcome, never a pass.
  • Flake mistaken for a plateau — a single non-deterministic test flips the score and the window-comparison reads it as "no improvement". Re-run the suspected check before declaring a plateau; surface flakiness instead of thrashing.
  • Score rose, but a regression hid inside it — fixing 6 checks while breaking 2 still raises the total. Without the regression guard the loop ships a regression. Always diff failures against the baseline green set, not just the aggregate score.
  • Persona-switch theater — asking the same agent to "now judge what you wrote" is not separation. Dispatch the judge as a fresh-context subagent that never saw the generator's reasoning.
  • Stale contract — iterating against a requirement the user changed mid-loop. Re-check the spec fingerprint each turn; a change aborts.

Do NOT

  • NEVER let the numeric score apply a change without judge confirmation.
  • NEVER record a green verdict over a tamper finding or a stale runner timestamp — inside the loop the detector is fail-closed.
  • NEVER widen a tamper-allow declaration past the one id it names.
  • NEVER continue past a regression because the overall score improved.
  • NEVER run the live-app Playwright path here — it is deferred (needs a runtime).
  • NEVER judge with the generator's own context — dispatch a fresh-context judge.
  • NEVER loop past max_attempts or a detected plateau.

See also

  • subagent-orchestration — do-and-judge (judge-sovereign, diff-read) is the sibling; this skill is test-verdict-gated.
  • /review-changes — one-shot multi-judge review; wires this loop as an opt-in step.
  • playwright-testing, quality-tools — verdict sources.
  • src/scripts/detect_verification_tampering.ts — the loop-local tamper and phantom-verification check bound at step 3.4, with its fixture corpus in tests/fixtures/tamper-corpus/ and its polarity proven both ways by --self-test.
  • autonomous-execution — the execution.fix_loop_max cap (this loop's own max_attempts is a separate, smaller number).
  • resident-process-governance — the runtime-free constraint this loop honors.
  • Optional impact pre-step (when a code-graph is present, ADR-124): run agent-config code-graph affected --since <ref> to scope which symbols a change touches before choosing verdict sources — cited, not duplicated; the loop itself is unchanged when no graph exists.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use when reviewing UI for accessibility — WCAG 2.2 AA, keyboard nav, focus, ARIA, contrast, screen-reader semantics — even on 'is this a11y-OK?' or 'mach das barrierefrei'.

日本語の概要は準備中です。原文の説明を表示しています。

event4u-app/agent-config112026年10月12日 更新

Use when defining or auditing the activation event — aha-moment selection, retention correlation, falsifiable definition. Triggers on 'what is our aha moment', 'redefine activation'.

日本語の概要は準備中です。原文の説明を表示しています。

event4u-app/agent-config112026年10月12日 更新

Use when capturing an architectural decision — file naming, next ADR number, Status / Context / Decision / Consequences, index regen; fires even without saying 'ADR'.

日本語の概要は準備中です。原文の説明を表示しています。

event4u-app/agent-config112026年10月12日 更新

Adversarial critique — devil's advocate, stress-test, honest teardown ('poke holes', 'be brutal', 'was hältst du davon'); explicit request only. Routine code or design review → code-review.

日本語の概要は準備中です。原文の説明を表示しています。

event4u-app/agent-config112026年10月12日 更新

Use when reading, creating, or updating agent documentation, module docs, roadmaps, or AGENTS.md. Understands the full .augment/, agents/, and copilot-instructions structure.

日本語の概要は準備中です。原文の説明を表示しています。

event4u-app/agent-config112026年10月12日 更新

Use for an adversarial red-team / blue-team / auditor review of an AI agent's CONFIG + behaviour (rules, skills, MCP, hooks, permissions) — attack-chain → defensive-gap list, not a code audit.

日本語の概要は準備中です。原文の説明を表示しています。

event4u-app/agent-config112026年10月12日 更新

event4u-app のスキルをすべて見る

このスキルの問題を報告する