Local is a dependency
Sixty scripts hardcoded one local folder. It worked for years — until an unattended job could write to it but not read it, and failed silently every day. Migrating away from local isn't a cleanup. It's removing the most invisible coupling there is.
The weakness
A fleet of scheduled jobs on one Mac wrote everything — reports, caches,
browser drops, even a couple of secrets — into a single folder: ~/Downloads.
Around sixty scripts hardcoded Path.home() / "Downloads" directly.
Nobody decided this; it accreted. The folder did three unrelated jobs at once, and
no code owned the convention, so it could never be moved.
Then one job went red. A daily hygiene check that cross-references a corpus of
audit files began reporting it could not enumerate the directory. The cause
wasn't the code. macOS protects ~/Downloads under its privacy layer
(TCC), and a background launchd process without Full-Disk-Access can
still write a file there — but the moment it tries to
list the folder, the read is denied.
Writes succeeded. Reads were denied. So every job that globbed that folder got back an empty list instead of an error — and carried on. The reports still wrote. The dashboard still went green. The cross-checks were just quietly running against nothing. Same signature as field note № 1: stale-green is the failure that compounds, because it looks exactly like success until the day you need the thing it was supposed to be checking.
The wrong fix (the one the OS invites)
The obvious fix is to make the dependency cooperate: grant each LaunchAgent Full-Disk-Access so it can read the protected folder. It even works — for a while. But it's the same trap as hardening a flaky vendor:
- It's per-agent and invisible. Forty-one jobs, each a manual grant in a system pane no version control can see. A new job is born broken until someone remembers.
- It silently revokes. A routine
brew upgradere-signs the Python binary, and macOS treats the re-signed binary as a stranger — the grant evaporates, and the fleet quietly returns to stale-green. - It deepens the coupling. You've now bound the entire fleet's correctness to a hand-maintained OS permission on one specific protected path. You made the weak thing load-bearing.
Granting access accepts the framing that the folder is the problem. The folder was never the problem.
The coupling wasn't ~/Downloads. It was that sixty scripts each believed, privately, that a specific local path would always be there and always be readable. Local was an un-provisioned, un-restorable dependency threaded through the whole fleet.
The reframe
This Mac is a single point of failure. The real requirement isn't "make the folder readable" — it's "when this machine dies, a new one restores cleanly." Under that lens, a hardcoded local path is not a convenience; it's a dependency you can neither see, version, nor reproduce. The job isn't to fix a permission. It's to turn the machine's layout into a contract — something a fresh machine can rebuild on purpose.
The removal
Four moves, each taking the coupling out rather than bracing it:
- One module owns the convention. A single contract module exposes the directory taxonomy — outbox, inbox, cache, config — as named constants. Sixty scripts stop hardcoding a path and import the contract instead. The convention now lives in one place, so it can finally move atomically.
- Back-compat by construction, so adoption is risk-free. With the environment unset, every constant resolves to exactly today's path. Importing the contract changes nothing until you choose to flip it. The migration carries zero behavioural risk right up to the last step, and rolls back by unsetting one variable.
- Inject the new layout once, fleet-wide. A single login agent promotes the new paths into the environment every job inherits — so forty-one jobs relocate with zero per-job edits. The same born-isolated trick the secret-handling used: re-assert the floor at login instead of patching each unit.
- Provision it on a fresh machine. The setup script creates the tree, with correct permissions, and drops a
RECAPTUREnote in each directory explaining how it refills. The layout is no longer an accident of history; it's a thing a new Mac builds from source.
The proof — and what verifying it surfaced
Removing a coupling only counts if you prove the system is stronger, not just rearranged. Two things earned that confidence — one expected, one not.
The unexpected proof came from a near-miss. A first, partial relocation moved one job's output but not a sibling script that independently hardcoded the old path — and a previously-green check went red. That's the whole argument for lockstep migration plus a verification gate: you move every producer and consumer of a path together, then run the real fleet and prove zero silent failures before you trust it. The regression wasn't a setback; it was the system telling the truth about a hidden coupling, cheaply, before it mattered.
Auditing the fleet to migrate it also revealed couplings the path-grep alone missed: a cluster of dashboard scripts that quietly exchanged data through the shared local folder, so they had to move as one atomic unit or break each other; and seventeen scripts carrying a stale path reference left over from an earlier home, working only by accident. You don't find those by assuming a uniform sweep. You find them by looking — which is the same discipline as measuring throughput instead of guessing it.
The principle, generalised
This was one folder on one Mac, but the moves aren't about folders:
- "Local" is the most invisible dependency you have. It never appears in a requirements file, never versions, never announces itself — until a fresh machine, an OS update, or a permission boundary reveals that half your system silently assumed it.
- Make conventions explicit and singular. A convention scattered across sixty files can't be changed, audited, or restored. One module that owns it can do all three.
- Migrate behind back-compat. A change that's a no-op until you flip it, and a one-variable rollback after, lets you move a whole fleet without a leap of faith.
- Lockstep, then verify under the real runtime. Move every producer and consumer together; prove it on the actual schedule, not in a console. Partial migration manufactures stale-green.
- Measure a machine by how cleanly it could be rebuilt. If the answer is "it couldn't, really," the machine is fragile no matter how reliable it feels today.
Migrating away from local isn't housekeeping. It's converting an accident — a path everyone assumed and no one owned — into a contract a new machine can honour. The folder still exists. It just stopped being load-bearing.
gf.cx filesystem-contract migration ·
imports assets.gf.cx favicon + card primitives