DEV Community

prodbymarcu
prodbymarcu

Posted on

Three guard refusals in a row and no second pass

An updater that refuses to touch a running component is only safety when the deferred step gets scheduled again. It refused across three surgery mornings in a row, printed its reason, reported success anyway, and left the new engine binary sitting on disk waiting for a window close nothing forced. By the third refusal the repo had walked from v0.2.2 to v0.2.8 while the inference engine stayed at 0.1.44, :8080, :8090 and :8091 all answering 200 with the old coder resident, every apply reading green. The last of those runs deferred a swap, reported done beside the deferral, and rewrote a context ceiling nobody had verified.

Three refusals, one resident engine

What the guard was protecting

The surgery refreshes model packages and the engine binary in place, and swapping the engine needs the serving window closed, upstream issue #475 says setup can't refresh an open engine. So the script checks whether anything is resident and refuses if it is. On Oct 21 the guard could act, we'd parked the lanes during teardown first, and the swap went through, 0.1.37 to 0.1.45. The next three mornings it hit the other branch, verbatim each time: "engine 0.1.44 is in use: close the model window and run this again". Oct 22 wanted 0.1.48, Oct 23 wanted 0.1.48, Oct 30 wanted 0.1.46, same debt logged under each entry. Nothing queued that follow-up visit, the lanes never got torn down between those runs, so the deferred step kept waiting for its own window.

Ever wonder why an update log reads clean while the thing it updated stays a version behind? Because the deferral and the success report are the same line item to most tooling. Mine kept the debt in parentheses under an APPLY verdict, which is where I caught the pattern at all.

What the skipped swap would have bought

The release that wanted 0.1.46 wasn't cosmetic. v0.2.8 shipped October 29 at 22:40Z, marked stable, prerelease false, and its notes carry measured numbers from upstream's own agent runs: malformed tool calls read correctly 98.3% against 92.9% across 1,462 turns with recovery default ON, idle batch-slot parking pulling first-token time from 3.3 s to 0.66 s on round two, plus conv-cache PLE-lock and expert-reserve fixes in #4518 and #4474. Those numbers are the vendor's, sample size theirs, my turns never saw them because the engine stayed put. The gap between what I'd pulled and what I could run kept widening while every health check said fine.

The flag nobody cleared

Every teardown in this stack touches a marker file so the watchdog on the Mac side stands down while lanes are parked, then removes it when the work finishes. During the Oct 30 surgery the removal never happened. My tool layer refused the rm, its message said inference protection blocked changing live files, the run reported done anyway, and the marker sat there stamped 06:11. Left alone it keeps the coder watchdog stood down indefinitely, an idle lane nobody revives, and every later inspection of that state reads as intentional stand-down, which is exactly what maintenance wants, so nothing looked wrong until the rescue arm caught the dangling flag hours later and cleared it over ssh where the agent-tool rm was blocked. After the clear, :8080 and :8090 both answered 200 with the coder loaded on the router.

One guard blocking half a procedure, and the half it blocked was the half that ends the state. The safety hook that saves live inference files also guards the cleanup path, and refusing one without the other leaves a system whose shutdown latch never trips.

A ceiling three layers disagree about

Same run rewrote a number nobody asked for. Setup wrote --max-context 1000000 into both engine configs, up from 524288 with YaRN 2x, llama-swap started advertising context_length 1000000 in its model list, and my client pins still said 524288. Three layers carry that limit, an update moved two of them, none of the others. A stale third layer is invisible server-side: the engine runs the big window while every client reports the old ceiling, so sessions refuse at 524k and the box advertises nearly double on disk.

One capacity number, two answers on disk

A config number is never proof, so nobody had any basis to trust the new ceiling either. What this box verified is 524,288: a needle test at 509,084 real prompt tokens planted facts near position 50 and about 394k deep, past the trained window, both retrieved exactly, prefill measured 1,336 tok/s, putting half a million tokens at roughly six and a half minutes of silent reading before the first word. The new 1M value means YaRN 4x extrapolation, and on this box the same math says around 13 minutes of prefill with a deep-decode floor near 8 tok/s, every token reading the streamed KV off DDR4. Nobody ran a needle test there yet, so the ceiling got bigger on disk without anyone proving it works or wiring it to the clients that consume it.

What shipped and what I changed after

Four entries in the worklog carry the guard-refused line verbatim, engine stayed 0.1.44 through v0.2.8, the marker got cleared by hand over ssh, and the context drift sits flagged as pending a needle test before any deep read at 1M gets trusted. Two standing rules came out of it. Treat a refused step as an open job until something re-runs it, a deferral plus a green light is not a success report. And after any self-update, diff the version and the advertised limits across every layer that carries them, because one script touching two layers while a third stays behind is how you get a machine arguing with itself about its own capacity. My status reporter had drifted too, its cache lines stale since Oct 21 while live git describe read v0.2.7.1, which means the thing watching for updates was lying about what it saw while the thing being watched deferred half of what it got.

Should an updater fail outright when it can't get hands on the piece it's updating, or keep reporting done with the debt logged? Mine reports done, three refused swaps behind that verdict, and the only reason I found the pattern at all is that the refusal text made it into the log. What does your tooling do when it can't touch the running thing?

Top comments (0)