Align DeepSeek and GLM execution with DS4

This commit is contained in:
Georg Bauer
2026-09-11 17:18:45 +02:00
parent 02db0968ae
commit 48c2f751b4
27 changed files with 4517 additions and 400 deletions
@@ -0,0 +1,519 @@
# DeepSeek standalone-reference follow-up — 2026-09-11
The original antirez/ds4 process is used only under the user's explicit
reference-benchmark authorization. No original C engine is linked into DS4Server.
Evidence: `local-eval-results/deepseek-paired-20260911.nyUCsL/`.
**Measurement qualification (user clarification, 2026-09-11):** The user was
watching videos in parallel, using part of the GPU. The exact overlap with each
earlier run is not recorded. The current sequential comparisons are therefore
not controlled idle-device performance acceptance or causal before/after proof.
Their outputs and functional checks remain useful; timing receipts are retained,
not discarded. Do not attribute every gap to video playback or claim thermal
throttling from this information. Further throughput acceptance runs are deferred
until competing GPU activity can be controlled; code work and functional tests
can continue. This does not waive the2% requirement.
## Initial pair is not performance-parity evidence
Both AR processes finished the full Summary README → lighthouse Story → Python
`is_prime` conversation after a separate32-token OK warmup. Installed0731 GGUF
only, power100, Low, temperature0.6/top-p0.95/min-p0/top-k0/seed42, context32768,
quality/SSD/canary/DSpark off. Startup30s/progress45s,112GiB process-memory guards,
no total timeout. No builds or other model tests overlapped the GPU runs.
Two mismatches invalidate this initial pair (`ar-{reference,rust}.*`):
- The standalone driver requested2048 prefill rows, whereas the UI/harness
requested automatic (0), which the DeepSeek executor resolves to4096 at this
context. Original DS4's automatic setting also resolves to4096. The reference
driver now requests0 and records the public session prefill-cap value instead
of silently assuming the same chunk for all models. GLM's automatic request
remains unchanged. No product chunk reduction or special harness path.
- The same first prompt contains2741 tokens in the original but2742 in the
production runtime. The direct Rust tokenizer and all three original
continuation fixtures agree exactly; the mismatch occurs later, in the shared
cached-prompt renderer. A valid system-bootstrap tag with empty chat history
took the continuation branch and prepended an EOS before the first user turn.
Both UI and headless generation use this function.
## Root-cause correction and regression
`render_text_prompt` now requires nonempty history for the cached continuation
branch. A first user turn uses canonical full rendering, while `align_prompt`
still reuses its prepared system prefix. Real ongoing histories retain the
existing append-only behavior. No artificial wait, power change, kernel change
or KV-persistence rewrite was introduced.
The CPU-only `ds4_chat_matches_original_session_tokens` regression loads only
GGUF metadata/tokenizer and original recorded token IDs. It first checks the
three-turn tokenizer contract, then invokes the same shared renderer with the
actual system-bootstrap frontier and tag. Before the fix it fails with:
```text
shared bootstrap renderer differs: 2742/2741 tokens;
starts [0, 1, 128803, 45585]/[0, 128803, 45585, 260]
```
`token-before.*` is the passing standalone-tokenizer diagnostic;
`bootstrap-before.*` is the deliberately failing shared-runtime regression.
Neither file is overwritten or treated as a successful full parity run.
The test also accepts the saved GLM fixture to cover the other shared consumer.
Reproduction after building release tests:
```sh
DS4SERVER_CHAT_REFERENCE=local-eval-results/deepseek-paired-20260911.nyUCsL/chat-token-fixture.json \
target/release/test-supervisor 2048 30 30 \
target/release/deps/ds4_server-6141856e5c0fa6df \
ds4_chat_matches_original_session_tokens
```
The fixed renderer passes both saved DeepSeek and GLM three-turn fixtures
(`{chat,glm-chat}-token-fixture-fixed.*`,0.04/0.05s). Release all-target/all-feature
build, warnings-denied Clippy, rustfmt/diff checks,17 enabled sampling tests and
two enabled tokenizer tests pass. The model-dependent tests remain explicitly
ignored by default and were invoked with the recorded local fixtures above.
CLI SHA256: `9fb13c7f9049c3b5059b4fe79b68bf997dbe4e1bfdc4c631c130595cab8c359a`.
Standalone driver SHA256:
`ad7a4b94a5918505c58130d336d026e2c5b9640aab717ef185808bebd7536a25`.
## Corrected complete AR pair
`fixed-ar-{reference,rust}.*` and `fixed-ar-comparison.json` contain the new
original-then-Rust pair. The original session confirms prefill-cap4096 and
engine power100. Every text/thinking/token/cache comparison passes; all turns
end naturally. Counts are826/1444/199, prompts2741/3587/5057 and cached1/3567/5031.
| Turn | Rust / original engine-prefill ms | Rust / original decode t/s |
| --- | ---: | ---: |
| Summary | 6561.316 / 5425.137 | 36.916 / 37.813 |
| Story | 286.826 / 290.380 | 32.712 / 34.246 |
| Python | 334.486 / 369.018 | 32.020 / 32.734 |
This is functional agreement for the complete AR workload, **not** performance
acceptance: all three decode ratios are below98% in this single pair, and the
Summary prefill is slower. Different natural outputs in the invalid initial
pair must not be used as before/after throughput evidence. No GUI/canary run was
performed in this clean series.
## DSpark pair: functional comparison fails
Both full processes finished naturally and both watchdogs exited successfully.
The final comparison exits1 deliberately (`dspark-comparison.json`); this is
not an inference crash. Rust confirms opportunistic sampling, confidence0.6,
strict/exact off; the original loads the installed three-stage/block5 support
model and enables direct verifier commits.
The first prompt/cache counts agree (2741/1), but its output already diverges:
647 Rust tokens versus1208 original tokens. Thus later speed ratios compare
different histories and **cannot establish matched-work performance parity**.
Counts in Story/Python are1675/195 versus1455/347. The raw rates are retained
in the comparison file, not promoted to valid performance results.
An independent frontier defect is visible even within Rust's own history:
after2741 prompt +647 output tokens, the next cache is3389 instead of3388;
after3409 prompt +1675 output tokens, it is5085 instead of5084. A speculatively
returned EOS remains committed. The shared consumer currently rewinds only
GLM, while original `ds4_session_rewind` also truncates the DeepSeek logical
frontier and invalidates DSpark capture. This is separate from the now-fixed
first-prompt bootstrap EOS and from the first-answer decode divergence.
### Next cohesive DSpark work unit
1. Locate the first divergent cycle with identical recorded target history:
compare proposal IDs/confidence, GPU row argmax, accepted prefixes and
compression/DSpark capture state against original DS4. Cover full acceptance,
partial acceptance and rejection before declaring the full implementation
equivalent. Existing target-owned self-tests alone are not an oracle proof.
2. Match the consumer's EOS frontier and capture invalidation using DS4's
DeepSeek contract, including an accepted-EOS transition into the next user
turn. Do not transplant GLM's KDA rollback or merely hide the extra count.
3. Remove verified extra verifier work as part of that same comparison:
Rust `eval_batch_inner(collect_tops)` reads/clones every row's full vocabulary
and computes argmax on the CPU. Original opportunistic verification passes
`row_logits=NULL`, obtains GPU row tops, then reads only the committed row
(`ds4.c:6911269124,6915369159,6921069216`). Preserve the separate exact-
sampling requirements and verify row/stop decisions before timing the change.
Also verify per-turn counter scope across warmup/resident switching before
using cycle/acceptance ratios as exclusive stage measurements.
The four reviewed AR/DSpark Python answers (both implementations) each pass
their five generated assertions and5011 independent cases in isolated Python
with restricted builtins (`python-quality.jsonl`). No model-generated tools
were invoked. This quality check does not waive DSpark's token/state mismatch.
The six-cell performance goal, repeated timing acceptance and actual UI
responsiveness acceptance remain open. The user's working bundle is unchanged.
All model/reference/canary processes from this follow-up have terminated.
## DSpark cycle/state audit (second work unit)
Evidence: `local-eval-results/ds4-cycle-audit-20260911.vfsUc8/`. The original
source and installed artifacts remain the same. `DS4_SPEC_CYCLE_TRACE=1` is an
opt-in diagnostic in the shared production consumer and standalone reference
driver; it records the sampled first token, returned IDs, generated count and
committed position. It is off by default. Original `DS4_DSPARK_SPEC_LOG=1`
adds draft lengths, full/partial acceptance and scheduler decisions without
changing the graph. These traced runs are **not clean throughput acceptance**.
The initial complete traced pair reproduces the failure. In the first Summary
cycle, both targets sample671; Rust proposes12275 and emits only671, while DS4
proposes3967 and emits `[671,3967]`. The original warmup first differs in the
fifth returned cycle, after earlier partial accepts. This is not evidence of
a context-size or power-setting cause.
### Consolidated findings and implementation tasks
This table scopes the inspected path to the installed0731 DSpark support,
resident M5 Max execution and default opportunistic sampling. It does not claim
completion for arbitrary SSD/strict/exact modes or the six-cell performance goal.
Original line references below are for pinned `ds4.c` at `ec7642c`.
| Area | Original behavior / Rust discrepancy | Current action |
| --- | --- | --- |
| Initial support KV | `3262732821`: target HC expansion, per-stage HC mixing and attention normalization precede KV projection. Rust projected stage-0 normalized hidden directly to KV. | Implemented the missing operations using existing Metal calls and batch scratch. First Summary proposal now matches. |
| Single accepted draft | `36205` and `69112`: even one draft uses the target batch verifier. Rust used scalar decode, with different arithmetic and no captured suffix for the next support cache. | Removed the resident single-draft scalar branch. First two Summary cycles then match. |
| Verifier capture | `2795128053`: capture contains the preceding seed row plus all verified target rows. Rust retained only the suffix. | Added seed-row capture with the original slot stride and sufficient workspace. |
| Cache timing and gaps | `6666566732`: seed from the captured batch only when its end equals the next proposal position; otherwise crop/reset the absolute cache window. Ring maintenance does not create or bridge a window (`33329`, `27712`). Rust eagerly seeded each batch, extended windows after failed proposals and tracked only modulo positions. | Added deferred seed ownership and absolute window start; no false append after rejected proposals. Replaced batch workspaces are released before allocation of the next batch. |
| Partial acceptance | `6922169240`: ordinary partial commits invalidate row and batch captures, preserve compressor-prefix state, and do not claim support KV rows. Rust retained the captures and extended support counters; its old seed scratch also overwrote captured hidden rows. | Invalidate the deferred capture, preserve the original cache frontier, and stop overwriting hidden capture storage. Three and then32 recorded Summary cycles pass. |
| Scheduler | `53500`, `65215`: reset per request. `53666`: a window pause replaces, rather than maximizes with, the cold no-draft pause. | Reset in shared prompt alignment; regression covers7→4 and clearing prior-request counters. |
| EOS consumer | `73690`: logical DeepSeek rewind plus capture invalidation, not GLM KDA rollback. | Shared consumer now invokes the model-specific DeepSeek rewind; invalid forward rewind is rejected before mutation. Full next-turn verification still required. |
| Q8 confidence arithmetic | `34350` calls `matvec_any`, which dispatches type8 to activation-quantized Q8 matvec (`81448170`). The installed confidence tensor is Q8_0 `[4352,1]`; Rust instead used the dequantized-weight × F32-input reference calculation. | Quantize activations for the confidence dot too, and match the two alternating four-lane ARM SDOT/FMA accumulators (`7510`) in both confidence and Markov scoring. CPU regression distinguishes the quantized result from the old F32-input dot. |
| Confidence/output head | `6678066835`: check first confidence before doing the vocabulary projection; read later rows only as required. Rust calculated all base logits and read all rows before the check. | Implemented the early gate and per-needed-row readback. Confidence-disabled execution keeps hidden/head submission fused. Full1755-cycle comparison remains exact; clean timing acceptance is separate. |
| Verifier output | `3632536431`, `69153`, `69210`: fuse head into the layer command sequence, obtain GPU row tops, read only the committed logits row. Rust drained before the head and cloned all vocabulary rows for CPU argmax. | Implemented fused submission, existing GPU argmax/top-k reductions and committed-row readback for the ordinary verifier. Exact sampling retains all target distributions. Full1755-cycle default-mode comparison remains exact. |
| CPU Markov workers | `3388933963`: persistent helper pool and fused Q8 argmax; `1912` defaults to min(online CPUs,12), including the caller. Rust created scoped OS threads on every dense argmax, using all18 logical CPUs here. | Implemented persistent Rust workers with the existing Q8 arithmetic, identical contiguous row partition and ordered first-tie reduction. The caller executes slot0; default12 total threads and positive integer `DS4_THREADS` overrides up to32. All1755 original cycles remain exact; timing acceptance remains separate. |
| Verifier allocations | Original graph retains verifier scratch and GPU frontier/prefix buffers; Rust constructed `BatchScratch` and snapshot buffers for every verifier. | Reuse baseline and high-water prefix buffers, plus one verifier batch per existing padded row shape. Scratch is recycled only after delayed seeding or capture invalidation. Extended32-cycle oracle regression proves native-buffer identity reuse and byte-exact rollback; full-chat and timing evidence below. |
| Acceptance telemetry | Rust's executor-wide cycle counts and resident support counters have different ownership scopes. | **Open:** reconcile request/session counters before deriving acceptance ratios or exclusive stage percentages. |
Excluded after checking the guards: seed-batch fusion defaults to the ROCm
gfx1151 path, not this Mac (`53412`); the Markov GPU branch is under
`#ifndef __APPLE__` (`34266`); adaptive extra decode splits are pre-M5-only.
The output-head padding to8 rows is present in DS4's helper (`26086`) and is
not an unmatched Rust optimization. None of these were blindly enabled/removed.
### Runnable regression evidence
`dspark_matches_original_summary_cycles` loads only the installed GGUFs and
the recorded original JSONL, prepares the actual bootstrap boundary, samples
with the shared DS4 sampler and verifies each cycle's IDs and position. It is
ignored by default and explicitly supervised when run:
```sh
DS4SERVER_DSPARK_REFERENCE=local-eval-results/ds4-cycle-audit-20260911.vfsUc8/before-reference.jsonl \
target/release/test-supervisor 114688 30 45 \
target/release/deps/ds4_server-6141856e5c0fa6df \
dspark_matches_original_summary_cycles
```
- `cycle-test-before.*`: fails at generated2, Rust `[10059]` versus original
`[10059,260,13672,294,270]`.
- `cycle-test-batch.*`: after single-row batch verification, fails at generated7,
Rust `[4496,3051,943,30941,22]` versus original `[4496,3051,943,30941]`.
- `cycle-test-capture.*`: all three unchanged expected cycles pass (7.28s).
- `cycle-test-32.*`:32 original cycles, prior-request scheduler reset and
safe logical rewind pass (9.32s). These are functional diagnostics, not
stories truncated for a throughput comparison.
The original full pair, intermediate cache-only full run and failing receipts
are retained. No original C implementation was added to the application; no
model download, bundle replacement, commit or push was performed.
### Confidence follow-up from the full chat
The subsequent `fixed-rust.*` full run matches451 complete returned cycles
(including warmup), then differs at Summary generated1018. The first divergent
decision is one cycle earlier: at position3759, original DS4 proposes `[588,699]`
and rejects the first draft, while Rust's confidence logit0.40281284 falls below
the0.6 sigmoid threshold and suppresses drafting entirely. The different
no-draft scheduler decision then changes the returned cycles. All turns still
end naturally, with counts1194/1424/296 and **no extra cached EOS**; this is
progress, not a matched-output performance pair (`fixed-cycle-comparison.json`).
Read-only inspection of the installed support GGUF confirms the confidence
head type8/Q8_0,4352 inputs. Correcting the activation quantization yields
confidence0.4063788 at that exact position and the original two draft IDs.
The stable Rust SDOT intrinsic is unavailable in this toolchain; the two SDOT
instructions are isolated in guarded Rust inline assembly, with stdlib NEON
FMA/reduction and the existing scalar fallback. No C host code or dependency
was added. Six focused DSpark CPU/layout tests pass, including the new
quantized-confidence test. Release all-target/all-feature build, Clippy with
warnings denied, rustfmt and diff checks pass after the correction.
Checkpoint-load invalidation now clears the new deferred capture and absolute
cache metadata through the same `reset_cache` helper as session reset. This
does not change the checkpoint format or disk KV policy.
### Completed functional comparison, performance still open
`quantized-rust.*` completes all three turns to natural EOS. All1755 returned
cycles match the original recording exactly, including warmup, IDs and committed
positions (`quantized-cycle-comparison.json`). All three text, thinking,
completion, prompt and cached-token comparisons pass
(`quantized-result-comparison.json`):
| Turn | Completion tokens | Prompt / cached | Rust / original prefill ms | Rust / original decode t/s | Decode gap |
| --- | ---: | ---: | ---: | ---: | ---: |
| Summary | 1208 | 2741 /1 | 5562.979 /5519.685 | 36.128 /36.580 | 1.24% |
| Story | 1455 | 3969 /3949 | 261.651 /281.080 | 30.366 /31.321 | 3.05% |
| Python | 347 | 5450 /5424 | 323.474 /344.868 | 33.936 /34.777 | 2.42% |
These are **diagnostic** timings with cycle logging, not repeat-median clean
performance acceptance. Story and Python still miss even the single-pair2%
threshold; the missing early-confidence gate, verifier submission/readback,
allocation and worker-lifetime tasks above remain explicit work. No UI canary
or real GUI event-loop acceptance is claimed for this series.
The Story has a coherent title, narrative and ending, not a clarification or
broken output. The Python answer is byte-identical to the previous original
DSpark answer (`python-reference-unchanged.json`), whose five generated asserts
and5011 independent cases passed in `deepseek-paired-20260911.nyUCsL/python-quality.jsonl`.
Six DSpark CPU/layout tests,17 shared sampling tests, the separate heap-fallback
test and two tokenizer tests pass; model-dependent tests are not silently
counted as run. The explicit32-cycle live regression passed before the final
confidence correction, and the final full1755-cycle harness/oracle comparison
validates the production path after it.
Final CLI SHA256:
`2d15458d12a14457519a22232061ce76182123b24f23d1ae595df424c36963e5`.
Traced standalone reference SHA256:
`395cc58f8ea59afa0a6e22f8d46b3fb3f129bc367b8ee3ee1a0dd4bc0f01bd4d`.
The working app bundle remains
`ea4d555c2faf0940d9cbcf76d8638ca614a9cb2c6b034e3b2f80aeef86b0b339`.
### Early confidence and lazy verifier output
The shared Rust executor now follows the original early confidence gate before
the draft vocabulary projection. Hidden and logits rows are read only when the
proposal loop needs them; disabling confidence keeps hidden/head encoding fused.
The ordinary verifier keeps its layer commands alive through the output head
and the existing GPU argmax/top-k reduction. It reads only the committed
distribution; exact stochastic sampling retains all row distributions.
No prefill-cap, power, artificial pause, kernel math or KV persistence change.
`lazy-head-rust.*`, `lazy-head-cycle-comparison.json` and
`lazy-head-result-comparison.json` establish the unchanged complete1755-cycle
recording and all three answers/thinking/token/cache/stop boundaries. Seven
focused CPU/layout tests pass (two installed-model tests remain ignored by
default), including the committed-row boundary regression. Release all-target,
all-feature build and warnings-denied Clippy pass. This full default-mode
comparison is not a new exact-stochastic oracle claim.
CLI SHA256: `de10b537c2cf2bfbb680ebc350e810305def3ca2ba59f0bea89f1d8c980699cb`.
The original driver and working app bundle hashes above are unchanged.
`run-clean-pairs.sh` records serial three-turn timing pairs without cycle logging,
original proposal logging or canary, with alternating reference-first/Rust-first
order. Both workers retain startup/progress/memory supervision, no total timeout.
The first postprocessing command used the wrong reference event name (`result`
instead of `reference_result`) and failed after both workers had finished; the
comparison was corrected against the unchanged receipts, with no inference rerun.
All six processes completed successfully, with natural EOS for all nine Rust
answers and matching reference content, thinking, prompt, cache and completion
counts (1208/1455/347 in every pair). `clean-{1,2,3}-comparison.json` and
`clean-pairs-summary.json` retain all results; none were discarded:
| Pair / order | Turn | Rust / DS4 prefill ms | Rust / DS4 decode t/s | Decode delta |
| --- | --- | ---: | ---: | ---: |
| 1 DS4→Rust | Summary | 6396.150 /5435.701 | 34.878 /37.298 | 6.49% |
| 1 | Story | 262.284 /289.008 | 28.623 /31.716 | 9.75% |
| 1 | Python | 350.909 /332.242 | 30.372 /35.511 | 14.47% |
| 2 Rust→DS4 | Summary | 7905.861 /7910.498 | 29.783 /28.784 | +3.47% |
| 2 | Story | 307.278 /376.104 | 25.918 /24.574 | +5.47% |
| 2 | Python | 363.522 /488.866 | 29.186 /27.959 | +4.39% |
| 3 DS4→Rust | Summary | 8389.686 /8292.276 | 27.523 /27.801 | 1.00% |
| 3 | Story | 301.627 /383.962 | 24.399 /24.151 | +1.02% |
| 3 | Python | 379.914 /458.934 | 27.995 /27.801 | +0.70% |
Pair3 is within2% in decode, with Summary prefill1.17% slower and the two short
continuation prefills faster. **It is not sufficient acceptance for this series:**
DS4 itself slows from37.30 to27.80 Summary t/s (about25.5%), and pair order changes
the sign of the relative gap. Median aggregation cannot establish a causal code
speedup in this nonstationary series. Do not compare the clean first pair against
the earlier logged pair as a before/after regression claim. Remaining worker and
allocation discrepancies still need their reference-aligned implementation and
an appropriately controlled follow-up.
Read-only system checks during pair2 reported no recorded thermal/performance
warning and25% system memory free; our benchmark processes ran strictly serially.
These observations do not prove stable GPU clocks or exclude other system GPU
activity. No application was stopped or configuration changed in response.
Rust supervisor totals were107.691/121.168/129.178s, maximum observed progress
gaps6.396/7.905/8.389s in prefill, supervisor lag60/59/59ms and exit0 throughout.
Canary was off: these are not GPU-canary or actual GUI event-loop measurements.
Original supervisor totals were96.236/124.665/127.935s, all with `error:null`.
The existing ignored `flash_0731_runs_exact_sampled_dspark` initially failed its
draft-count assertion: its four-token allowance takes the scheduler's existing
`max_tokens <10` no-draft branch. The test now allows16 tokens and explicitly
disables the confidence gate to exercise drafting independently of this short
fixture. It retains the original assertions and additionally invokes two-row
verification, checking both complete finite distributions, the GPU top ID
against CPU argmax, and the retained last-row logits. The supervised rerun
passes in1.60s (`lazy-head-exact-fixed.*`); the initial failure is retained in
`lazy-head-exact-test.*`. This is a regression check, not a new exact-sampling
reference/performance claim. No production setting was changed for this test.
Final warnings-denied Clippy, rustfmt and diff checks pass after this test-only
edit. No model or benchmark process remains from this work unit.
### Persistent CPU Markov workers
`src/engine/metal/markov.rs` replaces per-draft scoped thread creation with a
model-owned Rust worker pool. Original source contracts are `ds4.c:19121947`
(default min(online,12), caller plus helpers), `19712005` (contiguous partitions,
serial execution below512 rows), and `3385933963` (ordered first-tie Q8 argmax).
Positive integer `DS4_THREADS` settings are supported up to the original32-thread
limit. No CUDA/non-Apple Markov branch is enabled.
The GGUF mapping is shared through `Arc<Mmap>` without remapping or copying the
weights. Worker inputs own their temporary data: the full logits `Vec` is moved
into shared read-only ownership and returned after all dispatched jobs finish.
There are no borrowed raw pointers between worker lifetimes. Workers release
their input before signalling completion; results are drained on failure too,
and pool destruction closes and joins every helper. Existing dot/quantization
functions are reused without arithmetic changes. No dependency or native host
code was added.
`markov-rust.*` completes the full warmup and ongoing three-turn chat. All1755
original cycles and all answer/thinking/token/cache/EOS checks remain exact
(`markov-cycle-comparison.json`, `markov-result-comparison.json`). Two focused
Markov tests and seven GGUF tests pass, including thread and logits-buffer
reuse, ordered ties, shape validation and mapping bounds. Release all-target/
all-feature build and warnings-denied Clippy pass. The full diagnostic run is
not throughput acceptance. CLI SHA256:
`0e24c6e8102c2035cc89e93f77eede4235f5aa4611c36ce5fb225770641485f2`.
The remaining allocation task is concrete: `BatchScratch::allocate` reserves
workspace based on both row count and context position; `snapshot_spec_frontier`
allocates compressor/indexer/target snapshots every verifier cycle. Reuse must
preserve delayed support seeding, partial acceptance, error rollback and padded
output-head behavior. Merely retaining an arbitrary previous batch is not a
safe implementation of the original persistent scratch contract.
Two clean full pairs (`clean-markov-{1,2}-*`) ran DS4→Rust→Rust→DS4, power100,
same installed files/settings/warmup/ongoing chat, trace and canary off. All
content/thinking/prompt/cache/token checks pass; both workers in both pairs exit
successfully, without downloads or overlapping model processes:
| Pair | Turn | Rust / DS4 prefill ms | Rust / DS4 decode t/s | Decode delta |
| --- | --- | ---: | ---: | ---: |
| 1 | Summary | 6686.486 /5445.567 | 32.046 /36.968 | 13.32% |
| 1 | Story | 296.457 /280.371 | 26.201 /31.162 | 15.92% |
| 1 | Python | 376.741 /362.034 | 28.251 /34.122 | 17.21% |
| 2 | Summary | 8407.889 /8535.688 | 26.901 /27.488 | 2.14% |
| 2 | Story | 332.174 /383.535 | 23.301 /24.322 | 4.20% |
| 2 | Python | 398.755 /466.153 | 26.975 /28.215 | 4.40% |
The second pair still misses decode parity. DS4 Summary throughput again falls
by about25.6% over the series; no systemwide throttling cause is asserted. A
single `sudo -n powermetrics` query failed immediately because a password was
required (`markov-power-sample.txt`); it started no sampler. Rust supervisor
totals117.095/132.871s versus DS4 totals98.054/127.837s include different
frontend/finalization work and are not pure decode. Rust maximum progress gaps
were6.686/8.407s and supervisor lag59/58ms. No canary/UI-responsiveness claim.
To separate dispatch cost from GPU drift, the ignored CPU-only
`installed_markov_worker_dispatch` test uses installed Markov W1 row671 and the
actual W2 mapping with a fixed logits row. It compares per-call18-thread spawning
against persistent12 and18 workers, holding row arithmetic/input ownership
constant. Four alternating orders,128 calls per mode per round, all1536 argmax
results identical. Median times per128 calls:
| Dispatch | Median ms | ms/call |
| --- | ---: | ---: |
| Scoped18 | 40.356 | 0.3153 |
| Persistent12 (production default) | 36.077 | 0.2819 |
| Persistent18 (diagnostic only) | 30.496 | 0.2382 |
The default pool reduces this isolated dispatch/calculation time by10.6%, about
0.034ms per call; it does not explain seconds of whole-chat difference. This
diagnostic is neither a C Markov microbenchmark nor end-to-end parity evidence.
Production retains the reference's default12-thread policy. The same runnable
worker regression also closes one helper and checks that all other jobs drain,
an error is returned and the caller's original logits buffer is preserved.
Receipts: `markov-dispatch-test.*`, `markov-worker-failure-tests.txt`.
Final verification after the additional test-only coverage: seven enabled
DSpark tests pass; the explicitly supervised exact-sampling test passes in1.35s;
warnings-denied Clippy, rustfmt and diff checks pass. All processes from this
work unit have finished. No app bundle replacement, commit or push was made.
The full six-cell performance goal remains open.
### Persistent verifier buffers: functional checks pass, timing remains unaccepted
The next implementation reuses baseline compressor/indexer snapshots, high-water
prefix snapshots and one verifier workspace per existing padded row shape.
Deferred seed ownership determines when a batch can be recycled; full-prefill
workspaces are not retained. Position-sensitive verifier storage reserves the
session context. Existing output-head row padding, sampling, power and command
submission boundaries are unchanged. Error rollback keeps its previous behavior;
an error may drop scratch and require allocation on the next attempt.
Evidence remains in `local-eval-results/ds4-cycle-audit-20260911.vfsUc8/`.
CLI SHA256: `4f3643bd854cad1d317fdd6bb93649327902b19cb3cd7b9cfff24a760d57e880`.
The prior CLI is retained as `before-verifier-reuse-ds4-server` for a later
controlled comparison; merely comparing older sequential runs is insufficient.
- `reuse-cycle-test.txt`: the32-cycle original oracle passes, now also checking
native buffer identities for both padded verifier shapes and byte-exact
compressor/indexer rollback after another target step.
- `reuse-cycle-comparison.json` and `reuse-result-comparison.json`: the complete
traced chat matches all1755 original cycles and all text/thinking/token/cache
checks. Traced timing is diagnostic only.
- `reuse-exact-test.txt`: supervised exact-sampling regression passes after the
reuse changes, including complete target-distribution readback.
- `reuse-build.txt`, `reuse-clippy.txt`, `reuse-dspark-tests.txt`: release build,
warnings-denied Clippy and seven enabled DSpark tests pass.
- GPU allocation at each measured turn end is95,039,750,144bytes, approximately
73MiB more retained than the prior Summary endpoint. This is retained scratch,
not proof of a throughput improvement.
Two complete pairs ran in DS4→Rust→Rust→DS4 order, with trace/canary off and no
overlapping model processes or builds. The user subsequently confirmed concurrent
video playback; "clean" in these artifact filenames means instrumentation off,
**not** an idle GPU. Both pairs preserve all outputs and exit successfully.
| Pair | Turn | Rust / DS4 prefill ms | Rust / DS4 decode t/s | Decode delta |
| --- | --- | ---: | ---: | ---: |
| 1 | Summary | 6679.941 /5718.646 | 34.204 /38.273 | 10.63% |
| 1 | Story | 259.070 /273.257 | 28.306 /33.200 | 14.74% |
| 1 | Python | 355.567 /333.715 | 29.343 /36.744 | 20.14% |
| 2 | Summary | 8968.416 /10283.116 | 26.678 /24.830 | +7.44% |
| 2 | Story | 324.111 /445.256 | 21.926 /22.225 | 1.35% |
| 2 | Python | 365.097 /560.790 | 23.092 /26.814 | 13.88% |
Receipts: `clean-reuse-{1,2}-{comparison.json,rust.jsonl,reference.jsonl}` and
matching stderr. Rust supervisor totals110.153/140.256s versus original
93.671/141.037s include frontend/finalization differences, not just decode.
Rust progress gaps6.679/8.968s and supervisor lag45/45ms are not GPU-canary or
GUI-eventloop delays. No new responsiveness acceptance, app bundle replacement,
commit or push. Remaining work includes telemetry ownership reconciliation,
reference code/cost audit and the controlled full six-cell comparison.
### Interim checkpoint requested by the user
The current work unit is being closed for commit/push, not declared full parity.
The commit-gate test run exposed an already-committed stale Qwen source-inventory
assertion:22 runtime units were expected although both HEAD's Metal export and
the pinned generator contain26. The read-only command below verifies the entire
export byte for byte against pinned sources (17 custom bodies,26 runtime units,
dynamic QSA sources). Only the stale expected count is corrected; no kernel,
hash, fixture or per-body assertion is changed or removed.
```sh
python3 tools/mtplx-kernel-source.py local-eval-results/mtplx-reference-e652d55 --gated-delta-source local-eval-results/mtplx-reference-env-0.32.2/lib/python3.12/site-packages/mlx_lm/models/gated_delta.py --check
```
The app bundle is rebuilt as required by the commit gates. This supersedes the
earlier statements that this follow-up had not yet replaced the bundle; no GUI
or new throughput series is launched. Unrelated `tools/__pycache__/` files are
left untouched and excluded from the commit.
Commit verification: `cargo fmt --all -- --check`, warnings-denied all-target/
all-feature Clippy, `make bundle`, and `cargo test --all-features` pass. The full
suite reports303 main tests plus4 supervisor and4 integration tests passed,
zero failures,202 explicitly ignored main tests. The separately supervised
32-cycle and exact-sampling results above remain distinct from these normal
gates. `codesign --verify --deep --strict` and the bundle's `model-eval --help`
also pass without opening the GUI. Final suite receipt:
`local-eval-results/ds4-cycle-audit-20260911.vfsUc8/interim-commit-tests.txt`.
+585
View File
@@ -0,0 +1,585 @@
# GLM execution and responsiveness follow-up — 2026-09-11
## User acceptance and scope
- Qwen is confirmed good in normal interactive use.
- GLM decode is now also confirmed good interactively. GLM prefill remains
usable, but feels less smooth than Qwen and affects other applications.
This is not a claim of a complete freeze or a new confirmed beachball.
- The user authorized resuming the outstanding work and explicitly authorized
compiling/running antirez/ds4 as a standalone, supervised reference benchmark.
No DS4 C objects are linked into DS4Server or its application bundle.
- Qwen's golden master remains MTPLX; DeepSeek/GLM remain antirez/ds4.
The accepted 2.6% Qwen Summary AR exception is not a general tolerance.
## Implemented execution changes
Both scalar GLM loops now flush periodically every four completed layers,
excluding the final layer and SSD expert streaming. Previously they flushed
only once at layer four. This follows the active indexed DS4 graph, including
scalar MTP fallback/rejection replay. The reference's dynamic per-layer mapping
fallback must not be confused with Rust's static non-expert decode mapping:
`glm_streaming_model_spans` retains non-expert tensors, the configured resident
expert prefix, and incompatible expert layouts; selected experts are loaded
through the existing native cache. No new per-layer SSD waits were introduced.
Low-memory dynamic mapping fallback parity is not established by this patch.
GLM 5.3 prefill progress now advances at existing completed GPU drains and after
the final output evaluation, not after every submitted layer. Chunk selection,
prefill flush/drain placement, Metal kernels, sampling and power policy are
unchanged. This corrects progress accounting; it does not by itself fix the
remaining prefill smoothness issue.
Targeted checks passed: periodic/final/SSD decode boundary test; existing
prefill boundary test; live two-row verifier acceptance, rejection, rewind,
scalar fallback, recurrent state, unused HC workspace guards and lifetime
counters. The live test additionally verifies completed-prefill progress points.
## Standalone reference and instrumentation
`tools/ds4-session-reference.rs` is a separate Rust benchmark driver for the
unchanged public DS4 engine/session interface. It is deliberately not a Cargo
target and is never included in the app. Its build script verifies reference
commit `ec7642cdd9ec81d01ad4b1fd8f8a3d1511533748`, the pinned header hash,
unchanged tracked engine sources and current reference objects. The arm64 ABI
layout is checked against Clang's record layout (engine options 280 bytes,
distributed offset 152, TP offset 216).
The public DS4 CLI/API maps `low` to `high`. The driver instead constructs the
Low system prefix through the public chat API and passes tokens to the original
session implementation. It also reproduces the UI's separate system-prefix
prefill (9 tokens for GLM), and retains generated token history in one session.
`glm53_reference_prompt_tokens_match_shared_runtime` checks every token of all
four prompt streams, including continued turns, against the production Rust
tokenizer. The first complete matched-bootstrap AR reference passed this check.
Build from the DS4Server checkout, with already-built reference objects:
```sh
bash tools/build-ds4-session-reference.sh /Users/gb/Projects/ds4 /absolute/path/reference
```
Run the resulting binary from the reference checkout under `test-supervisor`:
```text
test-supervisor 114688 30 45 --command /absolute/path/reference MODEL_GGUF glm on README_PATH
```
The driver uses power100, Low, context32768, temperature0.6, top-p0.95,
top-k0, min-p0, seed42, SSD streaming off and graph-selected GLM chunks.
Warmup is a separate session (up to32 tokens), followed by README Summary,
lighthouse Story, and Python `is_prime` in one ongoing chat, to natural EOS.
There is no total-runtime watchdog. Missing models fail; no downloads occur.
DeepSeek is supported by the driver's `deepseek` family argument, with the
installed DSpark support GGUF required for acceleration-on; it has not yet been
validated by this follow-up's GLM runs.
Optional `DS4_REFERENCE_CANARY=/absolute/path/ds4-server` starts the **same native
probe and monitor implementation** as the UI/harness in a separate process.
The `gpu-canary` CLI accepts phase labels on stdin and ends on EOF. A readiness
handshake waits for the first successful probe before model loading. Its
readiness/stall/sample reports are not model-progress watchdog heartbeats.
Clean throughput runs leave this variable unset. An external observer and an
in-process observer must not be treated as identical OS scheduling conditions.
`DS4_REFERENCE_IN_PROCESS_CANARY=1` instead enables a native probe thread inside
the reference process. It links the same `native/metal/ds4_canary.m` used by
DS4Server, with the same4096-byte blit, separate queue and100ms cadence, rather
than duplicating a Metal implementation. This bridge contains no model code.
Its Rust monitor logs per-sample phases/timing but is not the UI event loop.
The optional external observer can also be enabled simultaneously. Neither is
enabled for clean reference throughput. `reference --canary-self-test` exercises
readiness, two phases and clean shutdown without loading a model.
The initial external-probe integration test exposed a startup race: a phase
could end before the executable initialized. It was not worked around by
loosening the assertion; the adapter now requires a readiness handshake. The
initial diagnostic without that handshake is retained, not a full-startup proof.
## Measurements and limitations
All raw receipts, outputs and failed attempts are retained under
`local-eval-results/glm-scheduling-20260911.7VSaeW/` (ignored, local evidence).
The before binary is the secured `02db096` implementation, SHA256
`ab289f067a7a01c22113eec76aa896638d83e392242192e1440d14ed11524d5c`.
Fresh complete AR runs (after, then before), same output/reasoning/tokens/EOS:
| Turn | Tokens | Before decode t/s | After decode t/s | Before prefill ms | After prefill ms |
| --- | ---: | ---: | ---: | ---: | ---: |
| Summary |640|24.467|25.403|7561|6034|
| Story |1102|23.703|24.135|262|255|
| Python |200|24.726|25.401|305|302|
These are single sequential pairs, not drift-controlled medians. The large
summary-prefill difference cannot be attributed to a decode-only flush change.
No hard decode regression was observed; full performance parity is not proven.
The matched-bootstrap original DS4 AR reference completed naturally at
26.618/25.123/25.825 decode t/s, with779/1047/198 output tokens. Its generated
text differs from Rust despite matching initial prompt tokens/settings; later
contexts therefore also differ. This is not an exact-output performance pair.
Reference prefill timers measure session sync; Rust's current GLM `prefill_ms`
still includes the observed UI phase. Do not silently equate those intervals.
The new Rust MTP run retains the previous625/1026/196 completion tokens and
identical output/reasoning. Its draft acceptance fractions are241/385 (62.6%),
342/685 (49.9%) and95/102 (93.1%). Python therefore has the expected higher
acceptance; MTP's benefit is workload-dependent, not uniformly absent.
The fresh MTP before/after pair also preserves every output/reasoning token
and natural completion:
| Turn | Tokens | Before decode t/s | After decode t/s | Before prefill ms | After prefill ms |
| --- | ---: | ---: | ---: | ---: | ---: |
| Summary |625|19.988|23.154|9303|6190|
| Story |1026|17.728|19.295|306|272|
| Python |196|27.843|29.506|347|322|
The same sequential-run/drift limitation applies. This establishes no observed
hard regression, not a controlled causal speedup or reference-parity acceptance.
### Canary placement and timestamp attribution
The full `after-mtp-dual-canary` run had simultaneous internal/external probes.
The internal probe recorded867 successful samples, with a prefill maximum
of490.740ms and decode maximum3.180ms. The external probe was ready before model
launch and continued until after termination:3004 successful samples, overall
maximum3.331ms (startup), and1.572ms while labelled `preparing` across the model
lifetime. That external label is deliberately not turn/phase attribution.
Both probes stopped cleanly; no sample failed or reached2s. This is diagnostic
evidence, not a clean throughput run or a compositor-frame test.
Thus the previous `completed_ms` cannot be interpreted as a measured systemwide
GPU blockade. It includes host-side waiting and completion delivery. The optional
shared native probe now also records commit-to-GPU-start (`gpu_wait_ms`),
GPU-start-to-end (`gpu_interval_ms`), and GPU-end-to-host-return (`host_return_ms`).
Metal's GPU timestamps use system mach time; the probe uses `mach_absolute_time`
and the native timebase for those differences, not `CLOCK_MONOTONIC`. Missing or
inconsistent timestamps remain null, not zero. The GPU interval includes possible
GPU scheduling/preemption, not exclusively active blit execution. See Apple's
[GPUStartTime documentation](https://developer.apple.com/documentation/metal/mtlcommandbuffer/gpustarttime).
The model-free Metal integration check verifies phase coverage, valid nonnegative
intervals and their bounds against wall completion; the synthetic unit check
retains null timing when unavailable. The existing UI uses the same enhanced
native probe, but its stats panel still displays the existing wall latency fields.
Neither model work nor disabled-canary execution invokes the new timestamp work.
The first full Rust timestamp run (`after-mtp-timeline`) preserved every MTP
output/reasoning token and EOS. All902 samples had valid Metal timestamps and
none failed. Its worst prefill sample was300.003ms:299.892ms before GPU start,
0.001917ms GPU interval, and0.105958ms after GPU end. The decode maximum was
3.733ms. This directly rules out delayed host return as the dominant cause of
that prefill sample; the queued probe waits for GPU execution. It does not show
that a different application's rendering queue is delayed by the same amount.
The subsequent extraction into the shared native object changes no probe work:
direct `[cb commit]` replaces the wrapper whose model-queue-only hook never
applied to this separate canary queue. Both native bindings pass their model-free
checks after extraction. Final current product binary SHA256:
`50b4b4abbbdc45ff600c1f46d0bec611879249ac8e4d8291d22d656b9c6e9a5d`;
standalone reference binary:
`ccc7a8a774cb1c202add6dba60b04dffe3597822b15a34e22c7e4a5574b50adf`;
shared probe source:
`dd3abc34088ee27ba0759f01a291b9b714114420295252d63e85fd6f326fddab`.
Answer correctness is checked separately from natural termination. Rust AR,
Rust MTP and reference AR passed their generated assertions plus5011 `is_prime`
cases (-10 through5000). The preliminary reference MTP output passed its own
five assertions but failed347 additional cases, first at49: it omits the
`i + 2` divisor test. This is a failed generated Python answer, not by itself
evidence of an engine defect. It must not be reported as a successful code
benchmark merely because EOS was reached. Details are in `python-check.json`.
### Reference clean MTP and record integrity
The clean `reference-mtp-clean` run (both canaries disabled) completed all turns
with the same593/872/167 tokens, text, stop tokens and failed Python answer as
the diagnostic reference run. Its prefill times were5462.306/351.803/434.414ms;
decode21.483/16.754/26.143t/s. The preceding in-process diagnostic measured
23.623/19.287/30.440t/s. This spread must not be disguised as a port speedup or
accepted2% parity: it is one sequential comparison with different probe state,
not controlled repeated clean medians. Canary-on throughput is not the baseline.
The first internal reference run reported788 successful probes, but only787
were independently parseable: a watchdog resource record interrupted one
canary JSON record at a pipe-read boundary. That failed record is preserved in
`reference-mtp-inline.stderr.log`, not silently counted as missing/zero latency.
The supervisor now forwards complete lines in one locked stream write (with a
64KiB cap for newline-free output), while watchdog progress still consumes every
incoming chunk immediately. EOF flushes partial output. A split-record regression
test and all existing memory/start/continuation/long-run watchdog tests pass.
The reference diagnostic is repeated as `reference-mtp-inline-records` for a
fully parseable receipt; the earlier run is retained as the failure evidence.
That repeated reference run completed with **771/771 parseable, successful,
fully timestamped samples** and identical593/872/167 generated tokens/text/EOS.
Prefill p95/max was233.106/264.292ms (48 samples); decode p95/max was
0.226/19.338ms (713 samples). The worst prefill probe waited264.195ms before
GPU start, ran over0.001750ms, and returned to the host0.092083ms after GPU end.
No probe reached2s. The reference's prefill samples also include its short
warmup; the worst sample occurred during the measured summary prefill.
Its diagnostic throughput was23.893/19.177/32.090t/s, not the clean baseline.
| Matched native in-process probe | Prefill p95 ms | Prefill max ms | Decode max ms |
| --- | ---: | ---: | ---: |
| DS4Server, `after-mtp-timeline` |289.978|300.003|3.733|
| Original DS4, `reference-mtp-inline-records` |233.106|264.292|19.338|
These sequential diagnostics reproduce the same GPU-start-wait phenomenon in
the golden master. They do not excuse the remaining Rust prefill cost, establish
statistical latency equivalence, or measure another application's compositor.
Moving inference to another thread cannot by itself reproduce the independent
process's scheduling conditions; process isolation is a distinct architectural
option, not implemented or declared proven as a UI fix here.
Verification at this checkpoint: release all-target/all-feature build; release
all-target/all-feature Clippy with warnings denied; rustfmt and diff checks;
11 model-eval unit tests; both model-free native probe bindings; all4 supervisor
tests; earlier live GLM verifier/progress/HC guards and the full AR/MTP chats.
The updated supervisor fixes measurement transport, not inference scheduling.
## Sampling versus model execution — continued investigation
The prior follow-up made concrete progress (execution fixes plus a fair native
in-process latency reference), but did not establish the full three-model,
AR/speculative2% goal. This continuation addresses the different GLM outputs
before treating their different ongoing histories as matched performance work.
`reference --sampler-fixture` runs the original public `ds4_sample_logits` without
loading a model or using Metal. The checked-in
`tests/fixtures/ds4-sampling-ec7642c.json` contains64 cases: four vocabulary sizes,
eight temperature/top-k/top-p/min-p settings, seeds0/42,32 consecutive tokens
per case and the final RNG state. The original Rust test failed40 of64 cases.
The shared DS4/GLM sampler now preserves the first argmax tie and original
negative sentinel, skips RNG consumption for greedy/all-invalid and the DS4
full-vocabulary min-p fallback, and preserves seed0 until the original RNG's
zero-state substitution. Qwen's independent MTPLX sampler is untouched.
All64 oracle cases and the16 enabled sampling tests pass. Crucially, the positive
temperature/top-p benchmark cases at seed42 already passed before the fix:
these edge corrections are not the explanation for the observed GLM chat gap.
Optional `DS4_REFERENCE_LOGITS_TRACE` records the first32 summary logit rows
through the public original session API. It requires AR mode, creates a new
file rather than overwriting one, and does not change generated tokens or RNG.
The full `reference-ar-logits` chat retained exactly the779/1047/198 tokens,
text and stop tokens of `reference-ar-bootstrap`. Its timings are diagnostic,
not a clean performance baseline. The binary trace contains19,824,640 bytes
(32 rows of154,880 little-endian floats). Its path is serialized as an OsString
and decoded losslessly by the replay test.
`glm53_reference_logits_replay_separates_sampling_from_execution` first samples
those original C-produced rows through the production Rust sampler: **all32
tokens match**. It then opens the installed GLM at Power100/context32768,
prefills the same9-token bootstrap and exact summary suffix, and advances only
with reference-selected tokens. Thus histories never diverge during comparison.
On the Rust-generated rows the test **fails at step17**, choosing906 instead of
the reference320. Already the first post-prefill row has max absolute difference
5.722162 and RMS difference0.851167. All32 per-step row errors are retained in
`logits-replay.stderr.log`; the watched test terminates normally with failure
status in9s. This is a new, deliberately retained red parity test, not a passed
live validation or a speed result. No DS4/GLM/Metal/CPU diagnostic override was
present in the parent environment.
The next localization belongs in the model execution path: compare existing
original DS4 per-layer tensor dumps with the corresponding Rust HC/KDA/DSA/FFN
stages, starting at the first bootstrap/prefill block. Do not explain this away
as stochastic output variation or hide it with a lower chunk/power setting.
No speculative numerical tolerance or new scheduling workaround was applied.
## Root cause: GLM 5.2 chunk boundary applied to GLM 5.3
The active original indexed GLM 5.3 path deliberately keeps full2048-token
chunks across both the old2048 indexer threshold and the4096/8192 dense-attention
threshold. Rust was still applying the GLM 5.2 top-k boundary: after the9-token
bootstrap it evaluated2039 tokens, whereas DS4 evaluated2048. This changes the
recurrent prefill computation, despite identical total prompt tokens.
The original layer0 bootstrap `attn_out` and `ffn_out` dumps matched Rust
bit-for-bit. The original position9 dumps contain2048*4096 floats, establishing
the actual chunk geometry rather than inferring it from configuration.
Detailed HC dump hooks elsewhere in DS4 belong to an inactive dense path and
were not used as evidence for the active indexed execution.
Rust now retains complete GLM 5.3 chunks and splits only the attention slices
at the dense/sparse boundary, as DS4 does. This also removes the incorrect
whole-pair sparse override for a two-row verifier crossing that boundary.
GLM 5.2 retains its old top-k splitting. Unit checks cover both families and
the4096/8192 attention transitions. No smaller chunk, delay, or power reduction
was introduced.
After this correction, the same fixed-history replay is green: **all32 full
154880-value logit rows are bit-identical** to the original trace (max absolute
and RMS error both0), and all sampled tokens agree. This run had no stage
instrumentation enabled. Evidence is retained under
`local-eval-results/glm-stage-20260911.rwQBaJ/mixed-replay.*.log`.
The earlier red replay remains historical evidence, not the current result.
The optional Rust stage reader exists only under `cfg(test)` and validates
tensor geometry before comparing values; it adds no production GPU drains.
The live verifier at frontier4095/context32768 passed across the4096 boundary,
including acceptance, rejection, rewind to either retained frontier, scalar
fallback and recurrent-state restoration (`mixed-boundary.*.log`,70.64s).
The32-row replay alone is not a complete performance or output-parity claim.
The initial source-only note about one-token suffixes was incomplete: the
shared UI/headless consumer already routes one-token extensions through scalar
execution. The actual remaining crossover was two/three-token extensions;
see the subsequent common-consumer correction below.
### Complete chats after the chunk correction
Fresh clean runs used the same ongoing workload, Power100/Low, native EOS,
separate warmup and no active canary. Rust executable SHA256:
`4b23c04325c931854b98c23bd2c98df8a5c2362927aa9b1faed65019d07fd40d`.
The original reference retained its prior tokens/text/stops exactly.
| Mode / turn | Rust tokens | DS4 tokens | Rust decode t/s | DS4 decode t/s | Output + thinking identical |
| --- | ---: | ---: | ---: | ---: | --- |
| AR Summary |779|779|24.512|20.955|yes|
| AR Story |1047|1047|22.956|19.744|yes|
| AR Python |198|198|23.436|20.650|yes|
| MTP Summary |593|593|20.235|21.427|yes|
| MTP Story |905|872|18.039|18.007|no|
| MTP Python |169|167|29.443|29.511|no|
All six Rust turns and six reference turns ended naturally. AR prompt/cached
counts also match exactly. Receipts: `clean-comparison.json`,
`mixed-ar-output-check.json`, `mixed-mtp-output-check.json` in the stage evidence
directory. The AR reference was materially slower than earlier clean runs;
these sequential pairs are not a controlled speedup or2% acceptance claim.
MTP Summary is about5.6% slower in Rust in this pair; the later MTP throughput
numbers do not compare identical histories. Prefill UI-phase and original
session-sync timers still have different boundaries (raw values in the receipt).
Control-loop maxima of4059ms are not GPU canary or compositor measurements.
### Second root cause: MTP stop token retained in the ongoing frontier
Although MTP Summary text/thinking and593 emitted tokens match, Rust starts
Story with3229 cached tokens and3249 prompt tokens; DS4 uses3228/3248.
The shared Rust generation consumer returned on an MTP stop token without
rewinding the already evaluated block. Both normal and raw original DS4 agent
consumers call `ds4_session_rewind(block_start + ti)` at that point. The standalone
reference's stop handling therefore agrees with its real agent, not just an
arbitrary benchmark convention.
The shared UI/headless consumer now calls `rewind_speculative_output`, a thin
GLM adapter over the existing two-row rollback, to keep exactly
`prompt_tokens + emitted_tokens` before retaining the chat.
This restores the saved two-row KDA state and replays the retained row; it does
not merely truncate IDs or re-render generated text. Invalid frontiers fail
explicitly. Both sampled and greedy generation use this consumer. Qwen's own
whole-turn controller is unchanged. Other model-specific speculative stop
contracts are not claimed validated by this GLM change.
The live verifier regression now exercises that same consumer rollback path.
`align_prompt` is intentionally not used: it retains one fewer token to force
logit recomputation during prompt synchronization, which is a different contract.
The full post-frontier-fix MTP measurement (`frontier-mtp.*.log`) now matches
the original for **all three turns**: text, thinking, emitted token count,
prompt count, cached frontier and natural stop. Emitted counts are593/872/167;
Story starts at3228 cached/3248 prompt tokens, Python at4120/4145. The executable
SHA256 is `b964336d64fbb90b3a9ca595a4705eda02e7afe9c39aedb4ea775e0d52fcf20e`.
`frontier-mtp-output-check.json` has three entries with every equality true;
the checked `jq -e` assertion requires all three entries and all five properties.
Decode rates are23.880/19.357/31.643t/s, versus21.427/18.007/29.511 in the directly
preceding clean original MTP run. This is one sequential pair, not repeated2%
acceptance. The Python answer is now exactly the reference's previously checked
incorrect answer (first counterexample49); matching the oracle does not waive
the independent generated-code quality failure.
### Final regression and responsiveness diagnostics
The final strict replay passes with bit-equal logits at all32 steps. The two
original layer0/position9 stage tensors each contain8388608 floats and also
match bit-for-bit (`final-replay.*.log`,10.21s). The updated live verifier at4095
passes through the same rollback entrypoint used by the consumer, including
invalid/unchanged-frontier checks, rejection and both retained rows
(`final-boundary.*.log`,82.27s). The five enabled GLM unit tests pass.
`final-canary` retained identical full MTP output/frontiers. Its in-memory
summary reports840 samples, no failures, prefill p95/max395.611/483.166ms,
decode max3.820ms and no sample crossing the configured2s threshold. However,
strict raw-log parsing found an interleaved canary/resource JSON record: the
model-eval parent inherited the child's stderr, and both processes serialized
JSON fragments to that descriptor. This raw file is retained as a **failed
record-integrity diagnostic**, not silently filtered into a complete sample set.
The model-eval supervisor now pipes child stderr and forwards complete lines
under the parent's shared stderr lock, the same lock used by resource samples.
Diagnostics do not refresh inference progress deadlines. Reader failures are
reported on join. This fixes the app harness counterpart of the earlier
standalone watchdog forwarding issue; it changes measurement transport, not
GPU scheduling or the UI inference graph.
The directly following original DS4 in-process probe run
(`final-reference-canary`) has841/841 parseable samples, no failures, unchanged
reference tokens/text/stops, prefill p95/max373.220/388.090ms and decode max4.370ms.
The worst prefill sample spent387.964ms before GPU start,0.002875ms over its
GPU interval and0.122ms returning to the host. Thus substantial prefill queue
waiting still occurs in the original oracle; the larger Rust spike is not
declared equivalent or explained away.
The repeated Rust run after the forwarding correction (`final-canary-records`)
completed the entire chat in83.744s and preserved all output/frontier fields.
Every JSON record beginning with `{` in stderr was parsed with `fromjson`
(no error suppression): **776/776 canary records and82/82 resource records**
match the independently reported totals. The checked receipt is
`final-canary-records-check.json`. There are no probe failures or observed2s
threshold crossings. Prefill p95/max is119.507/247.181ms; decode max1.854ms.
The worst sample waits247.062ms before GPU start, spans0.001750ms on the GPU,
and returns after0.115458ms. This lower maximum is not attributed to the
transport-only fix: the prior483ms Rust and388ms original spikes remain recorded,
and scheduling/throughput variability still requires repeated paired testing.
The optional probe remains off by default; no negligible-overhead claim is made.
Final source verification: release all-target/all-feature build and Clippy
with warnings denied; rustfmt/diff checks; five GLM unit tests; eleven
model-eval unit tests; sixteen sampling tests including the64-case original
sampler fixture; strict live logits/stage and consumer-rollback boundary tests.
The final CLI SHA256 is
`cbe04f8ce8f8d2fcb6c82b97c3d85b7bed561418893621a6a653d344d1aa6d85`.
The previously good bundle remains unchanged at SHA256
`ea4d555c2faf0940d9cbcf76d8638ca614a9cb2c6b034e3b2f80aeef86b0b339`.
## Common prompt timing and DS4 CPU sampling follow-up
Evidence for this continuation is under
`local-eval-results/glm-paired-20260911.eClfCS/`. The preceding goal turn made
verified progress (chunk scheduling and stop-token frontier fixes); it did not
establish the full six-cell performance goal.
The shared consumer now uses DS4's GLM5.3 resumed-prefill crossover of2 tokens,
not the generic4-token threshold. DS4 explicitly documents this choice as
measured on M5 Max/GB10 (`ds4.c:36784`). One-token continuations were already
scalar; cold/vision paths and the separate MTPLX whole-turn controller are
unchanged. The enabled crossover test covers GLM5.3 versus GLM5.2/DeepSeek.
DeepSeek/GLM now publish the existing `PromptTiming` at the shared prompt-
evaluation boundary: after restoration/bootstrap, around actual suffix execution
including its progress callbacks, before decode/checkpoint storage. Exact cache
hits report zero evaluated work. Separately unmeasured restore/history components
are `null`, not fabricated zeros; Qwen continues reporting the same measured
numeric values through `Some`. The new metric test and existing Qwen progress/
decode-timer test pass. The ordinary UI-prefill timer remains separately visible.
A fresh clean AR pair kept all three outputs/thinking/token counts/frontiers
identical. Rust's engine-prefill times were5235.183/269.769/320.767ms, original
DS4 session-sync8160.750/495.857/479.216ms; Rust decode24.811/23.114/23.410t/s
versus16.633/17.333/19.054. These large sequential-run differences are not a
controlled speedup or a completed repeat matrix (`baseline-ar-comparison.json`).
The reference driver now additionally queries and checks actual engine power100
after load, rather than only recording its requested options.
The CPU sampler still differed algorithmically: Rust sorted the full vocabulary
and drew from renormalized probabilities, while DS4 first tries a512-candidate
heap and draws from raw retained weights. A CPU-only replay uses the existing32
full logit rows, one32-draw warmup and16 measured batches (512 draws). The same
small runner serves the independent original public `ds4_sample_logits` and the
production Rust sampler. It loads no model and performs no Metal work; both are
supervised with1GiB memory/start30s/idle30s limits. The original public function
allocates a scratch buffer per call, unlike its session API, so its microbenchmark
is not an exact measure of session-sampler overhead.
Before alignment Rust took2.645ms/draw versus original0.834ms, with all512 tokens
equal. The aligned Rust path initially measured0.401ms/draw with the same512
tokens (`sampler-{before,after}-rust.json`, `sampler-reference.stdout.log`).
It uses stdlib `BinaryHeap`, DS4's logit/index tie order, bounded-nucleus fallback
without advancing RNG, original raw cumulative sampling, full-vocabulary/min-p
fallback and the original expf-verified log-space rejection boundary. Top-k
retains the original1024 cap. Separate distribution materialization for
speculative correction and Qwen's MTPLX sampler are untouched.
All64 original sampler fixture cases and17 enabled sampling tests pass, as does
the added missing-mass/near-one fallback, RNG and signed-zero tie check. Release
all-target/all-feature build and warnings-denied Clippy pass. The new executable
SHA256 is `ece6aed3601fb402e6dba6ac2e289d6e0c2dc86663600c3d4b1a4cc07e8fb42c`.
The first full post-sampler AR and MTP pairs both preserve all three outputs,
thinking, completion/prompt/cached counts and natural stops. The independently
queried reference engine reports power100. Receipts are
`sampler-{ar,mtp}-comparison.json`; these are single pairs, not the repeat matrix.
| Mode / turn | Rust / original engine-prefill ms | Rust / original decode t/s |
| --- | ---: | ---: |
| AR Summary | 5208.845 / 5548.775 | 26.129 / 24.711 |
| AR Story | 267.263 / 287.268 | 24.553 / 23.728 |
| AR Python | 319.127 / 341.355 | 24.964 / 24.520 |
| MTP Summary | 6574.400 / 5427.866 | 23.935 / 23.628 |
| MTP Story | 273.240 / 278.956 | 19.419 / 19.089 |
| MTP Python | 315.279 / 360.621 | 33.140 / 31.919 |
The Summary MTP prefill regression in this pair remains visible despite the
slightly faster Rust decode. Reversed-order repetitions are needed to distinguish
run variability from a repeatable graph cost. AR before/after the sampler keeps
the entire chat output identical and improves decode by5.310/6.225/6.638% in this
one sequential comparison (`sampler-ar-before-after.json`); no controlled causal
end-to-end percentage is inferred from that pair alone.
MTP is not universally beneficial in the original either: its Story decode is
19.089t/s versus23.728 AR, while Python is31.919 versus24.520. Rust's full MTP
cycle receipts show228/366,289/584 and82/86 accepted drafts respectively
(62.3%,49.5%,95.3%). The corresponding complete decode-loop time per cycle is
67.69/76.89/58.60ms. At1.62/1.49/1.94 emitted tokens per cycle, the Python case
amortizes the extra draft/verification work much better. These are whole-cycle
averages, not isolated kernel timings: the existing `verifier_ms` includes other
cycle work and must not be presented as an exclusive verification stage.
AR and MTP have different natural histories, so their t/s comparison is not a
matched-token microbenchmark. The previously recorded Python correctness failure
also remains open even though both implementations produce the same code.
### Reversed-order pairs: acceptance still fails
Both modes were repeated in original-then-Rust order, serially without builds
or canary probes. All twelve measured answers in these four processes again
match text/thinking/counts/cache frontiers and end naturally; all watchdogs
exit successfully. No slow run was discarded (`repeat2-*-comparison.json`).
| Mode / turn | Rust / original engine-prefill ms | Rust / original decode t/s |
| --- | ---: | ---: |
| AR Summary | 6738.280 / 5283.041 | 23.569 / 25.535 |
| AR Story | 309.647 / 281.591 | 21.743 / 24.186 |
| AR Python | 387.381 / 329.667 | 21.107 / 24.898 |
| MTP Summary | 9240.178 / 8835.102 | 17.706 / 17.678 |
| MTP Story | 358.905 / 402.447 | 15.146 / 14.581 |
| MTP Python | 403.605 / 491.547 | 25.843 / 23.655 |
AR decode now misses by7.70/10.10/15.23%; MTP Summary prefill misses by4.38%.
The subsequent original MTP run is itself much slower than its first run.
This excludes neither a Rust scheduling difference nor changing device clocks;
it does preclude a pass based on the favorable first pair or a selected median.
The required third pair and full six-cell acceptance remain outstanding.
Rust AR emits exactly9445/12612/2424 command buffers in both repetitions, with
the same outputs, but its GPU timestamp-interval sums increase from
34536/42061/8084ms to39285/47601/9590ms (`ar-drift-comparison.json`). Those sums
are `GPUEndTime - GPUStartTime` and may include preemption; they are not exclusive
kernel or hardware-clock measurements. The slowdown is not explained by changed
token counts or extra command buffers, and is not declared thermal throttling.
During the sequence, a read-only process snapshot showed only the intended
reference model process. macOS reported no recorded thermal/performance warning
and normal VM pressure (1), which does not exclude frequency changes. The
AGX PerformanceStatistics snapshot exposes utilization but no frequency field.
Hardware was freshly checked: Apple M5 Max,128GiB,18 logical CPUs.
## Remaining acceptance
- Compare repeated clean throughput pairs; GLM ongoing histories now match in
both modes, but sequential run variability does not establish2% performance parity.
- Localize the remaining GLM prefill cost against original DS4's active indexed
path, now that in-process GPU-start waiting is observable on both sides.
The engine-prefill timer is now exposed separately from UI-phase timing;
use that aligned boundary in the paired comparisons.
No chunk reduction or extra waits are justified by these measurements alone.
- Verify the corrected short-extension crossover live where needed, and other
model-specific speculative stop contracts; the recorded GLM workload does not
cover every possible interaction. Full chats pass after CPU-sampler alignment;
repeated timing acceptance remains separate.
- Validate the remaining SSD expert-streaming cases separately from resident
scheduling. This is unrelated to replacing DS4 KV checkpoint persistence.
- Complete the DeepSeek AR/DSpark reference cells and Qwen residual performance
analysis. Interactive confirmations are not a substitute for the six-cell
numerical acceptance matrix.
No bundle replacement, commit or push has been performed by this follow-up so far.
All processes have terminated. The subsequent DeepSeek comparison and its
separate bootstrap/DSpark findings are recorded in
[DeepSeek follow-up](deepseek-reference-followup-20260911.md).
@@ -7931,6 +7931,19 @@ Verifikation 2026-09-05, ohne GPU-Modelllauf oder breite Gates:
- `git diff --check`: bestanden. Keine Durchsatzverbesserung aus diesen Tests
abgeleitet. Vor der neuen DSpark-Messung bleiben P02/P03/P04 maßgeblich.
**Gemeinsamer DS4/GLM-Sampler angeglichen (11.09.):** Der CPU-only-Replay mit
32 echten GLM-Logit-Zeilen und512 gemessenen Auswahlen zeigte2,645ms pro Schritt
in Rust gegenüber0,834ms über die originale öffentliche DS4-Funktion. Die Rust-
Implementierung benutzt nun den begrenzten512-Kandidaten-Heap, originale Logit-
Tie-Reihenfolge, rohe CDF-Summen und DS4-Fallbacks statt vollständiger Sortierung
mit erneuter Normalisierung. Initial0,401ms/Schritt bei identischen512 Tokens;
64 Original-Fixturefälle und17 Sampling-Tests bestanden. Qwens MTPLX-Sampler und
die separate Verteilungsberechnung für spekulative Korrektur bleiben unverändert.
Ein kompletter GLM-AR-Chat bewahrt Ausgabe/Thinking/Frontiers und zeigt im einzelnen
Vorher-/Nachher-Paar5,36,6% höheren Decode-Durchsatz. Das ersetzt weder die
DSpark-Modusabnahme noch die wiederholte Gesamtmatrix. Details im
[GLM follow-up](glm-scheduling-followup-20260911.md).
### P14 — GLM-MTP tatsächlich batchen wie DS4
**Produktpfad umgesetzt, Referenz-Performanceabnahme offen (10.09.):**
@@ -7996,6 +8009,61 @@ Priorität P1; nach P04, P13; Quellcodedifferenz belegt.
### P15 — DS/GLM-Scheduling, Kaltstart und gemeinsame Runtime abgleichen
**Numerische GLM-Abweichung reproduziert (Fortsetzung11.09.):**
64 modellfreie Original-DS4-Sampler-Fälle sichern Tokens und RNG-Zustand ab;
Greedy-Tie/RNG- und Seed0-Abweichungen sind korrigiert, ohne Qwen zu ändern.
Die verwendeten positiven Seed42-Benchmarkfälle waren davon nicht betroffen.
Der neue feste-Historie-Test auf32 echten Original-DS4-Logit-Zeilen trennt die
Ursachen: Rust-Sampling derselben Zeilen liefert32/32 identische Tokens; Rust-
GPU-Ausführung derselben Eingaben liefert bereits nach Prefill max5,722/RMS0,851
Logit-Abweichung und bei Schritt17 ein anderes Sample. Der Test bleibt bewusst
rot und ignoriert für normale modellfreie Läufe. Die Referenz selbst bewahrt
den vollständigen AR-Chat exakt trotz optionalem Trace. Nächste Priorität ist
die erste divergierende HC/KDA/DSA/FFN-Stufe, nicht das Durchsatzetikett auf
auseinanderlaufenden Chathistorien. Belege/Kommandos und Grenzen stehen im
[GLM follow-up](glm-scheduling-followup-20260911.md).
**Fortsetzung 11.09.:** Der Benutzer bestätigt jetzt normalen GLM-Decode und
benutzbaren, aber gegenüber Qwen weniger geschmeidigen Prefill. Kein vollständiger
Freeze behauptet. Die unten am10.09. identifizierte residente skalare Flush-
Abweichung ist in beiden GLM-Schleifen korrigiert (periodisch alle4, ohne letzten
Layer/SSD-Streaming); Prefill-Fortschritt meldet nur abgeschlossene bestehende
Drains und den Batchabschluss. Frische vollständige AR/MTP-Vorher-/Nachher-Chats
bewahren Tokens/Text/Thinking/EOS ohne beobachtete harte Regression; einzelne
Laufpaare sind kein kontrollierter Speedup-Beweis. Der ausdrücklich genehmigte
Standalone-DS4-Benchmark benutzt originale DS4-Objekte ausschließlich außerhalb
des Produkts und reproduziert Low, separaten Bootstrap und laufende Chathistorie.
Die separate Canary-Prozessplatzierung war kein fairer Vergleich zum internen
Canary: gleichzeitig intern490,740ms versus extern höchstens3,331ms. Neue native
Metal-Zeitstempel lokalisieren eine300ms-Prefill-Probe fast vollständig vor dem
GPU-Start, nicht in der Host-Rückmeldung. Dieselbe Probe innerhalb des originalen
DS4-Prozesses reproduziert264,292ms Prefill-Spitze, ebenfalls vor dem GPU-Start;
771/771 Datensätze sind nach Korrektur der Watchdog-Ausgabeweiterleitung sauber
auswertbar. Die restliche Kosten-/Latenzdifferenz und weitere Abnahme bleiben in
[GLM follow-up](glm-scheduling-followup-20260911.md). P15 bleibt offen.
**GLM-Ausführungsursache lokalisiert (11.09.):** Rust übernahm die GLM-5.2-
Top-k-Chunkgrenze für GLM5.3: nach9 Bootstrap-Tokens2039 statt der originalen2048
Tokens. Nun bleiben GLM5.3-Chunks wie im aktiven DS4-Pfad vollständig; nur die
Attention-Slices werden an der Dense/Sparse-Grenze geteilt, auch für kreuzende
Verifier-Paare. Im unverändert vorgegebenen32-Schritt-Replay sind danach alle
Logit-Vektoren bitidentisch zur Originalreferenz, vorher lagen deutliche Fehler
bereits im ersten Vektor vor. Vollständige AR/MTP-Chats, Grenzfall-Livetest und
Performance-Neumessung bleiben erforderlich; dies allein schließt P15 nicht.
**Nachprüfung desselben Tages:** Der vollständige AR-Chat stimmt nun in allen
drei Antworten samt Thinking, Tokenzahlen und Prompt-/Cache-Grenzen überein.
Bei MTP wurde zusätzlich ein im gemeinsamen UI-/Harness-Consumer behaltenes
Stop-Token gefunden: der zweite Prompt hatte3249 statt3248 Tokens. Der Consumer
nutzt nun GLMs vorhandenen Zwei-Zeilen-Rollback, analog zur Stop-Behandlung des
originalen DS4-Agenten. Danach stimmt auch der vollständige MTP-Chat in allen
drei Antworten und Grenzen überein (593/872/167 ausgegebene Tokens). Der
Attention-Grenzfall4095+2 wurde live geprüft. Der strikte32-Logit-Replay und die
großen Layer0-Tensorvergleiche sind bitidentisch. Einzelne neue Geschwindigkeits-
paare und diese konkrete Workload schließen nicht die gesamte2%-Matrix oder
alle Interaktionsfälle ab; P15 bleibt offen. Ergebnisse und Einschränkungen im
[GLM follow-up](glm-scheduling-followup-20260911.md).
**Aktiver GLM-Pfad und durchgehender Canary geprüft (10.09.):**
`local-eval-results/glm-scheduling-canary-20260910.T1ABR1/{manifest.md,comparison.json}`
enthält zwei vollständige AR/MTP-Chats bis EOS bei Power100/Low und Canary an.
@@ -8061,6 +8129,61 @@ Priorität P1; nach P01, P04, P13; Source-Inventar vorhanden, Detailbeweis offen
Priorität P1; nach den relevanten P01P15; offen.
**Original-DS4-Vergleich erweitert (11.09.):** GLM-AR/MTP bewahren nach dem
CPU-Sampler-Abgleich in je zwei vollständigen Paaren Ausgabe/Thinking/Frontiers.
Die umgekehrte Reihenfolge zeigt dennoch AR-Decode-Rückstände bis15,23% und
MTP-Summary-Prefill bis4,38%; auch die Originalreferenz schwankt stark. Kein
Median-Pass, keine thermische Erklärung ohne Taktbeleg. Details und unveränderte
Command-Buffer-Zahlen im [GLM follow-up](glm-scheduling-followup-20260911.md).
Der erste DeepSeek-Vergleich ist ausdrücklich ungültig: Der Referenztreiber
forderte2048 statt des UI-/DS4-Automatikwerts4096 an. Zusätzlich fügte der
gemeinsame Produkt-Renderer bei einem reinen Bootstrap-Cache fälschlich EOS vor
dem ersten User-Prompt ein (2742 statt2741 Tokens). Der Tokenizer selbst stimmt.
Ein gezielter CPU-Test reproduziert diesen UI-/Headless-Fehler vor der Korrektur;
nach dem Nichtleer-History-Guard bestehen DeepSeek- und GLM-Originalfixtures.
Referenztreiber auf Automatik angeglichen, keine Produkt-Chunkverkleinerung.
Das korrigierte vollständige DeepSeek-AR-Paar stimmt nun in allen Antworten,
Thinking-, Token- und Cache-Feldern überein, verfehlt aber im Einzelpaar noch
das Durchsatzziel. Das neue DSpark-Paar scheitert funktional: erste Antwort
bereits647 statt1208 Tokens bei identischem Prompt; anschließend jeweils ein
zusätzlich behaltenes EOS im Rust-Cache. Die normale Beendigung und bestandene
Python-Tests ändern diesen roten Vergleich nicht. Nächste zusammenhängende
DSpark-Einheit: erster divergenter Proposal-/Verify-Zyklus, Stop-/Capture-Frontier
und zusätzliche Vollvokabular-Readbacks gemeinsam gegen Original DS4 prüfen
und angleichen, dann neu messen. Konkrete Quellen, Rohdaten und Tests im
[DeepSeek follow-up](deepseek-reference-followup-20260911.md).
**DSpark-Zyklus-/Zustandsabgleich fortgesetzt:** Der neue vollständige
Diagnoselauf stimmt jetzt in allen1755 Originalzyklen einschließlich Warmup,
Antworten, Thinking und Cachepositionen überein. Ursachen waren fehlende
HC-/Attention-Norm beim Support-KV-Aufbau, der abweichende Einzeldraft-Verifier,
Seed-/Teilannahme-Capture, Cachefenster-/Scheduler-/EOS-Übergänge und fehlende
Aktivierungsquantisierung des tatsächlich installierten Q8-Confidence-Kopfs.
Zusammenhängende Quellen-/Taskliste und Rot→Grün-Belege stehen im verlinkten
Follow-up. Early-Confidence-Gate und Verifier-Readbacks/Submission sind inzwischen
ebenfalls angeglichen; alle1755 Originalzyklen bleiben exakt gleich. Noch keine
Leistungsabnahme: saubere Wiederholungspaare zeigen starke zeitliche Drift in
beiden Implementierungen. Die CPU-Worker-Policy ist ebenfalls angeglichen:
dauerhafte12 Threads inklusive Aufrufer, weiterhin1755 identische Zyklen.
Ein CPU-only-Dispatchvergleich zeigt einen kleinen Gewinn, keine Erklärung für
den verbleibenden Gesamtgap. Verifier-/Frontier-Puffer werden inzwischen über
Zyklen wiederverwendet; der32-Zyklen-Test prüft Pufferidentität und bytegenaue
Rücknahme, der vollständige Chat weiterhin alle1755 Originalzyklen. Auch der
Exact-Sampling-Test besteht. Die jüngsten beiden Paare verfehlen jedoch weiter
Teile des Durchsatzziels; kein belegter Gesamtgewinn durch diese Änderung.
**Messbedingung nach Nutzerklarstellung (11.09.):** Parallel laufen Videos und
beanspruchen einen Teil der GPU. Die genaue zeitliche Überlappung früherer
Messungen ist unbekannt. Die jüngsten seriellen Paare bleiben als Rohdaten
erhalten, gelten aber nicht als kontrollierte2%-Abnahme oder kausaler
Vorher/Nachher-Beleg. Weder alle Differenzen auf Videos schieben noch thermische
Drosselung behaupten. Keine weiteren Durchsatzserien während dieser Nutzung;
Funktionsprüfungen und Code-Abgleich bleiben möglich. Die vollständige
Sechsfeldmatrix, Responsivitätsabnahme und Zähler-Scope-Bereinigung bleiben offen.
Der Nutzer hat den Abschluss und Commit/Push dieses Zwischenstands freigegeben;
die vorgeschriebenen Commit-Gates umfassen auch den erneuten Bundle-Bau.
**Aktuelles interaktives Test-Bundle bereitgestellt (10.09.,22:32):**
`make bundle` und strikte Codesign-Prüfung bestanden. Das Bundle enthält den
zuletzt vermessenen Release-Code und identische Metal-Ressourcen; der genaue