Skip to content

MEMBERS-DIRECTORY-001K — Validate saved WebP responses through the Account UI boundary #639

Closed

Description

@daliu

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, RIFF at bytes 0–3, and WEBP at bytes 8–11 may become a MemberDirectoryProfile.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 unavailable fallback must replace the image while Remove current saved photo remains 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/functions bridge 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→mocked firebase/functions bridge; reuse this existing file, with no rename/new test file.
  • SYSTEM_DESIGN.md
    • one separately named 001K source-only paragraph.
  • IMPLEMENTATION_PLAN.md
    • one separately named 001K current-source paragraph.
  • SECURITY.md
  • 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/functions mocked, prove mislabeled bytes render the generic unavailable state and never create a saved-thumbnail img or 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 unavailable fallback, 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

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

  1. added
    priority:P1High-priority follow-up
    type:securitySecurity or privacy boundary
    area:membershipMembership lifecycle and reconciliation
    area:webWeb application and hosting
    size:SSmall focused issue
    status:readyDependencies complete and ready to claim
    type:testingTest infrastructure and quality gates
    area:privacyPersonal data, consent, minimization, retention, and privacy operations
    status:in-progressClaimed and actively being implemented
    and removed
    status:readyDependencies complete and ready to claim
    on Aug 13, 2026
  2. self-assigned this
    on Aug 13, 2026
  3. daliu commented on Aug 13, 2026

    @daliu
    ContributorAuthor

    CLAIMED by /root at 2026-08-13T23:27:32.986Z on branch codex/issue-639-profile-webp-response, exact released base 7877babc96c78f54d11685b4ffb91496c3bf6945.

    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.
    • one separately named 001K current-source hunk each in SYSTEM_DESIGN.md, IMPLEMENTATION_PLAN.md, and SECURITY.md;
    • only the optional-directory one-sentence text alternative and one separately named no-terminal 001K source-evidence procedure in 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.

  4. daliu commented on Aug 13, 2026

    @daliu
    ContributorAuthor

    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 img path rather than the fixed unavailable state.

    GREEN and full evidence on the exact current worktree:

    • Focused service + real component bridge: 42/42 passed.
    • Full frontend: 18/18 suites, 1,159/1,159 tests passed.
    • TypeScript --noEmit: passed.
    • Frontend lint baseline: 120 files / 113 reviewed legacy errors / 6 reviewed legacy warnings.
    • Diagnostic production build: passed.
    • Workflow/release/security Node suite: 105/105 passed.
    • git diff --check: passed.
    • Exact six-path binary diff SHA-256: 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.ts remains byte-identical and literal false. 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.

  5. daliu commented on Aug 13, 2026

    @daliu
    ContributorAuthor

    CANDIDATE / PR MARKER — PR #640 is open at exact reviewed head db1211166f9a7388a40d6197f50f5b52f8d57c36, tree 524cad1dc12025e0adb09fc1c8f4e04caf5fd035, sole parent and current main 7877babc96c78f54d11685b4ffb91496c3bf6945.

    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-identical false; #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.

  6. added a commit that references this issue on Aug 13, 2026
  7. daliu commented on Aug 13, 2026

    @daliu
    ContributorAuthor

    FINAL RELEASE — COMPLETE/CLOSED; all six #639 claims RELEASED.

    PR #640 admin-squash-merged exact reviewed head db1211166f9a7388a40d6197f50f5b52f8d57c36 as exact main 3ca02e19fbe9977d15f602d37b5200956db1f2b3; identical tree 524cad1dc12025e0adb09fc1c8f4e04caf5fd035; exact six-path binary diff SHA-256 9dcf682311b2a788af65cfade3094ff1979ea55c3ef55343835c3865687a4e35.

    Evidence:

    • PR CI 31754952876: all five required jobs passed on the exact reviewed head.
    • Exact-main CI 31755169897: all five required jobs passed on exact main.
    • Netlify preview 6a7e5709e51bec00085f5631: ready on exact head; header/redirect checks passed; preview only; no Netlify/edge Functions.
    • Netlify main attempt 6a7e57de714e400007bbaf6f: failed/unpublished.
    • Netlify still reports published production control 9d5cc8612b4321172370bd949d307e7e4ac0ec7d.
    • Public marker is unchanged exact WEB-002C — Publish the bounded inert member-directory interface preview #623 JSON, SHA-256 b74498854585346aa66c0341e29c829245445ce986806c3864cad526b267876f, source c2d87d1f69f15e128a0bc9b1b9f915b7c8417aec, tree 411aa6ec9a9459f5d923030533ffc7c007fe6908, 62 files/digest d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1.
    • GitHub deployment records did not advance.
    • Remote feature branch is deleted.

    This was source-only response-boundary hardening. memberDirectoryAvailability.ts remains byte-identical and literal false. 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.

  8. removed their assignment
    on Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:membershipMembership lifecycle and reconciliationarea:privacyPersonal data, consent, minimization, retention, and privacy operationsarea:webWeb application and hostingpriority:P1High-priority follow-upsize:SSmall focused issuetype:reliabilityReliability and recoverytype:securitySecurity or privacy boundarytype:testingTest infrastructure and quality gates

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions