You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Officer impact: None yet. This child defines and tests an unused technical consent-decision receipt contract. It does not change signup, membership, discounts, Google, WhatsApp, Strava, officer screens, or any live account.
Officer documentation: Update only a named future-state consent-receipt section in docs/officers/EVENTS_SHOP_MEMBERS.md, including a Mermaid diagram and text alternative. Current officer procedures remain NOT AVAILABLE YET.
Deployment evidence: None at issue creation. Closure must distinguish source, tests, merge, website publication, Firebase deployment, provider configuration, production data, migration, and live behavior. A green workflow does not prove an external surface is live.
Problem
Parent #81 requires provider-neutral consent as part of external-account state. Merged child #370 derives effective consent only from caller-supplied latest-decision evidence, and merged child #445 consumes that effective disposition in provider-link lifecycle reconciliation. Neither contract defines how a grant or withdrawal becomes an immutable, ordered, replay-safe technical receipt.
Without this seam, a future runtime could overwrite the latest decision, accept a skipped or conflicting command, silently reorder withdrawal and re-grant, or feed #370 evidence that was not projected from the canonical technical history head.
Atomic outcome
Add one unused CommonJS pure module and focused tests that:
create a bounded provider-neutral consent-decision track head;
append one immutable grant or withdrawal receipt from the current head and one exact command; and
Use append-oriented individual receipts plus one bounded latest-state head. Do not place an unbounded receipts[] history in a mutable record.
Invariants
Every track, receipt, and disposition hard-codes grantsAuthority: false. Consent never grants membership, price, payment state, role, or admin authority.
The module is pure, deterministic, clockless, unused, CommonJS, and imported by no runtime or Functions index.
One track is bound to exactly one provider, opaque subject reference, and opaque scope reference.
The empty head has revision zero and represents no decision. none is never accepted as an append command.
The first receipt has revision one and no prior receipt; every later receipt advances the exact current revision by one and binds the exact latest receipt.
Exact retry of the latest command is read-only and returns the same canonical frozen receipt/head. Reusing that command ID with a changed receipt ID, expected revision, decision, or policy version fails closed.
A stale, future, skipped, repeated, or unsafe revision; current receipt-ID reuse; cross-track evidence; an internally inconsistent head; and safe-integer exhaustion fail closed.
Withdrawal never deletes or rewrites a prior grant. A later grant after withdrawal creates a new receipt.
Ordering comes only from the monotonic receipt revision. No timestamp, policy-version ordering, or recency rule is invented.
Inputs are strict exact plain data objects. Proxies, accessors, inherited fields, extra or missing fields, symbols, non-enumerable fields, malformed identifiers, PII-shaped values, and unsafe integers fail through one fixed non-echoing boundary.
Outputs and nested values are frozen. No input value is logged.
Durable all-history identifier uniqueness and create-only persistence remain future trusted-runtime responsibilities; this bounded source contract detects only conflicts visible at the current head.
Prove provider neutrality and exact provider/subject/scope binding against an independent test oracle.
Prove exact latest retry is read-only and returns the same frozen canonical receipt/head.
Reject changed latest-command reuse, stale/future/skipped/repeated revision, current receipt-ID reuse, cross-track and internally inconsistent heads, safe-integer exhaustion, malformed policy versions, and unknown enum values.
Prove hostile values/getters/proxies and raw email-, phone-, URL-, token-, error-, name-, or policy-text-shaped values never enter output, error, or logs.
Prove exact objects only: missing, extra, inherited, symbol, non-enumerable, accessor, and revoked-proxy inputs fail without getter invocation or input echo.
Prove outputs and nested enum collections are frozen.
Source scans prove only node:util and ./membershipConsentState are imported; there is no clock, environment, randomness, network, Firebase, provider SDK, logger, runtime/index import, or receipt-history array.
Focused tests, Functions lint/full tests, and applicable repository gates pass on Node 20.
Exact owned paths
New functions/membershipConsentReceipt.js
New functions/membershipConsentReceipt.test.js
Only the named consent-receipt section/diagram in SYSTEM_DESIGN.md
Only the matching future-state section/diagram in docs/officers/EVENTS_SHOP_MEMBERS.md
Remaining #81 work includes approved minimization/retention/deletion/access-revocation policy, runtime actor authorization, trusted capture facts, persistence, durable all-history command uniqueness, cross-record uniqueness, Firestore schema/Rules, Auth claim writes and token actions, provider wiring, migration, deployment, and live verification.
Explicitly out of scope
Do not add actor identity, capture method, notice or policy text, evidence content, timestamps represented as legal proof, provider-specific scope values, retention/deletion periods, withdrawal SLA, access roles, assisted-consent policy, or provider calls.
Do not edit Functions index/endpoints, Firestore Rules, packages, workflows, existing Google/WhatsApp/Strava runtime, GITHUB_ISSUES.md, GITHUB_ISSUE_SLICES.md, or provider/deployment configuration.
Do not use real members, accounts, provider identifiers, policy text, tokens, errors, or production data.
Claim protocol
Creation is not a claim. Before any repository file edit, assign the issue, create and push a unique branch from exact current main, 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.
Officer impact: None yet. This child defines and tests an unused technical consent-decision receipt contract. It does not change signup, membership, discounts, Google, WhatsApp, Strava, officer screens, or any live account.
Officer documentation: Update only a named future-state consent-receipt section in
docs/officers/EVENTS_SHOP_MEMBERS.md, including a Mermaid diagram and text alternative. Current officer procedures remainNOT AVAILABLE YET.Deployment evidence: None at issue creation. Closure must distinguish source, tests, merge, website publication, Firebase deployment, provider configuration, production data, migration, and live behavior. A green workflow does not prove an external surface is live.
Problem
Parent #81 requires provider-neutral consent as part of external-account state. Merged child #370 derives effective consent only from caller-supplied latest-decision evidence, and merged child #445 consumes that effective disposition in provider-link lifecycle reconciliation. Neither contract defines how a grant or withdrawal becomes an immutable, ordered, replay-safe technical receipt.
Without this seam, a future runtime could overwrite the latest decision, accept a skipped or conflicting command, silently reorder withdrawal and re-grant, or feed #370 evidence that was not projected from the canonical technical history head.
Atomic outcome
Add one unused CommonJS pure module and focused tests that:
classifyConsentStatecontract from MEMBERS-IDENTITY-001D — Provider-neutral versioned consent-state derivation (source only, unused) #370.Use append-oriented individual receipts plus one bounded latest-state head. Do not place an unbounded
receipts[]history in a mutable record.Invariants
grantsAuthority: false. Consent never grants membership, price, payment state, role, or admin authority.noneis never accepted as an append command.Required tests
not_consented,active,reaffirmation_required, andwithdrawn.node:utiland./membershipConsentStateare imported; there is no clock, environment, randomness, network, Firebase, provider SDK, logger, runtime/index import, or receipt-history array.Exact owned paths
functions/membershipConsentReceipt.jsfunctions/membershipConsentReceipt.test.jsSYSTEM_DESIGN.mddocs/officers/EVENTS_SHOP_MEMBERS.mdDependencies and coordination
Remaining #81 work includes approved minimization/retention/deletion/access-revocation policy, runtime actor authorization, trusted capture facts, persistence, durable all-history command uniqueness, cross-record uniqueness, Firestore schema/Rules, Auth claim writes and token actions, provider wiring, migration, deployment, and live verification.
Explicitly out of scope
Do not add actor identity, capture method, notice or policy text, evidence content, timestamps represented as legal proof, provider-specific scope values, retention/deletion periods, withdrawal SLA, access roles, assisted-consent policy, or provider calls.
Do not edit Functions index/endpoints, Firestore Rules, packages, workflows, existing Google/WhatsApp/Strava runtime,
GITHUB_ISSUES.md,GITHUB_ISSUE_SLICES.md, or provider/deployment configuration.Do not use real members, accounts, provider identifiers, policy text, tokens, errors, or production data.
Claim protocol
Creation is not a claim. Before any repository file edit, assign the issue, create and push a unique branch from exact current main, post
CLAIMED by <canonical agent> at <UTC>; branch <branch>; exact base <SHA>, re-read live comments, and movestatus:readytostatus:in-progress. Earliest valid claim wins.