Skip to content

prompt radix: pages carry their reuse identity, and a request's chunk starts decide its resumes (#2444 P2, C6) - #2888

Open
laudney wants to merge 4 commits into
ashhart:mainfrom
laudney:radix-c6-identity
Open

laudney wants to merge 4 commits into
ashhart:mainfrom
laudney:radix-c6-identity

Conversation

@laudney

@laudney laudney commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

What this changes

P2 of #2444, its second step: reuse identity (C6) in the core radix store. A page matches only under the same identity as the copy store checks today, and every current store user stays byte-equal.

Before (#2875) After
A page matches its key words and the ahead words past it the same, and the exact identities {at, tokens, gh, gw, hash} of every image over its rows and ahead words, and its namespace and frame
Two pictures under equal key words (a template without image markers) could share a page two branches; the text before them stays shared, and a split keeps an image on both sides
A request's own chunk starts ignored: marks and resumes on the page or grid the copy store's rule: on a planned store they replace the grid in marks, keeps, hits and the page-only walk, so a grid point inside the request's chunk is never its resume point
A key of another length than its prompt used as given reuses and keeps nothing, with a note
A keep past the rows the pass prefills allowed refused: the store holds prefilled rows only, so decoded rows would need decode spans first
Eviction's "this conversation moved past it" and shared cuts compared words compare words, images, namespace and frame
GLM keyed by its cache key the same key, and its stream's image identities beside it (frame stays 0: GLM has no frame_key)

Every text user passes no images, the default namespace and no starts, so its pages, marks and hits are as before. Namespace and frame are compared per node rather than kept in separate roots: no page is shared across them either way, and eviction and reclaim walk one tree.

Checks on this head

  • Head commit: 7d2aa5f, on main 484437b.
  • Lean checker on the base and on this head: 341 and 341, 0 new (main 484437b).
  • Tests run: zig build test test-golden -Dhip=true: 7344 passed, 43 skipped, 2 failed: cuda_disk_test and lane_host_rows_test's close, the disk-timing tests that fail on main too on the same busy host; zig build test-kv-pool: 25 passed; the store's tests: 62 passed; zig fmt --check build.zig zig and git diff --check: clean.
  • CI: pending.
  • Not run, and why: concurrent against solo on this step (its parent prompt radix: checkpoint parts per cache group, one hold a page, page-only stores (#2444 P2, C3) #2875 carries the 8-stream and evicting rows on the same store).

Receipt

  • Main against branch, same flags, greedy, a six-turn chat and a second chat sharing its long system prompt, every request's token hash and cached count compared:
Store user Device Store on Evicting Unset Off
Qwen 3.6 35B-A3B NVFP4 (TF_QWEN_KV_SHARE) GB10 equal equal equal equal
GLM-5.3-Flash NVFP4 (TF_KV_SHARE), TP=2 2 × GB10 equal equal equal equal
Kolibri-1 FP8 (TF_KV_SHARE) GB10 equal equal equal equal
Gemma 4 31B MLX 4-bit (TF_KV_SHARE) GB10 equal equal equal equal
Nemotron 3.5 Lightning MLX 4-bit, HIP store gfx1201 equal equal n/a equal
Qwen 3.5 9B MLX 4-bit, HIP store gfx1201 equal equal (too small to keep) n/a equal

GLM at TP=2 with --vision, one long shared text and then picture A, picture B at the same position, A again: main and this branch give the same tokens and cached counts, 0 / 6144 / 8192 (B reuses the text before the picture; A again resumes past it and replies as the first A).

  • Boxes it reaches: the core radix store and every user of it (the five TF_KV_SHARE families, Qwen 3.5/3.6 on CUDA, Qwen 3.5 and Nemotron on HIP).
  • New switch? None.
  • Environment: GB10 rows main 6b739dd against this head; HIP rows main fb8fdf3 against the same P2.1 + P2.2 diff on it; Zig 0.17.0, CUDA 13 nvcc for sm_121, ROCm hipcc for gfx1201; checkpoints as in prompt radix: checkpoint parts per cache group, one hold a page, page-only stores (#2444 P2, C3) #2875.
  • Exactness: token hashes equal main on every row run; within a user, store on, evicting and off give the same tokens.
  • Decode and prompt speed: from the rows' done lines, resumed ttft 0.131 / 0.132 s (Nemotron HIP) and 0.109 / 0.107 s (Qwen 3.5 HIP), decode 226.6 / 225.1 and 82.4 / 82.4 tok/s, one run each. The change adds compares at a page edge, nothing per token.
  • Licence of any new weights or drafter: n/a.

Host: the store's tests (62) and the kv-pool checks (24): two pictures under one key, an image at a page edge with a lookahead word, splits across and at an image, two namespaces, a request start off the grid and a grid point inside its chunk, a key of another length, a keep past the prefilled rows, a page-only store on a request's schedule, eviction across namespaces, a shared cut in another namespace, and a picture through the CUDA adapter. Planted removals (request starts ignored, images ignored, namespace ignored in eviction) each fail their tests.

Checklist

  • The title and description match the head commit, including the receipt and the stack.
  • New tests fail before the change, pass after it, and skip cleanly without their dependency.
  • Comments and docstrings are one line. No measurements or history in the source.
  • No personal data, machine names, internal hosts or local paths in the diff or its commits. No AI attribution lines.
  • Every token still goes through the lane rounds. No serial path, and nothing that needs drafts off.
  • Drafted output equals "draft": false, a resumed prompt equals a fresh one, and concurrent equals solo. (Resumed equals fresh, above; the rest not run.)
  • No precision traded for speed.
  • Decode and prompt processing are no slower than main at one stream and the widest admitted. (One stream only.)

@ashhart

ashhart commented Nov 12, 2026

Copy link
Copy Markdown
Owner

Thanks @laudney. We've read the four commits on top of #2875. Every text user keeps today's path: the new schedule rule reduces to the old grid and page step, Query.of is always keyed, a text cut hashes as before, and the existing radix tests pass with only .of(...) added. The image and namespace checks are applied where they belong: per page with its lookahead words, on insert and on both sides of a split. The tests cover the cases we'd have asked for, including an image at a page edge and a shared cut in another namespace. No asks on the code.

The CI runs on 6b79b26b5 were cancelled a minute after they started, so there's no result yet. We'll re-run them. It lands right after #2875. If #2875's commits change on landing, a rebase onto main will give the run instead.

  • Synthena (Ash's Agent)

C6 of ashhart#2444 makes reuse depend on more than the key: a request's
image identities and frame, a namespace, its own chunk starts and
the rows it prefills. The family's Query now carries them through
kv_prompts (a core-side image identity, converted by the CUDA
adapter) and GLM passes its stream's images. The store enforces
none of them yet, so every store user is unchanged.
C6 of ashhart#2444 for the resume schedule: as in the copy store, a
planned store cuts and resumes at a request's own chunk starts
when it gives them and on its grid otherwise, so a grid point
inside the request's chunk is never its resume point; the marks,
keeps and both tree walks use one rule. A key of another length
than its prompt now reuses and keeps nothing, and a keep past the
rows a pass prefills is refused. Without starts every store user
cuts where it did.
C6 of ashhart#2444 for content: a page matches only when its words, the
words past it, the exact identities of the images over them, and
its namespace and frame are all equal, as the copy store compares
exact image identities beside its key. Two pictures under equal
key words are two branches, text before them stays shared, and a
split keeps an image on both sides. Eviction reads the same
identity, so another namespace's longer prompt never counts as a
conversation moving past a state. Text keys match as before.
A shared cut was recorded by its words alone, so a cut planned in
one namespace or over one picture could flag another identity's
state at the same words as shared, and keep it from its normal
eviction order. The record now hashes the namespace, frame and
image identities too (text in the default namespace hashes the
same words as before). A test through the CUDA adapter shows a
picture reaching the store: text pages shared, image pages not.
@laudney

laudney commented Nov 13, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main 484437b now that #2875 is in (its commits landed patch-identical, so this is the same four commits on top): head 7d2aa5f. On this head: the store's tests (63) and the kv-pool checks (25) pass, test-cuda-host passes, lean 341 / 341 with 0 new, zig fmt --check and git diff --check clean. #1850 hasn't landed, so nothing changes for it here.

@ashhart

ashhart commented Nov 14, 2026

Copy link
Copy Markdown
Owner

Thanks @laudney, that is the run we wanted. We rebased our check onto today's main as well: the mbox applies cleanly, the store and kv-pool steps pass here too, and lean still adds nothing.

No asks left. This can queue as it stands.

  • Synthena (Ash's Agent)

This branch has not been deployed

No deployments
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.

2 participants