From 3bde9510cac7c1459a91cd47211f377153c5fd49 Mon Sep 17 00:00:00 2001 From: Dave Liu <7david12liu@gmail.com> Date: Wed, 26 Aug 2026 10:05:54 -0700 Subject: [PATCH] docs: record isolated Firebase staging deployment (#665) --- AGENTS.md | 2 +- GITHUB_ISSUES.md | 10 +++++----- GITHUB_ISSUE_SLICES.md | 2 +- IMPLEMENTATION_PLAN.md | 2 ++ OFFICER_START_HERE.md | 2 +- OPERATIONS_RUNBOOK.md | 10 ++++++---- README.md | 6 ++++-- SECURITY.md | 8 ++++---- SYSTEM_DESIGN.md | 8 ++++---- docs/officers/ACCESS_CONTINUITY.md | 4 ++-- docs/officers/EMERGENCY_AND_RECOVERY.md | 4 ++-- docs/officers/GLOSSARY.md | 4 ++-- docs/officers/PUBLISH_AND_CHECK.md | 6 +++--- docs/officers/SYSTEM_MAPS.md | 6 ++++-- 14 files changed, 41 insertions(+), 33 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 94b52c4..a863d5c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -114,7 +114,7 @@ The deterministic frontend Jest baseline is available through the command above. For Firebase-backed local development, run `npm run emulators` first and wait until Auth, Firestore, and Functions are ready under `demo-mprc-local`. In a second terminal, run `npm start` and use `http://localhost:3000`. Stop if any browser Firebase request uses a non-loopback host. The emulator suite does not isolate Stripe, Strava, email, or other provider calls made by Functions; those flows remain forbidden until their test configuration and safe sink are separately proven. -Optimized builds must explicitly select `staging` or `production`. WEB-001A1 #663 provides and tests that source boundary, but it does not create an owned staging project or isolate outside providers. Do not sign in, open private/admin pages, or exercise Firebase/provider behavior in a preview until the protected staging and provider evidence required by #105/CONFIG exists. +Optimized builds must explicitly select `staging` or `production`. WEB-001A1 #663 provides and tests that source boundary. WEB-001A2 #665 adds the owned `run-mprc-staging` static Hosting surface, but it does not configure a staging backend, protected release authority, or isolated outside providers. Do not sign in, open private/admin pages, or exercise Firebase/provider behavior in a preview until the protected backend and provider evidence required by #105/CONFIG exists. For Stripe lifecycle work, tests must include relevant negative and retry cases: invalid signature, duplicate/out-of-order Event, unpaid completion, amount/currency/environment mismatch, terminal-state protection, async success/failure, expiration, cancellation, and refund retry. Capacity/inventory work must include concurrent final-unit tests. diff --git a/GITHUB_ISSUES.md b/GITHUB_ISSUES.md index 5f11dd7..b56191b 100644 --- a/GITHUB_ISSUES.md +++ b/GITHUB_ISSUES.md @@ -77,7 +77,7 @@ Every issue inherits `AGENTS.md` and the definition of done in `IMPLEMENTATION_P | 21 | DATA-002 | Create immutable, truthful waiver evidence | P1 | M | blocked_owner_decision | RACE-001, LEGAL-001 decision | | 22 | ADMIN-001 | Move sensitive admin operations behind scoped APIs and durable audit | P1 | L | proposed | SEC-001, AUTH-003, PAY-002 | | 23 | MERCH-002 | Configure shipping, tax, returns, and order communications | P1 | L | blocked_owner_decision | MERCH-001, LEGAL-001 | -| 24 | WEB-001 | Move to controlled hosting and add browser security policy | P1 | L | source foundation in progress through #460/#663; not deployed | SAFETY-001, CI-001 | +| 24 | WEB-001 | Move to controlled hosting and add browser security policy | P1 | L | static staging active through #460/#663/#665; production cutover blocked | SAFETY-001, CI-001 | | 25 | OBS-001 | Add payment observability, alerts, SLOs, and redaction | P1 | M | proposed | PAY-003, PAY-005 | | 26 | RESILIENCE-001 | Establish backup, restore, retention, and audited repair | P1 | L | proposed | DATA-001, PAY-005 | | 27 | TEST-001 | Build the Stripe/Firebase security integration and E2E suite | P0 | L | in progress through #177; most children proposed | core security/payment/data children | @@ -134,7 +134,7 @@ GitHub Pages routes unknown SPA paths through `public/404.html`. The original br ### Agent handoff -Do not redesign routing or hosting in this issue; WEB-001 owns that. WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) now makes ordinary optimized previews select a reserved synthetic staging configuration, but private preview behavior remains blocked because no owned staging project or provider isolation is verified under #105/CONFIG. Firebase emulators do not make Stripe, Strava, or email safe. ABUSE-001A must explicitly defer App Check enforcement on `lookupRegistration`, `lookupOrder`, and `stravaExchangeCode` while the initial capability guard is active. DATA-001A owns the two payment-confirmation handoffs; OAUTH-001C within live [#88](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/88) owns the Strava exchange handoff. Do not weaken the guard. Do not include any real callback token in fixtures. #118 still owns the reported profile failure. +Do not redesign routing or hosting in this issue; WEB-001 owns that. WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) makes ordinary optimized previews select a reserved synthetic staging configuration. WEB-001A2 [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) adds an owned static Hosting stage, but private preview behavior remains blocked because its backend and outside-provider isolation are not configured under #105/CONFIG. Firebase emulators do not make Stripe, Strava, or email safe. ABUSE-001A must explicitly defer App Check enforcement on `lookupRegistration`, `lookupOrder`, and `stravaExchangeCode` while the initial capability guard is active. DATA-001A owns the two payment-confirmation handoffs; OAUTH-001C within live [#88](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/88) owns the Strava exchange handoff. Do not weaken the guard. Do not include any real callback token in fixtures. #118 still owns the reported profile failure. --- @@ -468,7 +468,7 @@ Use OAUTH-001A/B/C as bounded outcomes within canonical tracker [#88](https://gi ## AUTH-003 — Introduce scoped admin capabilities, MFA, and recent authentication **Labels:** `priority:P1`, `type:security`, `area:auth`, `area:firebase`, `size:L`, `needs-migration`, `needs-external-config` -**Status:** In progress through tracker [#460](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/460). Source-only child WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) adds environment-explicit builds, artifact checks, and inert Firebase Hosting SPA configuration; no staging/production Hosting site, headers, release authority, deployment, domain, or cutover is verified. +**Status:** Proposed. WEB-001A2 [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) adds static website staging only; it does not deploy or verify scoped capabilities, MFA, recent authentication, Rules, Functions, or operator behavior. **Depends on:** AUTH-001, AUTH-002, SEC-001 ### Problem @@ -1171,7 +1171,7 @@ Do not enable Stripe Tax, Canada shipping, or collect additional addresses until ## WEB-001 — Move to controlled hosting and add browser security policy **Labels:** `priority:P1`, `type:security`, `type:maintenance`, `area:web`, `size:L`, `needs-external-config` -**Status:** Proposed +**Status:** In progress through tracker [#460](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/460), source foundation [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663), and static staging [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665). Production cutover remains blocked. **Depends on:** SAFETY-001, CI-001 ### Problem @@ -1383,7 +1383,7 @@ Repository code cannot prove external production configuration. MPRC needs owned ### Scope - Complete the ownership roster in `OPERATIONS_RUNBOOK.md` with primary/backup and least privilege. -- Create/verify dedicated staging Firebase project and Stripe test/sandbox endpoint; keep production isolated. +- Extend the dedicated `run-mprc-staging` static project into a protected backend test environment, create and verify the Stripe test/sandbox endpoint, and keep production isolated. - Configure Secret Manager bindings, expected livemode/origin, commerce kill switch, App Check Enterprise/enforcement, TTL, budgets, IAM, protected GitHub environments/OIDC, email domain, Sentry redaction, backups, DNS/hosting, and Stripe event allowlist. - Verify Stripe account legal/support/statement/payout settings, team MFA/passkeys/roles, Radar, tax/shipping decisions, webhook secret rotation, alert ownership, and reconciliation schedule. - Run full staging dress rehearsal and incident/kill-switch/restore drills. diff --git a/GITHUB_ISSUE_SLICES.md b/GITHUB_ISSUE_SLICES.md index a632f1e..66cd8db 100644 --- a/GITHUB_ISSUE_SLICES.md +++ b/GITHUB_ISSUE_SLICES.md @@ -138,7 +138,7 @@ An agent-ready child has one observable outcome, one trust boundary, explicit de | MERCH-002B | proposed; A, MERCH-001B | Apply server shipping/tax config and actual total snapshots/reconciliation. | Test-mode taxable/pickup/shipping/mismatch fixtures. | | MERCH-002C | proposed; A/B, ADMIN-001C | Add fulfillment/return/restock state and audited operator actions. | Forbidden transitions and stock adjustment tests. | | MERCH-002D | proposed; A–C, MAIL-001B | Add minimum customer communications/UI and address minimization. | Lifecycle/email/PII projection tests. | -| WEB-001A | owner_action; source foundation tracked by [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663); CI-001B2 | #663 adds environment-explicit builds, executable artifact checks, a demo-only CLI default, and inert Hosting rewrites. An authorized owner must still provision isolated staging hosting, short-lived authority, canonical/sitemap behavior, deploy, readback, and rollback. | #663 source tests and synthetic Hosting-emulator deep routes are not a hosted stage; later ADR plus exact deployed staging/readback/rollback evidence is required. | +| WEB-001A | in progress through source foundation [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) and static staging [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665); CI-001B2 | #663 adds environment-explicit builds, executable artifact checks, a demo-only CLI default, and inert Hosting rewrites. #665 provisions isolated static staging, publishes exact source, and verifies public readback. Protected short-lived authority, backend/provider isolation, application headers, a release marker, tested rollback, and production cutover remain. | #665 provider evidence must name exact source/version, signed-out desktop/phone/deep-route readback, and the absent controls. Later evidence must prove protected authority, backend/provider isolation, security headers, marker, predecessor rollback, canonical production DNS/TLS, and cutover. | | WEB-001B | proposed; A | Add CSP/HSTS/frame/referrer/permissions/MIME/cache policy. | Automated header/CSP and browser flow smoke. | | WEB-001C | partial source retirement tracked by [#492](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/492); remaining work proposed; A/B, PAY-001A | Keep the dormant legacy raw-HTML renderer/parser removed, then migrate any legacy stored content to the structured #83 contract and validate external URLs. | #492 no-manifest/no-lock/no-source guard plus later XSS/protocol/legacy-content migration fixtures. No route, data, Rules, hosting, or live change is proved by #492. | | WEB-001D | owner_action; A–C | Execute controlled DNS cutover/rollback and retire old deploy path without enabling commerce. | Dated owner-approved cutover evidence. | diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md index 192b189..b36350e 100644 --- a/IMPLEMENTATION_PLAN.md +++ b/IMPLEMENTATION_PLAN.md @@ -38,6 +38,8 @@ MPRC can open a race or merchandise item for sale only when the platform can: **WEB-001A1 Firebase Hosting source foundation:** [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) is the first bounded child of #460. It makes controlled optimized builds environment-explicit, keeps local/test on the demo emulators, requires complete staging-named public Firebase configuration, rejects production identities in staging, scans the executable synthetic CI artifact, changes the unqualified CLI default to `demo-mprc-local`, and adds the inert `build/` Hosting rewrite. It deliberately does not provision staging, configure short-lived authority or branch/environment protection, deploy Hosting/Firebase, automate `production-web`, add release readback/rollback/headers, alter Netlify/Pages, or touch DNS/TLS. Source/tests/merge and a synthetic build are not staging or production evidence. +**WEB-001A2 isolated static staging:** [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) creates the club-owned `run-mprc-staging` Firebase project, one web app, and the static [run-mprc-staging.web.app](https://run-mprc-staging.web.app) Hosting site from exact merged source `a614c68d9a1a2be631a3be874a686d61e5d170a0`. The executable artifact scanner found the staging identity and rejected known production identities; provider, direct-route, desktop, and phone readback passed. This is signed-out visual staging only. It does not configure App Check, Auth test users, Firestore, Functions, Rules, indexes, Storage data, provider sandboxes, protected short-lived authority, a release marker, tested predecessor rollback, security headers, `production-web`, custom domains, DNS/TLS, or production publication. + ## 3. Dependency map ```mermaid diff --git a/OFFICER_START_HERE.md b/OFFICER_START_HERE.md index b15f81b..0c193a5 100644 --- a/OFFICER_START_HERE.md +++ b/OFFICER_START_HERE.md @@ -50,7 +50,7 @@ As of **2026-08-13**, a merge runs checks but does not start the GitHub release. As of **2026-08-14**, [#659](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/659) completed one accessibility-only Netlify release. Deploy `6a7ece87c5ca4d0007c1a3fc` is live from frozen source `7496fe0881fb52908c4ff2f40f488df09c94c908`; its exact 62-file marker and signed-out desktop/phone route-focus and menu checks passed. Repause merge `3138a00c1c48e1d5d1dcda0b44722b09a2194ff7` made the manifest inactive. Its attempt `6a7ed0ddb00a46000818878d` published nothing and retained the verified deploy. #623 deploy `6a7e072f8f346b0008510d29` is the recorded rollback, not current production. #659 changed no Firebase, provider configuration, account, sign-in state, production data, payment, or connected directory behavior. Officers do not run commands, sign in, enter data, or approve this as a reusable release. Follow the completed record in [Review, merge, release, and check a change](./docs/officers/PUBLISH_AND_CHECK.md). -As of **2026-08-23**, WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) adds source checks for an explicit staging-or-production website build and a Firebase Hosting SPA rewrite. This is **SOURCE ONLY, NOT LIVE**. There is no club-owned staging Hosting site, protected automatic Firebase Hosting release, custom domain, or officer publish control yet. Netlify still answers `runmprc.com`; a green #663 test or merged source change does not mean Firebase Hosting, Firebase backend services, DNS, GitHub Pages, Netlify, or the public website changed. +As of **2026-08-26**, WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) is merged, and WEB-001A2 [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) created the club-owned `run-mprc-staging` project and published exact source `a614c68d9a1a2be631a3be874a686d61e5d170a0` to [run-mprc-staging.web.app](https://run-mprc-staging.web.app). This is an **ENGINEERING STAGING SITE ONLY**. Desktop and phone public-route checks passed, but staging has no approved backend/provider test estate, App Check key, protected automatic release, release marker, tested predecessor rollback, security-header policy, custom domain, or officer publish control. Do not sign in or enter real information there. Netlify still answers `runmprc.com`; production Firebase Hosting remains empty, and no DNS, GitHub Pages, Netlify, backend, or production-data change occurred. The optional profile-photo and officer People-finder functions are still **NOT AVAILABLE YET**. #621 makes the frontend default an inert preview: My Account shows the future photo and separate finder-choice controls disabled, while the People finder stays behind the administrator guard and shows its name field and Search button disabled. The preview reads no saved photo or setting, accepts or uploads no photo, searches no name, and saves nothing; it shows no people or sample results. #623 published exactly that disabled interface as deploy `6a7e072f8f346b0008510d29`. Officers inspect the protected layouts only in synthetic local artifacts. The completed signed-out production review proved only the exact revision, normal sign-in and administrator guards, and absence of a member-directory network request. Do not sign in to production, choose a real photo, enter a real name, or treat the preview as a directory. #623 changed no Firebase, provider configuration, account, sign-in, or production data. #507 must later prove the privacy, authorization, staging, backend-first deployment, and readback gates before a separate reviewed source change may connect it. Follow the preview and source-review procedure in [Events, shop, members, and money](./docs/officers/EVENTS_SHOP_MEMBERS.md). diff --git a/OPERATIONS_RUNBOOK.md b/OPERATIONS_RUNBOOK.md index f26b4e1..e29c2a3 100644 --- a/OPERATIONS_RUNBOOK.md +++ b/OPERATIONS_RUNBOOK.md @@ -63,10 +63,12 @@ Maintain an internal inventory with project/account IDs and console links: | --- | --- | --- | --- | --- | --- | | Local source runtime | `demo-mprc-local` emulators | Providers remain separately gated | `localhost:3000` | None | Available for synthetic Firebase work after all three loopback emulators report ready | | CI | Separate named demo/emulator projects | Fixtures/test only | None | CI | Frontend, Functions, Rules, SPA, and commerce-journal checks run; broader gates remain partial | -| Staging | **Create dedicated project** | Test/sandbox + unique endpoint | `dev.runmprc.com` | `staging` | Launch blocker | +| Staging | `run-mprc-staging` | No provider sandbox or backend test configuration yet | `run-mprc-staging.web.app`; `dev.runmprc.com` not configured | No protected environment yet | Static signed-out engineering Hosting is available; backend/provider staging remains a launch blocker | | Production | `mid-peninsula-running-club` (verify) | Live + unique endpoint | `runmprc.com` | `production` | Informational site only until gates close | -The repository's only `.firebaserc` default is now `demo-mprc-local`, a deliberately non-deployable local namespace. It is an accidental-deploy brake, not staging. Every future deployment must still pass one exact privately approved project explicitly. Do not infer staging isolation from source or historical documentation; #113/#133 must create, own, map, and verify it. +WEB-001A2 [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) created and provider-read back `run-mprc-staging`, one web app, and Hosting version `3ffadcf2ac8cc760` from source `a614c68d9a1a2be631a3be874a686d61e5d170a0` on 2026-08-26. Always name that project explicitly; `.firebaserc` still defaults to the demo namespace. The static host is not complete environment isolation: App Check, Auth test configuration, Firestore, Functions, Rules, indexes, Storage data, provider sandboxes, protected deployment authority, `dev.runmprc.com`, release-marker readback, and tested rollback remain unavailable. + +The repository's only `.firebaserc` default is now `demo-mprc-local`, a deliberately non-deployable local namespace. It is an accidental-deploy brake, not staging. Every future deployment must still pass one exact privately approved project explicitly. Do not infer backend/provider isolation or release authority from the static host; #113/#133 must protect, map, and verify those remaining boundaries. ## 4. Configuration and secrets @@ -93,7 +95,7 @@ REACT_APP_STRAVA_CLIENT_ID The Firebase web configuration is public application configuration. It must still be environment-specific and paired with Auth restrictions, Firestore rules, and App Check. WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) makes controlled optimized builds choose `staging` or `production`; staging project IDs must include a distinct `staging` segment and the complete artifact check rejects known production identities. Production accepts only the exact reviewed public values. These values are not server credentials, but do not paste provider-console screenshots, private links, tokens, or any server credential into source or an issue. -`firebase.json` now has a source-only Hosting block for `build/` and missing-path SPA rewrites. Its predeploy chain rejects a Firebase CLI project that differs from the selected browser project, then rebuilds and scans executable JavaScript before upload. **Firebase Hosting publication is NOT AVAILABLE YET.** No staging site, channel, WIF identity, protected production branch, custom domain, release marker, rollback, or DNS/TLS change is created by #663. +`firebase.json` has a Hosting block for `build/` and missing-path SPA rewrites. Its predeploy chain rejects a Firebase CLI project that differs from the selected browser project, then rebuilds and scans executable JavaScript before upload. **Static engineering staging is available; protected and production publication are NOT AVAILABLE YET.** #665 used that chain for the first `run-mprc-staging` release. No WIF identity, protected production branch, custom domain, release marker, tested rollback, production release, or DNS/TLS change exists. ### App Check release state — NOT AVAILABLE YET @@ -239,7 +241,7 @@ Expected result: the browser uses a fully synthetic Firebase configuration, Auth The CLI readiness messages prove the three processes listened during that run. Mocked frontend tests prove endpoint selection, not process readiness. If an emulator later stops, requests fail locally; do not change the project or disable the guard. -Optimized builds are different. They must explicitly select `staging` or `production`; missing, local, incomplete, or cross-environment configuration stops startup. Ordinary Netlify deploy previews receive only the reserved synthetic staging configuration; the pinned release builder receives the exact reviewed public production web configuration. Both paths scan the built executable. A synthetic staging build proves artifact separation only—it is not an owned staging backend and does not isolate providers. Use previews and locally served artifacts only for public, read-only visual checks until protected staging is verified. Do not sign in or open account, member, admin, event-registration, shop-purchase, or provider flows. +Optimized builds are different. They must explicitly select `staging` or `production`; missing, local, incomplete, or cross-environment configuration stops startup. Ordinary Netlify deploy previews receive only the reserved synthetic staging configuration; `run-mprc-staging.web.app` receives the owned static staging web-app configuration; the pinned release builder receives the exact reviewed public production web configuration. Every path scans the built executable. Neither synthetic previews nor the static owned host provide an isolated backend or outside-provider sandbox. Use them only for public, signed-out, read-only visual checks until protected backend/provider staging is verified. Do not sign in or open account, member, admin, event-registration, shop-purchase, or provider flows. ### Forward Stripe events — NOT AVAILABLE YET for end-to-end use diff --git a/README.md b/README.md index 7694151..aac22df 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,8 @@ Historical developer/content/LLM guides remain under [`docs/`](./docs/README.md) **Deployment reality checked 2026-08-14:** merges run CI but do not start the manual release workflow. The protected gate accepts one exact current merged commit, rechecks its newest CI run after approval, uses one fixed Firebase target set, fails when protected authority/configuration is missing, verifies Firebase before publishing GitHub Pages, and gives no server credential to website preparation or publication. Ordinary Git-triggered Netlify production builds are paused. WEB-002D [#659](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/659) completed one bounded accessibility release: exact merge `46e23647d8e0bf9fa3a574ea5c5f993be10a419d` published deploy `6a7ece87c5ca4d0007c1a3fc` from source `7496fe0881fb52908c4ff2f40f488df09c94c908`, tree `ccac4c189c195db8ab594e0eefe256ea9fa04996`, 62 files, and artifact digest `e4c26e6f0fbcd086663d86238675f0be228fb649a00628c1c97d1166612f49c7`. Signed-out desktop and phone route-focus/menu checks passed. Repause merge `3138a00c1c48e1d5d1dcda0b44722b09a2194ff7` passed exact-main CI run `31783808994`; attempt `6a7ed0ddb00a46000818878d` published nothing, deploy `6a7ece87c5ca4d0007c1a3fc` remained live, and the manifest is inactive. #623 deploy `6a7e072f8f346b0008510d29` remains rollback history and its inert directory interface is unchanged beneath the accessibility delta. No Firebase, Rules, Functions, indexes, provider configuration, account, sign-in state, role, member data, payment, or connected directory backend changed. The prior bounded #473 deploy `6a6dc9ea588b0c0008036312` remains older history. The source stops adding a Pages `CNAME`, but GitHub Pages currently still claims `runmprc.com` and its default URL redirects there; only a controlled #136/WEB-001 publication and provider readback can clear that conflict. Reusable protected publication to the live Netlify-served `runmprc.com` is not configured yet. Treat GitHub Pages, Netlify, `runmprc.com`, Firebase, and outside providers as separate states. +**Owned staging checked 2026-08-26:** WEB-001A2 [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) created the isolated `run-mprc-staging` Firebase project under the club account and published exact source `a614c68d9a1a2be631a3be874a686d61e5d170a0` as Hosting version `3ffadcf2ac8cc760` at [run-mprc-staging.web.app](https://run-mprc-staging.web.app). Signed-out desktop, phone, direct `/events`, and empty-data checks passed. This is static engineering staging only: Auth, Firestore, Functions, App Check enforcement, outside-provider sandboxes, protected short-lived release authority, application security headers, a release marker, and a tested predecessor rollback are not configured. Do not sign in or use real data there. Production Firebase Hosting remains empty and `runmprc.com` remains on its existing Netlify deployment. + ## Local setup status The #99 local Firebase boundary is available for synthetic source development. It uses a non-addressable `demo-mprc-local` configuration and loopback Auth, Firestore, and Functions emulators. It stops startup when an emulator connection cannot be configured. App Check, Analytics, and Sentry stay off locally. @@ -66,7 +68,7 @@ npm start Open only `http://localhost:3000`. Stop if Firebase traffic uses a non-loopback host. Use synthetic records only. This does **not** make checkout, refunds, email, Strava, or other outside-provider calls safe; follow [OPERATIONS_RUNBOOK.md](./OPERATIONS_RUNBOOK.md) before any provider test. -Do not use a Netlify preview or locally served optimized `build/` for sign-in, private pages, admin work, or Firebase testing. WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) makes optimized builds choose `staging` or `production` explicitly, but it does not create or verify an owned staging project or isolate outside providers. +Do not use a Netlify preview, locally served optimized `build/`, or the static `run-mprc-staging` Hosting site for sign-in, private pages, admin work, or backend/provider testing. WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) makes optimized builds choose `staging` or `production` explicitly. WEB-001A2 [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) verifies an owned static stage, but does not configure its backend or isolate outside providers. ## Verification @@ -88,7 +90,7 @@ npx --no-install react-scripts build node scripts/firebase-hosting-contract.js verify build ``` -Rules and commerce-emulator tests require Java 21. The repository pins Firebase CLI 15.24.0; use only that lockfile copy with Node 20 and explicit `demo-*` projects. The synthetic values above authorize no provider call or deployment. The direct `react-scripts build` command avoids regenerating `public/sitemap.xml`; the following verifier proves that executable JavaScript selected the synthetic staging project and contains no known production Firebase identity. The normal `npm run build` validates its selected hosted environment and runs the sitemap generator. Hosted CI runs the frontend Jest suite under [#124](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/124), the SPA callback suite under [#126](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/126), and the release-gate source tests under [#135](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/135). [#133](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/133) still owns protected environment/OIDC configuration; [#136](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/136) owns the actual staged profile-recovery release. Required branch checks, owned staging, protected publication, and hosting consolidation remain open under [#105](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/105) and their atomic children. +Rules and commerce-emulator tests require Java 21. The repository pins Firebase CLI 15.24.0; use only that lockfile copy with Node 20 and explicit `demo-*` projects. The synthetic values above authorize no provider call or deployment. The direct `react-scripts build` command avoids regenerating `public/sitemap.xml`; the following verifier proves that executable JavaScript selected the synthetic staging project and contains no known production Firebase identity. The normal `npm run build` validates its selected hosted environment and runs the sitemap generator. Hosted CI runs the frontend Jest suite under [#124](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/124), the SPA callback suite under [#126](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/126), and the release-gate source tests under [#135](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/135). [#133](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/133) still owns protected environment/OIDC configuration; [#136](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/136) owns the actual staged profile-recovery release. Required branch checks, backend/provider isolation, protected publication, security headers, rollback proof, and hosting consolidation remain open under [#105](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/105) and their atomic children. These safety changes do not repair a missing member profile or prove deployed Firebase Rules/Functions. The reported profile-save failure remains [#118](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/118). diff --git a/SECURITY.md b/SECURITY.md index 52f4220..8bfb386 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -47,7 +47,7 @@ The findings below describe the repository at the start of the 2026-07-12 assess | RISK-007 | Repository source rejects unverified targets at the two existing role-grant endpoints. AUTH-001B [#196](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/196) adds exact verified-email checks to role-based Firestore Rules, and AUTH-001C [#209](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/209) tracks the matching gate at current Functions role consumers. Firebase deployment, verification-mirror refresh, revocation, authoritative membership, scoped capability/recent-auth controls, and replacement of the legacy static-key endpoint remain unproven. | Older deployed code or a remaining role-only server guard can let an unverified known-email account use member/admin authority. CSV export also retains separate minimization, recent-auth, and audit risks. | Deploy and verify the exact Rules/Functions through #105, complete the remaining AUTH-001 mirror/revocation work, require authoritative membership and scoped privileged access, harden roster export under #116, and retire the static-key endpoint. | | RISK-008 | `requireAppCheck` is controlled by optional `ENFORCE_APP_CHECK`; repository/deployment config does not prove it is true. Missing site key also disables client App Check. | Public callable functions may be scripted directly, enabling abuse and cloud/Stripe cost amplification. | Use Firebase runtime `enforceAppCheck: true` for sensitive callables, reCAPTCHA Enterprise, staged metrics, and no environment fail-open. | | RISK-009 | #99 source preserves and validates the complete same-origin Pages callback route, applies `strict-origin` before subresources, and suppresses initial callback App Check/telemetry startup; #126 adds that standalone suite as a blocking hosted CI step. #443 adds only the source/test Strava same-document handoff after the native and Router callback locations are clean. No production Stripe/Strava callback, provider-backed App Check token behavior, or live custom-domain handoff has been rehearsed, and the live custom domain uses a different host. | Hosting, provider, configuration, or release drift can still break return links or the App Check handoff even when source tests pass. Enforcing a callback callable without its matching released client handoff and staged provider evidence can also break confirmation or Strava exchange. | Keep the hosted callback gate blocking; keep `lookupRegistration`/`lookupOrder` deferred until DATA-001A; keep native enforcement for `stravaExchangeCode` deferred to ABUSE-001A2 after the exact #443 website source and provider-backed Enterprise token behavior are proven in protected staging; verify test-mode callbacks only after provider gates; consolidate hosting under WEB-001. | -| RISK-010 | Development/test use synthetic loopback Auth, Firestore, and Functions. WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) makes controlled optimized builds select `staging` or `production` explicitly, requires staging-named public Firebase configuration, rejects known production identities before SDK use, scans CI's executable staging artifact, and makes the Hosting predeploy hook bind the selected browser project to Firebase CLI's exact project before rebuilding and scanning. No owned staging project or provider sandbox is configured, and emulated Functions can still call outside providers. | A bypassed build path, unowned staging project, or provider-capable emulator can still be mistaken for complete staging and affect production/provider systems. | Keep private actions out of previews; merge and preserve #663's fail-closed gate; complete #113/#133 staging ownership and short-lived authority; prove test keys, sinks, provider isolation, and deployed artifact readback before end-to-end flows. | +| RISK-010 | Development/test use synthetic loopback Auth, Firestore, and Functions. WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) makes controlled optimized builds select `staging` or `production` explicitly and binds Hosting predeploy to the exact project. WEB-001A2 [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) creates owned `run-mprc-staging` with one web app and a scanned static Hosting release. App Check, Auth test configuration, Firestore, Functions, Rules, indexes, Storage data, provider sandboxes, protected authority, and a release marker remain absent; emulated Functions can still call outside providers. | A static visual stage, bypassed build path, or provider-capable emulator can be mistaken for complete staging and affect production/provider systems. | Keep private actions out of previews; preserve #663's fail-closed gate and #665's fixed project boundary; complete #113/#133 short-lived authority and backend/provider staging; prove test keys, sinks, provider isolation, exact marker readback, and rollback before end-to-end flows. | | RISK-011 | Local cancellation only changes Firestore; it does not expire the active Stripe Session. The webhook can later move a cancelled record back to paid. | Customers can pay a supposedly cancelled registration/order; capacity/inventory and support state diverge. | Add explicit cancellation saga with Stripe Session expiry and allowed-state transitions. | | RISK-012 | Repository source now denies every admitted positive late-registration amount before identifier/token allocation, registration writes, Stripe construction, or Product/Price/Payment Link calls, and the Admin screen exposes only the exact-zero compatibility path. Firebase deployment is unproven, and legacy reusable Payment Links may still exist. | Older deployed code or an existing link can still create unreconciled or repeated charges/Sessions for one logical registration. The exact-zero local record is also marked paid without Stripe and is not payment, free, comp, or membership authority. | Keep paid late registration unavailable; inventory, deactivate, and reconcile legacy links privately; then replace them with one-off idempotent Checkout Sessions through the normal registration/payment lifecycle. | | RISK-013 | The assessment baseline permitted Stripe promotions while Firestore stored base price. Repository source now disables promotion entry and automatic tax, requires a complete adjustment breakdown, and quarantines unknown or nonzero discount/tax/shipping amounts; deployment and provider state are unproven. | An older open Session, provider drift, skipped backend release, or later guard regression could still make reporting, refunds, and local payment confirmation disagree. | Privately inventory pre-change Sessions/provider settings, release through the protected gate, verify Firebase and Stripe separately, and keep every adjustment disabled until an approved authoritative model exists. | @@ -85,9 +85,9 @@ The findings below describe the repository at the start of the 2026-07-12 assess | RISK-033 | CSV export mitigates formula injection, but roster export has no explicit re-auth, download audit, row limit/streaming limit, or data-minimization profiles. | Add scoped exports, reason/re-auth, audit, minimum columns, safe filename IDs, and large-export controls. | | RISK-034 | Webhook error response includes the Stripe library's signature error detail. | Return generic client errors; keep sanitized structured diagnostics server-side. | | RISK-035 | The deterministic frontend Jest suite and standalone SPA callback suite run as separate blocking hosted CI steps. CI-001B4/#186 merged a non-mutating frontend lint gate as `bec7d5e365eacb418563a172029f241f660d9768`; exact PR and post-merge runs passed. CI-001B4A [#227](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/227) removes one reviewed `arrow-body-style` error, CI-001B4B [#239](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/239) removes one stale `AdminMembers` unknown-rule suppression record, and PAY-004C1 [#359](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/359) retires one `no-alert` warning plus two label-association errors with the unsafe reusable-link controls. Reviewed functional changes in [PR #391](https://github.com/Run-MPRC/Run-MPRC.github.io/pull/391) and [PR #392](https://github.com/Run-MPRC/Run-MPRC.github.io/pull/392) add one and two TypeScript files respectively while retiring two TSX errors each. CI-001B4C [#449](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/449) replaces the four remaining stale `react-hooks/exhaustive-deps` directives with ordinary same-line comments, without changing executable code or the gate. MEMBERS-CONTENT-001B [#492](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/492) removes one finding-free dormant JSX file. MEMBERS-DIRECTORY-001A [#505](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/505) adds four finding-free TypeScript/TSX files, MEMBERS-DIRECTORY-001B [#506](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/506) adds four more, WEB-SUGGESTIONS-001A [#618](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/618) adds one finding-free JSX page, and MEMBERS-DIRECTORY-001D [#621](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/621) adds one finding-free TypeScript availability module. The current baseline scans 120 files and still records 113 configured errors and 6 warnings after the lint process disables the repository's severity-masking `eslint-plugin-only-warn` hook. Branch protection, remaining lint-debt cleanup, and broader domain/integration coverage remain incomplete. | Continue reducing the reviewed finding baseline in focused changes, prove required branch checks, and add domain/integration coverage. Never regenerate the baseline merely to make CI green. | -| RISK-036 | #135 adds a manual exact-commit source gate, fixed profile-recovery targets, backend-first order, missing-config failure, and ordinary Git-triggered Netlify production containment. WEB-UX-001A [#457](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/457) used a temporary exact-artifact exception. On 2026-08-01 an overbroad WEB-002A artifact was merged after a late blocker and published; exact rollback merge `1099ee8` restored source `ed1b0833`, and `dee7951` paused the manifest. Bounded replacement [#473](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/473) then published exact source `39ab8649` as deploy `6a6dc9ea588b0c0008036312`; its delta is only Shop and Events/Calendar failure containment, and its public checks passed. Final control `cb6a8f0` made the manifest inactive; Netlify attempt `6a6dcdd47bc81e000859a249` stopped unpublished and left that bounded deploy as #623's rollback. WEB-002C [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) then completed one exact-artifact release: merge `9d5cc8612b4321172370bd949d307e7e4ac0ec7d` published frozen inert source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, 62 files, and digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1` as deploy `6a7e072f8f346b0008510d29`. Signed-out marker, route, guard, and no-connected-symbol/request checks passed. Repause merge `c8678c623afdd9becf77d596b71f36f26f04b746` made the manifest inactive; attempt `6a7e081e73fdd60009f7ba57` stopped unpublished and retained the verified deploy. The release source is absent and the rollback ref remains. Protected environments/OIDC, isolated staging, a reusable live-Netlify path, and provider-owned atomic rollback remain unverified. | Require a final blocker re-read and an executable delta from the live artifact before every release merge. Preserve the exact #473 rollback evidence, keep ordinary publication paused, and keep the reviewed Git rollback projection available. Treat #623 as a completed one-off, not a reusable control. Complete #133 and #136, provision isolated staging, protect the reusable Netlify release path under WEB-001, and rehearse provider rollback before broader production work. | +| RISK-036 | #135 adds a manual exact-commit source gate, fixed profile-recovery targets, backend-first order, missing-config failure, and ordinary Git-triggered Netlify production containment. WEB-UX-001A [#457](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/457) used a temporary exact-artifact exception. On 2026-08-01 an overbroad WEB-002A artifact was merged after a late blocker and published; exact rollback merge `1099ee8` restored source `ed1b0833`, and `dee7951` paused the manifest. Bounded replacement [#473](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/473) then published exact source `39ab8649` as deploy `6a6dc9ea588b0c0008036312`; its delta is only Shop and Events/Calendar failure containment, and its public checks passed. Final control `cb6a8f0` made the manifest inactive; Netlify attempt `6a6dcdd47bc81e000859a249` stopped unpublished and left that bounded deploy as #623's rollback. WEB-002C [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) then completed one exact-artifact release: merge `9d5cc8612b4321172370bd949d307e7e4ac0ec7d` published frozen inert source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, 62 files, and digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1` as deploy `6a7e072f8f346b0008510d29`. Signed-out marker, route, guard, and no-connected-symbol/request checks passed. Repause merge `c8678c623afdd9becf77d596b71f36f26f04b746` made the manifest inactive; attempt `6a7e081e73fdd60009f7ba57` stopped unpublished and retained the verified deploy. The release source is absent and the rollback ref remains. Protected environments/OIDC, backend/provider staging, a reusable live-Netlify path, and provider-owned atomic rollback remain unverified; #665 proves only the static host. | Require a final blocker re-read and an executable delta from the live artifact before every release merge. Preserve the exact #473 rollback evidence, keep ordinary publication paused, and keep the reviewed Git rollback projection available. Treat #623 as a completed one-off, not a reusable control. Complete #133 and #136, extend #665 into protected backend/provider staging, protect the reusable Netlify release path under WEB-001, and rehearse provider rollback before broader production work. | | WEB-002D completed exact-artifact containment for RISK-036 | [#659](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/659) completed one accessibility-only release on 2026-08-14. Exact release merge `46e23647d8e0bf9fa3a574ea5c5f993be10a419d` published deploy `6a7ece87c5ca4d0007c1a3fc`; its marker and all 62 artifact paths matched frozen source `7496fe0881fb52908c4ff2f40f488df09c94c908`, tree `ccac4c189c195db8ab594e0eefe256ea9fa04996`, digest `e4c26e6f0fbcd086663d86238675f0be228fb649a00628c1c97d1166612f49c7`, and exact six-path diff digest `462eeb01e7a9858678802464f7dd4b76cd2fcb3c13be827efb4f98fa53ca809c`. Signed-out desktop and phone route-focus/menu checks passed. Repause merge `3138a00c1c48e1d5d1dcda0b44722b09a2194ff7` passed exact-main CI run `31783808994`; attempt `6a7ed0ddb00a46000818878d` stayed unpublished and retained the verified deploy. Literal-false directory availability, Firebase, Rules, Functions, indexes, outside-provider configuration, accounts, sign-in, production data, payments, and connected directory behavior were unchanged. | The manifest is inactive; source/control/repause refs are absent; rollback ref `codex/netlify-source-659-rollback` remains pinned to #623 source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`. Treat #659 as a completed one-off, not reusable authority. Keep ordinary publication paused, preserve #507 connected-directory gates, and preserve active #616 OAUTH-001A2L files and its RISK-024 wording byte-for-byte. | -| WEB-001A1 source foundation for RISK-010 and RISK-036 | [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) adds a dependency-free hosted-build contract, complete environment-explicit browser configuration, executable staging-artifact identity scan, a demo-only Firebase CLI default, and an inert Firebase Hosting SPA rewrite. Missing/unsupported hosted environments, incomplete or malformed staging fields, known production identities in staging, and non-exact production public configuration fail closed. | This is source and synthetic artifact proof only. It creates no staging/Hosting resource, WIF/IAM identity, protected branch/environment, automatic deployment, release marker, provider readback, rollback, header policy, custom domain, DNS/TLS change, Firebase deployment, website publication, or live protection. Complete #113/#133 and the remaining #460 children before any staging or production claim. | +| WEB-001A1/A2 boundary for RISK-010 and RISK-036 | [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) adds the dependency-free hosted-build contract and Hosting rewrite. [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) adds one club-owned staging project, web app, finalized static Hosting release, provider readback, and signed-out desktop/phone route checks from exact source `a614c68`. | This proves static engineering staging only. It creates no staging backend/provider isolation, App Check, WIF/IAM identity, protected branch/environment, automatic deployment, release marker, tested predecessor rollback, complete header policy, custom domain, DNS/TLS change, production Hosting, `runmprc.com` publication, or live protection. Complete #113/#133 and the remaining #460 children before any end-to-end staging or production claim. | | RISK-037 | Account/registration deletion, export, retention, backup, and restore procedures are incomplete. | Approve retention matrix, automate minimization, support access/deletion requests, and test backup restoration. | | RISK-038 | Source-controlled secret scan is ad hoc; no continuous secret scanner, dependency update bot, SBOM, provenance, or branch protection is documented. | Add secret/dependency/code scanning, reviewed lockfile updates, protected environments/branches, and artifact provenance appropriate to project scale. | | RISK-039 | Some authenticated accounts can lack `members/{uid}` after the Firebase cutover; the account screen hid the read failure and exposed an update that could only fail. Manual database/account repair could corrupt roles or private data. | Use an authenticated create-once server bootstrap, keep browser creation denied, fail the UI closed, and prove backend-first deployment with synthetic accounts. | @@ -132,7 +132,7 @@ These entries are implementation evidence, not a production risk-acceptance deci | RISK-001, RISK-002, RISK-034 | PAY-003A [#101](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/101) source merged as `87bd1210575882cdd06214bcb98ed38ce00f71c2`, adding durable Stripe Event deduplication, transactional transition/processed marking, paid/amount/currency/Checkout-mode/reference-shape and explicitly configured livemode checks, async outcomes, monotonic refund/terminal guards, quarantine, generic signature failures, and a webhook-secret-only binding. | Firebase was not deployed. Complete CONFIG/PAY-001/PAY-002 contracts, metadata schema allowlist/migration, canonical reducers/reservations/outbox, retry/dead-letter/TTL/alerts, emulator integration, Stripe test-mode rehearsal, protected deploy, and reconcile. | | RISK-006, part of RISK-024/RISK-032 | #100 merged at `a7fc301e85b0aeabe396e771faea21d3fc8e7b2b`. OAuth secrets and server-owned financial/operational collections are denied; current catalog writes are restricted to inert drafts/display fields. | Firebase deployment skipped. Stage/deploy the exact Rules revision under #105, verify synthetic deny behavior, then move remaining catalog mutation to scoped APIs under ADMIN-001. | | RISK-009 | #99 preserves same-origin path, query, and fragment state through the Pages fallback, clears temporary state, rejects unsafe targets, and suppresses monitoring startup on initial capability callbacks. #126 adds the standalone suite as the named blocking `Run SPA callback safety tests` hosted step. | Keep exact hosted evidence on #126; verify exact website publication and later run approved test-mode Stripe/Strava callbacks; WEB-001 still owns controlled hosting. | -| RISK-010 | #99 uses a fully synthetic `demo-mprc-local` configuration, connects Functions/Auth/Firestore to loopback in development/test, routes the direct CSV Function URL locally, fails startup on connector errors, and completed a demo-only three-port CLI smoke. WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) adds explicit hosted selection and synthetic staging executable-artifact proof with no production Firebase identity. | #663 is not a deployed staging environment and does not isolate provider calls made by Functions. Complete #113/#133, an owned staging Hosting site, protected short-lived deployment, provider test keys/sinks, exact marker/readback, and rollback evidence before end-to-end flows. | +| RISK-010 | #99 uses a fully synthetic `demo-mprc-local` configuration, connects Functions/Auth/Firestore to loopback in development/test, routes the direct CSV Function URL locally, fails startup on connector errors, and completed a demo-only three-port CLI smoke. WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) adds explicit hosted selection and synthetic staging executable-artifact proof with no production Firebase identity. WEB-001A2 [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) adds the owned static staging site and provider readback. | Static Hosting does not isolate backend or provider calls made by Functions. Complete #113/#133 protected short-lived deployment and backend/provider staging, then prove test keys/sinks, exact marker/readback, and rollback before end-to-end flows. | | Test-only foundation for RISK-010 and RISK-035 | TEST-001A1 is tracked in live [#175](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/175). The Functions Jest setup installs a fixed-error, loopback-only guard around supported Node outbound transports and rejects any supplied production-like project/origin/emulator host or live Stripe mode/key. Shared deterministic deeply frozen fixtures use reserved values, and the existing webhook suite adopts one synthetic signed-payload helper. | This is a test-process boundary, not a runtime sandbox. It does not intercept every possible native/add-on transport, isolate an emulated Function process, configure a test provider, scan emitted artifacts, deploy Firebase, or prove live behavior. TEST-001A2 [#177](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/177) separately adds the bounded artifact scrubber and named CI/release gate; later TEST-001 children must add emulator sagas and isolated staging evidence. | | Emitted-test-output part of RISK-035 | TEST-001A2 is tracked in live [#177](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/177). Its source adds a dependency-free read-only scanner for explicit narrow artifact roots, bounded deterministic traversal, fixed redacted failures, deliberate synthetic allow/deny tests, the exact `Test artifact scrubber` CI job, and that job in both protected-release CI rechecks. Current CI still uploads no test artifact. | This scanner covers a documented bounded set of recognizable patterns; green is not a general data-loss-prevention guarantee or proof that every unknown/obfuscated value is absent. It does not inspect source, runtime logs, website builds, provider responses, production data, or an operating-system sandbox, and it does not sanitize a rejected file. Every later report producer must invoke the scanner before upload, and exact hosted evidence remains separate from source and local-test evidence. | | Configuration part of RISK-001/RISK-010 | CONFIG-001A [#149](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/149) merged through PR #150 as `2c62b8dd`, requiring an exact environment/origin/expected Stripe mode, key-mode compatibility on the four key-bound Functions, no production-origin fallback, and no Stripe API key on webhook/mail. CONFIG-001B1 [#151](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/151) adds exact `COMMERCE_ENABLED` parsing. A false ceiling denies new commerce before Firestore; otherwise new-commerce commands and every refund perform a fresh strict server-only global/domain/resource admission read. Missing controls/resource flags mean disabled; fixed errors expose no supplied value; Rules tests deny browser control; webhook/mail remain independent. | Neither source result configures or deploys Firebase/Stripe. B1 cannot stop already-admitted commands or existing Sessions/Payment Links and has no safe operator writer. CONFIG-001B2, PAY-002/PAY-004/PAY-005, and #105/#133/#136 retain protected control, expiry/reconciliation, staging, deployment, provider readback, and drill. No live payment or email is authorized. | diff --git a/SYSTEM_DESIGN.md b/SYSTEM_DESIGN.md index a564506..996371f 100644 --- a/SYSTEM_DESIGN.md +++ b/SYSTEM_DESIGN.md @@ -97,7 +97,7 @@ The former workflow automatically published Pages before attempting Firebase and WEB-002D [#659](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/659) completed one exact-artifact exception on 2026-08-14. Pinned preview `6a7ec998bf8fde00086d2bfe` matched control `137d8a8721339a6ca1079283cc34c1bd7cc2706c`. Exact release merge `46e23647d8e0bf9fa3a574ea5c5f993be10a419d` published deploy `6a7ece87c5ca4d0007c1a3fc` from source `7496fe0881fb52908c4ff2f40f488df09c94c908`, tree `ccac4c189c195db8ab594e0eefe256ea9fa04996`, 62 files, and artifact digest `e4c26e6f0fbcd086663d86238675f0be228fb649a00628c1c97d1166612f49c7`; the exact six-path predecessor diff digest was `462eeb01e7a9858678802464f7dd4b76cd2fcb3c13be827efb4f98fa53ca809c`. Signed-out desktop route-focus and phone menu/route-focus checks passed. Repause merge `3138a00c1c48e1d5d1dcda0b44722b09a2194ff7` passed exact-main CI `31783808994`; attempt `6a7ed0ddb00a46000818878d` stayed unpublished and retained the verified deploy. The manifest is inactive; temporary refs are absent; #623 deploy `6a7e072f8f346b0008510d29` is the rollback target. #659 changed no route set, content, Firebase surface, outside-provider configuration, account, sign-in state, production data, payment, or directory behavior; directory availability remains literal `false` and #507 still owns connection. -**WEB-001A1 Firebase Hosting foundation — SOURCE ONLY, NOT DEPLOYED:** [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) makes every controlled optimized browser build select `staging` or `production` explicitly. Local/test still use only `demo-mprc-local` and all three loopback emulators. A staging build requires a complete public Firebase web configuration whose project name has a `staging` boundary; both the browser startup boundary and build contract reject production-equal identities, and CI scans executable JavaScript for every selected staging field and absence of known production Firebase identities. Production requires the exact reviewed public web configuration. `firebase.json` now describes `build/`, a missing-path rewrite to `/index.html`, and a predeploy chain that binds the selected web configuration to Firebase CLI's exact `GCLOUD_PROJECT`, rebuilds, and scans the artifact before upload. `.firebaserc` defaults to the non-deployable demo namespace. This source does not create a Firebase Hosting site or channel, provision staging, authenticate to Google Cloud, protect `production-web`, publish a marker, change a custom domain, deploy Firebase, alter Netlify/Pages, or change `runmprc.com`. The current live topology and release diagram below therefore remain unchanged. +**WEB-001A1/A2 Firebase Hosting foundation and isolated static staging:** [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) makes every controlled optimized browser build select `staging` or `production` explicitly. Local/test still use only `demo-mprc-local` and all three loopback emulators. A staging build requires a complete public Firebase web configuration whose project name has a `staging` boundary; both the browser startup boundary and build contract reject production-equal identities, and CI scans executable JavaScript for every selected staging field and absence of known production Firebase identities. Production requires the exact reviewed public web configuration. `firebase.json` describes `build/`, a missing-path rewrite to `/index.html`, and a predeploy chain that binds the selected web configuration to Firebase CLI's exact `GCLOUD_PROJECT`, rebuilds, and scans the artifact before upload. `.firebaserc` defaults to the non-deployable demo namespace. On 2026-08-26, [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) created club-owned project `run-mprc-staging`, one web app, and finalized Hosting version `3ffadcf2ac8cc760` from exact merged source `a614c68d9a1a2be631a3be874a686d61e5d170a0`. Provider and rendered checks passed for [run-mprc-staging.web.app](https://run-mprc-staging.web.app), static assets, direct `/events`, desktop, and phone navigation; the empty staging data surface settled without an error. This is signed-out static visual staging only. It does not configure App Check, Auth test users, Firestore, Functions, Rules, indexes, Storage data, outside-provider sandboxes, protected short-lived authority, `production-web`, a release marker, tested predecessor rollback, response-header policy, custom domains, DNS/TLS, Netlify/Pages, production Hosting, or `runmprc.com`. ```mermaid flowchart TD @@ -1720,7 +1720,7 @@ Returning a `2xx` response to Stripe means the event has been durably accepted o | --- | --- | --- | --- | --- | | Local source runtime | Firebase Emulator Suite under `demo-mprc-local` | Not safe by Firebase emulation alone | `localhost:3000` | Synthetic data only; browser Firebase traffic is loopback-only | | CI | Ephemeral emulators and mocks | Stripe fixtures/signature tests; optional isolated test account | None | Synthetic data, no production secrets | -| Staging | Dedicated non-production Firebase project | Stripe sandbox/test keys and its own webhook endpoint | `dev.runmprc.com` | Synthetic or consented test records only | +| Staging | `run-mprc-staging`; static Hosting and one web app only | Not configured; no provider testing authorized | `run-mprc-staging.web.app`; `dev.runmprc.com` not configured | Signed-out public visual review only; no real data | | Production | Dedicated production Firebase project | Live restricted keys and production webhook secret | `runmprc.com` | Real data under documented retention and access policies | ```mermaid @@ -1741,9 +1741,9 @@ Text alternative: the local browser uses only the three loopback Firebase emulat #99 source selects a fully synthetic Firebase configuration for development/test, connects Auth, Firestore, and Functions to the loopback ports above, stops startup when connection setup fails, and leaves App Check, Analytics, and Sentry off locally. #139 additionally keeps Firebase Analytics off in every source environment and removes the direct Waiver SDK bypass pending an approved #110 policy. The Firebase CLI must still report all three emulators ready before the app is opened. Mocked endpoint tests alone do not prove listening processes, website publication, provider behavior, or deletion of earlier provider data/cookies. -Optimized builds must select `staging` or `production` explicitly. WEB-001A1 #663 rejects missing, local, incomplete, or cross-environment Firebase web configuration, and its artifact check rejects known production identities from a staging executable. Ordinary Netlify deploy previews receive and scan only the reserved synthetic staging configuration; the pinned release builder receives and scans the exact reviewed public production web configuration. Source separation does not create an owned staging project or isolate outside providers, so previews remain restricted to public, read-only visual review until #105/CONFIG supplies protected staging evidence. Do not sign in, open private/admin pages, or test Firebase/provider actions in those previews. +Optimized builds must select `staging` or `production` explicitly. WEB-001A1 #663 rejects missing, local, incomplete, or cross-environment Firebase web configuration, and its artifact check rejects known production identities from a staging executable. Ordinary Netlify deploy previews receive and scan only the reserved synthetic configuration; `run-mprc-staging.web.app` receives and scans the real isolated staging web-app identity; the pinned release builder receives and scans the exact reviewed public production web configuration. The owned static staging project does not by itself isolate outside providers or create a backend test estate, so both preview types remain restricted to public, signed-out, read-only visual review until #105/CONFIG supplies protected backend/provider evidence. Do not sign in, open private/admin pages, or test Firebase/provider actions in those previews. -`SITE_ORIGIN`, Firebase project IDs, App Check keys, Stripe keys, webhook endpoints, Sentry environments, and email providers must be environment-scoped. Live and test webhook secrets are never interchangeable. The repository still needs an explicit staging project before end-to-end rollout. +`SITE_ORIGIN`, Firebase project IDs, App Check keys, Stripe keys, webhook endpoints, Sentry environments, and email providers must be environment-scoped. Live and test webhook secrets are never interchangeable. `run-mprc-staging` now supplies only the public web-app and Hosting boundary; end-to-end rollout still needs protected staging backend/provider configuration and evidence. CONFIG-001A [#149](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/149) adds the source boundary for current commerce and confirmation-mail Functions: local is exact loopback, tests use HTTPS `.test`, staging is exactly `https://dev.runmprc.com`, and production is exactly `https://runmprc.com`. Test/live expected mode must match the server-key marker on the four key-bound Functions. Webhook and mail receive no Stripe API key, and invalid settings stop before rate-limit, business, mail, event-ledger, or Stripe writes. This source boundary does not create staging, configure Secret Manager or Stripe, deploy Firebase, enable commerce, or prove live behavior. diff --git a/docs/officers/ACCESS_CONTINUITY.md b/docs/officers/ACCESS_CONTINUITY.md index 40f95de..d076ef3 100644 --- a/docs/officers/ACCESS_CONTINUITY.md +++ b/docs/officers/ACCESS_CONTINUITY.md @@ -38,7 +38,7 @@ Until those six steps are recorded, this guide does not claim incapacitation cov | Club email provider | Notices and password recovery | Communications owner plus backup | | Social/community accounts | Public communication and member groups | Named owner plus backup | -WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) adds fail-closed Firebase Hosting build source, not service ownership. Continuity still requires two individual limited-access Firebase/Google Cloud administrators, an approved staging project, short-lived release identity, protected reviewers, and a tested rollback. Do not create an unofficial personal project to make the source checks pass. +WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) adds fail-closed Firebase Hosting build source. WEB-001A2 [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) records that the club account can reach production and owns the dedicated `run-mprc-staging` project and its static Hosting site. Continuity is still incomplete: name a second individual limited-access Firebase/Google Cloud administrator, configure the short-lived release identity and protected reviewers, and rehearse rollback after a second staging release exists. Do not create another project or use a personal project as a shortcut. ## Release access to record privately @@ -49,7 +49,7 @@ Record these facts without copying a credential or private provider identifier: 3. Name two reviewers for the protected `staging` environment. 4. Name two reviewers for the protected `production` environment. 5. Record that `Protected release` is the approved GitHub workflow. -6. Record the fixed environment-to-Firebase-project map. +6. Record the fixed environment-to-Firebase-project map: local `demo-mprc-local`, engineering staging `run-mprc-staging`, and production `mid-peninsula-running-club`. 7. Record the fixed release plans and named resources. 8. Record the owner of the short-lived cloud identity and its revocation procedure. 9. Record the latest missing-authority failure drill. diff --git a/docs/officers/EMERGENCY_AND_RECOVERY.md b/docs/officers/EMERGENCY_AND_RECOVERY.md index f6629c5..cbf45f5 100644 --- a/docs/officers/EMERGENCY_AND_RECOVERY.md +++ b/docs/officers/EMERGENCY_AND_RECOVERY.md @@ -26,7 +26,7 @@ | Symptom | Safe first response | | --- | --- | | Wrong public text, image, or link | Ask the platform owner for one reviewed revert pull request. | -| Site unavailable or old after a merge | Ask the platform owner to check Netlify and GitHub Pages separately; do not change DNS. #663 Firebase Hosting source is not a live host. | +| Site unavailable or old after a merge | Ask the platform owner to check Netlify, GitHub Pages, production Firebase Hosting, and engineering staging separately; do not change DNS. `run-mprc-staging.web.app` is not production or a `runmprc.com` fallback. | | Login or member access is wrong | Stop role requests and contact the identity/platform owners. | | Account exists but a verification email request is unavailable | Ask the member to stop resending. Record only the time, route path `/login` or `/account`, and plain status. Omit all query/fragment text. Do not ask for the email address, password, code, action link, mailbox access, or screenshot. | | Verification link is unusable or temporarily unavailable | Ask the member to stop after one deliberate check and one retry. Record only the time, clean route `/auth/action`, and plain result. Never copy anything after `?` or `#`, and never ask for the link, code, email address, or screenshot. | @@ -38,7 +38,7 @@ Live commerce is not approved as of 2026-07-12. If the public site appears to accept a real payment, do not test it with a real card. -Firebase Hosting recovery is **NOT AVAILABLE YET**. WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) adds source configuration only. Do not switch DNS, create a personal Firebase project, run a deploy, or assume Firebase Hosting is a fallback during an incident. Use the verified Netlify/Pages evidence and contact the platform owner plus backup. +Production Firebase Hosting recovery is **NOT AVAILABLE YET**. WEB-001A2 [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) publishes [run-mprc-staging.web.app](https://run-mprc-staging.web.app) for signed-out engineering review only. Its first release has no predecessor rollback, and disabling or replacing it is a platform-specialist action that has not been rehearsed. Do not switch DNS, sign in, enter data, run a deploy, or assume staging is a `runmprc.com` fallback during an incident. Use the verified Netlify/Pages evidence and contact the platform owner plus backup. ### Unexpected “Something went wrong” page — SOURCE ONLY, NOT LIVE diff --git a/docs/officers/GLOSSARY.md b/docs/officers/GLOSSARY.md index 3fb1bc5..05b522d 100644 --- a/docs/officers/GLOSSARY.md +++ b/docs/officers/GLOSSARY.md @@ -23,7 +23,7 @@ | Projection | A minimum server-only copy made for one approved task, such as finding an opted-in display name, without sending the full account record to the browser. | | Facial recognition | Automated processing that tries to identify or match a person from an image. The MPRC People finder does not do this and cannot accept a photo as a search. | | Firebase | The service used for login, database records, and backend Functions. | -| Firebase Hosting | Google's static website host. MPRC has source configuration for a future site, but no verified staging or production Firebase Hosting release yet. | +| Firebase Hosting | Google's static website host. MPRC has a verified engineering staging release, but no officer-controlled or production Firebase Hosting release yet. | | Firestore | The database inside Firebase. Saving an Admin form can change its records immediately. | | Function | A protected backend action, such as checking access or handling a payment event. | | Netlify | The service currently answering requests for `runmprc.com`. | @@ -34,7 +34,7 @@ | Service account | A non-human account used by automation. Its key is a secret and must have limited access. | | Two-factor authentication (2FA) | A second sign-in check, preferably a passkey, authenticator, or hardware key rather than a text message. | | Least privilege | Giving a person or service only the access needed for its job. | -| Staging | A separate safe environment used to test before production. MPRC does not yet have a proven isolated staging environment. | +| Staging | A separate environment used to test before production. MPRC has isolated static website staging, but its login, database, Functions, and outside-provider test environment are not proven yet. | | Index | A database helper that makes an approved query work. It is not the website home page. | | Test mode | A safe provider mode that uses fake payments and test data. | | Rollback or revert | A reviewed change that restores the last known-good version. | diff --git a/docs/officers/PUBLISH_AND_CHECK.md b/docs/officers/PUBLISH_AND_CHECK.md index 6abd358..5824c35 100644 --- a/docs/officers/PUBLISH_AND_CHECK.md +++ b/docs/officers/PUBLISH_AND_CHECK.md @@ -10,7 +10,7 @@ **Protected release status:** **NOT AVAILABLE YET.** Issue #135 provides the fail-closed source gate. Issue #133 must still configure protected `staging` and `production` environments, their named reviewers, and a short-lived cloud identity. Public browser build values must be named repository or organization variables because artifact preparation has no protected-environment access; #133/#136 must record and verify them separately. Do not add a long-lived Firebase key as a shortcut. -**Firebase Hosting status:** **SOURCE ONLY, NOT AVAILABLE YET.** WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) requires controlled optimized builds to name staging or production, scans CI's synthetic staging JavaScript for the staging project and absence of production Firebase identities, and adds a missing-path SPA rewrite to source. It creates no Firebase Hosting site/channel, staging project, cloud authority, protected web-production branch, automatic publication, release marker, rollback, custom domain, or DNS/TLS change. Officers do not use its source configuration as a publish button. +**Firebase Hosting status:** **ENGINEERING STAGING AVAILABLE; OFFICER AND PRODUCTION RELEASE NOT AVAILABLE YET.** WEB-001A1 [#663](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/663) requires controlled optimized builds to name staging or production and scans executable JavaScript for environment identity. WEB-001A2 [#665](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/665) created the club-owned `run-mprc-staging` project and published exact merged source `a614c68d9a1a2be631a3be874a686d61e5d170a0` to [run-mprc-staging.web.app](https://run-mprc-staging.web.app). The site is for signed-out public visual review only. It has no approved staging backend/provider data, App Check key, protected short-lived publication, release marker, tested predecessor rollback, complete security headers, custom domain, or DNS/TLS change. Officers do not sign in, enter information, or use the site as a publish control. Production Firebase Hosting remains empty, and Netlify still serves `runmprc.com`. **Live Netlify publication status:** a reusable protected release is **NOT AVAILABLE YET**. Ordinary Git-triggered production builds are paused by repository configuration. An overbroad #473 artifact was published and then rolled back on 2026-08-01; bounded #473 deploy `6a6dc9ea588b0c0008036312` is older history. #623 completed the inert-directory predecessor and remains the immediate rollback as deploy `6a7e072f8f346b0008510d29`, source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`. #659 completed one separate exact-artifact accessibility release. Deploy `6a7ece87c5ca4d0007c1a3fc`, source `7496fe0881fb52908c4ff2f40f488df09c94c908`, is production now. Its exact marker/artifact and signed-out route-focus/menu checks passed. The manifest is inactive, temporary refs are absent, and the rollback ref remains. Shop is the static catalog; Events and Calendar show a fixed retry-later notice; the directory remains inert. Event records remain unavailable because this did not deploy Firebase. GitHub Pages currently still claims the same custom domain; future source omits that claim, but #136/WEB-001 must publish and verify its removal. @@ -59,8 +59,8 @@ As of **2026-07-13**, with the internal tooling note below checked from source o - Source checked on 2026-07-22 pins the internal Firebase CLI to 15.24.0, and its emulator checks use Java 21. Officers do not install or run either tool; the platform maintainer owns them. This source change does not alter the release diagram or prove that Firebase was deployed. The provider and live-host facts below were not reverified for this tooling update. - Source checked on 2026-08-01 pins every root brace-expansion dependency family to reviewed compatible releases 1.1.18, 2.1.4, and 5.0.9 after a new advisory and follow-up bypass fixes. This is internal dependency evidence only. Officers do not install packages, run audit commands, or resolve dependency warnings; the platform maintainer owns those tasks. The separate minimatch finding remains open. This source change does not publish a website, deploy Firebase, change a provider, or prove live behavior. - A production Pages publication job cannot start until Firebase deployment and Function verification succeed. -- The `staging` option deliberately stops before deployment until #113/#133 name one exact approved staging Firebase project. A future staging release remains backend-only until a separate staging browser configuration and host exist. -- #663 source requires complete staging-named public browser configuration and gives CI a synthetic staging artifact scan. This does not satisfy the approved-project or hosted-staging requirements above. +- The club-owned `run-mprc-staging` project now supplies one static signed-out Hosting surface. Its first release is exact source `a614c68d9a1a2be631a3be874a686d61e5d170a0`; direct `/events` rewriting and desktop/phone public rendering passed. +- #663 source requires complete staging-named public browser configuration and gives CI a synthetic staging artifact scan. #665's provider readback proves only the static staging host. It does not supply protected authority, backend/provider isolation, App Check, a release marker, predecessor rollback, or permission to test sign-in/private/admin/commerce behavior. - `runmprc.com` is served by Netlify, not GitHub Pages. - GitHub Pages currently reports `runmprc.com` as its custom domain and redirects its normal address there. It is not an independently reachable copy today. - Future source stops writing that Pages domain claim. Only provider readback after #136/WEB-001 can prove it cleared. diff --git a/docs/officers/SYSTEM_MAPS.md b/docs/officers/SYSTEM_MAPS.md index f9cf4cd..3d42005 100644 --- a/docs/officers/SYSTEM_MAPS.md +++ b/docs/officers/SYSTEM_MAPS.md @@ -87,7 +87,9 @@ flowchart TD Functions --> Pages["Pages branch without Netlify's domain claim"] Main -. "Ordinary Git production build paused" .-> Netlify Main --> HostingSource["#663 Firebase Hosting source checks"] - HostingSource -. "No owned project, authority, or deploy" .-> FutureHosting["Firebase Hosting — NOT AVAILABLE YET"] + HostingSource --> StagingHosting["run-mprc-staging.web.app\nengineering staging only"] + StagingHosting -. "No backend/provider test estate, protected authority, marker, or rollback" .-> Stop + HostingSource -. "Production branch, headers, authority, and cutover missing" .-> FutureHosting["Production Firebase Hosting — NOT AVAILABLE YET"] Main -. "Completed #659 exact release; manifest inactive" .-> WebGate{"Temporary authority active?"} WebGate -- "No" --> Stop WebGate -- "Yes" --> Netlify @@ -96,7 +98,7 @@ flowchart TD Dev["dev — legacy branch"] -. "do not use for new release work" .-> PR ``` -In words: merge, release request, and protected approval are separate; a missing or failed Firebase gate publishes nothing; #663 adds only source checks and points to no usable Firebase Hosting project; ordinary merges cannot publish Netlify and the completed #659 exception is inactive; its deploy `6a7ece87c5ca4d0007c1a3fc` remains live while completed #623 deploy `6a7e072f8f346b0008510d29` is the immediate rollback and completed #473 deploy `6a6dc9ea588b0c0008036312` is older history; the future Pages branch must stop claiming the Netlify domain, and every host still needs separate proof. +In words: merge, release request, and protected approval are separate; #663 supplies the build checks and #665 publishes only the club-owned signed-out engineering staging site; that staging site cannot release production or authorize backend/provider testing. Ordinary merges cannot publish Netlify and the completed #659 exception is inactive; its deploy `6a7ece87c5ca4d0007c1a3fc` remains live while completed #623 deploy `6a7e072f8f346b0008510d29` is the immediate rollback and completed #473 deploy `6a6dc9ea588b0c0008036312` is older history; the future Pages branch must stop claiming the Netlify domain, and every host still needs separate proof. ## Account and permission ownership