Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bench/bashloop/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# bashloop — the arm bench for the bash-only task loop

Wave 3 of the bash-task-loop experiment
A harness for the bash task loop
(DESIGN.md): the same briefs run
on both belts — arm A with `CODEAF_TASK_BELT=node` (the older belt),
arm B with `CODEAF_TASK_BELT=bash` — n replicates, cells interleaved so the
Expand Down
8 changes: 4 additions & 4 deletions bench/conversation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ from, are in `lib/adapters.sh`:
| arm | interactive door | markers from |
|---|---|---|
| codeaf | yes | `internal/tui3/render.go` (`stateWord`, `waitingWord`) — the renderer itself, checked against a live pane |
| pi | yes | live pane capture on pi 0.84.2 in this lane; the provider segment is derived from the provider in use, not hardcoded |
| omp | yes | live pane capture on omp 18.1.2 in this lane |
| pi | yes | live pane capture on pi 0.84.2; the provider segment is derived from the provider in use, not hardcoded |
| omp | yes | live pane capture on omp 18.1.2 |
| opencode | **no** | no calibrated markers — its interactive cells are `unsupported` |

## Open models only
Expand Down Expand Up @@ -179,7 +179,7 @@ parse, the cell comes back `cost unknown` and not-comparable rather than zero.
A harness that loads the operator's skills, extensions and MCP servers is not
running the task it was given: it is running that task plus whatever is
installed on that machine — extra tools, a longer system prompt, extra latency,
and a different set on every box. A live pane in this lane showed omp mounting
and a different set on every box. A live pane showed omp mounting
MCP tools and failing one of them out of `~/.claude.json`, and pi listing
thirty-odd skills out of `~/.agents/skills`.

Expand Down Expand Up @@ -483,7 +483,7 @@ record of what they were. A cell whose directory already exists refuses too, and
records a skip. `--overwrite` is the deliberate way, and `--out` gives a run a
directory of its own.

Live runs so far, all by the owner:
Recorded runs:

* `notes/pilot-01.md` — the first print-door cells, and why one of its three
costs is not usable.
Expand Down
2 changes: 1 addition & 1 deletion bench/conversation/lib/adapters.sh
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ arm_role_pin() {
#
# A harness that loads the machine's skills, extensions and MCP servers is not
# running the task it was given: it is running that task plus whatever the
# person who owns the machine installed. A live pane in this lane showed omp
# person who owns the machine installed. A captured pane showed omp
# mounting MCP tools and failing one of them from `~/.claude.json`, and pi
# listing thirty-odd skills from `~/.agents/skills` — extra tools, extra system
# prompt, extra latency, and none of it the same on two machines.
Expand Down
3 changes: 1 addition & 2 deletions bench/conversation/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -442,8 +442,7 @@ for scenario in $SCENARIOS; do
# Did the cell's only route upstream survive the cell? A guard that exits
# mid-run leaves the harness dialling a closed port, and everything after
# that — no reply, no file, no receipt — is about the rig and not about the
# harness. It has happened once in this lane (notes/pilot-02-03.md), and it
# arrived looking exactly like a product failure.
# harness. A failed guard can look exactly like a product failure.
guard_died=0
if [ "$DRY_RUN" != "1" ] && [ "$UNGUARDED" != "1" ] && ! guard_alive; then
guard_died=1
Expand Down
11 changes: 6 additions & 5 deletions bench/idle-surface/replay.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
# this run started, after reading the proc cmdline of each; never pkill/killall.
#
# Usage: replay.sh K [K ...] e.g. replay.sh 5 50 200
# Env: BASE (scratch root, default /tmp/codeaf-idle-runs), WIN (window secs).
# Env: TAR and STUB are required. REPO defaults to the repository root.
# BASE defaults to $REPO/bench/idle-surface/runs; WIN is window seconds.
set -u
REPO="/home/santosh/src/c286tree"
REPO="${REPO:-$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)}"
BIN="$REPO/bin/codeaf"
TAR="${TAR:-/home/santosh/src/profiles/fresh-codeaf.tar}"
STUB="${STUB:-/home/santosh/src/stub.py}"
BASE="${BASE:-/home/santosh/src/c286tree/bench/idle-surface/runs}"
: "${TAR:?Set TAR to a profile tar archive}"
: "${STUB:?Set STUB to a canned-stream server script}"
BASE="${BASE:-$REPO/bench/idle-surface/runs}"
PORT="${PORT:-8099}"
WIN="${WIN:-30}"
CLK_TCK=$(getconf CLK_TCK)
Expand Down
8 changes: 5 additions & 3 deletions bench/idle-surface/wait.sh
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
#!/usr/bin/env bash
# wait.sh - idle CPU of a chat surface that WAITS ON WORK IN FLIGHT, by K.
# Usage: wait.sh K:MODE [K:MODE ...] e.g. wait.sh 5:nodelta 5:stream 200:nodelta
# Env: TAR is required; REPO defaults to the repository root and BASE to
# $REPO/bench/idle-surface/runs. WIN is the sampling window in seconds.
# One row per point: K, mode, threads, idle %core (two 30s windows), RSS before
# and after the windows, stub POST counts (requests in flight during sampling),
# first-delta count (0 means no output arrived), pane state word.
set -u
REPO="/home/santosh/src/c286tree"
REPO="${REPO:-$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)}"
BIN="$REPO/bin/codeaf"
TAR="${TAR:-/home/santosh/src/profiles/fresh-codeaf.tar}"
: "${TAR:?Set TAR to a profile tar archive}"
STUB="$REPO/bench/idle-surface/stub-tunable.py"
BASE="${BASE:-/home/santosh/src/c286tree/bench/idle-surface/runs}"
BASE="${BASE:-$REPO/bench/idle-surface/runs}"
PORT="${PORT:-8099}"
WIN="${WIN:-30}"
CLK_TCK=$(getconf CLK_TCK)
Expand Down
73 changes: 0 additions & 73 deletions bench/oneroad/cell.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,13 @@ ISSUES="${ISSUES:-20 21 22 23}"
MODEL="${MODEL:-deepseek/deepseek-v4-flash}"
NEW_BIN="${NEW_BIN:-$HOME/af-oneroad/bin/codeaf}"
OLD_BIN="${OLD_BIN:-$HOME/af-oldbase/bin/codeaf}"
# WAVE 1B'S BINARY, AND IT IS A SNAPSHOT RATHER THAN THE LIVE PATH ON PURPOSE.
# bin/codeaf is rebuilt in place by whoever is working the tree, and wave 1's
# batch cells landed two minutes before one such rebuild — which is luck, not a
# protocol. A wave measured against "whatever bin/codeaf was at the moment each
# cell happened to launch" is a wave whose arm has no single identity, so the
# bytes are copied once, sha'd into results/BINARIES, and every cell of the arm
# runs that copy.
ESC_BIN="${ESC_BIN:-$ONEROAD/bin/codeaf-esc-b70de31c}"
# Wave 1c's binary, snapshotted for the same reason ESC_BIN is.
PRE_BIN="${PRE_BIN:-$ONEROAD/bin/codeaf-pre-9b9a4c92}"
# Wave 1d: the raced screen, the ski-rental checkpoints and the ceiling, together.
CKPT_BIN="${CKPT_BIN:-$ONEROAD/bin/codeaf-ckpt-6b9809e9}"
# Wave 1e: the finalist. Everything at once.
FINAL_BIN="${FINAL_BIN:-$ONEROAD/bin/codeaf-final-c0e4f5a7}"
PI_BIN="${PI_BIN:-pi}"
OPENCODE_BIN="${OPENCODE_BIN:-$HOME/.opencode/bin/opencode}"

# The wall. bench/run.sh's forty minutes, in seconds, because a cell past it is
# recorded as DNF rather than left to spend.
# Raised from 2400 after wave 1g: its task-road cells ran 2126-2315s, close
# enough to the old wall that the number being measured was starting to be the
# wall rather than the work. A wall has to sit far enough above the work that a
# row hitting it means something went wrong, not that the task was ordinary.
CELL_SECONDS="${CELL_SECONDS:-3600}"
# How long the surface must be completely silent before the turn is called
# settled. A task thinking between tool calls is silent for tens of seconds, so
Expand Down Expand Up @@ -211,38 +195,13 @@ PY
else
quiet=0
fi
# THE STORE IS AUTHORITATIVE PAST A HARD MULTIPLE OF THE WINDOW, and this is
# the second half of a lesson that cost two cells. The footer's hint was
# wrong in one direction ('esc interrupt' outliving the turn) and the spinner
# is wrong in the other: a cell whose store had been silent for sixteen
# minutes was still drawing 'working' and would have run to the wall. A pane
# is a rendering, not a fact. So the screen may DELAY a settle but it may not
# prevent one — past 3x the silence window the store's own silence decides.
# A LIVE TASK VETOES THE SETTLE, AND NO AMOUNT OF SILENCE OVERRIDES IT.
#
# This is the rule that was missing, and its absence destroyed six wave-1f
# cells. The quiet window is evidence about the CONVERSATION and says nothing
# whatever about a task: a worker that has just typed `pytest` writes nothing
# anywhere for minutes. The old rule read that silence as "finished", reaped
# the tmux session, and killed the worker in the middle of its test run —
# eighteen minutes of real work, nought files landed, judges scoring the
# emptiness. THE STORE GOING QUIET IS NOT A TASK FINISHING.
#
# lib/tasklive.py counts any state it does not recognise as LIVE, so the way
# this rule fails is by waiting — bounded by the hard wall above — rather
# than by killing, which is bounded by nothing and loses the work.
sess="$(find "$CELL/profile/v3/projects" -mindepth 2 -maxdepth 2 -type d 2>/dev/null | head -1)"
live=0; stranded_ids=""
if [ -n "$sess" ]; then
tl="$(python3 "$ONEROAD/lib/tasklive.py" "$sess" 2>/dev/null)"
live="$(printf '%s' "$tl" | python3 -c 'import json,sys
try: print(json.load(sys.stdin)["live"])
except Exception: print(0)' 2>/dev/null)"
# STRANDED IS NOT LIVE. A task in a live state whose own journal has not
# seen a request for the stranded window has stopped working without
# landing; counting it live pinned wave 1h's batch cells to the hard wall
# for 3100 dead seconds apiece. It is named here so the row can say WHICH
# task stranded rather than just that the cell ended badly.
stranded_ids="$(printf '%s' "$tl" | python3 -c 'import json,sys
try: print(",".join(str(i) for i in json.load(sys.stdin).get("stranded_ids") or []))
except Exception: print("")' 2>/dev/null)"
Expand Down Expand Up @@ -274,14 +233,6 @@ except Exception: print("")' 2>/dev/null)"
done
tmux capture-pane -t "$SESSION_NAME" -p > "$CELL/tmux-final.txt"
tmux capture-pane -t "$SESSION_NAME" -p -S -4000 > "$CELL/tmux-scrollback.txt"
# THE SESSION IS REAPED ONCE ITS EVIDENCE IS CAPTURED, and forgetting this cost
# wave 1 real money in contention: `codeaf chat` is an interactive surface that
# never exits on its own, so every settled cell left a live process and a live
# tmux session behind it. Fourteen of them were still resident when wave 1b
# fired, competing for the same CPU as the cells being measured — which makes
# every wall clock after the first wave quietly worse than the harness it is
# supposed to be measuring. Capture first, then reap: the panes above are the
# only thing in the session worth keeping, and the store is on disk already.
tmux kill-session -t "$SESSION_NAME" 2>/dev/null
if [ -f "$CELL/outcome_override" ]; then cp "$CELL/outcome_override" "$CELL/outcome"; else echo OK > "$CELL/outcome"; fi
return 0
Expand Down Expand Up @@ -314,28 +265,12 @@ case "$ARM" in
codeaf-new-flash) run_codeaf "$NEW_BIN" 1; CODE=$? ;;
codeaf-new-crew) run_codeaf "$NEW_BIN" 0; CODE=$? ;;
codeaf-old-flash) run_codeaf "$OLD_BIN" 1; CODE=$? ;;
# Wave 1b. Same two configurations as the new-* arms, same protocol, different
# bytes: the question is whether the mid-turn escalation teaching moves the
# road column, so everything except the binary has to be held still.
codeaf-esc-flash) run_codeaf "$ESC_BIN" 1; CODE=$? ;;
codeaf-esc-crew) run_codeaf "$ESC_BIN" 0; CODE=$? ;;
# Wave 1c. The pre-turn route judge resolves the screen and the confirm
# through the TIER ROWS, so the all-flash arm runs both readings on flash and
# the crew arm runs the screen on the shipped low tier and the confirm on the
# kimi mastermind. That difference is not noise to be controlled away — it is
# what the two arms are FOR, and it is recorded as part of the arm.
codeaf-pre-flash) run_codeaf "$PRE_BIN" 1; CODE=$? ;;
codeaf-pre-crew) run_codeaf "$PRE_BIN" 0; CODE=$? ;;
codeaf-ckpt-flash) run_codeaf "$CKPT_BIN" 1; CODE=$? ;;
codeaf-ckpt-crew) run_codeaf "$CKPT_BIN" 0; CODE=$? ;;
# Wave 1e. crew is the intended default — the mark-reader sidecar and the
# confirm are mastermind calls and are simply ABSENT on the all-flash pin,
# which is why that arm is the cost ablation and not a second opinion.
#
# NEITHER ARM WRITES A `routing` ROW. The new default is latency under a price
# ceiling for the turn and price for background calls, and pinning the row
# would measure the pin instead of the default. The profile writer below has
# never written that key; this comment is here so nobody adds it.
codeaf-final-crew) run_codeaf "$FINAL_BIN" 0; CODE=$? ;;
codeaf-1f-crew) run_codeaf "$ONEROAD/bin/codeaf-1f-0fabf058" 0; CODE=$? ;;
codeaf-1g-crew) run_codeaf "$ONEROAD/bin/codeaf-1g-ec52e7ae" 0; CODE=$? ;;
Expand All @@ -352,14 +287,6 @@ WALL=$(( $(date +%s) - STARTED ))
cut -d' ' -f1-3 /proc/loadavg > "$CELL/loadavg-after"
say "$ARM/$TASK: harness finished, exit $CODE, ${WALL}s"

# ── what it actually did ────────────────────────────────────────────────────
#
# THE PATCH IS THE LANDED DIFF, AND IT IS BUILT HERE RATHER THAN BY A LATER PASS.
# lib/landed.py existed since wave 1d but was only ever run as a one-off script
# afterwards, so wave 1h's cells were recorded with `git diff` alone — which is
# EMPTY once a task has committed and merged. Six landed files read as "no
# changes", the judges were handed that, and they scored the cells zero. Any
# measurement a row depends on has to be taken by the runner that writes the row.
CHANGED="$(changed_files "$DIR")"
python3 - "$DIR" "$BASE_COMMIT" "$CELL" "$ONEROAD/lib" <<'LANDED'
import os, sys
Expand Down
2 changes: 1 addition & 1 deletion bench/oneroad/finalize.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
bundle that the driver would have written, rather than throwing away a run
that has already been paid for.
2. BACKFILL. When a road column is added or corrected — `escalated` was added
after wave 1 had landed — every earlier cell can be re-read against the new
after a run has finished — every earlier cell can be re-read against the new
reader instead of being left with a blank column or, worse, re-run and
quietly compared against rows measured on a different day.

Expand Down
17 changes: 0 additions & 17 deletions bench/oneroad/grid.sh
Original file line number Diff line number Diff line change
@@ -1,25 +1,8 @@
#!/usr/bin/env bash
# grid.sh — the whole 25-cell wave-1 grid, driven by ONE detached process.
#
# IT IS DETACHED ON PURPOSE. The first attempt at this grid was launched from an
# interactive harness, and when that harness restarted it took every cell with
# it: fifteen cells mid-flight, no rows. A benchmark that a terminal closing can
# kill is a benchmark that has to be re-run every time somebody's editor
# crashes, so this is started under setsid and writes its own pid where a person
# who lost it can find it (results/PIDS).
#
# THE CAP AND THE WAVES. Five arms of one task fire together (wave.sh says why),
# and no more than MAX_WAVES tasks are in the air at once — five cells a wave, so
# three waves is fifteen cells, which is the honest ceiling for one machine whose
# cells spend their middles waiting on a provider and their ends running pytest.
set -uo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TASKS="${TASKS:-20 21 22 23 batch}"
MAX_WAVES="${MAX_WAVES:-3}"
# ARMS lets one grid run a SUBSET of the arms over the same tasks, which is what
# a follow-up wave is: wave 1b re-asks the identical five tasks of two new arms
# and must not re-run the eight rows that already landed. Empty is every arm,
# which is what wave 1 wanted.
ARMS="${ARMS:-}"

mkdir -p "$ROOT/results"
Expand Down
5 changes: 0 additions & 5 deletions bench/oneroad/lib/judge_bundle.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,6 @@ def main():
meta = json.load(open(os.path.join(cell, "meta.json")))
fixed, broken = changed_tests(cell)
patch = read(os.path.join(cell, "diff.patch"), PATCH_CAP).strip() or "no changes"
# STRANDED WORK IS SHOWN, AND IT IS SHOWN APART. A part that worked in its own
# worktree and never merged has delivered nothing, so it must not sit inside
# PATCH where it reads as the attempt's output — wave 1h put raw conflict
# markers in front of a judge that way. It is still worth showing: "the work
# exists and did not land" is a different verdict from "nothing was done".
stranded = read(os.path.join(cell, "stranded.patch"), PATCH_CAP).strip()
report = report_of(cell, meta).strip() or "(the attempt said nothing)"

Expand Down
11 changes: 5 additions & 6 deletions bench/oneroad/lib/landed.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
and it is correct for the words road: chat edits the checkout and leaves the
changes uncommitted. IT IS BLIND TO THE TASK ROAD. A task works in a git
worktree, COMMITS, and merges back — so the checkout comes out clean and the
cell records zero changed files over work that really happened. Wave 1d turned
cell records zero changed files over work that really happened. An earlier implementation turned
nine cells onto that road at once and every one of them was being under-read.

So the work is the union of two things:
Expand Down Expand Up @@ -59,7 +59,7 @@ def worktrees(cell):
A task does not edit the clone: it branches into its own worktree under the
session folder (`<session>/trees/<n>`), works there, commits, and merges home
only when it LANDS. So a cell whose task was still running — or was killed
while running, which is what the settle bug did to six wave-1f cells — has
while running, which is what the settle bug did to recorded cells — has
all of its work here and none of it in the clone. Measuring only the clone
reported those cells as "0 files changed" over eighteen minutes of real work.

Expand Down Expand Up @@ -108,7 +108,7 @@ def worktree_patch(cell):
def patch(repo, base):
"""THE PATCH A JUDGE GRADES: everything that landed on the person's branch.

THE RULE, and it is the one wave 1h got wrong. A judge is grading what the
A judge grades what the
attempt DELIVERED, and delivery means the clone's branch:

base..HEAD what a task committed and merged home, plus
Expand All @@ -117,9 +117,8 @@ def patch(repo, base):

NOTHING FROM A TASK WORKTREE APPEARS HERE. A part working in
`<session>/trees/N` that never merged has produced nothing the person can
use, and wave 1h's batch bundle proved how badly that reads when mixed in:
the judge was shown raw `<<<<<<< Updated upstream` conflict markers as if
they were the diff. Stranded work is real and worth recording, so it is
use. Raw conflict markers from an unmerged worktree must not appear in the
delivered diff. Stranded work is real and worth recording, so it is
written separately by [worktree_patch] under its own heading — never here.

The failure this replaces was quieter and worse: `git diff` alone is EMPTY
Expand Down
Loading
Loading