Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
29908d8
docs(coref): design co-reference-aware compaction
amiddavid Aug 17, 2026
557449a
feat(coref): add the co-reference index and offload component
amiddavid Aug 17, 2026
756b595
feat(harbor): measure co-reference density on real agent traffic
amiddavid Aug 17, 2026
0362bd8
docs(coref): add the component reference, a cheat sheet, and nav
amiddavid Aug 17, 2026
e7a2623
fix(coref): never cut an output the index cannot see into
amiddavid Aug 17, 2026
e4a196b
docs(coref): address review — worked examples, split status, reward gate
amiddavid Aug 17, 2026
39a3fb2
docs(coref): separate Tier-2's blind detector from Tier-3's absent one
amiddavid Aug 17, 2026
9b09bf8
fix(coref): make the marker addressable and stop it claiming safety
amiddavid Aug 17, 2026
95f1965
fix(coref): lower min_batch_frac to a value real traffic can clear
amiddavid Aug 17, 2026
1017b08
docs(coref): record the deferral gate as designed and unquantified
amiddavid Aug 17, 2026
a068fab
docs(coref): record the held-out selection experiment and correct wha…
amiddavid Aug 19, 2026
9d5f937
fix(offload): scope the kept-verbatim guard by session and pin it
amiddavid Aug 19, 2026
eae9850
docs(coref): measure whether the deferral prize is reachable, and fix…
amiddavid Aug 19, 2026
720fecc
docs(reproduce): record that the benchmarks cannot run on Apple silic…
amiddavid Aug 19, 2026
55a817f
fix(coref.py): stop a session-key collision discarding 98% of a bench…
amiddavid Aug 20, 2026
b156686
docs: reattribute the ~27% saving from mask to extract_llm
amiddavid Aug 20, 2026
a5db8b7
fix(extract_llm): price the applied turn as a cache-write, not a cach…
amiddavid Aug 20, 2026
263c5de
docs(coref): first LOCA run -- coref acts, and mask removes 8.3x more
amiddavid Aug 20, 2026
3eb72d1
feat(extract_llm): allow_cached_prefix -- full-body reach, priced and…
amiddavid Aug 20, 2026
48ffc1b
docs(coref): deferral measured on LOCA -- 72% fewer summarizations, a…
amiddavid Aug 20, 2026
7c9347d
feat(extract_llm): prefix_classes -- make the pre-filter's class sele…
amiddavid Aug 20, 2026
ebd0e72
docs(experiments): add the iterNNN experiment log, retro-fitted
amiddavid Aug 20, 2026
753f3de
docs(experiments): iter003 -- reward integration works; correct an ov…
amiddavid Aug 20, 2026
0226e74
docs(experiments): iter004 design and pre-registered reading, before …
amiddavid Aug 20, 2026
7409b4c
docs(experiments): iter004 -- reward arms invalid, and why; the fold …
amiddavid Aug 21, 2026
200500f
docs(experiments): iter004b -- reward parity, demonstrated per-task n…
amiddavid Aug 21, 2026
80e95d5
fix(summarize): emit the summary as a user message, not system
amiddavid Aug 21, 2026
f7ed8f2
docs(experiments): iter005 -- deferral blocked by a shipped summarize…
amiddavid Aug 21, 2026
0971a32
fix(summarize): drop tool_results orphaned by the span it removes
amiddavid Aug 21, 2026
2b7e9f9
docs(experiments): iter005b/005c -- two summarize fixes, a third defe…
amiddavid Aug 21, 2026
2d6902d
fix(summarize): make a tool exchange atomic, fixing both pairing defe…
amiddavid Aug 21, 2026
d6c5231
feat(schema): static message-shape validator, and assert every preset…
amiddavid Aug 21, 2026
2edf6a1
feat(harbor): measure whether a prefix rewrite was ever already free
amiddavid Aug 21, 2026
bce735a
docs(coref): record what "fold" actually means, and that a rewrite is…
amiddavid Aug 21, 2026
b45b5dd
docs: capture the session's design discussion so it survives context …
amiddavid Aug 21, 2026
f6ce269
docs: close three gaps found by auditing the session's discussion points
amiddavid Aug 21, 2026
cd2d006
docs(experiments): root-cause the HTML 400s to the replay shim; stop …
amiddavid Aug 21, 2026
0045797
docs(results): correct the LOCA band table; three rows were rig artif…
amiddavid Aug 21, 2026
212977b
docs: note the two-sided effect, align the shim with forever, record …
amiddavid Aug 21, 2026
e2b1974
docs(experiments): 32k band solves 53% vs 64k's 25% -- the band was t…
amiddavid Aug 21, 2026
cd46b36
docs(results): write down the headroom argument and the reasoning err…
amiddavid Aug 21, 2026
cd1e8e5
docs(results): re-score the selection experiment for $0; merged stays…
amiddavid Aug 21, 2026
ecf4103
docs(experiments): pre-register iteration 010 before running it
amiddavid Aug 21, 2026
4eecbdc
docs(experiments): amend iter010 to n=75 before running; correct 5x c…
amiddavid Aug 21, 2026
ccd1a32
docs: correct the 5x n and cost error across every doc that carried it
amiddavid Aug 21, 2026
2936af7
feat(harbor): add paired reward analysis, validated before the arms land
amiddavid Aug 21, 2026
77f36e3
docs(experiments): pre-register iteration 011, the deferral experiment
amiddavid Aug 21, 2026
d8ed3cf
fix(harbor): report per-arm error counts; retract iter008's zero-erro…
amiddavid Aug 21, 2026
65f5962
feat(harbor): capture the request that causes the HTML 400, at the mo…
amiddavid Aug 21, 2026
535de68
docs(experiments): log the ITT deviation and three refuted HTML-400 h…
amiddavid Aug 21, 2026
4f6a57a
docs(experiments): localise the extra HTML-400s to the CG proxy hop
amiddavid Aug 21, 2026
ba7f013
docs(experiments): iteration 010 results -- no reward effect, and the…
amiddavid Aug 21, 2026
04a23ce
docs(experiments): abort iteration 011 -- summarize has a fourth shap…
amiddavid Aug 21, 2026
2ec2445
fix(schema): accept parallel tool exchanges; add tests reproducing an…
amiddavid Aug 21, 2026
ded9636
docs(experiments): pre-register iteration 012, the fold without summa…
amiddavid Aug 21, 2026
f378d5d
docs(experiments): iteration 012 -- savings_pct is inflated 3-8x and …
amiddavid Aug 21, 2026
62126f4
fix(apply): recover Anthropic tool-call ids; they were invisible to a…
amiddavid Aug 22, 2026
e4c4284
docs(experiments): record the apply root cause and two vacuous checks
amiddavid Aug 22, 2026
caf32d7
fix(apply): stop leaking role="tool" onto Anthropic wire on a count c…
amiddavid Aug 22, 2026
feaebb9
docs(experiments): record the two-stage fix and its live verification
amiddavid Aug 22, 2026
a048bc3
docs(experiments): record a third defect of the same family (thinking…
amiddavid Aug 22, 2026
728cfc3
docs(experiments): iter011 arm 1 -- 94.7% savings, 63% more money, sa…
amiddavid Aug 22, 2026
aab8e19
docs(experiments): iteration 011 complete -- deferral is real, monoto…
amiddavid Aug 22, 2026
838e8cf
docs: retract iter011's economic magnitude; disambiguate 'fold' vs 'm…
amiddavid Aug 22, 2026
d91b445
feat(extract_llm): add the merged design as bulk adjudication (select…
amiddavid Aug 22, 2026
fe4d8d0
docs(experiments): pre-register iteration 014, merged vs separate com…
amiddavid Aug 22, 2026
91b818e
docs(experiments): iter013 arm 1; shim repairs is the wrong lossy-bas…
amiddavid Aug 22, 2026
4ed3669
docs(experiments): 128k reveals a negative interaction between proxy …
amiddavid Aug 23, 2026
1d18312
docs(experiments): iteration 014 -- the merged design mostly declines…
amiddavid Aug 23, 2026
4d36f32
docs(experiments): record the stale-proxy bug that invalidated two arms
amiddavid Aug 23, 2026
4ca1f13
fix(extract_llm): merged mode was never bulk -- it adjudicated one ou…
amiddavid Aug 23, 2026
af760c6
docs(experiments): retract the 'proxy suppresses agent clearing' expl…
amiddavid Aug 23, 2026
4bc6905
docs(experiments): answer why CG arms carry 8x the context -- tool re…
amiddavid Aug 23, 2026
21c0ea1
docs(experiments): expand is CALLED and REFUSED -- corrects the zero-…
amiddavid Aug 23, 2026
459e532
docs+feat: always-advertise expand, and count the flap instead of inf…
amiddavid Aug 23, 2026
327643a
docs(experiments): iter016 stopped -- always-advertise fails, and two…
amiddavid Aug 23, 2026
7419d7e
docs(experiments): withdraw the "CG arms carry 8x the context" claim …
amiddavid Aug 23, 2026
0afa393
fix(proxy): answer unresolvable expand calls instead of relaying them…
amiddavid Aug 23, 2026
b818725
docs(experiments): pre-register iteration 017, the fixed expand loop
amiddavid Aug 23, 2026
e8f3f5b
fix(expand): restore expand results on the REQUEST path, covering the…
amiddavid Aug 23, 2026
619fd35
fix(metrics): surface expand_restored; measure whether the refusal re…
amiddavid Aug 23, 2026
6b10e7b
docs(experiments): iteration 019 — probe why merged declines, and cor…
amiddavid Aug 25, 2026
cc1aa9f
feat(offload): run merged as specified — bulk batch, forced obligatio…
amiddavid Aug 25, 2026
5bcc118
docs(experiments): iter020 amendment 1 — disable the econ gate for th…
amiddavid Aug 25, 2026
a9d666f
feat(components): prefix asks — put the question to the request's mod…
amiddavid Aug 26, 2026
9514a27
fix(proxy): pass the RESOLVED session to a prefix ask, and test the w…
amiddavid Aug 26, 2026
22263bb
docs(results): the floor and the gate — min_tokens vs economic_gate
amiddavid Aug 26, 2026
92da9d9
fix(offload): record the OFFERED batch, and stop the merged call firi…
amiddavid Aug 26, 2026
659e7a6
fix(cheapmodel): the adjudication reply was being truncated, and it r…
amiddavid Aug 26, 2026
fcf78cd
feat(adjudicate): declare a maintenance tool so the model answers in …
amiddavid Aug 26, 2026
2cc4232
docs(experiments): iteration 020 results -- 22/75 at parity cost, and…
amiddavid Aug 26, 2026
04edf94
docs(experiments): pre-register iteration 021, merged versus the ship…
amiddavid Aug 26, 2026
e351c70
docs(experiments): iteration 021 frozen inputs, recorded before launch
amiddavid Aug 26, 2026
11dd046
docs(experiments): iter021 amendment 1 -- errored runs score zero, an…
amiddavid Aug 26, 2026
3c92ea4
docs(experiments): correct iteration 020 from 22/75 to 21/75
amiddavid Aug 26, 2026
7fda3fd
docs(experiments): iter021 amendment 2 -- arm B ran below its coverag…
amiddavid Aug 26, 2026
f45702e
docs(experiments): iteration 021 results -- merged adds nothing detec…
amiddavid Aug 26, 2026
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
471 changes: 471 additions & 0 deletions components/offload/coref.go

Large diffs are not rendered by default.

457 changes: 457 additions & 0 deletions components/offload/coref_test.go

Large diffs are not rendered by default.

258 changes: 258 additions & 0 deletions deploy/harbor/cc_capture.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
#!/usr/bin/env python3
"""Convert Claude Code session transcripts into CONTEXT_GURU_CAPTURE JSONL, so coref.py
can measure co-reference density on REAL agent traffic without an eval-box run.

Why this exists. coref.py needs captured request bodies, and the corpus the improvement
plan cites (capture-tb / capture-swe / capture-swebench) lives on the eval box. But a
Claude Code transcript is the same traffic recorded one step earlier: the agent's own
append-only log of every message it sent. Converting it costs zero API dollars and yields
Tier-1-rich Read/Edit/Bash traffic — the substrate docs/proposals/coref-compaction.md §8
names as the right one for a deterministic reference detector.

Three things the transcript is NOT, and what this does about each:

1. It is one entry per content BLOCK, not per message. Consecutive same-role entries are
MERGED, because a real request body carries one assistant message with several blocks
(and one user message with the batched tool_results). Message COUNT is the axis
reference recency is measured on, so getting this wrong would rescale the whole A/B
distinction.
2. It spans many context windows. These sessions reach 3,000+ model turns, so no single
request ever held the whole thing — the agent compacted repeatedly. Emitting it as one
transcript would measure a request that never existed. So it is SEGMENTED at
--segment-tokens, each segment treated as its own session. This approximates the real
compaction boundaries (which the transcript does not record) by the budget that forces
them.
3. `thinking` blocks are model-authored, so they are mapped to text and count as a
reference-bearing surface. That is deliberate, not a shortcut: thinking is exactly
where a model restates the value it lifted out of a tool result, and the real wire
body carries it too.

Output is standard {provider, model, body} JSONL, one record per model turn, as an actual
capture would be. One deviation, and it is the only reason coref.py needed a change: a
full prefix per turn is O(n^2) bytes (47 GB across this machine's transcripts), and
non-final records are read ONLY for their token size (session_turns, the T estimate). So
every record except a segment's last carries `turn_tokens` plus just the segment's first
user message — enough for coref.py to size the turn and to group the segment — and
coref.py uses that field when present. A real capture has no such field and is unaffected.

Usage:
cc_capture.py <out.jsonl> [transcript.jsonl ...] [--segment-tokens N] [--min-turns N]
cc_capture.py <out.jsonl> --all [--segment-tokens N] # every local Claude Code session

--segment-tokens 180000 split a transcript into window-sized sessions (0 = never split)
--min-turns 8 drop segments with fewer model turns than this
--all use ~/.claude/projects/*/*.jsonl
"""
import glob
import json
import os
import sys

TOK = lambda s: max(1, len(s) // 4) # same proxy as coref.py / analyze_content.py


def load_entries(path):
"""Main-conversation user/assistant entries, in file order. Sidechain (subagent) entries
are a DIFFERENT conversation with its own context, so mixing them in would invent
references across two transcripts that never saw each other."""
out = []
with open(path, errors="replace") as f:
for line in f:
if not line.strip():
continue
try:
e = json.loads(line)
except ValueError:
continue
if e.get("type") not in ("user", "assistant") or e.get("isSidechain"):
continue
m = e.get("message") or {}
if m.get("content") is None:
continue
out.append(e)
return out


def blocks_of(entry):
"""Anthropic content blocks for one entry, with thinking mapped to text and anything
non-textual dropped (an image carries no identifiers an exact matcher could use)."""
c = (entry.get("message") or {}).get("content")
if isinstance(c, str):
return [{"type": "text", "text": c}] if c else []
if not isinstance(c, list):
return []
out = []
for b in c:
if not isinstance(b, dict):
continue
t = b.get("type")
if t == "text":
out.append({"type": "text", "text": b.get("text", "")})
elif t == "thinking":
out.append({"type": "text", "text": b.get("thinking", "")})
elif t == "tool_use":
out.append({"type": "tool_use", "id": b.get("id", ""),
"name": b.get("name", ""), "input": b.get("input", {})})
elif t == "tool_result":
out.append({"type": "tool_result", "tool_use_id": b.get("tool_use_id", ""),
"content": b.get("content")})
return out


def to_messages(entries):
"""Merge consecutive same-role entries into one message each (see docstring note 1)."""
msgs = []
for e in entries:
role = "assistant" if e.get("type") == "assistant" else "user"
bs = blocks_of(e)
if not bs:
continue
if msgs and msgs[-1]["role"] == role:
msgs[-1]["content"].extend(bs)
else:
msgs.append({"role": role, "content": bs})
return msgs


def msg_tokens(m):
"""Token size of one message, counted the way coref.py's session_turns counts it: the
reference-bearing surfaces and the tool-result bodies, not the JSON envelope."""
texts, results = [], []
c = m["content"]
for b in c:
t = b.get("type")
if t == "text":
texts.append(b.get("text", ""))
elif t == "tool_use":
texts.append(b.get("name", "") + " " + json.dumps(b.get("input", {})))
elif t == "tool_result":
rc = b.get("content")
if isinstance(rc, str):
results.append(rc)
elif isinstance(rc, list):
results.append("".join(x.get("text", "") for x in rc if isinstance(x, dict)))
elif rc is not None:
results.append(json.dumps(rc))
return TOK(" ".join(texts)) + sum(TOK(r) for r in results)


def segments(msgs, budget):
"""Split into sessions no larger than budget tokens (see docstring note 2). Splits only
BEFORE a user turn, so a tool_result is never separated from the assistant turn that
requested it — an orphaned pair would look like an output nobody asked for."""
if budget <= 0:
return [msgs]
out, cur, acc = [], [], 0
for m in msgs:
n = msg_tokens(m)
if cur and acc + n > budget and m["role"] == "user":
out.append(cur)
cur, acc = [], 0
cur.append(m)
acc += n
if cur:
out.append(cur)
return out


def first_user(msgs):
for m in msgs:
if m["role"] == "user":
return m
return msgs[0] if msgs else {"role": "user", "content": []}


def emit(seg, model, conv, out):
"""One record per model turn, as an append-only capture would hold. Only a segment's
last record carries the full transcript; earlier ones carry their size (see docstring).

`conv` is stamped explicitly because coref.py otherwise groups a session by the hash of
its first user message — correct for a real capture, where every request of a session
opens with the same task statement, but a mid-transcript segment opens on a tool_result
and those collide. Left inferred, 31 segments grouped down to 24 and the rest were
silently discarded, since only the largest member of a group is analyzed."""
turns = [i for i, m in enumerate(seg) if m["role"] == "assistant"]
if not turns:
return 0
head, acc, sizes = first_user(seg), 0, []
for i, m in enumerate(seg):
acc += msg_tokens(m)
if m["role"] == "assistant":
sizes.append(acc)
for n in sizes[:-1]:
out.write(json.dumps({"provider": "anthropic", "model": model, "conv": conv,
"turn_tokens": n,
"body": {"model": model, "messages": [head]}}) + "\n")
last = turns[-1]
out.write(json.dumps({"provider": "anthropic", "model": model, "conv": conv,
"body": {"model": model, "messages": seg[:last + 1]}}) + "\n")
return len(sizes)


def model_of(entries):
for e in entries:
m = (e.get("message") or {}).get("model")
if m:
return m
return "claude-sonnet-5"


def main():
args = sys.argv[1:]
if not args:
print(__doc__)
return 2
opt = {"--segment-tokens": "180000", "--min-turns": "8"}
files, i, use_all, out_path = [], 0, False, None
while i < len(args):
a = args[i]
if a == "--all":
use_all = True
elif a in opt:
i += 1
opt[a] = args[i]
elif a.startswith("--"):
print(f"unknown flag {a}")
return 2
elif out_path is None:
out_path = a
else:
files.append(a)
i += 1
if out_path is None:
print(__doc__)
return 2
if use_all:
files += sorted(glob.glob(os.path.expanduser("~/.claude/projects/*/*.jsonl")))
if not files:
print("no transcripts given")
return 2

budget, min_turns = int(opt["--segment-tokens"]), int(opt["--min-turns"])
n_seg = n_turn = n_src = 0
with open(out_path, "w") as out:
for path in files:
entries = load_entries(path)
msgs = to_messages(entries)
if not msgs:
continue
model = model_of(entries)
used = 0
stem = os.path.basename(path)[:8]
for k, seg in enumerate(segments(msgs, budget)):
if sum(1 for m in seg if m["role"] == "assistant") < min_turns:
continue
t = emit(seg, model, f"{stem}#{k}", out)
if t:
n_seg += 1
n_turn += t
used += 1
if used:
n_src += 1
print(f"wrote {out_path}: {n_src} transcripts -> {n_seg} sessions, {n_turn} turn records "
f"({os.path.getsize(out_path) / 1e6:.1f} MB)")
return 0


if __name__ == "__main__":
sys.exit(main())
Loading
Loading