Files
freno-dev/docs/deploy-source.md
agent-cto df788cb689 docs(deploy): one canonical repo, a mirror to Vercel, and a read-only probe (FRE-1695)
Records the measured divergence, the decision (Gitea canonical, GitHub
mikefreno/freno-dev as the push mirror Vercel builds), why Vercel cannot
build from Gitea and why agents cannot write to GitHub, and the one-time
operator runbook.

scripts/verify-deploy.sh proves the path with no credentials: both remotes'
master SHA, the two live copy strings that only coexist on the reconciled
line, /terms, and the FRE-371 ancestry. Against today's live site it fails
exactly where it should: GitHub master 4e412ede != Gitea a8ce226b, /agents
still serves the pre-FRE-997 title, /terms is 404.
2026-11-09 20:46:59 +00:00

6.0 KiB

The deploy line (FRE-1695)

Written 2026-11-09 by the CTO. Supersedes the implicit assumption in every earlier freno-dev landing report that "merged on Gitea" meant "live".

The defect

Production freno.me and its subdomains are built by Vercel from GitHub mikefreno/freno-dev. Agents merge into Gitea Mike/freno-dev. The two masters diverged at merge-base dd368d2:

Line Head at filing Ahead of merge-base
Gitea Mike/freno-dev master a8ce226b (2026-11-09 16:16Z) 12 commits — FRE-371, FRE-366, FRE-202, FRE-997, FRE-1670
GitHub mikefreno/freno-dev master 4e412ede (2026-11-09 15:40Z) 2 commits — NOOK-1037, NOOK-1038

Every Gitea merge since dd368d2 was undeployed, including the FRE-371 client-IP fix and the whole Nessa /terms page. Measured on the live site at 2026-11-09T20:46Z: /nook/agents served Agent coverage (the GitHub line's title) and /terms returned 404 (the Gitea line's page). No agent run can push to GitHub — /paperclip/.git-credentials holds git.freno.me entries only — so the divergence could not be closed from the agent side.

Decision

Gitea Mike/freno-dev is the canonical repository. GitHub mikefreno/freno-dev is a mirror, and it is the tree Vercel builds.

One line, one direction: Gitea master → GitHub master → Vercel → live.

Why this shape and not the alternatives

  • Vercel cannot build from Gitea. Vercel's git integrations are GitHub, GitLab and Bitbucket; a Gitea host is not a supported provider. So "point Vercel at the repo agents push to" is not a setting that exists. Even with a Gitea-hosted mirror on GitLab, the deploy repo would still be a mirror.
  • Agents can only push to Gitea. The per-agent credential is Gitea-only (git.freno.me), and every review/CI path the company runs — the PR relay (FRE-653, FRE-1680), the --checks sweep (FRE-1364), the verdict rows — is Gitea-shaped. Making GitHub canonical would mean re-issuing GitHub credentials to every agent and rewiring all of that. Keeping Gitea canonical keeps the authoring side exactly as it is.
  • Deploying from CI instead of a mirror (Gitea Actions → vercel --prod) is the third option and it is worse: freno-dev has no workflow files today, Gitea Actions cannot run in this installation (FRE-1267), and it would need a Vercel token on a runner. A mirror needs one credential, in one place, and no new CI.

Reconcile first, then mirror

The mirror must fast-forward. The two GitHub-only commits are sponsor-authored landing work that is live today (NOOK-1037 refresh, NOOK-1038 scoped-remote restore); they cannot be dropped. So the GitHub line is merged into Gitea master first:

git merge gh/master        # merge commit, no history rewrite

After that merge, GitHub master is an ancestor of Gitea master, and a plain git push (no --force) is a fast-forward. The mirror is configured without force-push so that any GitHub-side drift fails loudly instead of being silently overwritten.

Two conflicts were resolved in the merge, both copy contracts:

  1. src/components/nook/FeatureBreakdowns.tsx — took NOOK-1038's refreshed island bullets and kept FRE-997's 18 agents bullet (the roster on /agents lists all eighteen; agents.test.ts asserts equality).
  2. src/routes/nook/remote-claims.test.ts — one file holding both contracts. NOOK-1038 (2026-11-09, Mike's correction) supersedes FRE-323's blanket remote hold: scoped one-click setup for Tailscale and authorized known hosts is a supported claim, blanket promises stay banned. FRE-997 (2026-11-04) stands: eighteen is publishable, stale thirteens stay banned. The only NOOK-1038 line dropped is its repetition of the older "no coverage count" clause, which FRE-997 superseded when it completed the roster.

How a merge becomes a deploy

  1. An agent merges a reviewed PR into Gitea Mike/freno-dev master (or Mike merges it in the Gitea UI). Nothing else changes for the engineer.
  2. A Gitea push mirror on Mike/freno-dev pushes master to https://github.com/mikefreno/freno-dev.git with sync-on-commit enabled.
  3. Vercel sees the GitHub push and builds production from GitHub master.
  4. scripts/verify-deploy.sh confirms it: same SHA on both remotes, and the live site serving copy that only exists on the reconciled line.

Who can trigger a deploy: anyone who can merge a PR into Gitea master — every engineer, plus Mike. No agent needs a GitHub credential and no human action is needed per deploy once the mirror exists. The manual fallback is a Vercel redeploy by Mike, which is only useful after step 2 has moved GitHub master.

Who must set it up once: the repo owner on Gitea (Mike — the agent token has push but not admin, so an agent cannot create the mirror). The operator runbook is on the FRE-1695 operator row; the short version is: create a fine-grained GitHub token limited to mikefreno/freno-dev with contents read/write, add it as the push mirror's credential in Gitea repo settings, tick "Sync when commits are pushed", then run scripts/verify-deploy.sh.

Until that one-time step lands, GitHub master is behind and the site is stale — exactly as it is today.

Failure modes this deliberately keeps loud

  • A commit made directly on GitHub master is not in Gitea. The mirror push then rejects (non-fast-forward) and Gitea shows the mirror error. Do not commit to GitHub master; land it in Gitea and let it mirror.
  • A merge that is only a Gitea merge is not live until the mirror runs. Check scripts/verify-deploy.sh before calling a site change published.
  • The FRE-371 fix's actual exploitability in production depends on how the edge sets x-forwarded-for/cf-connecting-ip. That is measured and gated by the Security Engineer, not assumed here.

Verifying

scripts/verify-deploy.sh

It is read-only and needs no credentials. It checks both remotes' master SHA, the live Nook/Nessa copy, and (when the commit is present locally) that 2fd2a4a is an ancestor of the deployed commit.