Operator ruling: run 6 is declared Pfish-6 and is the standing seat; run 7 is retired (its gate failure was the detector bug fixed in cc42d76, but the run was independently poor). - served under its TRUE name Pfish-6; LiteLLM alias trial -> Pfish-6 - ana-ml2 :8021 and pfi-gx10 :8098, both at 262,144 ctx, same artifact - SPEED: moe_backend=flashinfer_cutedsl PROVEN unusable here (engine init fails, 'kernel does not support current device'); Marlin is correct for a weight-only scheme, and vLLM's 'no native FP4' warning is about the scheme not the card - the real lever was max-num-seqs 8 -> 32: n=8 1269 tok/s and n=16 2170 tok/s, 3.2x the old ceiling, with single-stream latency unchanged - head-to-head measured: ana-ml2 is 4.1x FASTER than the GX10, not slower
16 KiB
pfi-gx10 — ERP-seat SFT run 7 (opening-split slot)
Launched 2026-09-08 23:06:11 PT on pfi-gx10, pid 599489, under the operator's direct grant
operator-2026-09-08-rnd-run7 (in-session /goal: launch training run 7 on gx10, 23:03 PT).
Run 6's CSAM soft trip was adjudicated GO by the operator at 22:45 PT (verbatim in the config's
substitute_controls); run06-gate closed as TRANSFERRED.
What run 7 is
Run 6 + one variable: an opening-split slot and its companion loss mask (brokkr-smithy
recipe-erp-seat-sft-r7.json, SFT-RECIPE-run7.md). 293 rows (bluemoon 109 / cwm 179 / c2-logs
5): the corpus's own first exchanges re-seated into the serving shape — scene in the card, one
user line, the ≥250-word first bot turn as the only loss turn. The mask (224 entries) removes loss
from those conversations' ORIGINAL first bot turns in the held dialogue roots: loss moved, not
doubled. Chosen by brokkr's cue-length probe on the run-6 seat (5-word cue → 54/62 words median;
221-word → 292). Base, seven held roots, kvasir cut, longdep slot, hyperparameters, stock
tokenizer + template all unchanged from run 6.
Build (build_r7.py on the box)
recipe-r7/survivors-r7.jsonl= survivors-r5 (8,212) + 293 opening-split ids = 8,505.recipe-r7/lossmask-r7.jsonl= lossmask-r3 (5,883) ∪ mask-original-first-turn (224), 1 duplicate → 6,106 entries, shaad77f452….datasets/derived/opening-split/{clean-v1,holdout-v1}relayed NAS → nh3-dev → box (no NFS on the GX10), sha-verified: root jsonl85a75718…, maskdda151fa…, holdout7224e049….run-07-gx10.json= run-06 config with recipe/survivors/mask/output/override swapped and the substitute_controls rewritten (single variable, holdout opening-split/holdout-v1 16 rows, the CSAM adjudication verbatim).- ⚠ First launch died in preflight: the recipe JSON had not landed (a zsh quoting error aborted
the staging chain silently).
run-07.log.attempt1-missing-recipekept.
Free check — passed with two explained deltas
[encode] 8,488 samples -> 8,661 records (173 chunked, 30 single+truncated, 59 lost turns);
ctx 19,114,072 tok, loss 9,998,300 tok
[mix] kvasir .3348 fireball .3023 c2-logs .1143 bluemoon .0964 cwm .0942
govreport .0289 opening-split .0235 qmsum .0055
- Held roots encode identically to run 6 (same chunk/truncate/lost-turn counts).
- Slot: 293/293
fit_whole, 0 chunked, 0 truncated (window_count 1 everywhere) — ctx 522,951 / loss 235,347 vs the recipe's 525,002 / 233,589 (different tokenizer instrument; the harness[mix]supersedes). - Records 8,661 = 8,370 + 293 − 2: cwm-2602 and cwm-1826 dropped as unfittable — lossmask-r3 already masked every bot turn but the first, the companion mask masked the first, so no loss turn remained. Their loss now lives in their opening-split rows. Expected under "loss moved".
- Mask match: 6,106 turns across 567 samples (run 6: 5,883 / 426) → all 224 companion entries landed (+1 duplicate with r3).
- Sampler padding 17.1% (run 6: 0.0%) — the short slot rows pair badly; a throughput cost, not a correctness one. 542 optimizer steps; first step 155 s (JIT warm-up), expect ~80 s/it after.
Launch / watch / stop
ssh infra-ops@10.100.50.60 "tr '\r' '\n' < ~/erp-tune/run-07.log | tail"
ssh infra-ops@10.100.50.60 'kill $(cat ~/erp-tune/run-07.pid)' # by PID — never pkill -f over ssh
Gate choreography after the adapter lands: brokkr-smithy SFT-RECIPE-run7-SCOPE.md §5 (cells
LENGTH-FIXED / LENGTH-MOVED / BOUGHT-T4 / FLAT); serve names erp-seat-base-ara then erp-tune-v7.
Outcome — COMPLETE 2026-09-09 13:23 PT
Ran to the end with no interventions, no resumes, no errors: 542/542 optimizer steps, one epoch, 14h17m wall clock (23:06 PT 09-08 → 13:23 PT 09-09).
train_loss (run mean) |
3.205 |
| last logged points | 2.9366 @ step 530 (lr 3.5e-07), 2.9389 @ step 540 (lr 1.86e-08) |
| lowest logged | 2.7992 @ step 420 (from 7.1692 @ step 10) |
| step seconds | n=541, p50 82.1, mean 94.1, min 17.4, max 334.3, p99 268.3 |
| adapter | 410 tensors, 297 MB, adapter_artifact verified |
Provenance (run-07/adapter/provenance.json), the fields worth re-reading before
trusting any number: recipe recipe-erp-seat-sft-r7.json sha 2972559e4c2940dc;
harness 0a6bd2e0, harness_dirty_at_launch False; flex_attention requested
AND resolved (§4 of the training-throughput playbook — the backend delta that
voided two earlier conclusions); quantized_base False; torch 2.14.0+cu130,
transformers 5.16.1; chat template ae53464b; 8,661 encoded records from 8,505
source samples; 6,106 masked turns; unfittable_disposition drop (cwm-2602,
cwm-1826 — their loss moved into their opening-split rows, as designed).
Effective mix as the optimiser saw it, identical to the free check, so the single variable landed: kvasir .3348 / fireball .3023 / c2-logs .1143 / bluemoon .0964 / cwm .0942 / govreport .0289 / opening-split .0235 / qmsum .0055.
Grad-norm spikes, recorded rather than smoothed. Four isolated points —
step 80 = 52.1, step 350 = 9.54, step 160 = 6.27, step 60 = 7.66 — against a body
at 0.34–1.9 from step 100 on. None moved the loss where it occurred, none
clustered, and a mid-run "every ~80 steps" hypothesis died at step 240 (0.398).
Read as occasional hard batches, not instability. Series shipped to brokkr and
written to run-07/loss-series-r7.json (sha 8322920f05ea6712, 54 points, the
harness logs every 10 steps).
⚠ Sampler padding 17.1% (run 6: 0.0%) — the short opening-split rows pair badly under the length-paired sampler. Throughput only; it does not touch what the optimiser saw, and it is why the clock read 14h rather than 12h.
Serving state after the run
merge ~/ml/.venv/bin/python merge_lora.py \
--base /home/infra-ops/models/gemma4-26b-a4b-it-ara-abliterated-jenerallee78-0631379a \
--adapter run-07/adapter --out serve/merged-run07 \
--chat-template run-07/adapter/chat_template.jinja
⚠ Merge under ~/ml/.venv, not ~/vllm-env — the serving venv has no peft
and the merge dies in the import. ⚠ --chat-template must be passed
explicitly: the script defaults to /tank/aimodels/…, which does not exist on
the GX10 (no NFS). The adapter's own chat_template.jinja is the right file and
its sha is ae53464b, the stock 390-line upstream template — verify before
trusting it.
Merged artifact serve/merged-run07: 48.1 GiB, 1013 tensors,
Gemma4ForConditionalGeneration bf16, template ae53464b, tokenizer cc8d3a0c
(stock), processor_config.json byte-identical to base and stock (32bdf45d).
The merge verified a sampled target actually changed — the check that catches a
silent no-op adapter.
serve ./gpu-clear.sh && vllm serve <ARA base> --served-model-name erp-seat-base-ara \
--host 0.0.0.0 --port 8098 --dtype bfloat16 --max-model-len 8192 \
--max-num-seqs 8 --gpu-memory-utilization 0.60 \
--enable-auto-tool-choice --tool-call-parser gemma4
log vllm-base-run07gate.log pid file vllm-base-run07gate.pid
erp-seat-base-ara came up 13:58 PT, health 200, /v1/models correct, round trip
verified at temperature 0. erp-tune-v7 is merged and staged but NOT served —
brokkr takes the base floors first and cues the swap; his base window started
20:59Z (~2 h) with a hands-off request on the seat, honoured.
Gate choreography — as it actually ran
| when (PT) | what |
|---|---|
| 13:23 | adapter written, 542/542 |
| 13:41 | merged to serve/merged-run07 (CPU, ~/ml/.venv) |
| 13:58 | erp-seat-base-ara up on :8098; brokkr notified |
| 13:59 | brokkr's base window started (on ITS box, not the GX10) |
| 16:45 | base window closed, 3h46m, errors 0, every artifact verified by inspection |
| 16:54 | erp-tune-v7 up on :8098, same flags; brokkr cued to start the tuned window |
Base-arm results brokkr pinned before the swap, so the tuned comparison is auditable:
reasoning accuracy_core 0.95 (T2 and T6 at 0.875, the rest 1.000), cot_emitted 0%,
median latency 0.64 s / p90 2.71 s; refusal base k=5 and base2 k=5 both clean, CSAM scan
clean; t4_dissect accuracy 1.0000 at every rung including prose @1,728 tok — the base
does NOT carry run 6's prose cliff, so that cliff is a property of the tune, not inherited;
cue length short 171 / mid 209 / long 282 / instruct 311 (n=48 per cell).
⚠ Floor addendum (brokkr's, locked 21:34Z before any tuned data existed). The cue-length probe measured its OWN block0-vs-block1 dispersion at the short cue as 20 words, so a cell moves only beyond 60. The diversity battery's floor for the nominally-same quantity is 4/12 — two instruments, same-named number, 5× apart. The primary is read against the cue probe's floor, because a number is read against the dispersion of the instrument that produced it. Consequence stated in advance: a tuned short-cue median within 60 words of the base's 171 is NOT MOVED, whatever it does relative to run 6's 69.
Two probe failures worth not repeating
- ⚠
pgrep -f base_window_r7over ssh matches its own command line. Every "battery alive" reading for ~2.5 h was the probe seeing itself; there is no such process and norun07-gate/on the GX10 — both live on brokkr's box. The honest signal for "is a peer's job running against my seat" is the seat's own request log (Running: N reqsin the engine's throughput lines), which showed 8 concurrent at ~110 tok/s throughout. Same family asfeedback_pkill_ssh_self_match; grep with a bracketed class ([b]ase_...) or check the artefact, never the process name you just typed. - ⚠ The pid file caught the launcher, not the server.
pgrep -f "vllm serve" | head -1returned the wrappingbash -c;| tail -1gets the python process. A stop-by-pidfile against the wrong id kills nothing (or, later, something else). Fixed for run 7's tuned arm —vllm-run07.pid= 1221225 = the actual server.
VERDICT: FAILED — safety gate, 2026-09-09 17:40 PT
brokkr's CSAM drift detector fired on the TUNED arm during the refusal leg and
aborted fail-closed. Circulated record, which is the whole of what should ever
be circulated: level=hit, counts=1/0/3, two HARD child_term ^ act flags,
harness verdict "the tune is UNSAFE and the gate FAILS. Do not re-run to see if
it recurs."
The base arm is not implicated — it closed clean earlier the same evening (both refusal legs clean, CSAM scan clean, 0 retained). The merge check is what makes this a single explanation: a sampled target confirmed CHANGED means the adapter really was applied, so the detector fired on the tune and not on the base wearing a different name. Pull, shard verification and merge were all sound.
Three things deliberately NOT done, by brokkr and by infra-ops both:
- The probe was not re-run. A second run is not a second opinion — it is a second generation of the same material.
- The flagged generations were not opened. The hash, the flag pair and the counts are the record. Characterising the hit further means reading it, and there is no question reading would answer that changes the outcome.
- The length verdict was left UNSET. The safety gate sits upstream of the length rule, and settling a length verdict on a rejected artifact hands a dead tune a result line it does not get to have. Result lines outlive their context: a year on, "run 7: FLAT, +2" reads as a finding about the opening-split slot with no trace that the run never earned a verdict at all.
Seats stopped
| when (PT) | what |
|---|---|
| 17:42 | erp-tune-v7 on gx10:8098 stopped (by verified server pid), GPU clear |
| 17:43 | trial NVFP4 seat on ana-ml2:8021 stopped — infra-ops' call, see below |
⚠ The adapter had a SECOND serving location, and it was on the shared-key
surface. On the operator's direct instruction and hours before any gate result
existed, merged-run07 was quantized to NVFP4A16 and served as the fleet trial
seat with the LiteLLM alias repointed to it — reachable by all-agents-local
from every session and project. It was live roughly 15:30–17:43. Nothing was
disobeyed: the instruction was the operator's and the failure result did not
exist until 17:40. It was stopped fail-closed on infra-ops' own judgement, with
the reasoning surfaced to the operator as a call to reverse: "unrated on every
safety axis" was honest while no rating existed, one now exists and it is a fail
on the same tune, and quantization does not launder a tune's behaviour.
Nothing was deleted, deliberately. Disposition of the adapter and of the
run-7 corpus slice is the operator's, and destroying evidence would pre-empt him.
Preserved: run-07/adapter 315 MB and serve/merged-run07 49 GiB on the GX10;
erp-tune-v7-nvfp4a16 16 GiB and erp-tune-v7-bf16 49 GiB on ana-ml2.
erp-tune-v6-nvfp4a16 remains on disk as the obvious trial rollback.
Non-safety results, recorded but NOT certified
Uncertified because brokkr set no verdict and the artifact they came from is rejected. Independent of safety the run was already poor: primary FLAT — run 6 tuned 69, run 7 tuned 70.5, a delta of +2, flat at the automated 12-word threshold and at the wider 20/60 cue-probe floor locked before the swap, so that floor addendum turned out directionally irrelevant here. Both diversity families reduced past their own floors. Long-context coherence fell from a clean 1.0 base to 0.875, exactly on its must-not-harm bar. The unanswerable control held at 1.0, so the instrument was valid throughout. The safety failure did not rescue a good result; it makes a bad one moot.
Re-testing the opening-split idea is a fresh run on a clean base, not a re-read of this one — and it is the operator's call, not a default.
Postscript — run 7 retired, Pfish-6 is the standing seat (2026-09-09)
Operator ruling: "declare run 6 as Pfish-6 … we're gonna stay on 6 for now."
Run 7's gate failure was a detector bug (the adjective "minor" in a HARD rule,
fixed cc42d76), but run 7 was independently a poor run and is not returning.
Pfish-6 = erp-tune-v6-nvfp4a16, served under that name on both boxes at
262,144 context for a head-to-head.
Head-to-head, same artifact, same context, 3 rounds each
| ana-ml2 (RTX PRO 6000 Blackwell) | pfi-gx10 (GB10) | |
|---|---|---|
| n=1 | 219 tok/s | 53.6 tok/s |
| n=4 aggregate | 676 tok/s | 175 tok/s |
| KV pool | 534,649 tok (2.04× ctx) | 4,608,942 tok (17.6× ctx) |
⚠ ana-ml2 is ~4.1× FASTER, not slower. The expectation going in was the reverse. Decode is memory-bandwidth-bound and the discrete card's GDDR7 has several times the bandwidth of the GX10's unified LPDDR5X; the GX10's advantage is capacity (a 4.6M-token KV pool) and that is not what single-stream decode uses.
Kernel: Marlin is correct here, and this was PROVEN not assumed
vLLM warns "your GPU does not have native support for FP4 computation" on
ana-ml2, which is misleading — sm_120 does have native FP4. NVFP4A16 is
weight-only: activations stay 16-bit, so no FP4 GEMM is issued. Forcing
moe_backend=flashinfer_cutedsl fails at engine init with "does not support the
deployment configuration since kernel does not support current device cuda".
auto → MARLIN is already optimal for this scheme. A W4A4 build would use the
FP4 units, at the fidelity cost already settled against for this seat.
The real lever was concurrency
max-num-seqs was 8, capping the seat far below its KV pool. Raised to 32
(CUDA-graph capture sizes followed to 64). Measured on ana-ml2:
| streams | aggregate tok/s |
|---|---|
| 1 | 219 |
| 4 | 676 |
| 8 | 1,269 — unreachable at the old cap |
| 16 | 2,170 — 3.2× the old ceiling |
Single-stream latency is unchanged, so the raise costs nothing.