Skip to content

Write a join's partner label with the frame, one time per anchor - #182

Merged
shreyashankar merged 6 commits into
claude/beautiful-brown-atl3offrom
claude/join-label-in-anchor-kv
Oct 3, 2026
Merged

shreyashankar merged 6 commits into
claude/beautiful-brown-atl3offrom
claude/join-label-in-anchor-kv

Conversation

@shreyashankar

@shreyashankar shreyashankar commented Oct 3, 2026 •

Copy link
Copy Markdown
Member

This PR is on top of fsdatalab/quail#178.

Problem

Each join request has this order of tokens:

[preamble][anchor document][frame: the question][partner label][partner document][answer cue]

The partner label is the same for every pair of one anchor. In quail-b it is the 6 tokens "\n\nDOCUMENT {1}:\n". Quail kept the preamble, the anchor, and the frame in KV, but it wrote the label again for each pair. For example, on LEP-6 (Qwen3 4B fp8, sf 0.5), it wrote the label for each of 1,043,064 pairs: 6.26M tokens, which is 72% of the LEP-6 KV regret.

Solution

  • JoinStage.runtime_spec() puts the first partner's label in the frame. Quail writes the frame one time for each anchor, so it now writes the label one time for each anchor. Each pair writes only its partner document and the answer cue.
  • The classification of joined rows does the same: the partner label goes into the anchor note.
  • The model gets the same token sequence as before, so the answers do not change.
  • The join cost (planner/joins.py), the classification cost of joined rows (planner/classify.py), and the speed of light estimate (planner/estimate.py) count the label one time for each anchor.
  • In a join with more than one partner, only the first label moves into the frame. The other labels stay in the pair.
  • The docs (execution.mdx, planning.mdx) describe the new frame.

Impact

IMDB-13, IMDB-15, BIO-6, and LEP-6, Quail only, Qwen3 4B fp8, sf 0.5, one H100. Before: f15c5ca (/results/benchmarks/quailb/20261002T061804Z-a6ccc1fe, scored with quail-b 4298e7a). After: 3807348 (/results/benchmarks/quailb/20261002T235411Z-07638ba6).

Query Time before Time after Fresh tokens before Fresh tokens after KV regret before KV regret after Labels before Labels after
IMDB-13 97.4 s 92.2 s 11.27M 10.32M 10.9% 2.7% .858 .858
IMDB-15 115.7 s 110.4 s 13.63M 12.56M 13.1% 5.7% .829 .829
BIO-6 198.6 s 168.0 s 17.54M 15.06M 18.4% 5.0% .720 .720
LEP-6 639.6 s 585.6 s 74.31M 68.06M 11.7% 3.5% .775 .775

The four queries take 956.2 s, compared with 1,051.3 s before (9.0% less).

Prediction and result. Before the run, the prediction was:

  • Fresh tokens decrease by 6 tokens for each pair. This was correct for BIO-6 (15.06M, predicted 15.05M) and LEP-6 (68.06M, predicted 68.05M). On IMDB-13 the saving was 0.95M, not the predicted 1.03M, and IMDB-15 was also above the prediction (12.56M, predicted 12.42M or less). The prediction did not count the 6 tokens that each anchor now writes with its frame. On IMDB-13 these are about 12,500 anchors × 6 = 75k tokens, which is most of the difference. I did not check the IMDB-15 difference separately.
  • Time: IMDB-13 (92.2 s) and IMDB-15 (110.4 s) are in the predicted ranges. BIO-6 (168.0 s, predicted 180 to 195 s) and LEP-6 (585.6 s, predicted 600 to 630 s) are faster than predicted.
  • Label agreement does not change by more than 0.002. The largest change is IMDB-15, +0.0002.

Testing

  • ruff, check_long_strings.py, vulture, and pytest pass (211 passed, 4 skipped).
  • New: test_a_join_writes_its_first_partner_label_with_the_frame checks that the frame holds the first label and that the tokens after the anchor do not change.
  • Changed: two planner estimates in test_classify.py are lower (0.071 s to 0.063 s, 0.413 s to 0.410 s), and the fresh tokens of a joined-row classification in test_classify_stream.py decrease from 19 to 16.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BGcUxUrkntTY43pDwWgfK5


Generated by Claude Code


Generated by Claude Code

Every pair of one anchor has the same partner label directly after the
frame, so the label is now part of the frame. Each pair writes only its
partner document and the answer cue. The token sequence is the same, so
the answers do not change. The joined-row classification, the join
cost, and the speed of light estimate count the label the same way.
@shreyashankar
shreyashankar added this pull request to stack #183 October 3, 2026 00:11
@shreyashankar
shreyashankar merged commit be79a80 into main Oct 3, 2026
1 check passed
@shreyashankar
shreyashankar deleted the claude/join-label-in-anchor-kv branch October 4, 2026 00:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant