Repository navigation
OAUTH-001B10 — Require exact Strava disconnect client confirmation #610
Description
Outcome
My Account may hide the connected Strava identity and activity only after the callable fulfills with one exact ordinary confirmation: { ok: true }. Every other fulfilled value must enter the existing fixed unknown-result path.
Parent: #88. This is the explicitly reserved OAUTH-001B10 child and does not close the parent.
Problem
On exact main 9d8bfaae0a4f9e573053b4035954e933ae626875, src/services/strava/stravaService.ts returns unchecked callable result.data. StravaSection treats every fulfillment—including { ok: false }, null, or malformed data—as confirmed, hides the connected athlete/activity, and shows Connect Strava. That can falsely acknowledge an external-account revocation that the client did not confirm.
Invariant and allowed transition
Only an exact ordinary response with the sole own enumerable data property ok equal to primitive true may resolve. The service returns a fresh frozen canonical { ok: true }.
Null, primitives, arrays, custom/null prototypes, missing or extra keys, symbol/non-enumerable keys, inherited confirmation, accessors, ok: false, non-Boolean values, and exceptional reflection/data access reject with exactly Invalid Strava disconnect response. without echoing the input. The existing component catch must then preserve the connected view, end the busy state, re-enable Disconnect, and show the fixed refresh-before-retry alert.
Transport rejection stays uninspected and preserves its rejection identity.
Browser JavaScript cannot reliably identify every faithfully transparent nonthrowing Proxy. Firebase wire decoding does not ordinarily produce Proxies or accessors. The boundary safely projects any exact presented data contract rather than retaining the received object; revoked or throwing reflection is contained by the fixed error. Do not overclaim Proxy detection.
Exact scope
src/services/strava/stravaService.ts: one exact disconnect-confirmation reader; callable response becomesunknown; narrow the successful return to a fresh frozenReadonly<{ ok: true }>.src/pages/account/Account.test.tsx: a trustworthy RED, exact positive/negative/adversarial service matrix, transport-rejection preservation, and one composition proof through the existing fixed browser failure path.SECURITY.md: only the RISK-024 current-truth hunk; record this source boundary and remove only the now-resolved client-confirmation residual.docs/officers/EVENTS_SHOP_MEMBERS.md: only the existing “Strava disconnect failure privacy — SOURCE ONLY, NOT LIVE” procedure; distinguish rejected requests from fulfilled non-confirmations and preserve the no-terminal refresh/stop/escalate path.
No StravaSection.tsx runtime change is expected. Its existing rejection path already has the required fixed unknown-result behavior.
Excluded: Functions, Firestore/Rules, schemas/migrations, App Check/Auth admission, packages/locks, workflows, provider calls/configuration, real accounts/tokens/data, Firebase deployment, website publication, and live verification.
Acceptance and tests
- Trustworthy RED on the exact base: a callable fulfillment
{ data: { ok: false } }must reject with the fixed response error; old source instead fulfills{ ok: false }. - Accept only exact ordinary
{ ok: true }, including frozen input. - Return an independent, frozen canonical result and never the received object.
- Reject missing, false, non-Boolean, extra, inherited, accessor-backed, malformed, exceptional, and hostile-reflection shapes without invoking response field getters or exposing detail.
- Preserve transport rejection identity without inspection.
- Compose the actual service validator with My Account and prove an invalid fulfillment keeps athlete/activity visible, keeps Connect hidden, re-enables Disconnect, shows only the fixed alert, and logs no raw detail.
- Run focused frontend tests, the full frontend suite, lint baseline, SPA/safety checks, Functions/Rules/commerce regressions, diagnostic build, diff check, and dependency audits.
- Independent runtime/security, test, and backup-officer review must return GO on the exact remote head.
No migration is required.
Officer and deployment boundary
Officer impact: Source will stop a fulfilled but unconfirmed disconnect result from hiding the connected view. The member still receives the existing instruction to refresh before another attempt.
Officer documentation: docs/officers/EVENTS_SHOP_MEMBERS.md, existing disconnect-failure procedure only.
Deployment evidence: At issue creation, none. Source, tests, merge, website publication, runmprc.com, Firebase deployment, Strava/provider state, production data, and live behavior must be recorded separately. No real disconnect or provider call is authorized.
Residual provider serialization/reconciliation, connection-only writers, durable audit/tombstone, IAM/encryption, protected deployment, configuration, and live proof remain under #88.
Activity
daliu commentedon Aug 2, 2026
CLAIMED by /root at 2026-08-02T07:09:52Z on branch
codex/issue-610-strava-disconnect-confirmation, exact base9d8bfaae0a4f9e573053b4035954e933ae626875.Exact ownership:
src/services/strava/stravaService.ts: exact fulfilled disconnect-confirmation reader and callable return boundary only.src/pages/account/Account.test.tsx: separately named OAUTH-001B10 service matrix and one existing-browser-path composition test only.SECURITY.md: RISK-024 current-truth hunk only.docs/officers/EVENTS_SHOP_MEMBERS.md: existing Strava disconnect failure procedure hunk only.All other paths/hunks are excluded.
StravaSection.tsx, Functions, Firestore/Rules, packages, workflows, provider/configuration, real accounts/tokens/data, deployments, and live behavior are unclaimed. Any overlap is a STOP-and-coordinate condition.Officer impact: source-only preservation of the connected view for a fulfilled non-confirmation.
Officer documentation:
docs/officers/EVENTS_SHOP_MEMBERS.md, exact existing procedure hunk.Deployment evidence: none at claim; no website, Firebase, Strava, production-data, or live action.
daliu commentedon Aug 2, 2026
TRUSTWORTHY RED on exact base
9d8bfaae0a4f9e573053b4035954e933ae626875, before runtime or documentation changes:a306c6f36f0962feac599c6121184745164eaf67e04664a70d5544cc7fe5fc6fCI=true react-scripts test --watch=false --runInBand src/pages/account/Account.test.tsx -t OAUTH-001B10{ ok: false }; the regression requires the fixedInvalid Strava disconnect response.rejection.Only the named test exists at this marker. No runtime, SECURITY/officer documentation, Firebase, Strava/provider, data, deployment, or live change has been made. Claim remains held.
daliu commentedon Aug 2, 2026
RED EVIDENCE CORRECTION: the exact test-only binary diff SHA-256 is
03e16813248431f9a3f33cf8a6d0a642406ab5f13419ab9f762b05de56e2794a. The prior comment’s hash was a transcription error; its exact base, command, one intended failure, skipped count, observed old-source fulfillment, and no-runtime/no-doc boundary remain correct.daliu commentedon Aug 2, 2026
COMPLETE / CLOSED / CLAIM RELEASED
OAUTH-001B10 is complete. PR #611 merged after exact-head self-review and three independent GO reviews.
Evidence:
9d8bfaae0a4f9e573053b4035954e933ae6268754ea0b7f0e1d830f42a5c33c6d4cfed3b5f35c56d5975d21f867b27fafab901a10f5aa84e99c063f62c94be8c182c32405225566d63d29bedf379a857421501a5c0938c2901618095a4c23c8b69a6076f01c3f4be3f06efed50fa9a72Officer impact: A disconnect success is now accepted only after the callable returns the exact documented
{ok: true}confirmation. Malformed fulfilled responses stay on the connected screen and show the fixed failure path.Officer documentation:
docs/officers/EVENTS_SHOP_MEMBERS.md; engineering risk record:SECURITY.mdRISK-024.Deployment evidence (checked 2026-08-02):
6a6eeffad8ef7f0008e9bfc9is ready butpublished_atis null. Main attempt6a6ef0b0b8a874000896f33ais error withpublished_atnull.runmprc.comverified: the public release marker still identifies WEB-002A — Publish bounded Shop and Events permissions containment #473 (controlCommit9ad6837756cdd409d296009fde5082eeeae5c059, source39ab8649df411262c8109a3c81a57bc38f1e168b), not this merge.Residual: JavaScript reflection can encounter exotic provider-created Proxy objects; throwing/revoked proxies fail closed, and a transparent proxy that presents the exact contract is projected into a new frozen local object. The callable backend remains the trusted source of disconnect state. No schema, migration, package, live provider, or production-data change was required.
The issue is closed as completed, the branch is deleted remotely, the assignee and in-progress label are removed, and the claim is released.