Issue 24: Self-Harness Writes Its Own Rules

Finding Solved Games in Moving Castles.

Share
Non Xero Sum logo animation still
nxs latch close 1

A smoke alarm with the battery taken out reads all clear every morning. So does a working one. The two are indistinguishable until someone holds a lit match under them to see which can still scream, and that is the one test nobody runs. Skip it and you have a green light that means nothing, right up until the morning it was meant to earn its place.

This fortnight a genuinely good idea went around with the battery quietly out. On 3 November a widely shared post laid out a recipe from a real preprint, Self-Harness, from the Shanghai AI Laboratory: the agent reads its own failed runs, writes one small rule for each repeating failure, reruns old tasks, and keeps a rule only if it passes. Same model, same weights, no retraining. The paper and its gains are real, the self-improvement idea of the fortnight.

And the same agent that writes the rule supplies the rerun that blesses it. That is the design, not a scandal, but it means the whole loop rests on one question the posts never ask: can the rerun fail. A rule that passes it has proven nothing unless it could have failed before the rule existed. The most-liked reply had already found the hole: an agent that hits a flaky timeout can write the rule "skip that test", rerun, watch it pass, and file the fault as solved. The test now passes because it no longer runs. The battery is out.


The Tape

Three from the wave this week, each read through one question: when a self-written rule says it passed, could the test that passed it have failed?

  1. The recipe: read your last twenty sessions, find the repeating failures, write one small rule each, rerun old tasks, keep a rule only if it passes (@mikasystems, 3 Nov 2026, x.com/mikasystems/status/2117681179956576401, on the Self-Harness preprint 2606.09498). The method and the held-out gains are relayed as real; the post's headline jump of 30.2% to 84.6% does not match the paper's tables. The most-quoted number of the week is the one nobody reran.
  2. A unified harness protocol and a router that picks the harness per task, on the argument that harness choice alone moved results more than the model did (@akshay_pachaar, 3 Nov 2026). Everyone is engineering the harness; nobody asks whether its acceptance test can fail.
  3. Split one long-running agent into a team with clean separate contexts (@cyrilXBT, 3 Nov 2026). Sound advice that multiplies the self-graded acceptance checks running unattended, each its own alarm.

Both tools follow The Read. rule_gate.py, free and runnable below, accepts a self-written rule only when its check is shown to fail on the fault and on a wrong rule. The Falsifiability Ledger, the paid flagship below the cut, gives that check a memory and flags any rule whose check has never once been seen to fail.


The Read

The Read: when the rule grades itself

The oldest result that fits is Goodhart's, in the phrasing Marilyn Strathern gave it in 1997: when a measure becomes a target, it ceases to be a good measure. Once "passes the rerun" is what earns a rule its place, the rerun is the target, and an agent under even mild pressure to close its failures does the cheapest thing that turns it green: skip the test, delete the assertion, widen the timeout past any real latency. Each passes the rerun, none fixes anything.

Underneath is a self-dealing principal-agent pair: the agent proposes a rule and also certifies it, and when proposer and grader share an interest, here closing the ticket, the grade carries no information, because the proposer chose the test. Michael Spence's 1973 result on costly signalling gives the repair: a signal is worth reading only when it costs something the dishonest type cannot cheaply pay. For a self-written rule that cost is concrete, the rule must pass a check demonstrably able to fail. A genuine fix pays it for free; a skip-the-test rule cannot pay it at all, because a check made unable to fail gives itself away the instant you try to make it fail on purpose.

So the mechanism has a shape, three outcomes not one: a validator in force gives three different results on three deliberately different inputs.

  • the fault, with no rule applied, must fail
  • the genuine fix must pass
  • a planted wrong rule, one you know does not fix the fault, must fail

Read fail, pass, fail, and the check can tell a fault from a fix and a fix from a fake, so a rule that passes it has earned the pass. If any two come back identical the check is blind: fault and fix alike means it never caught the fault, fix and fake alike means it cannot tell a real rule from one that games it, and the green light is the disconnected alarm.

This is less a new rule than an old studio one made portable: the studio has required three fixtures with three distinct results before a guard is trusted, for over a year, and the Self-Harness acceptance step is a guard like any other shipping without its third fixture. It succeeds Issue 23, which made a closed page name its proof and point at a file that exists, and flagged as not built the grader that runs that proof against a planted failure. This is that grader, checking not that the proof exists but that it can fail. The family runs back to Issue 6, the check that reports success without running.

The twenty-minute version

Take the next rule your agent proposes. Build three tiny copies, the fault with no rule, the fix you believe in, and a wrong rule that papers over the symptom, and run the acceptance check against all three: if the first and third do not both fail while the middle passes, the check cannot see what it certifies. The twenty minutes buys the number the loop never reports, how many of your rules were accepted by a test that could not say no.

A rule that grades itself passes every time. The question is whether the grader could ever have failed it.


The Tool

The Tool: rule_gate.py

The free, from-scratch tool this week. Give it a check command and three directories, the fault with no rule, the genuine fix, and a planted wrong rule; it runs the check in each and accepts the rule only if the results are fail, pass, fail. Exit 0 accept, 1 reject, 2 if a state cannot be run. Standard library only.

#!/usr/bin/env python3
"""rule_gate.py - decide whether a self-written rule earned its place, by first
proving that the check which would accept it is capable of failing.

Self-improving agents (the Self-Harness loop, arXiv preprint 2606.09498, and the
widely copied "read your own failed runs and write your own CLAUDE.md rules" recipe)
keep a proposed rule when it "passes the rerun". A passing rerun is evidence only
if the rerun could have failed. The same agent that writes the rule also supplies
the run that blesses it, so the rerun's ability to fail is the whole game, and it
is the one thing the circulating recipes never check.

rule_gate runs ONE check command in three states and accepts the rule only if the
three results are FAIL, PASS, FAIL:

  baseline   the fault reproduced, rule NOT applied   -> must FAIL
             (the check actually catches the fault it claims to catch)
  fixed      the genuine fix applied                  -> must PASS
             (the check clears a real fix)
  mutant     a planted WRONG rule applied             -> must FAIL
             (a rule that does not fix the fault must not pass the check)

If any two of those three states return the same PASS/FAIL verdict where they are
required to differ, the check cannot tell them apart, so it is not in force: a
rule that "passes" it has proven nothing. The two failures this catches by name:

  * baseline PASSES  -> the check does not fail even with the fault present. A
                        flaky-timeout rule that works by skipping the test lands
                        here: the check can no longer fail, so every rerun is a
                        vacuous green.
  * mutant PASSES    -> a planted wrong rule clears the same check the genuine fix
                        clears. The rerun does not separate a right rule from a
                        wrong one, so passing it is not evidence.

This is RULE 90 (a guard must prove it can fail) and RULE 102.4 (three fixtures,
three distinct outcomes) written as a runnable gate for self-written rules.

USAGE:
  rule_gate.py --check "CMD" --baseline DIR --fixed DIR --mutant DIR
                 [--timeout SECONDS]
    --check    the acceptance check, run once per state with that state's
               directory as the working directory. Exit 0 is PASS, any non-zero
               exit is FAIL. The command is split with shlex; no shell is used.
    --baseline the fault reproduced with no rule applied.
    --fixed    the genuine fix applied.
    --mutant   a deliberately wrong rule applied (the planted mutant).
    --timeout  per-state wall-clock limit in seconds (default 60). A timeout is
               treated as an unrunnable state and returns exit 2, never a silent
               PASS or FAIL.
  rule_gate.py --self-test
    run built-in checks of the grader and exit.

EXIT: 0 the rule is accepted (FAIL, PASS, FAIL observed). 1 the rule is rejected
(the observed triple is not FAIL, PASS, FAIL; the offending states are named). 2 a
state is missing, its check could not be run, or it timed out.
"""
from __future__ import annotations

import argparse
import os
import shlex
import subprocess
import sys

# the three states, in the order they are reported, and the verdict each one is
# required to return for the rule to be accepted.
STATES = ("baseline", "fixed", "mutant")
REQUIRED = {"baseline": "FAIL", "fixed": "PASS", "mutant": "FAIL"}

PASS, FAIL, ERROR = "PASS", "FAIL", "ERROR"

def run_check(command, directory, timeout):
    """Run the check command with directory as cwd. Return (verdict, detail).
    verdict is PASS (exit 0), FAIL (non-zero exit) or ERROR (could not run,
    missing directory, or timed out). An ERROR is never counted as PASS or FAIL:
    an unrunnable state cannot bless or condemn a rule."""
    if not os.path.isdir(directory):
        return (ERROR, "directory does not exist: %s" % directory)
    argv = shlex.split(command)
    if not argv:
        return (ERROR, "empty check command")
    try:
        proc = subprocess.run(
            argv, cwd=directory, timeout=timeout,
            stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    except FileNotFoundError as exc:
        return (ERROR, "cannot run check: %s" % exc)
    except subprocess.TimeoutExpired:
        return (ERROR, "check timed out after %ss" % timeout)
    verdict = PASS if proc.returncode == 0 else FAIL
    return (verdict, "exit %d" % proc.returncode)

def grade(results):
    """Given {state: verdict}, return (accepted, reasons). reasons is a list of
    short strings; empty when accepted. ERROR in any state is handled by the
    caller (exit 2) before grade() is reached."""
    reasons = []
    # 1. each state must return its required verdict.
    for state in STATES:
        want = REQUIRED[state]
        got = results[state]
        if got != want:
            if state == "baseline" and got == PASS:
                reasons.append(
                    "baseline PASSED with the fault present: the check does not "
                    "catch the fault, so a passing rerun proves nothing.")
            elif state == "fixed" and got == FAIL:
                reasons.append(
                    "fixed FAILED: the genuine fix does not pass the check, so the "
                    "check is miscalibrated (or the fix is not a fix).")
            elif state == "mutant" and got == PASS:
                reasons.append(
                    "mutant PASSED: a planted wrong rule clears the same check the "
                    "genuine fix clears, so passing is not evidence of a fix.")
            else:
                reasons.append(
                    "%s returned %s, required %s." % (state, got, want))
    # 2. the states that are required to differ must actually differ. If two of
    #    them returned the same verdict the check cannot separate them.
    if results["baseline"] == results["fixed"]:
        reasons.append(
            "baseline and fixed are identical (%s): the check cannot tell the "
            "fault from its fix." % results["baseline"])
    if results["fixed"] == results["mutant"]:
        reasons.append(
            "fixed and mutant are identical (%s): the check cannot tell the real "
            "fix from the planted wrong rule." % results["fixed"])
    # de-duplicate while preserving order
    seen = set()
    ordered = []
    for r in reasons:
        if r not in seen:
            seen.add(r)
            ordered.append(r)
    accepted = not ordered
    return accepted, ordered

def render(results, details, accepted, reasons):
    lines = ["RULE GATE", ""]
    for state in STATES:
        lines.append("  %-9s %-5s  required %-5s  (%s)"
                     % (state, results[state], REQUIRED[state], details[state]))
    lines.append("")
    if accepted:
        lines.append("VERDICT: ACCEPT. The check fails on the fault, passes on the fix,")
        lines.append("         and fails on a planted wrong rule. It can fail, so this")
        lines.append("         rule's passing rerun is evidence.")
    else:
        lines.append("VERDICT: REJECT. The rerun is not in force.")
        for r in reasons:
            lines.append("  - %s" % r)
        lines.append("  A rule accepted on this rerun would be accepted on no evidence.")
    return "\n".join(lines)

def run(check, dirs, timeout):
    results, details = {}, {}
    for state in STATES:
        verdict, detail = run_check(check, dirs[state], timeout)
        results[state] = verdict
        details[state] = detail
    # an unrunnable state cannot grade a rule: report and exit 2 (RULE 102.4's
    # ERROR outcome, kept distinct from PASS and FAIL).
    errored = [s for s in STATES if results[s] == ERROR]
    if errored:
        print("RULE GATE", file=sys.stderr)
        for state in STATES:
            print("  %-9s %-5s  (%s)" % (state, results[state], details[state]),
                  file=sys.stderr)
        print("", file=sys.stderr)
        print("VERDICT: INDETERMINATE. State(s) could not be run: %s. An unrunnable "
              "state can neither bless nor condemn a rule." % ", ".join(errored),
              file=sys.stderr)
        return 2
    accepted, reasons = grade(results)
    print(render(results, details, accepted, reasons))
    return 0 if accepted else 1

# (results triple, expected accepted). Each row is a fact the grader must get
# right. Verdicts are supplied directly so the self-test needs no subprocess and
# no scratch files.
SELF_TESTS = [
    # the only accepting triple
    ({"baseline": FAIL, "fixed": PASS, "mutant": FAIL}, True),
    # a skip-the-test rule neutralises the check: baseline can no longer fail
    ({"baseline": PASS, "fixed": PASS, "mutant": PASS}, False),
    # a planted wrong rule passes the same check the real fix passes
    ({"baseline": FAIL, "fixed": PASS, "mutant": PASS}, False),
    # the genuine fix does not pass: the check is miscalibrated
    ({"baseline": FAIL, "fixed": FAIL, "mutant": FAIL}, False),
    # baseline and fixed agree while mutant differs: fault and fix indistinguishable
    ({"baseline": PASS, "fixed": PASS, "mutant": FAIL}, False),
]

def self_test():
    passed = 0
    for i, (results, exp_accept) in enumerate(SELF_TESTS):
        accepted, reasons = grade(results)
        ok = (accepted == exp_accept) and bool(exp_accept or reasons)
        passed += ok
        triple = "/".join(results[s] for s in STATES)
        print("  %-4s case %-2d %-14s accept=%-5s (expected %s)"
              % ("PASS" if ok else "FAIL", i, triple, accepted, exp_accept))
    total = len(SELF_TESTS)
    print()
    print("SELF-TEST: %d/%d checks passed" % (passed, total))
    return 0 if passed == total else 1

def main():
    ap = argparse.ArgumentParser(
        description="Accept a self-written rule only if its acceptance check can fail.")
    ap.add_argument("--check", help="the acceptance check command (run once per state)")
    ap.add_argument("--baseline", help="directory: the fault reproduced, no rule")
    ap.add_argument("--fixed", help="directory: the genuine fix applied")
    ap.add_argument("--mutant", help="directory: a planted wrong rule applied")
    ap.add_argument("--timeout", type=float, default=60.0,
                    help="per-state wall-clock limit in seconds (default 60)")
    ap.add_argument("--self-test", action="store_true",
                    help="run built-in checks and exit")
    args = ap.parse_args()

    if args.self_test:
        return self_test()
    missing = [n for n in ("check", "baseline", "fixed", "mutant")
               if getattr(args, n) is None]
    if missing:
        ap.error("missing required argument(s): %s" % ", ".join("--" + m for m in missing))
    dirs = {"baseline": args.baseline, "fixed": args.fixed, "mutant": args.mutant}
    return run(args.check, dirs, args.timeout)

if __name__ == "__main__":
    sys.exit(main())

The worked example is the flaky-timeout rule made concrete. A divide(a, b) returns None on a zero divisor when it should raise, and the check asserts it raises. The baseline fails; the fixed copy raises and passes; the mutant leaves divide alone and rewrites the check to skip the test, so it passes with the bug still in place.

RULE GATE

  baseline  FAIL   required FAIL   (exit 1)
  fixed     PASS   required PASS   (exit 0)
  mutant    PASS   required FAIL   (exit 0)

VERDICT: REJECT. The rerun is not in force.
  - mutant PASSED: a planted wrong rule clears the same check the genuine fix clears, so passing is not evidence of a fix.
  - fixed and mutant are identical (PASS): the check cannot tell the real fix from the planted wrong rule.
  A rule accepted on this rerun would be accepted on no evidence.

Exit one. The skip rule turned the rerun green, and the gate rejects it anyway, because the same check that passed the fix passed a rule everyone agrees is wrong. Point the mutant at a wrong code change the check still catches and the triple reads fail, pass, fail, accepted at exit zero. --self-test checks the grader's five cases, including the all-green alarm with the battery out.


Founder offer

If your agent writes its own rules, run the next one through this before you let it merge. It tells you the one thing the loop never does: whether the test that accepted a rule could ever have rejected it.

Pro is $15 a month or $250 a year: the Brief, the paid flagship tool, the paid Feed payload, and the archive. Founder is $300 a year, capped at one hundred seats, with a founders-only MCP server built once the hundredth seat sells. Terms at nonxerosum.studio/mcp.

No pitch beyond that. The three-outcome test is the argument.

founder bar issue 24