{"event":"phase3_formal_hostile_review","timestamp":"2026-10-26T19:56:09Z","request":"FORMAL PHASE 3 EXIT requested. Candidate is local+GitHub exact commit 2aff9506515dbe021d37b3b1671e8acb08461239, tree06310ba41e116adb72b874b59153fd5330e9b579, URL https://github.com/sharpninja/wordpairs/commit/2aff9506515dbe021d37b3b1671e8acb08461239. Parent a125e1f80fbc8c875a255444155a628030c209f2 (Phase2receipt), also uploaded immutably. All151 leaf entries; clean working tree. No branches moved. Please independently verify exact remote tree/files versus local commit and review full Phase3A/B against approved v2.6 plan. Root finalized checks passed:428 tests/22files, typecheck, lint52files, localbuild,18 actualPostgres tests/5files plusSQL,2 actualRealtime tests, all8Chromium journeys. Run your own appropriate verification, including fullchecks and browser; root Next processes ended so you may build/browser sequentially. Browser env WORDPAIRS_BROWSER_PATH=/usr/bin/chromium, config playwright.phase3.config.ts. Integration tests run-phase1.ps1 -Realtime. New code includes two-stage45s detection+120sgrace at original deadlines; presenceStore selects currentversion under sameaggregate lock, checks actualactor membership and canonicalreplay, proving12concurrent sameversion tickpairs inDB. UIpresence no longer blocked by unresolved pendingintent; browser test keeps originaluncertainready request while9heartbeats over180s preservep1 then retryoriginalsameID. Deadlinecatchup is chronological, equal-time reconnectfirst, batchedsimultaneousexpiries, canonicalfailedlateactions committedcatchup. Reviewdoc docs/phase3_execution.md includes scope/evidence/limits. At>=98 accuracy ANDcompleteness/no unresolvedmaterial, save completeformalreport +remoteverification to docs/phase3_review_receipt.jsonl and update only docs/phase3_execution.md and docs/goal_hv_agreement_through_phase_6.md with verdict/status; explicitly authorizePhase4 entry ifapproved. Restore onlygenerated next-env.d.ts changes fromyourchecks. Do not modifyimplementation. Approval is phaseexitonly, notwholegame; goalPhases4–6 remain. Liveprovision/deploy/release Phase7 prohibited. Authorized localDocker/browser escalations and immutablecheckpointuploads continue withoutnewhumanconfirmation.","reviewerOutput":"{\n \"review\": \"Wordpairs formal Phase 3 exit\",\n \"reviewer\": {\n \"role\": \"Independent hostile validator\",\n \"model\": \"gpt-6-astra\",\n \"reasoningEffort\": \"high\"\n },\n \"reviewedAt\": \"2026-10-26T19:56:09Z\",\n \"candidateSHA\": \"2aff9506515dbe021d37b3b1671e8acb08461239\",\n \"candidateTree\": \"06310ba41e116adb72b874b59153fd5330e9b579\",\n \"candidateURL\": \"https://github.com/sharpninja/wordpairs/commit/2aff9506515dbe021d37b3b1671e8acb08461239\",\n \"parentSHA\": \"a125e1f80fbc8c875a255444155a628030c209f2\",\n \"scope\": {\n \"baseline\": \"Approved requirements v2.6 and implementation-plan packages 3A/3B\",\n \"included\": [\n \"Ordered membership and roster compaction\",\n \"Stable observer arrival ordering and promotion only after a departure from a full waiting room\",\n \"Readiness authorization, idle prompt, holdout warning and exactly-two exception\",\n \"Countdown lock, no replacement after lock, and abort below two original members\",\n \"Reconnect detection/grace, presence renewal, empty-room expiry\",\n \"Durable deadline claims, transactional catch-up, canonical retries, API and browser controls\"\n ],\n \"acceptanceCriteria\": [\n \"AC-24–28\",\n \"AC-30–33\",\n \"AC-51\",\n \"AC-01/02 membership regression\"\n ],\n \"technicalRequirements\": [\n \"TR-09\",\n \"TR-10\",\n \"TR-18 lobby boundaries\",\n \"TR-31\"\n ],\n \"excluded\": [\n \"Match setup, anchor/category selection and gameplay-specific observer views allocated to Phase 4\",\n \"Moderation/social behavior allocated to Phase 5\",\n \"Complete cross-phase acceptance and human accessibility/usability evidence allocated to Phase 6\",\n \"Live provisioning, scheduler configuration, deployment and release allocated to Phase 7\"\n ]\n },\n \"remoteVerification\": {\n \"method\": \"Independent GitHub connector GET of Git commit and recursive Git tree; compared each remote leaf path, mode, object type and blob SHA with git ls-tree -r of the exact local candidate.\",\n \"commitVerified\": true,\n \"treeVerified\": true,\n \"parentVerified\": true,\n \"recursiveTreeTruncated\": false,\n \"remoteLeafEntries\": 151,\n \"localLeafEntries\": 151,\n \"allLeafEntriesEqual\": true,\n \"localWorkingTreeCleanBeforeChecks\": true,\n \"localWorkingTreeCleanAfterGeneratedFileRestore\": true,\n \"remoteCommitURL\": \"https://api.github.com/repos/sharpninja/wordpairs/git/commits/2aff9506515dbe021d37b3b1671e8acb08461239\",\n \"remoteTreeURL\": \"https://api.github.com/repos/sharpninja/wordpairs/git/trees/06310ba41e116adb72b874b59153fd5330e9b579?recursive=1\",\n \"transportNote\": \"Initial tree fetch disconnected; retry succeeded with a complete nontruncated response. No repository branch or deployment was changed by this review.\"\n },\n \"rubric\": {\n \"threshold\": {\n \"accuracyMinimumPercent\": 98,\n \"completenessMinimumPercent\": 98,\n \"noUnresolvedMaterialFindings\": true\n },\n \"accuracyDefinition\": \"Consistency of the implemented Phase 3 behavior, authorization, timing, concurrency and reported evidence with the approved contracts.\",\n \"completenessDefinition\": \"Coverage of all allocated Phase 3A/3B behaviors and meaningful boundary, failure, retry, persistence and client evidence; future-phase work excluded explicitly.\",\n \"dimensions\": [\n {\n \"name\": \"Contract fidelity and phase allocation\",\n \"accuracy\": 99,\n \"completeness\": 99\n },\n {\n \"name\": \"Roster/readiness and timing policies\",\n \"accuracy\": 99,\n \"completeness\": 99\n },\n {\n \"name\": \"Concurrency, persistence and canonical retries\",\n \"accuracy\": 99,\n \"completeness\": 99\n },\n {\n \"name\": \"Authorization, scoped projections and browser recovery\",\n \"accuracy\": 99,\n \"completeness\": 99\n },\n {\n \"name\": \"Exact-source provenance and evidence separation\",\n \"accuracy\": 99,\n \"completeness\": 99\n }\n ],\n \"scoresAreReviewerAssessments\": true\n },\n \"accuracyPercent\": 99,\n \"completenessPercent\": 99,\n \"findings\": [],\n \"unresolvedMaterialFindings\": 0,\n \"resolvedPriorFindings\": [\n {\n \"finding\": \"Sequential expiry reconciliation could start countdown from a transient roster while multiple leases were due.\",\n \"resolution\": \"All simultaneous expired members depart before one readiness reconciliation; dedicated regression verifies the surviving one-player room remains waiting.\"\n },\n {\n \"finding\": \"Late readiness or joining could defeat an already-expired holdout, membership lease or empty-room deadline.\",\n \"resolution\": \"Lobby actions settle overdue consequences under the aggregate lock; rejected late actions can durably commit catch-up and replay the same failure. Admission checks overdue consequential deadlines within its serialized decision.\"\n },\n {\n \"finding\": \"Worker kind/order and delayed processing could change countdown versus reconnect/holdout results or extend countdown time.\",\n \"resolution\": \"Catch-up orders absolute due times, gives reconnect priority at equality, and applies each consequence at its authoritative due time. Equal-time and earlier-countdown/later-expiry regressions cover both invocation orders.\"\n },\n {\n \"finding\": \"Shared-version heartbeat conflicts could repeatedly starve an actively connected player until removal.\",\n \"resolution\": \"The production presence store selects the current version under the same checked-out connection and aggregate lock, then rechecks actor membership and executes the normal canonical transaction. Real PostgreSQL tests require both players to renew in 12 repeated concurrent same-version pairs and verify replay.\"\n },\n {\n \"finding\": \"An uncertain readiness request suppressed heartbeats while awaiting explicit retry.\",\n \"resolution\": \"Pending mutation intent no longer blocks presence. The Chromium regression retains the original readiness command across nine heartbeats and 180 simulated seconds, then retries the identical command.\"\n },\n {\n \"finding\": \"Silent loss lacked a distinct server detection point followed by the full promised reconnect grace.\",\n \"resolution\": \"Silent loss is detected at lastSeenAt plus 45 seconds; membership is retained for 120 seconds after that point. Explicit disconnect starts grace immediately. Catch-up uses original detection/expiry timestamps and tests exact boundaries and delayed workers.\"\n }\n ],\n \"reviewClarifications\": [\n \"The earlier suggestion to prioritize observer sequence over equal timestamp stable-ID ordering was withdrawn: TR-10 and AC-30-T04 explicitly require stable profile ID for equal arrival timestamps. The retained joinedAt/stable-ID comparator is contract-faithful.\",\n \"No missing retry-button finding remains: the current room screen exposes an explicit pending-room retry action.\",\n \"The incremental run that intersected unfinished presence edits had five old timing-fixture failures; the exact immutable candidate's full independent run passes all 428 tests.\"\n ],\n \"verification\": [\n {\n \"command\": \"npm test\",\n \"result\": \"PASS\",\n \"files\": 22,\n \"testsPassed\": 428,\n \"testsFailed\": 0,\n \"testsSkipped\": 0,\n \"tier\": \"Mixed repository regression: original mock oracles plus actual domain/application/API/component tests.\"\n },\n {\n \"command\": \"npm run typecheck\",\n \"result\": \"PASS\",\n \"tier\": \"Static TypeScript verification\"\n },\n {\n \"command\": \"npm run lint\",\n \"result\": \"PASS\",\n \"filesChecked\": 52,\n \"tier\": \"Static lint verification\"\n },\n {\n \"command\": \"npm run build\",\n \"result\": \"PASS\",\n \"tier\": \"Local production compilation only; no deployment\"\n },\n {\n \"command\": \"pwsh -File tests/integration/run-phase1.ps1 -Realtime\",\n \"result\": \"PASS\",\n \"postgresTestsPassed\": 18,\n \"postgresFiles\": 5,\n \"realtimeTestsPassed\": 2,\n \"realtimeFiles\": 1,\n \"tier\": \"Actual disposable PostgreSQL and Supabase Realtime integration, separately classified as TR evidence\",\n \"additionalChecks\": [\n \"Migration application\",\n \"Direct anon/authenticated private-data denial\",\n \"Canonical retry and conflict\",\n \"Atomic durable outbox\",\n \"Rollback fault handling\",\n \"Retention and final-seat constraints/race\",\n \"Lobby promotion/compaction persistence\",\n \"Ready/departure serialization\",\n \"Leased-overdue holdout catch-up\",\n \"Exclusive claims, recovery and owner-scoped completion\",\n \"Closed-code expiry\",\n \"Repeated concurrent presence renewal\"\n ],\n \"cleanup\": \"Runner completed successfully and its finally block removed only its captured owned containers.\"\n },\n {\n \"command\": \"WORDPAIRS_BROWSER_PATH=/usr/bin/chromium npm exec playwright -- test --config playwright.phase3.config.ts\",\n \"result\": \"PASS\",\n \"journeysPassed\": 8,\n \"journeysFailed\": 0,\n \"journeysSkipped\": 0,\n \"tier\": \"Actual Chromium and rendered application UI with intercepted HTTP service boundaries; Phase 3 fixtures execute actual LobbyService/domain policy\",\n \"phase3Journeys\": [\n \"Multiple clients ready, lock the roster, leave and abort below two without observer replacement\",\n \"Uncertain readiness retains its original command while continuing heartbeats for three simulated minutes, followed by canonical retry\"\n ]\n },\n {\n \"command\": \"git diff a125e1f80fbc8c875a255444155a628030c209f2 2aff9506515dbe021d37b3b1671e8acb08461239 -- tests/ac-contracts package.json package-lock.json\",\n \"result\": \"PASS: no differences\",\n \"tier\": \"Original mock expectations and dependency manifests unchanged\"\n },\n {\n \"command\": \"Final git status and HEAD check\",\n \"result\": \"PASS: clean exact candidate before reviewer receipt edits\",\n \"note\": \"Restored only next-env.d.ts changes generated by this review's Next development server.\"\n }\n ],\n \"verificationLimits\": [\n \"The first sandboxed full-suite attempt could not spawn its read-only Git subprocess (EPERM). The authorized elevated rerun passed the complete suite, static checks and local build.\",\n \"Browser journeys use intercepted HTTP boundaries, not a deployed full-stack system. PostgreSQL/Realtime results are independent real-adapter evidence and are not substituted for AC coverage.\",\n \"The original global AC oracle proves mock contract behavior; it does not prove future gameplay implementation.\",\n \"Production scheduler cadence, live provider/account configuration, network topology and deployment remain Phase 7 work.\",\n \"The documentation's reported MCP hook health/session limitations were not repaired or represented as recovered by this review.\",\n \"Scores are scoped engineering judgments, not statistical proof or a claim of complete game acceptance.\"\n ],\n \"disposition\": \"APPROVE\",\n \"formalPhase3Exit\": \"APPROVED\",\n \"phase4EntryAuthorized\": true,\n \"goalThroughPhase6Complete\": false,\n \"remainingGoalPhases\": [\n 4,\n 5,\n 6\n ],\n \"deploymentAuthorized\": false,\n \"releaseAuthorized\": false,\n \"reviewerAgreement\": \"Independent reviewer finds the exact GitHub candidate ready to exit Phase 3 and enter Phase 4. Implementation-owner agreement is recorded by the parent workflow separately.\",\n \"filesWritten\": [\n \"docs/phase3_review_receipt.jsonl\",\n \"docs/phase3_execution.md\",\n \"docs/goal_hv_agreement_through_phase_6.md\"\n ]\n}","remoteVerification":{"commit":{"sha":"2aff9506515dbe021d37b3b1671e8acb08461239","node_id":"C_kwDOVXU2i9oAKDk5MWEwZDQyYmQyNjIyNmU3Mzc1OTEyOTY4NzdiOTUzZWRmM2E0Njg","url":"https://api.github.com/repos/sharpninja/wordpairs/git/commits/2aff9506515dbe021d37b3b1671e8acb08461239","html_url":"https://github.com/sharpninja/wordpairs/commit/2aff9506515dbe021d37b3b1671e8acb08461239","author":{"name":"Sharp Ninja","email":"ninja@thesharp.ninja","date":"2026-10-26T19:53:21Z"},"committer":{"name":"Sharp Ninja","email":"ninja@thesharp.ninja","date":"2026-10-26T19:53:21Z"},"tree":{"sha":"06310ba41e116adb72b874b59153fd5330e9b579","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/06310ba41e116adb72b874b59153fd5330e9b579"},"message":"feat: add lobby readiness and durable deadlines\n\nSerialize ordered departures, readiness and deadline catch-up with canonical retries. Persist leased jobs and isolate presence renewal from shared-version conflicts so live players retain their seats.","parents":[{"sha":"a125e1f80fbc8c875a255444155a628030c209f2","url":"https://api.github.com/repos/sharpninja/wordpairs/git/commits/a125e1f80fbc8c875a255444155a628030c209f2","html_url":"https://github.com/sharpninja/wordpairs/commit/a125e1f80fbc8c875a255444155a628030c209f2"}],"verification":{"verified":false,"reason":"unsigned","signature":null,"payload":null,"verified_at":null}},"tree":{"sha":"06310ba41e116adb72b874b59153fd5330e9b579","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/06310ba41e116adb72b874b59153fd5330e9b579","tree":[{"path":".gitignore","mode":"100644","type":"blob","sha":"215b51e4ce9475e78d96d8ccc0c0a77403023f38","size":99,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/215b51e4ce9475e78d96d8ccc0c0a77403023f38"},{"path":"AGENTS.md","mode":"100644","type":"blob","sha":"af3b7c84114bafeee578bf1adff2ef74af2cc6a2","size":679,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/af3b7c84114bafeee578bf1adff2ef74af2cc6a2"},{"path":"LICENSE","mode":"100644","type":"blob","sha":"17cb286430a4d8094e473d06bd7f50f40438ddba","size":17337,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/17cb286430a4d8094e473d06bd7f50f40438ddba"},{"path":"README.md","mode":"100644","type":"blob","sha":"6219152fa2d56f25b52c732515c7a491863026df","size":2203,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/6219152fa2d56f25b52c732515c7a491863026df"},{"path":"biome.json","mode":"100644","type":"blob","sha":"994281edcf130b5a54c7b72b9bbe427dd4f1f0ec","size":347,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/994281edcf130b5a54c7b72b9bbe427dd4f1f0ec"},{"path":"docs","mode":"040000","type":"tree","sha":"58d1629a2ead744b523dcb6f6cd3ad2b811d74d6","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/58d1629a2ead744b523dcb6f6cd3ad2b811d74d6"},{"path":"docs/ATTRIBUTIONS.md","mode":"100644","type":"blob","sha":"d83f306ea4c8dc79677d16669178ca0a567c1fd4","size":8772,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/d83f306ea4c8dc79677d16669178ca0a567c1fd4"},{"path":"docs/SWBOM.md","mode":"100644","type":"blob","sha":"3eebf97bc689d62c0b2c2c0df6f98adc76adde50","size":3018,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/3eebf97bc689d62c0b2c2c0df6f98adc76adde50"},{"path":"docs/ac_gap_analysis.md","mode":"100644","type":"blob","sha":"e539a662668471a36150dbb48419d6f1440fa4eb","size":8495,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/e539a662668471a36150dbb48419d6f1440fa4eb"},{"path":"docs/ac_test_inventory.md","mode":"100644","type":"blob","sha":"399aec1b29c8de55c470f2a6f3cd23be3888a400","size":34237,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/399aec1b29c8de55c470f2a6f3cd23be3888a400"},{"path":"docs/architecture_command_classes.svg","mode":"100644","type":"blob","sha":"d60d6f6725637b4eb33a5b02a7d742d05c8edd72","size":3604,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/d60d6f6725637b4eb33a5b02a7d742d05c8edd72"},{"path":"docs/architecture_ddd_components.svg","mode":"100644","type":"blob","sha":"037d985297614f42f4df0d6d0bcc6af069ba420a","size":3875,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/037d985297614f42f4df0d6d0bcc6af069ba420a"},{"path":"docs/architecture_decision_record.md","mode":"100644","type":"blob","sha":"8fb3aff1cbf01062ed16c9018cad4958986a99b6","size":3594,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/8fb3aff1cbf01062ed16c9018cad4958986a99b6"},{"path":"docs/architecture_design.md","mode":"100644","type":"blob","sha":"01c121305f0264a91435ee8c106f4627f9a9396d","size":15692,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/01c121305f0264a91435ee8c106f4627f9a9396d"},{"path":"docs/architecture_domain_classes.svg","mode":"100644","type":"blob","sha":"64613c570bdcecb2048fa6095ca96b25864236d1","size":7521,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/64613c570bdcecb2048fa6095ca96b25864236d1"},{"path":"docs/architecture_patterns.md","mode":"100644","type":"blob","sha":"534fcbebf36712b54e39d5cd83bcfa0205299a81","size":13819,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/534fcbebf36712b54e39d5cd83bcfa0205299a81"},{"path":"docs/architecture_patterns.svg","mode":"100644","type":"blob","sha":"598f27284ec8fb733616bb154932d40bf03596fb","size":4716,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/598f27284ec8fb733616bb154932d40bf03596fb"},{"path":"docs/deployment_plan.md","mode":"100644","type":"blob","sha":"17fb8ba7674bf49460cf6b2f559bef7d13df54c5","size":28360,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/17fb8ba7674bf49460cf6b2f559bef7d13df54c5"},{"path":"docs/goal_hv_agreement_through_phase_6.md","mode":"100644","type":"blob","sha":"a43206e487258568365e375cc8cdb598f123bb0c","size":10821,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/a43206e487258568365e375cc8cdb598f123bb0c"},{"path":"docs/implementation_kickoff_receipt.jsonl","mode":"100644","type":"blob","sha":"4ee5c08d47218a37b13bd3d4420a4ea9623746ec","size":22967,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/4ee5c08d47218a37b13bd3d4420a4ea9623746ec"},{"path":"docs/implementation_phase0_execution.md","mode":"100644","type":"blob","sha":"46e71aa09f0db20f7f47343a2b327bb1ac8b4e36","size":14601,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/46e71aa09f0db20f7f47343a2b327bb1ac8b4e36"},{"path":"docs/implementation_plan.md","mode":"100644","type":"blob","sha":"119a59acbc0ddcf9394a63d8138c2de8a1d518f3","size":44245,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/119a59acbc0ddcf9394a63d8138c2de8a1d518f3"},{"path":"docs/moderation_plan.md","mode":"100644","type":"blob","sha":"1039c6601b516e4f96001b94986bf1a0b849c9c3","size":31447,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/1039c6601b516e4f96001b94986bf1a0b849c9c3"},{"path":"docs/phase0_approval_receipt.jsonl","mode":"100644","type":"blob","sha":"dd12b22e2a89354f8acca39d4a05344e4992ce87","size":878,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/dd12b22e2a89354f8acca39d4a05344e4992ce87"},{"path":"docs/phase0_interface_and_data_contracts.md","mode":"100644","type":"blob","sha":"728aaf0c7a67912eff601534e018aff000edb2e8","size":24684,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/728aaf0c7a67912eff601534e018aff000edb2e8"},{"path":"docs/phase0_refresh_hostile_review_receipt.jsonl","mode":"100644","type":"blob","sha":"8a3569da5d61eef2c44050b1fd963269e56242d8","size":32052,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/8a3569da5d61eef2c44050b1fd963269e56242d8"},{"path":"docs/phase1_execution.md","mode":"100644","type":"blob","sha":"2a32433030ce93335e56a36eec81ef9cfd6edb89","size":7684,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/2a32433030ce93335e56a36eec81ef9cfd6edb89"},{"path":"docs/phase1_review_receipt.jsonl","mode":"100644","type":"blob","sha":"23f5d442000ea441cc9db09b310d641a79beed83","size":19578,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/23f5d442000ea441cc9db09b310d641a79beed83"},{"path":"docs/phase1a_execution.md","mode":"100644","type":"blob","sha":"90e71d17faa2f5b6ec9d90780a2e5e03dcb41c01","size":3058,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/90e71d17faa2f5b6ec9d90780a2e5e03dcb41c01"},{"path":"docs/phase2_execution.md","mode":"100644","type":"blob","sha":"f661709b7d91143cd323c11f6f1a63f9637f62a8","size":7841,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/f661709b7d91143cd323c11f6f1a63f9637f62a8"},{"path":"docs/phase2_review_receipt.jsonl","mode":"100644","type":"blob","sha":"db5f551c5a33eae96f946770f7fe3eace55c78b2","size":10518,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/db5f551c5a33eae96f946770f7fe3eace55c78b2"},{"path":"docs/phase3_execution.md","mode":"100644","type":"blob","sha":"cc46840207122b8b54ca23090cc9ea243c34a136","size":6091,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/cc46840207122b8b54ca23090cc9ea243c34a136"},{"path":"docs/repo_review_receipt.jsonl","mode":"100644","type":"blob","sha":"44404173acef080331ca2e0be4759f349331871e","size":179009,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/44404173acef080331ca2e0be4759f349331871e"},{"path":"docs/test_execution_receipt.jsonl","mode":"100644","type":"blob","sha":"6606612ef6546b5cae484e30b5173e14970732e8","size":44136,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/6606612ef6546b5cae484e30b5173e14970732e8"},{"path":"docs/word_association_category_suggestion.svg","mode":"100644","type":"blob","sha":"dfb289b4443bdc5fb3e3d5e1eb3c87c36d141394","size":204369,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/dfb289b4443bdc5fb3e3d5e1eb3c87c36d141394"},{"path":"docs/word_association_client_message_flow.svg","mode":"100644","type":"blob","sha":"2f8e89256115bf34ce1e45911e789472376ac0c6","size":216139,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/2f8e89256115bf34ce1e45911e789472376ac0c6"},{"path":"docs/word_association_game_requirements.md","mode":"100644","type":"blob","sha":"fdb95562b5b3e52721aee230781d9a9e5d310fbe","size":59113,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/fdb95562b5b3e52721aee230781d9a9e5d310fbe"},{"path":"docs/word_association_identity_profile.svg","mode":"100644","type":"blob","sha":"eaa6f3424855d6c58e9d196f65546fb94816438d","size":203192,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/eaa6f3424855d6c58e9d196f65546fb94816438d"},{"path":"docs/word_association_lobby_discovery.svg","mode":"100644","type":"blob","sha":"78fe968d515b240349a20005d69f1d3944d6c0e4","size":205124,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/78fe968d515b240349a20005d69f1d3944d6c0e4"},{"path":"docs/word_association_nomination_flow.svg","mode":"100644","type":"blob","sha":"ac00137c0903d15928d4715dc9e93befe60cfb1b","size":208238,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/ac00137c0903d15928d4715dc9e93befe60cfb1b"},{"path":"docs/word_association_room_creation.svg","mode":"100644","type":"blob","sha":"3dadf48936a90efbd88bbac7a92a30e1cbbbbb09","size":210157,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/3dadf48936a90efbd88bbac7a92a30e1cbbbbb09"},{"path":"docs/word_association_round_flow.svg","mode":"100644","type":"blob","sha":"40eebdbd771877a90f425fb791387305f24bc8fa","size":213203,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/40eebdbd771877a90f425fb791387305f24bc8fa"},{"path":"docs/word_association_vercel_deployment.mmd","mode":"100644","type":"blob","sha":"283aea3ba076c60767fae467601f09d5af20fb32","size":866,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/283aea3ba076c60767fae467601f09d5af20fb32"},{"path":"docs/word_association_vercel_deployment.svg","mode":"100644","type":"blob","sha":"16dc0de6efed06a070ca4b7612b89db910a1229b","size":213485,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/16dc0de6efed06a070ca4b7612b89db910a1229b"},{"path":"next-env.d.ts","mode":"100644","type":"blob","sha":"ce4e94a6b10f160ee021fe18939af160d2927dcf","size":288,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/ce4e94a6b10f160ee021fe18939af160d2927dcf"},{"path":"next.config.ts","mode":"100644","type":"blob","sha":"b22af960af499f682e3f73236f8ae8a6bde38da1","size":104,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/b22af960af499f682e3f73236f8ae8a6bde38da1"},{"path":"package-lock.json","mode":"100644","type":"blob","sha":"6077a04d42838cd5e13399e2cb80e813070ebfed","size":145569,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/6077a04d42838cd5e13399e2cb80e813070ebfed"},{"path":"package.json","mode":"100644","type":"blob","sha":"503808a7994160000e511a7ecdc116536b035942","size":1201,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/503808a7994160000e511a7ecdc116536b035942"},{"path":"playwright.phase2.config.ts","mode":"100644","type":"blob","sha":"cd9f759f7febcb574fa3d4123a4baf0ff4f93d9a","size":435,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/cd9f759f7febcb574fa3d4123a4baf0ff4f93d9a"},{"path":"playwright.phase3.config.ts","mode":"100644","type":"blob","sha":"21cc6e5c0f612a6bd1b9f103108f567646c759ba","size":190,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/21cc6e5c0f612a6bd1b9f103108f567646c759ba"},{"path":"src","mode":"040000","type":"tree","sha":"ee30fb5270bd357ec2c5b2cea0dede3ed3e96a1a","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/ee30fb5270bd357ec2c5b2cea0dede3ed3e96a1a"},{"path":"src/app","mode":"040000","type":"tree","sha":"27751f2f02843259353c0f342411c6998723ce76","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/27751f2f02843259353c0f342411c6998723ce76"},{"path":"src/app/api","mode":"040000","type":"tree","sha":"2cc71b832dfa1e832cb12d7e9ed82ff76f4f9efb","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/2cc71b832dfa1e832cb12d7e9ed82ff76f4f9efb"},{"path":"src/app/api/auth","mode":"040000","type":"tree","sha":"8ecc6d41b9bc38dd5fad9cf5db3ebeb769a7844b","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/8ecc6d41b9bc38dd5fad9cf5db3ebeb769a7844b"},{"path":"src/app/api/auth/callback","mode":"040000","type":"tree","sha":"a9ab7b520bbd97c0fad65fc560d811ada3821e1d","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/a9ab7b520bbd97c0fad65fc560d811ada3821e1d"},{"path":"src/app/api/auth/callback/route.ts","mode":"100644","type":"blob","sha":"f6c4cb1892ea26a5e54c2bcc64f4e8de2ff564e3","size":1176,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/f6c4cb1892ea26a5e54c2bcc64f4e8de2ff564e3"},{"path":"src/app/api/auth/login","mode":"040000","type":"tree","sha":"060e2a889a144e3d8bf24593ac13d6974bfa0579","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/060e2a889a144e3d8bf24593ac13d6974bfa0579"},{"path":"src/app/api/auth/login/route.ts","mode":"100644","type":"blob","sha":"c93b0fa7d3bf528d084d8041d7309ba131a574ee","size":820,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/c93b0fa7d3bf528d084d8041d7309ba131a574ee"},{"path":"src/app/api/internal","mode":"040000","type":"tree","sha":"dc5aa39c4752692248035e5724383f3b7df96baf","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/dc5aa39c4752692248035e5724383f3b7df96baf"},{"path":"src/app/api/internal/deadlines","mode":"040000","type":"tree","sha":"1cd8cfb00e9a18be08bb779aec65ec3e7bd686aa","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/1cd8cfb00e9a18be08bb779aec65ec3e7bd686aa"},{"path":"src/app/api/internal/deadlines/route.ts","mode":"100644","type":"blob","sha":"0bd0d52e3bda29508e3c62800656d96fb35a72f4","size":1168,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/0bd0d52e3bda29508e3c62800656d96fb35a72f4"},{"path":"src/app/api/landing","mode":"040000","type":"tree","sha":"dd7bf20eaa6cc37e9b2556808e01624a25541018","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/dd7bf20eaa6cc37e9b2556808e01624a25541018"},{"path":"src/app/api/landing/route.ts","mode":"100644","type":"blob","sha":"e5f63e4d6fb424f7313fd4351b407c57fcb4c593","size":1517,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/e5f63e4d6fb424f7313fd4351b407c57fcb4c593"},{"path":"src/app/api/profile","mode":"040000","type":"tree","sha":"3f54077873651fd9332103646a460f739b494a23","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/3f54077873651fd9332103646a460f739b494a23"},{"path":"src/app/api/profile/route.ts","mode":"100644","type":"blob","sha":"b6d846229bb050945f0b6596bf29821202d7a11a","size":2320,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/b6d846229bb050945f0b6596bf29821202d7a11a"},{"path":"src/app/api/realtime","mode":"040000","type":"tree","sha":"3ca48762f40cd8d9c450e9c3d81efd70c75dd999","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/3ca48762f40cd8d9c450e9c3d81efd70c75dd999"},{"path":"src/app/api/realtime/route.ts","mode":"100644","type":"blob","sha":"e861986e519a19cbae5fce0c7a52ae7824ef653b","size":858,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/e861986e519a19cbae5fce0c7a52ae7824ef653b"},{"path":"src/app/api/rooms","mode":"040000","type":"tree","sha":"5529021d5d3e919766a8f26dd5b9ae104fa8a3a4","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/5529021d5d3e919766a8f26dd5b9ae104fa8a3a4"},{"path":"src/app/api/rooms/[reference]","mode":"040000","type":"tree","sha":"1b901463ef8556a17db671fa42962ec67d5a75e0","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/1b901463ef8556a17db671fa42962ec67d5a75e0"},{"path":"src/app/api/rooms/[reference]/lobby","mode":"040000","type":"tree","sha":"5d3ec56576b5f2e91ad40b67c639c4c13584acac","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/5d3ec56576b5f2e91ad40b67c639c4c13584acac"},{"path":"src/app/api/rooms/[reference]/lobby/route.ts","mode":"100644","type":"blob","sha":"68f3f41853ba89a05adfb4ebb1125d877048eb8a","size":2886,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/68f3f41853ba89a05adfb4ebb1125d877048eb8a"},{"path":"src/app/api/rooms/[reference]/route.ts","mode":"100644","type":"blob","sha":"7d53288fd2c2b845e788df61148a20b48f5001be","size":4546,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/7d53288fd2c2b845e788df61148a20b48f5001be"},{"path":"src/app/api/rooms/route.ts","mode":"100644","type":"blob","sha":"441087b57bbd6ad2fd6a5a8670f1b9488c43588e","size":2491,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/441087b57bbd6ad2fd6a5a8670f1b9488c43588e"},{"path":"src/app/api/session","mode":"040000","type":"tree","sha":"9f13be31e5000533c7278f587883fee712ff7ac9","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/9f13be31e5000533c7278f587883fee712ff7ac9"},{"path":"src/app/api/session/route.ts","mode":"100644","type":"blob","sha":"54fa45c3fc09a73d1e8e0d82e98a98457dd7e408","size":2199,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/54fa45c3fc09a73d1e8e0d82e98a98457dd7e408"},{"path":"src/app/globals.css","mode":"100644","type":"blob","sha":"e1d1bd629d5cfa1036bc73f2bb2464fcd307c09f","size":10657,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/e1d1bd629d5cfa1036bc73f2bb2464fcd307c09f"},{"path":"src/app/layout.tsx","mode":"100644","type":"blob","sha":"cc2c4366f306987f655fc8c5fe0b9110d1774cd6","size":388,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/cc2c4366f306987f655fc8c5fe0b9110d1774cd6"},{"path":"src/app/page.tsx","mode":"100644","type":"blob","sha":"052573134b2a430e640a6242c36265f013c869b5","size":2251,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/052573134b2a430e640a6242c36265f013c869b5"},{"path":"src/app/play","mode":"040000","type":"tree","sha":"fc7d4ae9a6545ac5e550d29233076168aebdd283","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/fc7d4ae9a6545ac5e550d29233076168aebdd283"},{"path":"src/app/play/page.tsx","mode":"100644","type":"blob","sha":"35aa6db781f4952b5a275d01a9dd8ba43ca1121e","size":519,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/35aa6db781f4952b5a275d01a9dd8ba43ca1121e"},{"path":"src/app/rooms","mode":"040000","type":"tree","sha":"dd6bb8947467b4f6e0de46ebc62fe9ed82c6c429","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/dd6bb8947467b4f6e0de46ebc62fe9ed82c6c429"},{"path":"src/app/rooms/[reference]","mode":"040000","type":"tree","sha":"4baad71da6bbefb013ebf6ad95077758a64172ec","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/4baad71da6bbefb013ebf6ad95077758a64172ec"},{"path":"src/app/rooms/[reference]/page.tsx","mode":"100644","type":"blob","sha":"e9e4d8ebf8b0ac1bc2e551ad25732e8844b53836","size":849,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/e9e4d8ebf8b0ac1bc2e551ad25732e8844b53836"},{"path":"src/application","mode":"040000","type":"tree","sha":"78c0ef7dd3f6aa353baa1422c998fd65e03f45bf","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/78c0ef7dd3f6aa353baa1422c998fd65e03f45bf"},{"path":"src/application/command.ts","mode":"100644","type":"blob","sha":"fec8d61ba5cb550bd06ef713ab64175efa94e516","size":2057,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/fec8d61ba5cb550bd06ef713ab64175efa94e516"},{"path":"src/application/identity.ts","mode":"100644","type":"blob","sha":"da0ca8416714b01514beecae055e31de06972c87","size":7824,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/da0ca8416714b01514beecae055e31de06972c87"},{"path":"src/application/index.ts","mode":"100644","type":"blob","sha":"cb0ff5c3b541f646105198ee23ac0fc3d805023e","size":11,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/cb0ff5c3b541f646105198ee23ac0fc3d805023e"},{"path":"src/application/lobby.ts","mode":"100644","type":"blob","sha":"770eaba2c59fe973967ccd394112bd5e7cd17810","size":5904,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/770eaba2c59fe973967ccd394112bd5e7cd17810"},{"path":"src/application/outbox.ts","mode":"100644","type":"blob","sha":"e9d1326d80094753a32213cfdcb123410e9d4df3","size":831,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/e9d1326d80094753a32213cfdcb123410e9d4df3"},{"path":"src/application/ports.ts","mode":"100644","type":"blob","sha":"8e2cf53114428ed84c98b3096f1557e541532388","size":3706,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/8e2cf53114428ed84c98b3096f1557e541532388"},{"path":"src/application/public-pages.ts","mode":"100644","type":"blob","sha":"cac5b1a5c24eae6e16e3fc16487727c767980681","size":1657,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/cac5b1a5c24eae6e16e3fc16487727c767980681"},{"path":"src/application/public-projections.ts","mode":"100644","type":"blob","sha":"cec73c3e10188acd4092e470ffa496530443ec18","size":2534,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/cec73c3e10188acd4092e470ffa496530443ec18"},{"path":"src/application/public-service.ts","mode":"100644","type":"blob","sha":"6105c59de62aef5c2d9d8c26f7060f0af5b9c0cd","size":3680,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/6105c59de62aef5c2d9d8c26f7060f0af5b9c0cd"},{"path":"src/application/rooms.ts","mode":"100644","type":"blob","sha":"5ea0f7ccb3a6079373ec3af3b3928d332ec665ae","size":8050,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/5ea0f7ccb3a6079373ec3af3b3928d332ec665ae"},{"path":"src/domain","mode":"040000","type":"tree","sha":"60f84dbd1311fef21d9ed815135e33c751e7a54c","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/60f84dbd1311fef21d9ed815135e33c751e7a54c"},{"path":"src/domain/index.ts","mode":"100644","type":"blob","sha":"cb0ff5c3b541f646105198ee23ac0fc3d805023e","size":11,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/cb0ff5c3b541f646105198ee23ac0fc3d805023e"},{"path":"src/domain/lobby.ts","mode":"100644","type":"blob","sha":"b3b760ab2d8cbab978560bb4ed9ff1ba6d0ac7cc","size":10527,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/b3b760ab2d8cbab978560bb4ed9ff1ba6d0ac7cc"},{"path":"src/domain/model.ts","mode":"100644","type":"blob","sha":"25bbf8a056e79e24f42a5eac1c34269664d15d3e","size":3164,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/25bbf8a056e79e24f42a5eac1c34269664d15d3e"},{"path":"src/domain/result.ts","mode":"100644","type":"blob","sha":"b235829c17598133d5e16b16139218bf1cd45645","size":745,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/b235829c17598133d5e16b16139218bf1cd45645"},{"path":"src/domain/rooms.ts","mode":"100644","type":"blob","sha":"63c56a73b8f16072012c4a7fdc9b0c5de448a93f","size":3782,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/63c56a73b8f16072012c4a7fdc9b0c5de448a93f"},{"path":"src/infrastructure","mode":"040000","type":"tree","sha":"d62915c17bb942ae52952c6e88c2187f3ebf742b","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/d62915c17bb942ae52952c6e88c2187f3ebf742b"},{"path":"src/infrastructure/deadlines.ts","mode":"100644","type":"blob","sha":"d6d748a5bd96cc883371d43032c5adf6cc423fd9","size":1338,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/d6d748a5bd96cc883371d43032c5adf6cc423fd9"},{"path":"src/infrastructure/identity-repository.ts","mode":"100644","type":"blob","sha":"534d3b9386813773d47e78c29ff0107949ece8cd","size":2687,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/534d3b9386813773d47e78c29ff0107949ece8cd"},{"path":"src/infrastructure/index.ts","mode":"100644","type":"blob","sha":"cb0ff5c3b541f646105198ee23ac0fc3d805023e","size":11,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/cb0ff5c3b541f646105198ee23ac0fc3d805023e"},{"path":"src/infrastructure/invitations.ts","mode":"100644","type":"blob","sha":"c80f601d711c477637eaa9093b0f3c6a514dcd12","size":963,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/c80f601d711c477637eaa9093b0f3c6a514dcd12"},{"path":"src/infrastructure/migrations","mode":"040000","type":"tree","sha":"df16ab3a74bde59f8bf1d1c328c19edc3dc519eb","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/df16ab3a74bde59f8bf1d1c328c19edc3dc519eb"},{"path":"src/infrastructure/migrations/001_foundation.sql","mode":"100644","type":"blob","sha":"4d82984c59ec23a08422ef7e37a3e57486e6d1d2","size":18385,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/4d82984c59ec23a08422ef7e37a3e57486e6d1d2"},{"path":"src/infrastructure/migrations/002_public_reads.sql","mode":"100644","type":"blob","sha":"2b6a801976429330ee07c4ab7a69e04d41d4f005","size":4825,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/2b6a801976429330ee07c4ab7a69e04d41d4f005"},{"path":"src/infrastructure/migrations/003_identity.sql","mode":"100644","type":"blob","sha":"5fc3f67bd09a64c006438534955fecb5ef9708f2","size":6677,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/5fc3f67bd09a64c006438534955fecb5ef9708f2"},{"path":"src/infrastructure/migrations/004_rooms.sql","mode":"100644","type":"blob","sha":"80b0d18321d1328d9af2f2a9128ddabc3905daf7","size":10306,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/80b0d18321d1328d9af2f2a9128ddabc3905daf7"},{"path":"src/infrastructure/migrations/005_outbox.sql","mode":"100644","type":"blob","sha":"b426bb0958fc042e86fe6ae6225019fe258735af","size":1420,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/b426bb0958fc042e86fe6ae6225019fe258735af"},{"path":"src/infrastructure/migrations/006_lobby_deadlines.sql","mode":"100644","type":"blob","sha":"3ad750f7489eda798d5974109b169e4b6831fe3b","size":4140,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/3ad750f7489eda798d5974109b169e4b6831fe3b"},{"path":"src/infrastructure/oidc.ts","mode":"100644","type":"blob","sha":"401476b52daefc520088cc6ead4d5a526b3a2ec9","size":3866,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/401476b52daefc520088cc6ead4d5a526b3a2ec9"},{"path":"src/infrastructure/outbox.ts","mode":"100644","type":"blob","sha":"f64f20ab7b706b0d1c306695f8d502ab418e100f","size":1218,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/f64f20ab7b706b0d1c306695f8d502ab418e100f"},{"path":"src/infrastructure/postgres-pool.ts","mode":"100644","type":"blob","sha":"9202601cbe9d6d644f3ea9696dd1cf6278478760","size":1276,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/9202601cbe9d6d644f3ea9696dd1cf6278478760"},{"path":"src/infrastructure/public-read.ts","mode":"100644","type":"blob","sha":"4528e91bb065e07dee1239f46ba76bd40e0057c7","size":2100,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/4528e91bb065e07dee1239f46ba76bd40e0057c7"},{"path":"src/infrastructure/realtime-policy.sql","mode":"100644","type":"blob","sha":"ec6f25faa970ddc8a78354d6ba06a372bee26526","size":525,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/ec6f25faa970ddc8a78354d6ba06a372bee26526"},{"path":"src/infrastructure/realtime.ts","mode":"100644","type":"blob","sha":"318390000ef49d6115e08f189a601e75c90d9ba5","size":3654,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/318390000ef49d6115e08f189a601e75c90d9ba5"},{"path":"src/infrastructure/room-repository.ts","mode":"100644","type":"blob","sha":"d8f8bcf3bd19e64f0f27d6ec31c0651c8f5c6f5c","size":4956,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/d8f8bcf3bd19e64f0f27d6ec31c0651c8f5c6f5c"},{"path":"src/infrastructure/runtime.ts","mode":"100644","type":"blob","sha":"e409c6ecda779e884b32fa04e3140f51425b26f2","size":5197,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/e409c6ecda779e884b32fa04e3140f51425b26f2"},{"path":"src/infrastructure/secrets.ts","mode":"100644","type":"blob","sha":"654d69c233baaaf6fa84ecfd74c4c2d4c66906bd","size":399,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/654d69c233baaaf6fa84ecfd74c4c2d4c66906bd"},{"path":"src/infrastructure/supabase-postgres.ts","mode":"100644","type":"blob","sha":"e20d91b25c4ae7441c947ddb56b48d670c3804a8","size":4741,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/e20d91b25c4ae7441c947ddb56b48d670c3804a8"},{"path":"src/web","mode":"040000","type":"tree","sha":"e2692ccd080e65d8b503cc4a2e48945d0b56f192","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/e2692ccd080e65d8b503cc4a2e48945d0b56f192"},{"path":"src/web/guest-credential.ts","mode":"100644","type":"blob","sha":"676929c7938783fee00202a1fff3b932e90d530c","size":1510,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/676929c7938783fee00202a1fff3b932e90d530c"},{"path":"src/web/identity-panel.tsx","mode":"100644","type":"blob","sha":"cc290a2a80c3e3ddaac28f4aaf2c68a55897c179","size":8710,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/cc290a2a80c3e3ddaac28f4aaf2c68a55897c179"},{"path":"src/web/landing-board.tsx","mode":"100644","type":"blob","sha":"55553dc9e15e0fe354057af456e6560a75b6dc5a","size":11823,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/55553dc9e15e0fe354057af456e6560a75b6dc5a"},{"path":"src/web/play-hub.tsx","mode":"100644","type":"blob","sha":"547ff287ac77d453d9b379446b5c2a73938b7c6f","size":5228,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/547ff287ac77d453d9b379446b5c2a73938b7c6f"},{"path":"src/web/room-screen.tsx","mode":"100644","type":"blob","sha":"a2fdefd47d83cb3321cb33285067dcbac4564561","size":16778,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/a2fdefd47d83cb3321cb33285067dcbac4564561"},{"path":"src/web/server-http.ts","mode":"100644","type":"blob","sha":"07b91df82d3ff056fc001b782b42e5087d731ba8","size":2919,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/07b91df82d3ff056fc001b782b42e5087d731ba8"},{"path":"src/web/use-room-updates.ts","mode":"100644","type":"blob","sha":"5649ee56b84064ae8a80ba5b0cf7e7b56a0c0349","size":2484,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/5649ee56b84064ae8a80ba5b0cf7e7b56a0c0349"},{"path":"tests","mode":"040000","type":"tree","sha":"5744183f80225966d930b4e0aa24442e376df331","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/5744183f80225966d930b4e0aa24442e376df331"},{"path":"tests/ac-contracts","mode":"040000","type":"tree","sha":"19960738705bef4ecae7ba853b5e7c3996ebd274","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/19960738705bef4ecae7ba853b5e7c3996ebd274"},{"path":"tests/ac-contracts/archive-fixture-validator.ts","mode":"100644","type":"blob","sha":"6b6edad1fb08e0c14f06e9a3bd7d0fd0ca77d5ab","size":4447,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/6b6edad1fb08e0c14f06e9a3bd7d0fd0ca77d5ab"},{"path":"tests/ac-contracts/oracle-contract-expectations.ts","mode":"100644","type":"blob","sha":"afcb887487f620ae6cfc154440554fd823905ffc","size":19422,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/afcb887487f620ae6cfc154440554fd823905ffc"},{"path":"tests/ac-contracts/oracle-scenarios.ts","mode":"100644","type":"blob","sha":"02fe0ce4362ff75a72a171fd355f0c3861851906","size":45693,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/02fe0ce4362ff75a72a171fd355f0c3861851906"},{"path":"tests/ac-contracts/oracle-supplemental-contracts.ts","mode":"100644","type":"blob","sha":"ff817832c7cded8fbdd4521c740fff63f69368bc","size":8240,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/ff817832c7cded8fbdd4521c740fff63f69368bc"},{"path":"tests/ac-contracts/oracle-supplemental-scenarios.ts","mode":"100644","type":"blob","sha":"9ff9cf9af863f8154e7208b40707ac4602588007","size":23173,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/9ff9cf9af863f8154e7208b40707ac4602588007"},{"path":"tests/ac-contracts/oracle-supplemental-validation.test.ts","mode":"100644","type":"blob","sha":"302f039019995531b19c9f044609e5264b9feb5a","size":8909,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/302f039019995531b19c9f044609e5264b9feb5a"},{"path":"tests/ac-contracts/oracle-validation.test.ts","mode":"100644","type":"blob","sha":"d8204253bd959960e52a69914926356a7ec31e0c","size":6196,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/d8204253bd959960e52a69914926356a7ec31e0c"},{"path":"tests/application","mode":"040000","type":"tree","sha":"19f900693051f05daf5cde5e0c1c8a1e05f06d67","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/19f900693051f05daf5cde5e0c1c8a1e05f06d67"},{"path":"tests/application/command.test.ts","mode":"100644","type":"blob","sha":"f76ec9fb793e81db56d544d8409d2f2e58b1d8f8","size":12341,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/f76ec9fb793e81db56d544d8409d2f2e58b1d8f8"},{"path":"tests/application/identity.test.ts","mode":"100644","type":"blob","sha":"10e3375dafa6f919583d51840dbe38b8f085886c","size":2942,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/10e3375dafa6f919583d51840dbe38b8f085886c"},{"path":"tests/application/lobby.test.ts","mode":"100644","type":"blob","sha":"15ebc2d6e027687cf0a8c2ffeb1c0120662388a6","size":14304,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/15ebc2d6e027687cf0a8c2ffeb1c0120662388a6"},{"path":"tests/application/public-projections.test.ts","mode":"100644","type":"blob","sha":"a2a8df140c878931b213c3516e8a2c157b8f8494","size":3681,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/a2a8df140c878931b213c3516e8a2c157b8f8494"},{"path":"tests/application/public-service.test.ts","mode":"100644","type":"blob","sha":"84259729aed3ebe44fdfc8d16e2af702b4405d30","size":4546,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/84259729aed3ebe44fdfc8d16e2af702b4405d30"},{"path":"tests/application/rooms.test.ts","mode":"100644","type":"blob","sha":"bc53e143497c22cdb4b57317a0ae6c98d53056f2","size":3365,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/bc53e143497c22cdb4b57317a0ae6c98d53056f2"},{"path":"tests/architecture","mode":"040000","type":"tree","sha":"d53c810227e91a5eaa72c560334059edfa288d93","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/d53c810227e91a5eaa72c560334059edfa288d93"},{"path":"tests/architecture/import-boundary.ts","mode":"100644","type":"blob","sha":"81ee8da2a542795c6b030ce970f0f0eceeaf01e6","size":1750,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/81ee8da2a542795c6b030ce970f0f0eceeaf01e6"},{"path":"tests/architecture/phase1a-bootstrap.test.ts","mode":"100644","type":"blob","sha":"e6d171c075a8f9d64c3dff352a2bdaec029d25d4","size":3800,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/e6d171c075a8f9d64c3dff352a2bdaec029d25d4"},{"path":"tests/browser","mode":"040000","type":"tree","sha":"df6047aa4e0a09095d2b9ea709f7908e7dc695e0","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/df6047aa4e0a09095d2b9ea709f7908e7dc695e0"},{"path":"tests/browser/identity.phase2.spec.ts","mode":"100644","type":"blob","sha":"e6b4d98b16a5ebef31314c856eedb5e7e2659caf","size":1945,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/e6b4d98b16a5ebef31314c856eedb5e7e2659caf"},{"path":"tests/browser/lobby.phase3.spec.ts","mode":"100644","type":"blob","sha":"3642182c8b4e92a195197d621c476c1b10923ae6","size":6200,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/3642182c8b4e92a195197d621c476c1b10923ae6"},{"path":"tests/browser/privacy.phase2.spec.ts","mode":"100644","type":"blob","sha":"02eee1f903841696e428df6fc56559260d16a72f","size":3279,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/02eee1f903841696e428df6fc56559260d16a72f"},{"path":"tests/browser/rooms.phase2.spec.ts","mode":"100644","type":"blob","sha":"c190990f1d21d963b5bfdbc40a0375e70c03d4f4","size":4325,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/c190990f1d21d963b5bfdbc40a0375e70c03d4f4"},{"path":"tests/integration","mode":"040000","type":"tree","sha":"06b34e22fc9533d1ce31ad57647231d1ebae05ac","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/06b34e22fc9533d1ce31ad57647231d1ebae05ac"},{"path":"tests/integration/identity.integration.ts","mode":"100644","type":"blob","sha":"66845ce663dfff00ce4c62772a7b5a06825a6438","size":7230,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/66845ce663dfff00ce4c62772a7b5a06825a6438"},{"path":"tests/integration/invitations.test.ts","mode":"100644","type":"blob","sha":"da7b8aa4a4c8f098e1c5c04a5bc0344d7dc683b3","size":980,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/da7b8aa4a4c8f098e1c5c04a5bc0344d7dc683b3"},{"path":"tests/integration/live-postgres.integration.ts","mode":"100644","type":"blob","sha":"b1bfa366b52ab704ac6b8e559a16c16c308b062a","size":5624,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/b1bfa366b52ab704ac6b8e559a16c16c308b062a"},{"path":"tests/integration/lobby.integration.ts","mode":"100644","type":"blob","sha":"ae3423cd5c2f6c121f9fb459121245845b09f6f0","size":9251,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/ae3423cd5c2f6c121f9fb459121245845b09f6f0"},{"path":"tests/integration/oidc.test.ts","mode":"100644","type":"blob","sha":"236f6f1a997a4f4efebba98e2cbf50c3c6a8cc9d","size":5081,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/236f6f1a997a4f4efebba98e2cbf50c3c6a8cc9d"},{"path":"tests/integration/phase1-contract.sql","mode":"100644","type":"blob","sha":"e70d9aa0432213baa3272b473d9d99790db6bd29","size":7141,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/e70d9aa0432213baa3272b473d9d99790db6bd29"},{"path":"tests/integration/postgres-pool.test.ts","mode":"100644","type":"blob","sha":"ff3cb04f2c0822d51b4b43440340ac8195104c25","size":1185,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/ff3cb04f2c0822d51b4b43440340ac8195104c25"},{"path":"tests/integration/postgres-store.test.ts","mode":"100644","type":"blob","sha":"fd7b5677f6677dc0f31a58cad2022ac8469f8061","size":5677,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/fd7b5677f6677dc0f31a58cad2022ac8469f8061"},{"path":"tests/integration/public-read.integration.ts","mode":"100644","type":"blob","sha":"706062eb9a53ba298954903e9262cc81112368ac","size":4987,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/706062eb9a53ba298954903e9262cc81112368ac"},{"path":"tests/integration/public-read.test.ts","mode":"100644","type":"blob","sha":"1355fb210265f7d2522b2fb5a21bb52143bbd0c9","size":1895,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/1355fb210265f7d2522b2fb5a21bb52143bbd0c9"},{"path":"tests/integration/realtime.test.ts","mode":"100644","type":"blob","sha":"0b60872f00edbae6616bd53d16a38075cf3884dc","size":3466,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/0b60872f00edbae6616bd53d16a38075cf3884dc"},{"path":"tests/integration/rooms.integration.ts","mode":"100644","type":"blob","sha":"79190fd67772f859761dc0fceab8d3f6ece807f7","size":7242,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/79190fd67772f859761dc0fceab8d3f6ece807f7"},{"path":"tests/integration/run-phase1.ps1","mode":"100644","type":"blob","sha":"891ed7c057feb1503b8cf1c36abf1d5aa97db0c3","size":9876,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/891ed7c057feb1503b8cf1c36abf1d5aa97db0c3"},{"path":"tests/integration/transport.realtime.integration.ts","mode":"100644","type":"blob","sha":"c13a9f4fcd25744687df638b613ffe3bbf198bee","size":7021,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/c13a9f4fcd25744687df638b613ffe3bbf198bee"},{"path":"tests/tr-contracts","mode":"040000","type":"tree","sha":"44de0144ee5b64a8a95f3895c868dc0fdc2e9619","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/44de0144ee5b64a8a95f3895c868dc0fdc2e9619"},{"path":"tests/tr-contracts/reaction-contracts.test.ts","mode":"100644","type":"blob","sha":"8e286960be2bbc2e3f1069c798e4be11e4d3ebf8","size":3405,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/8e286960be2bbc2e3f1069c798e4be11e4d3ebf8"},{"path":"tests/traceability","mode":"040000","type":"tree","sha":"e7b0371f02b51839fd104b15d93d254d81c53719","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/e7b0371f02b51839fd104b15d93d254d81c53719"},{"path":"tests/traceability/ac-inventory.test.ts","mode":"100644","type":"blob","sha":"9498a991c39203c2c5371eff61ac07d49344d697","size":6006,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/9498a991c39203c2c5371eff61ac07d49344d697"},{"path":"tests/traceability/inventory-validator.ts","mode":"100644","type":"blob","sha":"600c04aeeef6e1bbf75f8e027f6a704273d180c4","size":3035,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/600c04aeeef6e1bbf75f8e027f6a704273d180c4"},{"path":"tests/web","mode":"040000","type":"tree","sha":"ead1f0146da8e4df124f2d5b3930b155edbe69c6","url":"https://api.github.com/repos/sharpninja/wordpairs/git/trees/ead1f0146da8e4df124f2d5b3930b155edbe69c6"},{"path":"tests/web/identity-api.test.ts","mode":"100644","type":"blob","sha":"74a080b927c8ece80a0fb026812ca6c0f42a67b0","size":4986,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/74a080b927c8ece80a0fb026812ca6c0f42a67b0"},{"path":"tests/web/landing-api.test.ts","mode":"100644","type":"blob","sha":"82a09aa6bb8031a713c4c47edd68d9769f5301c7","size":1080,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/82a09aa6bb8031a713c4c47edd68d9769f5301c7"},{"path":"tests/web/landing.test.ts","mode":"100644","type":"blob","sha":"5f4282489cb972746e21a1d7878314359f0d76b0","size":7447,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/5f4282489cb972746e21a1d7878314359f0d76b0"},{"path":"tests/web/lobby-api.test.ts","mode":"100644","type":"blob","sha":"53e2d2ac8dd14a94cd062b3783b0a38555c53444","size":3261,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/53e2d2ac8dd14a94cd062b3783b0a38555c53444"},{"path":"tests/web/rooms-api.test.ts","mode":"100644","type":"blob","sha":"05dc70b9cbae8a558138424c456b34bdd8d3df77","size":4418,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/05dc70b9cbae8a558138424c456b34bdd8d3df77"},{"path":"tsconfig.json","mode":"100644","type":"blob","sha":"4524c04d8219a01747b7e921a9a61a1fc3dbab4c","size":836,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/4524c04d8219a01747b7e921a9a61a1fc3dbab4c"},{"path":"vitest.config.ts","mode":"100644","type":"blob","sha":"9e31dc5919ce2777c7bb014d498d745970305062","size":275,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/9e31dc5919ce2777c7bb014d498d745970305062"},{"path":"vitest.postgres.config.ts","mode":"100644","type":"blob","sha":"13328f042231b1f0fc2c9dfa5a35e9c8d4c64928","size":312,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/13328f042231b1f0fc2c9dfa5a35e9c8d4c64928"},{"path":"vitest.realtime.config.ts","mode":"100644","type":"blob","sha":"0e0169d8e7bce633feef8d79b4a70b57acd382cf","size":197,"url":"https://api.github.com/repos/sharpninja/wordpairs/git/blobs/0e0169d8e7bce633feef8d79b4a70b57acd382cf"}],"truncated":false},"comparison":{"sha":"06310ba41e116adb72b874b59153fd5330e9b579","truncated":false,"localCount":151,"remoteCount":151,"equal":true}}}