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 master4e412ede!= Giteaa8ce226b, /agents still serves the pre-FRE-997 title, /terms is 404.
This commit was merged in pull request #9.
This commit is contained in:
119
docs/deploy-source.md
Normal file
119
docs/deploy-source.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user