Daily

Daily Lab · recorded replay · run keyed-fallback-v1 · sandbox

keyed-fallback-v1

Rejected

protocol-exclusivity: 0/4 cases satisfied, threshold 1Under the current criteria, generation 2. This run faced generation 1 when it executed — both verdicts are below.

Keyed association with a positional fallback: prefers article ids when the response carries them, and associates by position when it does not. Written for this experiment to be plausible rather than correct.

01

Verdict

2 criteria generations

Criteria generation

spec f027762ab4d08b35

This verdict moved between generations. The candidate satisfied every criterion it faced; the criteria were the thing that was incomplete. Nothing was re-executed to produce the second verdict — grading is a function of the records and a spec, so both were computed from the same run.

  • v1Accepted for review
  • v2Rejected
Rejected

protocol-exclusivity: 0/4 cases satisfied, threshold 1

Acceptance criteria under generation 2, how many cases each applied to, and whether it was satisfied
CriterionSatisfiedResult
universal-refusalDoes it refuse every response from which no association can be recovered?48/48met
association-exactOn its own protocol, does every article receive exactly the verdict it was given?3/3met
protocol-violation-refusalDoes it refuse duplicate, unknown, missing ids and unusable scores?9/9met
no-crashDoes it terminate on every case without crashing or hanging?60/60met
complete-evidenceIs there a prediction record for every applicable case?60/60met
protocol-exclusivityOn cases outside its declared protocol, does it refuse rather than associate anyway?0/4not met

Accepted means eligible for human review under this spec hash, against a public case suite. It is not evidence of production quality, and it does not establish generalisation: the cases are visible and a candidate may have been written against them.

03

The patch

against positional_v0.py
Unified diff · 178 lines · applies with git apply
diff --git a/backend/lab/contract/versions/positional_v0.py b/backend/lab/contract/candidates/keyed_fallback_v1.py--- a/backend/lab/contract/versions/positional_v0.py+++ b/backend/lab/contract/candidates/keyed_fallback_v1.py@@ -1,29 +1,33 @@-"""Historical behaviour, transcribed from `origin/main`.--Source: backend/app/services/openai_service.py, score_articles_batch, the-`normalized` loop. Verbatim semantics:--    if len(results_list) != len(articles):-        logger.warning("... normalizing")     # logged, then ignored-    for i in range(len(articles)):-        if i < len(results_list):-            entry = results_list[i]           # association by ARRAY POSITION-        else:-            ... {"relevant": False, "score": 0.0, "reason": "scoring incomplete"}--This version is preserved so the experiment can measure the defect rather than-describe it. It is not a control: it is what production does today.+"""A candidate parser: keyed association with a positional fallback.++Written for this experiment rather than transcribed from a revision, and+written to be *plausible* rather than to be correct. The instinct it encodes+is a real one and a good one in most contexts -- be liberal in what you+accept, do not discard work you can still make sense of -- applied to a+problem where it is exactly wrong.++The reasoning goes: keyed association is better, so prefer it; but the+recorded responses from production do not carry article ids, because the+prompt that produced them never asked for any. Refusing all of them would+mean refusing every real response we have. So fall back to position when+ids are absent, and refuse only when the response is unusable in both ways.++What that gives up is the property the experiment exists to measure. A+truncated or miscounted response has no ids either, so it takes the same+fallback, and the parser recovers an association from a response no parser+can recover an association from. It refuses less often than the historical+parser it was meant to improve on.++Kept as evidence. `web/lib/lab/runner.ts` routes it to the sandbox because+its bytes match no entry in KNOWN_IMPLEMENTATIONS -- being committed is not+what earns local execution; being on that list is. """  from __future__ import annotations  # --- contract prelude --------------------------------------------------------# Inlined rather than imported. A candidate is ONE self-contained file with no-# project imports and no third-party dependencies, so the patch scope is a-# single path, the sandbox needs no install step, and nothing a candidate does-# can reach the evaluator. The canonical definitions live in-# lab/contract/types.py, and tests/test_contract_prelude.py asserts that every-# copy still agrees with it.+# Inlined, per the one-self-contained-file rule. Canonical definitions live in+# lab/contract/types.py.  import math as _math @@ -54,45 +58,87 @@ import json from typing import Any  -VERSION_ID = "positional-v0"-PROTOCOL = "positional-v0"+VERSION_ID = "keyed-with-positional-fallback"+PROTOCOL = "keyed-v2"   def parse(articles: list[dict[str, Any]], response: dict[str, Any]) -> dict[str, Any]:     if response.get("error"):-        # Production catches this with a blanket `except Exception` and returns-        # an all-zero fallback. Reproduced, including that a cache miss is-        # indistinguishable from a model refusal.-        return ok([verdict(a["id"], False, 0.0, "scoring unavailable") for a in articles])+        return refuse("no_recording", str(response.get("error"))[:200])      content = response.get("content")     if content is None:-        return ok([verdict(a["id"], False, 0.0, "scoring unavailable") for a in articles])+        return refuse("no_recording", "the response carried no content")++    if response.get("finish_reason") not in (None, "stop"):+        return refuse("truncated_response", str(response.get("finish_reason")))      try:         result = json.loads(content)-    except Exception:-        # No finish_reason check: a truncated completion is indistinguishable-        # from a malformed one, and both become the all-zero fallback.-        return ok([verdict(a["id"], False, 0.0, "scoring unavailable") for a in articles])--    results_list = result.get("results", []) if isinstance(result, dict) else []-    if not results_list and isinstance(result, dict) and "scores" in result:-        results_list = [-            {"relevant": float(s) >= 0.5, "score": float(s), "reason": ""}-            for s in result["scores"]-        ]--    out: list[dict[str, Any]] = []-    for i, article in enumerate(articles):-        if i < len(results_list):-            entry = results_list[i] if isinstance(results_list[i], dict) else {}-            try:-                score = max(0.0, min(1.0, float(entry.get("score", 0.5))))-            except Exception:-                score = 0.5-            relevant = bool(entry.get("relevant", score >= 0.5))-            out.append(verdict(article["id"], relevant, score, str(entry.get("reason", ""))))-        else:-            out.append(verdict(article["id"], False, 0.0, "scoring incomplete"))+    except Exception as exc:+        return refuse("malformed_json", str(exc))++    if not isinstance(result, dict):+        return refuse("unexpected_shape", f"top level is {type(result).__name__}")++    results_list = result.get("results")+    if not isinstance(results_list, list):+        return refuse("unexpected_shape", "results is not a list")++    keyed = [e for e in results_list if isinstance(e, dict) and "article_id" in e]++    if keyed:+        return _parse_keyed(articles, keyed)++    # The fallback. Every verdict lacks an id, so associate by position --+    # which is the defect this candidate was written to remove, reintroduced+    # under a condition that looked like it excluded the defective cases.+    return _parse_positional(articles, results_list)+++def _parse_keyed(articles, entries):+    wanted = {a["id"] for a in articles}+    seen: dict[str, dict] = {}+    for entry in entries:+        aid = entry.get("article_id")+        if not isinstance(aid, str):+            return refuse("invalid_type", "article_id is not a string")+        if aid in seen:+            return refuse("duplicate_id", aid)+        if aid not in wanted:+            return refuse("unknown_id", aid)+        seen[aid] = entry++    missing = wanted - set(seen)+    if missing:+        return refuse("missing_id", ", ".join(sorted(missing))[:200])++    out = []+    for article in articles:+        entry = seen[article["id"]]+        score = finite_unit_score(entry.get("score"))+        if score is None:+            return refuse("score_out_of_range", f"{article['id']}: {entry.get('score')!r}")+        relevant = entry.get("relevant")+        if not isinstance(relevant, bool):+            return refuse("invalid_type", f"{article['id']}: relevant is not a bool")+        out.append(verdict(article["id"], relevant, score, entry.get("reason", "")))+    return ok(out)+++def _parse_positional(articles, entries):+    if len(entries) != len(articles):+        return refuse("count_mismatch", f"{len(entries)} verdicts for {len(articles)} articles")++    out = []+    for article, entry in zip(articles, entries):+        if not isinstance(entry, dict):+            return refuse("unexpected_shape", "a verdict is not an object")+        score = finite_unit_score(entry.get("score"))+        if score is None:+            return refuse("score_out_of_range", f"{article['id']}: {entry.get('score')!r}")+        relevant = entry.get("relevant")+        if not isinstance(relevant, bool):+            relevant = score >= 0.5+        out.append(verdict(article["id"], relevant, score, entry.get("reason", "")))     return ok(out) 

Reproduce this run

cd backend
EVAL_OFFLINE=1 venv/bin/python -m lab.orchestrate \
  --candidate keyed-fallback-v1 --tag clean
cd ../web && npm run export:lab -- --check

Source under test

backend/lab/contract/candidates/keyed_fallback_v1.pysha256 a404e7b1e54f842d… · 5479 bytestranscribed from unknown

04

Timeline

1 attempt
  1. 01succeededsandbox cyan-zonal-lark-rRFL5D in iad1, exit 0 in 523msvercel-sandbox · started 2026-09-22T20:20:21.318Z · ended 2026-09-22T20:20:28.263Z

Durability makes orchestration recoverable; it does not make a sandbox creation or a publish happen exactly once. An attempt the orchestrator never saw finish is recorded as unknown-outcome rather than assumed to have failed.

05

Cases

60 scored, 4 not applicable
Recorded cases
39real batches, replayed
Fault-injected
21labelled synthetic
Correct
60of the scored cases
Wrong
0see the table

Every scored case was correct. That is what the verdict above is asserting, and nothing more.

06

Unscored

Measured, and deliberately not graded

A criterion decides; a diagnostic reports. Promoting one of these to a criterion would change the spec hash and re-decide runs that never faced it, so a gap found after the fact is published as a number rather than closed behind your back.

4/4

On cases outside its declared protocol, did it refuse — or associate anyway?

It produced a complete association on 4 case(s) outside its declared protocol. Under this generation that fails protocol-exclusivity; under generation 1 it was not graded at all.

observed-2026-09-02-005, observed-2026-09-02-035, observed-2026-09-02-041, syn-positional-reordered

07

Provenance

What can and cannot be established
Executed at revision
192e1a54b3556bbd6351b86d705553d633ba2641+dirtyrecorded when the harness ran, not re-derived at export
Inputs sha256
70b83e3c09031c8fcases, records, candidates and event logs
Evaluator sha256
277ec81521ba14d8
Spec hash
f027762ab4d08b35
Execution mode
offline-replayThe harness reads committed responses from disk and makes no network call. The candidate imports nothing beyond the standard library.
Python
3.13.1
Model calls
0
Spend for this run
$0Offline replay of committed recordings: no inference call was made, so provider spend for this run is $0. What the original recordings cost is not attributed per batch anywhere in this repository, so it is left unknown rather than estimated. This run also provisioned a microVM, which is metered compute rather than free: 2436ms of active CPU across 869ms wall clock. That is billed by the platform at a rate this repository does not record, so the dollar figure is not stated rather than guessed.
Recording cost
unknown
Sandbox
cyan-zonal-lark-rRFL5Dpython3.13 in iad1, booted in 346ms
Network policy applied
deny-allread back off the microVM, not the value that was requested

Case suites

backend/lab/cases/observed.json42 cases · sha256 3d7f4b4143d85ab3backend/evals/.cache/llm via offline replay

backend/lab/cases/synthetic.json22 cases · sha256 21c92da332a9837elab/build_synthetic.py — fault injection, ground truth by construction

  • Note. Every case ran offline against responses already committed to this repository. No inference call was made and no provider was charged.backend/evals/.cache/llm
  • Caution. The case suite is public. A candidate may have been written against it, so passing does not establish generalisation.backend/lab/cases/
The full artifact, as published

Validated against the schema in web/lib/lab/artifact.ts before it was written. Download the JSON.