From 3c228d523435686e8aecdc1b47d9f0c80be9a4db Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Thu, 13 Aug 2026 11:08:25 +0530 Subject: [PATCH] =?UTF-8?q?fix(deploy):=20retire=20the=20maintenance=20ban?= =?UTF-8?q?ner=20=E2=80=94=20the=20outage=20it=20describes=20is=20over?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every publish build since the wind-down has pinned VITE_MAINTENANCE_MODE='1', so instanode.dev has been telling every visitor "instanode is temporarily unavailable while we perform maintenance… we'll be back shortly" — sticky banner on all 14 public routes, plus a BLOCKING modal on /login* and /app*. That was true when the prod cluster was intentionally paused. It stopped being true when api.instanode.dev came back on Azure AKS with a real Let's Encrypt certificate. The header above the flag already carried the removal instruction; it was simply never executed once the cluster returned, so the banner outlived its outage by about two months and the site has been advertising downtime while the platform served traffic normally. Verified green against the LIVE platform before removing it — the banner is honest protection while things are broken, so it only comes down once they are not: provision → psql round-trip (create/insert/select) /cache/new → redis-cli SET/GET /storage/new → presign PUT → presign GET (real bytes back) /stacks/new → live app on a Let's Encrypt cert (issuer CN=YR2) POST /internal/set-tier → 404 (prod gate holds) GET /metrics → 401 (now token-gated) Excluded by scope: /queue/new (NATS isolation mid-fix) and Razorpay (unconfigured, out of scope for the migration). The flag is removed rather than set to '0' — MaintenanceNotice.tsx renders null when it is unset, and the component plus its vite-env declaration stay, so a genuine maintenance window is one line away. The comment now forbids re-pinning it to a build-event expression: an expression that is always true on publish is indistinguishable from "on forever", which is exactly how this shipped. Verified on the built artifact, not just the config: `npm run gate` green (87 files, 1285 passed), then served dist/ and loaded it in Chromium — the banner is absent from / and the blocking modal is absent from /login, with the sign-in form fully reachable. Grepping the bundle for the copy is NOT a valid check: the strings are module-level constants that compile in regardless, and only the inlined flag decides whether they render. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- .github/workflows/deploy-pages.yml | 37 +++++++++++++++++------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml index cab871c..7d75045 100644 --- a/.github/workflows/deploy-pages.yml +++ b/.github/workflows/deploy-pages.yml @@ -47,24 +47,29 @@ jobs: # ────────────────────────────────────────────────────────────── # SCHEDULED-MAINTENANCE TOGGLE (src/components/MaintenanceNotice.tsx). # - # '1' → the published Pages build renders the customer-facing - # maintenance banner (every route) + a one-time dismissible - # modal on /app* + /login*. This is ON because the prod - # cluster (api.instanode.dev) is intentionally paused, so the - # SPA loads but every API call fails — the banner explains the - # downtime is scheduled and the data is safe. + # DELIBERATELY UNSET. The component renders null when the flag is + # unset or '0', so the banner is off. # - # Gated to PUBLISH events only (push to main / manual dispatch) so a - # PR's `build` check produces a byte-identical, banner-OFF artifact — - # it never publishes (the deploy job below is PR-gated) and runs no - # tests, so this has zero effect on the required CI checks. The - # separate build-and-test / playwright / coverage / lighthouse jobs - # never set this var, so they build with the notice OFF. + # It was pinned to '1' on every publish build while the prod cluster + # was intentionally paused. That pause ended: api.instanode.dev now + # runs on Azure AKS with a real Let's Encrypt certificate, and the + # banner outlived the outage it described — telling every visitor + # "instanode is temporarily unavailable" while the platform was in + # fact serving, and putting a blocking modal in front of /login and + # /app. The header above this line already carried the removal + # instruction; it was simply never executed once the cluster + # returned. # - # ▶ TO TURN THE BANNER OFF ON RESUME: set this to '0' (or delete the - # line) and re-run this deploy — or revert the PR that added it. - # The component renders null when the flag is unset/'0'. - VITE_MAINTENANCE_MODE: ${{ github.event_name != 'pull_request' && '1' || '0' }} + # ▶ TO RE-ENABLE for a genuine maintenance window, add: + # VITE_MAINTENANCE_MODE: '1' + # and remove it again when the window closes. Verified green + # before removal (2026-08-13): provision→psql, cache→redis-cli, + # storage presign round-trip, and a real /stacks/new deploy + # serving over a Let's Encrypt cert. + # + # Do not re-pin it to a build-event expression — an expression + # that is always true on publish is indistinguishable from "on + # forever", which is exactly how this shipped for two months. # NOTE: do NOT `cp dist/index.html dist/404.html` here. prerender.mjs # already writes dist/404.html as the bare SPA shell so every /app/* # bookmark / shared link / magic-link callback rehydrates the React