Day 35 — 'two gates, three daemons.'
Pre-flip gate-clearing that turned into archaeology. Gate 1: the adapter-naming collision — the hand-launched model is werbos-0.0.1 (three-part) but the train-daemon policy minted werbos-0.1 (two-part), so the README contradicted itself AND the daemon didn't recognize its own v1. Fixed: three-part werbos-MAJOR.MINOR.PATCH lineage, 5530 green. Gate 2: the nightly trainer had been FAILING every night — macOS TCC blocks launchd from the venv+script living under ~/Documents. Relocated the whole stack to ~/werbos (snapshot venv, no GUI grant). Then the twist: the werbos-0.1/0.2 'mystery tags' on the homelab weren't a mystery — a SECOND train-daemon (a Day-27 stub timer, growth-floor 0, ollama-create-copy 'trainer') was still churning out junk base-copies every 2 hours with the old naming. Disabled it, removed the junk. Both gates green; repo clear to flip.
“two gates, three daemons.”
The plan was small: clear the last two blockers before flipping the repo public. It turned into a dig — every gate I opened had a second problem hiding behind it, and the “mystery” at the end was a daemon nobody remembered was running.
Gate 1 — the adapter-naming collision (26a754f)
The first trained model, hand-launched on Day 30, is werbos-0.0.1
— three-part, on disk, in every doc and the THESIS. But the
train-daemon’s versioning policy used a two-part scheme:
werbos-0.1 → werbos-0.2. Two bugs fell out of the mismatch:
- The README contradicted itself — it told you to train
--out .../werbos-0.1and then chat--model werbos-0.0.1. A stranger copy-pasting hits “model not found.” A public-flip blocker hiding in plain sight. - The daemon didn’t recognize its own child —
next_version("werbos-0.0.1")didn’t match the two-part regex, so the ratchet treated the launched v1 as garbage and reset towerbos-0.1.
Fix: adopt three-part werbos-MAJOR.MINOR.PATCH, patch-bumping
(0.0.1 → 0.0.2), _INITIAL_VERSION = werbos-0.0.1 so the daemon
continues the launch lineage instead of forking a parallel one.
README examples now agree; every docstring/help/test reference
updated. 5530 green.
Gate 2 — the nightly trainer was failing every night
The launchd job had been erroring since the day it was armed:
Operation not permitted, exit 126. Not a chmod issue — macOS TCC
blocks launchd from the script and the venv, because the whole
training stack lives under ~/Documents (a protected folder). So no
nightly cycle had ever actually run.
Fix (relocate, no GUI grant): rebuilt the venv at ~/werbos/.venv
(pip install . → the git-pinned siblings, plus mlx-lm), copied the
script to ~/werbos/bin, repointed the plist out of the protected
tree. Clean run on the first try — pulled corpus, decided no_growth
(17 rows < floor 100), exit 0. The one tradeoff: that venv is a
snapshot, so training-code edits need a reinstall.
The twist — a third daemon nobody remembered
The werbos-0.1 / werbos-0.2 “mystery” Ollama tags on the homelab
weren’t a mystery once I looked: same blob id = identical copies
of the 3B base, not real adapters. Something was still making them
— and it was a second train-daemon: a Day-27 systemd timer,
2-hour cadence, --growth-floor 0 (trains every run no matter what),
pointed at a stub trainer that just ollama creates a copy of the
base. Scaffolding from before the real trainer existed, still dutifully
churning out junk every two hours with the deprecated naming.
Disabled the timer, removed the junk models. The homelab’s real job in the loop is corpus generation; training is Mac-only now (MLX needs Metal; the homelab is AMD CPU).
Numbers worth keeping
- 5530 tests green after the three-part conversion
- “hey buddy” nightly cycles run: 0 → working (TCC relocate)
- Junk models churned every 2h: stopped (third daemon killed)
AHAs
- Every gate had a second problem behind it. The naming fix exposed the daemon’s self-rejection; the launchd fix exposed the whole stack lives in a folder launchd can’t read; the “mystery” exposed a forgotten daemon. Pre-flip cleanup is where the closet skeletons rattle.
- A stub that “proves the pipeline” outlives its usefulness and becomes noise. The Day-27 scaffold was right to exist then and wrong to still be running now.
- Write the mystery down or re-debug it. The tag mystery was only fast to solve because Day-30’s launch lineage was documented.
Tomorrow
Both gates are green. The repo’s clear to flip — but instead of flipping, the higher-leverage move is to build the eyes: cross-layer observability, so the next time a daemon’s quietly broken, I can see it instead of digging.