Repository navigation
MEMBERS-IDENTITY-001A — Define provider-neutral membership authority and entitlement contract #208
Description
Officer impact: None yet. This child defines and tests an unused membership-authority contract. It does not change signup, dues, discounts, account access, officer screens, or any live member record.
Officer documentation: Update only the membership-authority future-state section in docs/officers/EVENTS_SHOP_MEMBERS.md, including a matching Mermaid diagram and text alternative. Current officer procedures must remain NOT AVAILABLE YET.
Deployment evidence: None at issue creation. Closure must report source, tests, merge, website, runmprc.com, Firebase, provider configuration, production data, migration, and live behavior separately. A green workflow proves no external surface is live.
Problem
The current website has Firebase accounts and role claims, but no provider-neutral contract separating a stable MPRC membership from the account used to sign in. A membership may exist before a website account, and annual access must eventually follow approved membership-term evidence. Google, WhatsApp, Strava, an email match, or a browser role must never become membership authority.
Downstream #82, #83, #109, and #114–#117 need one fail-closed contract, but owner decisions in #110/#113/#114 still block data fields, retention, legacy disposition, pricing, grace, plan eligibility, refunds/disputes, and production adoption.
Atomic outcome
Add one unused CommonJS pure module and focused tests that define a versioned provider-neutral membership-authority snapshot, deterministic technical transitions, and a fixed fail-closed entitlement projection.
The contract may represent:
- one stable opaque membership ID independent of Firebase UID;
- an optional explicit UID association with revision and an immediate last-command marker;
- one versioned current-term reference with explicit start/end boundaries and opaque plan/evidence references;
- explicit
decision_pendingstates for unresolved owner policy; and - a non-identifying entitlement result that is never active when required state is missing, malformed, conflicting, out of order, expired, suspended, or pending.
It does not decide whether an underlying payment, plan, person, household, refund, dispute, or legacy row is valid. A future trusted runtime must establish those facts.
flowchart LR
M["Stable MPRC membership ID"] --> A{"Explicit UID association?"}
A -- "No or conflict" --> D["No website entitlement"]
A -- "Yes" --> T{"Versioned term and evidence references complete?"}
T -- "No or decision pending" --> D
T -- "Yes" --> P{"Approved policy inputs and explicit time bounds admit access?"}
P -- "No" --> D
P -- "Yes" --> E["Fixed current-member entitlement result"]
G["Google / WhatsApp / Strava / email"] -. "projection only; never authority" .-> D
Text alternative: a stable membership record receives website access only after an explicit UID association and a complete, policy-approved term reference. Missing, conflicting, expired, suspended, or undecided state denies entitlement. External identities and channels never grant membership.
Invariants
- The module is pure, deterministic, unused, CommonJS, and has no Firebase, Firestore, Auth, Stripe, provider, clock, environment, network, logger, random, filesystem, or Functions-index import.
- Account identity and membership identity remain separate. No same-email, provider, phone, role, or client field creates an association.
- Membership IDs, command IDs, term IDs, plan references, and evidence references are bounded opaque values. No names, emails, phones, addresses, DOB, emergency contacts, provider IDs/tokens, payment IDs/details, URLs, free text, or roster data are accepted, returned, or logged.
- A record can remain valid without a UID. Such a record cannot produce website entitlement.
- UID association is explicit and revision-bound within one snapshot. Exact latest-command retry is read-only/deterministic; a changed latest retry or a correct-revision second/different UID association on the same membership fails closed. Durable UID uniqueness across membership records remains future trusted-runtime work.
- Term boundaries are explicit and half-open; the module does not choose calendar-year versus anniversary policy. Missing, invalid, reversed, expired, future-only, suspended, or
decision_pendingterms do not grant entitlement. - Plan and evidence references are opaque. The module does not verify payment, choose prices/plans, or interpret refund/dispute policy.
- Outputs are fixed and non-identifying. Invalid/hostile input exposes one generic boundary and no partial values.
- No unbounded mutable audit/history array is introduced. Runtime persistence and append-only audit are future work.
- No schema, Rules, custom claim, role, profile, migration, endpoint, UI route, provider configuration, deployment, or production record changes.
- Existing AUTH-001B — Require verified email for role-based Firestore access #196 verified-email and DATA-001C2 — Stop profile setup from copying Firebase Auth phone numbers #197 phone-minimization behavior remains unchanged.
Required tests
- Valid account-independent record with no UID remains valid but ineligible for website access.
- Explicit association plus a complete currently admitted term yields only the fixed entitled result.
- Exact latest-command retry is deterministic; a changed latest command, wrong expected revision, unchanged older-command replay, stale/reordered command, and correct-revision second/different UID association on the same membership fail closed. Reuse of an older raw command ID after an intervening command and UID uniqueness across separate membership records require the future durable journal/index.
- Missing/malformed identifiers, extra keys, accessors/proxies, unsupported versions/enums, invalid times, reversed bounds, boundary instants, future, expired, suspended, and pending decisions deny or return the generic invalid boundary as specified.
- Provider/email/phone/role/payment/PII fields are rejected.
- Inputs are not mutated; returned records/results are frozen or otherwise protected from caller mutation.
- Source scans prove no runtime/index import, external SDK, logger, environment, network, timestamp generation, random value, provider field, or deployment edge.
- Focused tests, full Functions tests/lint, Firestore Rules, frontend/SPA/build, workflow/artifact safety, and diff checks pass using Node 20 and Java 17 where applicable.
Exact owned paths
- New
functions/membershipAuthority.js - New
functions/membershipAuthority.test.js - Only the named membership-authority section and diagram in
SYSTEM_DESIGN.md - Only the matching membership-authority future-state section and diagram in
docs/officers/EVENTS_SHOP_MEMBERS.md
Dependencies and coordination
- Parent MEMBERS-IDENTITY-001 — Define authoritative membership and external-account state #81 is upstream of DATA-001B — Inventory personal data and approve a minimization/retention matrix #110, BACKEND-001 — Audit the Firebase cutover and approve legacy data disposition #113, MEMBERS-DUES-001 — Build server-authoritative annual membership checkout and renewal #114, MEMBERS-ADMIN-001 — Add audited officer membership association and manual activation #115, and AUTH-002A — Retire the legacy static-key membership sync before manual onboarding #117.
- SEC-001/SEC-001 — Replace the Firestore admin catch-all with resource-specific rules #100 is closed. AUTH-001B/AUTH-001B — Require verified email for role-based Firestore access #196 source is merged; live Firebase proof remains open and blocks runtime adoption, not this unused pure contract.
- The coordinating commerce task explicitly approved this disjoint child. PAY-002B2C3C may edit only its commerce-command C3C section in
SYSTEM_DESIGN.md; this child may edit only its named membership-authority section. - The later-merging pull request must refresh from current
mainand preserve both exact truths. - No other open ready issue or PR existed when this child was approved for publication.
Owner-dependent decisions deliberately deferred
- DATA-001B — Inventory personal data and approve a minimization/retention matrix #110: approved fields, purposes, access, retention, deletion, and sharing.
- BACKEND-001 — Audit the Firebase cutover and approve legacy data disposition #113: legacy source disposition and any future import.
- MEMBERS-DUES-001 — Build server-authoritative annual membership checkout and renewal #114 children: calendar versus anniversary policy, grace, plans/prices/eligibility, payment-evidence semantics, refunds/disputes, renewal/lapse/reactivation.
- AUTH-003/ADMIN: privileged authorization, recent authentication, MFA, revocation, and audit.
- Future children: durable command journal, cross-record UID uniqueness, Firestore schema, Rules, claims/token refresh, runtime adoption, migration, protected deployment, and live verification.
Explicitly out of scope
Do not edit commerce-command/C3A–C3C sections, STRIPE_COMMERCE_DESIGN.md, SECURITY.md, IMPLEMENTATION_PLAN.md, GITHUB_ISSUES.md, GITHUB_ISSUE_SLICES.md, Rules, Auth/profile/signup code, Functions index/endpoints, packages/workflows, or any provider/deployment configuration.
Do not use real members, accounts, payments, providers, or production data.
Claim protocol
Creation is not a claim. Before any file edit, assign the issue, post CLAIMED by <canonical agent> at <UTC>; branch <branch>; exact base <SHA>, re-read live comments, and move status:ready to status:in-progress. Earliest valid claim wins.
Activity
daliu commentedon Jul 14, 2026
CLAIMED by /root at 2026-07-14T03:22:49Z; branch
codex/issue-208-membership-authority; exact base1730977eca65dc7df59bb7f195bbc44afd7e5895.Exact ownership:
functions/membershipAuthority.jsfunctions/membershipAuthority.test.jsSYSTEM_DESIGN.mddocs/officers/EVENTS_SHOP_MEMBERS.mdThe active PAY-002B2C3C task owns only its commerce-command C3C hunk in
SYSTEM_DESIGN.mdand will preserve this membership hunk. I will preserve its hunk. All commerce journal/reconciliation files, C3A–C3C text,STRIPE_COMMERCE_DESIGN.md,SECURITY.md,IMPLEMENTATION_PLAN.md, issue trackers, Rules, Auth/profile/signup/runtime/index code, packages/workflows, providers, deployment, migration, and production data are excluded.MEMBERS-IDENTITY-001A: define membership authority contract (#210)
daliu commentedon Jul 14, 2026
COMPLETE / CLAIM RELEASED.
aee505cacd0d8f155ed14c9bb0942b02a158aa2df84c4c8883a2f6e9c400081051e9d8f4eaf64e05status:in-progresswas removed; the four-path claim is released.Deployment/live truth:
runmprc.comverified for this source: not applicable; no website behavior changed.Durable command replay, cross-record account-link uniqueness, approved membership/payment policy, schema, Rules, authorization, migration, protected deployment, and live proof remain future work. Do not treat #208 as an available membership system.
MEMBERS-DUES-001A: immutable membership term/evidence receipt ledger (#…
MEMBERS-DUES-001A: immutable membership term/evidence receipt ledger (#…
MEMBERS-IDENTITY-001C: provider-neutral external-account link + colli…
MEMBERS-IDENTITY-001E: reconcile membership entitlement to authorizat…
MEMBERS-ADMIN-001A: project officer manual off-platform dues-evidence…