Skip to content

MEMBERS-DIRECTORY-001L — Restore People-finder submit focus after search completion #641

Closed

Description

@daliu

Parent: #504. Connected release remains owned by #507.

Officer impact: No live officer workflow changes. In the preserved future People finder, a keyboard or screen-reader user who starts a valid search from the name field or Search button will return to that same control after the current search resolves, instead of being stranded after both controls were disabled during loading. The connected interface remains unavailable on production.

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. No Mermaid change because no element, page topology, permission, or data movement changes.

Deployment evidence: None at issue creation. This is source-only keyboard-focus 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

Restore focus to the exact connected People-finder control that held focus when one current valid search entered its pending state.

Defect

On exact released main 3ca02e19fbe9977d15f602d37b5200956db1f2b3, SearchAttempt natively disables both the name input and Search button while a search is pending. A focused input submitted with Enter or a focused Search button therefore loses keyboard focus. Completion only re-enables those controls and renders result cards, the empty state, or the fixed failure plus Clear; it records no focus destination. Keyboard and screen-reader users can be left on the document body after every completed search.

Invariants and transitions

  • Create a focus intent only after a valid query and request ID admit one search into pending, and only when the active element is the persistent name input or Search button.
  • Record only that exact origin and search-operation identity; no query, name, result, photo, account ID, or service value.
  • Keep the native disabled controls and duplicate-submission gate unchanged during pending.
  • When that exact current operation resolves to result cards, empty results, or fixed unavailable failure, consume the intent and focus the same now-enabled origin after render.
  • Programmatic/outside-focus submission creates no intent and never steals focus.
  • Validation and request-ID construction failure never enter pending; preserve enabled-control and natural-focus behavior.
  • Input editing and Clear remove obsolete intent. Clear keeps its zero-ID/zero-call behavior and focuses the empty name input.
  • App change, admin UID change, unmount, or obsolete operation cannot move focus in another context.
  • Focus creates no ID, search, retry, Clear action, result, audit, service call, or data URL.
  • Existing normalization, result disposal, fixed errors, response bounds, AdminGuard, stale fences, and voluntary-thumbnail behavior remain unchanged.
  • Availability stays false; default route remains inert/disabled/zero-context/zero-call.
  • Name-prefix search plus human comparison of voluntary thumbnails only. No photo query, facial recognition, matching, embedding, similarity, biometrics, totals, export, roster authority, or membership proof.

Exact ownership

  • src/pages/admin/members/AdminMemberDirectory.tsx: only an operation-bound submit-origin focus intent, Search-button ref, cleanup/clear guards, and guarded post-settlement focus handoff inside SearchAttempt.
  • src/pages/admin/members/AdminMemberDirectory.test.tsx: one separately named MEMBERS-DIRECTORY-001L block plus minimum directly affected helpers/assertions.
  • SYSTEM_DESIGN.md: one separately named 001L source-only paragraph.
  • IMPLEMENTATION_PLAN.md: one separately named 001L current-source paragraph.
  • SECURITY.md: one separately named 001L/RISK-042 row immediately after released 001K; 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 001L source-evidence procedure; no diagram change.

No CSS: the same native controls and existing focus styles are used.

Required tests

  • Capture trustworthy RED by focusing input or Search, starting a deferred valid search, asserting both disabled, modeling browser disabled-control focus eviction with blur(), settling, and proving old source leaves focus off the origin.
  • Matrix both origins across non-empty, empty, and fixed failure; current settlement restores the same persistent origin, not Clear/results/body.
  • Focus handoff consumes one exact intent and creates no second request, ID, retry, or Clear.
  • Programmatic/outside-focus submission never steals outside focus on settlement.
  • Validation and request-ID construction failure remain enabled/generic/focus-inert beyond natural focus, with no request.
  • Existing Clear behavior still removes query/messages/cards/names/images, focuses input, and creates no new ID/call.
  • App/admin change and unmount make late old resolution/rejection focus-inert.
  • Default unavailable preview remains zero-context/zero-ID/zero-call.
  • Existing response/privacy/disposal/photo/accessibility/mobile/stale tests plus full frontend, TypeScript, lint baseline, build, workflow/security tests, and diff check pass.

Explicit exclusions

Migration and residual risk

No migration. Focus handoff is accessibility behavior, not authorization, provider acknowledgement, audit proof, result correctness, or live evidence. Live #623 remains inert; #507 retains all connection/release gates.

Claim protocol

Assign and post a timestamped CLAIMED marker with exact branch/base before edits. Claim stays active through reviewed merge, exact-main audit, closure, and explicit release.

Activity

  1. added
    bugSomething isn't working
    priority:P1High-priority follow-up
    area:membershipMembership lifecycle and reconciliation
    area:webWeb application and hosting
    area:adminAdministrative workflows
    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
    on Aug 14, 2026
  2. daliu commented on Aug 14, 2026

    @daliu
    ContributorAuthor

    PRE-CLAIM INVARIANT REFINEMENT — focus recovery must not steal focus that the user deliberately moved during a pending search.

    The exact settlement rule is:

    • if the recorded origin already remains focused, do nothing and consume the exact-operation intent;
    • if focus was evicted to document.body or no meaningful active element when the origin became disabled, focus that same now-enabled origin and consume the intent;
    • if any other connected element owns focus at settlement, preserve that focus and consume the intent without moving it.

    Required tests therefore also include: focus input or Search, admit a deferred search, move focus to an outside persistent control while pending, settle to results/empty/failure, and prove the outside control retains focus. This is in addition to programmatic/outside-focused submission creating no intent. All six-path ownership/exclusions remain unchanged; no edit or claim exists yet.

  3. removed
    status:readyDependencies complete and ready to claim
    on Aug 14, 2026
  4. self-assigned this
    on Aug 14, 2026
  5. daliu commented on Aug 14, 2026

    @daliu
    ContributorAuthor

    CLAIMED by /root at 2026-08-14T00:02:22.173Z on branch codex/issue-641-admin-search-focus, exact released base 3ca02e19fbe9977d15f602d37b5200956db1f2b3.

    Exact ownership:

    • src/pages/admin/members/AdminMemberDirectory.tsx: only an exact-operation input-or-Search focus intent, Search ref, cleanup/edit/Clear guards, and a guarded settlement handoff that restores only from body/no meaningful focus and never steals another connected focus.
    • src/pages/admin/members/AdminMemberDirectory.test.tsx: one separately named MEMBERS-DIRECTORY-001L block plus minimum helpers/assertions.
    • one separately named 001L 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 001L source-evidence procedure in docs/officers/EVENTS_SHOP_MEMBERS.md; no CSS or Mermaid change.

    Everything else is immutable: Account/profile, Account.css, client services, availability, AdminGuard/routes/result-photo semantics, 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. The pre-claim no-focus-steal refinement at #641 (comment) is part of the claim. No source edit preceded this marker. Claim remains active through reviewed merge, exact-main audit, closure, and explicit release.

  6. daliu commented on Aug 14, 2026

    @daliu
    ContributorAuthor

    CANDIDATE EVIDENCE — exact six-path source-only patch on released base 3ca02e1.

    Exact uncommitted binary diff SHA-256: a1a8630995701e001af2c5fdfd256c01d9c022f457329fceef17f17d34024696.

    Trustworthy RED on unchanged runtime: the separately named MEMBERS-DIRECTORY-001L block failed exactly the six required restoration cells (input/Search × result cards/empty/fixed failure) while ten no-steal/fencing controls passed. GREEN: named 001L 22/22; full AdminMemberDirectory 47/47; full frontend 18 suites/1,181 tests; TypeScript; scoped ESLint; unchanged frontend lint baseline 120 files/113 reviewed errors/6 warnings; diagnostic production build; repository Node workflow/security tests 105/105; diff-check. Three independent reviews are GO: focus/race, privacy/security/scope, frontend/accessibility, plus a separate backup-officer/operations GO.

    The exact focus intent contains only the current operation Symbol and input-or-Search origin. It restores the same now-enabled origin only from body/root/absent/disconnected focus, never steals another connected focus, and creates no request ID, call, retry, result, audit, or data URL. App/admin changes, stale resolution or rejection, Clear/edit, and unmount are fenced.

    Availability remains literal false with blob 295909b0df8dd7c54a0f164f99d4943656aece4b. Active #616 Strava blobs remain 2eb48945061ab5ad2a896c6835f308cefd7fe63a and d1792d390bd57608fecab84341a6e5916fcf8196; its separate SECURITY hunk is untouched. No Firebase, provider, account, sign-in, production-data, deployment, publication, or live action occurred. Production remains inert #623. Claim stays active through exact-head CI, merge, exact-main/deployment audit, closure, and explicit release.

  7. daliu commented on Aug 14, 2026

    @daliu
    ContributorAuthor

    PR CANDIDATE — #642 is open at exact reviewed head 5166c92, tree 0a2deecc78c1c1645c50db8a1b79f991df41f580, sole parent/base 3ca02e1.

    PR: #642
    Exact six-file binary diff SHA-256: a1a8630995701e001af2c5fdfd256c01d9c022f457329fceef17f17d34024696. Local gates and four independent review dimensions are GO; hosted exact-head CI and preview are now pending. Availability remains false, #616 is preserved, and no Firebase/provider/data/account/sign-in/deployment/live action occurred. Claim remains active through merge, exact-main and deployment audit, closure, and explicit release.

  8. daliu commented on Aug 14, 2026

    @daliu
    ContributorAuthor

    #641 MEMBERS-DIRECTORY-001L FINAL RELEASE — COMPLETE/CLOSED and all six claims RELEASED.

    PR #642 admin-squash-merged exact reviewed head 5166c92 as exact main f3da2f3. Reviewed and main tree are identical: 0a2deecc78c1c1645c50db8a1b79f991df41f580. Exact six-file binary diff SHA-256: a1a8630995701e001af2c5fdfd256c01d9c022f457329fceef17f17d34024696.

    PR exact-head CI 31757138417 and exact-main CI 31757380724 each passed all five required jobs. Preview deploy 6a7e5fd72327120008492418 is ready, exact-head, unpublished, and deployed no Netlify or edge Functions. Exact-main attempt 6a7e60d3714e400007beb6ea is terminal error with published_at null. Netlify site deploy_id and published_deploy.id remain 6a7e072f8f346b0008510d29 / control 9d5cc86. Public release marker remains exact #623 source c2d87d1, tree 411aa6ec9a9459f5d923030533ffc7c007fe6908, 62 files, digest d837272a1e5efc1575809e87f532276b38d1a63f1dd79ec1aef0533f6da8afb1, marker SHA-256 b74498854585346aa66c0341e29c829245445ce986806c3864cad526b267876f. GitHub deployment records are unchanged.

    Availability remains literal false. No Firebase, Functions, Rules, index, provider configuration, account/sign-in, production-data, or connected/live action occurred. Active #616 paths and its separate SECURITY hunk remain byte-identical. Status and assignee will be cleared and the remote branch retired. Later work may refresh from exact released main f3da2f3 and must preserve the separate 001L hunks byte-for-byte.

  9. removed their assignment
    on Aug 14, 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:adminAdministrative workflowsarea:membershipMembership lifecycle and reconciliationarea:privacyPersonal data, consent, minimization, retention, and privacy operationsarea:webWeb application and hostingbugSomething isn't workingpriority:P1High-priority follow-upsize:SSmall focused issuetype:reliabilityReliability and recoverytype: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