diff --git a/.github/workflows/set-ec2-env-var.yml b/.github/workflows/set-ec2-env-var.yml index e9f8b06f1..0a44c803b 100644 --- a/.github/workflows/set-ec2-env-var.yml +++ b/.github/workflows/set-ec2-env-var.yml @@ -270,6 +270,24 @@ jobs: # two keys above this one DOES need the restart: the auth service is a # long-running container, not a per-run cron invocation. STATION_SIGNUP_ENABLED: ${{ secrets.STATION_SIGNUP_ENABLED }} + # FLOWSHEET_TAKEOVER_ENABLED (BS#2233) gates POST /flowsheet/join's + # explicit start-vs-join decision. Off (the default), `intent` and + # `expected_show_id` are ignored and the route silently co-hosts a + # caller onto whatever show is still open; on, an undecided caller + # gets a 409 `show_already_open` and `intent: "takeover"` closes the + # open show and starts their own. Not sensitive, but carried through + # the allowlist for the same "Unsupported secret_name" reason as + # DONATE_* above. Strict `=== 'true'` comparison + # (apps/backend/config/flowsheetTakeover.ts), same + # lowercase/::add-mask::/rollback rules as STATION_SIGNUP_ENABLED + # above. Pass restart_target=backend (the default) — only + # apps/backend reads it, and the backend is a long-running container, + # so the flip does need the restart. + # + # The flag is also the rollback: 'false' here restores the pre-BS#2233 + # behavior with no redeploy. Every 409-aware client tolerates the flag + # in either position, so it can be flipped back mid-show. + FLOWSHEET_TAKEOVER_ENABLED: ${{ secrets.FLOWSHEET_TAKEOVER_ENABLED }} run: | set -euo pipefail KEY="${{ inputs.key }}" @@ -297,6 +315,7 @@ jobs: STATION_SIGNUP_ALERT_EMAIL) VALUE="$STATION_SIGNUP_ALERT_EMAIL" ;; STATION_SIGNUP_DOWNGRADE_ENABLED) VALUE="$STATION_SIGNUP_DOWNGRADE_ENABLED" ;; STATION_SIGNUP_ENABLED) VALUE="$STATION_SIGNUP_ENABLED" ;; + FLOWSHEET_TAKEOVER_ENABLED) VALUE="$FLOWSHEET_TAKEOVER_ENABLED" ;; *) echo "::error::Unsupported secret_name '$SECRET_NAME'. Add it to the resolve step's env block." exit 1 diff --git a/docs/env-vars.md b/docs/env-vars.md index 496d8e7d9..b3a62bdee 100644 --- a/docs/env-vars.md +++ b/docs/env-vars.md @@ -173,7 +173,7 @@ Runtime vars supplied at `docker run --env-file .env` (all four have historicall ## Flowsheet Go-Live Intent -- `FLOWSHEET_TAKEOVER_ENABLED` (default `false`, BS#2233) — Strict `=== 'true'` gate (via `apps/backend/config/flowsheetTakeover.ts`'s `createEnvFlagConfig`, the same factory `CRITIC_REVIEWS_ENABLED` and `DONATE_ENABLED` use) for `POST /flowsheet/join`'s explicit start-vs-join decision. ON: a caller going live while a show they are not an active member of is still open must send `intent: "join"` (co-host) or `intent: "takeover"` (close it, start their own, `expected_show_id` required); sending neither is a `409 show_already_open` carrying `{ id, dj_name, start_time }`. OFF: `intent` and `expected_show_id` are ignored entirely and the route co-hosts as it always has. +- `FLOWSHEET_TAKEOVER_ENABLED` (default `false`, BS#2233) — Strict `=== 'true'` gate (via `apps/backend/config/flowsheetTakeover.ts`'s `createEnvFlagConfig`, the same factory `CRITIC_REVIEWS_ENABLED` and `DONATE_ENABLED` use) for `POST /flowsheet/join`'s explicit start-vs-join decision. ON: a caller going live while a show they are not an active member of is still open must send `intent: "join"` (co-host) or `intent: "takeover"` (close it, start their own, `expected_show_id` required); sending neither is a `409 show_already_open` carrying `{ id, dj_name, start_time }`. OFF: `intent` and `expected_show_id` are ignored entirely and the route co-hosts as it always has. In the `set-ec2-env-var.yml` allowlist; like `STATION_SIGNUP_ENABLED` (and unlike the cron-invoked `STATION_SIGNUP_DOWNGRADE_ENABLED`), the backend is a long-running container, so light-up needs the restart `restart_target=backend` performs. Rollback is the same invocation with the secret set to `false` — never cleared, since the resolve step hard-fails on an empty value. **Flag-OFF must never 400 or 409, and that is load-bearing rather than cosmetic.** `auto-dj-orchestrator` ships `intent: "takeover"` before the flip, and its `join()` throws on any response body without a show id, so a 400 on the unrecognized field would crash that daemon at activation. It is also what lets the four repos in this chain deploy in any order: BS ships dormant, every client becomes 409-aware while nothing is emitting 409s, and the flip is one env var. The flag is the rollback too — no redeploy.