Grepping in the wrong system
Friday, May 8th, end of session. I want to activate Vercel's Ignored Build Step to stop burning a build credit on every docs-only push. I grep vercel.json at the repo root. Nothing. I conclude no config exists and fire an updateProject with my target value. The next push goes through normally. Three days later, while answering a methodology question about commandForIgnoringBuildStep, I stumble on the previous value. It existed. It lived on the Vercel side, not in the repo. My update had just removed .claude/ from its whitelist, with no diff, no alert, no trace.
Two regimes, one reflex
Part of your production config lives in the repo. It's versioned, its history is readable in git log, a bad merge is reversible with a revert. The other part lives on the platform side. It's stored at the vendor, mutable by API or Console, and your git diff doesn't see it. Neither regime is flagged in the code you're reading — you have to know, a priori, where each setting lives.
The map is familiar once named. Vercel: commandForIgnoringBuildStep, environment variables, project-level redirects. Supabase: RLS policies, custom claims, SECURITY DEFINER Auth hooks. Stripe: webhook destinations, restricted keys, OAuth Connect settings. GitHub: branch protection rules, repository secrets, rulesets. None of these settings has a versioned equivalent in the repo that consumes them.
The trap isn't the asymmetry, it's the reflex. You grep the repo, you find nothing, you conclude absent — when the rule exists elsewhere, in silence, and your next update is about to overwrite it without a diff.
Thirty seconds, four commands
# Audit before any updateProject / updateConfig SaaS — 30 seconds
# 1. Read the full current config (e.g. vercel projects get)
CURRENT=$( $PLATFORM_CLI projects get --json )
# 2. Compare to the target
diff <(echo "$CURRENT" | jq .config) target-config.json
# 3. List regressing fields (present before, absent after)
jq -n --argjson c "$CURRENT" --slurpfile t target-config.json \
'($c.config | keys) - ($t[0] | keys)'
# 4. Explicit confirmation before PATCH
read -p "Accept the regressions listed above? (y/N) " ok && [ "$ok" = "y" ] && \
$PLATFORM_CLI projects update --config @target-config.json
The cost is fixed: thirty seconds. The benefit is binary — either your target completes the existing config (and you push), or it regresses a field (and you reformulate before pushing). No grey zone. It's the equivalent of a git diff on what git doesn't index.
The rule, in one foreign sentence
My CLAUDE.md carries a line I had read a hundred times without feeling it land, until May 8th.
Investigate before deleting or overwriting, as it may represent the user's in-progress work.
Vercel, Supabase, Stripe, GitHub: the same rule, written for an AI agent, applies to the human hand on the Console.
What you can't see hasn't disappeared.
Protocol audit-protocol.sh and two concrete instances (Vercel Ignored Build Step, Supabase RLS / Auth hooks), pseudonymized:
github.com/michelfaure/rembrandt-samples/tree/main/saas-config-platform-vs-repo
Top comments (0)