diff --git a/GITHUB_ISSUES.md b/GITHUB_ISSUES.md
index 70ee857..70c727e 100644
--- a/GITHUB_ISSUES.md
+++ b/GITHUB_ISSUES.md
@@ -1,6 +1,6 @@
# GitHub Issue Backlog: Secure Commerce Program
-**COMMUNITY-002 / #707:** one staging-only service/UI for pending membership requests/withdrawal, paid-term cancellation intent and free-event signup/cancellation. Dependencies: #701 hosted profiles/Auth/App Check, #705 approved paid-term policy and existing pure authority; paid activation/dues/production work stays separate. UID-only additive server collections, native identity/attestation, transaction/revision/saved-command safety and bounded reads; no payment, role, email, schedule, migration or production fallback. Officer impact: disposable staging review only. Officer documentation: STAGING_COMMUNITY plus entrypoints/maps/cost guide. Deployment evidence: source/emulator preparation only until native hosted acceptance is recorded. #114 and production launch remain open.
+**COMMUNITY-002 / #707:** one staging-only service/UI for pending membership requests/withdrawal, paid-term cancellation intent and free-event signup/cancellation. Dependencies: #701 hosted profiles/Auth/App Check, #705 approved paid-term policy and existing pure authority; paid activation/dues/production work stays separate. UID-only additive server collections, native identity/attestation, transaction/revision/saved-command safety and bounded reads; no payment, role, email, schedule, migration or production fallback. Officer impact: disposable staging review only. Officer documentation: STAGING_COMMUNITY plus entrypoints/maps/cost guide. Deployment evidence: version1 native archive/spec/IAM, website60435c8,38 genuine hosted checks and all four page actions verified on 2026-10-11; #707 records final website/visual/cleanup proof. #114 and production launch remain open.
**MEMBERS-CANCEL-001A / #705 (2026-10-11):** owner-approved cancellation retains membership access through the already-paid annual term and does not issue an automatic refund. Scope: versioned backend source policy, existing authority expiry/ownership/suspension regressions, and officer handoff. No cancellation endpoint, persistence, claim, Rule, IAM, website, provider or deployment change. #114 and hosted membership/event signup/cancellation remain open. Officer impact: the rule is recorded; no new member control is available. Officer documentation: entrypoint and Events/Shop/Members guide. Deployment evidence: source/local checks only until native issue records otherwise.
diff --git a/OFFICER_START_HERE.md b/OFFICER_START_HERE.md
index b5a0262..19d0237 100644
--- a/OFFICER_START_HERE.md
+++ b/OFFICER_START_HERE.md
@@ -16,7 +16,7 @@ Attach the exact wording, public link, or approved photo when you have it. The A
## Choose the closest task
-**Staging membership/free events — #707:** one isolated service and screen are being prepared for pending membership signup/withdrawal, paid-term cancellation requests and free-event signup/cancellation. No paid membership activation or real payment is included. Hosted acceptance is not verified yet. Follow the [staging-only review](./docs/officers/STAGING_COMMUNITY.md); production remains **NOT AVAILABLE YET**.
+**Staging membership/free events — #707:** one isolated service and screen passed hosted pending membership signup/withdrawal, synthetic paid-term cancellation and free-event signup/cancellation checks on 2026-10-11. No paid membership activation or real payment is included. Follow the [staging-only review](./docs/officers/STAGING_COMMUNITY.md); ask the specialist for disposable fixtures. The issue records the current website, visual review and cleanup; production remains **NOT AVAILABLE YET**.
**Membership cancellation decision, 2026-10-11:** Dave approved keeping access through the already-paid annual term, without an automatic refund. [#705](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/705) records the rule and checks the existing term-end logic only. A member cancellation control is **NOT AVAILABLE YET**; do not edit a member record or use race cancellation as a workaround. See [the membership policy handoff](./docs/officers/EVENTS_SHOP_MEMBERS.md#membership-cancellation--policy-approved-not-available-yet).
diff --git a/OPERATIONS_RUNBOOK.md b/OPERATIONS_RUNBOOK.md
index 5cc474d..9eac528 100644
--- a/OPERATIONS_RUNBOOK.md
+++ b/OPERATIONS_RUNBOOK.md
@@ -830,6 +830,8 @@ The current protected release plan names only the profile-recovery Functions. It
For #707, only the club owner may use the fixed `scripts/staging-community-release.js` after reviewed exact-main source/six successful jobs. It deploys one isolated Function through the existing explicit builder, with a separate four-permission runtime and native archive/resource readback. This is a separately approved staging owner route, not a widening of the protected profile workflow or a reusable production release. The profile path may inspect the one known community service but still deploys only its original pair. The specialist supplies/removes UID-only synthetic fixtures, tests actual Auth/App Check plus retry/ownership/capacity/term-boundary behavior, then records staged Hosting and cleanup evidence. Officers use [the no-terminal staging review](./docs/officers/STAGING_COMMUNITY.md). Never run against production or a payment provider; future release cleanup/rollback uses a separate reviewed owner action, not direct member edits.
+On 2026-10-11, #707 verified `communityActions` version1 from `7e3dc451368c70e4b63805927b12d413e8739b56`; its81,228-byte native archive exactly matches SHA256 `1b78f38d8b5563e9e88482f68d5f57c3249c49c43c69b49eed3efbcd5fa7e148`. Profile versions2/1 and their labels remained unchanged. First Hosting60435c8 passed38 genuine browser boundary/lifecycle checks and all four page actions. Hosting uses an email-verified club-owner short-lived token only in process memory, with explicit staging quota and no ADC/login/key fallback. A script/docs-only newer main may reuse the Function only with ancestor provenance, exact current bundle and native archive readback; no extra Function build is required. The final issue receipt separately records current Hosting, visual review and fixture cleanup; production/real payments remain excluded.
+
For future membership cancellation acceptance, use a disposable account and a synthetic approved term. Prove access remains just before the original term end and is denied at/after it; the term and payment evidence must not change. Also prove ownership denials, repeated/lost-response recovery, and that suspension is not undone. #705 currently supplies only the approved policy and existing-authority unit regressions, not the cancellation request or hosted proof. Do not test with production members or real payments.
Before every major payment release:
diff --git a/SECURITY.md b/SECURITY.md
index 8a3e438..f6e10f2 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -8,7 +8,7 @@ This is both the repository security policy and the current engineering risk reg
## 1. Production readiness decision
-**#707 isolated staging boundary:** one new service requires native Auth/App Check and an exact caller-account match; mutations also require verified email. It accepts closed bounded inputs and server-owned free-event/waiver/capacity state, saves command results transactionally and fences stale revisions. Browser access to new collections remains denied, including admins. The separate staging runtime has only transaction/get/create/update Firestore permissions; IAM is project-scoped, not collection-scoped. It has no Auth mutation, delete, secret, key, payment or mail permission. No claims, real membership/payment data, production fallback, raw error/body logging or legacy schema migration. Existing two profile Functions and their runtime IAM are unchanged. Hosted enforcement must be separately verified before claiming this source is live.
+**#707 isolated staging boundary:** one new service requires native Auth/App Check and an exact caller-account match; mutations also require verified email. It accepts closed bounded inputs and server-owned free-event/waiver/capacity state, saves command results transactionally and fences stale revisions. Browser access to new collections remains denied, including admins. The separate staging runtime has only transaction/get/create/update Firestore permissions; IAM is project-scoped, not collection-scoped. It has no Auth mutation, delete, secret, key, payment or mail permission. No claims, real membership/payment data, production fallback, raw error/body logging or legacy schema migration. Existing two profile Functions and their runtime IAM are unchanged. Native archive/spec/IAM and38 genuine hosted ownership/attestation/lifecycle checks were verified on 2026-10-11; this proves only the staged boundary, not production, financial operations or a spending cap.
The public informational website can continue operating with normal care. **Live race or merchandise payments should remain disabled until every P0 launch blocker below is closed and verified in a staging dress rehearsal.** The existing payment implementation is a useful prototype, but several correctness defects could mark unpaid transactions paid, lose payment callbacks, oversell race capacity, fail to reconcile late-payment links, or allow overly broad administrative access.
diff --git a/SYSTEM_DESIGN.md b/SYSTEM_DESIGN.md
index fa4e76a..0298ee5 100644
--- a/SYSTEM_DESIGN.md
+++ b/SYSTEM_DESIGN.md
@@ -10,7 +10,7 @@ The repository already contains a substantial prototype: a public React site, Fi
## 1. Goals and non-goals
-**Isolated nonfinancial lifecycle — #707, source prepared:** `communityOnly.js` exports only `communityActions`, outside the prototype index. Native Auth/App Check, exact account binding and verified email protect mutations. UID-only pending membership requests never grant dues/roles; cancellation preserves an approved synthetic authority record and its original expiry. Server-owned zero-price events/waiver snapshots and UID registrations share one capacity transaction. Per-account command results/revision fences prevent old cancellation retries changing a later signup. New `communityMemberships`, `communityEvents`, `communityCommands`, `communityLimits` and `communityConfig` collections are server-only; no migration or legacy commerce adoption. A separate runtime has exactly Firestore transaction/get/create/update permissions at staging-project scope. UI and server fail closed outside staging. The existing pure authority is now consumed only by this isolated staging service; earlier unused-runtime statements below remain historical outside this scope. No role/dues activation, Stripe/mail, officer admin endpoint, schedule or production release is included. Hosted acceptance remains unverified; see the [officer staging guide](./docs/officers/STAGING_COMMUNITY.md).
+**Isolated nonfinancial lifecycle — #707, staging only:** `communityOnly.js` exports only `communityActions`, outside the prototype index. Native Auth/App Check, exact account binding and verified email protect mutations. UID-only pending membership requests never grant dues/roles; cancellation preserves an approved synthetic authority record and its original expiry. Server-owned zero-price events/waiver snapshots and UID registrations share one capacity transaction. Per-account command results/revision fences prevent old cancellation retries changing a later signup. New `communityMemberships`, `communityEvents`, `communityCommands`, `communityLimits` and `communityConfig` collections are server-only; no migration or legacy commerce adoption. A separate runtime has exactly Firestore transaction/get/create/update permissions at staging-project scope. UI and server fail closed outside staging. The existing pure authority is now consumed only by this isolated staging service; earlier unused-runtime statements below remain historical outside this scope. No role/dues activation, Stripe/mail, officer admin endpoint, schedule or production release is included. First native hosted acceptance was verified on 2026-10-11; see the [officer staging guide](./docs/officers/STAGING_COMMUNITY.md) and #707 for current website/cleanup proof, not production availability.
**Engineering staging checkpoint, 2026-10-11 — #701:** only signup-profile creation and profile recovery are hosted and verified on Node 22. A profile-only entrypoint, explicit runtime/build accounts, scoped IAM and protected keyless deployment exclude commerce/mail/directory/Strava and website publication. Actual source archives/resource limits, genuine App Check/Auth, synthetic signup/recovery/denials/retries/concurrency and owned cleanup passed. Auth count returned to zero; no migration or production data/payment change. This supersedes source-only runtime/profile wording below only for isolated staging, not production or the target commerce platform. See the [dated officer map](./docs/officers/SYSTEM_MAPS.md#scoped-engineering-profile-release--701) and [acceptance proof](./docs/officers/LOW_COST_COMMUNITY.md#engineering-staging-profiles--701).
diff --git a/docs/officers/EVENTS_SHOP_MEMBERS.md b/docs/officers/EVENTS_SHOP_MEMBERS.md
index 0d572f2..47f21c8 100644
--- a/docs/officers/EVENTS_SHOP_MEMBERS.md
+++ b/docs/officers/EVENTS_SHOP_MEMBERS.md
@@ -12,7 +12,7 @@ There is currently no proven no-code switch that safely stops all new Stripe pay
## Membership cancellation — POLICY APPROVED, NOT AVAILABLE YET
-[#707](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/707) prepares the separate [staging-only request and free-event review](./STAGING_COMMUNITY.md). This does not launch production membership, grant a paid term, or repair paid race cancellation. Hosted evidence is still required.
+[#707](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/707) verified the separate [staging-only request and free-event review](./STAGING_COMMUNITY.md) on 2026-10-11. Fresh disposable fixtures still require the specialist. This does not launch production membership, grant a paid term, or repair paid race cancellation.
Dave approved this rule on October 11, 2026: cancelling membership keeps access through the already-paid annual term. Cancellation does not issue a refund. It does not extend the term or restore suspended access. Refunds and race cancellation remain separate.
diff --git a/docs/officers/LOW_COST_COMMUNITY.md b/docs/officers/LOW_COST_COMMUNITY.md
index 67624c5..0f62576 100644
--- a/docs/officers/LOW_COST_COMMUNITY.md
+++ b/docs/officers/LOW_COST_COMMUNITY.md
@@ -8,7 +8,7 @@
## What we are prioritizing
-[#707](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/707) adds one staging-only nonfinancial service, with the same min0/max2/256MB/30s limits and no polling, mail worker, subscription or scheduled job. Existing profile IAM stays unchanged; the new runtime has four Firestore permissions at staging-project scope. See the [staging scope, proof and recovery guide](./STAGING_COMMUNITY.md). This source preparation is not deployment proof or a cost guarantee.
+[#707](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/707) verified one staging-only nonfinancial service on 2026-10-11, with the same min0/max2/256MB/30s limits and no polling, mail worker, subscription or scheduled job. Existing profile IAM stays unchanged; the new runtime has four Firestore permissions at staging-project scope. See the [staging scope, proof and recovery guide](./STAGING_COMMUNITY.md). Hosted acceptance is not a cost guarantee or a production launch.
- Clear information about regular runs, meeting places, joining, and contacts.
- A useful events/calendar experience on phones as well as computers.
diff --git a/docs/officers/STAGING_COMMUNITY.md b/docs/officers/STAGING_COMMUNITY.md
index e4ac0fd..4441c28 100644
--- a/docs/officers/STAGING_COMMUNITY.md
+++ b/docs/officers/STAGING_COMMUNITY.md
@@ -1,6 +1,6 @@
# Membership and free events — staging only
-**Status:** SOURCE PREPARED; hosted deployment and acceptance are not verified yet under [#707](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/707). Production is **NOT AVAILABLE YET**.
+**Status:** STAGING ONLY — the Function and first website release were verified on 2026-10-11 under [#707](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/707). Pending membership requests/withdrawal, synthetic paid-term cancellation, free-event signup/cancellation, native Auth/App Check denials, retries and capacity passed hosted checks. Production is **NOT AVAILABLE YET**. The issue records the latest website source, visual review and disposable-data cleanup separately.
**Purpose:** test membership requests and free-event signup/cancellation without real members or payments.
@@ -16,7 +16,7 @@
- Free-event signup: confirms one place and records acceptance of the displayed test waiver.
- Cancel event signup: releases that place once. Old retries cannot cancel a later signup.
-Officer review after the specialist confirms deployment:
+Officer review after the specialist supplies fresh disposable fixtures:
1. Open the specialist-supplied staging `/community` link.
2. Confirm the page says **Staging test only**.
@@ -41,6 +41,8 @@ Officer review after the specialist confirms deployment:
**Success proof:** the specialist records exact source/CI, native Function archive and resource/IAM readback, staging Hosting release, genuine Auth/App Check denials, capacity/retry/ownership tests, and disposable-data cleanup separately. Local tests or a merge alone are not hosted proof. The term-end check uses synthetic evidence, not a real payment.
+The first verified backend is version 1 from `7e3dc451368c70e4b63805927b12d413e8739b56`. Its native archive is 81,228 bytes with SHA-256 `1b78f38d8b5563e9e88482f68d5f57c3249c49c43c69b49eed3efbcd5fa7e148`. The first verified website is `60435c8fe0846625f22067b0d9b2e76171317d2b`. Thirty-eight genuine hosted boundary/lifecycle checks passed, followed by all four page actions. Twenty distinct emulator accounts and two disposable hosted accounts separately proved final-seat safety. Cancellation preserved the synthetic term evidence and access; the real server clock then ended access. No custom role claims, charges, refunds or emails were created. These are dated staging proofs, not production availability or actual payment proof.
+
**Undo:** stop the staging review. Ask Dave and the platform specialist to use the reviewed staging rollback or remove the one staged community service. Do not edit a member record, role, payment or production setting yourself.
The specialist's Hosting release uses Dave's existing club login for a short-lived credential kept in memory. It does not require a new saved Firebase CLI login or key file. A later documentation or release-script fix may reuse the Function only after its downloaded source exactly matches the reviewed bundle; it does not silently deploy more backend code.
diff --git a/docs/officers/SYSTEM_MAPS.md b/docs/officers/SYSTEM_MAPS.md
index f95c3f8..b1cf8ae 100644
--- a/docs/officers/SYSTEM_MAPS.md
+++ b/docs/officers/SYSTEM_MAPS.md
@@ -2,11 +2,13 @@
These diagrams show where pages, information, and deployments go. Each diagram includes a one-sentence text version.
-## Staging community lifecycle — #707, source prepared
+## Staging community lifecycle — #707, first hosted release verified 2026-10-11
```mermaid
flowchart LR
Account["Staging My Account"] --> Page["/community; production disabled"]
+ Page --> Login["Signed out: sign in; return to /community"]
+ Login --> Identity
Page --> Identity["Native Auth + App Check; own account only"]
Identity --> Service["One communityActions Function; min0/max2"]
Service --> Requests["Pending membership / cancellation request; no paid grant"]
@@ -16,7 +18,7 @@ flowchart LR
Browser["Browser member/admin"] -. "Denied direct access" .-> Requests
```
-Text alternative: a staging-only account link opens one authenticated service that stores member requests, transactionally manages free-event seats and saves retry results, while preserving the original term and denying direct browser writes. Hosting/provider proof is not yet recorded; no production, payment, mail or role-grant path is added.
+Text alternative: a staging-only account link opens one authenticated service that stores member requests, transactionally manages free-event seats and saves retry results, while preserving the original term and denying direct browser writes; signed-out visitors return after sign-in. First Hosting/provider acceptance is recorded in the staging guide and #707; no production, payment, mail or role-grant path is added.
## Engineering staging billing — checked 2026-10-11
diff --git a/src/pages/community/Community.css b/src/pages/community/Community.css
new file mode 100644
index 0000000..198785d
--- /dev/null
+++ b/src/pages/community/Community.css
@@ -0,0 +1,54 @@
+.community-staging {
+ box-sizing: border-box;
+ width: calc(100% - 2.5rem);
+ max-width: 800px;
+ margin-inline: auto;
+ padding-block: 2rem;
+ overflow-wrap: anywhere;
+}
+
+.community-staging h1 { margin-bottom: 1rem; }
+.community-staging h2 { margin-bottom: 0.75rem; }
+.community-staging p { margin-block: 0.75rem; }
+.community-staging a { text-decoration: underline; }
+
+.community-staging [role="note"] {
+ padding: 1rem;
+ border-left: 4px solid var(--color-secondary);
+ background: var(--color-gray-500);
+}
+
+.community-staging section {
+ margin-top: 1.5rem;
+ padding: 1.25rem;
+ border: 1px solid #77759e;
+ border-radius: 0.75rem;
+}
+
+.community-staging button {
+ min-height: 44px;
+ max-width: 100%;
+ margin: 0.25rem 0.25rem 0.25rem 0;
+ padding: 0.6rem 1rem;
+ border: 1px solid #a9bfff;
+ border-radius: 0.4rem;
+ background: var(--color-primary);
+ color: #fff;
+ font: inherit;
+ cursor: pointer;
+}
+
+.community-staging button:disabled {
+ background: #32314e;
+ color: #c7c6d7;
+ border-color: #77759e;
+ cursor: not-allowed;
+}
+
+.community-staging label { display: flex; gap: 0.75rem; align-items: center; min-height: 44px; }
+.community-staging input[type="checkbox"] { width: 20px; min-width: 20px; height: 20px; }
+
+@media (max-width: 480px) {
+ .community-staging section { padding: 1rem; }
+ .community-staging button { width: 100%; margin-inline: 0; }
+}
diff --git a/src/pages/community/Community.test.tsx b/src/pages/community/Community.test.tsx
index 8f8e33c..cf0f237 100644
--- a/src/pages/community/Community.test.tsx
+++ b/src/pages/community/Community.test.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { MemoryRouter } from 'react-router-dom';
+import { MemoryRouter, useLocation } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async';
import {
act, fireEvent, render, screen, waitFor
@@ -42,6 +42,25 @@ test('signed-out page makes no backend call', () => {
expect(screen.getByRole('link', { name: 'Sign in to continue' })).toBeInTheDocument();
expect(call).not.toHaveBeenCalled();
});
+test('signed-out staging notice stays visible and sign-in returns to community', () => {
+ mockUser = null;
+ function LocationProbe() {
+ const location = useLocation();
+ return ;
+ }
+ render(
+
Loading account…
; + if (isLoading) returnLoading account…
Staging test only. Use made-up accounts. No real membership, race entry or payment is created.
+ Sign in to continue@@ -127,6 +130,7 @@ export default function Community() { && (
Access continues through the paid term ending + {' '} {new Date(status.membership.accessThroughMs).toLocaleString()} .