diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md index d32b523..63e33cf 100644 --- a/IMPLEMENTATION_PLAN.md +++ b/IMPLEMENTATION_PLAN.md @@ -28,7 +28,7 @@ MPRC can open a race or merchandise item for sale only when the platform can: 3. Schema changes are additive first. Backfills are idempotent, dry-runnable, and report counts/anomalies. 4. Backend/rules/indexes deploy before dependent clients. Legacy reads remain until migration evidence is complete. 5. No issue requires production secrets for development or CI. -6. Live-mode enabling is a separate protected operation. #135 supplies a manual, exact-commit, backend-first source gate and pauses ordinary Git-triggered Netlify production builds. WEB-UX-001A [#457](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/457) used one temporary web-only exception that required one exact `main` parent and independently verified one pinned source commit/tree. An overbroad WEB-002A attempt was rolled back on 2026-08-01; bounded replacement [#473](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/473) then published only the static Shop and fixed Events/Calendar failure messages as exact deploy `6a6dc9ea588b0c0008036312` from source `39ab8649df411262c8109a3c81a57bc38f1e168b`. Its public marker and page checks passed, and its temporary manifest became inactive again. WEB-002C [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) is now an active one-shot under review for one frozen inert member-directory interface artifact: source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, 62 files, digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`, and expected first parent `019353361210021483f23003e09ee6924b78e67c`. Until exact preview, merge, signed-out production readback, and immediate repause pass, #473 remains production and its deploy is the rollback target. #623 does not restore event records or authorize Firebase, providers, sign-in, production data, connected directory behavior, commerce, or a reusable release path. Protected environment/OIDC configuration, staged/live proof, fail-closed lint, required checks, and a protected live-Netlify path remain open under #105/#133/#136/WEB-001. +6. Live-mode enabling is a separate protected operation. #135 supplies a manual, exact-commit, backend-first source gate and pauses ordinary Git-triggered Netlify production builds. WEB-UX-001A [#457](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/457) used one temporary web-only exception that required one exact `main` parent and independently verified one pinned source commit/tree. An overbroad WEB-002A attempt was rolled back on 2026-08-01; bounded replacement [#473](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/473) then published only the static Shop and fixed Events/Calendar failure messages as exact deploy `6a6dc9ea588b0c0008036312` from source `39ab8649df411262c8109a3c81a57bc38f1e168b`. Its public marker and page checks passed, and its temporary manifest became inactive again. WEB-002C [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) completed one bounded release of the frozen inert member-directory interface on 2026-08-13. Exact merge `9d5cc8612b4321172370bd949d307e7e4ac0ec7d` published Netlify deploy `6a7e072f8f346b0008510d29` from source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, 62 files, and digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`. Signed-out guard, route, marker, and no-directory-request checks passed. Repause merge `c8678c623afdd9becf77d596b71f36f26f04b746` made the manifest inactive; its Netlify attempt stopped unpublished and retained the verified deploy. The release source is absent and rollback ref remains. #623 did not restore event records or authorize Firebase, providers, sign-in, production data, connected directory behavior, commerce, or a reusable release path. Protected environment/OIDC configuration, staged/live proof, fail-closed lint, required checks, and a protected live-Netlify path remain open under #105/#133/#136/WEB-001. 7. A provider Console setting is not complete until its non-secret configuration and verification evidence are recorded privately. 8. Security controls fail closed in hosted environments and remain developer-friendly only in explicit local/CI environments. 9. Do not trade payment integrity for UI responsiveness. Confirmation may say “processing”; it must not guess “paid.” @@ -169,7 +169,7 @@ Exit gate: - Payment SLOs, structured redacted logs, and actionable alerts are live. - Backup restoration into isolated infrastructure succeeds and is documented. -**Current optional-directory boundary:** Parent [#504](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/504) defines a private, opt-in officer people finder as name search with voluntary thumbnails—not facial recognition. MEMBERS-DIRECTORY-001A [#505](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/505) owns the signed-in person's server-only processed thumbnail and independent default-off preference. MEMBERS-DIRECTORY-001B [#506](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/506) adds source for the minimum server-only projection, current-state reconciler, bounded verified-admin name-prefix callable, query-free audit, and separate `/admin/member-directory` gallery. It returns at most 24 current opted-in display-name/optional-thumbnail cards and has no image query, facial recognition, cursor, total, export, or membership authority. MEMBERS-DIRECTORY-001D [#621](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/621) makes the shipped frontend boundary default unavailable: My Account and the guarded officer route show only visibly described, disabled layouts and perform zero directory reads, uploads, searches, saves, request-ID creation, or service calls. #623 freezes that inert interface over the current live source for one bounded Netlify release, but it is under review and not published. Protected layout proof remains synthetic; signed-out public proof, if publication later passes, is limited to revision and guard readback plus the absence of a directory request. [#507](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/507) still owns #110 policy completion, scoped authorization, #133 protected authority, isolated staging, required backend/index deployment and readback, and a later separately reviewed source flip before connected website publication and live proof. Do not reuse the current browser-side full-account filter or describe a disabled preview, #623 release candidate, or #505/#506 source as an available directory. +**Current optional-directory boundary:** Parent [#504](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/504) defines a private, opt-in officer people finder as name search with voluntary thumbnails—not facial recognition. MEMBERS-DIRECTORY-001A [#505](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/505) owns the signed-in person's server-only processed thumbnail and independent default-off preference. MEMBERS-DIRECTORY-001B [#506](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/506) adds source for the minimum server-only projection, current-state reconciler, bounded verified-admin name-prefix callable, query-free audit, and separate `/admin/member-directory` gallery. It returns at most 24 current opted-in display-name/optional-thumbnail cards and has no image query, facial recognition, cursor, total, export, or membership authority. MEMBERS-DIRECTORY-001D [#621](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/621) makes the shipped frontend boundary default unavailable: My Account and the guarded officer route show only visibly described, disabled layouts and perform zero directory reads, uploads, searches, saves, request-ID creation, or service calls. #623 published exactly that inert interface as deploy `6a7e072f8f346b0008510d29`; the temporary authority is re-paused. Protected layout proof remains synthetic. Signed-out public proof is limited to revision and guard readback plus the absence of a directory request. [#507](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/507) still owns #110 policy completion, scoped authorization, #133 protected authority, isolated staging, required backend/index deployment and readback, and a later separately reviewed source flip before connected website publication and live proof. Do not reuse the current browser-side full-account filter or describe the published disabled preview or #505/#506 source as an available directory. ### Phase 5 — End-to-end qualification diff --git a/OFFICER_START_HERE.md b/OFFICER_START_HERE.md index 4edd6fa..ebdb60c 100644 --- a/OFFICER_START_HERE.md +++ b/OFFICER_START_HERE.md @@ -46,8 +46,8 @@ Use the club's approved password manager for access. Share only a public link or - **Website live:** Did Netlify identify that commit, and was the exact change then seen on [runmprc.com](https://runmprc.com)? - **Outside service verified:** If Stripe, Netlify, DNS, Google, or email changed, was that service checked separately? -As of **2026-08-13**, a merge runs checks but does not start the GitHub release. The protected release is **NOT AVAILABLE YET** until its short-lived cloud identity and named environment approvers are configured under issue #133. Ordinary Git-triggered Netlify production builds are paused. An overbroad #473 web artifact was published and immediately rolled back. The bounded replacement is still live as Netlify deploy `6a6dc9ea588b0c0008036312` from source `39ab8649df411262c8109a3c81a57bc38f1e168b`: Shop is the static in-person catalog, while Events and Calendar show a fixed retry-later notice instead of a raw provider error. Event records are still unavailable because no Firebase repair was deployed. #623 is a separate one-shot release under review for a frozen inert member-directory interface. It has not published or been verified, and the current #473 deploy is its rollback target. This does not change sign-in, expose protected event offers, add officer editing, or make commerce safe. GitHub Pages still reports `runmprc.com` as its custom domain even though Netlify serves that name; source removal is not provider proof. A green test or workflow does **not** by itself prove that GitHub Pages, `runmprc.com`, Firebase, or that domain setting changed. +As of **2026-08-13**, a merge runs checks but does not start the GitHub release. The protected release is **NOT AVAILABLE YET** until its short-lived cloud identity and named environment approvers are configured under issue #133. Ordinary Git-triggered Netlify production builds are paused. An overbroad #473 web artifact was published and immediately rolled back; its bounded replacement remains the recorded rollback. #623 then completed one separate, exact-artifact release of the inert member-directory interface. Netlify deploy `6a7e072f8f346b0008510d29` is live from source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`. Signed-out route and guard checks passed, no member-directory request was observed, and repause merge `c8678c623afdd9becf77d596b71f36f26f04b746` made the temporary manifest inactive without replacing that deploy. Shop remains the static in-person catalog, while Events and Calendar show a fixed retry-later notice instead of a raw provider error. Event records are still unavailable because no Firebase repair was deployed. This does not change sign-in, expose protected event offers, add officer editing, or make commerce safe. GitHub Pages still reports `runmprc.com` as its custom domain even though Netlify serves that name; source removal is not provider proof. A green test or workflow does **not** by itself prove that GitHub Pages, `runmprc.com`, Firebase, or that domain setting changed. -The optional profile-photo and officer People-finder functions are still **NOT AVAILABLE YET**. #621 makes the frontend source 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 freezes that interface over the current live source for one exact release, but the release is still under review and production still serves #473. Officers inspect the protected disabled layouts only in synthetic local artifacts. If #623 later publishes, signed-out public review proves 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 changes no Firebase, provider, 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). +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). For the concise handbook, see [OFFICER_HANDBOOK.md](./OFFICER_HANDBOOK.md). The expanded task index is [docs/officers/README.md](./docs/officers/README.md). diff --git a/OPERATIONS_RUNBOOK.md b/OPERATIONS_RUNBOOK.md index 9188b8d..26db2f3 100644 --- a/OPERATIONS_RUNBOOK.md +++ b/OPERATIONS_RUNBOOK.md @@ -689,7 +689,7 @@ Post-release control result: safety merge `04d6d2cd88dda0e6ec7e2b6a71514e6ce2e4d WEB-002A [#473](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/473) completed its bounded web-only permissions containment on 2026-08-01. Exact two-parent merge `9ad6837756cdd409d296009fde5082eeeae5c059` published Netlify deploy `6a6dc9ea588b0c0008036312` from frozen source `39ab8649df411262c8109a3c81a57bc38f1e168b`, tree `d76b496cdc5e79015bc048cb961758abbe88b9ce`, 60 files, and digest `07b10c7d5ff176a1ad893d7549b07042312df35f4a4126e8765824ca94eaefb8`. Preview and live marker/header/robots/deep-route checks passed. Signed-out Shop, Events, Calendar, and Account checks passed; Shop shows the approved static catalog, and Events/Calendar show only the fixed retry-later notice. Final control merge `cb6a8f0a418fc14b448bce5ded71d68520415c92` made the temporary manifest inactive; Netlify attempt `6a6dcdd47bc81e000859a249` stopped unpublished, exact-main CI run `30696264830` passed all five jobs, and provider plus public-marker readback left deploy `6a6dc9ea588b0c0008036312` live. Both temporary release-source refs are absent; exact rollback source `ed1b0833f25822cee80c99ded8753722b5608a3f` remains. This did not restore event records or deploy Firebase, Rules, Functions, provider configuration, account state, protected offers, officer editing, ledger, or production data. Keep rollback deploy `6a6dc219a8136300081811db` as dated incident evidence. -WEB-002C [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) is an active one-shot Netlify release under review, not a completed publication. Its only frontend input is frozen inert source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, built as 62 files with digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`. The release control expects exact first parent `019353361210021483f23003e09ee6924b78e67c`. Until its pinned preview, exact two-parent merge, production marker, signed-out route/network checks, and immediate repause all pass, production remains #473 deploy `6a6dc9ea588b0c0008036312` from source `39ab8649df411262c8109a3c81a57bc38f1e168b`; that same deploy is #623's rollback target. Protected Account and administrator layouts are proved only with synthetic local artifacts. Production checks must stay signed out and can prove only the exact revision, normal sign-in and administrator guards, and absence of a member-directory request. Stop for any source, tree, count, digest, parent, marker, route, network, or repause mismatch. #623 has no authority for Firebase, Rules, Functions, indexes, outside-provider configuration, account/sign-in changes, real names/photos, or production data. Connected behavior remains **NOT AVAILABLE YET** under [#507](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/507). Follow the pending procedure in `docs/officers/PUBLISH_AND_CHECK.md`; do not reuse it as a general release button. +WEB-002C [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) completed its bounded inert member-directory interface release on 2026-08-13. Pinned Deploy Preview `6a7e05febf8fde00084cf9e0` matched release-control head `1fdb31f71fcaf01c33b5e57a4cd28fc473a4a737`, and PR CI run `31728469418` passed. Exact two-parent merge `9d5cc8612b4321172370bd949d307e7e4ac0ec7d`, parents `019353361210021483f23003e09ee6924b78e67c` and `1fdb31f71fcaf01c33b5e57a4cd28fc473a4a737`, tree `41b6d024d369d93f28ea49940b4f4e5710d3ab52`, passed exact-main CI run `31728908486`. Netlify deploy `6a7e072f8f346b0008510d29` became ready and published at `2026-08-13T18:05:35.983Z`. Its marker matched frozen source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, previous source `39ab8649df411262c8109a3c81a57bc38f1e168b`, rollback deploy `6a6dc9ea588b0c0008036312`, 62 files, and digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`. Signed-out `/account` and `/admin/member-directory` checks retained the normal guards; route and bundle review found no connected member-directory symbol or request. Protected Account and administrator layouts remain proved only with synthetic local artifacts. Repause head `d401daa409176dce0906c245adf3f20310cb513b` passed PR CI run `31728977578`; exact two-parent repause merge `c8678c623afdd9becf77d596b71f36f26f04b746`, parents `9d5cc8612b4321172370bd949d307e7e4ac0ec7d` and `d401daa409176dce0906c245adf3f20310cb513b`, passed all five exact-main jobs in run `31729248865`. Its Netlify attempt `6a7e081e73fdd60009f7ba57` errored unpublished; provider and marker readback retained deploy `6a7e072f8f346b0008510d29`. The manifest is inactive, the release source ref is absent, and rollback ref `codex/netlify-source-623-rollback` remains. #623 deployed no Firebase, Rules, Functions, or indexes; changed no outside-provider configuration, account, sign-in, or production data; and made no connected directory behavior available. Connected behavior remains **NOT AVAILABLE YET** under [#507](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/507). Do not reuse this exception as a general release button. Incident record: on 2026-08-01, overbroad source `094af1096ed8721597561cd59bf695d4c4a9d210` was published by merge `40728ff6141e34a279b70cc41d983c22ac5f0daa` as deploy `6a6dc0167fbe68000816b448` after a release-blocker comment. Exact rollback merge `1099ee8e6fdb81141fd9460de175b6d854cbcfdd` published deploy `6a6dc219a8136300081811db`, restoring source `ed1b0833`, tree `878c6628d961f4484cb49208aef53f1e9f2e3b47`, 60 files, and digest `7570955c2a00926e5813aef135f1799172cfd046072ac89fb4e492bed0797092`. Safety merge `dee79511b6e371329aa129139729e112e7a51aad` re-paused the manifest; its Netlify attempt `6a6dc35767a4ef000877e74b` did not publish, and provider readback left the rollback deploy live. The overbroad release ref was deleted and verified absent. This incident changed no Firebase, outside-provider configuration, account, payment, or production data. diff --git a/README.md b/README.md index ec3a27c..074c0b4 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Historical developer/content/LLM guides remain under [`docs/`](./docs/README.md) - `.github/workflows/`: frontend, Functions, Rules CI and deployment automation. - `public/404.html`, `public/index.html`, and `public/spa-navigation.js`: current tested GitHub Pages callback handoff. It preserves safe same-origin path, query, and fragment state. -**Deployment reality checked 2026-08-01:** 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. An overbroad #473 artifact was published and rolled back; bounded replacement deploy `6a6dc9ea588b0c0008036312` now serves exact source `39ab8649df411262c8109a3c81a57bc38f1e168b`. It adds only the static Shop and fixed Events/Calendar failure messages, deploys no Firebase, and does not restore event records. Its public marker/page checks passed and the temporary manifest is inactive again. 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. +**Deployment reality checked 2026-08-13:** 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. The completed bounded #623 release merge `9d5cc8612b4321172370bd949d307e7e4ac0ec7d` published deploy `6a7e072f8f346b0008510d29` from exact source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec` and tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`; its 62-file artifact digest is `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`. It adds only an inert profile-photo/searchability and officer People finder interface: the controls are visibly unavailable and make no directory request. No Firebase, provider, account, role, member data, photo, or search backend changed. Repause merge `c8678c623afdd9becf77d596b71f36f26f04b746` passed exact-main CI run `31729248865`; its Netlify attempt `6a7e081e73fdd60009f7ba57` published nothing, and deploy `6a7e072f8f346b0008510d29` remained live. The temporary #623 manifest is inactive again. The prior bounded #473 deploy `6a6dc9ea588b0c0008036312` remains rollback history, not current production. 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. ## Local setup status @@ -95,4 +95,4 @@ Business owners—not coding agents—must approve legal text, waiver/insurance ## Deployment warning -Pushing to `main` runs CI and does not start `.github/workflows/deploy.yml`. The manual workflow is fixed to an exact merged commit and reviewed target set, but it is **NOT AVAILABLE YET** until #133 configures protected environments and short-lived cloud authority. Ordinary Git-triggered Netlify production builds are paused except for the exact temporary #473 web-only control merge described in the runbook. That exception is not reusable and publishes no Firebase or provider change. A reusable protected live-Netlify publication path is still **NOT AVAILABLE YET**. Production changes still require protected approval, a compatible backend-first rollout, separate live-host proof, a named observer, and the runbook's post-deploy/reconciliation steps. +Pushing to `main` runs CI and does not start `.github/workflows/deploy.yml`. The manual workflow is fixed to an exact merged commit and reviewed target set, but it is **NOT AVAILABLE YET** until #133 configures protected environments and short-lived cloud authority. Ordinary Git-triggered Netlify production builds are paused. The completed #623 web-only exception is inactive and not reusable; it published no Firebase or provider change. The older #473 exception is retained only as rollback history. A reusable protected live-Netlify publication path is still **NOT AVAILABLE YET**. Production changes still require protected approval, a compatible backend-first rollout, separate live-host proof, a named observer, and the runbook's post-deploy/reconciliation steps. diff --git a/SECURITY.md b/SECURITY.md index c6daaba..3956537 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -68,7 +68,7 @@ The findings below describe the repository at the start of the 2026-07-12 assess | RISK-023 | The legacy `functions.config().api.key` endpoint uses a static shared key with no replay control, source restriction, App Check, authenticated operator, or request audit. The API is also scheduled for Firebase decommissioning in March 2027. | Key theft permits bulk role changes and future deployment failure. | Retire it in favor of authenticated admin workflow or narrowly authenticated scheduled import; migrate any remaining config to Secret Manager. | | RISK-024 | OAuth tokens remain plaintext. Repository Rules deny browser access, but protected deployment and live behavior are unproven; least-privilege runtime IAM and an encryption decision remain open. OAUTH-001A1H [#606](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/606) source transactionally rereads the exact access-token, refresh-token, and expiry tuple before persisting a refresh response. A retry rereads the tuple; changed, missing, or malformed state returns one fixed failure without a stale write or downstream bearer call. OAUTH-001B9 [#608](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/608) source records the disconnect secret's Firestore update time before optional revocation, then transactionally rereads it and deletes the local secret/connection pair only when the secret is absent or still has that exact version. A newer version, including byte-identical replacement, is preserved with one fixed unknown result; a transaction conflict rereads without repeating provider work. OAUTH-001B10 [#610](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/610) browser source admits only a fulfilled response value that presents exactly one own enumerable data field, `ok` equal to `true`; it returns a new frozen confirmation and routes other fulfilled results or exceptional inspection through the existing fixed unknown-result view without hiding the connection. Browser JavaScript cannot distinguish a transparent Proxy that faithfully presents that contract, so the received object is never retained. Synthetic tests use no real token, account, or provider call. Provider calls are still not serialized; an exact browser confirmation does not independently prove provider revocation, and provider/local and lost-acknowledgement reconciliation, a trusted connection-only write that does not also version the secret, deployment, and live behavior remain unproven. | Token theft exposes member activity data; an undeployed boundary or an unhandled provider/acknowledgement race can still lose availability or leave local and provider state ambiguous. | Deploy and read back server/IAM-only secret access, decide encryption, serialize or otherwise reconcile refresh and disconnect operations and lost acknowledgements, minimize scopes, audit access, and verify only with approved made-up staged accounts. | | RISK-025 | Admin authentication relies on password Auth plus a long-lived role token; no repository evidence of MFA, recent-auth checks, re-auth for refunds/role grants, or rapid revocation workflow. | A stolen admin session has broad durable impact. | Require MFA for privileged accounts, recent-auth for sensitive actions, capability roles, short sessions/forced refresh, and break-glass procedures. | -| RISK-042 | Profile photos and an officer people finder have no approved privacy notice, retention/backup treatment, scoped capability, or production release path. The existing Admin Members page downloads complete account documents and cannot enforce an opt-out promise. #505/#506 source supplies the private processed thumbnail, default-off preference, minimum server-only projection, and bounded audited verified-admin name search, but none is deployed. MEMBERS-DIRECTORY-001D [#621](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/621) makes the frontend default an inert, disabled preview with zero directory reads, uploads, searches, saves, request IDs, or service calls; it does not make the backend available. WEB-002C [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) has one frozen inert frontend artifact under review for a bounded Netlify release, but it is not published and does not connect the backend. | A photo, name, query, preference, prefix digest, or stable entry reference could be exposed, retained, enumerated, correlated, or mistaken for membership evidence if the connected path is enabled prematurely; automated face matching would add unapproved biometric processing. A browser availability constant is not authorization. | Keep the source-controlled availability boundary off and the feature separate from the official roster. Preserve current-source revalidation, direct Rules denials, fixed query/result bounds, no-store responses, pseudonymous rate keys, query-free audit, and synthetic race/opt-out/removal proof. Never store the original, persist raw queries, or add face recognition. Complete #110 policy inputs, AUTH-003 scoped authorization follow-up, #133 protected authority, and #507 staging plus backend-first deployment/readback before a reviewed source flip and connected website publication. | +| RISK-042 | Profile photos and an officer people finder have no approved privacy notice, retention/backup treatment, scoped capability, or connected production release path. The existing Admin Members page downloads complete account documents and cannot enforce an opt-out promise. #505/#506 source supplies the private processed thumbnail, default-off preference, minimum server-only projection, and bounded audited verified-admin name search, but none is deployed. MEMBERS-DIRECTORY-001D [#621](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/621) makes the frontend default an inert, disabled preview with zero directory reads, uploads, searches, saves, request IDs, or service calls; it does not make the backend available. WEB-002C [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) published exactly that frozen inert frontend as Netlify deploy `6a7e072f8f346b0008510d29`; signed-out guard and no-request checks passed, and the temporary release authority is inactive. It did not connect or deploy the backend. | A photo, name, query, preference, prefix digest, or stable entry reference could be exposed, retained, enumerated, correlated, or mistaken for membership evidence if the connected path is enabled prematurely; automated face matching would add unapproved biometric processing. A browser availability constant is not authorization. | Keep the source-controlled availability boundary off and the feature separate from the official roster. Preserve current-source revalidation, direct Rules denials, fixed query/result bounds, no-store responses, pseudonymous rate keys, query-free audit, and synthetic race/opt-out/removal proof. Never store the original, persist raw queries, or add face recognition. Complete #110 policy inputs, AUTH-003 scoped authorization follow-up, #133 protected authority, and #507 staging plus backend-first deployment/readback before a reviewed source flip and connected website publication. | | RISK-026 | Firestore Admin SDK bypasses rules and the Functions runtime IAM scope is not documented. #135 removes the long-lived service-account JSON path from release source, but the least-privilege short-lived deploy identity is not configured yet. | Server or CI compromise may expose the entire project; missing provider configuration also blocks release. | Complete the private IAM inventory and #133 OIDC/WIF configuration; keep runtime and deploy identities separate; never restore a JSON key shortcut. | | RISK-027 | Sentry optionally records user email and enables 100% replay on error; analytics/privacy consent, redaction, retention, and field-deny policies are not evidenced. | Forms and account flows contain PII that may be sent to monitoring vendors unexpectedly. | Disable replay on sensitive routes or configure strict masking, avoid email user context, set scrubbing/retention, consent policy, and vendor agreements. | | RISK-028 | No payment reconciliation job, dead-letter/quarantine workflow, or alert proves paid Stripe objects match Firestore. | Missed webhooks and partial failures can persist unnoticed. | Add scheduled reconciliation, alert thresholds, operator repair tooling, and a daily finance report. | @@ -85,7 +85,7 @@ 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 the bounded deploy live. WEB-002C [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) is now an active one-shot release under review. It pins frozen inert source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, 62 files, and digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1` to exact expected first parent `019353361210021483f23003e09ee6924b78e67c`, with current deploy `6a6dc9ea588b0c0008036312` as rollback. Until preview, merge, production readback, and immediate repause all pass, production remains the #473 deploy and source `39ab8649df411262c8109a3c81a57bc38f1e168b`. 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 marker and rollback evidence, keep ordinary publication paused, and keep the reviewed Git rollback projection available. #623 must fail closed on any parent, source, tree, count, digest, marker, or public-check mismatch and must be re-paused immediately after successful readback. 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, 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-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. | @@ -99,7 +99,7 @@ These entries are implementation evidence, not a production risk-acceptance deci | --- | --- | --- | | Source-only containment for RISK-008, RISK-017, RISK-022, RISK-032, and RISK-042 | MEMBERS-DIRECTORY-001A [#505](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/505) adds four caller-only profile callables with native App Check enforcement and fail-closed private no-store responses. Strict requests, revisions, current-name opt-in, normalized 256-by-256 WebP output, metadata/animation/size rejection, separate default-off visibility, server-only preference/photo records, atomic append-oriented audits, and direct-browser denials are covered with generated non-face data. No original image, filename, provider photo URL, image-derived digest, face matching, or membership authority is stored or returned. The exact `sharp@0.35.0` dependency has no finding in the 2026-08-01 production audits; the audits still report 4 existing root findings (1 high, 2 moderate, 1 low) and 10 existing Functions findings (9 moderate, 1 low). | This slice is not live and by itself supplies no officer search; #506 adds that separate source boundary. Every upload or retry still writes stable, domain-separated, SHA-256 account-key abuse-control bookkeeping, consumes quota, and depends on an unverified TTL; that pseudonym is linkable and is not anonymization. Profile/photo/audit state alone is read-only on an exact retry. Complete #110 privacy/retention/backup decisions, #133 protected short-lived authority, #507 isolated staging and backend-first deployment/readback, approved public notice wording, synthetic opt-out/removal/cache proof, website publication, and `runmprc.com` verification before use. Do not inspect real profiles or enable biometric processing. | | Source-only containment for RISK-008, RISK-017, RISK-022, RISK-032, and RISK-042 | MEMBERS-DIRECTORY-001B [#506](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/506) adds one separate officer people-finder page, one native-App-Check verified-admin callable, and one current-state projection reconciler with idempotent background retry. The browser submits only an explicit UUID/name-prefix command and accepts at most 24 exact display-name/optional-thumbnail projections. Direct Firestore access is denied. The server rejects Unicode controls/formats and invalid canonical bounds, stores only prefix digests under a proven 272-entry ceiling, permits 30 searches per verified-admin account/hour, queries at most 48 candidates, re-reads each current member/preference/photo record before returning it, and atomically records one minimal query-free audit. An opted-out, missing-name, malformed, stale, or now-nonmatching candidate is hidden. The existing full-account admin filter is visibly separate. | The projection's internal UID key, prefix digests, entry reference, rate key, and audit identity remain stable/linkable server-side pseudonyms, not anonymization. A response still contains personal data for its approved purpose. Exact request-ID reuse gets a fixed denial instead of retained-result replay and creates no second audit; the rate limiter may still consume an attempt. The current verified `admin` role is only a documented compatibility boundary, not a scoped people-finder capability. Source/tests/preview do not configure TTL, privacy notice, retention/backups, repair/backfill ownership, staging, Firebase Rules/Functions/indexes or trigger policy, Netlify, or production behavior. Complete #110, AUTH-003, #133, and #507 before use; never test against real profiles or add image queries, facial recognition, embeddings, similarity, analytics, or raw-query logs. | -| Frontend-only containment for RISK-042 | MEMBERS-DIRECTORY-001D [#621](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/621) adds one source-controlled availability boundary that defaults unavailable. The account page and `AdminGuard`-protected People finder render the future layout as visibly described, natively disabled controls. The default path does not mount the connected components, read a file or saved state, accept a name, create a request ID, initialize or call a directory service, or render sample or result cards. Focused tests preserve the connected source behind an explicit seam using only synthetic data. #623 freezes the equivalent inert interface projection from the current live source into an exact 62-file artifact, but the one-shot publication remains under review. Protected-layout evidence stays synthetic; any later public check must stay signed out and can prove only the exact revision, normal sign-in/admin guards, and absence of a member-directory request. | This is an accidental-call and misleading-interface containment, not an authorization, privacy, retention, backend, provider, deployment, or live-behavior control. A later build must not turn availability on through configuration drift or an unreviewed environment value. #623 changes no Firebase, provider, account, sign-in, or production data. #507 must complete approved notice and backup/removal wording, scoped authorization, protected authority, isolated staging, backend-first Rules/Functions/index deployment and readback, synthetic privacy/race proof, and then a separately reviewed source flip before connected website publication. Until then, no real name or photo may be entered, read, uploaded, searched, or saved. | +| Frontend-only containment for RISK-042 | MEMBERS-DIRECTORY-001D [#621](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/621) adds one source-controlled availability boundary that defaults unavailable. The account page and `AdminGuard`-protected People finder render the future layout as visibly described, natively disabled controls. The default path does not mount the connected components, read a file or saved state, accept a name, create a request ID, initialize or call a directory service, or render sample or result cards. Focused tests preserve the connected source behind an explicit seam using only synthetic data. #623 published the equivalent inert interface projection as exact 62-file deploy `6a7e072f8f346b0008510d29`. Protected-layout evidence stays synthetic; completed signed-out public checks proved only the exact revision, normal sign-in/admin guards, and absence of a member-directory request. The manifest is inactive. | This is an accidental-call and misleading-interface containment, not an authorization, privacy, retention, backend, provider, or connected-live-behavior control. A later build must not turn availability on through configuration drift or an unreviewed environment value. #623 changed no Firebase, provider configuration, account, sign-in, or production data. #507 must complete approved notice and backup/removal wording, scoped authorization, protected authority, isolated staging, backend-first Rules/Functions/index deployment and readback, synthetic privacy/race proof, and then a separately reviewed source flip before connected website publication. Until then, no real name or photo may be entered, read, uploaded, searched, or saved. | | Immediate Product-binding containment part of RISK-031 | PAY-PRODUCT-001A is tracked in live [#353](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/353). One dependency-free projection is used by the paid race and Shop checkout paths. A present stored Product link must be an own primitive non-empty string from 1 through 255 JavaScript code units and is copied without trimming, conversion, character restrictions, or `prod_` inference. Only a genuinely missing own field retains the compatibility Product-create path. Before any mapping write, a resolved Product must provide a bounded custom ID, exact Product kind, expected declared mode, and an installed-SDK 2xx response marker. Malformed stored links stop before token, registration/order identifier, Product-link or business-record write, or Stripe work; earlier access and request-count checks and their safety-counter writes may already have run. Malformed created results stop after at most one Product attempt but before mapping, Checkout Session, or business-record writes. | This structural containment does not prove provider origin, Stripe account ownership, intended catalog identity, metadata binding, Product status, price, dispatch, delivery, or reconciliation. A rejected create result may leave an orphaned Product; do not retry automatically. Anonymous clean-missing creation remains concurrency-prone and reachable from public traffic. Complete #113 inventory/disposition, authenticated idempotent catalog synchronization, Product-specific plan/pre-send/result/lost-acknowledgement/reconciliation controls, isolated staging, protected Firebase deployment, and provider proof before live commerce. | | Immediate current-handler containment part of RISK-003 | PAY-SESSION-001A is tracked in live [#357](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/357). The current paid race and Shop handlers build one immutable expectation before the Session call, catch rejection without opening it, and immediately project only a closed installed-SDK result. A result must match declared test/live mode, payment/open/unpaid state, exact cents, USD, buyer email, exact closed metadata, exact callbacks, a mode-compatible bounded Session ID, one canonical HTTPS capability at the hard-coded default `checkout.stripe.com` origin, and an installed-SDK 200 marker. Only copied ID/URL values continue; records store the ID but never the URL. Invalid results create no registration/order record and return one fixed unknown-result message. The website makes rejection or a missing paid URL terminal for that page visit, retains the form, and blocks a second direct handler call. | This is a narrow legacy compatibility stop, not trusted provider/account origin, deterministic business idempotency, dispatch/delivery proof, durable result evidence, payment proof, or adoption of the unused C4 chain. The Session call occurs first, so a rejected result may leave a payable orphan; earlier rate-counter, token/identifier, and lazy Product-mapping effects may remain. Reload, another tab/device, or a scripted caller bypasses the page lock. A configured Stripe custom checkout domain is blocked until #113 and a protected configuration boundary approve it. Complete PAY-002C/D persistence-first sagas, trusted C4 controller/result persistence, reconciliation, protected staging/deployment, provider readback, and exact website/Firebase/live proof. | | Immediate pre-render browser containment part of RISK-003 | PAY-SESSION-001B is tracked in live [#503](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/503). Each current public race and Shop page now keeps one component-local in-memory marker. After existing local checks admit a request, the handler sets that marker synchronously before analytics or its first Checkout promise can settle. A same-action or later submission on that mounted page is inert, including the gap before React renders the existing pending disabled button. Focused actual-route tests prove one service/analytics attempt across same-action and post-render repeats; preserve free-participant, volunteer-without-price-tier, and both paid-link navigation branches; and prove local waiver/native-disabled paths do not consume an attempt. | This browser marker is not a server boundary, durable idempotency key, provider dispatch/result record, business-state lock, payment proof, or reconciliation. It never releases during the mounted page visit because the admitted result must navigate or enter #357's terminal unknown-result state. Existing form controls other than the submit button remain editable. Reload, a remount, another tab/device, a script, or a direct service caller can bypass it. A same-mounted route change instead stays locked, and this slice does not fence an older pending result from that changed route. Complete PAY-002C/D persistence-first deterministic commands, durable replay/reconciliation, protected deployment, and exact website/Firebase/Stripe/live proof. | diff --git a/SYSTEM_DESIGN.md b/SYSTEM_DESIGN.md index 6add0c0..e2cc73e 100644 --- a/SYSTEM_DESIGN.md +++ b/SYSTEM_DESIGN.md @@ -86,14 +86,14 @@ Text alternative: browsers can use the React app, Auth, Firestore, Functions, St | Operational data | Cloud Firestore | `src/services`, `firestore.rules`, `firestore.indexes.json` | Appropriate for current scale; counters and state transitions require transactional design. | | Server API | First-generation Firebase callable/HTTP/trigger functions | `functions/` | Prototype covers most workflows; validation, idempotency, and isolation are incomplete. | | Payments | Stripe Checkout Sessions, Payment Links, refunds, signed webhook | `functions/createCheckoutSession.js`, `createMerchCheckout.js`, `stripeWebhook.js` | Not ready for live payments until P0 issues are complete. | -| Hosting and release | Netlify currently answers `runmprc.com`. GitHub Pages still reports the same custom domain, so its default URL redirects to the Netlify-served name instead of providing an independent copy. #135 source stops ordinary automatic releases, pauses Git-triggered Netlify production builds, and removes the Pages CNAME from future protected artifacts. After an overbroad WEB-002A artifact was rolled back, [#473](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/473) used one bounded replacement exception: exact merge `9ad6837` published source `39ab864`, tree `d76b496`, 60 files, and artifact digest `07b10c7d…` as deploy `6a6dc9ea588b0c0008036312`. Every mismatch failed closed, and the manifest became inactive again. WEB-002C [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) is an active one-shot under review for frozen inert source `c2d87d1`, tree `411aa6ec`, 62 files, and digest `d837272a…`, with exact expected first parent `0193533` and the #473 deploy as rollback. | `netlify.toml`, `config/netlify-production-release.json`, `scripts/netlify-release-policy.js`, `.github/workflows/deploy.yml`, `public/404.html` | **LIVE FRONTEND CONTAINMENT.** Until every #623 preview, merge, readback, and repause gate passes, production remains #473 deploy `6a6dc9ea588b0c0008036312` from source `39ab864`. Shop is the static pickup catalog; Events and Calendar disclose no raw provider error. Event records remain unavailable because no Firebase or provider repair was deployed. This does not complete the general protected host under #133/#136/WEB-001. | +| Hosting and release | Netlify currently answers `runmprc.com`. GitHub Pages still reports the same custom domain, so its default URL redirects to the Netlify-served name instead of providing an independent copy. #135 source stops ordinary automatic releases, pauses Git-triggered Netlify production builds, and removes the Pages CNAME from future protected artifacts. After an overbroad WEB-002A artifact was rolled back, [#473](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/473) used one bounded replacement exception: exact merge `9ad6837` published source `39ab864`, tree `d76b496`, 60 files, and artifact digest `07b10c7d…` as deploy `6a6dc9ea588b0c0008036312`. Every mismatch failed closed, and the manifest became inactive again. WEB-002C [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) completed a second bounded exception: exact merge `9d5cc86` published frozen inert source `c2d87d1`, tree `411aa6e`, 62 files, and digest `d837272a…` as deploy `6a7e072f8f346b0008510d29`. Signed-out guards and no-request proof passed; repause merge `c8678c6` left that deploy live and made the manifest inactive. | `netlify.toml`, `config/netlify-production-release.json`, `scripts/netlify-release-policy.js`, `.github/workflows/deploy.yml`, `public/404.html` | **LIVE FRONTEND CONTAINMENT.** Production is #623 deploy `6a7e072f8f346b0008510d29` from source `c2d87d1`. It adds only the disabled member-directory interface to the #473 surface. Shop remains the static pickup catalog; Events and Calendar disclose no raw provider error. Event records remain unavailable because no Firebase or provider repair was deployed. This does not connect the directory backend or complete the general protected host under #133/#136/WEB-001. | | Email | Firestore `mail` outbox designed for the Firebase Trigger Email extension | `functions/sendConfirmationEmail.js` | Extension/provider deployment is unverified; outbox creation is not transactionally idempotent and HTML needs escaping. | | Observability | Optional Sentry; Firebase Analytics configuration remains but its runtime is not initialized by #139 source | `src/services/monitoring`, `src/services/analytics` | #134 source bounds Sentry payloads. #139 source removes every application runtime Firebase Analytics import, initialization, and emission while preserving no-op call compatibility. Website publication, provider collection/cookies and historical data, consent, retention, access, deletion, and vendor configuration remain unverified under #110/#111. | | Third-party fitness | Strava OAuth tokens and statistics | `functions/strava.js`, `src/services/strava` | Functional prototype. The #100 source Rules deny browser token access, but Firebase deployment is unproven and transactional refresh, scopes/revocation, IAM/encryption decision, and audit remain OAUTH-001. | The former workflow automatically published Pages before attempting Firebase and could finish green after skipping Firebase. #135 replaces that source path with a manual exact-current-commit request, exact latest CI checks, one fixed backend plan, protected short-lived identity wiring, provider readback, and Firebase-before-Pages publication. Missing authority or failed/partial verification is red. Ordinary Git-triggered Netlify production builds stop. Replacement #473 continued only for one production `main` merge whose first parent was exact `dee79511b6e371329aa129139729e112e7a51aad`, then independently fetched and verified source commit `39ab8649df411262c8109a3c81a57bc38f1e168b` and tree `d76b496cdc5e79015bc048cb961758abbe88b9ce` before matching the fixed 60-file digest. Review also compared executable code against live artifact source `ed1b0833`; provenance alone did not authorize accumulated source. Its preview and production artifacts matched, and the manifest was then made inactive. -#623 now proposes the same fail-closed pattern for one inert member-directory interface artifact. The reviewed input must remain exact source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, 62 files, digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`, and first parent `019353361210021483f23003e09ee6924b78e67c`. Current production remains #473 deploy `6a6dc9ea588b0c0008036312` from source `39ab8649df411262c8109a3c81a57bc38f1e168b`, which is also the rollback target. A later merge, wrong branch/context/ref/tree/artifact, mismatched marker, missing signed-out public proof, or any uncertainty stops. If publication succeeds, the manifest must be re-paused immediately and its production attempt plus the retained live deploy read back separately. The release changes no Firebase, outside-provider configuration, sign-in state, or production data. Build hooks and a reusable protected Netlify publication path remain unverified. No source test clears the current Pages custom-domain claim, configures #133, or deploys #136; those remain separate provider states. The App Engine synchronization script is another surface that must be documented as active or retired. +#623 completed the same fail-closed pattern for one inert member-directory interface artifact. Deploy Preview `6a7e05febf8fde00084cf9e0` matched control head `1fdb31f71fcaf01c33b5e57a4cd28fc473a4a737`. Exact merge `9d5cc8612b4321172370bd949d307e7e4ac0ec7d`, with first parent `019353361210021483f23003e09ee6924b78e67c`, published deploy `6a7e072f8f346b0008510d29` from source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, 62 files, and digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`. Its marker also records previous source `39ab8649df411262c8109a3c81a57bc38f1e168b` and rollback deploy `6a6dc9ea588b0c0008036312`. Signed-out route, guard, and bundle checks found no connected member-directory request or symbol. Repause merge `c8678c623afdd9becf77d596b71f36f26f04b746` made the manifest inactive; attempt `6a7e081e73fdd60009f7ba57` stopped unpublished and retained the verified deploy and marker. The release source ref is absent and the rollback ref remains. The release changed no Firebase, outside-provider configuration, sign-in state, or production data. Build hooks and a reusable protected Netlify publication path remain unverified. No source test clears the current Pages custom-domain claim, configures #133, or deploys #136; those remain separate provider states. The App Engine synchronization script is another surface that must be documented as active or retired. ```mermaid flowchart TD @@ -109,16 +109,13 @@ flowchart TD Verify -- "No" --> Stop Verify -- "Yes" --> Pages["Publish Pages branch without a CNAME"] Merge -. "Ordinary Git production build paused" .-> Netlify["Netlify / runmprc.com\nreusable protected publication not available"] - Merge -. "#623 only: exact-parent one-shot under review" .-> WebGate{"Temporary authority and exact artifact valid?"} - WebGate -- "No" --> Stop - WebGate -- "Yes" --> WebOnly["Publish pinned web-only artifact"] + Completed["#623 exact-parent one-shot completed"] --> WebOnly["Pinned inert web-only artifact live"] WebOnly --> Netlify - Netlify --> WebReadback{"Exact marker and signed-out checks pass?"} - WebReadback -- "No" --> WebRollback["Restore recorded prior deploy"] - WebReadback -- "Yes" --> WebRepause["Disable temporary authority and verify no replacement"] + Netlify --> WebReadback["Exact marker and signed-out guards verified"] + WebReadback --> WebRepause["Temporary authority inactive; verified deploy retained"] ``` -Text alternative: ordinary merges run CI and do not publish Netlify. Production remains the completed #473 artifact unless the one exact #623 parent, frozen source, artifact, and marker all pass. #623 then requires signed-out public readback; failure restores the recorded prior deploy, while success immediately disables the temporary authority and verifies that the production artifact was not replaced. The separate protected workflow still requires approval and verified Firebase before publishing its Pages copy. +Text alternative: ordinary merges run CI and do not publish Netlify. #623 completed one exact-parent exception and production now serves its pinned inert artifact. Signed-out marker and guard checks passed, then the temporary authority was disabled without replacing the verified deploy. The separate protected workflow still requires approval and verified Firebase before publishing its Pages copy. ### GitHub Pages callback handoff @@ -688,7 +685,7 @@ The preserved connected branch sends nothing while the person types. Search happ The backend source still has no production index, Rules, Function, privacy-notice, retention/backup approval, or live proof. Synthetic local artifacts and tests prove that the protected #621 layouts are disabled and their default branches make zero directory calls. Publishing and anonymously reading back the exact frontend may prove only its revision, normal sign-in and administrator guards, and absence of a public member-directory request. [#507](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/507) must complete the #110 policy decision, scoped authorization, #133 protected short-lived authority, any required index and backend-first deployment/readback (including the trigger retry policy), isolated synthetic staging checks, and backup-officer procedure before a separately reviewed source change turns availability on. Only then may the connected website be published and verified on `runmprc.com`. #507 must also own an idempotent, dry-runnable projection repair/backfill for any later schema/normalization upgrade, or prove no older preference data exists for the initial target. A green source build, disabled preview, merge, or frontend publication is not authorization to search a real name or inspect a real photo. -WEB-002C [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) freezes only that inert interface into source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, and a 62-file artifact with digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`. Its one-shot Netlify release is under review, not published. Production still serves #473 deploy `6a6dc9ea588b0c0008036312` from source `39ab8649df411262c8109a3c81a57bc38f1e168b`. Protected-layout proof remains synthetic. Any later public proof must stay signed out and is limited to the exact revision, normal sign-in and administrator guards, and absence of a member-directory request. #623 has no Firebase, provider, account, sign-in, or production-data authority, and #507 remains **NOT AVAILABLE YET**. +WEB-002C [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) published only that inert interface as deploy `6a7e072f8f346b0008510d29`, from source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, and a 62-file artifact with digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`. Protected-layout proof remains synthetic. Completed signed-out public proof is limited to the exact revision, normal sign-in and administrator guards, and absence of a member-directory request. The manifest is inactive; the release source is absent; and the rollback ref remains. #623 deployed no Firebase, Rules, Functions, or indexes and changed no provider configuration, account, sign-in, or production data. #507 remains **NOT AVAILABLE YET**. ### 8.0a Provider-neutral membership authority and entitlement — SOURCE ONLY, UNUSED diff --git a/docs/officers/ACCESS_CONTINUITY.md b/docs/officers/ACCESS_CONTINUITY.md index 57633b6..57a801f 100644 --- a/docs/officers/ACCESS_CONTINUITY.md +++ b/docs/officers/ACCESS_CONTINUITY.md @@ -84,9 +84,15 @@ For each system, record only: 10. Confirm a normal merge does not start the GitHub release. 11. Confirm missing release authority becomes a red failure before backend installation, cloud authentication, deployment, or website publication. A public website artifact may be prepared without cloud authority. 12. Confirm Firebase verification must finish before the GitHub Pages publication job can start. -13. Confirm ordinary Netlify Git-triggered production builds remain paused. The temporary #473 release is complete: confirm its manifest is inactive, its release source is absent, and its live marker matches the current runbook. For any future exception, re-read the issue and pull request for a newer blocker and compare the executable delta with the current live artifact immediately before merge. -14. Confirm reviewers reject release requests older than 24 hours and request the current `main` commit again. -15. **NOT AVAILABLE YET:** complete the synthetic role-boundary drill below after the reviewed database, Function, and website revisions are safely available in protected staging. +13. Confirm ordinary Netlify Git-triggered production builds remain paused. +14. Confirm the live #623 marker names control `9d5cc8612b4321172370bd949d307e7e4ac0ec7d`, source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, 62 files, digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`, and deploy `6a7e072f8f346b0008510d29`. +15. Confirm repause merge `c8678c623afdd9becf77d596b71f36f26f04b746` passed CI run `31729248865`. +16. Confirm repause attempt `6a7e081e73fdd60009f7ba57` published nothing and deploy `6a7e072f8f346b0008510d29` stayed live. +17. Record the earlier completed #473 deploy `6a6dc9ea588b0c0008036312` as rollback history. +18. For any future exception, re-read the issue and pull request for a newer blocker. +19. Compare its executable delta with the current live artifact immediately before merge. +20. Confirm reviewers reject release requests older than 24 hours and request the current `main` commit again. +21. **NOT AVAILABLE YET:** complete the synthetic role-boundary drill below after the reviewed database, Function, and website revisions are safely available in protected staging. ### Synthetic role-boundary drill — NOT AVAILABLE YET diff --git a/docs/officers/EVENTS_SHOP_MEMBERS.md b/docs/officers/EVENTS_SHOP_MEMBERS.md index 1b5a3d3..3f70a78 100644 --- a/docs/officers/EVENTS_SHOP_MEMBERS.md +++ b/docs/officers/EVENTS_SHOP_MEMBERS.md @@ -2416,11 +2416,11 @@ Officer review steps after every prerequisite has proof: ## Optional profile photo and officer people finder — INERT FRONTEND PREVIEW; BACKEND NOT LIVE -**Purpose:** let officers review the future profile-photo, independent finder-choice, and People finder layouts without connecting the private backend. The #621 frontend source default is an inert preview: every related control is disabled; it reads no saved photo or setting, accepts or uploads no photo, searches no name, and saves nothing. #623 freezes only that inert interface over the current live source for one bounded Netlify release. That release is under review and not published. Production still serves #473 deploy `6a6dc9ea588b0c0008036312` from source `39ab8649df411262c8109a3c81a57bc38f1e168b`. After a later approved connection, a signed-in person could choose one private profile thumbnail and, separately, choose whether the People finder may show their display name and thumbnail. A properly authorized officer could search by name and compare voluntary thumbnails visually. The system will not search a photo or recognize a face. +**Purpose:** let officers review the future profile-photo, independent finder-choice, and People finder layouts without connecting the private backend. The #621 frontend default is an inert preview: every related control is disabled; it reads no saved photo or setting, accepts or uploads no photo, searches no name, and saves nothing. #623 published only that inert interface as bounded Netlify deploy `6a7e072f8f346b0008510d29`. Signed-out route, guard, and no-directory-request checks passed, and the temporary authority is inactive. After a later approved connection, a signed-in person could choose one private profile thumbnail and, separately, choose whether the People finder may show their display name and thumbnail. A properly authorized officer could search by name and compare voluntary thumbnails visually. The system will not search a photo or recognize a face. **Approver:** membership lead, privacy owner, and platform/security owner. The privacy owner must approve the final notice and backup/removal wording before connected publication. -**Prerequisites:** parent [#504](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/504), account source child [#505](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/505), search source child [#506](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/506), and frontend-preview child [#621](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/621) are reviewed. #623 must have its separately reviewed exact release record before publication. Review the protected disabled layouts only through synthetic local artifacts. If the exact #623 frontend artifact later publishes and is read back, inspect only its signed-out public revision and guards. Use only made-up accounts, made-up names, and generated non-face images for the preserved connected-source tests. Protected release [#507](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/507), the approved #110 privacy entry, scoped authorization, #133 protected release authority, and isolated staging are still required before any backend connection or live use. +**Prerequisites:** parent [#504](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/504), account source child [#505](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/505), search source child [#506](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/506), and frontend-preview child [#621](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/621) are reviewed. #623 has a separately reviewed completed release record. Review the protected disabled layouts only through synthetic local artifacts. Inspect production only while signed out, and only for its public revision and normal guards. Use only made-up accounts, made-up names, and generated non-face images for the preserved connected-source tests. Protected release [#507](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/507), the approved #110 privacy entry, scoped authorization, #133 protected release authority, and isolated staging are still required before any backend connection or live use. ```mermaid flowchart TD @@ -2431,14 +2431,14 @@ flowchart TD Officer --> Search["Name field and Search button disabled"] Account --> None["No directory name or photo read, upload, remove, search, or save"] Search --> None - Release["#623 exact inert artifact under review"] --> Public["Future signed-out revision and guard readback only"] + Release["#623 exact inert artifact published"] --> Public["Completed signed-out revision and guard readback only"] Public -. "does not prove protected layout" .-> Synthetic Later["Later #507 reviewed source flip"] --> Gates["Privacy, scoped authorization, staging, and backend-first readback"] Gates --> Connected["Future optional name search with voluntary thumbnails"] Connected -. "never photo search or proof" .-> Official["Membership, role, payment, or official records"] ``` -Text alternative: synthetic local artifacts prove the signed-in Account preview and administrator-guarded People finder with every directory control disabled. The #623 artifact is under review; if published, signed-out public checks prove only its exact revision, normal guards, and absence of a directory request, not the protected layouts. Only a later #507 source flip after privacy, authorization, staging, and backend-first readback could connect the optional name search and voluntary thumbnails. It will not search a photo, and a result will not prove or change an official record. +Text alternative: synthetic local artifacts prove the signed-in Account preview and administrator-guarded People finder with every directory control disabled. #623 published the exact inert artifact. Completed signed-out public checks prove only its exact revision, normal guards, and absence of a directory request, not the protected layouts. Only a later #507 source flip after privacy, authorization, staging, and backend-first readback could connect the optional name search and voluntary thumbnails. It will not search a photo, and a result will not prove or change an official record. Officer review steps for the #621 frontend preview: @@ -2464,9 +2464,9 @@ Officer review steps for the #621 frontend preview: 20. Confirm the copy says a future result will not prove membership. 21. Confirm the copy says there is no photo query or facial recognition. 22. Confirm synthetic tests still cover the preserved connected branches through an explicit test seam. -23. Ask whether #623 is still under review or has exact publication proof. -24. If it remains under review, record **not published** and stop the public checks. -25. If it published, ask the platform owner for release ID `WEB-002C-MEMBER-DIRECTORY-PREVIEW-2026-08-13`, source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, 62 files, digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`, and the exact public marker. +23. Ask the platform owner for the completed #623 publication record. +24. Confirm it names release ID `WEB-002C-MEMBER-DIRECTORY-PREVIEW-2026-08-13`, merge `9d5cc8612b4321172370bd949d307e7e4ac0ec7d`, and deploy `6a7e072f8f346b0008510d29` published on 2026-08-13. +25. Confirm its marker names source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, previous source `39ab8649df411262c8109a3c81a57bc38f1e168b`, rollback deploy `6a6dc9ea588b0c0008036312`, 62 files, and digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`. 26. Confirm the release record says no Firebase, provider, account, sign-in, or production-data action occurred. 27. Ask the platform owner for the matching signed-out public revision readback. 28. While signed out, open `/account` and confirm the normal sign-in boundary remains. @@ -2533,11 +2533,11 @@ Officer review steps for the preserved #506 connected source only: 39. Confirm loading, no-result, fixed-error, and missing-photo states remain readable. 40. Stop. Do not enable connected production Account or Admin controls, search a real name, inspect a real profile, or edit Firebase. -**Expected result:** the frontend artifact defaults to a visibly disabled preview that makes zero directory calls, accepts no file or name, and shows no person. Before exact publication proof, production remains the #473 deploy. Separate synthetic tests prove the protected disabled layouts and preserved connected source. Any later signed-out public readback proves only the exact revision, normal guards, and absence of a member-directory request. The backend and connected behavior remain unavailable. There is no public directory, official roster, public photo URL, Firebase Storage object, photo-as-query path, face recognition, similarity score, embedding, biometric template, export, result total, or pagination. +**Expected result:** production deploy `6a7e072f8f346b0008510d29` defaults to a visibly disabled preview that makes zero directory calls, accepts no file or name, and shows no person. Separate synthetic tests prove the protected disabled layouts and preserved connected source. Completed signed-out public readback proves only the exact revision, normal guards, and absence of a member-directory request. The backend and connected behavior remain unavailable. There is no public directory, official roster, public photo URL, Firebase Storage object, photo-as-query path, face recognition, similarity score, embedding, biometric template, export, result total, or pagination. **Stop conditions:** an enabled preview control; a preview that reads saved directory state, accepts a file or finder name, creates a directory request number, calls a directory service, or shows a sample or result card; a real person, name, photo, member record, production sign-in, direct production Firebase access, production data change, or member-directory callable request; a public/permanent photo URL; an upload that silently opts in; a result from a search transaction ordered after completed opt-out; a notice that fails to explain that an earlier-committed response may still arrive; raw image, name, query, result identity, or provider detail in a log, issue, screenshot, message, email, or AI tool; a request for photo search, face recognition, similarity matching, or biometric processing; missing privacy approval for connected publication; an unreviewed availability flip; or a claim that source, tests, merge, frontend publication, or preview means the backend feature is live. -**Success proof:** record the exact #505, #506, and #621 pull requests and merge commits; green focused and full checks; dependency review; independent privacy/security and backup-officer reviews; and explicit statements that Firebase, providers, accounts/sign-in, and production data were unchanged. While #623 is under review, record the exact source, tree, count, digest, expected parent, and current #473 production/rollback deploy, then state **not published**. If #623 later publishes, record the exact release merge, deploy, public marker, signed-out guards, anonymous no-directory-request result, repause attempt, and retained-deploy readback. Synthetic artifacts and tests prove only the disabled protected layouts and default zero-directory-call branches. Publication and anonymous readback prove only the exact revision, signed-out guards, and absence of a public member-directory request. Record separately that the privacy notice, backend deployment, connected behavior, and live directory were not performed. Final connected live proof belongs to #507. +**Success proof:** record the exact #505, #506, and #621 pull requests and merge commits; green focused and full checks; dependency review; independent privacy/security and backup-officer reviews; and explicit statements that Firebase, providers, accounts/sign-in, and production data were unchanged. For #623, record preview deploy `6a7e05febf8fde00084cf9e0`, preview head `1fdb31f71fcaf01c33b5e57a4cd28fc473a4a737`, PR CI `31728469418`, release merge `9d5cc8612b4321172370bd949d307e7e4ac0ec7d`, exact-main CI `31728908486`, production deploy `6a7e072f8f346b0008510d29`, exact public marker, signed-out guards, anonymous no-connected-symbol/request result, repause head `d401daa409176dce0906c245adf3f20310cb513b`, repause PR CI `31728977578`, repause merge `c8678c623afdd9becf77d596b71f36f26f04b746`, repause exact-main CI `31729248865`, unpublished attempt `6a7e081e73fdd60009f7ba57`, and retained-deploy readback. Record that the manifest is inactive, release source is absent, and rollback ref remains. Synthetic artifacts and tests prove only the disabled protected layouts and default zero-directory-call branches. Publication and anonymous readback prove only the exact revision, signed-out guards, and absence of a public member-directory request. Record separately that the privacy notice, Firebase/backend deployment, provider configuration, account/sign-in change, production-data action, connected behavior, and live directory were not performed. Final connected live proof belongs to #507. **Undo:** before or after frontend-preview publication, use one reviewed frontend revert or safe roll-forward and read back the exact disabled state. The #621 preview changes no Firebase record to undo. After a future approved backend release, use the documented backend-first release path and verify opt-out/removal with a made-up account. Never undo by deleting or editing a real account or Firebase record manually. diff --git a/docs/officers/PUBLISH_AND_CHECK.md b/docs/officers/PUBLISH_AND_CHECK.md index fdef2dd..869d2bd 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. -**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 replacement deploy `6a6dc9ea588b0c0008036312`, exact source `39ab8649df411262c8109a3c81a57bc38f1e168b`, is production now. Shop is the static catalog; Events and Calendar show a fixed retry-later notice instead of a raw provider error. Event records remain unavailable because this did not deploy Firebase. #623 is a separate one-shot release under review for one frozen inert member-directory interface artifact. It is not published or verified, and the #473 deploy is its rollback target. GitHub Pages currently still claims the same custom domain; future source omits that claim, but #136/WEB-001 must publish and verify its removal. +**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`, source `39ab8649df411262c8109a3c81a57bc38f1e168b`, remains the recorded rollback. #623 completed one separate exact-artifact release. Deploy `6a7e072f8f346b0008510d29`, source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, is production now. Its signed-out marker, guard, route, and no-directory-request checks passed. The manifest is inactive, the release source is absent, and the rollback ref remains. Shop is the static catalog; Events and Calendar show a fixed retry-later notice instead of a raw provider error. 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. ## The release gate @@ -57,7 +57,7 @@ As of **2026-07-13**, with the internal tooling note below checked from source o - `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. -- Ordinary Git-triggered Netlify production builds are paused. The completed #473 exception used one exact two-parent merge and pinned source/tree/artifact; its release source is retired. #623 temporarily arms a new exact-parent one-shot under review. It must publish only its frozen artifact, pass signed-out readback, and be re-paused immediately. +- Ordinary Git-triggered Netlify production builds are paused. The completed #473 exception used one exact two-parent merge and pinned source/tree/artifact; its release source is retired. #623 completed a second exact-parent one-shot, published only its frozen inert artifact, passed signed-out readback, and was immediately re-paused. Its release source is retired; its rollback ref remains. - Live race signup, merchandise payments, and refunds remain unavailable. - CONFIG-001B1 [#151](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/151) adds source enforcement for a server-only commerce pause. It is not in the fixed profile-recovery release plan, is not deployed, and has no approved officer control. A future reviewed plan must deploy the complete guarded Function set with the deploy ceiling and every runtime/resource flag off, then prove signed webhooks still work. Do not widen the current plan by hand. @@ -163,28 +163,27 @@ If a member or officer sees **Server configuration is unavailable**: 6. Do not expect GitHub Pages, Firebase, Netlify, or `runmprc.com` to change from a merge unless a separate exact temporary release is explicitly armed and reviewed. 7. For any other merge, if Netlify unexpectedly publishes, stop and treat it as a hosting incident. -## Temporary #623 inert member-directory interface release — UNDER REVIEW; NOT PUBLISHED +## Temporary #623 inert member-directory interface release — COMPLETED 2026-08-13 -**Purpose:** publish only the visibly disabled My Account profile-photo/finder-choice interface and the administrator-guarded People finder layout. This is an interface preview. It does not connect the private backend, read or save a setting, accept or upload a photo, search a name, or show a person. +**Purpose:** record the completed publication of only the visibly disabled My Account profile-photo/finder-choice interface and the administrator-guarded People finder layout. This is an interface preview. It does not connect the private backend, read or save a setting, accept or upload a photo, search a name, or show a person. **Approver:** Dave Liu as platform owner, plus the privacy/security reviewer. This is not an officer-operated control. -**Prerequisites:** approved issue [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) with no newer blocker; exact release ID `WEB-002C-MEMBER-DIRECTORY-PREVIEW-2026-08-13`; green exact-head checks; successful pinned Deploy Preview; source commit `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`; source tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`; 62-file digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`; exact first parent `019353361210021483f23003e09ee6924b78e67c`; current production and rollback deploy `6a6dc9ea588b0c0008036312`; current live source `39ab8649df411262c8109a3c81a57bc38f1e168b`; release source `codex/netlify-source-623-member-directory-preview`; rollback source `codex/netlify-source-623-rollback`; an executable diff proving only the inert interface was added to the live source; synthetic protected-layout proof; a prepared manifest-disable change; a named signed-out public observer; and no other `main` merge until verification and repause finish. +**Completed evidence:** approved issue [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623); release ID `WEB-002C-MEMBER-DIRECTORY-PREVIEW-2026-08-13`; pinned preview deploy `6a7e05febf8fde00084cf9e0`; preview head `1fdb31f71fcaf01c33b5e57a4cd28fc473a4a737`; green PR CI run `31728469418`; source commit `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`; source tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`; 62-file digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`; previous source `39ab8649df411262c8109a3c81a57bc38f1e168b`; rollback deploy `6a6dc9ea588b0c0008036312`; exact release merge `9d5cc8612b4321172370bd949d307e7e4ac0ec7d`, parents `019353361210021483f23003e09ee6924b78e67c` and `1fdb31f71fcaf01c33b5e57a4cd28fc473a4a737`, tree `41b6d024d369d93f28ea49940b4f4e5710d3ab52`; green exact-main CI run `31728908486`; ready production deploy `6a7e072f8f346b0008510d29`, published `2026-08-13T18:05:35.983Z`; signed-out guard, route, marker, and no-connected-symbol/request proof; repause head `d401daa409176dce0906c245adf3f20310cb513b`; green repause PR CI run `31728977578`; exact repause merge `c8678c623afdd9becf77d596b71f36f26f04b746`, parents `9d5cc8612b4321172370bd949d307e7e4ac0ec7d` and `d401daa409176dce0906c245adf3f20310cb513b`; green repause exact-main CI run `31729248865`; unpublished Netlify attempt `6a7e081e73fdd60009f7ba57`; retained production deploy and marker; inactive manifest; absent release source; and retained `codex/netlify-source-623-rollback` ref. Protected-layout proof remains synthetic. ```mermaid flowchart TD - Synthetic["Synthetic local protected-layout proof"] --> Preview["Pinned #623 Deploy Preview"] - Preview --> Match{"Marker, source, tree, count, and digest match?"} - Match -- "No" --> Keep["Stop — keep #473 deploy live"] - Match -- "Yes" --> Merge["Exact-parent merge commit"] - Merge --> Public["Signed-out public revision and guard checks"] - Public --> Good{"Exact artifact and no directory request?"} - Good -- "No" --> Rollback["Restore #473 deploy"] - Good -- "Yes" --> Repause["Disable manifest and verify no replacement"] - Repause --> Retire["Retire release source and record proof"] + Synthetic["Synthetic local protected-layout proof"] --> Preview["Pinned #623 Deploy Preview matched"] + Preview --> Merge["Exact-parent release merged"] + Merge --> Public["Signed-out revision and guards verified"] + Public --> NoRequest["No connected directory symbol or request"] + NoRequest --> Repause["Temporary authority disabled"] + Repause --> Verify["Unpublished attempt; #623 deploy retained"] ``` -In words: synthetic local artifacts prove the protected disabled layouts. The release preview must match the exact frozen artifact. Only the exact-parent merge may publish it. Signed-out public checks then prove only the revision, normal guards, and absence of a directory request. A mismatch leaves or restores the current #473 deploy; a success is immediately re-paused. +In words: synthetic local artifacts prove the protected disabled layouts. The exact preview matched the frozen artifact, the exact-parent merge published it, and signed-out public checks proved only the revision, normal guards, and absence of a directory request. The temporary authority was then disabled; its unpublished attempt left the verified #623 deploy and marker live. The #473 deploy remains the recorded rollback. + +Completed checklist, retained as the audit record: 1. Confirm the release pull request targets `main`. 2. Confirm its exact head and every required check are current and green. @@ -221,13 +220,13 @@ In words: synthetic local artifacts prove the protected disabled layouts. The re 33. Read the public marker again and confirm the verified deploy remains live. 34. Retire the #623 release source and verify it is absent. -**Expected result:** if every gate passes, Netlify serves exactly the frozen inert interface. My Account remains behind sign-in, the People finder remains behind the administrator guard, and no member-directory request is available to a signed-out observer. Protected layouts remain synthetic proof only. The release does not deploy Firebase, Rules, Functions, or indexes; configure a provider; change sign-in, accounts, or production data; or make the backend available. Connected behavior remains **NOT AVAILABLE YET** under #507. +**Expected result:** every gate passed, and Netlify serves exactly the frozen inert interface as deploy `6a7e072f8f346b0008510d29`. My Account remains behind sign-in, the People finder remains behind the administrator guard, and no member-directory request was available to the signed-out observer. Protected layouts remain synthetic proof only. The release deployed no Firebase, Rules, Functions, or indexes; configured no provider; changed no sign-in, account, or production data; and did not make the backend available. Connected behavior remains **NOT AVAILABLE YET** under #507. **Stop conditions:** stop if `main` advances; a branch, context, source, tree, count, digest, parent, marker, page, guard, network record, or repause result differs; the preview is missing; rollback is unavailable; a protected control is enabled; a public check asks for sign-in or private data; a real name or photo appears; a member-directory request is made; another production attempt starts; or any blocker remains open. -**Success proof:** keep the public deploy and marker links, exact hashes, check time, phone/computer widths, signed-out guard results, anonymous no-directory-request record, repause attempt, retained-deploy readback, and one redacted public screenshot if it contains no private content. Record Firebase, provider configuration, account/sign-in changes, and production-data changes as not performed. Do not call synthetic protected-layout proof public production proof. +**Success proof:** preview deploy `6a7e05febf8fde00084cf9e0` matched head `1fdb31f71fcaf01c33b5e57a4cd28fc473a4a737`, and PR CI run `31728469418` passed. Release merge `9d5cc8612b4321172370bd949d307e7e4ac0ec7d` and exact-main CI run `31728908486` passed. Production deploy `6a7e072f8f346b0008510d29` published at `2026-08-13T18:05:35.983Z`; its marker matched source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, tree `411aa6ec9a9459f5d923030533ffc7c007fe6908`, previous source `39ab8649df411262c8109a3c81a57bc38f1e168b`, rollback deploy `6a6dc9ea588b0c0008036312`, 62 files, and digest `d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1`. Signed-out phone/computer guard checks and the anonymous no-connected-symbol/request check passed. Repause head `d401daa409176dce0906c245adf3f20310cb513b` passed PR CI run `31728977578`; merge `c8678c623afdd9becf77d596b71f36f26f04b746` passed all five exact-main jobs in run `31729248865`. Attempt `6a7e081e73fdd60009f7ba57` stopped unpublished, and provider plus marker readback retained deploy `6a7e072f8f346b0008510d29`. The manifest is inactive; release source ref is absent; rollback ref remains. Firebase, provider configuration, account/sign-in, and production data were unchanged. Synthetic protected-layout proof is not public production proof. -**Undo:** before publication, leave deploy `6a6dc9ea588b0c0008036312` live. If the wrong result publishes, ask the Netlify team owner to restore that same deploy. If provider restore is unavailable, use only the reviewed exact-parent rollback pinned to source `39ab8649df411262c8109a3c81a57bc38f1e168b`, then rerun its exact preview and checks. Disabling the manifest alone does not roll back an already published deploy. +**Undo:** if the verified #623 interface later proves wrong, ask the Netlify team owner to restore recorded rollback deploy `6a6dc9ea588b0c0008036312`. If provider restore is unavailable, use only a newly reviewed exact-parent rollback pinned to source `39ab8649df411262c8109a3c81a57bc38f1e168b`, then rerun its exact preview and checks. The retained rollback ref is evidence, not standing publication authority. Disabling the manifest alone does not roll back an already published deploy. **Escalation:** platform owner first; privacy/security owner second; membership lead if the layout or promise is wrong. Use the private incident path if a real name, photo, account, or directory request appears. diff --git a/docs/officers/README.md b/docs/officers/README.md index e7f3dec..9a9ee89 100644 --- a/docs/officers/README.md +++ b/docs/officers/README.md @@ -63,13 +63,13 @@ In words: approve the merge, request one exact release, and approve its protecte Never shorten several of these states to “done.” -Independent officer publishing to the live Netlify host is **NOT AVAILABLE YET**. An overbroad #473 artifact was published and rolled back on 2026-08-01. The bounded replacement remains live as deploy `6a6dc9ea588b0c0008036312` from source `39ab8649df411262c8109a3c81a57bc38f1e168b`: Shop is the static pickup catalog, and Events/Calendar show a fixed retry-later notice instead of a raw provider error. Event records remain unavailable. #623 is one separate, exact-artifact release under review for the inert member-directory interface; it has not published or been verified, and the #473 deploy is its rollback target. This is not a reusable officer control. Use a platform maintainer until the Netlify connection and rollback path are documented and tested. +Independent officer publishing to the live Netlify host is **NOT AVAILABLE YET**. An overbroad #473 artifact was published and rolled back on 2026-08-01; bounded #473 deploy `6a6dc9ea588b0c0008036312` remains the recorded rollback. #623 completed one separate, exact-artifact release of the inert member-directory interface. Deploy `6a7e072f8f346b0008510d29`, source `c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec`, is live. Signed-out guard and no-request checks passed. The temporary manifest is inactive, and its repause attempt did not replace the verified deploy. Shop remains the static pickup catalog, and Events/Calendar show a fixed retry-later notice instead of a raw provider error. Event records remain unavailable. This is not a reusable officer control. Use a platform maintainer until the Netlify connection and rollback path are documented and tested. The protected GitHub release is also **NOT AVAILABLE YET** until #133 configures the environment approvers and short-lived cloud identity. Missing authority stops the release with a red failure before Firebase or website publication. GitHub Pages currently still claims `runmprc.com`, so its normal address redirects to the Netlify-served name. The source stops adding that claim, but #136/WEB-001 must publish and verify the provider setting before officers call Pages an independent copy. -The optional profile-photo and officer People-finder functions are **NOT AVAILABLE YET**. #621 makes the frontend source default an inert preview. My Account shows the future photo and independent finder-choice controls disabled. The administrator-guarded People finder shows its name field and Search button disabled. Neither preview reads saved state, accepts a file or name, creates a request, calls the directory services, or shows people. #623 freezes only that inert interface for one exact Netlify release, but it remains under review and is not production. Officers inspect the protected disabled layouts only in synthetic local artifacts. If publication later passes, signed-out public review proves only the exact revision, normal sign-in and administrator guards, and absence of a member-directory network request. Follow [Events, shop, members, and money](./EVENTS_SHOP_MEMBERS.md), and do not sign in to production or use a real name or photo. #623 changes no Firebase, provider, account, sign-in, or production data. #507 must later prove privacy approval, scoped authorization, isolated staging, backend-first deployment and readback, and a separate reviewed source flip before connected use. The future connected feature is not the official roster and performs no photo query or facial recognition. +The optional profile-photo and officer People-finder functions are **NOT AVAILABLE YET**. #621 makes the frontend default an inert preview. My Account shows the future photo and independent finder-choice controls disabled. The administrator-guarded People finder shows its name field and Search button disabled. Neither preview reads saved state, accepts a file or name, creates a request, calls the directory services, or shows people. #623 published only that inert interface as deploy `6a7e072f8f346b0008510d29`. Officers inspect the protected disabled layouts only in synthetic local artifacts. Completed signed-out public review proved only the exact revision, normal sign-in and administrator guards, and absence of a member-directory network request. Follow [Events, shop, members, and money](./EVENTS_SHOP_MEMBERS.md), and do not sign in to production or use a real name or photo. #623 changed no Firebase, provider configuration, account, sign-in, or production data. #507 must later prove privacy approval, scoped authorization, isolated staging, backend-first deployment and readback, and a separate reviewed source flip before connected use. The future connected feature is not the official roster and performs no photo query or facial recognition. ## Current safety warning diff --git a/docs/officers/REQUEST_A_CHANGE.md b/docs/officers/REQUEST_A_CHANGE.md index 956d312..5093dbf 100644 --- a/docs/officers/REQUEST_A_CHANGE.md +++ b/docs/officers/REQUEST_A_CHANGE.md @@ -34,7 +34,7 @@ Have one of these ready: If you open GitHub yourself, use the [canonical repository on `main`](https://github.com/Run-MPRC/Run-MPRC.github.io/tree/main), then select **Issues**. `main` is now the repository default. Do not use the legacy `dev` branch as the source for a new request. -The GitHub release is manual. A `main` merge runs checks but does not publish the GitHub Pages copy or deploy Firebase. Ordinary Git-triggered Netlify production builds are paused by repository configuration. The first #473 candidate was rolled back; its bounded replacement is live and its temporary manifest is inactive again. It is not a reusable officer control. Netlify provider settings remain separately unverified. Stop and escalate any unexpected publication. +The GitHub release is manual. A `main` merge runs checks but does not publish the GitHub Pages copy or deploy Firebase. Ordinary Git-triggered Netlify production builds are paused by repository configuration. The completed #623 exception published inert-interface deploy `6a7e072f8f346b0008510d29`, then repause attempt `6a7e081e73fdd60009f7ba57` published nothing and retained that deploy. Its temporary manifest is inactive, so it is not a reusable officer control. The earlier completed #473 deploy `6a6dc9ea588b0c0008036312` is rollback history. Netlify provider settings remain separately unverified. Stop and escalate any unexpected publication. ## If you cannot open an AI assistant diff --git a/docs/officers/SYSTEM_MAPS.md b/docs/officers/SYSTEM_MAPS.md index ac0cdf7..49dcf25 100644 --- a/docs/officers/SYSTEM_MAPS.md +++ b/docs/officers/SYSTEM_MAPS.md @@ -86,7 +86,7 @@ flowchart TD Rules --> Functions["Deploy and verify named Functions"] Functions --> Pages["Pages branch without Netlify's domain claim"] Main -. "Ordinary Git production build paused" .-> Netlify - Main -. "Completed #473 exact release; manifest inactive" .-> WebGate{"Temporary authority active?"} + Main -. "Completed #623 exact release; manifest inactive" .-> WebGate{"Temporary authority active?"} WebGate -- "No" --> Stop WebGate -- "Yes" --> Netlify Netlify["Netlify — current live host; reusable protected publication unavailable"] --> Live["runmprc.com"] @@ -94,7 +94,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; ordinary merges cannot publish Netlify and the completed #473 exception is inactive; the future Pages branch must stop claiming the Netlify domain, and both hosts still need separate proof. +In words: merge, release request, and protected approval are separate; a missing or failed Firebase gate publishes nothing; ordinary merges cannot publish Netlify and the completed #623 exception is inactive; its deploy `6a7e072f8f346b0008510d29` remains live while completed #473 deploy `6a6dc9ea588b0c0008036312` is rollback history; the future Pages branch must stop claiming the Netlify domain, and both hosts still need separate proof. ## Account and permission ownership @@ -154,27 +154,24 @@ In words: a signed-in member gets their existing profile unchanged or one new pe Issue [#118](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/118) owns this repair, and [#178](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/178) owns the temporary phone-collection pause. Source code and local tests do not make either live. The website, server Function, database permissions, and made-up live check must each be proven separately. -## Optional profile photo and officer people finder — SOURCE ONLY, NOT LIVE +## Optional profile photo and officer People finder — INERT FRONTEND PREVIEW LIVE; BACKEND NOT LIVE ```mermaid flowchart TD - Account["Signed-in person's Account page"] --> ProfileServer["Private App Check profile actions"] - ProfileServer --> Preference{"Finder choice on?"} - ProfileServer --> Thumbnail["Private processed thumbnail\noriginal not retained"] - Preference -- "No, missing, or invalid name" --> Hidden["No finder entry"] - Preference -- "Yes, current valid name" --> Projection["Minimum server-only name-prefix projection"] - Officer["Verified admin types a name and selects Search"] --> Search["Private App Check search\nfixed rate and result bounds"] - Search --> Projection - Search --> Recheck["Re-read current name, choice, and thumbnail"] - Recheck --> Cards["Up to 24 voluntary name/photo cards"] - Search --> Audit["Minimal audit\nno query or result identities"] - Browser["Browser, including admin"] -. "direct access denied" .-> Projection - Cards -. "does not prove or change" .-> Records["Membership, role, registration, payment, or official roster"] + Account["Signed-in person's Account page"] --> Photo["Photo preview and disabled Choose photo control"] + Account --> Choice["Disabled default-off searchable choice"] + Admin["Existing admin guard"] --> Finder["People finder page"] + Finder --> Input["Disabled name input and Search button"] + Photo -. "No upload or request" .-> Backend["Directory backend — NOT LIVE"] + Choice -. "No save or request" .-> Backend + Input -. "No search or results" .-> Backend + Face["Face or photo search"] --> Never["Not authorized and not available"] + Finder -. "does not prove or change" .-> Records["Membership, role, registration, payment, or official roster"] ``` -In words: a signed-in person separately controls a private processed thumbnail and a default-off finder choice. A verified admin may explicitly search a name prefix, but the server returns at most 24 cards only after rechecking each person's current choice, display name, and thumbnail. Browsers cannot directly access the projection. A card does not prove membership or grant authority. +In words: the live artifact contains the inert photo, searchable-setting, and People finder layouts, but every new control is disabled, no directory request or result is possible, and the backend is not live. Synthetic tests prove the protected Account and administrator layouts; production proof stayed signed out and confirmed only the normal guards and absence of a directory request. Face or photo search is neither authorized nor available, and seeing the interface proves no membership or authority. -Issue [#505](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/505) owns the source-only account slice. Issue [#506](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/506) owns the source-only server search and officer page. Issue [#507](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/507) still owns privacy approval, backend-first release, website publication, and live proof. No issue authorizes a photo query, facial recognition, similarity matching, or biometric processing. Every upload/search rate pseudonym and prefix digest is linkable, not anonymous, and remains private server state. +Issue [#623](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/623) published only this bounded inert interface. Connected source from [#505](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/505) and [#506](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/506) was deliberately excluded from the production artifact. Issue [#507](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/507) still owns privacy approval, backend-first release, website publication of connected behavior, and live proof. No issue authorizes a photo query, facial recognition, similarity matching, or biometric processing. Do not use real names or photos to test the inert preview. ## Verification email action — SOURCE ONLY, NOT LIVE diff --git a/tests/release-workflow.test.js b/tests/release-workflow.test.js index 0e03380..2d5c895 100644 --- a/tests/release-workflow.test.js +++ b/tests/release-workflow.test.js @@ -270,7 +270,7 @@ test('Netlify manifest pins the inactive bounded #623 interface release', () => ); }); -test('completed #473 records remain the current live predecessor truth', () => { +test('completed #623 records are live while #473 remains rollback history', () => { assert.match( netlifyConfig, /temporary #623 production authority is inactive again/i, @@ -280,108 +280,129 @@ test('completed #473 records remain the current live predecessor truth', () => { /Ordinary[\s\S]{0,20}previews use their checked-out tree/i, ); - const expectedTruth = new Map([ + finalReleaseTruth.forEach((contents, relativePath) => { + assert.match(contents, /#623/); + assert.match(contents, /6a7e072f8f346b0008510d29/); + assert.match(contents, /#473/); + [ + /PENDING #473 RELEASE/i, + /Temporary #473 permissions-containment release — PENDING REVIEW AND RELEASE/i, + /Issue #473 now prepares a replacement/i, + /#473's narrower replacement is \*\*NOT AVAILABLE YET\*\*/i, + ].forEach((staleClaim) => { + assert.doesNotMatch( + contents, + staleClaim, + `${relativePath} must not retain stale #473 release status`, + ); + }); + }); + + const completedTruth = new Map([ [ 'IMPLEMENTATION_PLAN.md', - /bounded replacement \[#473\][^\n]*deploy `6a6dc9ea588b0c0008036312`[^\n]*temporary manifest became inactive again/i, + /#623[^\n]*completed[^\n]*published[^\n]*6a7e072f8f346b0008510d29/i, ], [ 'OFFICER_START_HERE.md', - /bounded replacement is still live as Netlify deploy `6a6dc9ea588b0c0008036312`[^\n]*#623 is a separate one-shot release under review/i, + /#623[^\n]*completed[^\n]*6a7e072f8f346b0008510d29[^\n]*live/i, ], [ 'OPERATIONS_RUNBOOK.md', - /WEB-002A \[#473\][^\n]*completed[^\n]*9ad6837756cdd409d296009fde5082eeeae5c059[^\n]*6a6dc9ea588b0c0008036312[^\n]*cb6a8f0a418fc14b448bce5ded71d68520415c92[^\n]*6a6dcdd47bc81e000859a249/i, + /#623[^\n]*completed[^\n]*6a7e072f8f346b0008510d29[^\n]*published/i, ], [ 'README.md', - /bounded replacement deploy `6a6dc9ea588b0c0008036312`[^\n]*temporary manifest is inactive again/i, + /completed bounded #623 release[^\n]*published deploy `6a7e072f8f346b0008510d29`/i, ], [ 'SECURITY.md', - /Bounded replacement \[#473\][^\n]*6a6dc9ea588b0c0008036312[^\n]*Final control `cb6a8f0`[^\n]*6a6dcdd47bc81e000859a249/i, + /#623[^\n]*published[^\n]*inert[^\n]*6a7e072f8f346b0008510d29/i, ], [ 'SYSTEM_DESIGN.md', - /used one bounded replacement exception[^\n]*6a6dc9ea588b0c0008036312[^\n]*manifest became inactive again/i, + /#623[^\n]*completed[^\n]*published[^\n]*inert[^\n]*6a7e072f8f346b0008510d29/i, ], [ 'docs/officers/ACCESS_CONTINUITY.md', - /temporary #473 release is complete[^\n]*manifest is inactive[^\n]*release source is absent/i, + /live #623 marker[^\n]*deploy `6a7e072f8f346b0008510d29`/i, ], [ 'docs/officers/EVENTS_SHOP_MEMBERS.md', - /In-person Shop catalog — LIVE[\s\S]*Public Events-list load failure privacy — LIVE FRONTEND CONTAINMENT[\s\S]*Public Events-calendar load failure privacy — LIVE FRONTEND CONTAINMENT/i, + /#623 published only that inert interface[^\n]*deploy `6a7e072f8f346b0008510d29`/i, ], [ 'docs/officers/PUBLISH_AND_CHECK.md', - /Temporary #473 permissions-containment release — COMPLETED 2026-08-01[\s\S]*cb6a8f0a418fc14b448bce5ded71d68520415c92[\s\S]*6a6dcdd47bc81e000859a249/i, + /#623 completed[^\n]*Deploy `6a7e072f8f346b0008510d29`[^\n]*production now/i, ], [ 'docs/officers/README.md', - /bounded replacement remains live as deploy `6a6dc9ea588b0c0008036312`[^\n]*#623 is one separate[^\n]*release under review/i, + /#623 completed[^\n]*inert[^\n]*Deploy `6a7e072f8f346b0008510d29`[^\n]*live/i, ], [ 'docs/officers/REQUEST_A_CHANGE.md', - /bounded replacement is live[^\n]*temporary manifest is inactive again/i, + /completed #623 exception published inert-interface deploy `6a7e072f8f346b0008510d29`/i, ], [ 'docs/officers/SYSTEM_MAPS.md', - /Completed #473 exact release; manifest inactive/i, + /completed #623 exception[^\n]*deploy `6a7e072f8f346b0008510d29` remains live/i, ], ]); - - finalReleaseTruth.forEach((contents, relativePath) => { + completedTruth.forEach((expectedTruth, relativePath) => { + const record = finalReleaseTruth.get(relativePath); assert.match( - contents, - expectedTruth.get(relativePath), - `${relativePath} must describe final #473 authority and availability`, + record, + expectedTruth, + `${relativePath} must bind #623's completed state to the live deploy`, ); [ - /PENDING #473 RELEASE/i, - /Temporary #473 permissions-containment release — PENDING REVIEW AND RELEASE/i, - /Issue #473 now prepares a replacement/i, - /#473's narrower replacement is \*\*NOT AVAILABLE YET\*\*/i, + /#623[^\n]{0,80}(?:release|artifact)[^\n]{0,40}(?:is|remains|was) (?:still )?(?:under review|not published)/i, + /#623[^\n]{0,120}has not published or been verified/i, + /#623[^\n]{0,120}remains under review and is not production/i, + /That release is under review and not published/i, + /production (?:still )?serves[^\n]*#473/i, + /Temporary #623[^\n]*— (?:UNDER REVIEW|PENDING)/i, ].forEach((staleClaim) => { assert.doesNotMatch( - contents, + record, staleClaim, - `${relativePath} must not retain rollback-era #473 status`, + `${relativePath} must not retain stale #623 release status`, ); }); }); - const pendingTruth = [ - 'IMPLEMENTATION_PLAN.md', - 'OFFICER_START_HERE.md', - 'OPERATIONS_RUNBOOK.md', - 'SECURITY.md', - 'SYSTEM_DESIGN.md', - 'docs/officers/EVENTS_SHOP_MEMBERS.md', - 'docs/officers/PUBLISH_AND_CHECK.md', - 'docs/officers/README.md', - ].map((relativePath) => finalReleaseTruth.get(relativePath)); - pendingTruth.forEach((record) => { - assert.match(record, /#623/); - assert.match(record, /(?:under review|not published)/i); - assert.match(record, /6a6dc9ea588b0c0008036312/); - }); + const canonicalRecords = [ + finalReleaseTruth.get('OPERATIONS_RUNBOOK.md'), + finalReleaseTruth.get('docs/officers/PUBLISH_AND_CHECK.md'), + ]; [ + '9d5cc8612b4321172370bd949d307e7e4ac0ec7d', + '6a7e072f8f346b0008510d29', 'c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec', '411aa6ec9a9459f5d923030533ffc7c007fe6908', 'd837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1', '019353361210021483f23003e09ee6924b78e67c', + 'c8678c623afdd9becf77d596b71f36f26f04b746', + '6a7e081e73fdd60009f7ba57', + '31729248865', ].forEach((identifier) => { - [ - finalReleaseTruth.get('OPERATIONS_RUNBOOK.md'), - finalReleaseTruth.get('docs/officers/PUBLISH_AND_CHECK.md'), - ].forEach((record) => assert.match(record, new RegExp(identifier))); + canonicalRecords.forEach((record) => { + assert.match(record, new RegExp(identifier)); + }); + }); + canonicalRecords.forEach((record) => { + assert.match(record, /(?:62 files|62-file)/i); + assert.match( + record, + /(?:6a7e081e73fdd60009f7ba57[\s\S]{0,240}(?:unpublished|published nothing|publish nothing)|(?:unpublished|published nothing|publish nothing)[\s\S]{0,240}6a7e081e73fdd60009f7ba57)/i, + ); + assert.match( + record, + /(?:6a7e072f8f346b0008510d29[\s\S]{0,300}(?:retained|remained|left|stayed)|(?:retained|remained|left|stayed)[\s\S]{0,300}6a7e072f8f346b0008510d29)/i, + ); }); - const canonicalRecords = [ - finalReleaseTruth.get('OPERATIONS_RUNBOOK.md'), - finalReleaseTruth.get('docs/officers/PUBLISH_AND_CHECK.md'), - ]; + // Preserve the complete historical #473 release and rollback chain. [ '40728ff6141e34a279b70cc41d983c22ac5f0daa', '6a6dc0167fbe68000816b448',