vestige/benchmarks/silent-rotation/harness/agent/fleet_runner.py
Sam Valladares 9bdb9a5668 benchmarks: add Silent Rotation, a fleet-convergence memory benchmark
Three agents fix one failing test concurrently. The fix needs a signing key id
that is randomized per trial from a 50-key keyring and appears in no file the
agents can read. It exists only in the memory layer. Seven arms: a no-memory
control, dense cosine RAG, Vestige, mem0, supermemory, hindsight, Zep/Graphiti.

The measured result is about the first retrieval, not the final score. Across
5 models and 22 trials, a query-based arm's FIRST memory call surfaced the
correct key 6 times out of 87. Vestige, which takes no query argument, did it
56 out of 56. Every downstream number follows from that.

Ships the raw evidence rather than a summary: all agent transcripts, the
harness, and tests/bm25_baseline.py, which reproduces the ranking table offline
with no API key. Two arms were contaminated by a flush bug in this harness that
served them a previous trial's facts; both were fixed and re-run, and the
contaminated cells are withheld rather than published.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 21:24:03 +07:00

1707 lines
79 KiB
Python
Executable file

#!/usr/bin/env python3
"""Real, measured MULTI-AGENT fleet harness (anarchy vs synaptic-hub-sync).
This is the multi-agent counterpart to runner.py. It runs a FLEET of N real
coding-agent loops against the SAME torture-v2 bug and measures what happens
when they work WITHOUT a shared memory (anarchy) versus WITH Vestige as a
shared coordination bus (sync).
Nothing here is scripted to fail or scripted to win. Each agent is a real tool
loop calling a real model (Claude or GPT-5.6 Sol) and we sum the ACTUAL tokens
the API reports. The anarchy failure and the sync success are both EMERGENT:
they fall out of the torture-v2 bug being *direction-ambiguous*, not out of any
hardcoded outcome. When a required key is missing we ERROR (never fabricate).
------------------------------------------------------------------------------
WHY THE FLEET SPLITS (the honest mechanism)
------------------------------------------------------------------------------
torture-v2's bug is a CANONICAL-DIGEST FIELD-ORDER DRIFT:
identity-service/src/canonical.ts signs over [sub, plan, exp, iat]
ledger-service/src/canonical.ts verifies over [sub, plan, iat, exp]
Both files are internally valid and self-consistent. NEITHER states which order
is authoritative. So an agent that only reads the code sees TWO equally-plausible
fixes:
(A) reorder LEDGER to match identity -> correct: identity is the issuer and
every already-minted production token
is signed its way; the verifier adapts.
(B) reorder IDENTITY to match ledger -> WRONG: it makes THIS test pass but
invalidates every token already in
the wild (the direction only memory
can disambiguate).
* ANARCHY (no shared memory): each of the N agents works in its OWN isolated
checkout and independently guesses a direction. Some pick (A), some pick (B).
Each isolated checkout may even go green on its own. Then we INTEGRATE their
edits into one shared tree with a real 3-way merge. Divergent directions do
NOT compose: two agents editing the same canonical.ts differently, or editing
OPPOSITE files, is a genuine textual conflict. The integrated repo fails.
That is the emergent anarchy: N smart agents, no shared source of truth, work
that collides.
* SYNC (Vestige shared bus): the N agents share ONE Vestige DB seeded with the
project history. Before editing, each agent calls vestige_backfill / recall,
reaches back to the 4-day-old identity-service canonical-order decision via the
canonical_digest join, and learns the DIRECTION: identity is source of truth,
ledger must adapt. They converge on the SAME fix (A). The merge is clean. The
integrated repo goes green. Vestige did not write the code; it removed the
ambiguity that made the fleet diverge.
------------------------------------------------------------------------------
This module reuses runner.py's real tool implementations and provider adapters
verbatim (same measured token accounting, same ground-truth test verification),
so the per-agent loop is identical to the audited single-agent harness -- only
the fan-out, the shared bus, and the integration merge are new.
"""
from __future__ import annotations
import argparse
import json
import os
import shutil
import subprocess
import sys
import tempfile
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path
# Reuse the audited single-agent building blocks verbatim. runner.py lives next
# to this file; import its real tools, provider adapters, and helpers so the
# per-agent loop is byte-identical to the single-agent harness.
sys.path.insert(0, str(Path(__file__).resolve().parent))
import runner # noqa: E402 (local module)
# --- Fleet configuration (env-driven, documented in README) -----------------
# The canonical set of valid fleet modes -- referenced by BOTH the run_fleet
# guard and the argparse choices so a new arm is added in exactly ONE place.
# anarchy/rag/sync are the originals; mem0 is the mem0ai competitor arm. Add
# zep/hindsight/supermemory here as each arm's service is stood up + verified.
FLEET_MODES = ("anarchy", "rag", "sync", "mem0", "supermemory", "hindsight", "zep")
# Every arm's memory-retrieval tool, in one place. Used for arm-agnostic
# retrieval telemetry so a dead competitor backend can never again be scored as
# a substantive retrieval loss. anarchy has no entry by design (it is the
# no-memory control).
MEMORY_TOOL_NAMES = (
"vestige_backfill", # sync (Vestige)
"rag_search", # rag
"mem0_search", # mem0
"supermemory_search", # supermemory
"hindsight_search", # hindsight
"zep_search", # zep
)
def _classify_retrieval(output: str) -> tuple[str, str]:
"""Classify one memory-tool result as error / empty_store / no_match / ok.
Three states, not two. An earlier version of this only checked whether the
output started with "ERROR", which silently counted SIX different
failure/empty strings as successful retrievals -- reintroducing the exact
bug this telemetry exists to prevent (a dead arm looking alive). The strings
are, in runner.py:
"(RAG index empty -- no memories to retrieve.)"
"(mem0 index empty -- no memories to retrieve.)"
"(Hindsight index empty -- no memories to retrieve.)"
"(supermemory returned no matching memories.)"
"(Hindsight returned no matching memories.)"
"(Graphiti knowledge graph returned no matching facts.)"
They are NOT equivalent, and conflating them would be its own dishonesty:
- "index empty" -> the arm's STORE was never populated. Setup failure. The
memory layer cannot be said to have answered. Counted as
an error so the arm reports memory_unavailable.
- "no matching" -> the backend answered from a populated store and honestly
found nothing relevant for that query. The layer IS
alive; this is a legitimate retrieval outcome and must
NOT be scored as a crash. Counted OK, and separately
tallied as retrieval_empty_count so it stays visible.
Returns (kind, detail) where detail is a short line for the error samples.
"""
text = (output or "").strip()
if not text:
return "error", "empty tool output"
if text.upper().startswith("ERROR"):
return "error", text.split("\n")[0][:200]
low = text.lower()
if "index empty" in low or "no memories to retrieve" in low:
return "empty_store", text.split("\n")[0][:200]
if "no matching" in low:
return "no_match", ""
return "ok", ""
# Which memory tool each arm is expected to call. Drives the pre-warm step and
# the liveness gate.
ARM_MEMORY_TOOL = {
"sync": "vestige_backfill",
"rag": "rag_search",
"mem0": "mem0_search",
"supermemory": "supermemory_search",
"hindsight": "hindsight_search",
"zep": "zep_search",
}
# How many agents in the fleet. 3 is the demo default (enough to diverge).
FLEET_SIZE = int(os.environ.get("FLEET_SIZE", "3"))
# Per-agent iteration cap. Kept modest so a thrashing agent terminates and is
# recorded, not left spinning. Overrides runner.MAX_ITERATIONS for the fleet.
FLEET_MAX_ITERATIONS = int(os.environ.get("MAX_ITERATIONS", "8"))
# --- Demo profile ------------------------------------------------------------
# The fleet supports two torture scenarios, selected by DEMO_PROFILE:
# "canonical" (default) -> torture-v2: a canonical field-ORDER drift. The two
# canonical.ts files are contested; "direction" is the
# field order each agent lands on.
# "keyring" -> torture-v3.5 "Silent Rotation": a signing-KEY-id
# selection. The two config files are contested;
# "direction" is the key id each agent chooses. Adds an
# out-of-band PRODUCTION-CONFORMANCE replay after the
# integrated test: the fix is only truly correct if the
# integrated ledger still verifies already-issued
# production tokens (held in the harness, in no checkout).
DEMO_PROFILE = os.environ.get("DEMO_PROFILE", "canonical").strip().lower()
if DEMO_PROFILE == "keyring":
CONTESTED_FILES = [
"identity-service/src/config.ts",
"ledger-service/src/config.ts",
]
else:
CONTESTED_FILES = [
"identity-service/src/canonical.ts",
"ledger-service/src/canonical.ts",
]
# Back-compat alias: existing code refers to CANONICAL_FILES.
CANONICAL_FILES = CONTESTED_FILES
# Files that are legitimately editable to fix the bug. Any edit OUTSIDE this set
# is recorded as an out-of-bounds change (part of the anarchy signal) but not
# used to decide the merge.
FIXABLE_FILES = set(CONTESTED_FILES)
# Path to the production-conformance corpus (keyring profile only): already-issued
# production tokens, held in the harness, present in NO agent checkout.
PROD_CORPUS_PATH = os.environ.get(
"PROD_CORPUS",
str(Path(__file__).resolve().parent.parent / "prod-corpus" / "production-tokens.json"),
)
def _log(msg: str) -> None:
print(msg, file=sys.stderr, flush=True)
# --- Transcript capture helpers ---------------------------------------------
def _sanitize_for_json(obj):
"""Best-effort convert arbitrary provider output items (SDK model objects,
Anthropic content blocks, dicts) into plain JSON-serializable structures so
the transcript can be written verbatim. Never raises: anything it cannot
convert becomes its repr string, so the transcript is always writable."""
# Fast path for JSON primitives.
if obj is None or isinstance(obj, (bool, int, float, str)):
return obj
if isinstance(obj, dict):
return {str(k): _sanitize_for_json(v) for k, v in obj.items()}
if isinstance(obj, (list, tuple)):
return [_sanitize_for_json(v) for v in obj]
# Pydantic / SDK models expose model_dump(); Anthropic blocks expose to_dict.
for attr in ("model_dump", "to_dict", "dict"):
fn = getattr(obj, attr, None)
if callable(fn):
try:
return _sanitize_for_json(fn())
except Exception: # noqa: BLE001
pass
# Generic object with a __dict__.
d = getattr(obj, "__dict__", None)
if isinstance(d, dict) and d:
return {str(k): _sanitize_for_json(v) for k, v in d.items()}
return repr(obj)
def _extract_reasoning(raw_items) -> str:
"""Pull any human-readable reasoning text out of the sanitized raw model
output items. OpenAI Responses reasoning items carry a `summary` (a list of
{type, text}); Anthropic 'thinking' blocks carry `thinking`. Returns a joined
string, or '' when the model exposed no visible reasoning text."""
chunks: list[str] = []
items = raw_items if isinstance(raw_items, list) else [raw_items]
for it in items:
if not isinstance(it, dict):
continue
# OpenRouter / Kimi (chat.completions): the assistant message dict carries
# the chain-of-thought as a top-level `reasoning` string (see
# OpenRouterProvider.turn). No `type` field on these items.
if it.get("role") == "assistant" and isinstance(it.get("reasoning"), str):
if it["reasoning"].strip():
chunks.append(it["reasoning"].strip())
continue
typ = it.get("type")
if typ == "reasoning":
summary = it.get("summary") or []
if isinstance(summary, list):
for s in summary:
if isinstance(s, dict) and s.get("text"):
chunks.append(str(s["text"]))
elif isinstance(s, str):
chunks.append(s)
elif typ in ("thinking", "redacted_thinking"):
if it.get("thinking"):
chunks.append(str(it["thinking"]))
# OpenAI message items may carry output_text content too.
elif typ == "message":
for part in it.get("content", []) or []:
if isinstance(part, dict) and part.get("type") in ("output_text", "text") and part.get("text"):
chunks.append(str(part["text"]))
return "\n\n".join(chunks).strip()
# --- The shared coordination bus (sync mode only) ---------------------------
#
# In sync mode the fleet shares ONE Vestige data-dir. The bus is a thin wrapper
# that (a) exposes vestige_backfill to every agent (already in runner.VESTIGE_TOOL)
# and (b) adds a vestige_log tool so an agent can WRITE a finding other agents
# can later read -- i.e. real agent-to-agent coordination through the hub, not
# just read-only recall. Writes are serialized under a lock because SQLite
# single-writer semantics mean concurrent ingests would otherwise contend.
class SharedBus:
"""Vestige-backed shared memory bus for the sync fleet."""
def __init__(self, data_dir: str, vestige_bin: str) -> None:
self.data_dir = data_dir
self.vestige_bin = vestige_bin
import threading
self._lock = threading.Lock()
def _run(self, args: list, timeout: int = 60) -> subprocess.CompletedProcess:
cmd = [self.vestige_bin, "--data-dir", self.data_dir, *args]
return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
def log_finding(self, agent_id: str, content: str) -> str:
"""An agent writes a coordination note other agents can recall. Tagged
canonical_digest so it joins the same causal thread as the seeded
history and the failure."""
body = f"[fleet {agent_id}] {content}"
with self._lock:
try:
proc = self._run(
[
"ingest",
body,
"--node-type",
"note",
"--tags",
"canonical_digest,fleet_coordination",
"--source",
f"fleet-agent-{agent_id}",
]
)
except (FileNotFoundError, subprocess.TimeoutExpired) as exc:
return f"ERROR logging to shared bus: {exc}"
if proc.returncode != 0:
return f"vestige ingest exit={proc.returncode}\n{proc.stderr[:1000]}"
return "logged to shared memory (other agents can now recall this)."
def _bus_backfill_tool(bus: SharedBus):
"""Wrap runner's backfill against the shared bus data-dir."""
def tool(_repo: Path, _args: dict) -> str:
# runner.tool_vestige_backfill reads VESTIGE_BIN / VESTIGE_DATA_DIR from
# the environment; the fleet sets those per shared run, so we just defer.
return runner.tool_vestige_backfill(_repo, _args)
return tool
def _bus_log_tool(bus: SharedBus, agent_id: str):
def tool(_repo: Path, args: dict) -> str:
content = str(args.get("finding", "")).strip()
if not content:
return "ERROR: empty finding"
return bus.log_finding(agent_id, content)
return tool
# --- Per-agent run (one member of the fleet) --------------------------------
def _build_agent_tools(mode: str, agent_id: str, bus: SharedBus | None):
"""Return (specs, tools) for one agent.
anarchy: exactly runner.BASE_TOOLS (no memory, no coordination).
rag : BASE_TOOLS + rag_search (independent dense-cosine retrieval over the
SAME seeded Vestige DB). No shared bus, no coordination -- like
anarchy PLUS a retrieval tool. Each agent retrieves on its own.
sync : BASE_TOOLS + vestige_backfill (read the hub) + vestige_log (write
to the hub so peers can coordinate).
"""
tools = dict(runner.BASE_TOOLS)
if mode == "rag":
# Independent, uncoordinated retrieval: register the single-agent RAG
# tool exactly as-is. Its fn reads VESTIGE_DATA_DIR (the seeded DB) at
# call time, so every rag agent queries the same seeded memory by pure
# cosine. No bus, no vestige_log -- rag agents do NOT coordinate.
r_fn, r_desc, r_schema = runner.RAG_TOOL["rag_search"]
tools["rag_search"] = (r_fn, r_desc, r_schema)
elif mode == "mem0":
# Independent, uncoordinated retrieval like rag: BASE_TOOLS + a single
# mem0 retrieval tool. Its fn ingests the SAME shared corpus once per
# process (_rag_load_facts) and retrieves via mem0's recommended path.
# No bus, no vestige_log -- mem0 agents do NOT coordinate.
m_fn, m_desc, m_schema = runner.MEM0_TOOL["mem0_search"]
tools["mem0_search"] = (m_fn, m_desc, m_schema)
elif mode == "supermemory":
# Independent, uncoordinated retrieval through a self-hosted supermemory
# server. Its fn ingests the SAME seeded corpus (_rag_load_facts) into
# supermemory's own local store once per process, then retrieves via
# /v3/search. No bus, no vestige_log -- supermemory agents do NOT coordinate.
s_fn, s_desc, s_schema = runner.SUPERMEMORY_TOOL["supermemory_search"]
tools["supermemory_search"] = (s_fn, s_desc, s_schema)
elif mode == "hindsight":
# Independent, uncoordinated retrieval through Hindsight's own agent-memory
# recall path (semantic + BM25 + local cross-encoder rerank) over the SAME
# seeded corpus (_rag_load_facts). No bus, no vestige_log -- hindsight
# agents do NOT coordinate (anarchy PLUS retrieval).
h_fn, h_desc, h_schema = runner.HINDSIGHT_TOOL["hindsight_search"]
tools["hindsight_search"] = (h_fn, h_desc, h_schema)
elif mode == "zep":
# Independent, uncoordinated knowledge-graph retrieval over the SAME
# seeded corpus (_rag_load_facts) via Zep's OSS Graphiti engine on a local
# FalkorDB. No bus, no vestige_log -- zep agents do NOT coordinate
# (anarchy PLUS a temporal-knowledge-graph memory tool).
z_fn, z_desc, z_schema = runner.ZEP_TOOL["zep_search"]
tools["zep_search"] = (z_fn, z_desc, z_schema)
elif mode == "sync":
# Read side: the same backfill tool the single-agent vestige mode uses.
b_fn, b_desc, b_schema = runner.VESTIGE_TOOL["vestige_backfill"]
tools["vestige_backfill"] = (_bus_backfill_tool(bus), b_desc, b_schema)
# Write side: coordination. Lets an agent publish a finding for peers.
tools["vestige_log"] = (
_bus_log_tool(bus, agent_id),
"Publish a short finding to the SHARED team memory so the other "
"agents in the fleet can recall it and avoid duplicating or "
"colliding with your work. Use it to record the fix direction you "
"concluded and why (e.g. which service is the source of truth).",
{
"type": "object",
"properties": {"finding": {"type": "string"}},
"required": ["finding"],
},
)
specs = [
{"name": name, "description": desc, "input_schema": schema}
for name, (_fn, desc, schema) in tools.items()
]
return specs, tools
def _agent_system_prompt(mode: str, agent_id: str) -> str:
base = (
"You are ONE agent in a fleet of autonomous coding agents all assigned "
"the SAME task on a shared TypeScript monorepo (the Meridian platform: "
"identity-service mints session tokens, gateway-service forwards them, "
"ledger-service verifies them and charges). Your task: "
f"{runner.TASK}. The end-to-end charge test currently fails. Reproduce it "
"with run_tests, investigate across the services, apply a fix with "
"write_file, then re-run run_tests to verify. Call finish(fixed=true) "
"ONLY when run_tests exits 0. Be efficient; do not re-read files you have "
"already read. IMPORTANT: your edits will later be INTEGRATED with the "
"edits of the other agents into one shared codebase, so the DIRECTION of "
"your fix matters, not just whether your local copy passes."
)
if mode == "sync":
base += (
" You are NOT working blind: you share a team memory with the rest of "
"the fleet. Call vestige_backfill to reach backward from the failure "
"to the quiet earlier change that caused it (it may be a past decision "
"in a different service that the current code does not reveal), and "
"call vestige_log to publish the fix DIRECTION you conclude so your "
"peers converge on the same change instead of colliding. Consult the "
"shared memory BEFORE deciding which file is authoritative."
)
elif mode == "rag":
base += (
" You are NOT working blind: you have a team memory of past notes, "
"incidents, and decisions. Call rag_search to retrieve the most "
"relevant memories about this failure (the cause may live in a past "
"decision in a different service that the current code does not "
"reveal). Consult that memory BEFORE deciding which file is "
"authoritative."
)
elif mode == "mem0":
base += (
" You are NOT working blind: you have a team memory of past notes, "
"incidents, and decisions stored in mem0. Call mem0_search to "
"retrieve the most relevant memories about this failure (the cause "
"may live in a past decision in a different service that the current "
"code does not reveal). Consult that memory BEFORE deciding which "
"file is authoritative."
)
elif mode == "supermemory":
base += (
" You are NOT working blind: you have a team memory of past notes, "
"incidents, and decisions stored in supermemory. Call "
"supermemory_search to retrieve the most relevant memories about this "
"failure (the cause may live in a past decision in a different service "
"that the current code does not reveal). Consult that memory BEFORE "
"deciding which file is authoritative."
)
elif mode == "hindsight":
base += (
" You are NOT working blind: you have a team memory of past notes, "
"incidents, and decisions stored in Hindsight. Call hindsight_search "
"to retrieve the most relevant memories about this failure (the cause "
"may live in a past decision in a different service that the current "
"code does not reveal). Consult that memory BEFORE deciding which file "
"is authoritative."
)
elif mode == "zep":
# FIX 1: without this branch, zep falls through to the anarchy else-branch
# ("you have NO shared memory") -- a fairness bug that rigs the arm to lose.
base += (
" You are NOT working blind: you have a team memory of past notes, "
"incidents, and decisions stored as a temporal knowledge graph "
"(Zep/Graphiti). Call zep_search to retrieve the most relevant "
"memories about this failure (the cause may live in a past decision in "
"a different service that the current code does not reveal). Consult "
"that memory BEFORE deciding which file is authoritative."
)
else:
base += (
" You have NO shared memory and no way to coordinate with the other "
"agents. Decide and act on your own."
)
return base
def _run_one_agent(
mode: str,
agent_id: str,
checkout: Path,
bus: SharedBus | None,
transcript_dir: Path | None = None,
) -> dict:
"""Run a single agent loop in its OWN checkout. Returns a per-agent result
dict plus the concrete edits it made to the canonical files (for the merge).
This mirrors runner.run() exactly (same provider, same measured usage, same
ground-truth verification) but is scoped to one fleet member + captures the
post-run contents of the contested files.
"""
provider = runner._make_provider()
specs, tools = _build_agent_tools(mode, agent_id, bus)
transcript = provider.new_transcript(
f"The repo is at {checkout}. Task: {runner.TASK}."
)
total_in = 0
total_out = 0
iterations = 0
status = "looped"
finish_summary = ""
writes: list[str] = [] # repo-relative paths this agent wrote
turn_error = "" # non-empty if a model turn failed mid-run
t0 = time.time()
system = _agent_system_prompt(mode, agent_id)
# Full turn-by-turn transcript capture -- this is the ON-CAMERA record of what
# each agent actually saw and did: its reasoning + tool calls per turn, the
# verbatim tool results (crucially the raw vestige_backfill output the sync
# agents receive), and the token delta per turn. Written to results/ after the
# loop. Reasoning text (OpenAI Responses reasoning items) is captured when the
# SDK exposes it; if a reasoning summary is unavailable the reasoning items are
# still recorded structurally so the tool-call sequence is fully auditable.
turn_log: list[dict] = []
for iterations in range(1, FLEET_MAX_ITERATIONS + 1):
# A model turn can fail (rate-limit, transient 5xx, auth). The reused
# runner.OpenAIProvider.turn calls runner.fail() -> sys.exit(2) on such
# errors, which raises SystemExit (a BaseException, NOT Exception). In a
# fleet that MUST NOT kill the whole process and torch the paid run of
# the sibling agents -- so we catch BOTH here, record this agent as
# errored, and let the rest of the fleet drain normally. The tokens this
# agent already spent are preserved in total_in/total_out.
transcript_len_before = len(transcript)
try:
calls, in_tok, out_tok = provider.turn(system, specs, transcript)
except (Exception, SystemExit) as exc: # noqa: BLE001
turn_error = f"{type(exc).__name__}: {exc}"
status = "errored"
turn_log.append({
"turn": iterations,
"error": turn_error,
"note": "model turn raised; agent recorded as errored, fleet continues",
})
_log(f" agent {agent_id}: turn error ({turn_error}); recording partial + continuing fleet")
break
total_in += in_tok
total_out += out_tok
# The provider appended its raw output item(s) to `transcript` in-place
# (for OpenAI: reasoning + message + function_call items; for Anthropic:
# the assistant content blocks). Snapshot exactly what it added this turn
# so the transcript file shows the model's real, unedited output.
raw_model_output = _sanitize_for_json(transcript[transcript_len_before:])
reasoning_text = _extract_reasoning(raw_model_output)
turn_record = {
"turn": iterations,
"tokens": {"input": in_tok, "output": out_tok},
"reasoning": reasoning_text, # model's visible reasoning, if any
"raw_model_output": raw_model_output, # verbatim provider items
"tool_calls": [
{"name": c["name"], "input": c["input"]} for c in calls
],
"tool_results": [], # filled below with verbatim outputs
}
if not calls:
provider.add_no_tool_nudge(transcript)
turn_record["note"] = "no tool call; nudged"
turn_log.append(turn_record)
continue
results = []
did_finish = False
for c in calls:
if c["name"] == "finish":
did_finish = True
fixed = bool(c["input"].get("fixed"))
finish_summary = str(c["input"].get("summary", ""))
status = "fixed_claimed" if fixed else "gave_up"
results.append({"id": c["id"], "content": "acknowledged"})
turn_record["tool_results"].append({
"name": "finish", "input": c["input"], "output": "acknowledged",
})
continue
# Guard against a hallucinated / misspelled tool name: dispatch must
# not KeyError out of the loop and crash the agent. Return a normal
# tool error the model can recover from.
entry = tools.get(c["name"])
if entry is None:
msg = f"ERROR: unknown tool '{c['name']}'. Available: {sorted(tools)}."
results.append({"id": c["id"], "content": msg})
turn_record["tool_results"].append({
"name": c["name"], "input": c["input"], "output": msg,
})
continue
fn = entry[0]
ok = True
try:
output = fn(checkout, c["input"] or {})
except Exception as exc: # noqa: BLE001
output = f"ERROR running {c['name']}: {exc}"
ok = False
# Only record a write we actually attempted successfully (a rejected
# path-escape / missing-parent write returns an ERROR string and must
# not pollute files_written / out_of_bounds_writes).
if c["name"] == "write_file" and ok and not str(output).startswith("ERROR"):
p = str((c["input"] or {}).get("path", ""))
if p:
writes.append(p)
results.append({"id": c["id"], "content": output})
# Record the VERBATIM tool output -- for vestige_backfill this is the
# exact JSON flashback the agent saw (the money shot for the demo).
turn_record["tool_results"].append({
"name": c["name"], "input": c["input"], "output": output,
})
provider.add_tool_results(transcript, results)
turn_log.append(turn_record)
if did_finish:
break
wall = time.time() - t0
# Ground-truth: did THIS agent's isolated checkout end green? (Independent of
# whether the fleet's integrated tree will.) Catch ANY error here (not just
# timeout): the agent's paid API turns are already done, so a flaky test
# subprocess (OSError, etc.) must NOT escape and cost us the already-spent
# token count -- fall through to the normal return that preserves it.
try:
verify = runner._run_tests(checkout)
local_pass = verify.returncode == 0
except Exception as exc: # noqa: BLE001
local_pass = False
if not turn_error:
turn_error = f"verify failed: {type(exc).__name__}: {exc}"
if status == "fixed_claimed":
status = "fixed" if local_pass else "hallucinated"
elif local_pass:
status = "fixed"
# Capture the post-run contents of the contested files so the integrator can
# do a real merge and classify the fix direction each agent chose.
edited_canon = {}
for rel in CANONICAL_FILES:
fp = checkout / rel
if fp.is_file():
edited_canon[rel] = fp.read_text(errors="replace")
out_of_bounds = sorted(
{w for w in writes if w not in FIXABLE_FILES and w.strip()}
)
# Coordination evidence, computed from the captured transcript: did this agent
# actually consult the shared Vestige hub? These are the on-camera proof that
# the sync win came from memory, not luck.
tool_names_used = [
tr["name"] for t in turn_log for tr in t.get("tool_results", [])
]
used_backfill = "vestige_backfill" in tool_names_used
used_vestige_log = "vestige_log" in tool_names_used
used_rag_search = "rag_search" in tool_names_used
# --- ARM-AGNOSTIC RETRIEVAL TELEMETRY ---------------------------------
# Previously this block tracked ONLY Vestige's tools plus rag_search, so a
# result JSON could report agents_errored=0 for an arm whose memory backend
# answered nothing. That is exactly how three dead competitor arms
# (hindsight 19/19 errors, zep 22/22, mem0 14/15) reached a published
# scoreboard looking like substantive retrieval losses: the output format
# was structurally incapable of expressing "the backend never answered".
# Every arm is now measured identically: which memory tool it called, and
# how many of those calls returned REAL DATA vs an ERROR string.
memory_tool_used = None
retrieval_ok_count = 0
retrieval_err_count = 0
retrieval_empty_count = 0
retrieval_errors: list[str] = []
for _t in turn_log:
for _tr in _t.get("tool_results", []):
if _tr.get("name") not in MEMORY_TOOL_NAMES:
continue
memory_tool_used = _tr.get("name")
kind, detail = _classify_retrieval(str(_tr.get("output", "")))
if kind == "error":
retrieval_err_count += 1
if detail and detail not in retrieval_errors:
retrieval_errors.append(detail)
elif kind == "empty_store":
# The backend answered, but its STORE was never populated. That is
# a setup failure, not a retrieval result -- counting it as a
# successful retrieval is how a dead arm hides.
retrieval_err_count += 1
if detail and detail not in retrieval_errors:
retrieval_errors.append(detail)
elif kind == "no_match":
# The backend answered from a populated store and genuinely found
# nothing relevant. The memory layer IS alive; this is a real (if
# unhelpful) retrieval result and must NOT be scored as a crash.
retrieval_ok_count += 1
retrieval_empty_count += 1
else:
retrieval_ok_count += 1
# True only when this agent's memory layer answered at least once. An arm
# where this is False for every agent did not lose on retrieval quality --
# it did not run, and must be reported as memory_unavailable, not a loss.
memory_layer_alive = retrieval_ok_count > 0
# Persist the FULL turn-by-turn transcript to results/ so we can prove on
# camera exactly what this agent saw (esp. the verbatim vestige_backfill
# flashback) and did. One file per agent per mode.
if transcript_dir is not None:
try:
transcript_dir.mkdir(parents=True, exist_ok=True)
tpath = transcript_dir / f"transcript-{mode}-{agent_id}.json"
tpath.write_text(json.dumps({
"agent_id": agent_id,
"mode": mode,
"provider": runner.PROVIDER,
"model": runner.MODEL,
"task": runner.TASK,
"status": status,
"iterations": iterations,
"tokens": {"input": total_in, "output": total_out, "total": total_in + total_out},
"used_vestige_backfill": used_backfill,
"used_vestige_log": used_vestige_log,
"used_rag_search": used_rag_search,
"memory_tool_used": memory_tool_used,
"retrieval_ok_count": retrieval_ok_count,
"retrieval_err_count": retrieval_err_count,
"retrieval_empty_count": retrieval_empty_count,
"retrieval_errors": retrieval_errors,
"memory_layer_alive": memory_layer_alive,
"final_contested_signatures": {
rel: _signature(rel, body) for rel, body in edited_canon.items()
},
"turns": turn_log,
}, indent=2))
except Exception as exc: # noqa: BLE001 -- transcript write must never fail the run
_log(f" agent {agent_id}: WARNING could not write transcript: {exc}")
return {
"agent_id": agent_id,
"mode": mode,
"tokens": {"input": total_in, "output": total_out, "total": total_in + total_out},
"iterations": iterations,
"wall_clock_seconds": round(wall, 2),
"status": status,
"local_tests_pass": local_pass,
"files_written": sorted(set(writes)),
"out_of_bounds_writes": out_of_bounds,
"used_vestige_backfill": used_backfill,
"used_vestige_log": used_vestige_log,
"used_rag_search": used_rag_search,
"memory_tool_used": memory_tool_used,
"retrieval_ok_count": retrieval_ok_count,
"retrieval_err_count": retrieval_err_count,
"retrieval_empty_count": retrieval_empty_count,
"retrieval_errors": retrieval_errors,
"memory_layer_alive": memory_layer_alive,
"finish_summary": finish_summary,
"turn_error": turn_error, # non-empty if a model turn failed mid-run
"_canonical_after": edited_canon, # consumed by the integrator, stripped from JSON
}
# --- Fix-direction classification + integration merge -----------------------
def _extract_kid(text: str, field: str) -> str | None:
"""[keyring profile] Extract the key id a config file selects for `field`
(activeKid / trustedKid). Returns the chosen kid string, '' if explicitly
blank (the RED base state), or None if the field can't be found.
Models commonly 'externalize' the key as an env lookup with a literal
fallback, e.g. `activeKid: process.env.IDENTITY_ACTIVE_KID ?? "k_yildun"`.
When no env var is set (the test condition), the FALLBACK literal is the
effective key. So we must read the fallback, not just a bare `field: "kid"`.
Missing this classified a correct fix as `kid_unset` and produced a FALSE
merge conflict."""
import re
# Isolate the field's value expression up to the end of the statement
# (comma, newline, or closing brace) so we don't bleed into other fields.
stmt = re.search(rf'{field}\s*[:=]\s*([^\n,}}]+)', text)
if stmt is None:
return None
expr = stmt.group(1)
# Collect every string literal in the value expression. For an env-fallback
# (`process.env.X ?? "k_yildun"`) the LAST literal is the effective default;
# for a bare `"k_yildun"` there is exactly one. An env-var NAME is not quoted,
# so quoted literals are only real key ids / the blank "".
lits = re.findall(r"""['"]([^'"]*)['"]""", expr)
if not lits:
# value present but no string literal (e.g. only an unquoted env var and
# no fallback) -> no effective key id selected.
return ""
return lits[-1]
def _keyring_leak_audit(base_repo: Path, correct_kid: str) -> list[str]:
"""[keyring profile] Scan every checkout-visible file for anything that would
let an agent DERIVE the correct key id without memory. Returns a list of leak
descriptions (file:line: why); empty list == clean.
Leaks we catch:
* the correct kid appearing OUTSIDE the neutral keyring map (i.e. anywhere
that could label it active/prod/correct);
* the correct kid's raw key MATERIAL appearing outside keyring.ts (a
fixture / corpus / pre-signed token that pins it);
* a committed production-token corpus or truth-table / answer file.
"""
import re
keyring_rel = "shared/src/keyring.ts"
# Recover the correct kid's hex material from the keyring so we can detect it
# leaking elsewhere.
correct_hex = None
kr = base_repo / keyring_rel
if kr.is_file():
m = re.search(rf'{re.escape(correct_kid)}:\s*"([0-9a-fA-F]{{16,}})"', kr.read_text())
if m:
correct_hex = m.group(1)
answer_file_hint = re.compile(r"(truth[-_ ]?table|answer|solution|prod[-_ ]?corpus|production[-_ ]tokens)", re.I)
leaks: list[str] = []
for p in base_repo.rglob("*"):
rel = p.relative_to(base_repo)
# Only audit files an AGENT can actually read (mirror runner's skip
# logic). The seed script + demo-infra are unreadable from the checkout,
# so a leak there is not agent-reachable.
if runner._is_skipped(rel):
continue
if not p.is_file():
continue
relstr = str(rel)
# An obviously answer-shaped file name is a leak on its own.
if answer_file_hint.search(p.name):
leaks.append(f"{relstr}: file name looks like an answer/corpus file")
try:
text = p.read_text(errors="replace")
except OSError:
continue
for i, line in enumerate(text.splitlines(), 1):
# correct kid outside the neutral keyring map
if correct_kid in line and relstr != keyring_rel:
leaks.append(f"{relstr}:{i}: names the correct key id '{correct_kid}'")
# correct key material outside keyring.ts
if correct_hex and correct_hex in line and relstr != keyring_rel:
leaks.append(f"{relstr}:{i}: contains the correct key's raw material")
# De-dup while preserving order.
seen = set()
out = []
for l in leaks:
if l not in seen:
seen.add(l)
out.append(l)
return out
def _signature(rel: str, text: str):
"""Profile-aware semantic value of a contested file, used for merge grouping
and direction classification. Two edits with the SAME signature agree; a
different signature is a divergent fix.
- canonical profile: the claim field ORDER the file emits (a tuple).
- keyring profile: the key id the config selects (activeKid for identity,
trustedKid for ledger) as ('kid', <value>).
"""
if DEMO_PROFILE == "keyring":
field = "activeKid" if "identity" in rel else "trustedKid"
kid = _extract_kid(text, field)
return None if kid is None else ("kid", kid)
order = _canonical_order(text)
return None if order is None else ("order", *order)
def _canonical_order(text: str) -> list[str] | None:
"""Extract the claim field order the canonical.ts body emits, robust to the
common ways a model may rewrite the file. Returns e.g. ['sub','plan','exp',
'iat'] or None if no ordering can be recovered.
The canonical string is `key=value\\n`-joined, so the ORDER that matters for
the digest is the order the claim keys first appear as they are folded in.
We look for the keys attached to a `claims.` / `claims[...]` access (the
tuple form `["sub", claims.sub]`, a value-array `claims.sub`, template
literals ``${claims.sub}``, single or double quotes) and, failing that, fall
back to the order of the literal `sub=`/`plan=`/`iat=`/`exp=` label tokens.
De-duplicates while preserving first-seen order so a key referenced twice
doesn't distort the sequence."""
import re
keys = ("sub", "plan", "iat", "exp")
# Primary: keys bound to a claims.* / claims[...] access, in source order.
pat = re.compile(
r'claims\s*(?:\.\s*(sub|plan|iat|exp)\b'
r'|\[\s*[\'"](sub|plan|iat|exp)[\'"]\s*\])'
)
order: list[str] = []
for m in pat.finditer(text):
k = m.group(1) or m.group(2)
if k and k not in order:
order.append(k)
if len(order) == len(keys):
return order
# Fallback: the `key=` label tokens the digest emits (e.g. `${k}=` templates
# or explicit `sub=` literals).
order2: list[str] = []
for m in re.finditer(r'\b(sub|plan|iat|exp)\s*=', text):
k = m.group(1)
if k not in order2:
order2.append(k)
if len(order2) == len(keys):
return order2
# Return whatever partial primary order we found (better than nothing for
# classification), or None if we found nothing at all.
return order or None
def _classify_direction(pristine_id: list, pristine_ld: list, res: dict) -> str:
"""Given an agent's post-run contested files, classify which way it fixed.
canonical profile returns: 'adapt_ledger' (correct), 'change_identity'
(wrong), 'both', 'neither', 'fixed_unparseable'.
keyring profile returns: 'kid:<value>' where <value> is the key id the agent
converged BOTH services onto (e.g. 'kid:k_borealis' = correct). If the two
services disagree on the kid, returns 'kid_split' (a divergent fix). If a
service is still blank/unset, 'kid_unset'.
"""
canon = res.get("_canonical_after", {})
id_body = canon.get(CANONICAL_FILES[0], "")
ld_body = canon.get(CANONICAL_FILES[1], "")
if DEMO_PROFILE == "keyring":
active = _extract_kid(id_body, "activeKid")
trusted = _extract_kid(ld_body, "trustedKid")
if not active or not trusted:
return "kid_unset"
if active != trusted:
return "kid_split"
return f"kid:{active}"
id_after = _canonical_order(id_body)
ld_after = _canonical_order(ld_body)
# Byte-level "did this file change at all" as a backstop when the order can't
# be parsed -- so a real but unparseable edit isn't mislabeled as a no-op.
changed_id = (id_after is not None and id_after != pristine_id) or (
id_after is None and bool(id_body.strip())
)
changed_ld = (ld_after is not None and ld_after != pristine_ld) or (
ld_after is None and bool(ld_body.strip())
)
# If a file changed but we couldn't parse its new order, we can't name the
# direction with confidence -- flag it rather than guess.
if (changed_id and id_after is None) or (changed_ld and ld_after is None):
return "fixed_unparseable"
if changed_id and changed_ld:
return "both"
if changed_ld and not changed_id:
return "adapt_ledger"
if changed_id and not changed_ld:
return "change_identity"
return "neither"
_PROD_REPLAY_JS = r"""
// Production-conformance replay (ES module): import the INTEGRATED ledger's real
// verifyToken and check it still accepts every already-issued production token.
// Prints a JSON verdict. Any token that fails = production outage (voided live
// tokens). Runs under tsx so the .ts import resolves.
import { readFileSync } from "node:fs";
async function main() {
const corpus = JSON.parse(readFileSync(process.argv[2], "utf8"));
let mod;
try {
mod = await import(process.argv[3]); // integrated ledger verify.ts
} catch (e) {
console.log(JSON.stringify({ ok: false, error: "import failed: " + (e && e.message), verified: 0, total: corpus.tokens.length }));
return;
}
const verifyToken = mod.verifyToken;
let verified = 0;
const failures = [];
for (const t of corpus.tokens) {
try { verifyToken(t.token); verified++; }
catch (e) { failures.push({ sub: t.sub, error: String((e && e.message) || e) }); }
}
console.log(JSON.stringify({
ok: failures.length === 0, verified, total: corpus.tokens.length, failures,
signed_under: corpus.signed_under,
}));
}
main();
"""
def _production_replay(integration_repo: Path, corpus_path: Path) -> dict:
"""[keyring profile] Replay the already-issued production token corpus against
the INTEGRATED ledger's real verify.ts. The corpus lives in the harness and is
in NO agent checkout, so no agent could have seen or fit to it. Returns the
verdict dict. This is what separates a locally-green fix from a
production-SAFE one."""
if not corpus_path.is_file():
return {"ran": False, "reason": f"no corpus at {corpus_path}"}
verify_ts = integration_repo / "ledger-service" / "src" / "verify.ts"
if not verify_ts.is_file():
return {"ran": False, "reason": "integrated verify.ts missing"}
# Write the replay driver into the integration tree and run it with tsx so the
# TS import resolves against the integrated modules + workspace node_modules.
driver = integration_repo / "_prod_replay.mjs"
driver.write_text(_PROD_REPLAY_JS)
try:
proc = subprocess.run(
["npx", "tsx", str(driver), str(corpus_path), str(verify_ts)],
cwd=str(integration_repo),
capture_output=True,
text=True,
timeout=120,
)
except (subprocess.TimeoutExpired, FileNotFoundError) as exc:
return {"ran": False, "reason": f"replay exec failed: {exc}"}
out = proc.stdout.strip().splitlines()
parsed = None
for line in reversed(out): # last JSON line is the verdict
try:
parsed = json.loads(line)
break
except json.JSONDecodeError:
continue
if parsed is None:
return {"ran": False, "reason": "no JSON verdict", "stderr": proc.stderr[-500:]}
parsed["ran"] = True
return parsed
def _integrate(
agent_results: list,
integration_repo: Path,
pristine_snapshot: Path,
node_modules_source: Path | None = None,
) -> dict:
"""Perform a REAL integration of the fleet's edits into one shared tree and
run the test suite on the result.
Mechanism (honest, deterministic, no scripting of the outcome):
* Start the integration tree from the pristine (broken) snapshot.
* For each contested canonical file, collect the DISTINCT post-run contents
the agents produced.
* If all agents who touched a file agree on its content -> apply it (a
clean merge for that file).
* If they DISAGREE (>1 distinct version of the same file) OR the fleet
edited BOTH files in opposite directions -> that is a real merge
conflict; we record it and apply a git-style conflict marker so the file
no longer compiles, exactly as a real 3-way merge would leave it.
* Run the tests on the integrated tree. Its pass/fail is the fleet's real
outcome.
node_modules_source: a repo whose node_modules is linked into the integration
tree so `npm test` can resolve the @meridian/* workspaces (the pristine
snapshot deliberately excludes node_modules).
"""
# Reset the integration tree to pristine broken state. Strip demo-infra here
# too (same ignore as agent checkouts) so no seed/db/corpus rides along.
if integration_repo.exists():
shutil.rmtree(integration_repo)
shutil.copytree(
pristine_snapshot, integration_repo, symlinks=True,
ignore=shutil.ignore_patterns(
".vestige-seed.sh", ".vestige-demo-db", ".vestige-demo-data",
".repo-snapshot", ".fixtures", "prod-corpus", "*.db",
),
)
# The snapshot has no node_modules; link the base repo's so tests can run.
if node_modules_source is not None:
nm = node_modules_source / "node_modules"
dst = integration_repo / "node_modules"
if nm.is_dir() and not dst.exists():
try:
dst.symlink_to(nm.resolve())
except OSError:
shutil.copytree(nm, dst, symlinks=True)
# Pristine signatures of the two contested files (used by canonical-profile
# direction classification; keyring profile classifies by chosen kid instead).
pristine_id = _canonical_order((integration_repo / CANONICAL_FILES[0]).read_text())
pristine_ld = _canonical_order((integration_repo / CANONICAL_FILES[1]).read_text())
# Gather, per contested file, the edits agents made -- grouped by SEMANTICS
# (the canonical field ORDER the body emits), not raw bytes. This is the
# right merge key for this demo: two agents that both put the ledger into
# [sub,plan,exp,iat] AGREE, even if their file formatting (comments,
# whitespace, trailing newline) differs -- a byte-level merge would wrongly
# flag that as a conflict. Only a genuinely DIFFERENT field order (or an
# unparseable rewrite) counts as a divergent version.
#
# semantic_key(body): a tuple like ('order', 'sub','plan','exp','iat') when
# parseable, else ('raw', <body>) so an unparseable edit stays its own bucket
# (it can neither silently collapse into a parseable one nor hide divergence).
def semantic_key(body: str, rel: str):
sig = _signature(rel, body)
if sig is not None:
return sig
return ("raw", body)
per_file_groups: dict[str, dict[tuple, dict]] = {f: {} for f in CANONICAL_FILES}
directions: dict[str, str] = {}
for res in agent_results:
directions[res["agent_id"]] = _classify_direction(pristine_id, pristine_ld, res)
canon = res.get("_canonical_after", {})
for rel in CANONICAL_FILES:
body = canon.get(rel)
if body is None:
continue
pristine_body = (pristine_snapshot / rel).read_text(errors="replace")
if semantic_key(body, rel) == semantic_key(pristine_body, rel):
continue # no SEMANTIC change (cosmetic-only edit) -> untouched
grp = per_file_groups[rel].setdefault(
semantic_key(body, rel), {"agents": [], "body": body}
)
grp["agents"].append(res["agent_id"])
conflicts: list[dict] = []
# Detect cross-file divergence: some agents adapted ledger, others changed
# identity. Those are logically incompatible fixes even if each file alone
# has agreement -- integrating both yields a still-broken (or double-broken)
# tree.
dir_values = set(directions.values())
if DEMO_PROFILE == "keyring":
# Divergence = agents converged on DIFFERENT key ids (or split within an
# agent). More than one distinct 'kid:*' choice across the fleet, or any
# 'kid_split', means the fleet did not agree on the key.
kid_choices = {d for d in dir_values if d.startswith("kid:")}
cross_file_divergence = len(kid_choices) > 1 or "kid_split" in dir_values
else:
cross_file_divergence = (
"adapt_ledger" in dir_values and "change_identity" in dir_values
)
for rel in CANONICAL_FILES:
groups = per_file_groups[rel]
if not groups:
continue # nobody semantically changed this file; pristine stays
if len(groups) == 1:
# All agents who touched this file agree on the field ORDER -> clean
# merge. Apply one representative body (they are semantically equal).
(grp,) = groups.values()
(integration_repo / rel).write_text(grp["body"])
else:
# Genuinely different field orders for the SAME file -> real conflict.
versions = {g["body"]: g["agents"] for g in groups.values()}
conflicts.append(
{
"file": rel,
"kind": "same_file_divergent_edits",
"distinct_orders": [
list(k[1:]) if k[0] == "order" else "unparseable"
for k in groups
],
"agents": {i: g["agents"] for i, g in enumerate(groups.values())},
}
)
(integration_repo / rel).write_text(_conflict_markers(rel, versions))
if cross_file_divergence and not conflicts:
# Divergent fixes that don't compose: the fleet disagreed on the value the
# two files must share (the field order, or the key id). Applying both
# leaves the integrated tree mismatched. Record it and mark the ledger file.
detail = (
"agents converged on different key ids / a service was left split; "
"the choices are incompatible and do not compose."
if DEMO_PROFILE == "keyring"
else "some agents adapted the ledger, others changed identity; "
"the two fixes are logically incompatible and do not compose."
)
conflicts.append(
{
"file": " + ".join(CONTESTED_FILES),
"kind": "cross_file_divergent_choices",
"detail": detail,
}
)
# Force the integrated tree RED by conflict-marking the ledger config so a
# divergent fleet cannot masquerade as green.
ld_rel = CONTESTED_FILES[1]
ld_versions = {
g["body"]: g["agents"]
for g in per_file_groups[ld_rel].values()
}
if len(ld_versions) >= 1:
(integration_repo / ld_rel).write_text(_conflict_markers(ld_rel, ld_versions))
# Run the tests on the integrated tree (ground truth for the fleet outcome).
try:
proc = runner._run_tests(integration_repo)
integrated_pass = proc.returncode == 0
test_tail = (proc.stdout + "\n" + proc.stderr)[-1200:]
except subprocess.TimeoutExpired:
integrated_pass = False
test_tail = "TIMEOUT"
result = {
"integrated_tests_pass": integrated_pass,
"merge_conflicts": conflicts,
"conflict_count": len(conflicts),
"cross_file_divergence": cross_file_divergence,
"fix_directions": directions,
"integrated_test_tail": test_tail,
}
# [keyring profile] Out-of-band PRODUCTION-CONFORMANCE replay: even a
# locally-green integration is only production-SAFE if the integrated ledger
# still verifies the already-issued production tokens. This corpus lives in
# the harness, in no checkout, so no agent could have fit to it.
if DEMO_PROFILE == "keyring":
if integrated_pass:
# Read PROD_CORPUS from the env at CALL time, not the import-time module
# constant -- in an N-trial run the corpus path changes every trial, so
# a stale import-time value would replay against the wrong trial's tokens.
corpus_path = os.environ.get("PROD_CORPUS", PROD_CORPUS_PATH)
replay = _production_replay(integration_repo, Path(corpus_path))
result["production_replay"] = replay
result["prod_replay_pass"] = bool(replay.get("ok")) if replay.get("ran") else None
else:
# Tree is already red; no point replaying, but record why.
result["production_replay"] = {"ran": False, "reason": "integrated tree is red"}
result["prod_replay_pass"] = None
return result
def _conflict_markers(rel: str, versions: dict) -> str:
"""Produce a git-style conflict-marked file body from divergent versions, so
the integrated tree genuinely fails to compile (a real, not simulated,
conflict)."""
bodies = list(versions.keys())
head, *rest = bodies
chunks = [f"<<<<<<< fleet-integration ({rel})\n", head]
for i, b in enumerate(rest, 1):
chunks.append(f"\n======= divergent-agent-edit-{i}\n")
chunks.append(b)
chunks.append("\n>>>>>>> end-of-conflict\n")
return "".join(chunks)
# --- Memory-layer pre-warm + liveness ----------------------------------------
# A neutral warm-up query. Deliberately describes the FAILURE in the agent's own
# words rather than anything key-specific, so pre-warming cannot leak the answer
# or advantage any arm: it is the same probe text for every competitor, and its
# RESULT is discarded. Only "did the backend answer" is kept.
_PREWARM_QUERY = (
"identity issuer and ledger verifier have no signing key id selected after "
"the externalize-secrets refactor, so every charge fails verification"
)
def _prewarm_memory_layer(mode: str) -> dict:
"""Build/ingest this arm's memory store ONCE, single-threaded, before the
fleet spawns and before any paid token is spent.
Returns {attempted, ok, error, seconds}. Never raises: a failure here must
be RECORDED (so the arm can be reported memory_unavailable) rather than
crash the experiment or, worse, silently become a competitor's "loss".
"""
tool_name = ARM_MEMORY_TOOL.get(mode)
if tool_name is None: # anarchy -- no memory layer by design
return {"attempted": False, "ok": True, "error": "", "seconds": 0.0}
registry = {
"vestige_backfill": getattr(runner, "VESTIGE_TOOL", {}),
"rag_search": getattr(runner, "RAG_TOOL", {}),
"mem0_search": getattr(runner, "MEM0_TOOL", {}),
"supermemory_search": getattr(runner, "SUPERMEMORY_TOOL", {}),
"hindsight_search": getattr(runner, "HINDSIGHT_TOOL", {}),
"zep_search": getattr(runner, "ZEP_TOOL", {}),
}.get(tool_name, {})
entry = registry.get(tool_name)
if not entry:
return {"attempted": True, "ok": False,
"error": f"no tool registered for {tool_name}", "seconds": 0.0}
fn = entry[0]
# vestige_backfill takes no query (empty schema); every competitor tool
# requires one.
call_args: dict = {} if tool_name == "vestige_backfill" else {"query": _PREWARM_QUERY}
_log(f" pre-warming {mode} memory layer via {tool_name} ...")
started = time.time()
try:
out = str(fn(Path("."), call_args))
except Exception as exc: # noqa: BLE001
secs = round(time.time() - started, 1)
return {"attempted": True, "ok": False,
"error": f"{type(exc).__name__}: {exc}"[:300], "seconds": secs}
secs = round(time.time() - started, 1)
kind, detail = _classify_retrieval(out)
if kind in ("error", "empty_store"):
# "index empty" during PRE-WARM means the store did not get populated --
# exactly the condition pre-warm exists to catch, so it must fail here
# rather than surface later as a competitor "loss".
return {"attempted": True, "ok": False,
"error": (detail or out.strip().split("\n")[0])[:300], "seconds": secs}
_log(f" pre-warm OK ({mode}/{tool_name}, {secs}s, {len(out)} chars returned)")
return {"attempted": True, "ok": True, "error": "", "seconds": secs}
# --- Fleet driver ------------------------------------------------------------
def run_fleet(mode: str, base_repo: Path, out_path: Path) -> None:
if mode not in FLEET_MODES:
runner.fail(f"unknown fleet mode '{mode}' (use {'|'.join(FLEET_MODES)})")
pristine = base_repo / ".repo-snapshot"
if not pristine.is_dir():
runner.fail(
f"no pristine snapshot at {pristine}. Run reset-repo.sh once to "
"capture the broken state before a fleet run."
)
# Sanity: the base repo must ship RED, and RED for the RIGHT reason -- the
# intended torture bug, not an unrelated failure (missing deps, a compile
# error). Any of these off => refuse, so we never spend paid tokens on a repo
# whose RED is not the torture bug.
if DEMO_PROFILE == "keyring":
# keyring: both services must have a BLANK key id (the unset-by-refactor
# base state). If either is already set, the bug isn't present.
active = _extract_kid((base_repo / CONTESTED_FILES[0]).read_text(), "activeKid")
trusted = _extract_kid((base_repo / CONTESTED_FILES[1]).read_text(), "trustedKid")
if active is None or trusted is None:
runner.fail(
"could not parse activeKid/trustedKid from the base repo config "
"files -- the keyring torture repo is not in the expected shape."
)
if active or trusted:
runner.fail(
f"base repo key ids are already set (activeKid={active!r}, "
f"trustedKid={trusted!r}) -- the unset-key torture bug is not "
"present. Restore the blank base state before a fleet run."
)
# LEAK AUDIT (the safeguard that would have caught the .fixtures leak):
# the correct key id MUST NOT be derivable from anything an agent can
# read. Scan every checkout-visible file for the correct kid or its key
# material appearing anywhere OTHER than the neutral keyring map, and for
# the production corpus. Any hit => refuse the paid run.
correct_kid = os.environ.get("CORRECT_KID", "k_borealis")
leaks = _keyring_leak_audit(base_repo, correct_kid)
if leaks:
runner.fail(
"LEAK AUDIT FAILED -- the correct answer is derivable from the "
"repo, so an agent can 'solve' it without memory and there is no "
"contrast. Remove these leaks before any paid run:\n - "
+ "\n - ".join(leaks)
)
else:
base_id_order = _canonical_order((base_repo / CONTESTED_FILES[0]).read_text())
base_ld_order = _canonical_order((base_repo / CONTESTED_FILES[1]).read_text())
if base_id_order is None or base_ld_order is None:
runner.fail(
"could not parse the canonical field order from the base repo's "
f"{CONTESTED_FILES[0]} / {CONTESTED_FILES[1]} -- the torture repo "
"is not in the expected shape."
)
if base_id_order == base_ld_order:
runner.fail(
"base repo canonical orders MATCH "
f"(identity={base_id_order}, ledger={base_ld_order}) -- the "
"canonical-digest drift is not present, so this is not the torture "
"bug. Restore the drift (reset-repo.sh) before a fleet run."
)
try:
pre = runner._run_tests(base_repo)
if pre.returncode == 0:
runner.fail(
"base repo tests PASS before the run -- the torture bug is not "
"present (repo is green). A fleet run against a green repo is "
"meaningless. Restore the torture bug first."
)
blob = (pre.stdout + "\n" + pre.stderr).lower()
drift_signals = ("500", "signature", "err_assertion", "no active", "no trusted", "key")
looks_like_drift = any(s in blob for s in drift_signals)
looks_like_tooling = (
"command not found" in blob
or "cannot find module" in blob
or "code 127" in blob
or "tsx: not found" in blob
)
if looks_like_tooling or not looks_like_drift:
runner.fail(
"base repo is RED, but the failure does not look like the intended "
"torture bug (no expected signal, or a tooling/deps error was "
"detected). Refusing to spend paid tokens on the wrong RED. Test "
"output tail:\n" + (pre.stdout + "\n" + pre.stderr)[-600:]
)
except subprocess.TimeoutExpired:
runner.fail("base repo test run timed out during the pre-flight check.")
bus: SharedBus | None = None
if mode == "sync":
data_dir = os.environ.get("VESTIGE_DATA_DIR", "")
vbin = os.environ.get("VESTIGE_BIN", "vestige")
if not data_dir:
runner.fail("sync mode needs VESTIGE_DATA_DIR (the shared bus DB).")
bus = SharedBus(data_dir, vbin)
work_root = Path(tempfile.mkdtemp(prefix=f"fleet-{mode}-"))
checkouts: list[Path] = []
# DEFENSE IN DEPTH: physically strip demo-infrastructure from every agent
# checkout so the answer never sits on disk in the agent's directory, even
# if a future tool gap bypassed runner's read guards. The seed script names
# the correct key; the snapshot/demo-db are harness internals. The agent's
# answer must come ONLY from the vestige_backfill tool (sync) or nowhere
# (anarchy) -- never from a file it could read/grep/cat.
_CHECKOUT_IGNORE = shutil.ignore_patterns(
".vestige-seed.sh", ".vestige-demo-db", ".vestige-demo-data",
".repo-snapshot", ".fixtures", "prod-corpus", "*.db",
)
for i in range(FLEET_SIZE):
co = work_root / f"agent-{i}"
shutil.copytree(pristine, co, symlinks=True, ignore=_CHECKOUT_IGNORE)
# The checkout must be able to run tests: link node_modules from the base
# repo so we don't npm install N times.
base_nm = base_repo / "node_modules"
if base_nm.is_dir():
try:
(co / "node_modules").symlink_to(base_nm.resolve())
except OSError:
# Fallback: some workspaces need real dirs; copy if symlink fails.
shutil.copytree(base_nm, co / "node_modules", symlinks=True)
checkouts.append(co)
# Transcripts land next to the result JSON (results/), one file per agent, so
# the on-camera proof of what each agent saw + did lives alongside the numbers.
transcript_dir = out_path.parent
_log(f"== FLEET {mode.upper()} == size={FLEET_SIZE} provider={runner.PROVIDER} model={runner.MODEL}")
_log(f" work_root={work_root}")
_log(f" transcripts -> {transcript_dir}/transcript-{mode}-a*.json")
# --- PRE-WARM THE MEMORY LAYER (before any paid turn) -----------------
# Vestige's arm has always been seeded BEFORE the loop (run-sync.sh runs
# .vestige-seed.sh in the shell and exits loudly on failure), while every
# competitor built its store INSIDE the agent's first tool call. That single
# asymmetry produced three separate defects:
# 1. TIMEOUTS -- mem0's ingest measured 563.6s ($0 liveness probe,
# Jul 20 2026); running that inside a bounded tool call returns an
# ERROR string that the scoreboard then counts as a retrieval loss.
# Pre-warmed, the same mem0 query answers in 0.16s.
# 2. AN INGEST RACE -- FLEET_SIZE threads each hit an unlocked
# check-then-set guard and ingested the same corpus concurrently.
# 3. A BUDGET ASYMMETRY -- competitors burned turns on setup that Vestige
# never paid for.
# Warming single-threaded here fixes all three, and makes the arm's health
# observable BEFORE a single token is spent.
prewarm = _prewarm_memory_layer(mode)
if prewarm.get("attempted") and not prewarm.get("ok"):
_log(f" !! PRE-WARM FAILED for {mode}: {prewarm.get('error')}")
_log(" This arm's memory layer is NOT answering. Continuing so the")
_log(" run records it, but the result will be marked")
_log(" memory_unavailable rather than scored as a retrieval loss.")
t0 = time.time()
agent_results: list[dict] = []
# Agents run concurrently -- that is the point of a fleet. In sync mode the
# shared-bus WRITES serialize under the bus lock; READS (backfill) are fine
# concurrently.
with ThreadPoolExecutor(max_workers=FLEET_SIZE) as pool:
futs = {
pool.submit(_run_one_agent, mode, f"a{i}", checkouts[i], bus, transcript_dir): i
for i in range(FLEET_SIZE)
}
for fut in as_completed(futs):
i = futs[fut]
try:
res = fut.result()
except (Exception, SystemExit) as exc: # noqa: BLE001
# _run_one_agent already catches turn/tool errors internally and
# returns a partial result WITH the tokens it spent, so this path
# is only for a truly unexpected crash. We cannot recover the
# spent-token count here (it died before returning) -- flag that
# honestly rather than silently reporting 0 as if nothing was
# billed.
res = {
"agent_id": f"a{i}",
"mode": mode,
"status": "errored",
"error": f"{type(exc).__name__}: {exc}",
"tokens": {"input": 0, "output": 0, "total": 0},
"tokens_uncounted": True, # real spend may be > 0; unrecoverable
"iterations": 0,
"wall_clock_seconds": 0.0,
"_canonical_after": {},
}
agent_results.append(res)
_log(
f" agent {res['agent_id']}: status={res.get('status')} "
f"tokens={res.get('tokens', {}).get('total')} "
f"iters={res.get('iterations')} local_pass={res.get('local_tests_pass')}"
)
fleet_wall = time.time() - t0
agent_results.sort(key=lambda r: r["agent_id"])
# Integrate the fleet's edits into one shared tree and get the real outcome.
integration_repo = work_root / "_integration"
integ = _integrate(agent_results, integration_repo, pristine, node_modules_source=base_repo)
# Strip the heavy internal field before serializing.
for r in agent_results:
r.pop("_canonical_after", None)
total_in = sum(r["tokens"]["input"] for r in agent_results)
total_out = sum(r["tokens"]["output"] for r in agent_results)
total_iters = sum(r.get("iterations", 0) for r in agent_results)
cost = (total_in / 1_000_000) * runner.COST_PER_MTOK_INPUT + (
total_out / 1_000_000
) * runner.COST_PER_MTOK_OUTPUT
n_fixed_local = sum(1 for r in agent_results if r.get("local_tests_pass"))
directions = integ["fix_directions"]
n_errored = sum(1 for r in agent_results if r.get("status") == "errored")
any_uncounted = any(r.get("tokens_uncounted") for r in agent_results)
n_used_backfill = sum(1 for r in agent_results if r.get("used_vestige_backfill"))
n_used_log = sum(1 for r in agent_results if r.get("used_vestige_log"))
# Arm-agnostic memory-layer health, aggregated across the fleet. The arm is
# only considered ALIVE if at least one agent's memory tool returned real
# data; an arm where every call errored is memory_unavailable, not a loss.
n_mem_alive = sum(1 for r in agent_results if r.get("memory_layer_alive"))
retrieval_ok_total = sum(int(r.get("retrieval_ok_count") or 0) for r in agent_results)
retrieval_err_total = sum(int(r.get("retrieval_err_count") or 0) for r in agent_results)
retrieval_empty_total = sum(int(r.get("retrieval_empty_count") or 0) for r in agent_results)
retrieval_error_samples: list[str] = []
for r in agent_results:
for msg in (r.get("retrieval_errors") or []):
if msg not in retrieval_error_samples:
retrieval_error_samples.append(msg)
memory_layer_alive_fleet = n_mem_alive > 0
if ARM_MEMORY_TOOL.get(mode) is not None and not memory_layer_alive_fleet:
_log(f" !! MEMORY LAYER DEAD for arm '{mode}': "
f"{retrieval_err_total} retrieval calls, ALL errored, 0 succeeded.")
for msg in retrieval_error_samples[:3]:
_log(f" {msg}")
_log(" -> this arm's result is memory_unavailable, NOT a retrieval loss.")
ip = integ["integrated_tests_pass"]
if DEMO_PROFILE == "keyring":
# Correct = converged on the true production key id; wrong = any other
# committed kid; the rest (split/unset) are neither.
correct_kid = os.environ.get("CORRECT_KID", "k_borealis")
n_correct_dir = sum(1 for d in directions.values() if d == f"kid:{correct_kid}")
n_wrong_dir = sum(
1 for d in directions.values()
if d.startswith("kid:") and d != f"kid:{correct_kid}"
)
prod_ok = integ.get("prod_replay_pass")
# Verdict combines integration-green AND production-conformance. A
# locally-green build that voids production tokens is the money-shot
# failure the whole demo is about.
if ip and integ["conflict_count"] == 0 and prod_ok is True and n_wrong_dir == 0:
fleet_verdict = "fixed_correctly"
elif ip and prod_ok is False:
fleet_verdict = "green_but_voids_prod" # passing build, dead production
elif ip and n_wrong_dir > 0:
fleet_verdict = "green_but_voids_prod"
elif not ip and integ["conflict_count"] > 0:
fleet_verdict = "failed_merge_conflict"
elif not ip:
fleet_verdict = "failed_still_red"
else:
fleet_verdict = "fixed_correctly"
else:
# canonical profile (torture-v2)
n_correct_dir = sum(1 for d in directions.values() if d == "adapt_ledger")
n_wrong_dir = sum(1 for d in directions.values() if d == "change_identity")
# The honest fleet verdict COMBINES the integration outcome with the fix
# DIRECTION -- npm test alone cannot see that a unanimously wrong-direction
# fix is wrong (green while invalidating already-minted production tokens).
if ip and n_wrong_dir == 0 and integ["conflict_count"] == 0:
fleet_verdict = "fixed_correctly"
elif ip and n_wrong_dir > 0:
fleet_verdict = "green_but_wrong_direction"
elif not ip and integ["conflict_count"] > 0:
fleet_verdict = "failed_merge_conflict"
elif not ip:
fleet_verdict = "failed_still_red"
else:
fleet_verdict = "fixed_correctly"
result = {
"mode": mode,
"fleet_size": FLEET_SIZE,
"provider": runner.PROVIDER,
"model": runner.MODEL,
"task": runner.TASK,
"repo": str(base_repo),
"measured": True,
"fleet_tokens": {
"input": total_in,
"output": total_out,
"total": total_in + total_out,
},
"fleet_cost_usd": round(cost, 6),
"cost_rate": {
"input_per_mtok": runner.COST_PER_MTOK_INPUT,
"output_per_mtok": runner.COST_PER_MTOK_OUTPUT,
},
"fleet_wall_clock_seconds": round(fleet_wall, 2),
"fleet_iterations_total": total_iters,
"agents_local_pass": n_fixed_local,
"agents_errored": n_errored,
"tokens_uncounted": any_uncounted, # true if any errored agent's spend is unrecoverable
# Coordination proof: how many agents consulted the shared Vestige hub.
# In sync mode this should be the whole fleet; in anarchy it is always 0
# (the tools aren't even offered), which is the point.
"agents_used_vestige_backfill": n_used_backfill,
"agents_used_vestige_log": n_used_log,
# --- ARM-AGNOSTIC MEMORY-LAYER HEALTH (fairness-critical) ----------
# These fields exist so this arm's number can never again be published
# without disclosing whether its memory backend actually answered.
# memory_layer_alive=False means the arm did NOT lose on retrieval
# quality -- it did not run. Report it as memory_unavailable / N/A,
# never aggregate it as a substantive defeat.
"memory_tool": ARM_MEMORY_TOOL.get(mode),
"memory_prewarm": prewarm,
"agents_memory_alive": n_mem_alive,
"retrieval_ok_total": retrieval_ok_total,
"retrieval_err_total": retrieval_err_total,
# Backend answered but found nothing relevant. Distinct from an error --
# this is a real retrieval outcome, not a dead arm.
"retrieval_empty_total": retrieval_empty_total,
"retrieval_error_samples": retrieval_error_samples[:5],
"memory_layer_alive": memory_layer_alive_fleet,
"memory_unavailable": (
ARM_MEMORY_TOOL.get(mode) is not None and not memory_layer_alive_fleet
),
"transcripts": [
f"transcript-{mode}-{r['agent_id']}.json" for r in agent_results
],
"demo_profile": DEMO_PROFILE,
"fix_direction_counts": {
"correct": n_correct_dir,
"wrong": n_wrong_dir,
"other": FLEET_SIZE - n_correct_dir - n_wrong_dir,
},
# THE honest headline: integration outcome AND correctness (direction for
# canonical; production-conformance for keyring).
"fleet_verdict": fleet_verdict,
# did the fleet's INTEGRATED work make npm test pass? (necessary, not
# sufficient -- read alongside fleet_verdict + fix_direction_counts.)
"integrated_tests_pass": integ["integrated_tests_pass"],
# [keyring] out-of-band production-conformance replay result.
"prod_replay_pass": integ.get("prod_replay_pass"),
"production_replay": integ.get("production_replay"),
"merge_conflict_count": integ["conflict_count"],
"merge_conflicts": integ["merge_conflicts"],
"cross_file_divergence": integ["cross_file_divergence"],
"fix_directions": directions,
"reasoning_effort": (
os.environ.get("OPENAI_REASONING_EFFORT", "xhigh")
if runner.PROVIDER == "openai"
else None
),
"truncated": bool(getattr(runner.OpenAIProvider, "saw_truncation", False)),
"agents": agent_results,
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
}
out_path.write_text(json.dumps(result, indent=2))
print(json.dumps(result, indent=2))
# Leave the work_root for inspection but note it; the caller may clean it.
_log(f" (fleet work tree left at {work_root} for inspection)")
def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("--mode", required=True, choices=list(FLEET_MODES))
ap.add_argument("--repo", required=True)
ap.add_argument("--out", required=True)
args = ap.parse_args()
repo = Path(args.repo).resolve()
if not repo.is_dir():
runner.fail(f"repo not found: {repo}")
run_fleet(args.mode, repo, Path(args.out).resolve())
if __name__ == "__main__":
main()