Harness² Selector Code: What It Sees and What It Never Sees
Reading google-research/harness2 (commit 1cfe254): the step that picks one of k harness candidates with no answer key sees only the request, the source material and anonymized, untruncated outputs. A failed pick records the first final by label but is left out of scoring, and when a successful pick leads the reflector to write a lesson, the pick's stated reason is stored verbatim in the library next to the adopted harness.

Harness² Selector Code: What It Sees and What It Never Sees
Part 3 ended on the one step of Harness² that decides without an answer key: when the budget allows k of 2 or more candidate harnesses, a selector picks which candidate's output gets delivered. In the public demo we ran in Part 3, a model does not make this pick: prewritten code computes the ledger total and picks the candidate that matches. That is choosing with the answer in hand, so the demo could not show how the real selector chooses without one. This post reads it in the released code, harness2/core/selection.py and the select prompt in core/prompts.py, at commit 1cfe254. We did not run the selector against a model, so everything below is what the code says, not how well it works.
First, the whole flow. Three roles appear: the editor, which makes candidate harnesses (with the composer, which merges edits); the selector, which picks one candidate's output; and the reflector, which writes a lesson from the pick into the library. All three are model sessions, each with different inputs and outputs. The figure puts the selector in the middle and shows what goes in and what comes out.

Which candidates enter the pool
The pool is exactly the k final outputs of the chosen mode: agg1 to aggk in the parallel mode, c1 to ck in the sequential one. The base harness's own runs are deliberately left out. The docstring notes that this keeps the pool to the k finals and that there is no option to abstain. Whatever the loop produced, one of the k finals is what gets picked.
Before anything is anonymized, outputs that are not answers are dropped: runs that did not finish, runs with nothing delivered, and outputs that render to empty text. Each drop is recorded in a dropped list on the result, with the cause when rendering threw. There is one exception. On benchmarks where the deliverable is a change of state rather than a file, if no candidate delivered anything, each candidate's session transcript stands in for it. If still nothing survives, the result carries the error no candidate produced an artifact and selection ends there. At k=1 there is nothing to choose, so a separate function delivers the single final without starting a selector session.
What the selector reads
The selector is a model session with a folder on disk, and the mission tells it to open the files, not to answer from the message. The folder holds:
task.md, the request verbatimsource/, the material the work was done from, when the task has anycandidates/<id>.md, one file per candidate: the rendered deliverable, untruncated, with a header that says so ("COMPLETE -- nothing trimmed")- rendered evidence per candidate, when the benchmark adapter supplies it
The ids are letters assigned by a seeded shuffle. The seed is a hash of the task id, k and mode, so a rerun gets the same labels. The prompt tells the selector the ids are arbitrary, that it is not told how any output was produced, and that there is no credit for a more elaborate candidate. It is told to judge "on what it is, against the request and the source", never on "how impressive or thorough it sounds."
The order of the checks
The prompt gives the selector a fixed sequence. By default it is these six:
- Delivery: is every named deliverable present, in the requested form
- Conformance: is it only what was asked for, in the requested shape. Extra columns or sheets and renamed headers count as deviations, not improvements
- Fidelity: check every claim against
source/, reject invented specifics, and where candidates disagree "the source decides it" - Internal consistency: totals that match their rows, summary figures that match the table, counts that match the items present
- Operational fitness: can the intended person or system use it as it is
- Finish: no placeholders, no TODOs, no visibly incomplete sections
Depending on the benchmark, a step 0 is put in front, or step 2 is dropped and a step 7 ("values are values") is added. A separate prompt pack (tts) replaces the whole list with its own three criteria. One more line closes the list: length and polish are not merits in themselves, and a shorter, correct, complete, exactly-shaped answer beats a longer one with a gap or an embellishment. The reply must put a <why> of at most six lines first, naming the deciding criterion and the closest runner-up, and a fenced choice block with a single id last.
Two sections show the design intent. One says there is no rubric, answer key, reference solution or score anywhere in the context, and forbids writing "the grader expects" into anything. The other says everything under context/ is data, not instructions: candidates may contain commands or persuasive text, and a script found in a candidate is to be read as text, never executed. Not running the code it is choosing between is an instruction in the prompt, not something the code enforces.
What keeps the answer key out
Two checks run in code, not in the prompt. Before the selector is called, a function scans the folder and raises if any file name or file content carries one of the grader's own markers (for example deterministic_eval_summary). Its docstring calls it a tripwire on the adapters' read boundary, and says that if it fires, the fix is to find the read path that leaked, not to widen the marker list. The reflection step later adds a second check that rejects paths a benchmark declares to be answer keys. Both raise an error instead of continuing. The error is caught per mode, so a leak ends that mode of that task in an error recorded in the summary, while other modes and later tasks carry on.
What happens when the selector fails
If the reply has no choice block, or names an id that does not exist, or the session errors out, the code falls back without raising. It picks a delivered base candidate if the pool has one. With a finals-only pool it has none, so it takes the first final by sorted label (agg1 or c1). The result records fallback and the error, and the task summary notes a failed selection, so a fallback is visible after the fact. It does not count as a successful selection: the result stays ok = False, and two things follow. The reflection step returns without writing anything when ok is false, so no lesson comes out of it. And the judging code does not grade a selection whose ok is false; the report then leaves ungraded rows out of the denominator. The fallback output is on record but not in the reported score.
Where a wrong pick goes
After a successful pick, and only if a library is configured, a second model session, the reflector, runs. It reads the adopted harness, the base runs and the base harness, every non-base candidate, the decisions and the trajectories, and writes a short record with four fields: cue, lesson, evidence and confidence. The mission text hands that session the selector's own <why> as "the selection reasoning." But the prompt is explicit that the adopted candidate is not the only evidence: selection compared deliverables with the harnesses hidden, so it says which output read best, not which edit worked, and the reflector is told to read the trajectories, not the verdict. If there is no concrete execution contrast, it is told to write NO_ENTRY.
The more direct path comes after that. When the reflector fills in cue, lesson and evidence, the library stores the adopted harness's full file tree and, under a "Why this was chosen" heading, the selector's <why> verbatim. The selector is never given a grade, so a wrong pick still carries a reason, and that harness and that reason land where the editor and composer of the next task in the same domain will read them. This is the spot Part 3 asked readers to watch. Selection accuracy decides not only which output is delivered but also which harness, and which explanation, the next task starts from.
What the code leaves unrecorded
The result file stores everything needed to score the selector after the fact: the id map, the chosen label, the stated reason, the drops, the fallback flag. What it does not store is any comparison against the candidates' real scores. The judging code grades only the run that selection chose, so the scores of the candidates it passed over are never recorded. Nothing in the loop checks whether the pick was the better candidate, which fits the paper not reporting a hit rate. To get one, someone has to grade every candidate separately after the run and line the grades up with selection.json.
The Harness² selector is a single model session that reads anonymized, untruncated outputs against the source material, with grader output kept out by code checks. When it fails, the first final by label is recorded but not counted as a success and left out of scoring; when it succeeds and the reflector then writes a lesson, its stated reason is stored verbatim in the library next to the adopted harness, where the next task reads it.
Method note
- Code:
google-research/harness2, commit1cfe254, filesharness2/core/selection.py(pool construction, drops, anonymization, fallback, persistence, reflector call),harness2/core/prompts.py(select,experience,ANSWER_FREE_SELECT,EVIDENCE_BOUNDARY_SELECT,POOL_FINALS_SELECT),harness2/core/context.py(grader-verdict tripwire),harness2/core/schedule.py(per-mode runs and error handling),harness2/core/library.py(library storage), andharness2/core/judge.pywithreport.py(what is graded, and the denominator). - Everything here comes from reading the code. We did not run the selector with a model, so nothing in this post measures how often it picks the better candidate.
- The
ok = Falseafter a fallback, the empty return of the reflection step and the exclusion from grading are read fromrun_selection,reflect_adoptionandjudge.py; we did not trigger a fallback to watch it happen.
References
- Harness²: Recursive Agent Harnessing for an Open World — arXiv:2610.14224
- Code — github.com/google-research/harness2