Private research document · 2026-10-18 · not for publication —
names machine-specific ports, paths, and processes. Companion records: ~/manifest.md §3
(cockpit / punchclock / pipeline lines), flags 13–16 (~/flags.txt), checklist 48
(~/todo.checklist), mem #141/#142 (topic infra).
Question asked: where is this system brittle — where can it fail in a way that is silent, self-inflicted, or unrecoverable without a human?
Method. Every claim below is from one of three places: (a) the actual source, read this
session; (b) the machine’s own files (ledgers, ~/.run/*, process table); (c) the 12 hours
of incident the searxng chain just lived — a queue clobber, a 36-second gate flap, one deck kill/rebuild,
a 59-minute agent job dispatched mid-session. Nothing here is recalled.
One deno serve process on 127.0.0.1:8443 is, at once: the HUD (the owner’s dashboard),
the tailnet front’s target (443 → / and /studio), the queue’s dispatch
pump, the deep-work gate’s consumer, and the pipelines card. It drains one FIFO, one job at a time, from
~/.run/queue.json, which three writers touch: the card (both books:
~/pipelines/<slug>/meta.json + the schedule), the pipeline CLI (both books),
and the pump itself (persist() on state change). The focus gate (a 30-second watch
loop under launchd) flips a boolean that throttles the pump and ComfyUI.
Mechanism. pi-activity
(~/projects/punchclock/adapters/pi/pi-activity.py) builds lanes from pi-ledger events and
transcript mtimes; idle = 300 s of quiet, active = an event within 120 s,
poll every 30 s. Thinking writes no transcript bytes. A sustained ≈5-minute thinking
stretch is indistinguishable from the agent being gone.
Evidence (this session). The focus ledger shows
flip-off 16:50:33Z → the pump dispatched the searxng plan at 16:50:19Z-window, and
start-comfyui ran — then flip-on 16:50:49Z, 36 s later, as my session
resumed. A 59-minute agent job ran, and ComfyUI loaded its weights (the unified-memory hog the 10-14 ruling
exists to keep away), while the working session was mid-thought. The 10-14 purpose — the agent
gets the machine while the agent is present — inverts exactly in its most load-bearing window:
a long think.
Severity. High. The throttle’s failure direction is the dangerous one: a false off runs heavy work under the operator; a false on merely defers work, which the queue absorbs.
Fix. The ledger already defines a beat work-kind and the harness plumbs it
(work_kinds=("start","beat")) — the missing piece is emission: the pi extension
writes a beat when a session begins thinking, so an in-flight think reads as activity. Fallback if emission
proves coarse: never flip off while a session started < 30 min ago has not recorded a
stop.
Mechanism. makePump().tick()
(~/projects/cockpit/lib/studio/queue.ts ≈L330):
// the dispatch slot — one at a time if (store.runningCount() >= 1) return; ... await deps.runPipeline(job); // `pipeline runTwo independent wedges, same outcome. (a) Crash: the deck process is the HUD + the tailnet face + the pump + the gate reader. It has no watchdog — launchd only runs--wait`, NO timeout
com.pi-web.* and
com.rosey.focus; the 10-17 KeepAlive experiment was rightly abandoned (it raced the clean
stop, the 2026-10-15 lesson). So a deno crash or OOM = everything queued dark and silent until a
human notices. There is no “queue is non-empty but nothing is dispatching” alert. (b) Hang:
--wait does code = p.wait() with no deadline; a wedged agent =
runningCount() ≥ 1 forever = every tick() early-returns by design. One
hung child = a permanently silent queue.
Adjacent. A corrupt queue.json makes load() return an
empty store (graceful boot — good) but silently loses every queued image job (the card’s
self-heal recovers only pipeline rows; image jobs leave no ledger trail).
Severity. High. A work system that cannot revive itself and in which one wedged row freezes the whole queue fails invisibly. Both modes require a human staring at the HUD to notice.
Fix. (a) A non-reviving watchdog: a periodic launchd agent that curls
/api/who and restarts the deck only when dark and no manual-off marker exists
(cockpit stop writes the marker; the watcher respects it) — supervision that preserves the
clean off/on standard, which raw KeepAlive could not. (b) A dispatch deadline: the pump tracks
started; a pipeline row silent for N minutes with a dead/absent --wait pid is
marked failed, the slot frees, the queue lives. (c) On corrupt file: rename to
queue.json.corrupt-<ts>, boot empty, and surface the loss in the HUD — never silent.
Mechanism. QueueStore.persist() saves its in-memory view over the
whole file; the only merge, syncFromFile(), runs at the top of tick() — which
early-returns while busy > 0. A card- or CLI-written row is invisible to the pump for as long
as any job runs. (This is the generalization of manifest rule 1(e), added today: a write-back
path is a writer.)
Evidence. Your 16:29:56Z searxng click wrote the row correctly (the two-books fix
was deployed). The co-running system-heat plan finished at 14:15Z–window →
remove() → persist() → the file was rewritten from the pump’s blind
view → the row was gone. LEDGER said queued; SCHEDULE said []; the HUD said
“queued” (it renders the ledger). The books diverged because the pump’s writer doesn’t
read before it writes.
Severity. High — silent work loss with a cheerful UI. Status:
queued as checklist 48 + flag 14; the fix is one function (syncFromFile() before the write)
+ a regression test. Awaiting your green light for a rebuild window.
Three real divergences found while verifying the above — all of them of the class rule 1(c) warns about (a record written from intent is a lie waiting to happen), today biting in both directions:
| Record | Machine | Direction of the lie | Cost paid |
|---|---|---|---|
Manifest: “run takes a per-slug lock (~/.run/locks/pipeline-<slug>,
released at finalize) — no double dispatch” |
No lock exists anywhere in the current tree, and git log --all shows it never did in
job-queue. The only guards are a read-then-act ledger check (TOCTOU: two concurrent runs can
both read “not running” and both launch) and the deck’s single in-process slot. |
Record claims a guard the code lacks | This audit would have been “safe” on paper; it took four reads to prove the lock a phantom. |
Manifest cockpit line: “live = the source tree (vite dev on
8090)” |
The live deck is a built snapshot (_fresh/server.js, 8443). The same line, later,
says 8443 built artifact — the manifest contradicts itself. |
Record lags the 10-18 repoint | — |
| &ldash; (no stamp) | _fresh/ carries no provenance: nothing says which git commit the running deck was built
from. |
Machine lacks a record it needs | I concluded “the live deck predates the fix” from manifest+mtimes and was wrong — the content-hash of the chunk proved the fix deployed. ~30 min of a false deploy story. |
Severity. Medium–high, compounding. Every other finding is easier to hide
when the deploy surface itself is unprovable. Fix. (a) Correct manifest lines to the
machine (do it the moment a finding lands). (b) A cockpit start writes
_fresh/BUILD-INFO (HEAD, branch, build time) and a /api/deploy
endpoint serves it; a mismatch with HEAD prints at start. Turns “is the fix live?”
from an investigation into a one-liner.
“Never run both decks (two pumps on one queue.json double-dispatch)” is a manifest
sentence. Nothing mechanical stops a second deno serve: bin/cockpit
manages 8090 (its pidfile is .run/cockpit.pid), while the live 8443 deck was started by
ad-hoc bash with a non-canonical, stale pidfile (8443-serve 25776 — flag 13; 25776 is
dead, the real pid is 62577). cockpit stop silently no-ops on the deck that’s actually
running. Image double-dispatch (two pumps → two engines → one ComfyUI) is unguarded; pipeline
double-dispatch rests on the racy check of finding 4. Fix. Make 8443 the
bin/cockpit instance (the script already honors COCKPIT_PORT — one wrapper:
start --prod) + a single-instance lock (the repo’s lib/locks.ts) taken at
boot, checked on every dispatch.
File mtimes are local CDT; the ledgers write epoch-ms; the pipeline ledger writes ISO-Z; the schedule writes epoch-seconds. I misread the incident timeline twice this session (13:59Z appeared “before” 08:26 — it was 08:59 CDT, after) and one misread rode into a compaction boundary. Any reader that pairs an mtime with a Z-timestamp makes a 5-hour coin flip. Fix. A rule, not code: epochs are canonical; mtimes are display-only — written into the manifest so every future reader inherits the discipline.
The 10-15 design deliberately chose one slot, FIFO, one at a time. It was the right call for memory (safety: the focus gate’s whole premise). The cost is throughput: a long plan blocks a quick render, and vice versa; the searxng plan’s 59 minutes was a full day’s worth of render capacity. Fix (design call, not urgent). Kind-aware lanes — heavy agent works stay gated; light renders may take the slot in between — or, cheaper: at least make the slot’s policy visible in the HUD (why is my render waiting 40 minutes?) so the ceiling reads as a choice.
cockpit on/off takes / and /studio together; the serve map is
tailscaled’s in-memory state (10-15 flag — a tailscaled restart darkens the maps until
the front is re-toggled). A known, ruled tradeoff of one-front simplicity. Listed for completeness; the
watchdog of finding 2 should health-check the face, not just the app.
| # | Fix | Where | Dark window |
|---|---|---|---|
| 1 | Thinking-beats for the gate (extension emits beat; the ledger+watch already half-plumb it) |
~/projects/punchclock + the pi extension | none — the watcher hot-reloads the contract |
| 2 | Pump dispatch deadline + corrupt-file quarantine (finding 2) | cockpit/lib/studio/queue.ts | shares #3’s rebuild |
| 3 | persist() merges (syncFromFile before save) + regression test (finding 3; checklist 48 / flag 14) |
cockpit/lib/studio/queue.ts | one rebuild + off/on of the deck (~10–20 s, whole front dark) |
| 4 | Build provenance: BUILD-INFO + /api/deploy + start-time stamp check (finding 4) |
cockpit build + bin/cockpit | same rebuild |
| 5 | Canonical 8443 via bin/cockpit start --prod + single-instance lock + dead-lock reaping (findings 4+5; closes flag 13) |
bin/cockpit + lib/locks.ts | same rebuild (the off/on drill becomes the proof) |
| 6 | Non-KeepAlive deck watchdog (finding 2; manifest + launchd) | ~/Library/LaunchAgents + manifest | none — additive |
#2–#5 ride one rebuild so the owner pays one dark window; #1 and #6 need none. Findings 6–7 are rule-level and cost a manifest line, not a rebuild.
(a) The rebuild window for #2–#5 — your call (the earlier ask was cancelled). (b) Whether the
watchdog’s manual-off marker pattern satisfies your clean off/on standard (it is designed to: the marker
is the standard, made machine-readable). (c) The searxng build itself stays terminal-only
(“pipeline run searxng-self-host build”) — the plan is in
~/implementation-plans/searxng-self-host-impl-plan.html, chain is planned,
ready when you are.