Skip to content

core: extract family-neutral lane planners and halt lifecycle - #861

Closed
jayleaton wants to merge 4 commits into
ashhart:mainfrom
jayleaton:shared/lane-host-core
Closed

jayleaton wants to merge 4 commits into
ashhart:mainfrom
jayleaton:shared/lane-host-core

Conversation

@jayleaton

Copy link
Copy Markdown
Contributor

What this changes

Extract #662's family-neutral lane host and lane core on main c7137bb31a7dad924fb541a7068422127b9a94b2, preserving the prompt-piece lifecycle, opt-in planner, proposer/row-policy hooks, deterministic pricing and halt behavior with their tests. This branch is independent: it requires neither sessions (#637) nor TP, CUDA or DeepSeek code.

Illustrative control flow:

LaneHost
  default loop (existing whole/chunked prefill)
  opt-in Rounds -> admit -> prompt pieces -> finals -> shared decode
  halt -> next round boundary -> fail queued/filling/live requests
lanes.Engine -> optional proposer, row policy, timed pricing

Receipt

  • Environment, with the TensorFold commit, MLX or PyTorch version, machine and GPU, checkpoint and revision: local Linux CPU host, Zig 0.17.0; candidate 7c8ba10e622ed5695fb416cea160d23da8accb30, pinned base c7137bb31a7dad924fb541a7068422127b9a94b2. No checkpoint, GPU, MLX or PyTorch used.
  • Exactness, from tools/bench_concurrent.py --alone --serial or token_sha against "draft": false: no device/model receipt. Scripted host tests exercise identical token output for queued prompts in pieces versus whole prompts, cancellation, failure isolation and halt cleanup.
  • Decode speed before and after, from tools/bench_openai.py: not measured; this is a host-only extraction, and planner/backend performance needs a model/device gate.
  • Prompt speed before and after: not measured; optional prompt-piece processing can affect prompt execution and needs backend qualification.
  • Tests run, with pass, fail and skip counts: final clean-head checks below. Some targets used Zig’s cache; counts describe this invocation, not a full-suite total. Direct same-engine-tree receipts from the original extraction: engine API 117/117 and lane core 85/85 passed. The earlier uncached extraction host receipt recorded 753 passed, 5 skipped; those skips remain explicit. The app-only base advance leaves all engine sources unchanged.
Gresume-shared-lanes: commit 7c8ba10e622ed5695fb416cea160d23da8accb30 tree 663bcf6cfd0ff0c32fe3b05b18ad61e41c85c240 dirty 0 2026-10-15T01:06:55Z
install rc=0 Build Summary: 10/10 steps succeeded
test rc=0 Build Summary: 46/46 steps succeeded; 753/758 tests passed (5 skipped)
test-golden rc=0 Build Summary: 4/4 steps succeeded
fuzz-cortheon rc=0 Build Summary: 3/3 steps succeeded; 8/8 tests passed
test-cuda-host rc=0 Build Summary: 27/27 steps succeeded
test-server-cpu rc=0 Build Summary: 3/3 steps succeeded
zig fmt --check rc=0 0 files
git diff --check rc=0
7c8ba10e lean: 527 problems, 527 on the base, 0 new
FAILED STEPS 0

Merge Danger — Door: two-way. Blast Radius: core. A code revert restores the previous API and host loop. Optional planner hooks affect shared request scheduling, admission, cancellation and state cleanup for any backend opting in; device consumers still require qualification.

Checklist

  • 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.
  • No precision traded for speed. If the bits change, the description says which sums change and why.
  • Prompt processing is no slower than the last release.
  • The description says which platforms I ran, Metal M1 to M5 and CUDA, and which I could not.
  • 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. No AI attribution lines.

Extract the family-neutral lane changes from ashhart#662 onto pinned main,
including per-request proposers, row policies, deterministic pricing,
prompt-piece lifecycle and the round-boundary halt tests.

Ported from a4d95d8657c54adc0ec683eb84df84e22963414f,
55aedb0715266d73f216fc4414de1c5ebc5c4ef0 and
00025f0ab33c319b76fadc1d54b1ed10a1dfe8ea.
No sessions, TP or model-family dependency is required.
@ashhart

ashhart commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Thanks, @jayleaton. Needs changes at 7c8ba10. In zig/src/core/lane_rounds.zig:116, a seventeenth piece calls h.drop, freeing its job while its key remains in finals; runFinals then dereferences it. Please batch pieces or remove every remaining reference before freeing. Also, zig/src/core/lane_halt.zig:20-24 clears job lists even when copying them fails, losing requests without terminal events. Drain without allocating or transfer the existing lists' ownership. These are opt-in path defects; I found no separate default-loop token change.

@jayleaton

Copy link
Copy Markdown
Contributor Author

Thanks, @ashhart. Both are fixed in 7293d9e7. The current head, 4c351a39, is an empty commit on the same tree, added to rerun CI after the fmt job timed out downloading setup-zig.

  • Pieces past sixteen (lane_rounds.zig): pieces now run in bounded batches, and a job is no longer freed while a later piece or its final still refers to it. A failed repeated piece drops its job once, and that job's remaining pieces and finals are skipped.
  • Halt (lane_halt.zig): halt now takes over the existing queued and admitted lists under the lock. It no longer copies them, so it can't fail on allocation, and every request gets its terminal event.

New regressions in zig/src/core/lane_review_test.zig, run by zig build test:

  • "more than sixteen planned pieces retain their job until its final". Before the fix this faulted with the page allocator.
  • "halt transfers queued and admitted jobs when every subsequent allocation fails". Before the fix it expected two terminal events, got zero, and leaked the jobs.
  • "failed repeated pieces drop their job once and skip its remaining batches".

Host gate on tree a21d86cb (Linux x86_64, Zig 0.17.0): build 10/10, test 46/46, test-golden 4/4, fuzz-cortheon 3/3, test-cuda-host 27/27, test-server-cpu 3/3. zig fmt and git diff --check are clean, and lean_check shows 527 inherited findings and 0 new. desktop, mobile, zig and fmt pass at 4c351a39. No device or model run was done for this change.

Main (46a08c1) moved the lane host's endings to lane_host_end.zig, its
disk asks to lane_host_rows.zig, added Recall readers and Copy proposals,
and made deliver() take a finished job off `admitted` itself. ashhart#861's
changes go onto that shape:

- lane_stream.open carries main's stream fields (cacheKey/bornLen, Recall
  reader, images, key, fill_on); freeProposer also releases the Recall reader.
- halt's reason reaches main's ends.closeAll; failAll keeps its warning.
- the round planner's loop answers disk asks, refuses on a stale learner,
  writes on idle turns and flushes on its last stop, as main's loop does.
- the round planner no longer removes a delivered job again: with main's
  deliver it removed the next live job, or panicked at the list's end
  (lane_rounds_test's first test, index out of bounds, before this fix).
- windows.copyProposal: a priced proposer's copy stands as given, its none
  too, ahead of main's Recall fallback; new recall_engine_test case.
- engine_api.zig stays at 600 lines: Opened on one line, Rounds exported
  beside LaneHost, the redundant lane_host_test import dropped (lane_host.zig's
  test block imports it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
…/08a-config

The lane core's round planner, prompt pieces and halt come from the extracted shared branch, with its
bounded piece batches and allocation-free halt, in place of this stack's older copy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
…o stack/08b-engram

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
…o stack/08c-kernels

zig/build/cuda.zig: main's CUDA test runner block, plus the DeepSeek-V4.1 runner install.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
…to stack/08e-block

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
… stack/08r-runtime

aot.zig: main's exact-then-general variant search keeps this branch's trace (both passes note a hit);
specMatches answers what find can serve, so the fixture's unaligned pointer with a 16-divisible count takes the general variant.
abi.zig: main already has Memcpy2D (cuMemcpy2DAsync_v2 for nemotron); this branch's copy goes, its layout test checks main's names.
store_test.zig: the zero-budget test and the historyOf test both stay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
…to stack/09a-kv

build.zig: the KV step beside the sessions and DeepSeek-V4.1 steps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
…ack/09b-forward

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
…to stack/10-prefill

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
…o stack/11a-sampling

zig/build/cuda.zig: the keyed sampler's device step beside main's runner block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
…nto stack/11b-draft

The family drafter builds on the shared lane core from ashhart#861 unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
… stack/11c-device-drafts

dspark_dev.zig fills main's cuda.abi.Memcpy2D (src, src_pitch, dst, dst_pitch, width, height): the runtime layer
now keeps main's copy of that ABI struct instead of a second one with CUDA's field names. Same 128-byte layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
…) into stack/11d-batched-rows

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
… into stack/12a-serving-host

ashhart#663 now keeps drain and keepalive on the template path, and the review moved the family hook here (ashhart#702).
This layer adds that hook back: family.zig, chat_generation.zig and openai_run.zig, on top of current main's server:
- Recall, /v1/imprint, System One, vision input (normalizeWith, api.Image, cache_key), Stale refusals, token_sha256,
  and reply_text.Shown all keep main's versions. A family's own prepared images are `family_images`, kept apart
  from main's `images`.
- A family render now gets the prompt cache's rewind too: rewindLen probes through renderIds. That is the gap the
  ashhart#663 review named. No served-family gate has run on it yet.
- zig/build/server.zig: `addTo` also takes the tokenizer and lanes, for `dsv41_serve`; cortheon_fuzz, hip and xpu pass them.
  test-cuda-host keeps main's goldens, tokenizer, GLM and tool-parse tests, and also compiles tensorfold-native's root.
- Every server file imports the named `json` module (the json.zig-in-two-modules failure ashhart#663 hit).
- DeepSeek.load writes a missing tokenizer's diagnostic into the caller's problem arena instead of gpa. A new test
  in deepseek_test.zig leaks with the old allocation and passes with the fix.
- --recall with DeepSeek-V4.1 is refused at startup: Recall keys its record on the chat template's tokenizer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
… family hook) into stack/12b-serving-engine

tensorfold-dsv41 builds against main's server: its checkpoint CLI gets main's exlr8 import (server.withEngine),
and the host compile check's build options carry slide_test_hooks (false), which main.zig reads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
, family hook) into stack/13a-performance-host

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 16, 2026
…t#861) into stack/13b-performance-device

The shared corrections reach the device head: sessions null-unlimited / zero-none budgets and the Mac NVMe-test guard
(ashhart#637), the TP graph-cache startup agreement (ashhart#636, graph_cache_env), main's ashhart#642 NCCL send/recv, and ashhart#861's lane core.
- sessions_gpu.zig: TF_DSV41_SESSION_RESIDENT / _RESIDENT_GIB default to null (unlimited). The old 0 default
  would now mean "no idle chats kept". The store's policy comes from one `policy` function, and its test fails with
  the old default.
- zig/build/cuda.zig: main's runner block with the DeepSeek-V4.1 image-aware runner, tool, server and sampler installs.
- zig/build/dsv41.zig: the host compile check's options carry slide_test_hooks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ashhart ashhart mentioned this pull request Oct 17, 2026
@ashhart

ashhart commented Oct 17, 2026

Copy link
Copy Markdown
Owner

Thanks @jayleaton for the bounded-piece and allocation-free halt repairs, and for the three regressions. Both original lifetime findings are addressed in the common-runtime integration: a job survives every remaining piece/final, and halt transfers the existing lists so allocation failure cannot lose terminal events.

We retain the repeated-piece drop-once control and your authorship. The empty CI-rerun commit does not change that source result. Host coverage stays separate from each consuming family's device checks, and later window changes retain these shared planners rather than introducing another scheduling loop.

Posted by Ash's AI Assistant Synthena

ashhart added a commit that referenced this pull request Oct 18, 2026
…ced proposer's copy

@jayleaton's newest #861 head (e6df8ad) merges 1.0.12 into the PR.
d4ddbfa is that commit under his name with the same tree, parents and
message, less its AI co-author line, which this history does not carry.
Its resolution matches the one landed here in be757af, apart from
where Recall's reader is freed, the order of two Job fields and the
layout of Opened; the tree keeps ours, which also admits nothing while
the device is stale. Two things are new and taken: a test that a
priced proposer's copy is used as given, an empty one included, with no
gate and no Recall in its place, and a one-line comment that says so in
copyProposal.
ashhart added a commit that referenced this pull request Oct 18, 2026
…he 27B's K splits (#887), drafter releases (#893, #894), GLM's split check (#899) and Intel Arc (#802)
ashhart added a commit that referenced this pull request Oct 18, 2026
…restore's failure paths, fixed after review, in #861's, #802's and #888's lines
@ashhart

ashhart commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Thank you, @jayleaton, for fixing the planner findings and porting the round planner onto 1.0.12's host.

We carried your work into 1.1.0 in 4a9b8f7, preserving your authorship. Our integration adapts stream opening to the released host and makes failure, cancellation and close finish every held job without allocating or opening an unadmitted stream.

The fixtures exercise planner failure and allocation failure during cleanup. No family selects this planner in 1.1.0. We are closing the PR because its replayed commits have different IDs.

Posted by Ash's AI Assistant Synthena

@ashhart ashhart closed this Oct 18, 2026
jayleaton added a commit to jayleaton/TensorFold that referenced this pull request Oct 18, 2026
ashhart#861's lane planners are in main (903f601, be757af), so this layer takes main's lane files and drops its copy:
engine_api.zig, lane_halt*.zig, lane_host*.zig, lane_review_test.zig, lane_rounds*.zig, lane_stream.zig and
lanes/{backend,config,engine,engine_test,fake,lanes,open,pieces,proposer,recall_engine_test,trim,windows}.zig are
main's bytes. Each was byte-identical to ashhart#861's head e6df8ad here; DeepSeek-V4.1's host side imports none of them.
- build.zig: dsv41_build.add beside main's sys and checkpoint_config wiring, declared before both walks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
BlivionIaG pushed a commit to BlivionIaG/TensorFold that referenced this pull request Oct 20, 2026
…t pieces and halt

Three conflicts with this tree's lane host, resolved keeping both sides: lane_host.zig takes the planner's fields,
hooks and lane_stream.open beside the tip's Recall, stale-device, disk and fill-flag code; windows.zig's priced
proposer returns its copy inside the tip's Copy result; engine_api.zig imports the two new test files beside the
tip's list. takeCancels, failAll, closeAll and born had moved out of lane_host.zig on the tip, so ashhart#861's two edits
there (the failed-round warning and closeAll's halt) are carried to lane_host_end.zig.
BlivionIaG pushed a commit to BlivionIaG/TensorFold that referenced this pull request Oct 20, 2026
…e's host

lane_stream.open came from a host without Recall, image prompts or the fill flag, so the default loop would have lost
them: it now keys the cache lookup by the request's cache key and born length, gives the stream Recall's reader, its
images and key, frees the reader on a failed start, and raises fill_on as the inline code did. The planner loop calls
the cancel, failure and close functions where this tree keeps them (lane_host_end.zig); deliver already takes a
finished job off the list, so the loop no longer removes a second one. Like the default loop, the planner admits
nothing while the device is stale (refusing what waits), answers the app's kept-state questions, writes disk states
while idle and flushes them on a stop.
BlivionIaG pushed a commit to BlivionIaG/TensorFold that referenced this pull request Oct 20, 2026
BlivionIaG pushed a commit to BlivionIaG/TensorFold that referenced this pull request Oct 20, 2026
…ported by name

engine_api.zig was exactly 600 lines; ashhart#861's halt hook and its two test imports took it to 610, past the lean rule.
PreparedImage, Vision, VideoSource, FrameSink, PreparedVideo, VideoOffer and VisionOpen move unchanged into their
own file, and engine_api.zig re-exports each under its old name, so no caller changes.
BlivionIaG pushed a commit to BlivionIaG/TensorFold that referenced this pull request Oct 20, 2026
Main (87eab73) moved the lane host's endings to lane_host_end.zig, its
disk asks to lane_host_rows.zig, added Recall readers and Copy proposals,
and made deliver() take a finished job off `admitted` itself. ashhart#861's
changes go onto that shape:

- lane_stream.open carries main's stream fields (cacheKey/bornLen, Recall
  reader, images, key, fill_on); freeProposer also releases the Recall reader.
- halt's reason reaches main's ends.closeAll; failAll keeps its warning.
- the round planner's loop answers disk asks, refuses on a stale learner,
  writes on idle turns and flushes on its last stop, as main's loop does.
- the round planner no longer removes a delivered job again: with main's
  deliver it removed the next live job, or panicked at the list's end
  (lane_rounds_test's first test, index out of bounds, before this fix).
- windows.copyProposal: a priced proposer's copy stands as given, its none
  too, ahead of main's Recall fallback; new recall_engine_test case.
- engine_api.zig stays at 600 lines: Opened on one line, Rounds exported
  beside LaneHost, the redundant lane_host_test import dropped (lane_host.zig's
  test block imports it).
BlivionIaG pushed a commit to BlivionIaG/TensorFold that referenced this pull request Oct 20, 2026
…f a priced proposer's copy

@jayleaton's newest ashhart#861 head (e6df8ad) merges 1.0.12 into the PR.
0521eaa is that commit under his name with the same tree, parents and
message, less its AI co-author line, which this history does not carry.
Its resolution matches the one landed here in c38a3fc, apart from
where Recall's reader is freed, the order of two Job fields and the
layout of Opened; the tree keeps ours, which also admits nothing while
the device is stale. Two things are new and taken: a test that a
priced proposer's copy is used as given, an empty one included, with no
gate and no Recall in its place, and a one-line comment that says so in
copyProposal.
BlivionIaG pushed a commit to BlivionIaG/TensorFold that referenced this pull request Oct 20, 2026
BlivionIaG pushed a commit to BlivionIaG/TensorFold that referenced this pull request Oct 20, 2026
…restore's failure paths, fixed after review, in ashhart#861's, ashhart#802's and ashhart#888's lines
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