Repository navigation
Every merge to main publishes the production docs site with no human gate — the cloudflare-docs environment has no required reviewer #266
Description
Filed by the repo:objectos seat (objectstack#9831) at 2026-09-04T12:55Z, out of the incident on #261 — where a merge by this seat replaced a working (stale) production site with a broken one, and the seat did not understand at merge time that it was publishing.
Maintainer instruction, verbatim (2026-09-04):
所有的部署应该有人工确认
The gap, stated mechanically
In this repo, merging to main IS deploying to production. There is no step between them.
merge PR → push to main → deploy-docs.yml → pnpm run deploy
→ Cloudflare Worker docs-objectos
→ docs.objectos.ai (live)
The workflow declares environment: name: cloudflare-docs, which is exactly the GitHub mechanism that can require a human approval before a job runs. It is not configured with one.
Measured, rather than read from settings (the settings API is not reachable from the agent container): PR #263 merged at 12:36:47Z and deploy run #142 started at 12:36:48Z — one second later. A job gated by a required reviewer sits in Waiting until a human approves. This one did not wait.
Why this is priority:p0
The agent seat that caused today's outage never held Cloudflare credentials and never ran a deploy command. Its actual privilege was merge to main — and that silently carries "publish to production" with it. Every guardrail this lane operates under (draft PRs, review checklists, merge queue, governed-surface rules) is built around the belief that merging is a reversible, internal act. In this repo it is not, and nothing anywhere says so.
Compounding it, and why "just revert" is not the safety net anyone assumes: an oversized upload is rejected at version creation, so a failed deploy does not roll back — it leaves the previously-uploaded version serving. A git revert of a bad deploy therefore does not restore the site. Recovery requires a Cloudflare-side version rollback, which needs credentials no agent has. The forward path is automatic and unattended; the recovery path is manual and gated. That asymmetry is the defect.
The ask (maintainer action — no agent can do this)
Repo Settings → Environments → cloudflare-docs → Required reviewers. Add at least one human. That makes every production deploy stop and wait for a click, without changing a line of workflow code.
Worth deciding at the same time:
- Whether
www.objectos.app/*should still be bound to this Worker at all — raised separately by the maintainer on 2026-09-04 and not part of this card; the binding is pre-existing (5b4df1b, 2026-06-04) and unrelated to the outage. - Whether the deploy job should assert a new version ID was created, since "rejected" and "succeeded" are indistinguishable from the step's exit code alone (tracked on Nothing measures the docs Worker bundle before deploy, so exceeding Cloudflare's 64 MiB limit fails silently after merge #262).
⛔ Lane frozen until this exists
This seat is not merging anything to main in this repo until there is a human gate on the deploy, regardless of how safe the diff looks. A docs-content PR and a production release are the same act here, and this seat has now demonstrated it cannot be trusted to hold that distinction in its head. Recorded on the seat post; the queue cards that would fire a deploy are blocked on this card.
Related: #261 (the outage), #262 (nothing measures the bundle before deploy), #265 (behaviour unverifiable before deploy), objectstack (the skills-side rule).
Activity
ci(docs): add a manual Cloudflare rollback workflow
os-project-manager commentedon Sep 4, 2026
Closed
not planned— the maintainer declined the human gate, and the requirement it served is met another way.repo:objectosseat (objectstack#9831), 2026-09-04T14:15Z.The decision, in the maintainer's own words
Asked for it on 2026-09-04, after the outage:
Objected to the cost when I proposed required reviewers on the
cloudflare-docsenvironment:And on seeing the automated verification layer land and prove itself:
⛔ Both statements are recorded, not just the later one. A reader arriving at the next incident should see the requirement, the cost that killed it, and what replaced it — not a card that says "wanted, then never mind".
Why declining is the right call, not merely the maintainer's call
The objection was correct on the economics, and there is a stronger objection I put to them at the time: a required reviewer gates attention, not correctness.
On 2026-09-04 a human clicking "approve" would have learned nothing. Nobody could tell before merge whether the page would render — that is #265, still open. The click would have been ceremony, paid on every docs typo, and the site would have broken anyway.
What actually catches that failure is now live (#269 / PR #270): the deploy is gated on CI, the published artifact is the tested one, the live site is smoke-checked after every deploy with a negative control proving the check can fail, a bad deploy auto-rolls-back, and any failure files a card. That answers "deploys must not reach production unverified" — the real requirement under 「人工确认」 — without a human in the loop on every prose fix.
Risk-proportionate gating was offered and also declined, and is recorded here in case it is wanted later:
content/docs/**auto-deploys,apps/docs/**andpnpm-lock.yamlrequire a click. Checked against the day's two merges, it would have gated PR #263 (the one that broke the site) and waved through PR #264 (a prose fix). It remains a sound design; it is simply not needed once the automated layer exists.What is NOT closed by this
wrangler dev/opennextjs-cloudflare preview, so no page can be smoke-tested in the Workers runtime before merge #265 — nobody can still verify a rendering change before merge. The automated layer catches it after, within about a minute, and rolls back. That is a smaller exposure window, not zero.Related: #269 / PR #270 (what replaced this), #261, #262, #265, #267, objectstack#15364 (the skills-side record).
Generated by Claude Code