Freezes the lv-mccarthy gate design while no McCarthy generation exists, per the
lv-hemingway precedent: a threshold chosen after seeing the numbers is not a
threshold. Three arms (base-unadapted, ckpt900, ckpt450), 60 beats, 4 seeds.
Settles the voice-axis question D1 deferred. McCarthy's corpus measures 0.0 quote
marks per 10k against Hemingway's 838, so "emit no quotation marks" is the cheapest
way to move a char-bigram Delta without learning a sentence. Three parts:
PRIMARY unchanged -- the mccarthy register names the punctuation and
--system-from drives the base control with the same prompt, so the
cheap win is handed to both sides.
SECONDARY voice_distance.py --secondary-normalised re-runs the whole analysis
with punctuation stripped from the reference and every arm. A
conservative lower bound; reported, never the verdict.
TRIGGER voice_distance.py --punct-report evaluates a pre-registered line --
base-unadapted quote density above 100 per 10k means the control did
not take the win it was handed, and the normalised read is promoted
to load-bearing. 100 is the order-of-magnitude line between this
corpus's 0.0 and Hemingway's 838, chosen now rather than after the
table prints.
ckpt450 is NOT tied with the minimum (+4.9x the 0.00393 median neighbour jitter)
and the pre-registration says so. It is generated to test a stated prior and to
price the memorisation headroom an earlier checkpoint buys on an in-copyright
author, with a decision rule that says exactly what result would let it displace
ckpt900.
Instrument controls, run before this landed:
- the voice_distance.py refactor reproduces the shipped lv-hemingway
voice_distance.txt BYTE FOR BYTE on the default path
- strip_punct drops a quote-bearing sample from 2500.0 to 0.0 marks per 10k
- the secondary read still resolves a gap on the Hemingway arms (+0.410 at
7.3x floor), so a null on McCarthy would be a finding, not a blind detector
Pre-flight re-run at gate time rather than quoted from 2026-09-17:
- leak gate: 0 of 75 renameable, 0 of 37 sub-threshold, 0 separator-split,
four controls green
- beat-contamination audit: 0 of 3942 beats AND 0 of 3942 responses, against
Hemingway's 70 of 7094 -- build_sft_pairs.py --source-entities earned its
mandatory flag
Also records three provenance defects found on first read of the run and their
disposition: the hardcoded "r49-babyyarros-pairs-pilot" run label (cosmetic, same
literal on all three runs), the empty harness_commit (all three runs), and a
pairs_sha256_16 that is not a sha256sum of the file (consistent across runs, so a
cache key rather than a fault). The run is bound to McCarthy's pairs by record
count, not by the label.
eshpfi-management
Infrastructure management workspace for the PFI fleet (plus the ESH home-lab host). Tracks server state, canonical Docker Compose stacks, per-host configs, and the tooling that moves them around.
See CLAUDE.md for the full set of conventions and the rules Claude Code sessions follow when working here.
The fleet
Docker hosts:
| Host | IP | Site | Role |
|---|---|---|---|
| fv-ml1 | 10.251.50.54 |
Fountain Valley (10.251.0.0/16) |
GPU / AI inference (bare metal, 4× RTX PRO 6000 Blackwell Max-Q) |
| ana-docker | 10.250.50.70 |
Anaheim | General-purpose Docker + cross-site hubs (VM on pfi-pve) |
| nh3-docker | 10.100.50.40 |
NH3 (10.100.0.0/16) |
General-purpose Docker (VM on nh3-pve) |
| esh-docker-vm | 10.0.50.45 |
ESH home lab (esteban.net) |
Home-lab Docker (VM on esh-pve, non-PFI scope) |
| vm-esh-nas | 10.0.50.154 |
ESH home lab | NAS-adjacent Docker, NFS-mounted shares (VM on esh-pve-nas, non-PFI scope) |
Proxmox hypervisors (tracked for inventory; not Docker targets):
| Host | IP | Site | Role |
|---|---|---|---|
| pfi-pve | 10.250.250.31 |
Anaheim | Proxmox VE (188 GB / Xeon Silver 4310) |
| nh3-pve | 10.100.250.60 |
NH3 | Proxmox VE (62 GB / i9-13900H) |
| esh-pve | 10.0.250.35 |
ESH home lab | Proxmox VE (62 GB / i9-13900H) |
| esh-pve-nas | 10.0.50.55 |
ESH home lab | Proxmox VE, storage-dedicated (125 GB / Xeon W-1250) |
Per-host snapshots of the running system live under servers/<host>/system-details.txt, refreshed via scripts/refresh-server-info.sh.
Layout
.
├── CLAUDE.md # conventions; loaded by Claude Code sessions
├── README.md # this file
├── scripts/ # workstation tooling
│ ├── server_inspect.sh # read-only diagnostic, runs on remote via stdin
│ ├── proxmox_inspect.sh # Proxmox-aware probe (VMs, LXCs, storage, backup coverage)
│ ├── refresh-server-info.sh # pull fresh system-details.txt for one/all hosts
│ ├── refresh-proxmox-info.sh # pull fresh proxmox-details.txt for one/all PVE nodes
│ ├── add-host.sh # register a new server (writes servers/<name>/ssh-target)
│ ├── sync-stacks.sh # pull /opt/docker/{compose,conf}/ → stacks-mirror/
│ ├── deploy-stack.sh # push stacks-mirror/<host>/<stack>/ with diff + prompt
│ ├── discover-fortigate.sh # DHCP lease list from a FortiGate via SSH
│ ├── discover-unifi.sh # client list from a UniFi Controller via REST
│ └── discover-gaps.sh # find IPs in discovery TSVs not tracked in servers/
├── servers/ # per-host notes + latest snapshot + ssh-target fallback
│ └── <host>/
│ ├── README.md
│ ├── system-details.txt # regenerate on demand
│ └── ssh-target # <ip> or <user>@<ip>, used when DNS fails
├── stacks/ # canonical compose files (source of truth)
│ └── <stack>/
│ ├── compose.yaml
│ ├── .env.example
│ └── README.md
├── stacks-mirror/ # gitignored — live mirror from sync-stacks.sh
├── configs/ # host-level config files that aren't docker-compose
│ ├── homepage/ # canonical config for the fleet dashboard (on esh-docker-vm)
│ └── restic/<host>/ # resticprofile configs + pre-backup hooks
└── docs/ # general reference (network, models, proxmox, etc.)
└── pfi/
Current stacks
GPU (fv-ml1):
llama-swap— GGUF model swapper via llama.cpp (port 9292)vllm— embeddings (8001) + reranker (8002) + Skywork reward classifier (8003) via vLLM
Anaheim non-GPU (ana-docker):
traefik,crowdsec,gitea,vaultwarden,synapse,seafile,searxng,openwebui,sillytavern,mailrise,rustdesk,dockge,it-tools- (
mattermostretired 2026-04-21 — compose dir may still linger, containers gone) - Notes / feeds:
miniflux(RSS, 8080),nevermore(twice-daily LLM-curated brief, 8181, multi-tenant — extracted to its own repo atvh/nevermore),memos(note server, 5230) - Assistant tooling:
task-board(MCP + dashboard for assistant task state, 7878) - Fleet services:
beszel(metrics hub, port 8090),dozzle-hub(log viewer, 8088),backrest(restic UI, 9898) - Backup target:
rest-server-anaon port 8000
GPU fv-ml1 (non-canonical for now):
comfyui,kokoro,parakeet,vibevoicealongside the canonicalllama-swap+vllm
NH3 (nh3-docker):
adguard,dockge, plus Beszel/Dozzle agents
NH3 (Synology 10.100.50.50):
rest-server-nh3— restic backup target (port 8000)
ESH home lab (esh-docker-vm):
adguard,homeassistant(macvlan),esphome,mosquitto,paperless-ngx,pgadmin,calibre-web-automated,drawio,traefik,homepage,uptime-kuma, plus Beszel/Dozzle agents
ESH home lab (vm-esh-nas):
filezilla(web UI on port 5800),dockge, plus Beszel/Dozzle agents. Mounts/mnt/{share,music,books,media}from the Debian NAS at 10.0.50.50.
Common tasks
Refresh one host's snapshot:
scripts/refresh-server-info.sh ana-docker
Refresh all hosts:
scripts/refresh-server-info.sh all
Refresh all Proxmox nodes (separate flow — captures VM/LXC/backup-coverage):
scripts/refresh-proxmox-info.sh all
Add a new host:
scripts/add-host.sh <name> <ip-or-user@ip>
scripts/refresh-server-info.sh <name>
Validate discovery (without hitting the network):
scripts/refresh-server-info.sh --validate-only all
Push a stack to a host (with diff + confirm):
scripts/deploy-stack.sh <host> <stack>
Pull every server's compose/conf trees into stacks-mirror/ (not committed — see .gitignore):
scripts/sync-stacks.sh all
Bootstrap a new fleet repo from this one:
scripts/fork-fleet.sh ~/development/<other-fleet>-management
# optional: override the fleet-name baked into the skeleton CLAUDE.md / README
scripts/fork-fleet.sh ~/development/<dest> <fleet-name>
Mirrors the reusable tooling (everything under scripts/, the
generic playbook templates, .gitignore, conventions section of
CLAUDE.md) into the destination dir, strips fleet-specific content
(servers/, stacks/, configs/, fleet-named playbooks
(deploy-*, decouple-*), docs/orientation.md, docs/runbooks/,
docs/pfi/, STATUS.md, host-pinned helper scripts), regenerates
skeleton CLAUDE.md / README.md / STATUS.md with the new fleet
name, and initializes a fresh git history with one "Initial commit".
The script does not create a gitea remote or push — namespace +
repo name are an explicit manual step. The "next steps" output prints
the exact tea repo create + git remote add + git push commands
to wire it up when ready.
Backup pipeline
Backups are driven by per-host resticprofile configs under configs/restic/<host>/, scheduled via systemd timers on each host:
- Writes: each host backs up to its site-local rest-server (
rest-server-anaorrest-server-nh3), over HTTP basic-auth. - Authentication: shared
.htpasswdfile on both rest-servers, one entry per host; credentials stored in/etc/restic/restic.envon each client host. - Encryption: per-host client-side passphrase in
/etc/restic/password(unique per repo; losing it = losing that host's backups). - Visibility: Backrest (
http://10.250.50.70:9898) shows every repo for browsing/restore. - Schedule: backup at 01:00 daily,
forgetat 03:00 daily, weeklycheck --read-data-subset 10%on Sundays. - Prune: manual ceremony (rest-server runs with
--append-only, which blocks destructive prune ops). - Off-site: cross-site rsync between the two rest-server data dirs is planned (not yet implemented).
Coverage status (as of 2026-04-29)
Goal: every Docker host + configs + every database covered, not just VM images.
| Layer | State |
|---|---|
| VM-level (Proxmox vzdump) | ✅ All running guests covered across pfi-pve / nh3-pve / esh-pve-nas; esh-pve has VMID 108 uncovered |
| ana-docker restic (host files + DBs) | ✅ configs/restic/ana-docker/ with pre-backup hooks for synapse / seafile / vaultwarden-pg / gitea (native dump) / openwebui |
| fv-ml1 restic | ✅ configs/restic/fv-ml1/ — bare-metal host files (no DB hooks needed) |
| nh3-docker restic | ✅ Light — no DB hooks needed |
| esh-docker-vm restic | ✅ With DB hooks for paperless-postgres (external), home-assistant + pgadmin + uptime-kuma (host-side sqlite3), calibre-web-automated (in-container sqlite3) |
| vm-esh-nas restic | ✅ Light — NFS mounts explicitly excluded |
| nh3-dev (workstation) restic | ✅ /home/lkraven + /etc with language-toolchain and build-output excludes |
| irv-ml1 restic | ✅ Cross-site to rest-server-nh3 via WireGuard |
| esh-vm-db restic | ✅ With pg_dumpall + mongodump pre-backup hooks |
| Cross-site redundancy | ✅ ana-nas → nh3-nas rsync at 04:00 daily; nh3-nas → ana-nas at 05:00 daily (configs/rsync/) |
| Prune ceremony | ✅ Quarterly manual ritual documented in docs/runbooks/nh3-prune-ritual.md (DSM-mediated --append-only toggle) |
| offen/docker-volume-backup sidecars on esh-docker-vm | ❌ Remove once restic proves itself (~1 week of clean runs) |
Authoritative vs. mirror
- Authoritative: files on each server under
/opt/docker/compose/<stack>/and/opt/docker/conf/<stack>/. - This workspace: source-of-truth copies under
stacks/<name>/(hand-curated), and a gitignored mirror understacks-mirror/pulled bysync-stacks.sh.
Edit in stacks/, push with deploy-stack.sh. Never commit stacks-mirror/ — it can contain embedded plaintext secrets from upstream compose files that haven't been audited yet.