Skip to content
nano-gpt-data-curation

claude-opus-5

nano-gpt-data-curation — graded by the task's verifier against a measured baseline.

backend
modal
variant
claude claude-opus-5
metric
held-out multi-domain perplexity
actions
78
duration
1h 4m
recorded
2026-08-03

run iddclm-nano-curation__q2CFtsE

Everything claude-opus-5 did on this task, in order.

download JSON ↗
claude-codeclaude-opus-568 turns36 narration78 action78 observation32 reasoning1 final
#26
reasoning (redacted)

encrypted chain-of-thought — recorded, not exposed

toolEdit
args
{
  "replace_all": false,
  "file_path": "/workspace/submission/curate.py",
  "old_string": "    # ---- register-balanced round-robin allocation with equal token quotas\n    order = [sorted(range(len(kept)), key=lambda i: -kept[i][\"scores\"][r]) for r in range(NREG)]\n    quota = BUDGET * OVERSHOOT / NREG\n    ptr = [0] * NREG\n    used = [0.0] * NREG\n    taken = set()\n    sel = []\n    active = list(range(NREG))\n    while active:\n        for r in list(active):\n            while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:\n                ptr[r] += 1\n            if ptr[r] >= len(order[r]) or used[r] >= quota:\n                active.remove(r)\n                continue\n            i = order[r][ptr[r]]; ptr[r] += 1\n            taken.add(i)\n            d = kept[i]\n            used[r] += d[\"tok\"]\n            sel.append(d[\"id\"])",
  "new_string": "    # ---- register-balanced allocation with equal TOKEN quotas.\n    # Always extend whichever register is furthest below its quota, so every prefix\n    # of the emitted list (in particular the 12M-token prefix the trainer consumes)\n    # carries the target's 25/25/25/25 register mixture.\n    order = [sorted(range(len(kept)), key=lambda i: -kept[i][\"scores\"][r]) for r in range(NREG)]\n    frac = [w / sum(REG_W) for w in REG_W]\n    cap = BUDGET * OVERSHOOT\n    ptr, used, taken, sel = [0] * NREG, [0.0] * NREG, set(), []\n    while True:\n        cand = [r for r in range(NREG)\n                if frac[r] > 0 and ptr[r] < len(order[r]) and used[r] < cap * frac[r]]\n        if not cand:\n            break\n        r = min(cand, key=lambda r: used[r] / frac[r])\n        while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:\n            ptr[r] += 1\n        if ptr[r] >= len(order[r]):\n            continue\n        i = order[r][ptr[r]]; ptr[r] += 1\n        taken.add(i)\n        d = kept[i]\n        used[r] += d[\"tok\"]\n        sel.append(d[\"id\"])"
}
Edit result
The file /workspace/submission/curate.py has been updated successfully. (file state is current in your context — no need to Read it back)

[metadata] {"filePath": "/workspace/submission/curate.py", "oldString": "    # ---- register-balanced round-robin allocation with equal token quotas\n    order = [sorted(range(len(kept)), key=lambda i: -kept[i][\"scores\"][r]) for r in range(NREG)]\n    quota = BUDGET * OVERSHOOT / NREG\n    ptr = [0] * NREG\n    used = [0.0] * NREG\n    taken = set()\n    sel = []\n    active = list(range(NREG))\n    while active:\n        for r in list(active):\n            while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:\n                ptr[r] += 1\n            if ptr[r] >= len(order[r]) or used[r] >= quota:\n                active.remove(r)\n                continue\n            i = order[r][ptr[r]]; ptr[r] += 1\n            taken.add(i)\n            d = kept[i]\n            used[r] += d[\"tok\"]\n            sel.append(d[\"id\"])", "newString": "    # ---- register-balanced allocation with equal TOKEN quotas.\n    # Always extend whichever register is furthest below its quota, so every prefix\n    # of the emitted list (in particular the 12M-token prefix the trainer consumes)\n    # carries the target's 25/25/25/25 register mixture.\n    order = [sorted(range(len(kept)), key=lambda i: -kept[i][\"scores\"][r]) for r in range(NREG)]\n    frac = [w / sum(REG_W) for w in REG_W]\n    cap = BUDGET * OVERSHOOT\n    ptr, used, taken, sel = [0] * NREG, [0.0] * NREG, set(), []\n    while True:\n        cand = [r for r in range(NREG)\n                if frac[r] > 0 and ptr[r] < len(order[r]) and used[r] < cap * frac[r]]\n        if not cand:\n            break\n        r = min(cand, key=lambda r: used[r] / frac[r])\n        while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:\n            ptr[r] += 1\n        if ptr[r] >= len(order[r]):\n            continue\n        i = order[r][ptr[r]]; ptr[r] += 1\n        taken.add(i)\n        d = kept[i]\n        used[r] += d[\"tok\"]\n        sel.append(d[\"id\"])", "originalFile": null, "structuredPatch": [{"oldStart": 312, "oldLines": 26, "newStart": 312, "newLines": 29, "lines": ["     for d in kept:", "         d[\"tok\"] = 0.2745 * d[\"nchars\"] + 1.0", " ", "-    # ---- register-balanced round-robin allocation with equal token quotas", "+    # ---- register-balanced allocation with equal TOKEN quotas.", "+    # Always extend whichever register is furthest below its quota, so every prefix", "+    # of the emitted list (in particular the 12M-token prefix the trainer consumes)", "+    # carries the target's 25/25/25/25 register mixture.", "     order = [sorted(range(len(kept)), key=lambda i: -kept[i][\"scores\"][r]) for r in range(NREG)]", "-    quota = BUDGET * OVERSHOOT / NREG", "-    ptr = [0] * NREG", "-    used = [0.0] * NREG", "-    taken = set()", "-    sel = []", "-    active = list(range(NREG))", "-    while active:", "-        for r in list(active):", "-            while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:", "-                ptr[r] += 1", "-            if ptr[r] >= len(order[r]) or used[r] >= quota:", "-                active.remove(r)", "-                continue", "-            i = order[r][ptr[r]]; ptr[r] += 1", "-            taken.add(i)", "-            d = kept[i]", "-            used[r] += d[\"tok\"]", "-            sel.append(d[\"id\"])", "+    frac = [w / sum(REG_W) for w in REG_W]", "+    cap = BUDGET * OVERSHOOT", "+    ptr, used, taken, sel = [0] * NREG, [0.0] * NREG, set(), []", "+    while True:", "+        cand = [r for r in range(NREG)", "+                if frac[r] > 0 and ptr[r] < len(order[r]) and used[r] < cap * frac[r]]", "+        if not cand:", "+            break", "+        r = min(cand, key=lambda r: used[r] / frac[r])", "+        while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:", "+            ptr[r] += 1", "+        if ptr[r] >= len(order[r]):", "+            continue", "+        i = order[r][ptr[r]]; ptr[r] += 1", "+        taken.add(i)", "+        d = kept[i]", "+        used[r] += d[\"tok\"]", "+        sel.append(d[\"id\"])", "     print(f\"[5/5] selected {len(sel)} docs; est tokens/register: \"", "           f\"{[int(u) for u in used]} (names {REG_NAMES})\", flush=True)", "     est = sum(kept[i][\"tok\"] for i in taken)"]}], "userModified": false, "replaceAll": false}
#27
reasoning (redacted)

encrypted chain-of-thought — recorded, not exposed

toolBashAdd register weights and generate margin variant
args
{
  "command": "cd /workspace; sed -i 's/^REG_NAMES = .*/REG_NAMES = [\"wiki\", \"webprose\", \"news\", \"qa\"]\\nREG_W = [1.0, 1.0, 1.0, 1.0]          # relative token quota per register (target is 25\\/25\\/25\\/25)/' submission/curate.py; grep -n \"REG_W\" submission/curate.py | head; python3 variants.py margin",
  "description": "Add register weights and generate margin variant"
}
Bash result
48:REG_W = [1.0, 1.0, 1.0, 1.0]          # relative token quota per register (target is 25/25/25/25)
321:    frac = [w / sum(REG_W) for w in REG_W]
margin: 28238 ids -> /tmp/sel_margin.json

[stdout]
48:REG_W = [1.0, 1.0, 1.0, 1.0]          # relative token quota per register (target is 25/25/25/25)
321:    frac = [w / sum(REG_W) for w in REG_W]
margin: 28238 ids -> /tmp/sel_margin.json
[metadata] {"noOutputExpected": false}
#28
narration

Launching batch 2 — six runs testing the allocator, gate strictness, register purity, and DF-filtered vocabulary:

toolBashRun DF-filtered curation variants
args
{
  "command": "cd /workspace; (python3 submission/curate.py --dfmin 8 --cache /tmp/c_df8 --out /tmp/sel_df8.json > /tmp/df8.log 2>&1; python3 submission/curate.py --dfmin 8 --clip 3.0 --cache /tmp/c_df8c --out /tmp/sel_df8clip.json > /tmp/df8c.log 2>&1) ; tail -4 /tmp/df8.log; tail -3 /tmp/df8c.log; python3 variants.py nogates 2>&1 | tail -2; echo \"TIME: $(cat .timer/remaining_secs)\"",
  "description": "Run DF-filtered curation variants"
}
Bash result
92070 after near-dup removal
[5/5] selected 24915 docs; est tokens/register: [6600541, 6600360, 6600637, 6600909] (names ['wiki', 'webprose', 'news', 'qa'])
      est total tokens 26.4M (budget 12M)
wrote /tmp/sel_df8.json
[5/5] selected 24980 docs; est tokens/register: [6600627, 6603197, 6600311, 6600279] (names ['wiki', 'webprose', 'news', 'qa'])
      est total tokens 26.4M (budget 12M)
wrote /tmp/sel_df8clip.json
nogates: 21088 ids -> /tmp/sel_nogates.json
TIME: 4468

[stdout]
      92070 after near-dup removal
[5/5] selected 24915 docs; est tokens/register: [6600541, 6600360, 6600637, 6600909] (names ['wiki', 'webprose', 'news', 'qa'])
      est total tokens 26.4M (budget 12M)
wrote /tmp/sel_df8.json
[5/5] selected 24980 docs; est tokens/register: [6600627, 6603197, 6600311, 6600279] (names ['wiki', 'webprose', 'news', 'qa'])
      est total tokens 26.4M (budget 12M)
wrote /tmp/sel_df8clip.json
nogates: 21088 ids -> /tmp/sel_nogates.json
TIME: 4468
[metadata] {"noOutputExpected": false}
#29
reasoning (redacted)

encrypted chain-of-thought — recorded, not exposed

toolBashRun batch 2: six variants
args
{
  "command": "cd /workspace; nohup python3 eval_batch.py bal2 strict margin nogates df8 df8clip > /tmp/eval2.log 2>&1 & echo launched; sleep 120; grep -E \"packed|RESULT\" /tmp/eval2.log",
  "description": "Run batch 2: six variants"
}
Bash result
launched
[bal2] packed 12000000 tokens from 14364 docs (mean 835 tok/doc)
[strict] packed 12000000 tokens from 11068 docs (mean 1084 tok/doc)
[margin] packed 12000000 tokens from 16092 docs (mean 746 tok/doc)
[nogates] packed 12000000 tokens from 8260 docs (mean 1453 tok/doc)
[df8] packed 12000000 tokens from 14603 docs (mean 822 tok/doc)
[df8clip] packed 12000000 tokens from 14629 docs (mean 820 tok/doc)

[stdout]
launched
[bal2] packed 12000000 tokens from 14364 docs (mean 835 tok/doc)
[strict] packed 12000000 tokens from 11068 docs (mean 1084 tok/doc)
[margin] packed 12000000 tokens from 16092 docs (mean 746 tok/doc)
[nogates] packed 12000000 tokens from 8260 docs (mean 1453 tok/doc)
[df8] packed 12000000 tokens from 14603 docs (mean 822 tok/doc)
[df8clip] packed 12000000 tokens from 14629 docs (mean 820 tok/doc)
[metadata] {"noOutputExpected": false}
#30
narration

While batch 2 trains, let me check those 96 <p> docs (potential exact surface match for the 25% Q&A block) and write a per-register diagnostic trainer.

toolBashInspect p-tag documents
args
{
  "command": "cd /workspace; python3 -c \"\nimport json\nn=0\nhits=[]\nfor line in open('data/pool.jsonl'):\n    r=json.loads(line)\n    t=r['text']\n    if '</p>' in t:\n        hits.append(r['id'])\n        if n<4:\n            print('=== id',r['id'],'len',len(t)); print(repr(t[:300])); n+=1\nprint('total </p> docs:',len(hits))\njson.dump(hits, open('/tmp/ptag_ids.json','w'))\n\"",
  "description": "Inspect p-tag documents"
}
Bash result
=== id 6138 len 3373
'XForms/Read and write with get and put\nSometimes all you need to do is to put a nice user friendly form that edits a single static XML file. In this case a static file is any file where you know the exact pathname to the file when the form is created and you know that the file name will never change'
=== id 13746 len 4110
'Scaling the Windows Stack George Beech @GABeech PICC ‘12.\nout of 23\nPost on 27-Dec-2015\nEmbed Size (px)\n<p>PowerPoint Presentation</p> <p>Scaling the Windows StackGeorge Beech @GABeechPICC 12AgendaWhat is Stack Exchange?Growth this YearOur Technology StackHow we scaleDealing with Windows stack scali'
=== id 14810 len 2295
'If you are building a website and need to sign people in, you can use IndieAuth.com to handle web sign-in so that you don\'t have to implement OAuth code for each provider.\n<form action="https://indieauth.com/auth" method="get"> <label for="indie_auth_url">Web Address:</label> <input id="indie_auth_u'
=== id 22017 len 10485
"There's good news on the drug war: The world knows how to end it -- so why can't the United States figure it out?\n- By Charles Kenny<p> Charles Kenny is a senior fellow at the Center for Global Development, a Schwartz fellow at the New America Foundation, and author, most recently, of Getting Better"
total </p> docs: 69

[stdout]
=== id 6138 len 3373
'XForms/Read and write with get and put\nSometimes all you need to do is to put a nice user friendly form that edits a single static XML file. In this case a static file is any file where you know the exact pathname to the file when the form is created and you know that the file name will never change'
=== id 13746 len 4110
'Scaling the Windows Stack George Beech @GABeech PICC ‘12.\nout of 23\nPost on 27-Dec-2015\nEmbed Size (px)\n<p>PowerPoint Presentation</p> <p>Scaling the Windows StackGeorge Beech @GABeechPICC 12AgendaWhat is Stack Exchange?Growth this YearOur Technology StackHow we scaleDealing with Windows stack scali'
=== id 14810 len 2295
'If you are building a website and need to sign people in, you can use IndieAuth.com to handle web sign-in so that you don\'t have to implement OAuth code for each provider.\n<form action="https://indieauth.com/auth" method="get"> <label for="indie_auth_url">Web Address:</label> <input id="indie_auth_u'
=== id 22017 len 10485
"There's good news on the drug war: The world knows how to end it -- so why can't the United States figure it out?\n- By Charles Kenny<p> Charles Kenny is a senior fellow at the Center for Global Development, a Schwartz fellow at the New America Foundation, and author, most recently, of Getting Better"
total </p> docs: 69
[metadata] {"noOutputExpected": false}
#31
narration

Only 69 stray-HTML docs, not StackExchange format — no surface match available there either. Writing a per-register diagnostic trainer (same frozen recipe/seed, extra per-block readout):

toolBashCreate diagnostic trainer with per-register readout
args
{
  "command": "cd /workspace; python3 - <<'EOF'\nsrc = open('train_nano.py').read()\n# identical recipe; adds a per-register breakdown of the held-out loss (diagnostic only)\nextra = '''\n# ---- diagnostic: per-register breakdown (4 equal blocks of the multi-domain target)\nREG = [\"wiki\", \"webprose\", \"news\", \"qa\"]\nnb = len(ho) // 4\nper = {}\nwith torch.no_grad():\n    for b in range(4):\n        seg = ho[b*nb:(b+1)*nb]\n        nw = (len(seg) - 1) // a.block\n        st = [j * a.block for j in range(nw)]\n        s2, n2 = 0.0, 0\n        for i in range(0, nw, a.batch):\n            bs = st[i:i+a.batch]\n            x = torch.stack([seg[s:s+a.block] for s in bs]).to(dev)\n            y = torch.stack([seg[s+1:s+1+a.block] for s in bs]).to(dev)\n            with torch.autocast(\"cuda\", dtype=torch.bfloat16):\n                _, l = model(x, y)\n            s2 += l.item() * len(bs); n2 += len(bs)\n        per[REG[b]] = math.exp(s2 / max(1, n2))\nout[\"per_register_ppl\"] = per\njson.dump(out, open(a.out_json, \"w\"))\nprint(\"PER_REGISTER \" + \"  \".join(f\"{k}={v:.1f}\" for k, v in per.items()))\n'''\nopen('diag_train.py','w').write(src + extra)\nprint(\"written\")\nEOF\nsed -i 's|\"python3\", \"/workspace/train_nano.py\"|\"python3\", os.environ.get(\"TRAINER\",\"/workspace/train_nano.py\")|' eval_batch.py; grep -n \"TRAINER\" eval_batch.py; grep -E \"RESULT|packed\" /tmp/eval2.log | tail -3",
  "description": "Create diagnostic trainer with per-register readout"
}
Bash result
written
47:    cmd = ["python3", os.environ.get("TRAINER","/workspace/train_nano.py"), "--train_npy", f"/tmp/train_{nm}.npy",
[nogates] packed 12000000 tokens from 8260 docs (mean 1453 tok/doc)
[df8] packed 12000000 tokens from 14603 docs (mean 822 tok/doc)
[df8clip] packed 12000000 tokens from 14629 docs (mean 820 tok/doc)

[stdout]
written
47:    cmd = ["python3", os.environ.get("TRAINER","/workspace/train_nano.py"), "--train_npy", f"/tmp/train_{nm}.npy",
[nogates] packed 12000000 tokens from 8260 docs (mean 1453 tok/doc)
[df8] packed 12000000 tokens from 14603 docs (mean 822 tok/doc)
[df8clip] packed 12000000 tokens from 14629 docs (mean 820 tok/doc)
[metadata] {"noOutputExpected": false}
#32
reasoning (redacted)

encrypted chain-of-thought — recorded, not exposed

toolBashPoll batch 2 results
args
{
  "command": "sleep 150; grep -A8 \"RESULTS\" /tmp/eval2.log; echo \"TIME: $(cat /workspace/.timer/remaining_secs)\"",
  "description": "Poll batch 2 results"
}
Bash result · error
Exit code 143
Command timed out after 2m 0s

[error] tool reported failure
#33
reasoning (redacted)

encrypted chain-of-thought — recorded, not exposed

toolBashPoll batch 2 results again
args
{
  "command": "sleep 100; grep -A8 \"RESULTS\" /tmp/eval2.log; echo \"TIME: $(cat /workspace/.timer/remaining_secs)\"",
  "description": "Poll batch 2 results again"
}
Bash result
=== RESULTS (dev PPL, lower better) ===
  361.178  bal2
  365.990  df8clip
  371.044  df8
  386.585  margin
  387.072  nogates
  391.452  strict
TIME: 4068

[stdout]
=== RESULTS (dev PPL, lower better) ===
  361.178  bal2
  365.990  df8clip
  371.044  df8
  386.585  margin
  387.072  nogates
  391.452  strict
TIME: 4068
[metadata] {"noOutputExpected": false}
#34
narration

Batch 2 tells me: gates help in combination (nogates 387), strict over-filtering hurts (391), register-purity hurts (386), and round-robin allocation (354.8) beat token-exact balance (361.2). The critical open question is transfer: dfmin=1 wins on dev but may be exploiting dev-specific topical words. Let me test that properly with a fit-on-half / test-on-other-half experiment.

toolBashMeasure register token shares in 12M prefix
args
{
  "command": "cd /workspace; python3 -c \"\nimport json\ndocs=json.load(open('/tmp/curate_cache/docs.json'))\nby={d['id']:d for d in docs}\nimport numpy as np\n# actual per-register token share of the 12M prefix, for rr vs greedy orderings\nfor nm in ['balanced','bal2']:\n    sel=json.load(open(f'/tmp/sel_{nm}.json'))\n    tot=0; share=[0.0]*4\n    for i in sel:\n        d=by[i]; t=0.2745*d['nchars']+1\n        r=int(np.argmax(d['scores']))\n        if tot+t>12e6: break\n        share[r]+=t; tot+=t\n    print(nm, 'argmax-register token shares', [round(s/tot,3) for s in share], 'tot', int(tot))\n\"",
  "description": "Measure register token shares in 12M prefix"
}
Bash result
balanced argmax-register token shares [0.295, 0.463, 0.156, 0.086] tot 11999838
bal2 argmax-register token shares [0.262, 0.485, 0.165, 0.087] tot 11998728

[stdout]
balanced argmax-register token shares [0.295, 0.463, 0.156, 0.086] tot 11999838
bal2 argmax-register token shares [0.262, 0.485, 0.165, 0.087] tot 11998728
[metadata] {"noOutputExpected": false}
#35
narration

Round-robin's implicit mixture leans more Wikipedia, less web-prose — and it won. Now the transfer test plus a per-register diagnostic, run together:

toolBashBuild half-fit selections and transfer target
args
{
  "command": "cd /workspace; python3 - <<'EOF'\nimport re\ns=open('submission/curate.py').read()\ns=s.replace('_ap.add_argument(\"--cache\", default=\"/tmp/curate_cache\")',\n '_ap.add_argument(\"--halffit\", action=\"store_true\",\\n                 help=\"diagnostic: fit the profile on the FIRST half of each register block only,\\\\n so the model can be tested on the unseen second half (transfer check)\")\\n_ap.add_argument(\"--cache\", default=\"/tmp/curate_cache\")')\ns=s.replace(\"\"\"    blocks = [tok.decode(a[i * n:(i + 1) * n]) for i in range(NREG)]\n    eos = tok.eos_token_id\n    idx = np.where(a == eos)[0]\n    segs = [tok.decode(s) for s in np.split(a, idx) if len(s) > 30]\"\"\",\n\"\"\"    half = n // 2 if _A.halffit else n\n    blocks = [tok.decode(a[i * n:i * n + half]) for i in range(NREG)]\n    fit = np.concatenate([a[i * n:i * n + half] for i in range(NREG)])\n    eos = tok.eos_token_id\n    idx = np.where(fit == eos)[0]\n    segs = [tok.decode(s) for s in np.split(fit, idx) if len(s) > 30]\"\"\")\nopen('submission/curate.py','w').write(s)\n# held-out second halves (never used for fitting) -> transfer test target\nimport numpy as np\na=np.load('data/multi_dev.npy'); n=len(a)//4\nB=np.concatenate([a[i*n+n//2:(i+1)*n] for i in range(4)])\nnp.save('/tmp/devB.npy', B.astype(np.uint16)); print('devB', B.shape)\nEOF\nsed -i 's|\"--heldout_npy\", \"/workspace/data/multi_dev.npy\"|\"--heldout_npy\", os.environ.get(\"HELDOUT\",\"/workspace/data/multi_dev.npy\")|' eval_batch.py\npython3 submission/curate.py --halffit --dfmin 1 --cache /tmp/c_hf1 --out /tmp/sel_hf1.json 2>&1 | tail -2\npython3 submission/curate.py --halffit --dfmin 8 --cache /tmp/c_hf8 --out /tmp/sel_hf8.json 2>&1 | tail -2\necho \"TIME: $(cat .timer/remaining_secs)\"",
  "description": "Build half-fit selections and transfer target"
}
Bash result
devB (500000,)
      est total tokens 26.4M (budget 12M)
wrote /tmp/sel_hf1.json
      est total tokens 26.4M (budget 12M)
wrote /tmp/sel_hf8.json
TIME: 3938

[stdout]
devB (500000,)
      est total tokens 26.4M (budget 12M)
wrote /tmp/sel_hf1.json
      est total tokens 26.4M (budget 12M)
wrote /tmp/sel_hf8.json
TIME: 3938
[metadata] {"noOutputExpected": false}
#36
reasoning (redacted)

encrypted chain-of-thought — recorded, not exposed

toolBashRun transfer test and per-register diagnostic
args
{
  "command": "cd /workspace; HELDOUT=/tmp/devB.npy nohup python3 eval_batch.py hf1 hf8 > /tmp/eval3.log 2>&1 &\nsleep 5\nTRAINER=/workspace/diag_train.py nohup python3 eval_batch.py balanced > /tmp/eval_diag.log 2>&1 &\necho launched both; sleep 100; grep -E \"RESULT|PER_REG\" /tmp/eval3.log /tmp/eval_diag.log; tail -3 /tmp/eval3.log",
  "description": "Run transfer test and per-register diagnostic"
}
Bash result
launched both
[hf8] packed 12000000 tokens from 14962 docs (mean 802 tok/doc)
launched hf1
launched hf8

[stdout]
launched both
[hf8] packed 12000000 tokens from 14962 docs (mean 802 tok/doc)
launched hf1
launched hf8
[metadata] {"noOutputExpected": false}
#37
reasoning (redacted)

encrypted chain-of-thought — recorded, not exposed

toolBashCompute winning round-robin queue token shares
args
{
  "command": "cd /workspace; python3 -c \"\nimport json, numpy as np\ndocs=json.load(open('/tmp/curate_cache/docs.json'))\nfor d in docs: d['tok']=0.2745*d['nchars']+1\ndef gates(d):\n    return (d['nwords']>=120 and d['nchars']>=700 and d['cov']>=0.50 and d['frac_alpha']>=0.68\n      and d['frac_digit']<=0.16 and d['frac_upper']<=0.13 and d['frac_short_lines']<=0.45\n      and d['uniq_line_ratio']>=0.70 and 0.22<=d['uniq_word_ratio']<=0.85\n      and d['mean_line_words']>=8.0 and d['pipe']<=3.0)\nkept=sorted([d for d in docs if gates(d)], key=lambda d:-max(d['scores']))\nse,sp,sm,K=set(),set(),set(),[]\nfor d in kept:\n    e,p,m=d['sk']\n    if e in se or p in sp or m in sm: continue\n    se.add(e);sp.add(p);sm.add(m);K.append(d)\norder=[sorted(range(len(K)), key=lambda i:-K[i]['scores'][r]) for r in range(4)]\n# replicate round-robin (doc-count) and record queue of each pick\nptr=[0]*4; used=[0.0]*4; taken=set(); seq=[]\nactive=list(range(4)); quota=12e6*2.2/4\nwhile active:\n    for r in list(active):\n        while ptr[r]<len(order[r]) and order[r][ptr[r]] in taken: ptr[r]+=1\n        if ptr[r]>=len(order[r]) or used[r]>=quota: active.remove(r); continue\n        i=order[r][ptr[r]]; ptr[r]+=1; taken.add(i); used[r]+=K[i]['tok']; seq.append((r,K[i]))\ntot=0; qs=[0.0]*4; nd=[0]*4\nfor r,d in seq:\n    if tot+d['tok']>12e6: break\n    qs[r]+=d['tok']; nd[r]+=1; tot+=d['tok']\nprint('rr QUEUE token shares', [round(q/tot,3) for q in qs], 'docs', nd, 'tot', int(tot))\nprint('mean tok/doc per queue', [round(qs[r]/max(1,nd[r])) for r in range(4)])\n\"",
  "description": "Compute winning round-robin queue token shares"
}
Bash result
rr QUEUE token shares [0.307, 0.29, 0.196, 0.206] docs [2938, 2938, 2938, 2938] tot 11999838
mean tok/doc per queue [1255, 1186, 802, 842]

[stdout]
rr QUEUE token shares [0.307, 0.29, 0.196, 0.206] docs [2938, 2938, 2938, 2938] tot 11999838
mean tok/doc per queue [1255, 1186, 802, 842]
[metadata] {"noOutputExpected": false}
#38
narration

Winning mixture was ~31/29/20/21 (more Wikipedia + prose, less news/Q&A). Let me check the transfer test:

toolBashRead transfer and diagnostic results
args
{
  "command": "sleep 60; grep -E \"RESULT\" -A5 /tmp/eval3.log; echo \"=== diag ===\"; grep -E \"PER_REGISTER|RESULT\" -A5 /tmp/eval_diag.log; echo \"TIME: $(cat /workspace/.timer/remaining_secs)\"",
  "description": "Read transfer and diagnostic results"
}
Bash result
=== RESULTS (dev PPL, lower better) ===
  362.462  hf1
  363.906  hf8
=== diag ===
=== RESULTS (dev PPL, lower better) ===
  354.828  balanced
TIME: 3727

[stdout]
=== RESULTS (dev PPL, lower better) ===
  362.462  hf1
  363.906  hf8
=== diag ===
=== RESULTS (dev PPL, lower better) ===
  354.828  balanced
TIME: 3727
[metadata] {"noOutputExpected": false}
#39
narration

Transfer test settled it: dfmin=1 (362.5) ≈ dfmin=8 (363.9) on unseen target text — so the gain is from register/style features, not dev-specific topical words. Keeping the simpler criterion. Now tuning the mixture, plus a lighter-gates probe:

toolBashGenerate mixture variants and read per-register diagnostic
args
{
  "command": "cd /workspace; python3 - <<'EOF'\ns=open('variants.py').read()\ns=s.replace('''elif which == \"strict\":''','''elif which == \"light\":\n    kept_l = dedup(sorted([d for d in docs if\n        d[\"nwords\"] >= 80 and d[\"nchars\"] >= 450 and d[\"cov\"] >= 0.45\n        and d[\"frac_alpha\"] >= 0.60 and d[\"frac_digit\"] <= 0.20\n        and d[\"frac_upper\"] <= 0.16 and d[\"frac_short_lines\"] <= 0.60\n        and d[\"uniq_line_ratio\"] >= 0.60 and 0.18 <= d[\"uniq_word_ratio\"] <= 0.88\n        and d[\"mean_line_words\"] >= 6.0 and d[\"pipe\"] <= 6.0],\n        key=lambda d: -max(d[\"scores\"])))\n    print(\"light pool:\", len(kept_l))\n    sel = balanced(kept_l)\nelif which == \"strict\":''')\nopen('variants.py','w').write(s)\nEOF\nfor v in w.307-.29-.196-.206 w.375-.35-.14-.135 w.45-.40-.08-.07 light; do python3 variants.py $v 2>&1|tail -1; done\ncat /tmp/res_balanced.json; echo; echo \"TIME: $(cat .timer/remaining_secs)\"",
  "description": "Generate mixture variants and read per-register diagnostic"
}
Bash result
w.307-.29-.196-.206: 24266 ids -> /tmp/sel_w.307-.29-.196-.206.json
w.375-.35-.14-.135: 23614 ids -> /tmp/sel_w.375-.35-.14-.135.json
w.45-.40-.08-.07: 23147 ids -> /tmp/sel_w.45-.40-.08-.07.json
light: 25866 ids -> /tmp/sel_light.json
{"train_npy": "/tmp/train_balanced.npy", "heldout_ppl": 354.82780476939985, "mean_loss": 5.871632614809614, "max_iters": 3000, "seed": 1337, "train_s": 161.6, "per_register_ppl": {"wiki": 691.1877213780052, "webprose": 266.4132668923361, "news": 282.6106237640412, "qa": 303.35743323818673}}
TIME: 3697

[stdout]
w.307-.29-.196-.206: 24266 ids -> /tmp/sel_w.307-.29-.196-.206.json
w.375-.35-.14-.135: 23614 ids -> /tmp/sel_w.375-.35-.14-.135.json
w.45-.40-.08-.07: 23147 ids -> /tmp/sel_w.45-.40-.08-.07.json
light: 25866 ids -> /tmp/sel_light.json
{"train_npy": "/tmp/train_balanced.npy", "heldout_ppl": 354.82780476939985, "mean_loss": 5.871632614809614, "max_iters": 3000, "seed": 1337, "train_s": 161.6, "per_register_ppl": {"wiki": 691.1877213780052, "webprose": 266.4132668923361, "news": 282.6106237640412, "qa": 303.35743323818673}}
TIME: 3697
[metadata] {"noOutputExpected": false}
#40
narration

Per-register diagnostic on the current best: wiki 691 vs webprose 266 / news 283 / qa 303 — the Wikipedia block dominates the loss, exactly as the missing-surface-form analysis predicted. Launching the mixture sweep:

toolBashRun mixture sweep batch
args
{
  "command": "cd /workspace; nohup python3 eval_batch.py w.307-.29-.196-.206 w.375-.35-.14-.135 w.45-.40-.08-.07 light > /tmp/eval4.log 2>&1 & echo launched; sleep 115; grep -E \"packed|RESULT\" /tmp/eval4.log",
  "description": "Run mixture sweep batch"
}
Bash result
launched
[w.307-.29-.196-.206] packed 12000000 tokens from 13975 docs (mean 859 tok/doc)
[w.375-.35-.14-.135] packed 12000000 tokens from 13591 docs (mean 883 tok/doc)
[w.45-.40-.08-.07] packed 12000000 tokens from 13143 docs (mean 913 tok/doc)
[light] packed 12000000 tokens from 14275 docs (mean 841 tok/doc)

[stdout]
launched
[w.307-.29-.196-.206] packed 12000000 tokens from 13975 docs (mean 859 tok/doc)
[w.375-.35-.14-.135] packed 12000000 tokens from 13591 docs (mean 883 tok/doc)
[w.45-.40-.08-.07] packed 12000000 tokens from 13143 docs (mean 913 tok/doc)
[light] packed 12000000 tokens from 14275 docs (mean 841 tok/doc)
[metadata] {"noOutputExpected": false}
#41
narration

Drafting the claim while the sweep finishes:

toolBashPrepare extra mixtures, poll sweep results
args
{
  "command": "cd /workspace; python3 variants.py w.55-.30-.075-.075 2>&1|tail -1; python3 variants.py w.25-.25-.25-.25 2>&1|tail -1; sleep 105; grep -A6 RESULTS /tmp/eval4.log; echo \"TIME: $(cat .timer/remaining_secs)\"",
  "description": "Prepare extra mixtures, poll sweep results"
}
Bash result
w.55-.30-.075-.075: 23383 ids -> /tmp/sel_w.55-.30-.075-.075.json
w.25-.25-.25-.25: 24488 ids -> /tmp/sel_w.25-.25-.25-.25.json
TIME: 3427

[stdout]
w.55-.30-.075-.075: 23383 ids -> /tmp/sel_w.55-.30-.075-.075.json
w.25-.25-.25-.25: 24488 ids -> /tmp/sel_w.25-.25-.25-.25.json
TIME: 3427
[metadata] {"noOutputExpected": false}
#42
reasoning (redacted)

encrypted chain-of-thought — recorded, not exposed

toolBashPoll sweep results
args
{
  "command": "sleep 90; grep -A6 RESULTS /tmp/eval4.log; echo \"TIME: $(cat /workspace/.timer/remaining_secs)\"",
  "description": "Poll sweep results"
}
Bash result
=== RESULTS (dev PPL, lower better) ===
  338.948  light
  360.489  w.307-.29-.196-.206
  379.055  w.375-.35-.14-.135
  380.281  w.45-.40-.08-.07
TIME: 3337

[stdout]
=== RESULTS (dev PPL, lower better) ===
  338.948  light
  360.489  w.307-.29-.196-.206
  379.055  w.375-.35-.14-.135
  380.281  w.45-.40-.08-.07
TIME: 3337
[metadata] {"noOutputExpected": false}
#43
narration

light gates jumped to 338.9 — my moderate gates were throwing away useful documents. And pushing the mixture toward Wikipedia hurts (379-380). Let me map the gate-looseness curve:

toolBashTest gate looseness curve
args
{
  "command": "cd /workspace; python3 - <<'EOF'\ns=open('variants.py').read()\ns=s.replace('''elif which == \"strict\":''','''elif which == \"light2\":       # very loose: keep almost everything readable\n    kept_l = dedup(sorted([d for d in docs if\n        d[\"nwords\"] >= 60 and d[\"cov\"] >= 0.35\n        and d[\"frac_alpha\"] >= 0.50 and d[\"frac_digit\"] <= 0.28\n        and d[\"frac_upper\"] <= 0.22 and d[\"frac_short_lines\"] <= 0.75\n        and d[\"uniq_line_ratio\"] >= 0.50 and 0.15 <= d[\"uniq_word_ratio\"] <= 0.92\n        and d[\"mean_line_words\"] >= 4.0 and d[\"pipe\"] <= 12.0],\n        key=lambda d: -max(d[\"scores\"])))\n    print(\"light2 pool:\", len(kept_l)); sel = balanced(kept_l)\nelif which == \"light3\":       # length + English-coverage only\n    kept_l = dedup(sorted([d for d in docs if d[\"nwords\"] >= 80 and d[\"cov\"] >= 0.45],\n        key=lambda d: -max(d[\"scores\"])))\n    print(\"light3 pool:\", len(kept_l)); sel = balanced(kept_l)\nelif which == \"nogatesrr\":    # no gates at all, round-robin allocation\n    kept_l = dedup(sorted([d for d in docs if d[\"nwords\"] >= 50],\n        key=lambda d: -max(d[\"scores\"])))\n    print(\"nogatesrr pool:\", len(kept_l)); sel = balanced(kept_l)\nelif which == \"strict\":''')\nopen('variants.py','w').write(s)\nEOF\nfor v in light2 light3 nogatesrr; do python3 variants.py $v 2>&1|tail -2; done\nnohup python3 eval_batch.py light2 light3 nogatesrr w.25-.25-.25-.25 > /tmp/eval5.log 2>&1 & echo launched",
  "description": "Test gate looseness curve"
}
Bash result
light2 pool: 135660
light2: 24728 ids -> /tmp/sel_light2.json
light3 pool: 151857
light3: 20863 ids -> /tmp/sel_light3.json
nogatesrr pool: 160949
nogatesrr: 21088 ids -> /tmp/sel_nogatesrr.json
launched

[stdout]
light2 pool: 135660
light2: 24728 ids -> /tmp/sel_light2.json
light3 pool: 151857
light3: 20863 ids -> /tmp/sel_light3.json
nogatesrr pool: 160949
nogatesrr: 21088 ids -> /tmp/sel_nogatesrr.json
launched
[metadata] {"noOutputExpected": false}
#44
narration

Updating curate.py to the winning configuration (round-robin allocation, parameterized gates) while the batch runs:

toolRead
args
{
  "file_path": "/workspace/submission/curate.py",
  "offset": 280,
  "limit": 70
}
Read result
280	        docs = json.load(open(sc_f))
281	    else:
282	        print("[3/5] scoring pool", flush=True)
283	        with MPPool(NPROC, initializer=_init, initargs=(V_uni, V_bi, F, W, off)) as p:
284	            parts = p.map(work_score, chunks(POOL, 1500))
285	        docs = [d for part in parts for d in part]
286	        json.dump(docs, open(sc_f, "w"))
287	    print(f"      scored {len(docs)} docs", flush=True)
288	
289	    # ---- quality gates: format junk removal (register-agnostic)
290	    def ok(d):
291	        return (d["nwords"] >= 120 and d["nchars"] >= 700
292	                and d["cov"] >= 0.50
293	                and d["frac_alpha"] >= 0.68
294	                and d["frac_digit"] <= 0.16
295	                and d["frac_upper"] <= 0.13
296	                and d["frac_short_lines"] <= 0.45
297	                and d["uniq_line_ratio"] >= 0.70
298	                and 0.22 <= d["uniq_word_ratio"] <= 0.85
299	                and d["mean_line_words"] >= 8.0
300	                and d["pipe"] <= 3.0)
301	
302	    elig = [d for d in docs if ok(d)]
303	    print(f"[4/5] {len(elig)}/{len(docs)} docs pass quality gates", flush=True)
304	
305	    # ---- dedup (keep the higher-scoring member of each near-dup cluster)
306	    elig.sort(key=lambda d: -max(d["scores"]))
307	    seen_e, seen_p, seen_m, kept = set(), set(), set(), []
308	    for d in elig:
309	        e, pfx, mh = d["sk"]
310	        if e in seen_e or pfx in seen_p or mh in seen_m:
311	            continue
312	        seen_e.add(e); seen_p.add(pfx); seen_m.add(mh)
313	        kept.append(d)
314	    print(f"      {len(kept)} after near-dup removal", flush=True)
315	
316	    # ---- estimated GPT-2 token count (calibrated chars->tokens, +1 for EOS)
317	    for d in kept:
318	        d["tok"] = 0.2745 * d["nchars"] + 1.0
319	
320	    # ---- register-balanced allocation with equal TOKEN quotas.
321	    # Always extend whichever register is furthest below its quota, so every prefix
322	    # of the emitted list (in particular the 12M-token prefix the trainer consumes)
323	    # carries the target's 25/25/25/25 register mixture.
324	    order = [sorted(range(len(kept)), key=lambda i: -kept[i]["scores"][r]) for r in range(NREG)]
325	    frac = [w / sum(REG_W) for w in REG_W]
326	    cap = BUDGET * OVERSHOOT
327	    ptr, used, taken, sel = [0] * NREG, [0.0] * NREG, set(), []
328	    while True:
329	        cand = [r for r in range(NREG)
330	                if frac[r] > 0 and ptr[r] < len(order[r]) and used[r] < cap * frac[r]]
331	        if not cand:
332	            break
333	        r = min(cand, key=lambda r: used[r] / frac[r])
334	        while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:
335	            ptr[r] += 1
336	        if ptr[r] >= len(order[r]):
337	            continue
338	        i = order[r][ptr[r]]; ptr[r] += 1
339	        taken.add(i)
340	        d = kept[i]
341	        used[r] += d["tok"]
342	        sel.append(d["id"])
343	    print(f"[5/5] selected {len(sel)} docs; est tokens/register: "
344	          f"{[int(u) for u in used]} (names {REG_NAMES})", flush=True)
345	    est = sum(kept[i]["tok"] for i in taken)
346	    print(f"      est total tokens {est/1e6:.1f}M (budget {BUDGET/1e6:.0f}M)", flush=True)
347	    assert len(sel) == len(set(sel))
348	    json.dump(sel, open(OUT, "w"))
349	    print("wrote", OUT, flush=True)

[metadata] {"type": "text", "file": {"filePath": "/workspace/submission/curate.py", "content": "        docs = json.load(open(sc_f))\n    else:\n        print(\"[3/5] scoring pool\", flush=True)\n        with MPPool(NPROC, initializer=_init, initargs=(V_uni, V_bi, F, W, off)) as p:\n            parts = p.map(work_score, chunks(POOL, 1500))\n        docs = [d for part in parts for d in part]\n        json.dump(docs, open(sc_f, \"w\"))\n    print(f\"      scored {len(docs)} docs\", flush=True)\n\n    # ---- quality gates: format junk removal (register-agnostic)\n    def ok(d):\n        return (d[\"nwords\"] >= 120 and d[\"nchars\"] >= 700\n                and d[\"cov\"] >= 0.50\n                and d[\"frac_alpha\"] >= 0.68\n                and d[\"frac_digit\"] <= 0.16\n                and d[\"frac_upper\"] <= 0.13\n                and d[\"frac_short_lines\"] <= 0.45\n                and d[\"uniq_line_ratio\"] >= 0.70\n                and 0.22 <= d[\"uniq_word_ratio\"] <= 0.85\n                and d[\"mean_line_words\"] >= 8.0\n                and d[\"pipe\"] <= 3.0)\n\n    elig = [d for d in docs if ok(d)]\n    print(f\"[4/5] {len(elig)}/{len(docs)} docs pass quality gates\", flush=True)\n\n    # ---- dedup (keep the higher-scoring member of each near-dup cluster)\n    elig.sort(key=lambda d: -max(d[\"scores\"]))\n    seen_e, seen_p, seen_m, kept = set(), set(), set(), []\n    for d in elig:\n        e, pfx, mh = d[\"sk\"]\n        if e in seen_e or pfx in seen_p or mh in seen_m:\n            continue\n        seen_e.add(e); seen_p.add(pfx); seen_m.add(mh)\n        kept.append(d)\n    print(f\"      {len(kept)} after near-dup removal\", flush=True)\n\n    # ---- estimated GPT-2 token count (calibrated chars->tokens, +1 for EOS)\n    for d in kept:\n        d[\"tok\"] = 0.2745 * d[\"nchars\"] + 1.0\n\n    # ---- register-balanced allocation with equal TOKEN quotas.\n    # Always extend whichever register is furthest below its quota, so every prefix\n    # of the emitted list (in particular the 12M-token prefix the trainer consumes)\n    # carries the target's 25/25/25/25 register mixture.\n    order = [sorted(range(len(kept)), key=lambda i: -kept[i][\"scores\"][r]) for r in range(NREG)]\n    frac = [w / sum(REG_W) for w in REG_W]\n    cap = BUDGET * OVERSHOOT\n    ptr, used, taken, sel = [0] * NREG, [0.0] * NREG, set(), []\n    while True:\n        cand = [r for r in range(NREG)\n                if frac[r] > 0 and ptr[r] < len(order[r]) and used[r] < cap * frac[r]]\n        if not cand:\n            break\n        r = min(cand, key=lambda r: used[r] / frac[r])\n        while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:\n            ptr[r] += 1\n        if ptr[r] >= len(order[r]):\n            continue\n        i = order[r][ptr[r]]; ptr[r] += 1\n        taken.add(i)\n        d = kept[i]\n        used[r] += d[\"tok\"]\n        sel.append(d[\"id\"])\n    print(f\"[5/5] selected {len(sel)} docs; est tokens/register: \"\n          f\"{[int(u) for u in used]} (names {REG_NAMES})\", flush=True)\n    est = sum(kept[i][\"tok\"] for i in taken)\n    print(f\"      est total tokens {est/1e6:.1f}M (budget {BUDGET/1e6:.0f}M)\", flush=True)\n    assert len(sel) == len(set(sel))\n    json.dump(sel, open(OUT, \"w\"))\n    print(\"wrote\", OUT, flush=True)", "numLines": 70, "startLine": 280, "totalLines": 354}}
#45
reasoning (redacted)

encrypted chain-of-thought — recorded, not exposed

toolEdit
args
{
  "replace_all": false,
  "file_path": "/workspace/submission/curate.py",
  "old_string": "    # ---- quality gates: format junk removal (register-agnostic)\n    def ok(d):\n        return (d[\"nwords\"] >= 120 and d[\"nchars\"] >= 700\n                and d[\"cov\"] >= 0.50\n                and d[\"frac_alpha\"] >= 0.68\n                and d[\"frac_digit\"] <= 0.16\n                and d[\"frac_upper\"] <= 0.13\n                and d[\"frac_short_lines\"] <= 0.45\n                and d[\"uniq_line_ratio\"] >= 0.70\n                and 0.22 <= d[\"uniq_word_ratio\"] <= 0.85\n                and d[\"mean_line_words\"] >= 8.0\n                and d[\"pipe\"] <= 3.0)\n\n    elig = [d for d in docs if ok(d)]",
  "new_string": "    # ---- eligibility gates. These are deliberately LIGHT: measured on the dev\n    # target, junk-filtering on its own buys nothing over random selection, and\n    # tightening the gates *hurts* (it starves the match score of candidates and\n    # forces it deeper down each register's ranking). They only remove documents\n    # too short or too unlike running English prose to be scored meaningfully.\n    G = dict(nwords=80, nchars=450, cov=0.45, alpha=0.60, digit=0.20, upper=0.16,\n             short_lines=0.60, uniq_line=0.60, uwr_lo=0.18, uwr_hi=0.88,\n             line_words=6.0, pipe=6.0)\n\n    def ok(d):\n        return (d[\"nwords\"] >= G[\"nwords\"] and d[\"nchars\"] >= G[\"nchars\"]\n                and d[\"cov\"] >= G[\"cov\"]\n                and d[\"frac_alpha\"] >= G[\"alpha\"]\n                and d[\"frac_digit\"] <= G[\"digit\"]\n                and d[\"frac_upper\"] <= G[\"upper\"]\n                and d[\"frac_short_lines\"] <= G[\"short_lines\"]\n                and d[\"uniq_line_ratio\"] >= G[\"uniq_line\"]\n                and G[\"uwr_lo\"] <= d[\"uniq_word_ratio\"] <= G[\"uwr_hi\"]\n                and d[\"mean_line_words\"] >= G[\"line_words\"]\n                and d[\"pipe\"] <= G[\"pipe\"])\n\n    elig = [d for d in docs if ok(d)]"
}
Edit result
The file /workspace/submission/curate.py has been updated successfully. (file state is current in your context — no need to Read it back)

[metadata] {"filePath": "/workspace/submission/curate.py", "oldString": "    # ---- quality gates: format junk removal (register-agnostic)\n    def ok(d):\n        return (d[\"nwords\"] >= 120 and d[\"nchars\"] >= 700\n                and d[\"cov\"] >= 0.50\n                and d[\"frac_alpha\"] >= 0.68\n                and d[\"frac_digit\"] <= 0.16\n                and d[\"frac_upper\"] <= 0.13\n                and d[\"frac_short_lines\"] <= 0.45\n                and d[\"uniq_line_ratio\"] >= 0.70\n                and 0.22 <= d[\"uniq_word_ratio\"] <= 0.85\n                and d[\"mean_line_words\"] >= 8.0\n                and d[\"pipe\"] <= 3.0)\n\n    elig = [d for d in docs if ok(d)]", "newString": "    # ---- eligibility gates. These are deliberately LIGHT: measured on the dev\n    # target, junk-filtering on its own buys nothing over random selection, and\n    # tightening the gates *hurts* (it starves the match score of candidates and\n    # forces it deeper down each register's ranking). They only remove documents\n    # too short or too unlike running English prose to be scored meaningfully.\n    G = dict(nwords=80, nchars=450, cov=0.45, alpha=0.60, digit=0.20, upper=0.16,\n             short_lines=0.60, uniq_line=0.60, uwr_lo=0.18, uwr_hi=0.88,\n             line_words=6.0, pipe=6.0)\n\n    def ok(d):\n        return (d[\"nwords\"] >= G[\"nwords\"] and d[\"nchars\"] >= G[\"nchars\"]\n                and d[\"cov\"] >= G[\"cov\"]\n                and d[\"frac_alpha\"] >= G[\"alpha\"]\n                and d[\"frac_digit\"] <= G[\"digit\"]\n                and d[\"frac_upper\"] <= G[\"upper\"]\n                and d[\"frac_short_lines\"] <= G[\"short_lines\"]\n                and d[\"uniq_line_ratio\"] >= G[\"uniq_line\"]\n                and G[\"uwr_lo\"] <= d[\"uniq_word_ratio\"] <= G[\"uwr_hi\"]\n                and d[\"mean_line_words\"] >= G[\"line_words\"]\n                and d[\"pipe\"] <= G[\"pipe\"])\n\n    elig = [d for d in docs if ok(d)]", "originalFile": null, "structuredPatch": [{"oldStart": 286, "oldLines": 18, "newStart": 286, "newLines": 26, "lines": ["         json.dump(docs, open(sc_f, \"w\"))", "     print(f\"      scored {len(docs)} docs\", flush=True)", " ", "-    # ---- quality gates: format junk removal (register-agnostic)", "+    # ---- eligibility gates. These are deliberately LIGHT: measured on the dev", "+    # target, junk-filtering on its own buys nothing over random selection, and", "+    # tightening the gates *hurts* (it starves the match score of candidates and", "+    # forces it deeper down each register's ranking). They only remove documents", "+    # too short or too unlike running English prose to be scored meaningfully.", "+    G = dict(nwords=80, nchars=450, cov=0.45, alpha=0.60, digit=0.20, upper=0.16,", "+             short_lines=0.60, uniq_line=0.60, uwr_lo=0.18, uwr_hi=0.88,", "+             line_words=6.0, pipe=6.0)", "+", "     def ok(d):", "-        return (d[\"nwords\"] >= 120 and d[\"nchars\"] >= 700", "-                and d[\"cov\"] >= 0.50", "-                and d[\"frac_alpha\"] >= 0.68", "-                and d[\"frac_digit\"] <= 0.16", "-                and d[\"frac_upper\"] <= 0.13", "-                and d[\"frac_short_lines\"] <= 0.45", "-                and d[\"uniq_line_ratio\"] >= 0.70", "-                and 0.22 <= d[\"uniq_word_ratio\"] <= 0.85", "-                and d[\"mean_line_words\"] >= 8.0", "-                and d[\"pipe\"] <= 3.0)", "+        return (d[\"nwords\"] >= G[\"nwords\"] and d[\"nchars\"] >= G[\"nchars\"]", "+                and d[\"cov\"] >= G[\"cov\"]", "+                and d[\"frac_alpha\"] >= G[\"alpha\"]", "+                and d[\"frac_digit\"] <= G[\"digit\"]", "+                and d[\"frac_upper\"] <= G[\"upper\"]", "+                and d[\"frac_short_lines\"] <= G[\"short_lines\"]", "+                and d[\"uniq_line_ratio\"] >= G[\"uniq_line\"]", "+                and G[\"uwr_lo\"] <= d[\"uniq_word_ratio\"] <= G[\"uwr_hi\"]", "+                and d[\"mean_line_words\"] >= G[\"line_words\"]", "+                and d[\"pipe\"] <= G[\"pipe\"])", " ", "     elig = [d for d in docs if ok(d)]", "     print(f\"[4/5] {len(elig)}/{len(docs)} docs pass quality gates\", flush=True)"]}], "userModified": false, "replaceAll": false}
#46
reasoning (redacted)

encrypted chain-of-thought — recorded, not exposed

toolEdit
args
{
  "replace_all": false,
  "file_path": "/workspace/submission/curate.py",
  "old_string": "    # ---- register-balanced allocation with equal TOKEN quotas.\n    # Always extend whichever register is furthest below its quota, so every prefix\n    # of the emitted list (in particular the 12M-token prefix the trainer consumes)\n    # carries the target's 25/25/25/25 register mixture.\n    order = [sorted(range(len(kept)), key=lambda i: -kept[i][\"scores\"][r]) for r in range(NREG)]\n    frac = [w / sum(REG_W) for w in REG_W]\n    cap = BUDGET * OVERSHOOT\n    ptr, used, taken, sel = [0] * NREG, [0.0] * NREG, set(), []\n    while True:\n        cand = [r for r in range(NREG)\n                if frac[r] > 0 and ptr[r] < len(order[r]) and used[r] < cap * frac[r]]\n        if not cand:\n            break\n        r = min(cand, key=lambda r: used[r] / frac[r])\n        while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:\n            ptr[r] += 1\n        if ptr[r] >= len(order[r]):\n            continue\n        i = order[r][ptr[r]]; ptr[r] += 1\n        taken.add(i)\n        d = kept[i]\n        used[r] += d[\"tok\"]\n        sel.append(d[\"id\"])",
  "new_string": "    # ---- register-balanced allocation: interleave the four per-register rankings\n    # one document at a time, so all four registers are covered to the same RANK\n    # DEPTH. Measured against equal-token-share allocation this is better (dev PPL\n    # 354.8 vs 361.2 under identical gates): equalising tokens forces the thin\n    # registers (news, Q&A) deeper down their rankings than the fat ones, and the\n    # tail of a thin register is worse than the tail of a fat one. Emitting one doc\n    # per register per cycle keeps every prefix of the list register-balanced.\n    order = [sorted(range(len(kept)), key=lambda i: -kept[i][\"scores\"][r]) for r in range(NREG)]\n    quota = [BUDGET * OVERSHOOT * w / sum(REG_W) for w in REG_W]\n    ptr, used, taken, sel = [0] * NREG, [0.0] * NREG, set(), []\n    active = [r for r in range(NREG) if REG_W[r] > 0]\n    while active:\n        for r in list(active):\n            while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:\n                ptr[r] += 1\n            if ptr[r] >= len(order[r]) or used[r] >= quota[r]:\n                active.remove(r)\n                continue\n            i = order[r][ptr[r]]; ptr[r] += 1\n            taken.add(i)\n            d = kept[i]\n            used[r] += d[\"tok\"]\n            sel.append(d[\"id\"])"
}
Edit result
The file /workspace/submission/curate.py has been updated successfully. (file state is current in your context — no need to Read it back)

[metadata] {"filePath": "/workspace/submission/curate.py", "oldString": "    # ---- register-balanced allocation with equal TOKEN quotas.\n    # Always extend whichever register is furthest below its quota, so every prefix\n    # of the emitted list (in particular the 12M-token prefix the trainer consumes)\n    # carries the target's 25/25/25/25 register mixture.\n    order = [sorted(range(len(kept)), key=lambda i: -kept[i][\"scores\"][r]) for r in range(NREG)]\n    frac = [w / sum(REG_W) for w in REG_W]\n    cap = BUDGET * OVERSHOOT\n    ptr, used, taken, sel = [0] * NREG, [0.0] * NREG, set(), []\n    while True:\n        cand = [r for r in range(NREG)\n                if frac[r] > 0 and ptr[r] < len(order[r]) and used[r] < cap * frac[r]]\n        if not cand:\n            break\n        r = min(cand, key=lambda r: used[r] / frac[r])\n        while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:\n            ptr[r] += 1\n        if ptr[r] >= len(order[r]):\n            continue\n        i = order[r][ptr[r]]; ptr[r] += 1\n        taken.add(i)\n        d = kept[i]\n        used[r] += d[\"tok\"]\n        sel.append(d[\"id\"])", "newString": "    # ---- register-balanced allocation: interleave the four per-register rankings\n    # one document at a time, so all four registers are covered to the same RANK\n    # DEPTH. Measured against equal-token-share allocation this is better (dev PPL\n    # 354.8 vs 361.2 under identical gates): equalising tokens forces the thin\n    # registers (news, Q&A) deeper down their rankings than the fat ones, and the\n    # tail of a thin register is worse than the tail of a fat one. Emitting one doc\n    # per register per cycle keeps every prefix of the list register-balanced.\n    order = [sorted(range(len(kept)), key=lambda i: -kept[i][\"scores\"][r]) for r in range(NREG)]\n    quota = [BUDGET * OVERSHOOT * w / sum(REG_W) for w in REG_W]\n    ptr, used, taken, sel = [0] * NREG, [0.0] * NREG, set(), []\n    active = [r for r in range(NREG) if REG_W[r] > 0]\n    while active:\n        for r in list(active):\n            while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:\n                ptr[r] += 1\n            if ptr[r] >= len(order[r]) or used[r] >= quota[r]:\n                active.remove(r)\n                continue\n            i = order[r][ptr[r]]; ptr[r] += 1\n            taken.add(i)\n            d = kept[i]\n            used[r] += d[\"tok\"]\n            sel.append(d[\"id\"])", "originalFile": null, "structuredPatch": [{"oldStart": 325, "oldLines": 29, "newStart": 325, "newLines": 29, "lines": ["     for d in kept:", "         d[\"tok\"] = 0.2745 * d[\"nchars\"] + 1.0", " ", "-    # ---- register-balanced allocation with equal TOKEN quotas.", "-    # Always extend whichever register is furthest below its quota, so every prefix", "-    # of the emitted list (in particular the 12M-token prefix the trainer consumes)", "-    # carries the target's 25/25/25/25 register mixture.", "+    # ---- register-balanced allocation: interleave the four per-register rankings", "+    # one document at a time, so all four registers are covered to the same RANK", "+    # DEPTH. Measured against equal-token-share allocation this is better (dev PPL", "+    # 354.8 vs 361.2 under identical gates): equalising tokens forces the thin", "+    # registers (news, Q&A) deeper down their rankings than the fat ones, and the", "+    # tail of a thin register is worse than the tail of a fat one. Emitting one doc", "+    # per register per cycle keeps every prefix of the list register-balanced.", "     order = [sorted(range(len(kept)), key=lambda i: -kept[i][\"scores\"][r]) for r in range(NREG)]", "-    frac = [w / sum(REG_W) for w in REG_W]", "-    cap = BUDGET * OVERSHOOT", "+    quota = [BUDGET * OVERSHOOT * w / sum(REG_W) for w in REG_W]", "     ptr, used, taken, sel = [0] * NREG, [0.0] * NREG, set(), []", "-    while True:", "-        cand = [r for r in range(NREG)", "-                if frac[r] > 0 and ptr[r] < len(order[r]) and used[r] < cap * frac[r]]", "-        if not cand:", "-            break", "-        r = min(cand, key=lambda r: used[r] / frac[r])", "-        while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:", "-            ptr[r] += 1", "-        if ptr[r] >= len(order[r]):", "-            continue", "-        i = order[r][ptr[r]]; ptr[r] += 1", "-        taken.add(i)", "-        d = kept[i]", "-        used[r] += d[\"tok\"]", "-        sel.append(d[\"id\"])", "+    active = [r for r in range(NREG) if REG_W[r] > 0]", "+    while active:", "+        for r in list(active):", "+            while ptr[r] < len(order[r]) and order[r][ptr[r]] in taken:", "+                ptr[r] += 1", "+            if ptr[r] >= len(order[r]) or used[r] >= quota[r]:", "+                active.remove(r)", "+                continue", "+            i = order[r][ptr[r]]; ptr[r] += 1", "+            taken.add(i)", "+            d = kept[i]", "+            used[r] += d[\"tok\"]", "+            sel.append(d[\"id\"])", "     print(f\"[5/5] selected {len(sel)} docs; est tokens/register: \"", "           f\"{[int(u) for u in used]} (names {REG_NAMES})\", flush=True)", "     est = sum(kept[i][\"tok\"] for i in taken)"]}], "userModified": false, "replaceAll": false}
#47
reasoning (redacted)

encrypted chain-of-thought — recorded, not exposed

toolBashCheck gate looseness results
args
{
  "command": "cd /workspace; grep -A6 RESULTS /tmp/eval5.log; echo \"TIME: $(cat .timer/remaining_secs)\"",
  "description": "Check gate looseness results"
}
Bash result
TIME: 3257

[stdout]
TIME: 3257
[metadata] {"noOutputExpected": false}
#48
reasoning (redacted)

encrypted chain-of-thought — recorded, not exposed

toolBashPoll gate looseness results
args
{
  "command": "sleep 105; grep -A6 RESULTS /tmp/eval5.log; echo \"TIME: $(cat /workspace/.timer/remaining_secs)\"",
  "description": "Poll gate looseness results"
}
Bash result
TIME: 3146

[stdout]
TIME: 3146
[metadata] {"noOutputExpected": false}
#49
reasoning (redacted)

encrypted chain-of-thought — recorded, not exposed

toolBashPoll gate looseness results again
args
{
  "command": "sleep 110; grep -A6 RESULTS /tmp/eval5.log || tail -3 /tmp/eval5.log; echo \"TIME: $(cat /workspace/.timer/remaining_secs)\"",
  "description": "Poll gate looseness results again"
}
Bash result
launched light3
launched nogatesrr
launched w.25-.25-.25-.25
TIME: 3036

[stdout]
launched light3
launched nogatesrr
launched w.25-.25-.25-.25
TIME: 3036
[metadata] {"noOutputExpected": false}
#50
narration

Writing claim.md while the batch finishes:

toolWrite
args
{
  "file_path": "/workspace/claim.md",
  "content": "# Claim: at a fixed token budget, held-out perplexity is set by *register-mixture match*, not by \"quality\"\n\n## Hypothesis\n\nFor a fixed 12M-token budget drawn from a 200M-token raw web pool, held-out\nperplexity on a broad multi-register target is governed almost entirely by how well\nthe selection's **register mixture** matches the target's, and hardly at all by\ngeneric document-quality filtering.\n\nOperationally: score every pool document with a per-register Naive-Bayes /\nimportance-weight log-ratio against the *disclosed* target\n(`s_r(d) = (1/N_d) Σ_f c_f(d) log[p_r(f)/p_pool(f)]`, unigram+bigram features),\nthen fill the budget by interleaving the four per-register rankings. I predicted this\nwould beat a random selection by ≳20% and beat an *unbalanced* global top-k on the\nsame score by ≳5%, while heuristic junk-filtering alone would land at random.\n\n## Mechanism, and what it predicts *other than* the final perplexity\n\nThe pool is Common-Crawl-style web text; the target is four 250k-token blocks —\nWikiText-formatted Wikipedia, high-quality web prose, newswire, StackExchange Q&A.\nThe mechanism is that each target block is predicted by data of *its own register*,\nand registers are not interchangeable, so the budget must be spread over all four.\nThree observables follow, all measurable without looking at the final score:\n\n1. **Junk filters alone ≈ random.** If quality is not the operative variable, a\n   selection that applies only my format gates and then picks randomly inside them\n   should not beat random selection. → *Observed: gates-only 464.0 vs random 457.5\n   dev PPL — no gain (slightly worse).*\n2. **The per-register loss breakdown is strongly non-uniform, worst on Wikipedia,\n   for a surface-form reason.** The target's Wikipedia block is WikiText-tokenized\n   (spaced punctuation, ` @-@ `, ` @,@ `). I grepped the pool: **0 of 182,016\n   documents** contain that form (and only 69 contain `</p>`, so the Q&A block's\n   HTML form is absent too). No selection can supply it, so that block should carry\n   a much higher loss than the rest. → *Observed on the balanced selection:\n   wiki 691 vs web-prose 266, news 283, Q&A 303.* This is the binding ceiling on\n   the achievable score, and it is a property of the pool, not of the criterion.\n3. **Tightening the gates should *hurt*, not help.** If matching is what matters,\n   gates only shrink the candidate set and force the match score deeper down each\n   register's ranking. → *Observed, monotonically: strict gates 391.5 → moderate\n   354.8 → light 338.9 dev PPL.*\n\n## Falsification\n\nThe claim would have been falsified by any of:\n\n- **(a) Quality-only wins.** Gates-only ≈ balanced-match ⇒ quality is the variable.\n  *Result: 464.0 vs 338.9. Not falsified.*\n- **(b) Balance is inert.** Global top-k on the same score, ignoring registers,\n  matching balanced selection. *Result: 388.6 vs 354.8 under identical gates —\n  balance is worth ~9%. Not falsified.*\n- **(c) The gain is dev-topical, not register-level.** The profile is fitted on the\n  disclosed dev sample, so its edge could be topic leakage (documents about\n  Shackleton because the dev block is), which would not transfer to the hidden\n  sample. Test: refit the profile on only the **first half** of each register block\n  and evaluate on the **unseen second half**; compare against a profile restricted\n  to features occurring in ≥8 distinct target segments (register/style vocabulary\n  only, topical terms removed). If the edge were topical, the unrestricted profile\n  would collapse on unseen text. *Result: 362.5 (unrestricted) vs 363.9\n  (topic-stripped) — statistically indistinguishable, so the signal is register-level\n  and survives a disjoint sample. Not falsified; I kept the simpler unrestricted\n  profile.*\n- **(d) Mixture-pushing keeps helping.** If more of the highest-loss register were\n  always better, reweighting toward Wikipedia should keep improving things. It does\n  not: 31/29/20/21 → 360.5, 37/35/14/13 → 379.1, 45/40/8/7 → 380.3. The target\n  mixture, not the loss-weighted mixture, is the right allocation — consistent with\n  the claim and a real constraint on it.\n\n## Transfer\n\nWhat transfers is the recipe, not the id list: **decode the disclosed target, split\nit into its constituent registers, fit per-register importance weights against the\npool background, and interleave the per-register rankings to fill the budget.** It\nneeds no labels, no reference model and no GPU — the full pipeline over 182k\ndocuments runs in ~40 s on 14 CPU cores, so it scales to pools far larger than this\none.\n\nExpected limits when transferred:\n- The gain shrinks as the pool's natural mixture approaches the target's; here the\n  pool is dominated by low-value web chatter, which is why the margin is large.\n- The gain is capped by surface forms absent from the pool (observable 2). If a\n  target register's tokenization/markup does not exist in the pool, selection cannot\n  recover it; that block's loss stays high and dominates the average.\n- Interleaving by rank depth (not by equal token share) matters whenever registers\n  differ in how deeply the pool supports them: equalising tokens drags the thin\n  registers further down their rankings (354.8 → 361.2 when switched).\n- Gates should be set as loose as the scorer tolerates; they are a guard against\n  unscoreable documents, not a quality mechanism.\n\n## Result summary (dev PPL, frozen 30M GPT, 12M tokens, identical recipe)\n\n| selection | dev PPL |\n|---|---|\n| random pool sample (do-nothing baseline) | 457.5 |\n| format-quality gates only, random within | 464.0 |\n| global top-k on match score (no register balance) | 388.6 |\n| balanced match, moderate gates | 354.8 |\n| **balanced match, light gates (submitted)** | **338.9** |\n"
}
Write result
File created successfully at: /workspace/claim.md (file state is current in your context — no need to Read it back)

[metadata] {"type": "create", "filePath": "/workspace/claim.md", "content": "# Claim: at a fixed token budget, held-out perplexity is set by *register-mixture match*, not by \"quality\"\n\n## Hypothesis\n\nFor a fixed 12M-token budget drawn from a 200M-token raw web pool, held-out\nperplexity on a broad multi-register target is governed almost entirely by how well\nthe selection's **register mixture** matches the target's, and hardly at all by\ngeneric document-quality filtering.\n\nOperationally: score every pool document with a per-register Naive-Bayes /\nimportance-weight log-ratio against the *disclosed* target\n(`s_r(d) = (1/N_d) Σ_f c_f(d) log[p_r(f)/p_pool(f)]`, unigram+bigram features),\nthen fill the budget by interleaving the four per-register rankings. I predicted this\nwould beat a random selection by ≳20% and beat an *unbalanced* global top-k on the\nsame score by ≳5%, while heuristic junk-filtering alone would land at random.\n\n## Mechanism, and what it predicts *other than* the final perplexity\n\nThe pool is Common-Crawl-style web text; the target is four 250k-token blocks —\nWikiText-formatted Wikipedia, high-quality web prose, newswire, StackExchange Q&A.\nThe mechanism is that each target block is predicted by data of *its own register*,\nand registers are not interchangeable, so the budget must be spread over all four.\nThree observables follow, all measurable without looking at the final score:\n\n1. **Junk filters alone ≈ random.** If quality is not the operative variable, a\n   selection that applies only my format gates and then picks randomly inside them\n   should not beat random selection. → *Observed: gates-only 464.0 vs random 457.5\n   dev PPL — no gain (slightly worse).*\n2. **The per-register loss breakdown is strongly non-uniform, worst on Wikipedia,\n   for a surface-form reason.** The target's Wikipedia block is WikiText-tokenized\n   (spaced punctuation, ` @-@ `, ` @,@ `). I grepped the pool: **0 of 182,016\n   documents** contain that form (and only 69 contain `</p>`, so the Q&A block's\n   HTML form is absent too). No selection can supply it, so that block should carry\n   a much higher loss than the rest. → *Observed on the balanced selection:\n   wiki 691 vs web-prose 266, news 283, Q&A 303.* This is the binding ceiling on\n   the achievable score, and it is a property of the pool, not of the criterion.\n3. **Tightening the gates should *hurt*, not help.** If matching is what matters,\n   gates only shrink the candidate set and force the match score deeper down each\n   register's ranking. → *Observed, monotonically: strict gates 391.5 → moderate\n   354.8 → light 338.9 dev PPL.*\n\n## Falsification\n\nThe claim would have been falsified by any of:\n\n- **(a) Quality-only wins.** Gates-only ≈ balanced-match ⇒ quality is the variable.\n  *Result: 464.0 vs 338.9. Not falsified.*\n- **(b) Balance is inert.** Global top-k on the same score, ignoring registers,\n  matching balanced selection. *Result: 388.6 vs 354.8 under identical gates —\n  balance is worth ~9%. Not falsified.*\n- **(c) The gain is dev-topical, not register-level.** The profile is fitted on the\n  disclosed dev sample, so its edge could be topic leakage (documents about\n  Shackleton because the dev block is), which would not transfer to the hidden\n  sample. Test: refit the profile on only the **first half** of each register block\n  and evaluate on the **unseen second half**; compare against a profile restricted\n  to features occurring in ≥8 distinct target segments (register/style vocabulary\n  only, topical terms removed). If the edge were topical, the unrestricted profile\n  would collapse on unseen text. *Result: 362.5 (unrestricted) vs 363.9\n  (topic-stripped) — statistically indistinguishable, so the signal is register-level\n  and survives a disjoint sample. Not falsified; I kept the simpler unrestricted\n  profile.*\n- **(d) Mixture-pushing keeps helping.** If more of the highest-loss register were\n  always better, reweighting toward Wikipedia should keep improving things. It does\n  not: 31/29/20/21 → 360.5, 37/35/14/13 → 379.1, 45/40/8/7 → 380.3. The target\n  mixture, not the loss-weighted mixture, is the right allocation — consistent with\n  the claim and a real constraint on it.\n\n## Transfer\n\nWhat transfers is the recipe, not the id list: **decode the disclosed target, split\nit into its constituent registers, fit per-register importance weights against the\npool background, and interleave the per-register rankings to fill the budget.** It\nneeds no labels, no reference model and no GPU — the full pipeline over 182k\ndocuments runs in ~40 s on 14 CPU cores, so it scales to pools far larger than this\none.\n\nExpected limits when transferred:\n- The gain shrinks as the pool's natural mixture approaches the target's; here the\n  pool is dominated by low-value web chatter, which is why the margin is large.\n- The gain is capped by surface forms absent from the pool (observable 2). If a\n  target register's tokenization/markup does not exist in the pool, selection cannot\n  recover it; that block's loss stays high and dominates the average.\n- Interleaving by rank depth (not by equal token share) matters whenever registers\n  differ in how deeply the pool supports them: equalising tokens drags the thin\n  registers further down their rankings (354.8 → 361.2 when switched).\n- Gates should be set as loose as the scorer tolerates; they are a guard against\n  unscoreable documents, not a quality mechanism.\n\n## Result summary (dev PPL, frozen 30M GPT, 12M tokens, identical recipe)\n\n| selection | dev PPL |\n|---|---|\n| random pool sample (do-nothing baseline) | 457.5 |\n| format-quality gates only, random within | 464.0 |\n| global top-k on match score (no register balance) | 388.6 |\n| balanced match, moderate gates | 354.8 |\n| **balanced match, light gates (submitted)** | **338.9** |\n", "structuredPatch": [], "originalFile": null, "userModified": false}