You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit ea278e7
Browse filesBrowse the repository at this point in the historyBrowse files
Production had no ref to release from: `platform-deploy.yml` was manual
dispatch only, so a release was whoever clicked "Run workflow". The old
repo released on push to its `prod` branch; this restores that model on
the monorepo.
## What changed
### `platform-deploy.yml` — deploy on push to `prod`
```yaml
push:
branches: [prod]
concurrency:
group: platform-deploy-production
cancel-in-progress: false
```
`prod` is the production ref — it points at the commit that is live, so
advancing it is the release:
```bash
git push origin main:prod # release whatever main is at
```
No path filter, deliberately: the old repo had none, and a push to
`prod` is already deliberate. The concurrency group mirrors staging's
(`cancel-in-progress: false`), so a deploy is never interrupted between
the API migration and the workers.
### `schema-compat` — the production guard, restored
The old repository's job, ported as-is: Phase 1 applies the candidate's
migrations to a real Postgres 18; Phase 2 checks out `prod` and runs its
`platform-api-integration` suite on that schema. It runs on PRs and,
through `require-schema-compat`, on every production deploy (a push to
`prod` checks itself, as before; a manual dispatch from another ref is
checked against `prod`). Two integration tests only ever passed on
PGlite; they are fixed so the suite holds on Postgres too.
Accepted limits, same as the old repository and stated in the job
comment: the baseline is the `prod` branch head rather than the deployed
revision, and released migrations are assumed append-only (drizzle never
re-applies an applied entry and skips entries not newer than the last
applied). A stricter guard (deploy-recorded baselines, an append-only
checker) was tried on this branch and removed: more moving parts than
the risk it covers.
### Docs
`platform/meta/operations.md` (environments table, secrets note,
workflow list) and `platform/README.md` — which `platform/AGENTS.md`
symlinks to — now describe the branch model, and the agent guardrail
becomes "do not push `prod`" instead of "deploys are manual".
## First release notes
- `prod` in this repo currently points at `ab92e6d3` (2026-06-02, the
SDK repo's old release branch), 1214 commits behind `main`. It is an
ancestor of `main`, so advancing it is a fast-forward.
- The old repo's `prod` (`ea101e78`) is also an ancestor of `main`, so
no prod-only work is lost.
- **No database migrations ride along**: all 26 files in
`platform/packages/api/drizzle` are blob-identical between the old
repo's `prod` and `main`, so the first release from here applies none.
- Nothing deploys until someone pushes `prod`. That push is the trigger;
there is no separate button.
## Follow-ups this unblocks
- Retire the old repo's `Deploy Production` (push to its `prod`) at the
same moment, so only one repo can write production.
- `platform-ci.yml`'s `schema-compat` job is still inert with the
comment "the merged repository's production ref has intentionally not
been chosen yet" — `prod` is now that ref, so the job can be ported
next.
- The old repo's `prod` branch carried a ruleset (`deletion`,
`non_fast_forward`, `update`, bypass for org admins / write role / the
maintainers team). Nothing protects `prod` here yet, which matters more
now that a push to it deploys production.
## Verified
- `actionlint` on the workflow: clean
- `vp fmt --check`: clean
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **High Risk**
> Production deploys become automatic on `prod` pushes and gate releases
on migration compatibility against live `prod` code; mis-timed or
breaking migrations can block or endanger production rollout.
>
> **Overview**
> **Production releases now advance the `prod` branch** instead of
relying on manual workflow dispatch. Pushes to `prod` trigger
`platform-deploy.yml`, with a non-cancelling concurrency group so
deploys are not interrupted between API migration and worker rollout.
The reusable CI workflow accepts `require-schema-compat`, and production
deploy always sets it so the guard runs on every production trigger
(including manual dispatch from another ref).
>
> **The `schema-compat` CI job is enabled** (it was previously inert).
It applies the candidate’s Drizzle migrations to Postgres 18, then
checks out `prod` and runs `platform-api-integration` against that
schema so live code must tolerate the new schema before ship. PRs get
the same check; staging deploys skip it. If `prod` predates the monorepo
platform tree, migrations still run but integration tests are skipped
with a warning.
>
> **Docs** (`platform/README.md`, `platform/meta/operations.md`) now
describe push-to-`prod` as the production trigger and warn agents not to
push `prod`.
>
> **Two integration tests were adjusted for real Postgres** used by
`schema-compat`: the rollback test models **sequential** rollbacks with
a transaction hold instead of concurrent lock contention (Postgres
lease/409 behavior differs from PGlite); the sandbox teardown-race test
hooks **`cutover-ready:`** KV writes (post-commit, no open tx) so
teardown ordering is deterministic on pooled Postgres.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
22e988b. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Production still runs a pre-monorepo revision, so there is no platform code to test
151
+
# against: the schema is checked, the code is not. That gap closes with the first
152
+
# release from this repository, after which this branch stops being taken.
153
+
echo 'usable=false' >> "$GITHUB_OUTPUT"
154
+
echo '::warning::The compatibility baseline predates the platform, so the production code was not exercised against the migrated schema. This stops once prod carries the platform.'
Copy file name to clipboardExpand all lines: platform/README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -73,7 +73,7 @@ Paths in this file are relative to `platform/` unless they begin with `../`. For
73
73
74
74
The `@voidcloud/platform` workspace package retains the dashboard-only `dev` and `build` scripts. Dashboard deploys run after the platform workers in the platform deploy pipeline.
75
75
76
-
**Production deploys are manual only; staging deploys on every push to `main`.** See [`meta/operations.md`](./meta/operations.md#github-actions) for the workflow triggers. Do not ask to push or deploy.
76
+
**Production deploys on push to `prod`; staging deploys on every push to `main`.** See [`meta/operations.md`](./meta/operations.md#github-actions) for the workflow triggers. Do not push `prod` or ask to deploy.
Copy file name to clipboardExpand all lines: platform/meta/operations.md
+9-6Lines changed: 9 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -27,10 +27,10 @@ Five Cloudflare Workers:
27
27
28
28
Two fully isolated environments. Each has its own CF resources (KV, R2, dispatch namespace, analytics engine) and a separate Hyperdrive configuration pointing to its own PlanetScale PostgreSQL database.
29
29
30
-
| Environment | API URL | Dashboard | User Sites | Trigger |
`platform-deploy.yml` uses the `Prod` environment and runs only on manual dispatch; `platform-deploy-staging.yml` uses `Staging` and also runs on every push to `main` that matches the `platform-ci.yml` path filter. Both run only when the repository variable `VOID_PLATFORM_DEPLOY_ENABLED` is `true`.
234
+
`platform-deploy.yml` uses the `Prod` environment and runs on every push to `prod` or on manual dispatch; `platform-deploy-staging.yml` uses `Staging` and runs on every push to `main` that matches the `platform-ci.yml` path filter, or on manual dispatch. Both run only when the repository variable `VOID_PLATFORM_DEPLOY_ENABLED` is `true`.
235
235
236
236
**GitHub Actions `CF_API_TOKEN` permissions** — narrower-scope token used only for wrangler deploys. Separate from the API worker runtime token.
237
237
@@ -513,13 +513,16 @@ Four platform workflows live in the repository-level `.github/workflows/` direct
513
513
5.`vp run check:platform` and `vp run check:sdk` (typecheck the platform packages and the SDK packages; the playgrounds are typechecked by `ci.yml`)
514
514
6.`vp test run --project platform-unit` and `--project platform-api-integration`
515
515
7. Builds the API build container image (PRs only)
516
+
8. The production schema-compatibility guard (`schema-compat`; PRs and production deploys): migrates a fresh Postgres 18 with the candidate's migrations and runs the `prod` branch's `platform-api-integration` suite on it
**`platform-deploy.yml`** — push to `prod`, or manual dispatch (production, environment: `Prod`):
518
519
519
520
1. Runs `platform-ci.yml` first
520
521
2.`vp run build` (SDK packages the dashboard bundles)
521
522
3.`vp run --filter @voidcloud/platform deploy` (api with drizzle-kit migrations, proxy, tail, dispatch, dashboard)
522
523
524
+
`prod` is the production ref: it points at the commit that is live, so advancing it is the release (`git push origin main:prod` deploys whatever `main` is at). There is no path filter — a push to `prod` is deliberate. The branch carries a `prod` ruleset that blocks deletion and force-pushes and allows updates only from its bypass actors (organization admins, repository admins, and the `Void` team), so a push to `prod` is a maintainer action. A `concurrency` group (`platform-deploy-production`, `cancel-in-progress: false`) keeps one deploy running and at most one pending, so a deploy is never interrupted between the API migration and the workers.
525
+
523
526
**`platform-deploy-staging.yml`** — push to `main` that matches the `platform-ci.yml` path filter, or manual dispatch (staging, environment: `Staging`):
0 commit comments