Repository navigation
MEMBERS-DIRECTORY-001K — Validate saved WebP responses through the Account UI boundary #639
Description
Parent: #504. Connected release remains owned by #507.
Officer impact: No live officer workflow changes. In the preserved future My Account interface, clearly mislabeled saved-thumbnail response bytes will be rejected before reaching the page, while structurally WebP bytes that the browser cannot display will keep the existing recoverable Photo unavailable fallback and Remove action.
Officer documentation: Update SYSTEM_DESIGN.md, IMPLEMENTATION_PLAN.md, SECURITY.md, and only the optional-directory one-sentence text alternative plus one no-terminal source-evidence procedure in docs/officers/EVENTS_SHOP_MEMBERS.md. The data-flow diagram does not change.
Deployment evidence: None at issue creation. This is source-only response-boundary hardening. memberDirectoryAvailability.ts must remain byte-for-byte false; no website, Firebase, provider, account/sign-in, production-data, deployment, or connected-live action is authorized.
Atomic outcome
Validate structurally WebP saved-photo responses at the actual Account component→service boundary without changing outbound photo-upload semantics.
Defect
On exact released main 7877babc96c78f54d11685b4ffb91496c3bf6945, memberDirectoryService.ts validates returned profile photos for exact fields, image/webp, canonical bounded base64, 256×256 dimensions, and UUID version, but accepts arbitrary decoded bytes. The server stored-photo boundary and officer-search client additionally require at least 12 bytes with RIFF at bytes 0–3 and WEBP at bytes 8–11. Existing profile component tests mock the service, so they cannot prove malformed callable bytes stop before the Account DOM.
Invariant
- Only an exact returned photo object with canonical decoded bytes between 12 and 65,536 bytes,
RIFFat bytes 0–3, andWEBPat bytes 8–11 may become aMemberDirectoryProfile.photo. - Failure uses only the fixed
Invalid member directory response.error; no raw bytes, provider values, filename, or caught detail is rendered or logged. - Structural admission is not full image decoding. Header-valid bytes may still fail browser decode; the existing version-scoped byte-free
Photo unavailablefallback must replace the image whileRemove current saved photoremains available. - The structural check applies only to returned saved-photo state. Outbound JPEG, PNG, and WebP upload admission and exact bytes remain unchanged.
- The actual component→actual service→mocked
firebase/functionsbridge is tested in the existing service test file; no real Firebase/network/account/data access. - Availability stays false; the default branch remains inert and zero-call.
- No photo query, facial recognition, matching, embedding, similarity, biometric processing, roster authority, or membership proof.
Exact ownership
src/services/account/memberDirectoryService.ts- only its private canonical-base64 helper return value and inbound returned-photo RIFF/WEBP structural admission.
src/services/account/memberDirectoryService.test.ts- one separately named MEMBERS-DIRECTORY-001K block covering the response matrix and a real
MemberDirectoryProfile→actual service→mockedfirebase/functionsbridge; reuse this existing file, with no rename/new test file.
- one separately named MEMBERS-DIRECTORY-001K block covering the response matrix and a real
SYSTEM_DESIGN.md- one separately named 001K source-only paragraph.
IMPLEMENTATION_PLAN.md- one separately named 001K current-source paragraph.
SECURITY.md- one separately named 001K/RISK-042 row immediately after released 001J; preserve active OAUTH-001A2L — Bound Strava activity/statistics JSON and cancel the unread statistics body #616 OAUTH-001A2L/RISK-024 byte-for-byte.
docs/officers/EVENTS_SHOP_MEMBERS.md- only the optional-directory one-sentence text alternative and one separately named no-terminal 001K evidence procedure; no Mermaid change.
Required tests
- Capture trustworthy RED on old runtime for canonical non-WebP bytes resolving and reaching the actual connected component image path.
- Accept an exact 12-byte RIFF/WEBP structural envelope.
- Accept an exact 65,536-byte structurally valid envelope.
- Reject empty, truncated (<12), wrong-RIFF, wrong-WEBP, noncanonical, and 65,537-byte responses with the one fixed error.
- Preserve exact MIME/dimension/version/object/accessor/hostile-value validation.
- Prove canonical non-RIFF outbound WebP upload bytes still reach the callable unchanged.
- Through the real component and real service with only
firebase/functionsmocked, prove mislabeled bytes render the generic unavailable state and never create a saved-thumbnailimgor data URL. - Through that bridge, prove admitted-but-browser-undecodable bytes initially reach the fixed-type saved image; a synthetic error then removes its data URL, renders the accessible
Photo unavailablefallback, keeps Remove enabled, and creates no extra callable. - Default unavailable branch remains zero-context, zero-ID, and zero-call.
- Focused/full frontend, TypeScript, lint baseline, diagnostic build, workflow/security tests, diff check, and independent security/frontend/operations reviews pass.
Explicit exclusions
MemberDirectoryProfile.tsxand its mocked unit test, Account wiring/tests, CSS/layout, admin finder/search service, outbound upload semantics, or new test/lint-baseline files.- Functions, Rules, indexes, schemas, repair/backfill, packages, workflows, or release controls.
- Privacy-notice approval, AUTH-003 capability design, role/MFA changes, or MEMBERS-DIRECTORY-001C — Release and verify the opt-in officer photo directory #507 activation.
- Firebase/provider configuration, deployment, sign-in, accounts, production data, real names/photos, or live connected behavior.
- Both active OAUTH-001A2L — Bound Strava activity/statistics JSON and cancel the unread statistics body #616 Strava files and its separately named SECURITY OAUTH-001A2L/RISK-024 hunk.
Migration and residual risk
No migration. Client magic validation is structural admission, not full decoding, authenticity, server-state proof, provider authorization, or deployment evidence. Browser decode fallback remains necessary. #507 retains all connection/release gates.
Claim protocol
Assign the issue and post a timestamped CLAIMED marker naming the exact branch and released base before any source edit. The claim remains active through reviewed merge, exact-main audit, closure, and explicit release.
Activity
daliu commentedon Aug 13, 2026
CLAIMED by /root at 2026-08-13T23:27:32.986Z on branch
codex/issue-639-profile-webp-response, exact released base7877babc96c78f54d11685b4ffb91496c3bf6945.Exact ownership:
src/services/account/memberDirectoryService.ts: only inbound returned-photo canonical-base64 decoding and RIFF/WEBP structural admission; outbound upload admission remains unchanged.src/services/account/memberDirectoryService.test.ts: one separately named MEMBERS-DIRECTORY-001K response/integration block in this existing file; real component + real service, only firebase/functions mocked; no new file.SYSTEM_DESIGN.md,IMPLEMENTATION_PLAN.md, andSECURITY.md;docs/officers/EVENTS_SHOP_MEMBERS.md; no Mermaid change.Everything else is immutable: MemberDirectoryProfile runtime/unit test, Account wiring, CSS, admin finder/search service, availability, Functions, Rules, indexes, packages, workflows, release controls, privacy/capability policy, providers, accounts/sign-in, data, deployment/live behavior, #507 gates, and both active #616 Strava files plus its OAUTH-001A2L/RISK-024 SECURITY hunk. No source edit preceded this marker. Claim remains active through reviewed merge, exact-main audit, closure, and explicit release.
daliu commentedon Aug 13, 2026
IMPLEMENTATION / RED-GREEN / REVIEW MARKER — exact six-path candidate on released base
7877babc96c78f54d11685b4ffb91496c3bf6945.Trustworthy test-only RED on the unchanged runtime: 38/42 passed and 4/42 failed exactly where expected—an 11-byte truncated response, wrong RIFF marker, and wrong WEBP marker all resolved instead of rejecting, and canonical mislabeled bytes reached the actual connected Account component
imgpath rather than the fixed unavailable state.GREEN and full evidence on the exact current worktree:
--noEmit: passed.git diff --check: passed.9dcf682311b2a788af65cfade3094ff1979ea55c3ef55343835c3865687a4e35.Three independent final reviews are GO with no remaining findings: security/privacy/response-contract; frontend/integration/a11y; backup-officer/operations/docs. The inbound saved-photo response now requires canonical decoded bytes from 12 through 65,536, RIFF at bytes 0–3, and WEBP at bytes 8–11. Clearly mislabeled bytes use the existing fixed error and never reach an image/data URL. Structurally admitted bytes that the browser cannot display keep the accessible byte-free Photo unavailable fallback and enabled Remove action with no extra callable. Outbound JPG/PNG/WebP upload admission and exact bytes remain unchanged.
memberDirectoryAvailability.tsremains byte-identical and literalfalse. The exact six changed paths are the claim. Both active #616 Strava blobs and its RISK-024/OAUTH SECURITY area remain unchanged. Source/tests changed only; nothing is merged or published, runmprc.com remains the inert #623 artifact, and Firebase/providers/accounts/sign-in/data/live connected behavior remain unchanged. Claim remains active through reviewed merge and exact-main release audit.daliu commentedon Aug 13, 2026
CANDIDATE / PR MARKER — PR #640 is open at exact reviewed head
db1211166f9a7388a40d6197f50f5b52f8d57c36, tree524cad1dc12025e0adb09fc1c8f4e04caf5fd035, sole parent and current main7877babc96c78f54d11685b4ffb91496c3bf6945.PR: #640
Exact six-path binary diff SHA-256:
9dcf682311b2a788af65cfade3094ff1979ea55c3ef55343835c3865687a4e35. Three independent pre-push reviews are GO and all local focused/full/release gates are green. Availability remains byte-identicalfalse; #616 protected paths/hunk remain unchanged. Hosted exact-head CI and deploy-preview checks are now pending. Nothing is merged or published; Firebase/providers/accounts/data/live behavior remain unchanged. Claim remains active through merge and exact-main audit.Validate saved WebP responses (#639) (#640)
daliu commentedon Aug 13, 2026
FINAL RELEASE — COMPLETE/CLOSED; all six #639 claims RELEASED.
PR #640 admin-squash-merged exact reviewed head
db1211166f9a7388a40d6197f50f5b52f8d57c36as exact main3ca02e19fbe9977d15f602d37b5200956db1f2b3; identical tree524cad1dc12025e0adb09fc1c8f4e04caf5fd035; exact six-path binary diff SHA-2569dcf682311b2a788af65cfade3094ff1979ea55c3ef55343835c3865687a4e35.Evidence:
31754952876: all five required jobs passed on the exact reviewed head.31755169897: all five required jobs passed on exact main.6a7e5709e51bec00085f5631: ready on exact head; header/redirect checks passed; preview only; no Netlify/edge Functions.6a7e57de714e400007bbaf6f: failed/unpublished.9d5cc8612b4321172370bd949d307e7e4ac0ec7d.b74498854585346aa66c0341e29c829245445ce986806c3864cad526b267876f, sourcec2d87d1f69f15e128a0bc9b1b9f915b7c8417aec, tree411aa6ec9a9459f5d923030533ffc7c007fe6908, 62 files/digestd837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1.This was source-only response-boundary hardening.
memberDirectoryAvailability.tsremains byte-identical and literalfalse. No Firebase, Functions, Rules, indexes, provider, account/sign-in, production-data, or connected-live action occurred. Production remains the inert #623 interface preview; #507 still owns connection and release gates. Active #616 paths and SECURITY hunk remain preserved.All six exact #639 path/hunk claims are now free.