Skip to content

Commit c950bc6

Browse files
authored
Merge pull request #597 from Metabuilder-Labs/sl-b42192e082b0
lots of fixes in resend, downsize, summrize relearn analyzers and leading with avoidable waste on ui
2 parents 85c0342 + 0fe45ea commit c950bc6

75 files changed

Lines changed: 8428 additions & 1664 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 47 additions & 5 deletions
Large diffs are not rendered by default.
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
# Does writing a lesson down make the same work cheaper? — a measurement
2+
3+
**Status: measured, negative. Do not build the session-level relearn rework on this corpus.**
4+
Run 2026-07-26 against the full local corpus (6,176 sessions / 527,089 spans / 2026-05-22 → 2026-07-24).
5+
Reproduce with `tokenjam/core/optimize/repeat_task.py` (unit tests: `tests/unit/test_repeat_task.py`).
6+
7+
## The question
8+
9+
`relearn` prices **failure episodes** — individual erroring tool calls, clustered by failure
10+
signature. Measured total on this corpus: **$46.26 across 55 clusters**. The hypothesis was that this
11+
is implausibly small because the episode is the wrong unit: the waste is not the failed call, it is
12+
the **inflated session** around it. An agent that does not know a project's constraints explores,
13+
reads the wrong files, backtracks, and re-sends a growing context on every turn of that flailing.
14+
15+
The proposed replacement: cluster sessions doing the same repeated work, then compare cost across the
16+
point at which the relevant lesson was written down. The field observation motivating it: setting up
17+
one project repeatedly took 40+ minutes, and dropped to under 20 minutes after its faults were
18+
codified.
19+
20+
Four things had to be true. Three of them are not.
21+
22+
## 1. Are repeat-task clusters identifiable? — **Yes, and easily**
23+
24+
Using the session's first user prompt as a task statement, with ids / paths / numbers masked and
25+
scoped to the project (`repeat_task.task_cluster_key`):
26+
27+
| | |
28+
|---|---|
29+
| sessions with a recoverable task statement | 2,711 |
30+
| distinct clusters | 346 |
31+
| clusters with ≥ 24 sessions | 19, covering 1,668 sessions |
32+
| largest cluster | 496 sessions |
33+
34+
31 clusters at n ≥ 5 cover **89%** of all sessions with a task statement. This is much better than
35+
expected, for a reason worth stating plainly: most of these prompts are **machine-issued templates**,
36+
so matching on them is closer to an identity test than a similarity test. False-positive risk is
37+
near zero *for templated work*.
38+
39+
That caveat is load-bearing. This corpus belongs to a heavy agent-harness user, and its repeat
40+
structure is harness-generated. A corpus of hand-typed human prompts would cluster far worse, and
41+
nothing here measures how much worse.
42+
43+
## 2. Does the method reach back far enough? — **No. ~30 days.**
44+
45+
The task statement lives in the agent harness's on-disk transcript, which the harness rotates on its
46+
own schedule. Availability, by month, over sessions tokenjam retained spans for:
47+
48+
| month | sessions in DB | with a recoverable task statement |
49+
|---|---|---|
50+
| 2026-05 | 42 | 0 (**0.0%**) |
51+
| 2026-06 | 3,906 | 142 (**3.6%**) |
52+
| 2026-07 | 2,188 | 2,186 (**99.9%**) |
53+
54+
This is fatal in a specific way. A before/after needs the **uninformed** runs, and the uninformed runs
55+
are by definition the *old* ones — the ones that happened before anyone had written the lesson down.
56+
Those are exactly the sessions whose task statement no longer exists. The high-confidence clusterer
57+
can only see the informed side.
58+
59+
For the motivating project specifically: 22 sessions in May, **0 with a recoverable task statement**.
60+
61+
## 3. Can the span-only fallback substitute? — **No, and this is the load-bearing negative**
62+
63+
Spans are retained past transcript rotation, so a span-only "same work" similarity is the only thing
64+
that reaches the uninformed era. The ticket proposed `cwd` + tool-sequence shape. That was scored
65+
against the task-statement ground truth on the window where both exist (972 July sessions with ≥ 8
66+
tool calls, 200,000 sampled session pairs). Baseline same-work pair rate: **0.147**.
67+
68+
| predicate | precision | recall | lift |
69+
|---|---|---|---|
70+
| identical opening-3 tools | 0.260 | 0.501 | 1.8× |
71+
| identical opening-8 tools | 0.247 | 0.183 | 1.7× |
72+
| tool-mix cosine ≥ 0.98 | 0.236 | 0.356 | 1.6× |
73+
| tool-mix cosine ≥ 0.99 | 0.247 | 0.202 | 1.7× |
74+
| **same project** (alone) | 0.383 | 0.244 | 2.6× |
75+
| same project + opening-8 | 0.481 | 0.051 | 3.3× |
76+
| same project + cosine ≥ 0.98 | 0.499 | 0.096 | 3.4× |
77+
| **same project + opening-8 + cosine ≥ 0.95** | **0.538** | **0.043** | **3.7×** |
78+
| same project + opening-12 + cosine ≥ 0.99 | 0.535 | 0.015 | 3.6× |
79+
80+
The best achievable operating point is **precision 0.54 at recall 0.04**: roughly **half** of the
81+
pairs it calls "the same work" are not, while it captures 4% of the real repeats. Tightening the
82+
predicate does not help — precision plateaus at ~0.54 and recall collapses.
83+
84+
The reason is mundane. Tool-call shape is dominated by *which tool the agent is holding*, not by
85+
*what task it is doing*. Almost every coding-agent session looks like Bash, Read, Edit, Bash, Bash.
86+
87+
`repeat_task.TOOL_SHAPE_MATCH` carries this measured 0.54 as data, and
88+
`measure_codification_delta` **refuses** to price any cluster derived from it.
89+
90+
### This also settles the `script` / `relearn` boundary
91+
92+
`analyzers/workflow_restructure.py` (the `script` analyzer) clusters sessions by ordered tool-call
93+
signature — the same primitive measured above. So the table is a direct audit of `script`'s
94+
clustering, and it says: **that primitive identifies a shape, not a task.**
95+
96+
That is not a bug in `script`, because a script replaces a *shape*. It is exactly the right unit for
97+
"could a deterministic script do this". It is the wrong unit for "was this the same work", which is
98+
why `relearn` cannot borrow it.
99+
100+
The two analyzers are **disjoint and should stay separate**:
101+
102+
| | `script` | `relearn` |
103+
|---|---|---|
104+
| recurrence detected | same tool-call **shape** | same **failure** signature |
105+
| question | is this deterministic enough to replace with code? | is this recurring because a lesson isn't written down? |
106+
| fix emitted | a script | a rule (CLAUDE.md / skill / hook) |
107+
| unit | the session's shape | the failure episode |
108+
109+
They overlap only in that both are triggered by repetition. Neither subsumes the other, and
110+
converging them would merge a shape-clusterer with a failure-clusterer that were measured here to be
111+
answering different questions. **Recorded boundary: keep both; `relearn` must not adopt `script`'s
112+
signature as a same-work test.**
113+
114+
## 4. Is the effect detectable above the noise? — **No, not at this effect size**
115+
116+
Even inside the tightest cluster obtainable — one machine-generated prompt template, one project —
117+
per-session cost is extremely noisy:
118+
119+
| cluster | n | median $ | CV | p10 | p90 |
120+
|---|---|---|---|---|---|
121+
| ticket-worker × project A | 87 | 4.41 | 0.79 | 1.48 | 12.07 |
122+
| ticket-worker × project B | 78 | 2.23 | 1.15 | 0.26 | 8.79 |
123+
| ticket-worker × project C | 95 | 1.34 | 1.21 | 0.51 | 7.32 |
124+
| ticket-worker × project D | 63 | 2.77 | 0.85 | 1.13 | 8.91 |
125+
| interactive sessions × project B | 29 | 20.32 | 1.36 | 1.71 | 296.48 |
126+
127+
Coefficient of variation **0.7–1.2**, with p10→p90 spanning an order of magnitude. The 95% bootstrap
128+
interval on the median at n ≈ 45 per side is **±46–49%**.
129+
130+
The effect being hunted is ~50% (40 min → under 20 min). **It sits at the noise floor of the best
131+
cluster available.** Detecting it reliably needs either far larger n per side or a paired design that
132+
holds task difficulty constant — and the residual variance here is task difficulty, since each run of
133+
the "same" template does a different ticket.
134+
135+
## 5. The before/after test itself
136+
137+
Codification events = commits touching `CLAUDE.md` / `learnings.md` in each project (135 events in
138+
the motivating project, spread over ~30 distinct days from 2026-05-28 to 2026-07-17 — codification is
139+
**continuous and drip-fed**, not a single step change, which is itself a problem for a before/after
140+
design).
141+
142+
Across the entire corpus there are **13** testable (cluster × codification-event) pairs with ≥ 12
143+
sessions on both sides. Results:
144+
145+
| project | event | n before / after | median $ before → after | ratio | 95% CI | verdict |
146+
|---|---|---|---|---|---|---|
147+
| C | 2026-07-18 | 56 / 39 | 0.92 → 3.09 | 3.35 | [1.92, 4.83] | dearer |
148+
| C | 2026-07-18 | 70 / 25 | 1.21 → 4.05 | 3.36 | [2.32, 6.28] | dearer |
149+
| C | 2026-07-19 | 76 / 19 | 1.27 → 4.11 | 3.23 | [2.31, 6.55] | dearer |
150+
| A | 2026-06-28 | 13 / 74 | 3.26 → 4.96 | 1.52 | [0.93, 2.10] | null |
151+
| A | 2026-06-29 | 30 / 57 | 3.52 → 5.14 | 1.46 | [0.97, 2.34] | null |
152+
| A | 2026-07-02 | 60 / 27 | 3.42 → 7.19 | 2.10 | [1.25, 2.84] | dearer |
153+
| B | 2026-07-03 | 24 / 54 | 5.33 → 1.45 | 0.27 | [0.17, 0.48] | cheaper |
154+
| B | 2026-07-10 | 26 / 52 | 4.87 → 1.45 | 0.30 | [0.17, 0.51] | cheaper |
155+
| B | 2026-07-16 | 50 / 28 | 3.36 → 0.52 | 0.16 | [0.09, 0.44] | cheaper |
156+
| A | 2026-07-16 | 24 / 39 | 2.83 → 2.77 | 0.98 | [0.54, 1.60] | null |
157+
| B (interactive) | 3 events | ~13-17 / ~12-16 || 0.56–1.25 | e.g. [0.06, 5.88] | null |
158+
159+
**The same treatment produces ratios from 0.16× to 3.35×, with intervals excluding 1.0 in both
160+
directions.** That is the signature of a confound, not an effect.
161+
162+
### The confound, identified
163+
164+
Model routing. The harness right-sizes the model per ticket, and that mix moved *hard* under every
165+
comparison:
166+
167+
| project | week | median $ | model mix |
168+
|---|---|---|---|
169+
| B | 2026-W27 | 6.48 | opus 94% |
170+
| B | 2026-W28 | 2.35 | sonnet 71%, opus 22%, haiku 6% |
171+
| B | 2026-W29 | 1.40 | sonnet 36%, opus 35%, haiku 27% |
172+
| C | 2026-W29 | 1.25 | opus 57%, sonnet 39% |
173+
| C | 2026-W30 | 7.00 | opus 99% |
174+
175+
Project B's "codification saved 84%" is the model right-sizing rollout. Project C's "codification
176+
cost 235% more" is the same mechanism running backwards. **5 of the 7 apparently-significant results
177+
had the model mix change underneath them.**
178+
179+
### Controlling for it
180+
181+
Restricting to sessions ≥ 90% served by a single model (`repeat_task.model_mix_is_stable`):
182+
183+
| project | event | n before / after | ratio | 95% CI | verdict |
184+
|---|---|---|---|---|---|
185+
| C | 2026-07-18 | 25 / 33 | 2.26 | [1.51, 3.12] | dearer |
186+
| C | 2026-07-18 | 34 / 24 | 2.36 | [1.50, 4.00] | dearer |
187+
| C | 2026-07-19 | 40 / 18 | 2.19 | [1.12, 4.26] | dearer |
188+
| **A** | 2026-06-28 | 13 / 73 | 1.48 | [0.91, 2.14] | **null** |
189+
| **A** | 2026-06-29 | 30 / 56 | 1.52 | [0.96, 2.37] | **null** |
190+
| **A** | 2026-07-02 | 59 / 27 | 2.17 | [1.26, 2.87] | **dearer** |
191+
| **A** | 2026-07-16 | 21 / 37 | 0.89 | [0.51, 1.55] | **null** |
192+
| B | 2026-07-03 | 22 / 22 | 0.40 | [0.24, 0.75] | cheaper |
193+
| B | 2026-07-10 | 24 / 20 | 0.45 | [0.25, 0.88] | cheaper |
194+
| B | 2026-07-16 | 30 / 14 | 0.37 | [0.21, 0.78] | cheaper |
195+
196+
**Project A is the motivating project — the known-positive the method exists to reproduce. It comes
197+
back `null` or `dearer` at every testable codification event**, with up to 144 model-matched sessions.
198+
The gate prices it at **$0.00**.
199+
200+
The signs still disagree across projects for the same treatment, so the surviving B/C results are
201+
residual confounding (ticket-difficulty drift, harness version), not a demonstrated effect.
202+
203+
## 6. What about the original field observation?
204+
205+
It is real as a *project-level trend*, and it is not attributable to codification. Median active
206+
session minutes for the motivating project:
207+
208+
| week | n | median active min | p25 | p75 | median $ |
209+
|---|---|---|---|---|---|
210+
| 2026-W22 | 16 | 111.4 | 9.6 | 812.4 | 21.03 |
211+
| 2026-W23 | 71 | **37.5** | 9.5 | 315.4 | 22.73 |
212+
| 2026-W24 | 76 | **45.1** | 11.8 | 255.5 | 24.29 |
213+
| 2026-W26 | 13 | 30.2 | 1.6 | 122.3 | 2.39 |
214+
| 2026-W27 | 12 | **16.7** | 3.0 | 454.6 | 3.20 |
215+
| 2026-W29 | 15 | 29.5 | 4.0 | 141.4 | 1.64 |
216+
217+
37.5–45.1 min falling to 16.7–29.5 min matches the recollection closely. But:
218+
219+
- The interquartile range is enormous (9.5 → 315 min in W23). The median is drifting inside noise an
220+
order of magnitude wider than the drift.
221+
- Median cost fell **10×** ($22.73 → $1.64) over the same span. No plausible codification effect is
222+
10×.
223+
- What actually changed is **what a "project A session" is**: long human-driven interactive sessions
224+
in W22–W24 gave way to short headless ticket-worker sessions from W26 on. That is a change of task
225+
mix, not a change in the informedness of a fixed task.
226+
- There is no repeat-task cluster spanning the boundary, because W22–W24 transcripts are gone.
227+
228+
The observation is consistent with codification helping. It is equally consistent with three other
229+
explanations, and this corpus cannot separate them.
230+
231+
## Verdict
232+
233+
**The uninformed-vs-informed signal cannot be measured on this corpus at a confidence that would
234+
support pricing.** Specifically:
235+
236+
1. Repeat-task clusters are identifiable — but only for ~30 days, and the uninformed side is older.
237+
2. The only similarity method that reaches further tops out at precision 0.54. Half its clusters
238+
would be wrong, in an unknown direction, behind a causal claim.
239+
3. Within-cluster cost noise (CV 0.7–1.2) puts the ±47% detection floor right at the ~50% effect size.
240+
4. Every apparently-significant delta is explained by model routing; controlling for it leaves the
241+
known-positive project at null.
242+
243+
Shipping a session-level relearn rework on this basis would produce **confident nonsense**, which is
244+
worse than $46.26. The session-inflation hypothesis is not refuted — it is **unfalsifiable with
245+
current instrumentation**.
246+
247+
## What this does to the write-budget verdict
248+
249+
The write budget suppresses a proposed rule when its modelled standing cost exceeds its modelled
250+
gross saving — recorded as net-negative for 18 of 25 clusters, 6–24× underwater. The hope was that a
251+
measured before/after would either validate or overturn that model.
252+
253+
**It does neither, and that is the honest status.** The measurement that could adjudicate it is not
254+
obtainable here. Concretely:
255+
256+
- **Not overturned.** There is no measured evidence that codification saves more than the model
257+
credits it for. In the one project where a saving was expected, the measured result is null.
258+
- **Not validated.** The model's blind spot is real and unaddressed: it counts what a rule costs to
259+
carry and never counts what it saves by preventing a flail. This measurement does not fill that
260+
gap; it shows the gap cannot be filled by observation alone at present.
261+
- **Practical consequence:** keep the current suppression rule, and stop describing it as
262+
empirically settled in either direction. It is a model, and it remains one.
263+
264+
## What would make this measurable
265+
266+
Not more analysis of this corpus — different instrumentation. In rough order of value:
267+
268+
1. **Persist the task statement at ingest.** A normalized, masked task-statement hash written to the
269+
session row at ingest survives transcript rotation and would extend the high-confidence clusterer
270+
backwards indefinitely. This is the single highest-value change and it is cheap.
271+
2. **Stamp the codification event on the session.** Sessions already resolve a project `cwd`;
272+
recording which CLAUDE.md/learnings.md revision was in effect turns the before/after from a
273+
date-join into an exact attribute, and handles drip-fed codification correctly.
274+
3. **Record the routed model on the session row.** The confound that dominated every result here has
275+
to be a first-class control, not something reconstructed from span aggregation.
276+
4. **Only then** revisit the session-level unit, on repeat clusters that straddle a *specific*
277+
lesson rather than a project-wide commit stream.
278+
279+
Until at least (1) and (3) exist, `relearn` should keep pricing failure episodes. The $46.26 is
280+
small, but it is *measured*, and the alternative on offer is not.

docs/optimize/reuse.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ Each cluster carries two framings, rendered side by side:
6666
| **cache-reuse** | `avg_planning_cost × (repetitions − 1)` | Recoverable going forward by reusing the existing skeleton instead of re-planning. Conservative — you already paid once. |
6767
| **script-replacement** | `avg_planning_cost × repetitions` | Upper bound — replacing every planning call with a deterministic template eliminates all of it. |
6868

69-
The aggregate `estimated_recoverable_usd` (what the Lens Overview tile
69+
The aggregate `past_overspend_usd` (what the Lens Overview tile
7070
reads) uses the conservative cache-reuse number. All dollar figures flow
7171
through `core/framing.py`, so subscription users see token-share framing
7272
and local users see token counts instead of dollars.

docs/optimize/subagent.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Rendering follows the same plan-tier-aware convention as the rest of `tj optimiz
5454

5555
## Estimate basis / confidence
5656

57-
Candidate-only in v1 — `estimated_recoverable_usd` and `estimated_recoverable_tokens` are deliberately `None`; the analyzer surfaces the spend sitting in flagged subagents (`flagged_cost_usd`) rather than assert a guaranteed recovery. `estimate_confidence` is `"heuristic"` and `estimate_basis` reads:
57+
Candidate-only in v1 — `past_overspend_usd` and `past_overspend_tokens` are deliberately `None`; the analyzer surfaces the spend sitting in flagged subagents (`flagged_cost_usd`) rather than assert a guaranteed recovery. `estimate_confidence` is `"heuristic"` and `estimate_basis` reads:
5858

5959
> spend concentrated in structurally-flagged subagents (premium model with little output, or large context with little output); review before re-dispatching — no guaranteed saving
6060

docs/optimize/verbosity.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ plans see the over-baseline token figure instead.
6666

6767
## Estimate basis / confidence
6868

69-
`estimated_recoverable_tokens` is the over-baseline output summed across flagged
70-
sessions; `estimated_recoverable_usd` prices it at **output** rates.
69+
`past_overspend_tokens` is the over-baseline output summed across flagged
70+
sessions; `past_overspend_usd` prices it at **output** rates.
7171
`estimate_confidence` is `"heuristic"` and `estimate_basis` reads:
7272

7373
> output tokens above the per-task-shape median, priced at output rates — a

tests/agent-pre-release-v0.4.0.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Focused on the delta since v0.3.5. The runner (`tests/agent-pre-release-runner.m
66
- TokenJam Lens UI rebrand (Overview triage screen + Optimize tab + real charts)
77
- Reuse — 5th analyzer + `tj report --reuse` artifact export
88
- `core/framing.py` — single source of truth for plan-tier rendering
9-
- `estimated_recoverable_usd` contract on every savings analyzer
9+
- `past_overspend_usd` contract on every savings analyzer
1010
- `cache_write_tokens` surfaced through DB → API → CLI → UI
1111
- Security: `.tj/config.toml` untracked + CI guard
1212
- Onboard: plain `tj onboard --plan` honored; tool_inputs capture toggle added; stale URLs removed
@@ -231,11 +231,11 @@ curl -s "http://127.0.0.1:7391/api/v1/optimize?since=30d" | python3 -m json.tool
231231
**Expected:**
232232
- The response includes a top-level `framing` key with `pricing_mode`, `plan_tier`, `display_rule` fields
233233
- The `findings` object includes a `reuse` key
234-
- `downgrade` is either null or a typed object with `estimated_recoverable_usd`, `monthly_savings_usd`, and a non-empty caveat
234+
- `downgrade` is either null or a typed object with `past_overspend_usd`, `monthly_savings_usd`, and a non-empty caveat
235235

236236
**Assertions:**
237237
```bash
238-
curl -s "http://127.0.0.1:7391/api/v1/optimize?since=30d" | python3 -c "import json,sys;d=json.load(sys.stdin);assert 'framing' in d and 'pricing_mode' in d['framing'];assert 'reuse' in d['findings'];g=d.get('downgrade');assert g is None or g.get('estimated_recoverable_usd') is not None;print('ok: framing + reuse + downgrade contract')"
238+
curl -s "http://127.0.0.1:7391/api/v1/optimize?since=30d" | python3 -c "import json,sys;d=json.load(sys.stdin);assert 'framing' in d and 'pricing_mode' in d['framing'];assert 'reuse' in d['findings'];g=d.get('downgrade');assert g is None or g.get('past_overspend_usd') is not None;print('ok: framing + reuse + downgrade contract')"
239239
```
240240

241241
---

tests/integration/test_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ async def test_optimize_chain_framing_and_recoverable_fields(client):
701701
findings = data.get("findings") or {}
702702
for name in ("cache", "script", "trim"):
703703
if name in findings:
704-
assert "estimated_recoverable_usd" in findings[name]
704+
assert "past_overspend_usd" in findings[name]
705705
assert "estimate_basis" in findings[name]
706706

707707

0 commit comments

Comments
 (0)