Root filesystem disk audit: point-in-time attribution and recommendations (v2 supersedes v1)

Headline numbers

149.65 GiBdf used measured

Byte-derived df used figure.

148.43 GiBAllocated, dedup measured

inventory-v2 total. Hardlink duplicates are excluded.

145.75 GiBApparent size inferred

Separate series. The allocated-minus-apparent gap is inferred.

2.38 GiBHardlink duplicate excluded measured

Not counted in allocated dedup.

1.22 GiBResidual, unattributed unattributed

df used minus allocated dedup. Not yet attributed to any group.

7 inodesDeleted-open measured

Counts only. 1921024 bytes. Audit snapshot values above are unchanged. Later probe (16:00Z, not a replacement for the snapshot): 124 rows holding 74.8 MiB (lsof +L1).

12.00 GiBSwap verified

Swap files, counted within the inventory parts.

df size 160921083904 bytes, df available 0 bytes. At the audit snapshot (taken mid-cleanup, ~14:27-14:40Z) the root filesystem was full, with 0 bytes available. A later read-only probe at 16:00Z (different time and metric) showed 16.11 GiB available, 89% used, and falling: down 245 MiB since ~15:19Z.

The v1 byte figures below come from a different pass (14:27-14:30). They are not directly comparable to the v2 GiB figures above.

v1 byte figures, separate pass
Measure (v1 pass, bytes)Bytes
Allocated (v1)161921875968
Apparent (v1)156491051863
Hardlink duplicate (v1)2556145664
Residual (v1)1315233792

Allocation inventory (GiB, v2)

P01 lane-worktree-groupP02 os-usrP03 session-checkout-groupP04 swap-groupP05 scratch-groupP06 primary-checkout-1P07 home-config-groupP08 agent-home-groupP09 cache-groupP10 venv-groupP11 other-worktree-groupP12 audio-groupP13 other-root-groupP14 os-varP15 os-bootP16 other-top-level-groupR rounding remainder (unverified)
  • P01 lane-worktree-group
  • P02 os-usr
  • P03 session-checkout-group
  • P04 swap-group
  • P05 scratch-group
  • P06 primary-checkout-1
  • P07 home-config-group
  • P08 agent-home-group
  • P09 cache-group
  • P10 venv-group
  • P11 other-worktree-group
  • P12 audio-group
  • P13 other-root-group
  • P14 os-var
  • P15 os-boot
  • P16 other-top-level-group
  • R rounding remainder (unverified)

Ranked by size

P01 lane-worktree-group46.92 GiB
P02 os-usr13.89 GiB
P03 session-checkout-group12.63 GiB
P04 swap-group12.00 GiB
P05 scratch-group10.59 GiB
P06 primary-checkout-19.83 GiB
P07 home-config-group9.82 GiB
P08 agent-home-group9.55 GiB
P09 cache-group7.26 GiB
P10 venv-group6.90 GiB
P11 other-worktree-group2.89 GiB
P12 audio-group2.75 GiB
P13 other-root-group2.63 GiB
P14 os-var0.69 GiB
P15 os-boot0.06 GiB
P16 other-top-level-group0.01 GiB

Additivity (centi-GiB integers): parts 148.42 + remainder 0.01 = 148.43 GiB; total_gib 148.43 GiB. Result: additive.

Allocation groups; GiB = 2^30 bytes
IDGroupGiBFilesShareConfidenceNote
P01lane-worktree-group46.9292250331.6%executor-reported233 lane categories merged. Largest reclaimable-candidate finding. Candidate only: ownership of each lane is unverified; do not delete without owner review. v1 listed only 26 lane categories (5.63 GiB).
P02os-usr13.892323599.4%executor-reportedOS and toolchain. Not a candidate.
P03session-checkout-group12.633787648.5%executor-reported2 categories merged. Agent session checkouts.
P04swap-group12.0038.1%verifiedTwo swap files, byte-verified (12884901888 B in v1 pass). Swap in use is 4.26 GiB (research note). Not a delete candidate.
P05scratch-group10.59702087.1%executor-reported8 categories merged. Scratch: bounded quota and TTL are a recommendation (R4).
P06primary-checkout-19.83907636.6%executor-reportedLive checkout. Includes user pack data (webapp packs/uploads). Never auto-deleted.
P07home-config-group9.821774736.6%executor-reported4 categories merged. Home and configuration.
P08agent-home-group9.551188276.4%executor-reported10 categories merged. Agent and tool homes.
P09cache-group7.26787854.9%executor-reportedCaches.
P10venv-group6.90533454.7%executor-reported4 categories merged. Virtual environments.
P11other-worktree-group2.89995341.9%executor-reported57 categories merged. Non-lane worktrees.
P12audio-group2.75301501.9%executor-reportedAudio assets. Storage routing is a recommendation (FLAC to StorageBox, OGG to object storage).
P13other-root-group2.63214471.8%executor-reported53 categories merged. Includes two largest-file archives.
P14os-var0.6971880.5%executor-reportedVariable OS data including logs.
P15os-boot0.065770.0%executor-reportedBoot.
P16other-top-level-group0.0119630.0%executor-reported6 categories merged.
Rrounding remainder (unverified)0.01——unverifiedExplicit 0.01 GiB rounding row so parts sum to total. Not the 67.25 GiB v1 remainder, which was a truncation artefact (v2 v1_truncation block).

Allocated (dedup) versus apparent size

Allocated, dedup (v2 GiB)148.43 GiB
Apparent (v2 GiB)145.75 GiB
Allocated versus apparent (v2 GiB)
SeriesGiBConfidenceNote
Allocated, dedup148.43measuredAdditive total. Hardlink duplicates excluded.
Apparent145.75inferredSeparate series. Not merged with allocated.
Hardlink duplicates excluded2.38measuredRemoved from the allocated dedup series.
Allocated minus apparent (difference)2.68inferredAttributed to block rounding and sparse files. Inferred, not measured.

Two separate series, never merged. Allocated minus apparent (2.68 GiB) is attributed to ext4 block rounding and sparse-file effects; this is INFERRED, not measured. Hardlink duplicates (2.38 GiB) are excluded from allocated_dedup. v1 pass (different snapshot): allocated 161921875968 B, apparent 156491051863 B.

*_b_v1 byte figures come from a different (v1) pass than v2 GiB. v1 bytes: allocated 161921875968 B, apparent 156491051863 B, hardlink 2556145664 B. Not mixed into the GiB figures above.

Section confidence: inferred

df reconciliation (waterfall, GiB)

Waterfall: df used 149.65 GiB − allocated dedup 148.43 GiB = 1.22 GiB residual, unattributed (stated residual 1.22 GiB).

df size149.87 GiB
df used149.65 GiB
df available0.00 GiB
Allocated dedup (v2)148.43 GiB
Hardlink duplicate (excluded)2.38 GiB
Residual (1.22 GiB), unattributed1.22 GiB
Unexplained gap (0.07 GiB)0.07 GiB
Deleted-open files0.00 GiB
Swap files (in P04)12.00 GiB
df reconciliation entries
EntryGiBConfidence
df size149.87measured
df used149.65measured
df available0.00measured
Allocated dedup (v2)148.43measured
Hardlink duplicate (excluded)2.38measured
Residual (1.22 GiB), unattributed1.22unattributed
Unexplained gap (0.07 GiB)0.07unverified
Deleted-open files0.00measured
Swap files (in P04)12.00verified

Overlapping rollups

Each row is a separate view of the same bytes. Do not add rows together.

NOT ADDITIVE — overlapping views, do not sum
LabelGiBFilesAdditive
lane-worktree-group46.92922503false
tooling-group35.417692false
venv-group22.52234289false
session-checkout-group12.63378764false
swap-group12.002false
cache-group7.5584213false
audio-group7.443385false
node_modules-group7.29256941false
git-group1.8140654false
pycache-group1.4869279false
logs-group0.457364false

Extensions (ranked by GiB)

Ranked by allocated GiB. Extension is taken from the filename, not from file content.

(none)26.29 GiB
png25.44 GiB
so12.58 GiB
onnx9.62 GiB
json8.56 GiB
md5.61 GiB
js5.57 GiB
py5.27 GiB
ogg4.55 GiB
123.38 GiB
93.32 GiB
gz3.24 GiB

Modified-time histogram (PROXY ONLY)

PROXY ONLY, not growth, no time series. Last-write, create, copy or touch time; not a growth measure.

pre-20251.33 GiB
2025-010.00 GiB
2025-020.00 GiB
2025-030.00 GiB
2025-040.01 GiB
2025-050.01 GiB
2025-060.02 GiB
2025-070.00 GiB
2025-080.03 GiB
2025-090.02 GiB
2025-100.06 GiB
2025-110.12 GiB
2025-120.19 GiB
2026-010.29 GiB
2026-020.24 GiB
2026-037.99 GiB
2026-040.56 GiB
2026-050.09 GiB
2026-062.26 GiB
2026-071.72 GiB
2026-082.61 GiB
2026-0910.22 GiB
2026-10120.59 GiB

Months sum to 148.36 GiB against 148.43 GiB allocated: a 0.07 GiB gap. Cause not measured (unverified).

Largest entries (redacted)

Redacted: leaf names are withheld. Columns are rank, GiB, type and directory group only.

Largest entries (redacted)
RankGiBTypeDir group
18.00(none)swap-group
24.00(none)swap-group
31.34zipother-root-group
40.84socache-group
50.84soscratch-group
60.84sovenv-group
70.539cache-group
80.539scratch-group
90.539venv-group
100.5013os-usr
110.50zipscratch-group
120.50socache-group
130.50soscratch-group
140.50sovenv-group
150.42soos-usr
160.42soos-usr
170.4112cache-group
180.4112scratch-group
190.4112venv-group
200.41socache-group
210.41soscratch-group
220.41sovenv-group
230.41soaudio-group
240.39soos-usr
250.34(none)home-config-group
260.34(none)home-config-group
270.33zipscratch-group
280.28(none)home-config-group
290.28(none)os-usr
300.27(none)agent-home-group

Worktrees

Status is unreconciled. Lane groups are candidates; ownership is unverified and nothing may be deleted without owner review.
Worktree statistics
MetricValue
Lane groups (v2)233.00
Lane GiB46.92
Git linked worktree dirs587.00
Git main repo dirs120.00
Listed by git worktree list301.00
Statusunreconciled
Classificationcandidate lane groups; ownership unverified; no deletion without owner review (derived from p2 note)

Dependencies

Edges are the recorded dependency intent (configured, policy or observed). Node state is what was last recorded for each node. Nothing here was probed live.

frontendservicejobdatastorestoragecheckoutwriters/api/* proxied to API-origin gateway/api/* proxied to API-origin …enqueues jobs to job_queueenqueues jobs to job_queuedepends on gatewaydepends on gatewaydepends on job queuedepends on job queueclaims jobs in Modal-side workers; no local worker by enqueue-only policyclaims jobs in Modal-side wor…OGG routed to S3-compatible storageOGG routed to S3-compatible s…FLAC routed to archival storage boxFLAC routed to archival stora…TEMP, export cache and jobs writersTEMP, export cache and jobs w…installed unit WorkingDirectory targets live checkout (parity unverified)installed unit WorkingDirecto…reapers run only from gateway startup and request pathsreapers run only from gateway…reclaim touches build outputs and pycache only (configured list)reclaim touches build outputs…Gateway app (API origin s…FailedScaler serviceStopped or disabledLocal worker service (sta…Stopped or disabledPostgres job queueNot inspected (policy only)S3-compatible object stor…Not inspected (policy only)Archival storage box (FLA…Not inspected (policy only)Cloudflare Pages frontendNot inspected (policy only)Primary live checkoutLive or observed activeReapers (request-path, st…Live or observed activeHost resource guardFailedScratch writers (TEMP, ex…Configured (static read)

Edge confidence

Node state

Failed

  • Gateway app (API origin service) — FAILED, disabled; cause unestablished (observed, runtime notes §8)
  • Host resource guard — service FAILED; 2-minute timer active (observed)

Stopped or disabled

  • Scaler service — inactive, disabled (observed, runtime notes §8)
  • Local worker service (stale unit) — inactive, disabled (observed, runtime notes §8); absence consistent with enqueue-only policy

Not inspected (policy only)

  • Postgres job queue — not inspected (policy-described only)
  • S3-compatible object storage — not inspected (policy-described only)
  • Archival storage box (FLAC) — not inspected (policy-described only)
  • Cloudflare Pages frontend — not inspected; reported unaffected by gateway loss (policy)

Live or observed active

  • Primary live checkout — live; installed units target it (observed); parity with repo unverified
  • Reapers (request-path, startup, timer-driven) — request-path and startup triggers configured; tmp sweep timer active (observed); no local packs/projects reaper

Configured (static read)

  • Scratch writers (TEMP, export cache, jobs) — writers configured (static read); no TTL or quota bound today

Shutdown impact

Derived only from recorded edges. A node with no recorded dependents is not proof that nothing depends on it.

Shutdown impact derived from edges
NodeStateDepends onIf it stops, loses function for
Gateway app (API origin service)FAILED, disabled; cause unestablished (observed, runtime notes §8)Postgres job queue (enqueues jobs to job_queue); S3-compatible object storage (OGG routed to S3-compatible storage); Archival storage box (FLAC) (FLAC routed to archival storage box); Scratch writers (TEMP, export cache, jobs) (TEMP, export cache and jobs writers); Primary live checkout (installed unit WorkingDirectory targets live checkout (parity unverified))Cloudflare Pages frontend: /api/* proxied to API-origin gateway [inferred]; Scaler service: depends on gateway [inferred]; Reapers (request-path, startup, timer-driven): reapers run only from gateway startup and request paths [inferred]
Scaler serviceinactive, disabled (observed, runtime notes §8)Gateway app (API origin service) (depends on gateway); Postgres job queue (depends on job queue)No recorded dependents in evidence.
Local worker service (stale unit)inactive, disabled (observed, runtime notes §8); absence consistent with enqueue-only policyPostgres job queue (claims jobs in Modal-side workers; no local worker by enqueue-only policy)No recorded dependents in evidence.
Postgres job queuenot inspected (policy-described only)None recorded.Gateway app (API origin service): enqueues jobs to job_queue [inferred]; Scaler service: depends on job queue [inferred]; Local worker service (stale unit): claims jobs in Modal-side workers; no local worker by enqueue-only policy [inferred]
S3-compatible object storagenot inspected (policy-described only)None recorded.Gateway app (API origin service): OGG routed to S3-compatible storage [inferred]
Archival storage box (FLAC)not inspected (policy-described only)None recorded.Gateway app (API origin service): FLAC routed to archival storage box [inferred]
Cloudflare Pages frontendnot inspected; reported unaffected by gateway loss (policy)Gateway app (API origin service) (/api/* proxied to API-origin gateway)No recorded dependents in evidence.
Primary live checkoutlive; installed units target it (observed); parity with repo unverifiedNone recorded.Gateway app (API origin service): installed unit WorkingDirectory targets live checkout (parity unverified) [verified]; Host resource guard: reclaim touches build outputs and pycache only (configured list) [inferred]
Reapers (request-path, startup, timer-driven)request-path and startup triggers configured; tmp sweep timer active (observed); no local packs/projects reaperGateway app (API origin service) (reapers run only from gateway startup and request paths)No recorded dependents in evidence.
Host resource guardservice FAILED; 2-minute timer active (observed)Primary live checkout (reclaim touches build outputs and pycache only (configured list))No recorded dependents in evidence.
Scratch writers (TEMP, export cache, jobs)writers configured (static read); no TTL or quota bound todayNone recorded.Gateway app (API origin service): TEMP, export cache and jobs writers [inferred]

Installed services: wiring and shutdown impact

Services on this host and how they connect. Confidence: M = measured, C = config-evidenced, I = inferred.

Installed services: wiring and shutdown impact
UnitState on this hostExecStart or rolePort / routeLocal data depsRemote deps (names only)Shutdown impactConfidence
producehits-appdisabled; nothing listens on port 7860role: FastAPI gateway on the API originport 7860 (no listener)none recordedPostgreSQL job queue; Hetzner Cloud API via scalernone on this host (already not serving)M
producehits-scalerdisabledrole: provisions auto-scaled workersnonenone recordedPostgreSQL job queue; Hetzner Cloud APInone on this host while disabledM
producehits-workerdisabledrole: job worker daemon; hostname guard refuses to start on this hostnonenone recordedPostgreSQL job queue; Modal GPUnone on this host (disabled by policy)M
nginxsongchop.com and api-origin.songchop.com forward to 127.0.0.1:7860, which refuses connections (curl exit 7)role: reverse proxy and static file server (config)songchop.com and api-origin.songchop.com to 7860; other product domains serve static files from the coming-soon web rootcoming-soon web root (static files)nonestopping would not change the 7860 refusal; static product domains go offlineC (routes); public 502 is I (inferred, not curl-verified)
producehits-boot-selfheal.serviceenabled; unit body not readrole: boot-time self-heal unit (unit body not read, so role is unverified)none recordedunverifiedunverifiedUnverifiedM (enabled, unit list); body unverified
producehits-host-guardtimer-driven guard; earlier audit recorded the service as failed with timer active; current state not re-verifiedrole: timer-driven host guardnoneunverifiednone recordedunverified; prune call sites appear commented out around lines 293-294 (unverified)M (earlier audit); current state unverified
cx-console-tunnelunit disabled; a cloudflared process started 2026-10-17 is still running from a deleted binary named cloudflared.oldrole: tunnel to console hostsingress covers history and console hosts on 8898, /mission on 8899 (not listening), files on 8081none recordedCloudflare tunnel edgerestart would swap in the new binary; owner decision, not taken hereM (process); C (ingress)
cx-synctimer every 10 minutes; last run 15:04 UTC succeededrole: pushes an encrypted credential blob via the cx sync scriptnoneencrypted credential blob (contents not read)remote sync target (name only, not recorded here)pauses sync pushes; no local service impactM
producehits-backupdaily timer at 03:30 UTC; deploy/backup-to-storagebox.sh; systemd reports exit 0 at 03:34:54 UTCdeploy/backup-to-storagebox.sh: writes bundle, tarball and encrypted env to a remote storage box; also uploads a credentials archive (operator credentials and keys) and a checksum list to the dated code-backups folder; keeps 14 dated dirsnonebundle, tarball, encrypted env, credentials archive, checksum listremote storage box (name only)I: a failed run would leave no new off-host copy until the next run (upload unverified)M (exit 0); upload unverified: journal has no entries for the day
temp Postgres lanerunning on port 54329 from /tmp/lane-pg; not a system unit; 101 MBrole: temporary Postgres instanceport 54329/tmp/lane-pg data directory (101 MB)nonestopping drops only this temporary lane dataM
producehits-syncnot a unit, timer or cron; name is only a cache directoryused by deploy/dev-sync.sh:8 and deploy/go-live.sh:9 in manual operator flowsnonecache directory onlynonenone (no running process)I

Documentation conflicts

Installed vs source

Unverified

Writers, triggers, retention and measured growth

Read-only audit, partial, as of 2026-10-19. Nothing was deleted, vacuumed or restarted. Labels: measured means command output; config-evidenced means a file and line; inferred means reasoning from those. Anything unexplained is listed under Gaps.
Retention and growth by category
CategoryWriterTriggerRetention enforcedCurrent activity (mtime proxy)Growth evidenceConfidence
Worktrees (lane and session)Lane and session tooling; creator not tracedAutosave timer (producehits-session-autosave); creation trigger unverifiedprune.sh:33: git worktree remove only when the worktree is under the session folder, clean, landed, idle 24 h or more (default), and has no process inside. This is the only worktree removal path found.Not measured (sizes only)Lanes 47.37 GiB over 233 roots (prior 46.92; +0.45, cause not established). Sessions 10.13 GiB over 54 roots. Other roots 12.21 GiB (derived).measured
Session and artifact dirsPi and CX session logs (~/.pi/agent/sessions, ~/cx-sessions)Each session run (inferred)None found.~/.pi/agent/sessions: 786 files changed in 24 h. ~/cx-sessions: 63,695 files changed in 24 h (766.93 MB).~/.pi/agent/sessions 279.7 MB; ~/cx-sessions 2.9 GB (2,945.3 MB). No prior baseline, so growth is not measured.inferred
Harness homes~/.config/cx/harness-homes, written by harness runsHarness launch and session activity (inferred)host-guard prune_stale_harness_dirs (claude-*, opencode; over 120 min) at host-guard:242. Its call sites at :293-294 are commented out, so pruning is probably inactive (unverified).16,642 files changed in 24 h (288.57 MB)~/.config/cx/harness-homes 997.8 MB now. No prior baseline.inferred
Caches (~/.cache, uv)Package and tool caches. Largest entry is puccinialin (747 MB). uv lives in ~/.local/share/uv.Tool invocation (inferred)host-guard reclaim_disk:254-260 removes ~/.cache/uv on the disk-pressure branch. Same branch also removes /var/crash/*.crash. The threshold and whether the call runs are unverified. No age rule.~/.cache: 89 files (8.42 MB) changed in 24 h~/.cache 7,378,226,887 B to 944,160,768 B (-6.0 GiB, measured). ~/.local/share/uv 1,504,415,086 B to 1,653,059,584 B (+141.8 MiB, measured). The ~/.cache drop has no per-subdirectory baseline.measured
Journal and /var/logsystemd-journald; services through logrotate (cx-proxy, nginx, rsyslog, ufw, others)Continuous logging; logrotate.timer last ran at 00:23 todayafcut-host-cleanup.sh:11 runs journalctl --vacuum-size=200M daily (last run 00:23:50 freed 50M from the current dir). logrotate: weekly, rotate 4; cx-proxy size 25M, rotate 3. Logrotate caps by file count, not total size. No rule removes the old machine-id dir./var/log: 22 files (29.80 MB) changed in 24 hjournalctl --disk-usage reports 24M (current dir only); du reports 145M for the whole tree. Old dir is 113M, dated 2026-10-13, and not counted. /var/log 206.7 MB. Caps: SystemMaxUse 200M (20-producehits-cap.conf:3) and 500M (size-cap.conf:2). Effective 500M is inferred from file order.measured
/tmp and /var/tmp (/tmp is tmpfs)Session and tool scratch (lane-pg, packmobile, dbprobe, multiselect-chrome, lane-node, jiti)Tool runs (inferred)afcut-host-cleanup.sh:14-17 deletes top-level /tmp entries older than 2 days, excluding claude-*, tmux-*, systemd-private-*, jiti and node-compile-cache. host-guard prune_tmp_caches and scratch pruning (:195-205) are inactive at :293-294 (unverified). tmpfiles tmp.conf:9-14 is exclude-only; there is no age rule for /tmp or /var/tmp. producehits-tmp-sweep thresholds are unread./tmp: 6,969 files changed in 24 h (241.39 MB). /var/tmp: 3 files (0.13 MB)./tmp 332.0 MB. /var/tmp 216.4 MB with only 3 recent files and no age rule. Largest /tmp entries: lane-pg 101M, packmobile 65M (two dirs), dbprobe 45M. No prior baseline.measured
1G tmpfs under home (~/fill.UDRv/tmp)UnknownUnknownNone found. Separate filesystem; not in the / used count.Not measured1G tmpfs size (per brief); seen in findmnt; contents not measured.unverified
Temp Postgres lane (/tmp/lane-pg)Unknown; likely the temp Postgres lane (inferred)Lane start (unverified)None found. The 2-day /tmp rule applies only if the entry is older than 2 days (not checked).Not measured101 MB (du). Liveness on port 54329 not checked.unverified
Backups and build outputsproducehits-backup (remote dated dirs; also uploads a credentials archive and a checksum list to the dated code-backups folder; upload success unverified); build output $REPO/dist and __pycache__producehits-backup timer; build runsbackup-to-storagebox.sh: KEEP=14 newest dated dirs (:34); remote rm at :173; local stage and credential cleanup by trap (:55, :101). reclaim_disk removes $REPO/dist and __pycache__ under disk pressure (:254-260).Not measuredNot measured. Remote backup state not checked.config-evidenced
Large tool installs (sizes only)Editor server, sound bench, hermes, codex, grok sessionsTool use (inferred)None found.~/.hermes: 151 files (4.69 MB) in 24 h. ~/.codex: 1 file. ~/.vscode-server and ~/sound-bench: none in 24 h. ~/.grok/sessions: none.~/.vscode-server 4,213.4 MB; ~/sound-bench 2,975.9 MB; ~/.hermes 3,506.4 MB; ~/.codex 2,443.0 MB; ~/.grok/sessions 1,225.2 MB. No growth baseline.measured

Facts

Gaps (unexplained)

Sizes are apparent bytes. The mtime proxy shows recent writes only, not growth.

Migration

RECOMMENDATION ONLY: each item is a proposed change, not an instruction.

Migration items
IDTitleKindStatusBlockersTag
M-1Clock-gate the three existing reapers on one gateway timercoderecommendedR4 bounded scratch quota and TTL should land first (sequencing)RECOMMENDATION ONLY
M-2Opt-in local pack/project reclaim after remote manifest and object checkscodeblockedFounder retention policy for pack and upload directories (retention.md §6); research-first (F4)RECOMMENDATION ONLY
M-3Parameterize the host resource guard (statvfs, env thresholds, CRIT names pack and upload dirs)coderecommendedF3: diff installed host guard against repo copy firstRECOMMENDATION ONLY
R1Neutralize the stale worker unit after owner confirms its stateopsrecommendedOwner confirmation of stale worker unit stateRECOMMENDATION ONLY
R2Ensure gateway and scaler units are enabled and revivableopsblockedF1: gateway FAILED cause not established; research before any restartRECOMMENDATION ONLY
R3Clock-gate existing reapers (alias of M-1)codealiasSee M-1RECOMMENDATION ONLY
R4Bounded scratch quota and TTL over TEMP, export cache, jobs and projects rootscoderecommendedF2: checkout parity and stray tmpfs origin (BLOCKS R4)RECOMMENDATION ONLY
R5Opt-in local pack/project reclaim (alias of M-2)codeblockedFounder retention policy (see M-2)RECOMMENDATION ONLY
R6Parameterize host resource guard (alias of M-3)codealiasSee M-3RECOMMENDATION ONLY
LW-1Lane-worktree reclaim candidate (~46.9 GiB executor-reported, 233 categories)opscandidate, ownership unverified, owner review requiredPer-lane ownership not verified; Owner review required before any actionRECOMMENDATION ONLY

Principles

Coding-only relocation checklist and bounded lifecycle plan

PLAN ONLY. Nothing has been migrated, cleaned, restarted, disabled or deleted. Every command below is a later step for an owner or an authorised worker. None was run to produce this section.

Labels: measured = command output in the topology notes; config-evidenced = unit, script or file text; inferred = reasoned from those, not checked.

Part A. Coding-only host: relocation checklist

Moves and stays
ItemCurrent stateDecisionLabelNotes
producehits-app (uvicorn gateway, loopback 7860)Disabled; nothing listens on 7860MOVE (already absent here; live copy is on the gateway)measuredNothing to move. Remove the dependent nginx routes here.
producehits-scalerDisabledMOVE-CHECK: confirm exactly one active scaler remotely before any changemeasuredDocs place the only scaler on the gateway. Do not start a second one here.
producehits-workerDisabledSTAYS DISABLED (repo law: no worker on the API origin)measuredWorkers are auto-scaled Hetzner instances. None run here.
nginx routes for songchop.com and wwwProxy to 127.0.0.1:7860 (dead upstream)REMOVE after gate 1 (DNS confirmed to the gateway)config-evidencedOther product domains serve static coming-soon roots. Leave them unless the owner decides otherwise.
nginx route for api-originProxy to 127.0.0.1:7860 (dead upstream)REMOVE after gate 2 (gateway route verified from outside)config-evidencedSave the site file first (cutover C1).
nginx /screenfeed/ and /beat-bench/ routes/screenfeed/ targets 127.0.0.1:8899, which is not listeningOWNER DECISION: remove or keepmeasuredPort 8899 not listening at sample time.
producehits-backup (timer, nightly 03:30 UTC)Exit 0 at 03:34:54 UTC today; journal has no entries for the unit todayMOVE to the remote gateway, or STAY with a recorded decision. Do not disable without a replacementconfig-evidencedThe only off-GitHub backup in the config read. Run output unverified.
Local database dependenciesProduction DB is remote (46.224.109.170, per docs). A temporary Postgres lane runs on loopback 54329Production path: none local. Temporary lane: DISCARD after owner confirmsmeasuredThe temporary lane is not production. Its data directory sits in a temp folder.
cx-proxy and cx-claude-failoverEnabled and running (loopback 8327 and 8317)STAYmeasuredBreaking them breaks local CX model routing.
cx-console tunnel (cloudflared)Unit disabled; process running from a deleted binarySTAYmeasuredFour public hostnames route through it. The /mission route is already dead.
cx-sync timer (every 10 min)ActiveSTAYconfig-evidencedCross-machine credential sync. Not a product dependency.
Git worktrees301 entries in the worktree listSTAYmeasuredLifecycle is in Part B. Nothing is removed by this plan.
pi sessions and graphifyTooling state and knowledge graphSTAYconfig-evidencedProject graph is rebuilt by the owning tooling.
producehits-sync, go-live.sh, dev-sync.shNo unit or timer; manual scripts. Headers read, bodies not readSTAY (not moved). Do not runmeasuredgo-live.sh deploys the studio. Read its body before any use.

Dependency order (sequence, not executed)

  1. Gate 0: close topology questions T1 to T4 (table below) by written receipts.
  2. Gate 1: DNS for api-origin and songchop.com resolves to the one confirmed gateway address (check R1, run from outside this host).
  3. Gate 2: the gateway serves the API route to a check from outside (check R2).
  4. Gate 3: exactly one scaler process and one autopull timer on the gateway (checks R3, owner-run).
  5. Gate 4: a fresh remote backup exists and its run is logged (check R4, owner-run, not from this seat).
  6. Gate 5: rollback copies exist: nginx site files and the backup timer unit saved to a dated folder (cutover C1).
  7. Cutover C2 to C6 (below). Only after gates 0 to 5 pass in writing.
  8. Part B configuration (journald, logrotate, tmpfiles, observability) is independent of the cutover. Apply after gate 0 with owner approval.
Remote readiness checks to run later
CheckCommand (NOT RUN)Pass criterionRun by
R1dig +short api-origin.songchop.com, then dig +short songchop.com (run from outside this host)Both return the single confirmed gateway addressOwner or delivery worker
R2curl -s --proto-default https -o /dev/null -w '%{response_code}' api-origin.songchop.com/api/product-config (from outside)Returns 200Owner or delivery worker
R3On the gateway: systemctl is-active producehits-scaler; pgrep -fc 'shared/scaler.py'; systemctl list-timers --allScaler active; pgrep count 1; exactly one autopull timer listedOwner (gateway access)
R4On the backup target: list the newest dated folder. On the backup host: journalctl -u producehits-backup since todayDated folder from the last run; a journal entry for the runOwner (not from this seat)
R5On the gateway: grep -c '^DB_PRIVATE_HOST=' <gateway checkout>/.env (counts lines only; never print values)Count 1. Confirms the private DB host is set, not defaultedOwner (gateway access)
R6On this host: ss -ltnp | grep -c ':7860 ' ; nginx -t (after any edit)Count 0 before and after cutover; nginx -t passesWorker at cutover
R7On this host: systemctl is-enabled producehits-app producehits-scaler producehits-workerAll three report disabledWorker at cutover

Cutover steps (later)

  1. C1: copy the nginx site files and the backup timer unit to a dated folder (to be created). Gate 5.
  2. C2: remove the songchop.com, www and api-origin proxy blocks from the nginx site files. Keep the static roots. Run nginx -t.
  3. C3: reload nginx only after C2 passes nginx -t.
  4. C4: disable producehits-backup.timer only if the backup has moved, and only after the new host has completed one successful run.
  5. C5: run R6 and the public check from outside. Record the result in the cutover receipt.
  6. C6: write the disposition receipts for every item touched.

Rollback steps (prepared before cutover)

  1. RB1: restore the saved nginx site files, run nginx -t, then reload nginx.
  2. RB2: if C4 was applied, re-enable and start producehits-backup.timer.
  3. RB3: if DNS was changed by the owner, revert the records to the values recorded at gate 1. This plan takes no DNS action itself.
  4. RB4: remove the Part B drop-in files and restore the prior journald settings. The effect follows the next journald configuration load.
Shutdown impact
ServiceImpact if stopped or removedLabelSource note
producehits-app, producehits-scaler, producehits-workerNone here (no listener, disabled)measuredUnits disabled; port 7860 closed.
nginx (stop or reload)Static coming-soon sites and /screenfeed/ on this host stop answeringconfig-evidencedWhether those domains still resolve here was not checked.
nginx routes for songchop.com and api-originResponses change from the dead upstream to whatever the removal yieldsinferredNot verified with a public request.
cx-console tunnelFour public hostnames go darkconfig-evidencedThe /mission route already fails because 8899 is not listening (measured).
cx-proxy and cx-claude-failoverLocal CX model routing breaksinferredNot tested.
cx-sync timerCross-machine credential sync stopsconfig-evidencedTimer every 10 minutes.
producehits-backup timerNightly off-GitHub backup stopsconfig-evidencedToday run exit 0, journal empty (measured). Run contents unverified.
Temporary Postgres lane (loopback 54329)Temporary test data stopsmeasuredNot production. Discard only after owner confirmation.
certbot (failing since 2026-10-14)Not changed by this planconfig-evidencedSeparate task. Listed so it is not mixed into the cutover.

Unresolved topology questions blocking the plan

Topology questions
#QuestionWhat the docs sayWhat was measuredBlocks
T1Which gateway host is current?Repo law and CLAUDE.md name 138.201.247.255 as the API origin. The infrastructure reference names 49.12.12.91 as the live gateway and scaler. The 2026-10-15 deletion audit says the older box is deleted.Nothing listens on 7860 here. The gateway address was not checked from this host.Gate 1, every nginx route change
T2What are the DB host defaults?Production DB 46.224.109.170 is consistent across docs. Private 10.88.0.20 is the default when a network id is set. 188.245.228.253 is the fallback default in scaler code and three deploy scripts. No doc names it as a current host.No environment dump was taken. Whether a running environment uses 188.245.228.253 is unknown.Any move of the scaler or workers; the local-DB answer
T3Is this host in the documented topology?The migration audit names this coding host as the migration target (cutover 2026-10-13). The topology docs do not list it as a role.Hostname measured. Role inferred as coding and CX host.Host-role decisions in Part A; which backup stays
T4Did the backup run and what did it upload?Timer config keeps 14 dated folders. Unit exit 0 at 03:34:54 UTC today.Journal has no entries for the unit today (journal not short of space). Upload unverified.Gate 4 and the backup move

Part B. Bounded lifecycle: coding host

Coding host lifecycle
CategoryExecutable owner (unit or script)Limit / quotaTTLSuccess cleanupFailure cleanupStartup cleanup
Scratchafcut-host-cleanup.sh (existing; top level of /tmp only, older than 2 days). producehits-tmp-sweep (existing; thresholds not read, unverified). producehits-host-guard prune_tmp_caches (existing; its call sites are commented out, so activity unverified). New dedicated scratch folder: to be created2 GiB cap on the dedicated scratch folder (proposed, to be created)2 days (proposed; matches the existing /tmp rule)Each job deletes its own scratch subfolder on exit (to be created, same trap pattern as the backup script)Failed-job folders kept for the TTL for diagnosis, then removed by the tmpfiles age rule (to be created)systemd-tmpfiles-clean.timer (existing; daily at 13:51 UTC, measured). No /tmp age rule exists
Logssystemd-journald with a single drop-in (to be created; two conflicting caps exist today, 200M and 500M, effective 500M inferred). logrotate.timer for file logs (existing). afcut-host-cleanup vacuum (existing; 200M)SystemMaxUse 200M; SystemMaxFileSize 50M; SystemKeepFree 2G (proposed)MaxRetentionSec: 2week (existing in the 200M cap drop-in)Not applicableJournal vacuum under pressure. Align the afcut-host-cleanup vacuum target to 200M so the two agreejournald applies its caps on start. Writer of the disk-free log file is unknown: Parked
Cachesafcut-host-cleanup.sh (existing; apt-get clean). producehits-host-guard reclaim_disk (existing; conditional; disk threshold unverified; covers uv, copilot, npm and node-gyp caches). cx-sync (temporary files only). Per-cache cap: to be created2 GiB per cache (proposed). Current sizes of the caches not measured14 days idle (proposed; no existing rule)Nonereclaim_disk on disk pressure (existing; threshold unverified)None
Workspaces and worktreesproducehits-session-autosave prune.sh (existing; the only automatic remover; manual agent deletions also occurred on the audit day, see Cleanup forensic verdict). It removes a worktree only when it sits under the session folder, is clean, has no unlanded commits against the land or live branch, has been idle at least SESSION_PRUNE_IDLE_HOURS (default 24), and has no process whose working directory is inside itNo count-based deletion. 301 entries measured; report-only candidate list (below)24 hours idle (existing guard default; configured value unverified)prune.sh only, after the guard passes. Its owner must dispose each family firstNo automatic cleanup. Dirty or unlanded worktrees go to dispositions (Parked by default)None

Part B. Bounded lifecycle: future service VPS

Service VPS lifecycle
CategoryExecutable owner (unit or script)Limit / quotaTTLSuccess cleanupFailure cleanupStartup cleanup
ScratchTo be created. The app has a temp-folder setting (name only); no unit or script cleanup was measured for it on the service host2 GiB cap (proposed)2 days (proposed)Each job deletes its own subfolder on exit (to be created)Failed folders kept for the TTL, then removed by the tmpfiles age rule (to be created)systemd-tmpfiles-clean.timer, if present on the service image (unverified)
Logssystemd-journald drop-in (to be created; no cap found in the config read). producehits-app journal output (existing unit; memory-guard drop-in in config). Scaler and autopull logs in journaldSystemMaxUse 1G; SystemMaxFileSize 100M; SystemKeepFree 2G (proposed; the disk size of the service host is not measured)MaxRetentionSec: 2week (proposed)Not applicableJournal vacuum under pressure (to be created)journald applies its caps on start
CachesTo be created. No cache owner was measured on the service host2 GiB per cache (proposed)14 days idle (proposed)NonePressure-driven clean-up (to be created)None
Workspaces and working filesTo be created. The service host should hold no git worktrees (proposal). Any working audio files follow the storage routing law and are owned by the appTo be created (no measured size)To be createdOwned by the app; cleanup after the job reaches its final state (to be created)Failed jobs kept for the TTL, then removed (to be created)None
Backup stagingproducehits-backup (existing; local staging removed by its exit trap). Remote dated folders kept at 14 by the script (existing)Local staging: one run onlyRemote: 14 dated folders (existing)Local staging removed by the trapLocal staging removed by the trapNone. Remote storage is not counted as local retention

Remote storage (backup box, object storage) is not retention without ownership, limits, TTL and cleanup. It is not counted as capacity for any category above.

Settings for journald, logrotate, tmpfiles and caches

Proposed numbers
SettingCoding hostService VPSBasis
journald cap (SystemMaxUse)Single drop-in at 200M. Remove the 500M size-cap drop-in so one value wins1G (proposed)Two conflicting drop-ins measured on the coding host; service host cap not found
journald file size (SystemMaxFileSize)50M (existing value)100M (proposed)Existing coding-host drop-in
journald free space (SystemKeepFree)2G (existing in size-cap drop-in)2G (proposed)Existing coding-host drop-in
journald retention (MaxRetentionSec: 2week)2week (existing)2week (proposed)Existing coding-host drop-in
logrotate, file logsweekly, rotate 4 (default config, measured); cx-proxy size 25M, rotate 3 (existing)weekly, maxsize 25M, rotate 4, compress (proposed)logrotate caps by count only, so pair the count with maxsize
tmpfiles scratch ruleDedicated folder with age rule: e /var/tmp/producehits-scratch 0750 root root 2d (to be created)Same line, owned by the service user (to be created)No age-delete rule exists for /tmp or /var/tmp today; do not add one for all of /tmp
Cache TTL ruleAge rule for each cache folder at 14 days (to be created)Same (to be created)No cache age rule exists today

Observability

Observability
MetricThreshold and cadenceAlert levelOwner
Filesystem free space (df)Check every 15 minutes. Alert on used percentage: warn 80%, alert 90%, critical 95%warn, alert, critical as statedOwner to be created
Inode use (df -i)Check every 15 minutes. Warn 80%, alert 90%, critical 95%. Current inode use not measuredwarn, alert, critical as statedOwner to be created
du snapshotDaily at 04:45 UTC on both hosts, and before and after any cleanupReport onlyOwner to be created
Per-category byte metricsDaily, from the du snapshot: scratch, journal, file logs, caches, worktrees, pi sessions, backup stagingReport only; alert if a category grows 50% in a day (proposed)Owner to be created
Report-only candidate listWeekly. Lists worktrees and folders that meet the existing guard criteria or exceed 1 GiB and are older than 7 days. Deletes nothingReport onlyOwner to be created

Worktree rule

No automatic worktree deletion. Candidates are report-only. The existing prune.sh guard (idle at least 24 hours, clean, landed, no process inside) is the only automatic remover. Manual agent deletions on the audit day (Claude session ~14:17–14:56Z, under broad owner authorization, with no pre-deletion backup for non-cache items) also removed data outside prune.sh. Each family needs an owner disposition before it is relied on.

Dispositions for dirty or unfinished work

Dispositions: Ready, Continue, Salvage, Parked, Superseded. Receipts go under docs/work-dispositions/. This checkout has a top-level work-dispositions/ folder and no docs/ folder, so the receipt location must be reconciled. Nothing below is Ready.

Dispositions
ItemEvidenceDispositionReceiptNext outcome and owner
Installed checkout: 8 uncommitted entries; HEAD differs from the session HEAD (measured)Not inspectedParkeddocs/work-dispositions/<item-id>.md (to be created)No owner assigned. The next outcome is a classification pass by an assigned owner
Four shared/ files differ between session and installed copies (measured)Audio source, a user-images migration, routes, worker daemonParkedTo be createdDo not adopt. Routes and the worker daemon are high-risk files
Topology docs disagree on gateway and deleted host (T1, T3)Docs stale per the 2026-10-15 auditContinueTo be createdOne owner confirms the gateway address through R1 and R2, then edits the docs. Owner not yet assigned
Backup run evidence (T4)Empty journal; no upload checkContinueTo be createdRead-only check by the owner (R4). Blocks the backup move
Lane crew-frontier family worktree: 28 uncommitted entries (measured, worktree-sizing.md)lane/crew-frontier-ca5dc309 holds uncommitted work; no owner classification yetParked, preservedTo be createdNever prune or relocate until an owner classifies. No owner assigned
Session 20261017-071650-cx worktree: 130 uncommitted entries (measured, worktree-sizing.md)session/20261017-071650-cx holds a large uncommitted set; no owner classification yetParked, preservedTo be createdNever prune or relocate until an owner classifies. No owner assigned
Disk-free log file writerNo writer found in the searched pathsParkedTo be createdPreserve as is. Do not delete the file
Temporary Postgres lane (loopback 54329)Temporary data; not productionParkedTo be createdDiscard only after owner confirmation
Session worktrees (301 entries)Each entry needs its own dispositionParked by defaultOne receipt per candidateSuperseded only with a replacement recorded. Nothing is deleted by this plan
producehits-sync, go-live.sh and dev-sync.shHeaders read; bodies not readParkedTo be createdRead the bodies before any use. go-live.sh deploys the studio
Presumed-lost derived datasets from the key-corpus scratch directory (derived-round8 and wav; no copy found; owner copy unknown)Manual agent deletions on the audit day (Claude session ~14:17–14:56Z); no pre-deletion backup for non-cache itemsParkedPreserved evidence; no receipt createdPreserved evidence. No recovery attempted. Owner copy unknown; no owner assigned
The scratch-service workload on port 18765 stopped during cleanup (no auto-restart; owner of that app unchecked)Stopped during the audit-day cleanup session (~14:17–14:56Z)ParkedTo be createdOwner of the app unchecked. No restart attempted; no owner assigned

Not verified in this plan

Cleanup forensic verdict: what was deleted on the audit day

Scope: deletions ran during an emergency clearing on the audit day, between about 14:17Z and 14:56Z. The audit snapshot was taken during that window. Evidence tiers: confirmed regenerable; preserved-recovery-path (unexercised); concrete breakage; not verifiable. Observed impact and causal inference are kept separate.

What was deleted, and the evidence for each removal

Audit-day cleanup removals and their evidence
DeletionStatusEvidence tierObserved impact (vs causal inference)Recovery options (none executed)
Lane virtual environment (6.2 GB)Runconfirmed regenerableAbsent at 16:00Z. No unit, env file or script references it. No requirements file was captured before deletion, so the exact package set is unknown.Rebuild from the lane requirements if they exist; otherwise re-resolve. Pins unverified.
Key-corpus scratch: genre, full-audio and raw sub-directories (3.4 GB)Runpreserved-recovery-path (unexercised)Absent at 16:00Z. A committed-manifest restore script can rebuild these from recorded sources and hashes, and fails closed if anything is missing. Not run by this report.Run the restore in a scratch location after confirming the manifests and fixtures are present (presence unverified).
Key-corpus scratch: derived round-8 outputs and wav set (about 1.7 GB)Runnot verifiableNo directory with that name under the searched roots at 16:00Z. No copy found. No recovery script covers derived outputs. Presumed lost.Ask the data owner whether a copy exists. If none, regeneration from the source pipeline is needed (pipeline not checked).
Scratch service virtual environment (6.2 GB) and the local service it servedRun; service process stoppedconcrete breakageNo listener on the scratch port at 16:00Z; the scratch directory is empty. No unit restarts it. The app owner was not checked. The venv itself is regenerable.Identify the owner first. Rebuild the venv and restart only with owner confirmation.
Sync package virtual environment (6.2 GB)Runconfirmed regenerableAbsent at 16:00Z. Cache-class path with no references found.Recreated on the next install.
Pip and uv temporary directories and caches (about 6 GB)Runconfirmed regenerableAbsent at 16:00Z. Re-downloaded on the next install. Home cache directory now 0.94 GB.Automatic on the next install.
Five test-output cache directories (about 370 MB)Runconfirmed regenerableAll absent at 16:00Z. Re-emitted by the next test run.Re-run the tests.
npm, pip and model caches; old editor server installsRunconfirmed regenerableCache class. Not re-probed at 16:00Z; the record of the removal is the only evidence.Re-downloaded or reinstalled on demand.
One removal callDenied by the built-in safety checknot applicableThe target is not named in the record. The call removed nothing.None needed. Record the refused target if it is identified.
Systemd journal vacuumed to 100 MBRunnot verifiableJournal history before the vacuum is gone and cannot be checked. Journal size caps were added separately.None for the removed history. Keep the caps.
Proxy log and system log truncatedRunnot verifiablePrior contents cannot be recovered or checked. Logrotate and journald caps were added.None for the prior content.
Consequence: the key-corpus restore script default input rootsNot a removal; the defaults now dangleconcrete breakageThe default roots point at the removed directories. Without environment overrides the script exits non-zero. Confirmed by grep of the script; the script was not run.Restore the corpus, or set the input-root overrides to its new location. Editing the script is an owner change.

Did we mess up?

Partly, yes. Most of what was removed was regenerable cache and virtual-environment material, and that class can be restored by reinstalling. The real losses are different. The derived round-8 outputs and wav set (about 1.7 GB) appear gone with no copy found. The scratch service was stopped without checking its owner and is down. The key-corpus restore script now points at directories that no longer exist. Journal history and log content before the trims cannot be recovered. The removals were agent-chosen. For non-cache items there was no pre-deletion backup or bundle, and no per-path byte counts were taken first. The "about 24 GB free" figure in the cleanup record matches no measurement. Measured available space was 4.1 GiB at 14:56Z and 16.11 GiB at 16:00Z, and it is falling again. The freed-space gain cannot be attributed to named deletions. The producehits-app failure at 13:19Z predates the cleanup and is not attributed to it.

Snapshot against the later probes

Figures from different metrics and times are shown side by side for context. They are not a before-and-after comparison of any single deletion.

Audit snapshot compared with later probes
MeasureAudit snapshot (14:27-14:40Z, mid-cleanup)Later probes (16:00Z unless stated)Comparable?
Available space (df)0 bytes4.1 GiB at 14:56Z; 16.11 GiB at 16:00Z; down 245.2 MiB since about 15:19ZSame metric; different times. Not attributed to any deletion.
Used space (df)149.65 GiB (byte-derived)127.6 GiBSame metric; different times.
Allocated, dedup148.43 GiB (inventory v2)Not re-measuredDifferent metric from df used. Do not subtract one from the other.
Deleted-open7 inodes, 1.9 MB124 lsof rows, 74.8 MiBDifferent counting method. Shown as a later probe only.
Git worktrees301 (14:39Z)302Not a deletion effect; no worktrees were removed.
Sessions directoryNot recorded55 entriesNo baseline.
Listed deleted pathsNot checked11 of 11 absentPresence check only; no byte counts.
Failed systemd unitsproducehits-app failed at 13:19Z (before the cleanup window)3 failed; producehits-app namedThe failure predates the cleanup and is not attributed to it.

Limits

Not done by this report

No cleanup, restore or migration performed by this report. No deletion, service start or restart, credential change or file restore was made. The later-probe figures are read-only observations.

Update: causes, cleanup accounting and preventive changes (evening 2026-10-19)

Current correction: 2026-10-20 recovery and enforcement

The historical audit below is preserved, not a live dashboard. At 13:30 UTC the development disk was again 96% used. About 240 crew checkout directories occupied 52,466 MiB. The replacement services host was only 4% used: moving scheduled services did not move or bound agent checkouts.

Recovery removed 206 clean inactive checkout copies with remotely preserved commits and no ignored files, retaining their branches. Dirty, active, held, parked and unarchived work was preserved. Disk use fell to 64%, with about 53 GB available. Package cache reclaim was separate. This is a current measured recovery, not validation of the older inferred reclaim totals.

Permanent enforcement is now active on the development host: new lane creation invokes retention and admission under the creation lock; default maximum 120 claimed checkout directories and minimum 20 GiB free. A separate installed timer runs safe retention every 15 minutes with a 6-hour age. No session or pane is killed. Ignored files block removal and all safety gates are checked again immediately before removal. Source commit 069ed9d6 is backed up; actual local dispatch uses this source. Fleet publication is pending unrelated intentional edits in the authoritative checkout, not silently claimed complete.

The services-host scheduled backup did fire at 03:53:18 UTC with exit status 0. Both daily analytics jobs have successful target-side output. Weekly search jobs are not yet due. The development backup timer remains disabled. Pack migration completed: 476 directories checked, 409 remotely verified and evicted, zero errors or missing uploads. The 67 differing-manifest directories remain preserved, with no overwrite. Local packs fell to 561 MiB and root ended at 62% used, about 56 GB available.

Added after the audit: an evening update (samples at 22:52Z, 22:59Z and 23:05Z, 2026-10-19). It does not replace or edit any audit-snapshot figure above. Read-only; this report performs no cleanup.

Causes of continued growth, from paired measurements

Used space rose about 1.25 GB in the 7 minutes between samples A and B and about 0.36 GB in the 6 minutes between B and C. Disk was 87% used with about 19.9 GB free at the last sample. Ranked growers:

Growers between paired samples
GrowerWhat was seenConfidenceOwner or note
Lane and crew git worktreesEach new checkout is about 223 MB (docs about 91 MB, models about 34 MB, annotations about 33 MB, plus static assets). 4 were created between samples A and B and 1 between B and C. 191 directories now total about 42.5 GB.measuredCreated by the agent lane spawner in the CX toolkit, not by the web application.
One-shot archive and rebuild bundlesAbout 395 MB appeared in an archive directory (two bundles of 195 MB and 209 MB) and a matching 395 MB rebuild scratch directory, written once at about 22:59Z and static afterwards.measuredOne-off by a current session; not a recurring grower.
Primary repository pack rewriteA 108 MB pack file was rewritten between 22:50Z and 22:59Z (garbage collection or repack).measuredRewrite, not net growth.
Mission databaseAbout 160 MB, growing about 1 MB per 5 minutes with an active write-ahead log.measuredSlow and steady.
Small new directories in the windowThree tool-cache directories of 84-90 MB each.measuredNot tracked further.

Not growing in the window

Checked and flat
ItemResultConfidence
AI agent session logsNot the hot grower in this window.measured
Generated pack directories (476)4.96 GB, no change across the samples.measured
System journal40 MB.measured
User uploads4 KB.measured
Backups directory4 MB.measured
Deleted-but-open files over 50 MBNone found.measured

Reading: the audit-day pressure came from many large worktrees. In this window the dominant growth is still new worktrees, not session logs, packs, uploads or the journal. Three samples over about 13 minutes are a short window, not a trend.

Cleanup accounting since the audit

Cleanup accounting
ItemAmountConfidence
Cleanup already reported on the audit day12.3 GiBexecutor-reported
Merged worktrees removed after the audit284executor-reported
Net space reclaimed since the audit by those removalsabout 36 GB (range 36-45 GB)inferred
Available space16.11 GiB at 16:00Z; about 19.9 GiB at 23:05Zmeasured

The 36-45 GB reclaim figure is an inference from free space moving from 16 GiB at 16:00Z while new worktrees kept arriving. There is no byte receipt for it and it is not added to the 12.3 GiB figure as a measurement. The two amounts are separate and not summed here.

Permanent preventive changes: honest status

Preventive changes by disposition
ChangeStatusEvidence and limit
Worktree count cap and age-based cleanup in the CX toolkitpendingNo landed commit found. The only retention work located is an incomplete checkpoint branch for cold session homes, marked not approved to land. A cap and TTL for lane worktrees was not found in the toolkit history.
Cold-session archiver to the archival storage boxin progressIncomplete checkpoint on a non-deployment branch (classifier, verified archive and eviction tool, offline tests). Its own receipt says not approved to land; known conflicts are open. Nothing is installed or running from it.
Bounded scratch with a time-based sweeper (temporary files)landedA 5-minute temporary-file sweeper timer is on the main branch and was observed active on this host. This covers the host temporary directory only.
Upload sweeper: signed-in reclaim, bounded costlandedOn the main branch (commit present in the remote main history). Whether it is deployed on the gateway was not checked.
Pack cold-mirror fix: non-destructive publish, exact-size reclaim gate, bounded retry, packs to archival storagelandedSource and tests are on the main branch; the disposition receipt reads Ready with a 29 of 29 gate. Gateway deployment and a production run were not verified here.
Webapp scratch directories bounded with a TTL sweeper (all of them)pendingNo dedicated source-fix branch was found. Generated pack directories still have no local reaper per the dependency section.
Services host owns scheduled jobs and backupin progressDocumentation on the main branch records the services-host backup timer enabled and active, with its first run due 2026-10-20 03:53Z; the service had never run when documented. The move of some duties is documented as partial.
Development host backup timer disabledobserved onlyThe unit file state was read as disabled on this host at 23:08Z. The timer was documented as live earlier the same day, and no landed commit recording the disable was found. Who disabled it, and why, is unverified.

Status words follow the work-disposition receipts and the main branch history. Landed means present in the remote main history, not deployed or proven in production.

Verified

Not verified

Duplication and overlap

Hardlink duplicates are excluded from the allocated total. The rollups below overlap each other and the inventory parts. Do not add them up or to the allocated total.

Hardlink duplicates (excluded)
Hardlink measureValueConfidence
Hardlink duplicate excluded (measurements, v2)2.38 GiBmeasured
Hardlink duplicate (allocated_vs_apparent)2.38 GiBinferred
Overlapping rollups, not additive
RollupGiBFilesAdditive
lane-worktree-group46.92 GiB922503overlapping, not additive
tooling-group35.41 GiB7692overlapping, not additive
venv-group22.52 GiB234289overlapping, not additive
session-checkout-group12.63 GiB378764overlapping, not additive
swap-group12.00 GiB2overlapping, not additive
cache-group7.55 GiB84213overlapping, not additive
audio-group7.44 GiB3385overlapping, not additive
node_modules-group7.29 GiB256941overlapping, not additive
git-group1.81 GiB40654overlapping, not additive
pycache-group1.48 GiB69279overlapping, not additive
logs-group0.45 GiB7364overlapping, not additive

Limits of this evidence

These limits apply to every figure in this report. Read them before acting on any number.

  1. residual 1.22 GiB (df used minus allocated dedup) is unattributed
  2. worktree counts unreconciled; lane groups are candidates only
  3. executor group labels not verified against workload
  4. unit states observed in executor logs only
  5. root-checkout parity with installed units unverified
  6. fill tmpfs origin not inspected
  7. DB worker rows and billing not checked
  8. gateway-down cause not established
  9. top-30 leaf names intentionally withheld
  10. point-in-time snapshot with concurrent writers
  11. v1 figures superseded by v2: v1 listed 26 lane categories and left 45.87 GiB uncategorised due to truncation; df used is byte-derived 149.65 GiB, not 149.63
  12. allocated vs apparent difference attributed to block rounding and sparse files is inferred, not measured
  13. extension is a filename property, not a content type
  14. independent review pending
  15. models claimed cxproxy/claude-haiku-5-5 unverified
  16. mtime month map sums to 148.36 GiB vs 148.43 GiB dedup allocated: 0.07 GiB difference unexplained, likely two-decimal rounding of ~300 near-zero buckets (unverified)
  17. durable copy limitation: at the audit snapshot (~14:27-14:40Z) the root filesystem was full with 0 bytes available and the Pages deployment plus /tmp artifacts are the only copies; /tmp is volatile. The 16:00Z probe showed 16.11 GiB available, so this is time-scoped, not current
  18. update section: 284 merged-worktree removals and the 36-45 GB reclaim are executor-reported or inferred; no byte receipt
  19. update section: preventive-change status is from commit and receipt inspection only; deployment and production behaviour not verified
  20. update section: three paired samples over about 13 minutes are not a growth trend
  21. Exposure (measured, session grep output): a session-level grep printed literal database credentials from a team-access runbook. Values are not repeated in this report. Owner decision required; no credential changes were made by this report.
  22. Deletions occurred during and after the snapshot window (Claude session approx. 14:17-14:56Z), so the audit snapshot (14:27-14:40Z) does not describe the post-cleanup disk state.
  23. No per-path pre-delete byte counts were captured, so the amount freed by each deletion is not measured.
  24. The audit allocated-size figure and the later df-used figure are different metrics at different times; delta attribution of df-used change to the deletions is not established.
  25. One generated dataset (derived round data and wav files) is unrecovered and presumed lost.
  26. The cleanup record claim of about 24 GB free matches no measurement. The audit snapshot shows df avail 0 B; the post-cleanup probe shows df avail 17,303,072,768 B (about 17.3 GB). Free-space figures from the df free column and the avail column are not interchangeable.

Independent review

Review status: independent review pending. This report has not been independently reviewed. Treat every figure as provisional until that review is recorded.

Claims flagged unverified or inferred

Sources