Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ Exit gate:

**MEMBERS-DIRECTORY-001E current source boundary:** [#627](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/627) hardens only the preserved connected frontend. New opt-in uses the projection's exact bounded Unicode display-name eligibility; an existing opt-in remains removable after the name becomes ineligible. Profile placeholders and control-linked generic errors, explicit search validation state, a non-counting successful-search announcement, scoped explicit contrast, keyboard/touch geometry, 320-pixel containment, and stale file-read fencing improve accessibility and race behavior without adding a data path. The availability value remains `false`, so the default source branch remains inert; the live #623 preview remains unchanged. This issue changes no Functions, Rules, indexes, service contract, package, workflow, release control, provider, account, sign-in, or production data. #507 still owns connection, privacy approval, scoped authorization, isolated staging, backend-first deployment/readback, the reviewed availability flip, connected publication, and live proof.

**MEMBERS-DIRECTORY-001F current source boundary:** [#629](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/629) changes only the preserved connected Account photo controls. A valid selected JPG, PNG, or WebP is validated and read locally into a centered-square component-memory draft labeled **Selected photo — not uploaded yet**. Selecting, reading, previewing, or cancelling creates no request ID and sends nothing. Only **Save profile photo** creates the request ID and sends the existing revisioned upload request. Confirmed Save clears the draft after refetch. Request-ID failure or a definitive rejection with successful refetch retains a retryable draft; the retry uses the refreshed revision. Unknown upload/readback state or failed rejection readback discards the draft and hides controls. A visibility save preserves the independent draft and refreshes its later Save revision. The application never reads, retains, renders, logs, sends, or otherwise exposes `file.name`; tests use only opaque generated fixture names. Stale reads and render events are fenced across reselection, Cancel, unmount, application change, and account change. Invalid or unreadable selections retain no draft; an unrenderable draft drops its bytes and cannot be saved. The separate saved thumbnail stays authoritative, with a version-reset **Photo unavailable** fallback and Remove still available if it cannot render. Finder visibility remains independent. The availability value stays `false`, the default branch and live #623 preview remain inert, and #507 retains every backend, privacy, authorization, staging, deployment, connection, publication, and live-proof gate.

### Phase 5 — End-to-end qualification

**Issue:** TEST-001 plus final closure evidence from all prior phases
Expand Down
1 change: 1 addition & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,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-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 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. |
| Source-only privacy and accessibility containment for RISK-042 | MEMBERS-DIRECTORY-001E [#627](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/627) makes the preserved connected Account branch use the projection's bounded Unicode display-name eligibility before a new opt-in while preserving turn-off for an existing opt-in whose name becomes ineligible. It gives no-photo placeholders image semantics, associates generic photo/setting errors with the affected control, exposes name-search validation state and descriptions, and announces a successful non-empty result without a total. Native controls retain keyboard use, explicit readable foreground/background colors, at least 44-pixel interaction height, and 320-pixel containment. A deferred file read cannot submit or render after the application/user context changes. Generated-only tests cover eligible/ineligible current-name updates, accessibility states, narrow layout/contrast classes, and stale file-read races. | This is source-only frontend hardening behind the unchanged `false` availability value. The live #623 preview remains inert; no backend, Rules, index, service contract, package, workflow, provider, release, account, sign-in, or production-data behavior changes. Accessibility state is not authorization, and a browser eligibility check is not server enforcement. #507 still owns privacy approval, scoped authorization, protected authority, isolated staging, backend-first deployment/readback, the availability flip, connected publication, and live proof. Do not use a real name or photo. |
| Source-only explicit photo-review containment for RISK-042 | MEMBERS-DIRECTORY-001F [#629](https://github.com/Run-MPRC/Run-MPRC.github.io/issues/629) makes the preserved connected Account branch validate and read a selected JPG, PNG, or WebP locally into a centered-square component-memory draft labeled **Selected photo — not uploaded yet**. Selection, validation, reading, preview, and Cancel create no request ID and call no directory service. Only explicit **Save profile photo** creates the request ID and sends the existing revisioned upload request. Confirmed Save clears the draft after authoritative refetch. Request-ID failure or definitive rejection plus successful refetch retains a retryable draft and adopts the refreshed revision; unknown or failed readback discards the draft and hides controls. A visibility save preserves the draft. The application never reads, retains, renders, logs, sends, or otherwise exposes `file.name`; tests use only opaque generated fixture names. Generation and application/account-context fences prevent an older read or render event from changing or uploading a newer draft. Invalid and unreadable selections retain no draft. Unrenderable bytes and their draft UI are discarded, the fixed error remains associated with the persistent file control, and no Save action is exposed. The authoritative saved thumbnail has a version-reset, byte-free **Photo unavailable** fallback while Remove remains available. | A local preview still places private image bytes in browser memory, and explicit Save does not itself prove an approved notice, scoped authority, backend deployment, or successful processing. Retryable bytes intentionally remain in component memory only for request-ID failure or definitive rejection with successful readback; an unknown outcome clears them. This source-only UI control stays behind the unchanged `false` availability value; the live #623 preview remains inert. It changes no visibility preference or service/server contract. #507 still owns privacy and retention approval, scoped authorization, protected authority, isolated staging, backend-first deployment/readback, the availability flip, connected publication, and live proof. Use only generated non-face test images; do not inspect or upload a real photo. |
| 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. |
Expand Down
Loading