You are working on StratoFusion. Execute the controlled Phase C production
cutover from the proven OVH rehearsal stack at
https://vm-staging.stratofusion.io to the canonical production origin
https://stratofusion.io.
This prompt is explicit authorization to prepare, commit, push, and perform the
production cutover, including the final database restore and DNS changes, but
only after every hard gate below passes. It is not authorization to destroy or
decommission Vercel, Fly.io, Neon, the vm-* rehearsal aliases, or any other
rollback resource. Decommissioning is Phase D and requires separate approval
after a stability window.
Do not stop after writing a plan. Work through preparation, verification,
cutover, and reporting in this thread. Pause only for a hard gate, an account
login/MFA handoff, a material conflict with the repository, or a failed check
that makes proceeding unsafe.
Use PowerShell for Windows-side repository work, Git, PNPM, DNS checks, and
SSH orchestration. Never use WSL or bare bash. Invoke Git Bash explicitly
only for repository .sh scripts that require POSIX behavior. On the Linux VM,
normal POSIX shell commands are appropriate.
Use the in-app Browser for authenticated provider dashboards and end-to-end
browser verification when required. Use Computer control only when a task
cannot be completed reliably through the browser or terminal. Reuse signed-in
sessions, ask me to take over for login or MFA, and never ask me to paste a
password, secret, OAuth token, private key, or database URL into chat.
Current Known State
Treat these facts as starting context and verify all mutable facts before use:
Repository: C:\code\stratofusion.
Migration branch: migrate/vm-consolidation.
Current known branch head: ad1613515b6bfa546c0de1a3e2224b1d5eb1f1b0.
The rehearsal app and rclone health endpoints have previously returned
healthy responses.
Rehearsal names currently point to the OVH VM:
vm-staging.stratofusion.io
vm-rclone.stratofusion.io
vm-grafana.stratofusion.io
vm-glitchtip.stratofusion.io
The current production app remains on Vercel, its production database remains
Neon, and its data plane remains Fly.io until cutover.
The VM uses compose Postgres restored from Neon and must have
CRON_REPLICAS=0 until the scheduler handoff is proven safe.
AUTH_ACCESS_PAUSED only pauses sign-in/sign-up. It does not freeze writes
from already authenticated users and is not an acceptable write-freeze by
itself.
The current Caddyfile serves only the vm-* names and needs production
hostnames before cutover.
The migration-branch GitHub workflow deliberately bakes vm-staging and
vm-rclone public URLs. The final image must be built from main or another
explicitly corrected production build path with apex URLs.
vercel.json still defines production cron schedules. DNS movement alone
does not prove that Vercel Cron has stopped.
Google and Dropbox rehearsal callbacks were previously added to the
production provider apps. Treat Microsoft Entra, Stripe, Clerk, and all
current dashboard state as unverified until directly confirmed.
Preserve unrelated working-tree changes. In particular, do not modify or
delete an unrelated untracked vercel-stratofusion-dns-table.png if present.
Target Production Topology
Service
Production hostname
Target
App
stratofusion.io
OVH VM 15.204.243.136
App alias
www.stratofusion.io
canonical redirect or proxy consistent with existing production behavior
Rclone
rclone.stratofusion.io
OVH VM 15.204.243.136
Grafana
grafana.stratofusion.io
OVH VM 15.204.243.136
GlitchTip
glitchtip.stratofusion.io
OVH VM 15.204.243.136
Database
compose Postgres stratofusion-prod
fresh final restore from Neon
Scheduler
compose cron container
exactly one replica only after legacy schedules are disabled
Keep the vm-* hostnames available through the initial rollback window unless
their presence creates a verified security or routing problem.
Non-Negotiable Safety Invariants
Never print complete .env files or reveal secrets in commands, logs, chat,
screenshots, commits, or documentation. Compare secret length or SHA-256
hashes when identity must be verified.
Never point the VM at Neon as its writable DATABASE_URL. Neon is read-only
input to restore-from-neon.sh; the VM app must use compose Postgres.
Keep VM cron at CRON_REPLICAS=0 until the old Vercel scheduler is disabled
and the new production stack passes core validation.
Drain and verify all active rclone/Fly operations before the write freeze and
final database dump.
Do not run pnpm db:migrate after restoring the Neon dump. The dump already
contains the migration history.
Do not perform destructive provider operations. Manual rclone commands use
--dry-run unless this prompt specifically requires a live non-destructive
smoke operation. Do not run delete, purge, move, sync-delete, bisync recovery,
or overwrite tests.
Capture existing DNS records, TTLs, deployment IDs, image tags, Git SHAs, and
rollback commands before changing production state.
Never enable writes on both the legacy and VM databases at the same time.
Do not claim that local and production images are byte-identical. Different
baked NEXT_PUBLIC_* URLs normally produce different image digests. Prove
release equivalence with the Git commit/tree identity, reviewed source diff,
build inputs, and image labels.
If users can write to the VM after the final restore, a DNS-only rollback to
Neon can lose those writes. Keep production access paused until the no-write
rollback window has passed, and explicitly report when rollback changes from
DNS-only to a database reconciliation exercise.
Hard Stop Conditions
Do not change production DNS if any of these is true:
Phase B evidence is incomplete for app health, rclone health, Clerk,
Google Drive, OneDrive, Dropbox, upload, download, Stripe webhook,
Grafana, GlitchTip, backup, or drain-gate behavior.
Microsoft Entra does not contain both the apex production callback and the
temporary vm-staging callback.
The selected cutover source tree differs from the rehearsed tree in
unreviewed application logic.
Active transfer operations cannot be drained or their state is ambiguous.
There is no tested mechanism that blocks authenticated writes on legacy
production during the final dump.
Vercel Cron cannot be disabled or proven inactive before VM cron activation.
The final Neon restore reports missing tables, migration inconsistencies, or
unexplained row-count differences.
The VM image was built with vm-staging/vm-rclone public URLs instead of
production URLs.
The production Caddy routes or runtime environment are incomplete.
A rollback path has not been recorded and checked.
DNS TTL is materially higher than expected and the previous TTL has not
elapsed; report the risk and obtain explicit confirmation before proceeding.
When blocked, continue all safe diagnostics and preparation, then report the
exact failed gate and the smallest required operator action.
Phase 1: Inventory And Evidence
Inspect the working tree, branch, recent commits, branch relationship to
main, and open PR/check state. Do not overwrite unrelated changes.
Record current public DNS answers and TTLs for:
stratofusion.io, www.stratofusion.io, rclone.stratofusion.io,
grafana.stratofusion.io, glitchtip.stratofusion.io, and all four
vm-* names.
Capture the current Vercel production deployment ID/commit and the current
Fly production worker release without changing them.
Connect to the OVH VM and capture, without secrets:
host identity and disk/memory health;
repository commit and tree hash;
compose service status;
app and rclone container image names, tags, and image digest labels;
current non-secret hostname-related environment values;
CRON_REPLICAS, AUTH_ACCESS_PAUSED, and whether the cron container is
actually absent/stopped;
recent backup status and available restore points.
Run real TLS health checks against vm-staging and vm-rclone and inspect
Caddy logs for certificate or routing errors.
Reconcile the Phase B checklist. Produce a concise pass/fail table and do
not infer a pass from a generic /api/health response.
Phase 2: Prepare The Cutover Release
Make the smallest coherent repository changes required for final production.
At minimum, inspect and address all of the following:
Caddy must serve the five production hostnames. Keep vm-* aliases during
the rollback window. Preserve unlimited/unbuffered rclone streaming.
Decide and implement the established www canonical behavior; do not create
a redirect loop or change callback hosts.
Remove staging-only hardcoding from production compose configuration.
GlitchTip domain, Grafana root URL, app URL, rclone URL, DSNs, and related
host-sensitive settings must resolve to production values at cutover while
rehearsal values remain usable before cutover. Prefer existing environment
configuration patterns over duplicate compose files.
Remove or leave empty OAUTH_REHEARSAL_ORIGIN for final production. Remove
vm-staging.stratofusion.io from CRON_EXTRA_ALLOWED_HOSTS when it is no
longer needed. Set the production GlitchTip/Grafana host variables and the
apex Stripe webhook signing secret as required by the existing config.
The GitHub Actions production build variables must bake:
the existing live Clerk and Stripe publishable keys.
Remove the temporary migration-branch deploy trigger or hardcoded rehearsal
build branch only when the same source tree is safely available on main.
Disable production Vercel cron schedules as part of the scheduler handoff.
Preserve development schedules if the dev deployment still needs them.
Do not enable VM cron merely because vercel.json was edited; verify the
production Vercel deployment containing the change is active and that its
scheduled jobs are absent/inactive.
Establish a real, tested legacy-production maintenance/write-freeze
mechanism. AUTH_ACCESS_PAUSED is insufficient. Prefer a reversible,
environment-controlled gate that can be enabled on Vercel while remaining
disabled on the VM. It must block authenticated UI/API mutations, OAuth
callbacks, cron execution, and write-producing webhooks on legacy
production while allowing a minimal health/maintenance response. Drain
active operations before enabling it. Ensure external webhook providers
receive a retryable failure rather than a false success if events cannot be
processed during the freeze.
Add focused tests for any maintenance gate, host validation, Caddy/compose
configuration helper, or scheduler behavior changed. Update canonical
deployment, OAuth, rclone, testing, and runbook documentation where behavior
changes.
Run pnpm env:guard, focused tests, type checking, and the broader checks
warranted by the diff. Validate compose and Caddy configuration without
exposing interpolated secrets.
Commit and push the cutover preparation intentionally. Ensure CI passes. Deploy
the candidate source tree to vm-staging with rehearsal build arguments first
where practical, then rerun all affected Phase B checks. Record the rehearsed
Git tree hash. The final main release may have a different commit SHA due to
merge mechanics, but its source tree and application logic must match the
reviewed candidate except for explicitly documented production build/runtime
configuration.
Phase 3: Confirm External Production Configuration
Using authenticated dashboards where necessary, verify before DNS movement:
Clerk live instance recognizes stratofusion.io as its production domain
and allows the apex origin/callback behavior required by the app.
Google production OAuth client contains
https://stratofusion.io/api/google.
Microsoft Entra production app contains
https://stratofusion.io/api/onedrive, supports the intended personal and
organizational account types, and has no unresolved tenant/login blocker.
Dropbox production app contains
https://stratofusion.io/api/dropbox.
Stripe live webhook endpoint is
https://stratofusion.io/api/webhooks/stripe, and the VM uses that exact
endpoint's signing secret rather than the temporary vm-staging secret.
Production DNS records can be edited and their previous values/TTLs have
been recorded.
Keep both apex and vm-staging callbacks during the rollback window. Do not
remove the apex callbacks at any point. Hand browser control to me for login or
MFA and resume immediately after I confirm completion.
Phase 4: Build And Stage The Final Production Image
Select and record CUTOVER_SHA, its Git tree hash, and the previous known
good VM tag.
Merge or fast-forward the reviewed migration tree to main using the
repository's normal workflow. Do not force-push or rewrite shared history.
Confirm CI and the VM build/deploy workflow pass for CUTOVER_SHA.
Confirm the final app image labels contain CUTOVER_SHA and that its baked
public URLs are apex production values. Do not rely on the tag latest.
Before deployment, update /opt/stratofusion/deploy/.env atomically and
securely with production hostnames, apex OAuth callbacks, the apex Stripe
webhook secret, production observability URLs, CRON_REPLICAS=0, and
AUTH_ACCESS_PAUSED=true. Do not display the file.
Deploy TAG=<CUTOVER_SHA> through the normal drain-gated workflow. Verify
internal app/rclone health, compose status, image labels, and Caddy config.
Keep user access and cron paused. The apex certificate may not issue until
DNS points to the VM; this is expected, but all other pre-DNS checks must
pass.
Phase 5: Freeze Legacy Writes And Take The Final Restore
This is the start of the maintenance window.
Announce the maintenance start in the work log with an exact UTC timestamp.
Verify active Fly and VM rclone operations are zero and no backup/sync job is
launching. Do not terminate a live transfer merely to shorten the window.
Enable the tested write-freeze on legacy Vercel production and verify from
both signed-out and authenticated paths that mutations cannot reach Neon.
Verify the production Vercel cron schedules are inactive. Keep VM cron at
zero.
Confirm webhook/OAuth behavior during the freeze is retryable or safely
blocked and does not acknowledge unprocessed writes.
Run the final restore-from-neon.sh on the OVH VM using the Neon production
URL supplied securely outside chat. Let the script stop app/rclone, recreate
compose Postgres, restore, analyze, and compare counts.
Capture the dump timestamp, restore completion time, migration count,
sequence checks, critical-table checks, and row-count comparison. Explain
every discrepancy before proceeding.
Verify the VM app and rclone restart healthy against compose Postgres and
that the VM has not written to Neon.
Take or confirm a fresh VM/provider snapshot and offsite backup where the
existing runbook supports it.
If this phase fails, leave production DNS unchanged, keep VM cron at zero,
disable public VM access as appropriate, restore legacy Vercel service, and
report the blocker.
Phase 6: DNS Cutover
Only after all prior gates pass, update the production DNS zone so these names
route to the OVH VM:
Name
Required destination
stratofusion.io
15.204.243.136
www.stratofusion.io
canonical apex or 15.204.243.136, consistent with the chosen DNS design
rclone.stratofusion.io
15.204.243.136
grafana.stratofusion.io
15.204.243.136
glitchtip.stratofusion.io
15.204.243.136
Remove conflicting Vercel records only as required to make these answers
unambiguous. Do not delete the recorded previous values. Keep TTL at about 300
seconds through the rollback window.
Monitor authoritative and public resolvers until the expected answers appear.
Then monitor Caddy until valid public certificates are issued for every final
hostname. Do not bypass TLS errors in the production pass criteria.
Phase 7: Production Validation
Keep VM cron at zero and keep general access paused during the first smoke
checks. Record evidence for each item:
https://stratofusion.io/api/health returns 200 with a valid public TLS
certificate and reports healthy database connectivity.
https://www.stratofusion.io follows the intended canonical behavior.
https://rclone.stratofusion.io/health returns 200 with valid TLS.
Grafana and GlitchTip load at their production hostnames without redirecting
to vm-* names.
Container image labels and /api/health or build metadata, if available,
identify CUTOVER_SHA.
Application and rclone logs contain no startup validation, CORS, database,
OAuth-origin, certificate, or secret errors.
Send a Stripe live test event and confirm signature verification and a 2xx
response on the apex endpoint.
Open the production sign-in flow and verify Clerk loads from the apex. Use a
tightly controlled operator window if access must be unpaused.
Connect or reconnect Google Drive, OneDrive, and Dropbox one at a time. Each
redirect and return must remain on stratofusion.io, each account must be
stored in compose Postgres, and no callback may land on Vercel/Neon.
Perform a small, non-destructive upload and download using an operator-owned
test account and test folder. Browser traffic must use
https://rclone.stratofusion.io; verify exact-origin CORS and byte success.
Clean up test data through the normal UI only if the operation and target
are explicit and approved; otherwise leave it labelled for later cleanup.
Confirm Grafana receives current metrics and GlitchTip receives separate
app and worker smoke events.
Verify backup configuration and run a non-destructive backup smoke if it
was part of the rehearsed checklist.
If any core check fails before general user access is opened, roll back using
the no-write procedure below. Do not keep debugging with production partially
open.
Phase 8: Scheduler Handoff And Reopen
Reconfirm Vercel Cron is disabled and no legacy scheduler has fired during
the maintenance window.
Reconfirm restored jobs were not unintentionally parked with rehearsal-only
timestamps. Compare against the final Neon source and the documented Phase B
parking procedure before changing schedules.
Set CRON_REPLICAS=1, apply compose, and prove exactly one cron container is
running.
Observe at least two expected execution cycles for sync reconciliation and
backup scheduling. Confirm no duplicate launches, correct compose Postgres
writes, and correct VM rclone operation IDs.
Restore normal production sign-in/sign-up by setting
AUTH_ACCESS_PAUSED=false only after the operator smoke tests pass.
Disable the legacy Vercel write-freeze only if Vercel must remain an active
rollback target and doing so cannot reopen writes to Neon. Normally leave
the legacy deployment in maintenance during the rollback window.
Record the exact UTC time general production access reopened.
Monitor health, error rate, OAuth failures, Stripe events, cron logs, queue
depth, database connections, disk, CPU, memory, and backups closely for at
least the first hour.
At the moment general users can write to compose Postgres, state clearly in the
work log: DNS-only rollback is no longer data-safe; rollback now requires VM write freeze and database reconciliation back to Neon.
Rollback
Prepare and record both rollback modes before cutover.
No-Write Rollback
Use this only before general writes have been accepted on the VM:
Keep or restore CRON_REPLICAS=0 on the VM.
Keep VM user access paused.
Restore the captured DNS records and TTLs to Vercel/Fly.
Promote or restore the recorded previous-good Vercel production deployment.
Restore Vercel cron schedules only after verifying the VM scheduler is off.
Disable the legacy write-freeze and verify Vercel/Neon health.
Confirm Stripe, Clerk, provider callbacks, and Fly rclone are again serving
the legacy production path.
Post-Write Rollback
Do not perform a DNS-only rollback after VM writes begin. First:
Freeze VM writes and disable VM cron.
Drain VM rclone operations.
Quantify database and external side-effect divergence since the final dump.
Design and verify a forward data migration/reconciliation from compose
Postgres back to Neon, including Stripe/webhook and provider-operation state.
Obtain explicit operator approval for that reconciliation plan.
Only then restore legacy DNS and schedulers.
If the app image alone is faulty while VM data remains authoritative, prefer
TAG=<previous-good-sha> ./deploy.sh on the VM over moving the database back to
Neon. Verify compatibility before rolling back across schema changes.
Deferred Cleanup
Do not perform these in the immediate cutover without separate approval:
deleting Vercel projects or deployments;
deleting Fly apps, machines, volumes, secrets, or workflows;
deleting Neon branches/projects or Weaviate Cloud data;
removing vm-* DNS aliases or callback entries needed for rollback;
rotating Clerk or token-encryption secrets;
deleting old Docker images, backups, snapshots, or database dumps;
removing monitoring history;
beginning Phase D repository cleanup.
After the agreed stability window, present a separate Phase D cleanup plan that
includes retention, export, rollback expiry, cost, and secret-rotation choices.
Final Report
Provide a concise but complete report containing:
cutover start, DNS change, general reopen, and completion times in UTC;
CUTOVER_SHA, Git tree hash, app/rclone image tags and digest labels;
source/rehearsal equivalence evidence and expected build-argument differences;
files changed, commits created, branch/PR/merge state, and CI results;
old and new DNS records plus observed propagation and TLS status;
final Neon dump/restore verification and any count differences;
legacy write-freeze and scheduler-disable evidence;
production runtime hostname values without secrets;
pass/fail evidence for health, Clerk, Google, OneDrive, Dropbox, Stripe,
upload/download, Grafana, GlitchTip, backup, and cron;
whether general writes have started and which rollback mode remains safe;
deferred cleanup items, remaining risks, and the recommended stability window.
Do not report success unless every core production check passes. If the cutover
is blocked or rolled back, state the exact phase reached, current source of
truth for user data, active scheduler, active DNS destination, and next safe
action.