diff --git a/docs/PROJECT_LOG.md b/docs/PROJECT_LOG.md index e4373f7..1972cd9 100644 --- a/docs/PROJECT_LOG.md +++ b/docs/PROJECT_LOG.md @@ -69,6 +69,20 @@ Payments/monetization P0s are separately listed in `docs/MVP_STATUS_AND_DEV_PLAN ## Log +### 2026-10-15 — Safe crew inventory transfer and demo reload continuity (#208) + +Reserved the existing economy-transfer action, TRAP give flow, their new regressions, and narrowly scoped demo-reseed inventory continuation before editing from protected main `9eef5aa`. This is independent of open ATTACK #204, Nightfall #205, DRIVE #202, identity #169, current-login API #206, and legacy session-owner #207 runtime files; their branches were not edited or merged. + +The existing `transferItemToMember` used browser-incompatible CommonJS `require`, accepted malformed quantities, dropped metadata, and deducted all matching stash stacks. It now uses static ESM imports and existing role rules, validates positive whole requested quantities against current stock/active recipient, accepts an optional exact source-stack ID, preserves product/gear metadata with unique carried IDs, and returns explicit success/failure. TRAP confirms only successful gives, shows retryable inline denial, and guards one selected action against same-frame taps. Unclassified legacy weapons remain unsupported; no DRIVE classification or new authority was invented. Contacts' ignored return result remains a separately coordinated follow-up because its file overlaps deferred identity work. + +Actual reload tracing additionally reproduced demo startup erasing transferred carried inventory. The minimal demo-only repair preserves it only for the prior demo player and matching demo-gang member, never another account/gang. Other seed reset behavior is unchanged. + +Regression-first evidence covers base store/UI runtime failures; second-batch, missing-feedback and reseed failures before their fixes; and actual carried-record loss after page reload. Final focused/adjacent suite: 35 passed (29 new regressions plus six existing seeder tests). Full gates: 1,062 frontend passed / four existing intentional skips / 94 files; lint 0 errors and unchanged 200 baseline warnings; typecheck, production build, asset audit/packages and diff hygiene passed; isolated backend 107 passed. Independent read-only review found no material issues. A separately built local demo passed desktop-to-TRAP give, role-denial and actual reload at 390×844, 375×812 and 1440×900 with zero uncaught page exceptions. + +Built-preview console evidence remains honest: unchanged `/favicon.svg`, `/assets/game_logo.png` and `/assets/generated/ui/icons/icon_news_v001.png` return 404 (5/4/4 occurrences including reload), while dev SPA fallback masks those HTTP failures. Reported under #190; no shell/index/sprite/manifest or asset edit occurred. This is not clean-console, authenticated saved-game, external-beta or launch proof. Evidence: `docs/evidence/2026-10-15-inventory-transfer/README.md`, raw red/green/full gates, browser JSON, screenshots, portable runner and source hashes. + +The ten-PR audit also identified the already posted unresolved P1 in #206; integration hold recorded on #175. #175 remains open for separately approved isolated-staging two-synthetic-user Auth/RLS/denied-direct-write and canonical Flask consequence/reload/second-session proof. Migration 007 is already applied and must not be replayed. Older project-log current-state/roadmap blocks remain historical; this entry does not rewrite them or supersede the contributor guide. No remote SQL/migration, Auth configuration, production, deployment, scheduler, payment, release tag, protected branch or other model branch changed. Branch `fix/safe-crew-inventory-transfer` is prepared for integration-owner review, not merged or deployed. + ### 2026-10-01 — Backend timestamps are timezone-aware UTC (#170) - Replaced all 17 `datetime.utcnow()` call sites in the live backend runtime with one shared helper, `backend/python/utils/utc.py` (`utc_now`, `to_iso_utc`, `utc_now_iso`). Python 3.12 deprecates `utcnow()` and the required CI runs the full backend suite, so the debt was visible on every run: the audited baseline emitted 153 warnings, all of them this single warning. The suite now runs with 0 warnings. diff --git a/docs/evidence/2026-10-15-inventory-transfer/README.md b/docs/evidence/2026-10-15-inventory-transfer/README.md new file mode 100644 index 0000000..37d4504 --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/README.md @@ -0,0 +1,75 @@ +# Safe crew inventory transfer — verification record + +_Manus · 2026-10-15 · [Issue #208](https://github.com/BrandDead/slide/issues/208) · base `9eef5aac28a82275d7a2e1596e8658b167953ed7`_ + +--- + +## Player outcome and authority + +A player opens **TRAP** from the existing command desktop, selects a product stack and an active eligible crew member, and presses **GIVE**. The existing economy store deducts only the requested units from that exact stack; the existing roster stores the complete carried record. Recorded product risk/quality and gear stats are retained. Rejected actions do not move inventory or report success, provide visible feedback, and remain retryable. Two same-frame taps on one selected give submit once; a later explicit selection can give again. + +The store action uses ESM imports, positive safe-integer requested quantities, current stock/recipient checks, existing role rules, optional exact source-stack identity, and unique carried-item IDs. Legacy unclassified `weapon` items remain blocked; no ranged/melee classification or DRIVE loadout behavior was invented. Contacts remains compatible with the action's original three arguments, but its pre-existing unconditional success message is a separately coordinated follow-up. + +Demo startup previously rebuilt starter crew without its persisted inventory. The narrowly scoped reseed repair carries inventory forward only when the pre-seed player is `demo-player` and the prior member belongs to the same demo gang. It does not import another account/gang's items. Other demo reset behavior is unchanged. + +**No new store, combat/economy authority, API, schema, migration, production configuration, scheduler, payment flow, asset, or multiplayer behavior was added.** Local demo persistence is not authenticated saved-game proof for #175. + +## Regression-first evidence + +`store-ui-red.log` records failure against unchanged main: the live action's CommonJS `require` fails at runtime. Real browser reproduction at 390×844 and 1440×900 also recorded `require is not defined` with no inventory transfer in `browser-base.json`. + +`selected-batch-red.log` shows an explicitly selected second same-item stack incorrectly consuming the first stack; `inline-feedback-red.log` shows no visible rejection alert; `demo-reseed-red.log` shows two real startup/persistence regressions failing; and `browser-reload-red.log` shows the transferred carried record becoming `undefined` after real reload. These were observed before their respective fixes. + +`focused-green.log` then records **35 passing tests**: 29 new transfer/UI/reseed regressions and six existing adjacent Contacts/books/progression reseed tests. `independent-review.md` records a read-only second review with **no material findings**. + +## Full local gates + +| Gate | Verified result | +| --- | --- | +| Full frontend tests | 1,062 passed; 4 existing intentional skips; 94 files | +| Lint | 0 errors; 200 unchanged baseline warnings | +| Typecheck and production build | Passed | +| Asset audit | 112 assets; 0 errors/warnings; 7.70 MB / 20 MB budget | +| Package validation | 5 packages; 4 schemas; passed | +| Isolated backend pytest | 107 passed | +| Diff hygiene | Passed | + +Commands and raw output are retained in `full-preflight.log` and `backend-green.log`. Only terminal trailing whitespace and extra EOF blank lines were normalized for diff hygiene; assertions, outcomes and errors are unchanged. The existing oversized-bundle warnings remain. Backend tests ran with remote Supabase/database variables blank; no remote production data was accessed or changed. + +## Final built-game player path + +The **separately built demo artifact**, not just the dev server, was checked at **390×844, 375×812, and 1440×900**. `browser-built.json` records each assertion and raw error list. The route was mature-content notice → command desktop → TRAP → product → Lil Dre → GIVE → product → Big Rome → rejected GIVE → actual page reload → desktop → TRAP. + +All three scoped paths passed: stash 50→49, one retained carried unit with the same complete persisted record after reload, denied shooter product with no second success message, visible inline rejection, and reachable GIVE hit target. There were **zero uncaught page exceptions**. Same-frame repeat, exact batch selection, stale stock/member state, and legitimate repeat-selection behavior have real component/store regression coverage; browser proof is not claimed for every unit-test case. + +![Phone denial leaves stock unchanged and provides visible rejection](built-small-phone-role-denied.png) +_Figure 1: Final 375×812 built-demo rejection state; GIVE/CANCEL remain reachable._ + +![Desktop reload retains both the remaining stash and Lil Dre's carried item](built-desktop-after-reload.png) +_Figure 2: Final 1440×900 built-demo after reload; stash remains x49 and Lil Dre carries one item._ + +### Existing resource failures are not hidden + +This is **not clean-console or launch approval**. The built artifact exposed unchanged missing `/favicon.svg`, `/assets/game_logo.png`, and `/assets/generated/ui/icons/icon_news_v001.png`. Their files are absent from the protected base, and this repair does not alter their index/shell/sprite references. The raw evidence records 5, 4, and 4 resource-error occurrences across the three viewports including reload. The dev server's SPA fallback had hidden those HTTP 404s. + +These paths were reported to the existing [visual workstream #190](https://github.com/BrandDead/slide/issues/190#issuecomment-6193823864). The runner only classifies those explicit proven-baseline 404 paths; any other HTTP error, non-resource console error, or page exception fails the scoped check. No replacement assets or hardcoded fallback URLs were added. + +## Reproduction and handoff + +From the repo on Node 24: + +```bash +bash .agents/skills/slide-release-safety/scripts/preflight.sh src/stores/__tests__/inventoryTransfer.test.ts +cd backend/python +SUPABASE_URL= SUPABASE_KEY= SUPABASE_SERVICE_ROLE_KEY= SUPABASE_ANON_KEY= DATABASE_URL= ./venv/bin/python -m pytest tests -q +``` + +For the browser runner, build with `VITE_DEMO_MODE=1` into a disposable output folder, serve it on port 3001, and use an isolated Chromium profile. Copy `check-trap.mjs` to a disposable QA folder, install `puppeteer-core` there without changing repo dependencies, then run: + +```bash +SLIDE_PREVIEW_URL=http://127.0.0.1:3001 \ +SLIDE_EVIDENCE_DIR=/absolute/path/to/this/evidence/folder \ +node /absolute/path/to/disposable-qa/check-trap.mjs built +``` + +The tested source/test SHA-256 values and base revision are recorded in `verification-summary.json`. Later integration must preserve every concurrent append-only project-log entry and rerun the combined candidate. Protected-main merge, production deployment, external beta, Auth/RLS and second-account proof remain separate gates. Do not replay migration 007. diff --git a/docs/evidence/2026-10-15-inventory-transfer/backend-green.log b/docs/evidence/2026-10-15-inventory-transfer/backend-green.log new file mode 100644 index 0000000..e6448d2 --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/backend-green.log @@ -0,0 +1,3 @@ +........................................................................ [ 67%] +................................... [100%] +107 passed in 2.20s diff --git a/docs/evidence/2026-10-15-inventory-transfer/base-desktop-after-give.png b/docs/evidence/2026-10-15-inventory-transfer/base-desktop-after-give.png new file mode 100644 index 0000000..caa07cc Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/base-desktop-after-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/base-desktop-before-give.png b/docs/evidence/2026-10-15-inventory-transfer/base-desktop-before-give.png new file mode 100644 index 0000000..378ea29 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/base-desktop-before-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/base-phone-after-give.png b/docs/evidence/2026-10-15-inventory-transfer/base-phone-after-give.png new file mode 100644 index 0000000..9d1acbe Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/base-phone-after-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/base-phone-before-give.png b/docs/evidence/2026-10-15-inventory-transfer/base-phone-before-give.png new file mode 100644 index 0000000..9d1acbe Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/base-phone-before-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/browser-base.json b/docs/evidence/2026-10-15-inventory-transfer/browser-base.json new file mode 100644 index 0000000..54b51dd --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/browser-base.json @@ -0,0 +1,48 @@ +[ + { + "name": "phone", + "viewport": { + "width": 390, + "height": 844 + }, + "mode": "base", + "before": 50, + "after": 50, + "giveControl": { + "x": 124, + "y": 800.5116577148438, + "width": 181.578125, + "height": 32, + "visible": true, + "hit": true + }, + "pageErrors": [ + "require is not defined", + "require is not defined" + ], + "pass": true + }, + { + "name": "desktop", + "viewport": { + "width": 1440, + "height": 900 + }, + "mode": "base", + "before": 50, + "after": 50, + "giveControl": { + "x": 244, + "y": 856.479248046875, + "width": 991.578125, + "height": 32, + "visible": true, + "hit": true + }, + "pageErrors": [ + "require is not defined", + "require is not defined" + ], + "pass": true + } +] diff --git a/docs/evidence/2026-10-15-inventory-transfer/browser-built.json b/docs/evidence/2026-10-15-inventory-transfer/browser-built.json new file mode 100644 index 0000000..3e4e2f0 --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/browser-built.json @@ -0,0 +1,169 @@ +[ + { + "name": "phone", + "viewport": { + "width": 390, + "height": 844 + }, + "mode": "built", + "url": "http://127.0.0.1:3001", + "before": 50, + "after": 49, + "scope": "inventory player path; not a clean-console or launch approval", + "giveControl": { + "x": 124, + "y": 800.5116577148438, + "width": 181.578125, + "height": 32, + "visible": true, + "hit": true + }, + "pageErrors": [], + "consoleErrors": [ + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)" + ], + "failedResources": [ + { + "url": "http://127.0.0.1:3001/favicon.svg", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/game_logo.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/generated/ui/icons/icon_news_v001.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/game_logo.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/generated/ui/icons/icon_news_v001.png", + "status": 404 + } + ], + "checks": [ + "real Trap give", + "stock deducted once", + "carried item persisted", + "role denial has no success", + "inline rejection visible", + "real reload retains exact carried record and stock" + ], + "pass": true + }, + { + "name": "small-phone", + "viewport": { + "width": 375, + "height": 812 + }, + "mode": "built", + "url": "http://127.0.0.1:3001", + "before": 50, + "after": 49, + "scope": "inventory player path; not a clean-console or launch approval", + "giveControl": { + "x": 124, + "y": 768.3202514648438, + "width": 166.578125, + "height": 32, + "visible": true, + "hit": true + }, + "pageErrors": [], + "consoleErrors": [ + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)" + ], + "failedResources": [ + { + "url": "http://127.0.0.1:3001/assets/game_logo.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/generated/ui/icons/icon_news_v001.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/game_logo.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/generated/ui/icons/icon_news_v001.png", + "status": 404 + } + ], + "checks": [ + "real Trap give", + "stock deducted once", + "carried item persisted", + "role denial has no success", + "inline rejection visible", + "real reload retains exact carried record and stock" + ], + "pass": true + }, + { + "name": "desktop", + "viewport": { + "width": 1440, + "height": 900 + }, + "mode": "built", + "url": "http://127.0.0.1:3001", + "before": 50, + "after": 49, + "scope": "inventory player path; not a clean-console or launch approval", + "giveControl": { + "x": 244, + "y": 856.4043579101562, + "width": 991.578125, + "height": 32, + "visible": true, + "hit": true + }, + "pageErrors": [], + "consoleErrors": [ + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)" + ], + "failedResources": [ + { + "url": "http://127.0.0.1:3001/assets/game_logo.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/generated/ui/icons/icon_news_v001.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/game_logo.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/generated/ui/icons/icon_news_v001.png", + "status": 404 + } + ], + "checks": [ + "real Trap give", + "stock deducted once", + "carried item persisted", + "role denial has no success", + "inline rejection visible", + "real reload retains exact carried record and stock" + ], + "pass": true + } +] diff --git a/docs/evidence/2026-10-15-inventory-transfer/browser-fixed.json b/docs/evidence/2026-10-15-inventory-transfer/browser-fixed.json new file mode 100644 index 0000000..46206b9 --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/browser-fixed.json @@ -0,0 +1,62 @@ +[ + { + "name": "phone", + "viewport": { + "width": 390, + "height": 844 + }, + "mode": "fixed", + "before": 50, + "after": 49, + "giveControl": { + "x": 124, + "y": 800.5042724609375, + "width": 181.578125, + "height": 32, + "visible": true, + "hit": true + }, + "pageErrors": [], + "pass": true + }, + { + "name": "small-phone", + "viewport": { + "width": 375, + "height": 812 + }, + "mode": "fixed", + "before": 50, + "after": 49, + "giveControl": { + "x": 124, + "y": 768.5186767578125, + "width": 166.578125, + "height": 32, + "visible": true, + "hit": true + }, + "pageErrors": [], + "pass": true + }, + { + "name": "desktop", + "viewport": { + "width": 1440, + "height": 900 + }, + "mode": "fixed", + "before": 50, + "after": 49, + "giveControl": { + "x": 244, + "y": 856.3202514648438, + "width": 991.578125, + "height": 32, + "visible": true, + "hit": true + }, + "pageErrors": [], + "pass": true + } +] diff --git a/docs/evidence/2026-10-15-inventory-transfer/browser-reload-red.log b/docs/evidence/2026-10-15-inventory-transfer/browser-reload-red.log new file mode 100644 index 0000000..cc363a3 --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/browser-reload-red.log @@ -0,0 +1,79 @@ +phone live Trap controls: BACK +THE TRAP +$4.1K in stash +ALL +WEAPONS +ARMOR +VEHICLES +PRODUCT +TOOLS +CONSUMABLES +STASH +DRU +Cannabis +x50 +$1.0K +DRU +Cocaine +x20 +$1.6K +DRU +Percocet +x30 +$1.5K +CREW +LI +Lil Dre +DEALER +LV2 +BI +Big Rome +SHOOTER +LV3 +TA +Tasha +LOOKOUT +LV2 +KI +Kilo +ENFORCER +LV3 +node:internal/modules/run_main:122 + triggerUncaughtException( + ^ + +AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: ++ actual - expected + ++ undefined +- [ +- { +- acquiredAt: '2026-10-15T13:50:05.190Z', +- id: 'e7f37b9a-449d-45a5-8789-147e424e0f02', +- itemId: 'weed', +- name: 'Cannabis', +- quantity: 1, +- type: 'drug', +- value: 20 +- } +- ] + + at file:///home/ubuntu/slide-audit/check-trap.mjs:85:14 { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: undefined, + expected: [ + { + id: 'e7f37b9a-449d-45a5-8789-147e424e0f02', + type: 'drug', + itemId: 'weed', + name: 'Cannabis', + quantity: 1, + acquiredAt: '2026-10-15T13:50:05.190Z', + value: 20 + } + ], + operator: 'deepStrictEqual' +} + +Node.js v22.13.0 diff --git a/docs/evidence/2026-10-15-inventory-transfer/built-desktop-after-give.png b/docs/evidence/2026-10-15-inventory-transfer/built-desktop-after-give.png new file mode 100644 index 0000000..684750d Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/built-desktop-after-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/built-desktop-after-reload.png b/docs/evidence/2026-10-15-inventory-transfer/built-desktop-after-reload.png new file mode 100644 index 0000000..1f908d6 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/built-desktop-after-reload.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/built-desktop-before-give.png b/docs/evidence/2026-10-15-inventory-transfer/built-desktop-before-give.png new file mode 100644 index 0000000..53f1e37 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/built-desktop-before-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/built-desktop-role-denied.png b/docs/evidence/2026-10-15-inventory-transfer/built-desktop-role-denied.png new file mode 100644 index 0000000..3030360 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/built-desktop-role-denied.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/built-phone-after-give.png b/docs/evidence/2026-10-15-inventory-transfer/built-phone-after-give.png new file mode 100644 index 0000000..8e432ff Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/built-phone-after-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/built-phone-after-reload.png b/docs/evidence/2026-10-15-inventory-transfer/built-phone-after-reload.png new file mode 100644 index 0000000..fcef6a3 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/built-phone-after-reload.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/built-phone-before-give.png b/docs/evidence/2026-10-15-inventory-transfer/built-phone-before-give.png new file mode 100644 index 0000000..9d1acbe Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/built-phone-before-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/built-phone-role-denied.png b/docs/evidence/2026-10-15-inventory-transfer/built-phone-role-denied.png new file mode 100644 index 0000000..668e790 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/built-phone-role-denied.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/built-small-phone-after-give.png b/docs/evidence/2026-10-15-inventory-transfer/built-small-phone-after-give.png new file mode 100644 index 0000000..7d9796f Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/built-small-phone-after-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/built-small-phone-after-reload.png b/docs/evidence/2026-10-15-inventory-transfer/built-small-phone-after-reload.png new file mode 100644 index 0000000..3a41b13 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/built-small-phone-after-reload.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/built-small-phone-before-give.png b/docs/evidence/2026-10-15-inventory-transfer/built-small-phone-before-give.png new file mode 100644 index 0000000..7b8909d Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/built-small-phone-before-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/built-small-phone-role-denied.png b/docs/evidence/2026-10-15-inventory-transfer/built-small-phone-role-denied.png new file mode 100644 index 0000000..c60cf75 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/built-small-phone-role-denied.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/check-trap.mjs b/docs/evidence/2026-10-15-inventory-transfer/check-trap.mjs new file mode 100644 index 0000000..e9600aa --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/check-trap.mjs @@ -0,0 +1,117 @@ +import puppeteer from 'puppeteer-core'; +import fs from 'node:fs/promises'; +import assert from 'node:assert/strict'; + +const mode = process.argv[2] ?? 'fixed'; +const out = process.env.SLIDE_EVIDENCE_DIR ?? new URL('.', import.meta.url).pathname; +const url = process.env.SLIDE_PREVIEW_URL ?? 'http://127.0.0.1:3001'; +const browser = await puppeteer.launch({ executablePath: '/usr/bin/chromium', headless: true, args: ['--no-sandbox'] }); +const results = []; +try { + for (const [name, width, height] of [['phone', 390, 844], ['small-phone', 375, 812], ['desktop', 1440, 900]]) { + const context = await browser.createBrowserContext(); + const page = await context.newPage(); + await page.setViewport({ width, height }); + const pageErrors = []; + const consoleErrors = []; + const failedResources = []; + page.on('pageerror', (error) => pageErrors.push(error.message)); + page.on('console', (message) => { + if (message.type() === 'error') consoleErrors.push(message.text()); + }); + page.on('response', (response) => { + if (response.status() >= 400) failedResources.push({ url: response.url(), status: response.status() }); + }); + await page.goto(url, { waitUntil: 'networkidle0' }); + await page.evaluate(() => [...document.querySelectorAll('button')].find((button) => button.textContent.includes('I AM 18')).click()); + await page.waitForSelector('[aria-label="TRAP"]'); + await page.click('[aria-label="TRAP"]'); + await page.waitForSelector('.trap-item'); + console.log(name + ' live Trap controls: ' + (await page.evaluate(() => document.querySelector('.trap-app').innerText))); + const before = await page.$eval('.trap-item-qty', (element) => Number(element.textContent.replace('x', ''))); + const item = await page.$('.trap-item'); + await item.click(); + const dealer = await page.$('.trap-member-card'); + await dealer.click(); + await page.waitForSelector('.trap-gift-btn', { visible: true }); + await new Promise((resolve) => setTimeout(resolve, 300)); + const reachable = await page.$eval('.trap-gift-btn', (button) => { + const rect = button.getBoundingClientRect(); + return { x: rect.x, y: rect.y, width: rect.width, height: rect.height, + visible: rect.x >= 0 && rect.y >= 0 && rect.right <= innerWidth && rect.bottom <= innerHeight, + hit: document.elementFromPoint(rect.x + rect.width / 2, rect.y + rect.height / 2)?.closest('.trap-gift-btn') === button }; + }); + await page.screenshot({ path: `${out}/${mode}-${name}-before-give.png` }); + await page.click('.trap-gift-btn'); + await new Promise((resolve) => setTimeout(resolve, 300)); + const after = await page.evaluate((initialStock) => { + const stash = JSON.parse(localStorage.getItem('dealt-slide-economy'))?.state.inventory; + return { + stash: stash ? stash.find((item) => item.itemId === 'weed')?.quantity ?? 0 : initialStock, + members: JSON.parse(localStorage.getItem('dealt-slide-gang'))?.state.members ?? [], + notifications: JSON.parse(localStorage.getItem('dealt-slide-notifications'))?.state.notifications ?? [], + }; + }, before); + await page.screenshot({ path: `${out}/${mode}-${name}-after-give.png` }); + if (mode === 'base') { + assert(pageErrors.some((error) => error.includes('require is not defined'))); + assert.equal(after.stash, before); + } else { + assert.equal(after.stash, before - 1); + assert.equal(pageErrors.length, 0); + assert(reachable.visible && reachable.hit); + const recipient = after.members.find((member) => member.id === 'demo-dealer-1'); + assert(recipient.inventory.some((item) => item.itemId === 'weed' && item.quantity === 1)); + assert(after.notifications.some((notification) => notification.title === 'Item Given')); + // Realistic denial through the same visible control: product to a shooter. + await page.click('.trap-item'); + await page.$$eval('.trap-member-card', (cards) => cards.find((card) => card.textContent.includes('Big Rome')).click()); + await page.waitForSelector('.trap-gift-btn', { visible: true }); + await page.click('.trap-gift-btn'); + await new Promise((resolve) => setTimeout(resolve, 300)); + const denied = await page.evaluate(() => { + return { + stash: JSON.parse(localStorage.getItem('dealt-slide-economy')).state.inventory.find((item) => item.itemId === 'weed').quantity, + notifications: JSON.parse(localStorage.getItem('dealt-slide-notifications')).state.notifications, + }; + }); + assert.equal(denied.stash, before - 1); + assert.equal(denied.notifications.filter((notification) => notification.title === 'Item Given').length, 1); + assert(denied.notifications.some((notification) => notification.title === 'Cannot Equip')); + assert.equal(pageErrors.length, 0); + assert(await page.$eval('.trap-gift-panel [role="alert"]', (element) => element.textContent.includes("can't hold drugs"))); + await page.screenshot({ path: `${out}/${mode}-${name}-role-denied.png` }); + await page.reload({ waitUntil: 'networkidle0' }); + await page.waitForSelector('[aria-label="TRAP"]'); + await page.click('[aria-label="TRAP"]'); + await page.waitForSelector('.trap-member-card'); + await new Promise((resolve) => setTimeout(resolve, 450)); + await page.screenshot({ path: `${out}/${mode}-${name}-after-reload.png` }); + const restored = await page.evaluate(() => ({ + stash: JSON.parse(localStorage.getItem('dealt-slide-economy')).state.inventory.find((item) => item.itemId === 'weed').quantity, + carried: JSON.parse(localStorage.getItem('dealt-slide-gang')).state.members.find((member) => member.id === 'demo-dealer-1').inventory, + })); + assert.equal(restored.stash, before - 1); + assert.deepEqual(restored.carried, recipient.inventory); + assert.equal(pageErrors.length, 0); + } + if (mode !== 'base') { + const baselineMissing = ['/favicon.svg', '/assets/game_logo.png', '/assets/generated/ui/icons/icon_news_v001.png']; + assert(failedResources.every((resource) => resource.status === 404 + && baselineMissing.includes(new URL(resource.url).pathname)), JSON.stringify(failedResources)); + assert(consoleErrors.every((error) => error.includes('Failed to load resource:') + && error.includes('404')), consoleErrors.join('\n')); + assert.equal(consoleErrors.length, failedResources.length); + } + results.push({ name, viewport: { width, height }, mode, url, before, after: after.stash, + scope: 'inventory player path; not a clean-console or launch approval', + giveControl: reachable, pageErrors, consoleErrors, failedResources, checks: mode === 'base' ? ['runtime bug reproduced'] + : ['real Trap give', 'stock deducted once', 'carried item persisted', 'role denial has no success', + 'inline rejection visible', 'real reload retains exact carried record and stock'], pass: true }); + await context.close(); + } + await fs.writeFile(`${out}/browser-${mode}.json`, JSON.stringify(results, null, 2) + '\n'); + console.log(JSON.stringify(results, null, 2)); +} finally { + await browser.close(); +} diff --git a/docs/evidence/2026-10-15-inventory-transfer/demo-reseed-red.log b/docs/evidence/2026-10-15-inventory-transfer/demo-reseed-red.log new file mode 100644 index 0000000..a51b01a --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/demo-reseed-red.log @@ -0,0 +1,75 @@ + +> dealt-slide-mvp@1.0.0 test +> vitest run src/utils/__tests__/demoSeedInventory.test.ts + + + RUN v2.1.9 /home/ubuntu/projects/slide/frontend + + ❯ src/utils/__tests__/demoSeedInventory.test.ts (4 tests | 2 failed) 25ms + × demo carried inventory continuity > keeps a real transferred item across two reseeds without restoring consumed stock or duplicating contacts 16ms + → expected undefined to deeply equal [ { …(9) } ] + × demo carried inventory continuity > keeps persisted carried metadata through hydration followed by the actual demo-startup reseed 5ms + → expected undefined to match object { itemId: 'river-cut', …(4) } + +⎯⎯⎯⎯⎯⎯⎯ Failed Tests 2 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL src/utils/__tests__/demoSeedInventory.test.ts > demo carried inventory continuity > keeps a real transferred item across two reseeds without restoring consumed stock or duplicating contacts +AssertionError: expected undefined to deeply equal [ { …(9) } ] + +- Expected: +Array [ + Object { + "acquiredAt": "2026-10-15T13:49:34.385Z", + "id": "98559b11-8ba0-493e-ae30-4a3b47a5358a", + "itemId": "river-cut", + "name": "River Cut", + "odRisk": 12, + "quality": 72, + "quantity": 1, + "tier": 2, + "type": "drug", + }, +] + ++ Received: +undefined + + ❯ src/utils/__tests__/demoSeedInventory.test.ts:21:87 + 19| applyDemoSeed(); + 20| applyDemoSeed(); + 21| expect(useGangStore.getState().getMemberById(BLOCK_LOOP_IDS.dealer… + | ^ + 22| expect(useGangStore.getState().getMemberById(BLOCK_LOOP_IDS.dealer… + 23| expect(useEconomyStore.getState().inventory[0].quantity).toBe(2); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/2]⎯ + + FAIL src/utils/__tests__/demoSeedInventory.test.ts > demo carried inventory continuity > keeps persisted carried metadata through hydration followed by the actual demo-startup reseed +AssertionError: expected undefined to match object { itemId: 'river-cut', …(4) } + +- Expected: +Object { + "itemId": "river-cut", + "odRisk": 12, + "quality": 72, + "quantity": 1, + "tier": 2, +} + ++ Received: +undefined + + ❯ src/utils/__tests__/demoSeedInventory.test.ts:34:92 + 32| await useGangStore.persist.rehydrate(); + 33| applyDemoSeed(); + 34| expect(useGangStore.getState().getMemberById(BLOCK_LOOP_IDS.dealer… + | ^ + 35| itemId: 'river-cut', quantity: 1, quality: 72, tier: 2, odRisk: … + 36| }); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/2]⎯ + + Test Files 1 failed (1) + Tests 2 failed | 2 passed (4) + Start at 13:49:31 + Duration 2.85s (transform 562ms, setup 186ms, collect 842ms, tests 25ms, environment 1.12s, prepare 117ms) diff --git a/docs/evidence/2026-10-15-inventory-transfer/fixed-desktop-after-give.png b/docs/evidence/2026-10-15-inventory-transfer/fixed-desktop-after-give.png new file mode 100644 index 0000000..684750d Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/fixed-desktop-after-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/fixed-desktop-after-reload.png b/docs/evidence/2026-10-15-inventory-transfer/fixed-desktop-after-reload.png new file mode 100644 index 0000000..1cda7e7 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/fixed-desktop-after-reload.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/fixed-desktop-before-give.png b/docs/evidence/2026-10-15-inventory-transfer/fixed-desktop-before-give.png new file mode 100644 index 0000000..caa07cc Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/fixed-desktop-before-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/fixed-desktop-role-denied.png b/docs/evidence/2026-10-15-inventory-transfer/fixed-desktop-role-denied.png new file mode 100644 index 0000000..3030360 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/fixed-desktop-role-denied.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/fixed-phone-after-give.png b/docs/evidence/2026-10-15-inventory-transfer/fixed-phone-after-give.png new file mode 100644 index 0000000..8e432ff Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/fixed-phone-after-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/fixed-phone-after-reload.png b/docs/evidence/2026-10-15-inventory-transfer/fixed-phone-after-reload.png new file mode 100644 index 0000000..13fb620 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/fixed-phone-after-reload.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/fixed-phone-before-give.png b/docs/evidence/2026-10-15-inventory-transfer/fixed-phone-before-give.png new file mode 100644 index 0000000..9d1acbe Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/fixed-phone-before-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/fixed-phone-role-denied.png b/docs/evidence/2026-10-15-inventory-transfer/fixed-phone-role-denied.png new file mode 100644 index 0000000..668e790 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/fixed-phone-role-denied.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/fixed-small-phone-after-give.png b/docs/evidence/2026-10-15-inventory-transfer/fixed-small-phone-after-give.png new file mode 100644 index 0000000..7d9796f Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/fixed-small-phone-after-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/fixed-small-phone-after-reload.png b/docs/evidence/2026-10-15-inventory-transfer/fixed-small-phone-after-reload.png new file mode 100644 index 0000000..7f7d899 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/fixed-small-phone-after-reload.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/fixed-small-phone-before-give.png b/docs/evidence/2026-10-15-inventory-transfer/fixed-small-phone-before-give.png new file mode 100644 index 0000000..7b8909d Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/fixed-small-phone-before-give.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/fixed-small-phone-role-denied.png b/docs/evidence/2026-10-15-inventory-transfer/fixed-small-phone-role-denied.png new file mode 100644 index 0000000..c60cf75 Binary files /dev/null and b/docs/evidence/2026-10-15-inventory-transfer/fixed-small-phone-role-denied.png differ diff --git a/docs/evidence/2026-10-15-inventory-transfer/focused-green.log b/docs/evidence/2026-10-15-inventory-transfer/focused-green.log new file mode 100644 index 0000000..543e497 --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/focused-green.log @@ -0,0 +1,19 @@ + +> dealt-slide-mvp@1.0.0 test +> vitest run src/stores/__tests__/inventoryTransfer.test.ts src/components/trap/__tests__/TrapApp.transfer.test.tsx src/utils/__tests__/demoSeedInventory.test.ts src/utils/__tests__/demoSeedContacts.test.ts src/utils/__tests__/demoSeedBooks.test.ts src/utils/__tests__/demoSeedProgress.test.ts + + + RUN v2.1.9 /home/ubuntu/projects/slide/frontend + + ✓ src/stores/__tests__/inventoryTransfer.test.ts (19 tests) 19ms + ✓ src/utils/__tests__/demoSeedContacts.test.ts (2 tests) 15ms + ✓ src/utils/__tests__/demoSeedInventory.test.ts (4 tests) 19ms + ✓ src/utils/__tests__/demoSeedBooks.test.ts (2 tests) 12ms + ✓ src/components/trap/__tests__/TrapApp.transfer.test.tsx (6 tests) 653ms + ✓ THE TRAP transfer confirmation > gives the selected product, retains its stats, and reports actual success 339ms + ✓ src/utils/__tests__/demoSeedProgress.test.ts (2 tests) 11ms + + Test Files 6 passed (6) + Tests 35 passed (35) + Start at 13:50:28 + Duration 4.00s (transform 1.11s, setup 761ms, collect 4.62s, tests 728ms, environment 6.42s, prepare 547ms) diff --git a/docs/evidence/2026-10-15-inventory-transfer/full-preflight.log b/docs/evidence/2026-10-15-inventory-transfer/full-preflight.log new file mode 100644 index 0000000..61838c1 --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/full-preflight.log @@ -0,0 +1,1461 @@ + +== Diff hygiene (origin/main-tL2525...HEAD) == + +== Changed paths == + +== Focused regression == + + RUN v2.1.9 /home/ubuntu/projects/slide/frontend + + ✓ src/stores/__tests__/inventoryTransfer.test.ts (19 tests) 18ms + + Test Files 1 passed (1) + Tests 19 passed (19) + Start at 13:51:15 + Duration 2.01s (transform 159ms, setup 147ms, collect 211ms, tests 18ms, environment 960ms, prepare 92ms) + + +== Full validation == + +> dealt-slide-mvp@1.0.0 validate +> npm run lint && npm run typecheck && npm test && npm run assets:audit && npm run assets:packages + + +> dealt-slide-mvp@1.0.0 lint +> eslint "src/**/*.{ts,tsx}" --report-unused-disable-directives + + +/home/ubuntu/projects/slide/frontend/src/__tests__/economy-pillar1.test.ts + 7:32 warning 'beforeEach' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/__tests__/idempotency.test.ts + 7:32 warning 'beforeEach' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/__tests__/lasOlasReliability.test.tsx + 10:10 warning 'useDrugInventory' is defined but never used @typescript-eslint/no-unused-vars + 11:10 warning 'useBlockLoopStore' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/alchemy/AlchemyLab.tsx + 11:15 warning 'BaseElement' is defined but never used @typescript-eslint/no-unused-vars + 11:28 warning 'CraftedDrug' is defined but never used @typescript-eslint/no-unused-vars + 11:41 warning 'AlchemyRecipe' is defined but never used @typescript-eslint/no-unused-vars + 102:11 warning 'player' is assigned a value but never used @typescript-eslint/no-unused-vars + 102:19 warning 'updateMoney' is assigned a value but never used @typescript-eslint/no-unused-vars + 277:6 warning React Hook useCallback has missing dependencies: 'addInventoryItem' and 'addNotification'. Either include them or remove the dependency array react-hooks/exhaustive-deps + 285:9 warning 'discoveredRecipes' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/block/DrugAssignmentPanel.tsx + 347:54 warning React Hook useMemo has an unnecessary dependency: 'inventory'. Either exclude it or remove the dependency array react-hooks/exhaustive-deps + 351:62 warning React Hook useMemo has unnecessary dependencies: 'assignments' and 'inventory'. Either exclude them or remove the dependency array react-hooks/exhaustive-deps + 352:58 warning React Hook useMemo has unnecessary dependencies: 'assignments' and 'inventory'. Either exclude them or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/casino/Casino.tsx + 5:18 warning 'AnimatePresence' is defined but never used @typescript-eslint/no-unused-vars + 315:6 warning React Hook useCallback has missing dependencies: 'PAYOUTS' and 'SYMBOLS'. Either include them or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/cocaine-crush/CocaineCrush.tsx + 30:11 warning 'player' is assigned a value but never used @typescript-eslint/no-unused-vars + 66:9 warning 'availableDrugs' is assigned a value but never used @typescript-eslint/no-unused-vars + 260:17 warning 'validatedMatches' is assigned a value but never used @typescript-eslint/no-unused-vars + 320:6 warning React Hook useCallback has a missing dependency: 'commitSession'. Either include it or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/common/GameSprite.tsx + 22:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 29:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 36:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 41:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 45:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 49:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 56:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 66:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 70:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 74:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 79:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 122:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 130:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 142:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 152:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 281:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 288:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 296:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 304:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + +/home/ubuntu/projects/slide/frontend/src/components/compliance/AgeGate.tsx + 11:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 16:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 25:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 29:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + +/home/ubuntu/projects/slide/frontend/src/components/contacts/ContactProfile.tsx + 11:3 warning 'useEconomyStore' is defined but never used @typescript-eslint/no-unused-vars + 231:9 warning 'equippedClothing' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/contacts/Contacts.tsx + 20:100 warning 'calculateHospitalImpact' is defined but never used @typescript-eslint/no-unused-vars + 22:36 warning 'MemberStatus' is defined but never used @typescript-eslint/no-unused-vars + 37:57 warning 'killMember' is assigned a value but never used @typescript-eslint/no-unused-vars + 39:11 warning 'uploads' is assigned a value but never used @typescript-eslint/no-unused-vars + 285:42 warning 'memberId' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + 527:30 warning 'memberId' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + 659:9 warning 'bailCost' is assigned a value but never used @typescript-eslint/no-unused-vars + 724:7 warning 'RANK_TITLES' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/contacts/LevelUpPopup.tsx + 27:7 warning 'RANK_TITLES' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/contacts/RoleContactCard.tsx + 40:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 99:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 104:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + +/home/ubuntu/projects/slide/frontend/src/components/dealt-v2/DealtSpeed.tsx + 8:51 warning 'useMemo' is defined but never used @typescript-eslint/no-unused-vars + 10:46 warning 'useEconomyStore' is defined but never used @typescript-eslint/no-unused-vars + 61:7 warning 'UNIT_CONVERSIONS' is assigned a value but never used @typescript-eslint/no-unused-vars + 67:7 warning 'UNIT_LABELS' is assigned a value but never used @typescript-eslint/no-unused-vars + 143:11 warning 'player' is assigned a value but never used @typescript-eslint/no-unused-vars + 161:6 warning React Hook useEffect has a missing dependency: 'nextDeal'. Either include it or remove the dependency array react-hooks/exhaustive-deps + 181:6 warning React Hook useEffect has a missing dependency: 'handleTimeout'. Either include it or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/dealt-v2/DealtSymptoms.tsx + 8:51 warning 'useMemo' is defined but never used @typescript-eslint/no-unused-vars + 10:61 warning 'useEconomyStore' is defined but never used @typescript-eslint/no-unused-vars + 71:46 warning 'level' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + 116:11 warning 'streak' is assigned a value but never used @typescript-eslint/no-unused-vars + 116:19 warning 'completeDeal' is assigned a value but never used @typescript-eslint/no-unused-vars + 131:6 warning React Hook useEffect has a missing dependency: 'nextClient'. Either include it or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/dealt/DealtMode.tsx + 40:6 warning React Hook useEffect has missing dependencies: 'currentClient', 'currentOutcome', and 'generateNewClient'. Either include them or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/driveby/DriveByEngine.tsx + 422:6 warning React Hook useCallback has a missing dependency: 'playSound'. Either include it or remove the dependency array react-hooks/exhaustive-deps + 922:6 warning React Hook useEffect has missing dependencies: 'render' and 'targets.length'. Either include them or remove the dependency array react-hooks/exhaustive-deps + 926:11 warning 'block' is assigned a value but never used @typescript-eslint/no-unused-vars + 1165:6 warning React Hook useCallback has unnecessary dependencies: 'ammo', 'carHealth', 'heat', and 'score'. Either exclude them or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/economy/MarketMembers.tsx + 147:6 warning React Hook useCallback has a missing dependency: 'maxMembers'. Either include it or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/gang/GangMemberCard.tsx + 8:3 warning 'Heart' is defined but never used @typescript-eslint/no-unused-vars + 9:3 warning 'Target' is defined but never used @typescript-eslint/no-unused-vars + 10:3 warning 'Brain' is defined but never used @typescript-eslint/no-unused-vars + 11:3 warning 'Zap' is defined but never used @typescript-eslint/no-unused-vars + 12:3 warning 'Shield' is defined but never used @typescript-eslint/no-unused-vars + 13:3 warning 'Star' is defined but never used @typescript-eslint/no-unused-vars + 14:3 warning 'ChevronRight' is defined but never used @typescript-eslint/no-unused-vars + 15:3 warning 'Skull' is defined but never used @typescript-eslint/no-unused-vars + 16:3 warning 'AlertTriangle' is defined but never used @typescript-eslint/no-unused-vars + 17:3 warning 'Clock' is defined but never used @typescript-eslint/no-unused-vars + 18:3 warning 'TrendingUp' is defined but never used @typescript-eslint/no-unused-vars + 19:3 warning 'Award' is defined but never used @typescript-eslint/no-unused-vars + 20:3 warning 'Crosshair' is defined but never used @typescript-eslint/no-unused-vars + 22:3 warning 'MoreVertical' is defined but never used @typescript-eslint/no-unused-vars + 25:3 warning 'Flame' is defined but never used @typescript-eslint/no-unused-vars + 27:40 warning 'CityRegion' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/gang/MemberCreation.tsx + 72:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + +/home/ubuntu/projects/slide/frontend/src/components/graffiti/GraffitiGame.tsx + 7:46 warning 'useCallback' is defined but never used @typescript-eslint/no-unused-vars + 9:81 warning 'generateAllGraffitiOptions' is defined but never used @typescript-eslint/no-unused-vars + 10:50 warning 'GraffitiMember' is defined but never used @typescript-eslint/no-unused-vars + 10:66 warning 'GangProfile' is defined but never used @typescript-eslint/no-unused-vars + 318:6 warning React Hook useEffect has a missing dependency: 'checkForEncounters'. Either include it or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/layout/OSShell.tsx + 52:61 warning 'incomePerMinute' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/layout/RaidEventOverlay.tsx + 46:10 warning '_showBail' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/map/BlockModeView.tsx + 220:6 warning React Hook useCallback has an unnecessary dependency: 'player.bankBalance'. Either exclude it or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/map/BlockOverlay.tsx + 34:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + 46:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + +/home/ubuntu/projects/slide/frontend/src/components/map/ClaimBlockModal.tsx + 19:58 warning 'reset' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/map/DrugAssignmentPanel.tsx + 96:61 warning React Hook useMemo has a missing dependency: 'drugStore'. Either include it or remove the dependency array react-hooks/exhaustive-deps + 110:6 warning React Hook useMemo has a missing dependency: 'drugStore'. Either include it or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/map/NPCPanel.tsx + 15:8 warning 'NPCMember' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/map/PlayableMap.tsx + 198:6 warning React Hook useEffect has missing dependencies: 'center', 'mode', and 'zoom'. Either include them or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/map/TacticalPlacementOverlay.tsx + 38:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + +/home/ubuntu/projects/slide/frontend/src/components/map/__tests__/DrugAssignmentPanel.test.ts + 7:32 warning 'beforeEach' is defined but never used @typescript-eslint/no-unused-vars + 7:44 warning 'vi' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/missions/Missions.tsx + 44:6 warning React Hook useEffect has a missing dependency: 'missions.length'. Either include it or remove the dependency array react-hooks/exhaustive-deps + 61:6 warning React Hook useEffect has a missing dependency: 'handleMissionComplete'. Either include it or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/onboarding/Onboarding.tsx + 41:11 warning 'player' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/settings/SettingsPage.tsx + 10:3 warning 'useEconomyStore' is defined but never used @typescript-eslint/no-unused-vars + 11:3 warning 'useDealtStore' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/slide/BlockDriveByEngine.tsx + 149:5 warning React Hook useCallback has a missing dependency: 'resolveEvent'. Either include it or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/slide/CanvasStreetRenderer.tsx + 5:3 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + +/home/ubuntu/projects/slide/frontend/src/components/slide/CanvasStreetRendererV3.tsx + 17:8 warning 'ImpactSurfaceKind' is defined but never used @typescript-eslint/no-unused-vars + 133:7 warning 'MEMBER_RENDER_HEIGHT' is assigned a value but never used @typescript-eslint/no-unused-vars + 236:10 warning 'memberRenderPoint' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/slide/FPSOverlay.tsx + 288:14 warning The ref value 'gunRef.current' will likely have changed by the time this effect cleanup function runs. If this ref points to a node rendered by React, copy 'gunRef.current' to a variable inside the effect, and use that variable in the cleanup function react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/slide/SlideGame.tsx + 15:10 warning 'soundManager' is defined but never used @typescript-eslint/no-unused-vars + 32:8 warning 'SlidePhase' is defined but never used @typescript-eslint/no-unused-vars + 123:11 warning 'player' is assigned a value but never used @typescript-eslint/no-unused-vars + 124:11 warning 'members' is assigned a value but never used @typescript-eslint/no-unused-vars + 408:9 warning 'newDefenders' is never reassigned. Use 'const' instead prefer-const + +/home/ubuntu/projects/slide/frontend/src/components/slide/SlidePhaser3Scene.ts + 38:3 warning 'GRID_WIDTH' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.tsx + 29:14 warning Fast refresh only works when a file only exports components. Move your React context(s) to a separate file react-refresh/only-export-components + 60:17 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components + +/home/ubuntu/projects/slide/frontend/src/components/topdown/BipNDipGame.tsx + 136:6 warning React Hook useEffect has a missing dependency: 'session.footChase'. Either include it or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/topdown/PhaserTopDownBlock.tsx + 110:6 warning React Hook useEffect has a missing dependency: 'block'. Either include it or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/topdown/PoliceRaidGame.tsx + 97:6 warning React Hook useEffect has a missing dependency: 'raidState'. Either include it or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/components/topdown/TopDownShooter.tsx + 9:40 warning 'useEffect' is defined but never used @typescript-eslint/no-unused-vars + 9:51 warning 'useRef' is defined but never used @typescript-eslint/no-unused-vars + 15:3 warning 'useEconomyStore' is defined but never used @typescript-eslint/no-unused-vars + 18:15 warning 'GangMember' is defined but never used @typescript-eslint/no-unused-vars + 18:27 warning 'InventoryItem' is defined but never used @typescript-eslint/no-unused-vars + 119:7 warning 'RELOAD_COST' is assigned a value but never used @typescript-eslint/no-unused-vars + 183:43 warning 'gangColor' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + 248:11 warning 'player' is assigned a value but never used @typescript-eslint/no-unused-vars + 249:32 warning 'updateMember' is assigned a value but never used @typescript-eslint/no-unused-vars + 250:11 warning 'addNotification' is assigned a value but never used @typescript-eslint/no-unused-vars + 277:10 warning 'showCommandPanel' is assigned a value but never used @typescript-eslint/no-unused-vars + 277:28 warning 'setShowCommandPanel' is assigned a value but never used @typescript-eslint/no-unused-vars + 288:9 warning 'assignedMembers' is assigned a value but never used @typescript-eslint/no-unused-vars + 584:6 warning React Hook useCallback has an unnecessary dependency: 'defenders'. Either exclude it or remove the dependency array react-hooks/exhaustive-deps + 658:6 warning React Hook useCallback has a missing dependency: 'endCombat'. Either include it or remove the dependency array react-hooks/exhaustive-deps + 663:6 warning React Hook useCallback has a missing dependency: 'endCombat'. Either include it or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/hooks/useApi.ts + 83:5 warning React Hook useCallback has a missing dependency: 'options'. Either include it or remove the dependency array react-hooks/exhaustive-deps + 95:6 warning React Hook useEffect has missing dependencies: 'execute', 'method', and 'options.immediate'. Either include them or remove the dependency array react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/hooks/useBlockClaim.ts + 124:41 warning 'gangName' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + 210:29 warning 'userId' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/hooks/useBlockSatellite.ts + 114:20 warning The ref value 'requestIdRef.current' will likely have changed by the time this effect cleanup function runs. If this ref points to a node rendered by React, copy 'requestIdRef.current' to a variable inside the effect, and use that variable in the cleanup function react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/hooks/useBlockSync.ts + 131:36 warning The ref value 'debounceTimers.current' will likely have changed by the time this effect cleanup function runs. If this ref points to a node rendered by React, copy 'debounceTimers.current' to a variable inside the effect, and use that variable in the cleanup function react-hooks/exhaustive-deps + +/home/ubuntu/projects/slide/frontend/src/services/apiClient.ts + 247:39 warning 'newToken' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/services/combatService.ts + 12:3 warning 'Vehicle' is defined but never used @typescript-eslint/no-unused-vars + 15:3 warning 'UNIT_STATS' is defined but never used @typescript-eslint/no-unused-vars + 16:3 warning 'VEHICLE_STATS' is defined but never used @typescript-eslint/no-unused-vars + 19:3 warning 'isPositionValid' is defined but never used @typescript-eslint/no-unused-vars + 21:3 warning 'isAdjacent' is defined but never used @typescript-eslint/no-unused-vars + 262:38 warning 'defender' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + 266:41 warning 'defender' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/services/location.service.ts + 10:3 warning 'buildBlockBounds' is defined but never used @typescript-eslint/no-unused-vars + 12:3 warning 'isInServiceArea' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/services/supabase.ts + 799:26 warning 'region' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/stores/authStore.ts + 98:25 warning 'authData' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/stores/blockStore.ts + 15:3 warning 'DriveByEvent' is defined but never used @typescript-eslint/no-unused-vars + 587:32 warning '_removed' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/stores/combatStore.ts + 12:3 warning 'CombatOutcome' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + 15:3 warning 'CombatSession' is defined but never used @typescript-eslint/no-unused-vars + 16:3 warning 'Drug' is defined but never used @typescript-eslint/no-unused-vars + 17:3 warning 'Recipe' is defined but never used @typescript-eslint/no-unused-vars + 21:3 warning 'Mission' is defined but never used @typescript-eslint/no-unused-vars + 45:11 warning 'get' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + 404:13 warning 'get' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/stores/npcStore.ts + 289:13 warning 'get' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/utils/ImpactEngine.ts + 377:11 warning 'life' is never reassigned. Use 'const' instead prefer-const + +/home/ubuntu/projects/slide/frontend/src/utils/PerformanceManager.ts + 399:11 warning 'clampedDelta' is assigned a value but never used @typescript-eslint/no-unused-vars + 492:32 warning 'priority' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/utils/__tests__/bailHospitalSystem.test.ts + 24:8 warning 'RecoveryKind' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/utils/alchemyEngine.ts + 8:3 warning 'CraftedDrug' is defined but never used @typescript-eslint/no-unused-vars + 10:3 warning 'CraftingSession' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/utils/combatResolver.ts + 12:3 warning 'CombatEventResult' is defined but never used @typescript-eslint/no-unused-vars + 286:44 warning 'attacker' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + 347:31 warning 'route' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/utils/dealtEngine.ts + 387:9 warning Unexpected lexical declaration in case block no-case-declarations + +/home/ubuntu/projects/slide/frontend/src/utils/gameLoopEngine.ts + 16:3 warning 'HEAT_CONFIG' is defined but never used @typescript-eslint/no-unused-vars + 25:62 warning 'ODEvent' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/utils/graffitiEngine.ts + 91:53 warning 'secondary' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/utils/gridFactory.ts + 12:3 warning 'MicroCoord' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/utils/gridGenerator.ts + 19:3 warning 'TileGenerationContext' is defined but never used @typescript-eslint/no-unused-vars + 24:10 warning 'getCityConfig' is defined but never used @typescript-eslint/no-unused-vars + 325:13 warning 'gridHeight' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/utils/moraleSystem.ts + 92:3 warning 'rng' is assigned a value but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/utils/turnLogic.ts + 1:33 warning 'macroToMicroRegion' is defined but never used @typescript-eslint/no-unused-vars + 29:3 warning 'rng' is defined but never used. Allowed unused args must match /^_/u @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/utils/vehicleEngine.ts + 15:3 warning 'VEHICLE_SEAT_CONFIGS' is defined but never used @typescript-eslint/no-unused-vars + 18:8 warning 'VehicleSeatConfig' is defined but never used @typescript-eslint/no-unused-vars + +/home/ubuntu/projects/slide/frontend/src/utils/weaponSystem.ts + 12:8 warning 'ShooterTier' is defined but never used @typescript-eslint/no-unused-vars + +✖ 200 problems (0 errors, 200 warnings) + 0 errors and 2 warnings potentially fixable with the `--fix` option. + + +> dealt-slide-mvp@1.0.0 typecheck +> tsc --noEmit + + +> dealt-slide-mvp@1.0.0 test +> vitest run + + + RUN v2.1.9 /home/ubuntu/projects/slide/frontend + + ✓ src/utils/__tests__/blockMappers.test.ts (16 tests) 33ms + ✓ src/__tests__/idempotency.test.ts (18 tests) 24ms + ✓ src/__tests__/lasOlasReliability.test.tsx (30 tests | 4 skipped) 30ms +stderr | src/components/driveby/__tests__/carCrewTarget.test.tsx > CarCrewSelector → street handoff (#108) > hands a geocoded AddressResult through CarCrew and into a coordinate-seeded scene +Not implemented: Window's scrollTo() method +Not implemented: Window's scrollTo() method + + ✓ src/stores/blockStore.encounter.test.ts (20 tests) 1329ms +stderr | src/components/driveby/__tests__/carCrewTarget.test.tsx > CarCrewSelector → street handoff (#108) > pre-fills a target locked from the Maps recon pin +Not implemented: Window's scrollTo() method +Not implemented: Window's scrollTo() method + + ✓ src/stores/__tests__/mostWantedStore.test.ts (48 tests) 31ms +stderr | src/components/driveby/__tests__/carCrewTarget.test.tsx > CarCrewSelector → street handoff (#108) > labels the offline text fallback and hands a text-seed target when no geocoder result is chosen +Not implemented: Window's scrollTo() method +Not implemented: Window's scrollTo() method + +stderr | src/components/driveby/__tests__/carCrewTarget.test.tsx > CarCrewSelector → street handoff (#108) > two coordinate-distinct autocomplete picks produce distinct scenes +Not implemented: Window's scrollTo() method +Not implemented: Window's scrollTo() method + + ✓ src/utils/__tests__/ghostCrewEngine.test.ts (29 tests) 29ms + ✓ src/components/raid/__tests__/policeRaid.test.ts (42 tests) 23ms +stderr | src/components/driveby/__tests__/carCrewTarget.test.tsx > CarCrewSelector → street handoff (#108) > two coordinate-distinct autocomplete picks produce distinct scenes +Not implemented: Window's scrollTo() method +Not implemented: Window's scrollTo() method + + ✓ src/utils/__tests__/policeRaidEngine.test.ts (46 tests) 22ms + ✓ src/game/loop/__tests__/blockLoop.test.ts (18 tests) 25ms + ✓ src/utils/__tests__/bailHospitalSystem.test.ts (59 tests) 29ms + ✓ src/stores/__tests__/getBackStore.test.ts (43 tests) 27ms +stderr | src/components/driveby/__tests__/carCrewTarget.test.tsx > CarCrewSelector → street handoff (#108) > offers dealer, recruit, shooter and driver as drivers, but only shooters as passengers +Not implemented: Window's scrollTo() method + +stderr | src/components/driveby/__tests__/carCrewTarget.test.tsx > CarCrewSelector → street handoff (#108) > lets a shooter drive without counting them as the passenger shooter +Not implemented: Window's scrollTo() method +Not implemented: Window's scrollTo() method + +stderr | src/components/driveby/__tests__/carCrewTarget.test.tsx > CarCrewSelector → street handoff (#108) > refuses a now-injured or changed-role passenger before launch +Not implemented: Window's scrollTo() method +Not implemented: Window's scrollTo() method + +stderr | src/components/driveby/__tests__/carCrewTarget.test.tsx > CarCrewSelector → street handoff (#108) > shows the member portrait first, and labels role art when identity is missing +Not implemented: Window's scrollTo() method +Not implemented: Window's scrollTo() method + +stderr | src/components/driveby/__tests__/carCrewTarget.test.tsx > CarCrewSelector → street handoff (#108) > visibly labels role art when a stored personal portrait fails to load +Not implemented: Window's scrollTo() method + +stderr | src/components/driveby/__tests__/carCrewTarget.test.tsx > CarCrewSelector → street handoff (#108) > shows actual carried inventory and core member stats without inventing a weapon or cash +Not implemented: Window's scrollTo() method + +stderr | src/components/driveby/__tests__/carCrewTarget.test.tsx > CarCrewSelector → street handoff (#108) > does not invent full health or gear when the roster has no health record +Not implemented: Window's scrollTo() method + + ✓ src/components/driveby/__tests__/carCrewTarget.test.tsx (12 tests) 3251ms + ✓ CarCrewSelector → street handoff (#108) > hands a geocoded AddressResult through CarCrew and into a coordinate-seeded scene 1017ms + ✓ CarCrewSelector → street handoff (#108) > two coordinate-distinct autocomplete picks produce distinct scenes 1408ms + ✓ src/stores/__tests__/ghostCrewStore.test.ts (11 tests) 51ms + ✓ src/render/__tests__/projection.test.ts (40 tests) 35ms + ✓ src/stores/__tests__/rivalStripDefense.test.ts (11 tests) 39ms + ✓ src/utils/__tests__/marketMembersCatalog.test.ts (44 tests) 50ms + ✓ src/utils/__tests__/blockDNAResolver.test.ts (16 tests) 27ms + ✓ src/components/topdown/__tests__/bipNDipGame.test.ts (27 tests) 46ms + ✓ src/utils/__tests__/blockDNALegacyContract.test.ts (20 tests) 36ms + ✓ src/render/__tests__/dioramaAdapter.test.ts (9 tests) 43ms + ✓ src/game/combat/__tests__/combatSession.test.ts (11 tests) 23ms + ✓ src/render/__tests__/worldActorResolver.test.ts (25 tests) 20ms + ✓ src/__tests__/economy-pillar1.test.ts (14 tests) 13ms + ✓ src/stores/__tests__/blockLoopShiftStore.test.tsx (9 tests) 649ms + ✓ Strip shifts through the shared stores > offers the next shift from the desk once the recovery is decided 416ms + ✓ src/game/loop/__tests__/blockLoopShifts.test.ts (9 tests) 72ms + ✓ src/stores/__tests__/inventoryTransfer.test.ts (19 tests) 19ms + ✓ src/utils/__tests__/blockDNAReloadIdentity.test.ts (7 tests) 38ms + ✓ src/game/combat/__tests__/CombatSessionController.test.ts (8 tests) 12ms + ✓ src/components/gang/__tests__/PhotoMemberCreator.test.tsx (5 tests) 1150ms + ✓ PhotoMemberCreator > identifies stock offline previews without claiming the photo was generated 483ms + ✓ src/render/__tests__/proceduralDriveBy.test.ts (16 tests) 41ms + ✓ src/stores/__tests__/npcStore.test.ts (14 tests) 17ms + ✓ src/game/combat/__tests__/aimedFire.test.ts (5 tests) 12ms + ✓ src/__tests__/betaGate.smoke.test.ts (12 tests) 270ms + ✓ src/hooks/__tests__/useBlockSync.test.tsx (5 tests) 263ms + ✓ src/config/__tests__/blockDNA.test.ts (23 tests) 73ms + ✓ src/utils/__tests__/memberXpWiring.test.ts (18 tests) 11ms + ✓ src/components/tutorial/TutorialOverlay.test.tsx (4 tests) 404ms + ✓ TutorialOverlay > lets an enabled Launch Attack tap pass through the phone hint 310ms + ✓ src/components/layout/BlockLoopDesk.test.tsx (8 tests) 1286ms + ✓ BlockLoopDesk > rejects a street cell and places a curb dealer with a visible income/exposure split 400ms + ✓ BlockLoopDesk > runs a deal receipt then books a deterministic wound 525ms + ✓ src/stores/__tests__/blockLoopStore.test.ts (5 tests) 39ms + ✓ src/utils/__tests__/shoeboxAnalytics.test.ts (6 tests) 37ms + ✓ src/components/gang/__tests__/MemberProgressPanel.test.ts (18 tests) 11ms + ✓ src/components/map/PlayableMap.test.tsx (6 tests) 355ms + ✓ src/components/trap/__tests__/TrapApp.transfer.test.tsx (6 tests) 655ms + ✓ THE TRAP transfer confirmation > gives the selected product, retains its stats, and reports actual success 364ms + ✓ src/components/slide/__tests__/v3Projection.test.ts (16 tests) 7ms + ✓ src/components/topdown/__tests__/blockTopDownCoords.test.ts (18 tests) 19ms + ✓ src/components/graffiti/__tests__/graffitiWiring.test.ts (14 tests) 26ms +stderr | src/__tests__/betaOnePath.test.tsx > Las Olas closed-beta one path > walks the seeded Las Olas desk from lock through deal, wound, and reload-safe books +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) +Warning: An update to BlockLoopDesk inside a test was not wrapped in act(...). + +When testing, code that causes React state updates should be wrapped into act(...): + +act(() => { + /* fire events that update state */ +}); +/* assert on the output */ + +This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) + + ✓ src/__tests__/betaOnePath.test.tsx (4 tests) 1384ms + ✓ Las Olas closed-beta one path > does not treat a missing local acknowledgement as 18+ just because this is a demo build 429ms + ✓ Las Olas closed-beta one path > walks the seeded Las Olas desk from lock through deal, wound, and reload-safe books 749ms + ✓ src/game/assets/__tests__/assetPackages.test.ts (4 tests) 6ms + ✓ src/services/worldPersistence.service.test.ts (6 tests) 8ms + ✓ src/components/map/__tests__/DrugAssignmentPanel.test.ts (11 tests) 8ms + ✓ src/components/map/GhostThreatBanner.test.tsx (5 tests) 573ms + ✓ GhostThreatBanner > routes an open Strip attack to the Strip 388ms + ✓ src/game/combat/__tests__/portableContracts.test.ts (3 tests) 8ms + ✓ src/components/layout/CityBriefing.test.tsx (6 tests) 252ms + ✓ src/utils/__tests__/driveByTarget.test.ts (11 tests) 14ms + ✓ src/components/map/TacticalDiorama.test.tsx (4 tests) 816ms + ✓ TacticalDiorama player path > renders the Las Olas street plate with cover, street, crew, objective, and extraction 304ms + ✓ src/components/cocaine-crush/__tests__/cocaineCrush.test.ts (11 tests) 11ms +stderr | src/services/blockPersistence.service.test.ts > blockPersistence.service authoritative projection > does not fall through to an unguarded upsert when the server rejects a stale projection +[BlockPersistence] Skipped stale block projection after a newer encounter result. + + ✓ src/services/blockPersistence.service.test.ts (4 tests) 14ms + ✓ src/components/slide/__tests__/phaserBridge.test.ts (21 tests) 12ms + ✓ src/components/map/__tests__/NPCThreatBanner.test.tsx (5 tests) 306ms + ✓ src/config/__tests__/blockDNACatalogExport.test.ts (6 tests) 112ms +stderr | src/components/system/RouteLoadBoundary.test.tsx > RouteLoadBoundary > shows recovery UI and keeps the fallback board when a heavy surface fails +Error: WebGL unavailable + at Boom (/home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.test.tsx:7:9) + at renderWithHooks (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:15486:18) + at mountIndeterminateComponent (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:20103:13) + at beginWork (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:21626:16) + at HTMLUnknownElement.callCallback (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:4164:14) + at HTMLUnknownElement.callTheUserObjectsOperation (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/generated/idl/EventListener.js:26:30) + at innerInvokeEventListeners (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:360:16) + at invokeEventListeners (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:296:3) + at HTMLUnknownElementImpl._dispatch (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:243:9) + at HTMLUnknownElementImpl.dispatchEvent (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:114:17) +Error: WebGL unavailable + at Boom (/home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.test.tsx:7:9) + at renderWithHooks (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:15486:18) + at mountIndeterminateComponent (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:20103:13) + at beginWork (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:21626:16) + at HTMLUnknownElement.callCallback (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:4164:14) + at HTMLUnknownElement.callTheUserObjectsOperation (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/generated/idl/EventListener.js:26:30) + at innerInvokeEventListeners (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:360:16) + at invokeEventListeners (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:296:3) + at HTMLUnknownElementImpl._dispatch (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:243:9) + at HTMLUnknownElementImpl.dispatchEvent (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:114:17) +The above error occurred in the component: + + at Boom (/home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.test.tsx:10:9) + at RouteLoadBoundary (/home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.tsx:69:1) + +React will try to recreate this component tree from scratch using the error boundary you provided, RouteLoadBoundary. + +stderr | src/components/system/RouteLoadBoundary.test.tsx > RouteLoadBoundary > retries and remounts children after a synchronous render failure +Error: chunk failed + at Flaky (/home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.test.tsx:37:30) + at renderWithHooks (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:15486:18) + at mountIndeterminateComponent (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:20103:13) + at beginWork (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:21626:16) + at HTMLUnknownElement.callCallback (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:4164:14) + at HTMLUnknownElement.callTheUserObjectsOperation (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/generated/idl/EventListener.js:26:30) + at innerInvokeEventListeners (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:360:16) + at invokeEventListeners (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:296:3) + at HTMLUnknownElementImpl._dispatch (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:243:9) + at HTMLUnknownElementImpl.dispatchEvent (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:114:17) +Error: chunk failed + at Flaky (/home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.test.tsx:37:30) + at renderWithHooks (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:15486:18) + at mountIndeterminateComponent (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:20103:13) + at beginWork (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:21626:16) + at HTMLUnknownElement.callCallback (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:4164:14) + at HTMLUnknownElement.callTheUserObjectsOperation (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/generated/idl/EventListener.js:26:30) + at innerInvokeEventListeners (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:360:16) + at invokeEventListeners (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:296:3) + at HTMLUnknownElementImpl._dispatch (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:243:9) + at HTMLUnknownElementImpl.dispatchEvent (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:114:17) +The above error occurred in the component: + + at Flaky (/home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.test.tsx:54:30) + at RouteLoadBoundary (/home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.tsx:69:1) + +React will try to recreate this component tree from scratch using the error boundary you provided, RouteLoadBoundary. + +stderr | src/components/system/RouteLoadBoundary.test.tsx > RouteLoadBoundary > retries a rejected React.lazy import with a fresh loader attempt +Error: Failed to fetch dynamically imported module + at /home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.test.tsx:58:31 + at /home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.tsx:77:11 + at processTicksAndRejections (node:internal/process/task_queues:104:5) +Error: Failed to fetch dynamically imported module + at /home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.test.tsx:58:31 + at /home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.tsx:77:11 + at processTicksAndRejections (node:internal/process/task_queues:104:5) +The above error occurred in the component: + + at RetryableLazy (/home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.tsx:36:43) + at Suspense + at RouteLoadBoundary (/home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.tsx:69:1) + at LazyRoute (/home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.tsx:148:3) + +React will try to recreate this component tree from scratch using the error boundary you provided, RouteLoadBoundary. + + ✓ src/components/system/RouteLoadBoundary.test.tsx (4 tests) 394ms + ✓ src/hooks/useGhostCrewSync.test.tsx (3 tests) 201ms + ✓ src/components/map/__tests__/playableMapGeometry.test.ts (3 tests) 7ms +stderr | src/components/layout/BlockLoopDesk.fallback.test.tsx > BlockLoopDesk diorama fallback board > advances loop placement from a fallback board cell click +Error: WebGL unavailable + at default (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.fallback.test.tsx:4:11) + at renderWithHooks (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:15486:18) + at mountIndeterminateComponent (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:20103:13) + at beginWork (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:21626:16) + at HTMLUnknownElement.callCallback (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:4164:14) + at HTMLUnknownElement.callTheUserObjectsOperation (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/generated/idl/EventListener.js:26:30) + at innerInvokeEventListeners (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:360:16) + at invokeEventListeners (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:296:3) + at HTMLUnknownElementImpl._dispatch (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:243:9) + at HTMLUnknownElementImpl.dispatchEvent (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:114:17) +Error: WebGL unavailable + at default (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.fallback.test.tsx:4:11) + at renderWithHooks (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:15486:18) + at mountIndeterminateComponent (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:20103:13) + at beginWork (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:21626:16) + at HTMLUnknownElement.callCallback (/home/ubuntu/projects/slide/frontend/node_modules/react-dom/cjs/react-dom.development.js:4164:14) + at HTMLUnknownElement.callTheUserObjectsOperation (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/generated/idl/EventListener.js:26:30) + at innerInvokeEventListeners (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:360:16) + at invokeEventListeners (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:296:3) + at HTMLUnknownElementImpl._dispatch (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:243:9) + at HTMLUnknownElementImpl.dispatchEvent (/home/ubuntu/projects/slide/frontend/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:114:17) +The above error occurred in the component: + + at default (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.fallback.test.tsx:4:11) + at RouteLoadBoundary (/home/ubuntu/projects/slide/frontend/src/components/system/RouteLoadBoundary.tsx:69:1) + at section + at div + at BlockLoopDesk (/home/ubuntu/projects/slide/frontend/src/components/layout/BlockLoopDesk.tsx:72:56) + +React will try to recreate this component tree from scratch using the error boundary you provided, RouteLoadBoundary. + + ✓ src/components/layout/BlockLoopDesk.fallback.test.tsx (1 test) 841ms + ✓ BlockLoopDesk diorama fallback board > advances loop placement from a fallback board cell click 839ms + ✓ src/utils/__tests__/demoSeedInventory.test.ts (4 tests) 31ms + ✓ src/utils/__tests__/BulletCamEngine.test.ts (5 tests) 13ms + ✓ src/components/encounter/__tests__/UnifiedEncounterLog.test.tsx (1 test) 68ms + ✓ src/__tests__/routePerformance.contract.test.ts (6 tests) 6ms +stderr | src/components/topdown/__tests__/TopDownShooter.launch.test.tsx > TopDownShooter empty seats > stays disabled when the passenger cannot shoot, then enables for a shooter +Not implemented: Window's scrollTo() method +Not implemented: Window's scrollTo() method +Not implemented: Window's scrollTo() method + + ✓ src/components/topdown/__tests__/TopDownShooter.launch.test.tsx (2 tests) 381ms + ✓ src/components/missions/__tests__/AttackPlanner.launch.test.tsx (2 tests) 320ms + ✓ src/components/map/BlockModeView.test.tsx (1 test) 362ms + ✓ BlockModeView beta chrome > keeps diorama, board, and encounter as the only Strip tabs and forwards map failure 360ms + ✓ src/types/contracts/blockScene.test.ts (3 tests) 6ms + ✓ src/utils/__tests__/bulletCamTrigger.test.ts (6 tests) 8ms + ✓ src/hooks/__tests__/useBlockSatellite.test.ts (7 tests) 5ms + ✓ src/components/contacts/__tests__/Contacts.test.tsx (1 test) 418ms + ✓ Contacts photo recruit detail > shows the generated photo recruit backstory in the contact profile 416ms + ✓ src/utils/__tests__/nearbyBlocks.test.ts (4 tests) 7ms + ✓ src/components/phone/__tests__/PhoneApp.test.tsx (2 tests) 295ms + ✓ src/components/compliance/AgeGate.test.tsx (5 tests) 484ms + ✓ AgeGate demo evaluation chrome > shows the mature-content gate and evaluation banner without skipping 18+ 476ms + ✓ src/utils/__tests__/demoSeedBooks.test.ts (2 tests) 21ms +stderr | src/services/__tests__/avatarGeneration.service.test.ts > offline photo preview > returns loadable registered stock art for every recruit role +[AvatarService] Backend unavailable, using mock assets. +[AvatarService] Backend unavailable, using mock assets. +[AvatarService] Backend unavailable, using mock assets. +[AvatarService] Backend unavailable, using mock assets. +[AvatarService] Backend unavailable, using mock assets. +[AvatarService] Backend unavailable, using mock assets. +[AvatarService] Backend unavailable, using mock assets. + +stderr | src/services/__tests__/avatarGeneration.service.test.ts > offline photo preview > keeps unrequested outputs absent in the offline preview +[AvatarService] Backend unavailable, using mock assets. + + ✓ src/services/__tests__/avatarGeneration.service.test.ts (2 tests) 12ms + ✓ src/utils/__tests__/demoSeedContacts.test.ts (2 tests) 11ms + ✓ src/components/hub/Leaderboard.test.tsx (2 tests) 268ms + ✓ src/utils/__tests__/demoSeedProgress.test.ts (2 tests) 9ms + ✓ src/components/system/StartupErrorBoundary.test.tsx (2 tests) 288ms + ✓ src/stores/__tests__/notificationStore.test.ts (2 tests) 6ms + ✓ src/utils/authPlayer.test.ts (5 tests) 4ms + ✓ src/utils/__tests__/geo.test.ts (5 tests) 6ms + ✓ src/utils/__tests__/phaserReady.test.ts (3 tests) 6ms + ✓ src/components/layout/__tests__/OSShellBalance.test.tsx (2 tests) 376ms + ✓ command desk authoritative street cash > shows and refreshes the live player balance for account-123 314ms + ✓ src/game/ops/__tests__/opsCoordinates.test.ts (2 tests) 7ms + ✓ src/stores/__tests__/combatIntentStore.test.ts (1 test) 3ms + ✓ src/__tests__/releasePreflight.test.ts (4 tests) 291ms + ✓ src/components/hub/Leaderboard.security.test.ts (1 test) 3ms + ✓ src/__tests__/assetProcessor.test.ts (8 tests) 1651ms + ✓ asset processor incremental imports > retains registered actors when importing a new actor and on a repeated no-op write 378ms + + Test Files 94 passed (94) + Tests 1062 passed | 4 skipped (1066) + Start at 13:51:48 + Duration 33.99s (transform 4.37s, setup 9.40s, collect 19.00s, tests 21.03s, environment 84.66s, prepare 8.20s) + + +> dealt-slide-mvp@1.0.0 assets:audit +> node scripts/assets/audit.mjs + + +SLIDE asset audit +────────────────────────────────────────────────────────────────────── +Assets checked : 112 +Package files : 13 (1.57 MB) +Runtime total : 7.70 MB / 20 MB budget +Errors : 0 +Warnings : 0 + +AUDIT PASSED + +> dealt-slide-mvp@1.0.0 assets:packages +> node scripts/assets/validate-packages.mjs + +Asset package validation passed: 5 package(s), 4 schema(s). + +== Production build == + +> dealt-slide-mvp@1.0.0 build +> vite build + +vite v5.4.21 building for production... +transforming... + +/assets/game_logo.png referenced in /assets/game_logo.png didn't resolve at build time, it will remain unchanged to be resolved at runtime + +/assets/bg_menu.jpg referenced in /assets/bg_menu.jpg didn't resolve at build time, it will remain unchanged to be resolved at runtime + +/assets/bg_driveby.jpg referenced in /assets/bg_driveby.jpg didn't resolve at build time, it will remain unchanged to be resolved at runtime +✓ 3347 modules transformed. +rendering chunks... +computing gzip size... +dist/index.html 0.90 kB │ gzip: 0.47 kB +dist/assets/maplibre-gl-worker-BSIqwooQ.js 476.61 kB +dist/assets/AttackPlanner-Q4knGRYB.css 1.05 kB │ gzip: 0.45 kB +dist/assets/Leaderboard-CQC2u3lr.css 3.07 kB │ gzip: 1.02 kB +dist/assets/PoliceRaidGame-TxbI8IBd.css 3.16 kB │ gzip: 1.12 kB +dist/assets/PhoneApp-rpWN35Mf.css 3.25 kB │ gzip: 1.13 kB +dist/assets/PhotoMemberCreator-CHDEykYB.css 4.29 kB │ gzip: 1.30 kB +dist/assets/BlockLoopDesk-CDQqxJnT.css 4.88 kB │ gzip: 1.68 kB +dist/assets/UnifiedEncounter-7rne5g4o.css 4.91 kB │ gzip: 1.72 kB +dist/assets/Missions-CnuTdh9M.css 5.05 kB │ gzip: 1.52 kB +dist/assets/CocaineCrush-DLp4t8x8.css 5.31 kB │ gzip: 1.60 kB +dist/assets/BipNDipGame-OUTspsaX.css 5.81 kB │ gzip: 1.85 kB +dist/assets/ModernOpsEncounter-D1nefR-j.css 6.48 kB │ gzip: 2.10 kB +dist/assets/TrapApp-DxzDWJwG.css 6.71 kB │ gzip: 1.53 kB +dist/assets/Casino-DTlBntHn.css 7.26 kB │ gzip: 1.78 kB +dist/assets/AlchemyLab-Cp6Zrgs6.css 8.45 kB │ gzip: 2.20 kB +dist/assets/DealtModeSelector-DagPjzKc.css 8.50 kB │ gzip: 1.97 kB +dist/assets/TacticalDiorama-CeUNbIO4.css 8.70 kB │ gzip: 2.53 kB +dist/assets/MostWantedApp-C1fxl-9j.css 9.46 kB │ gzip: 2.36 kB +dist/assets/Shoebox-D3lVPOny.css 9.48 kB │ gzip: 2.53 kB +dist/assets/Market-DwwWzb5U.css 9.80 kB │ gzip: 2.52 kB +dist/assets/TopDownShooter-kwv7Hf2b.css 11.19 kB │ gzip: 2.67 kB +dist/assets/DriveByGame-Ds2v5ExV.css 12.16 kB │ gzip: 3.21 kB +dist/assets/SlideGame-c2BLx4Qu.css 13.34 kB │ gzip: 3.27 kB +dist/assets/index-U8R8UmkV.css 14.78 kB │ gzip: 3.95 kB +dist/assets/GraffitiGame-B3XyHHUs.css 15.11 kB │ gzip: 3.40 kB +dist/assets/TerritoryMap-Cn2HY3vV.css 38.33 kB │ gzip: 8.41 kB +dist/assets/App-CHZw-vxm.css 82.32 kB │ gzip: 15.83 kB +dist/assets/vendor-maplibre-GRinvwPn.css 83.06 kB │ gzip: 10.52 kB +dist/assets/abstractAudioBus-CPI4W7dJ.js 0.12 kB │ gzip: 0.13 kB +dist/assets/kernelBlurVaryingDeclaration-BKBSlNgm.js 0.18 kB │ gzip: 0.16 kB +dist/assets/kernelBlurVaryingDeclaration-D9JtdnJ-.js 0.19 kB │ gzip: 0.17 kB +dist/assets/sceneVertexDeclaration-C_sJFrnI.js 0.30 kB │ gzip: 0.21 kB +dist/assets/flowGraphUnaryOperationBlock-bo5wFDVo.js 0.30 kB │ gzip: 0.22 kB +dist/assets/flame-KZr3s-2C.js 0.36 kB │ gzip: 0.29 kB +dist/assets/flowGraphBinaryOperationBlock-DGBLcSEJ.js 0.38 kB │ gzip: 0.24 kB +dist/assets/logDepthDeclaration-Z7lVjHSy.js 0.39 kB │ gzip: 0.26 kB +dist/assets/logDepthDeclaration-B0Yd7rC1.js 0.41 kB │ gzip: 0.27 kB +dist/assets/moneyRouter-PAlbU0OI.js 0.49 kB │ gzip: 0.28 kB +dist/assets/shopping-bag-DX_OIf_z.js 0.51 kB │ gzip: 0.34 kB +dist/assets/pass.fragment-Bb1QqnHB.js 0.53 kB │ gzip: 0.36 kB +dist/assets/packingFunctions-DbtSDAj3.js 0.53 kB │ gzip: 0.30 kB +dist/assets/meshUboDeclaration-CmjAklUx.js 0.57 kB │ gzip: 0.32 kB +dist/assets/meshUboDeclaration-dsUPGWEu.js 0.57 kB │ gzip: 0.32 kB +dist/assets/shadowMapFragmentSoftTransparentShadow-reX_nCL3.js 0.58 kB │ gzip: 0.38 kB +dist/assets/flowGraphSceneReadyEventBlock-D7HpNnFZ.js 0.59 kB │ gzip: 0.36 kB +dist/assets/flowGraphPauseAnimationBlock-BKn4UVOf.js 0.59 kB │ gzip: 0.35 kB +dist/assets/shadowMapFragmentSoftTransparentShadow-Dwa5g_Uu.js 0.62 kB │ gzip: 0.40 kB +dist/assets/rgbdEncode.fragment-DKOkc_dm.js 0.62 kB │ gzip: 0.41 kB +dist/assets/rgbdDecode.fragment-DAzr8l46.js 0.63 kB │ gzip: 0.41 kB +dist/assets/flowGraphConstantBlock-CaMDC5A8.js 0.64 kB │ gzip: 0.38 kB +dist/assets/glowMapMerge.vertex-DT890hBu.js 0.65 kB │ gzip: 0.40 kB +dist/assets/pass.fragment-AfJgdWDT.js 0.66 kB │ gzip: 0.40 kB +dist/assets/flowGraphBranchBlock-sHtLjZ8P.js 0.68 kB │ gzip: 0.37 kB +dist/assets/vertexColorMixing-DQmMZtqT.js 0.68 kB │ gzip: 0.35 kB +dist/assets/flowGraphGLTFDataProvider-4z2h7KfI.js 0.68 kB │ gzip: 0.40 kB +dist/assets/flowGraphCodeExecutionBlock-4-TS-Bk_.js 0.69 kB │ gzip: 0.38 kB +dist/assets/flowGraphGetVariableBlock-BUBUNS-G.js 0.69 kB │ gzip: 0.39 kB +dist/assets/flowGraphContextBlock-BHTVQHGm.js 0.69 kB │ gzip: 0.37 kB +dist/assets/flowGraphCachedOperationBlock-DjWMW2bs.js 0.71 kB │ gzip: 0.34 kB +dist/assets/flowGraphCancelDelayBlock-5YuSJe4i.js 0.74 kB │ gzip: 0.46 kB +dist/assets/depthBoxBlur.fragment-B2me0gsH.js 0.75 kB │ gzip: 0.46 kB +dist/assets/bumpVertex-BV8_hm-z.js 0.75 kB │ gzip: 0.35 kB +dist/assets/rgbdEncode.fragment-2OKUIkr_.js 0.75 kB │ gzip: 0.44 kB +dist/assets/flowGraphIndexOfBlock-Bn2eQOUL.js 0.75 kB │ gzip: 0.42 kB +dist/assets/glowMapMerge.vertex-3vu60kVv.js 0.76 kB │ gzip: 0.44 kB +dist/assets/rgbdDecode.fragment-Cpk_QDh9.js 0.76 kB │ gzip: 0.45 kB +dist/assets/flowGraphSendCustomEventBlock-RY3cxGhm.js 0.76 kB │ gzip: 0.43 kB +dist/assets/flowGraphConditionalDataBlock-Bv_uQM_P.js 0.77 kB │ gzip: 0.40 kB +dist/assets/flowGraphSceneTickEventBlock-BCvETl97.js 0.77 kB │ gzip: 0.41 kB +dist/assets/flowGraphCounterBlock-BRWeJkUO.js 0.78 kB │ gzip: 0.42 kB +dist/assets/envTextureLoader-B2qp6_Z2.js 0.78 kB │ gzip: 0.48 kB +dist/assets/flowGraphGetAssetBlock-BPrf-gfh.js 0.78 kB │ gzip: 0.44 kB +dist/assets/flowGraphArrayIndexBlock-BvZLZsOZ.js 0.79 kB │ gzip: 0.44 kB +dist/assets/flowGraphFlipFlopBlock-Bty-AEtF.js 0.85 kB │ gzip: 0.46 kB +dist/assets/flowGraphFunctionReferenceBlock-BLrUlI4x.js 0.85 kB │ gzip: 0.44 kB +dist/assets/flowGraphDebounceBlock-DBnSbtc5.js 0.91 kB │ gzip: 0.45 kB +dist/assets/flowGraphDoNBlock-DOfpBb15.js 0.92 kB │ gzip: 0.47 kB +dist/assets/flowGraphSequenceBlock-Bq7kHb29.js 0.92 kB │ gzip: 0.46 kB +dist/assets/depthBoxBlur.fragment-CUNNO4vc.js 0.93 kB │ gzip: 0.53 kB +dist/assets/vertexColorMixing-Rg7xf3MC.js 0.94 kB │ gzip: 0.40 kB +dist/assets/color.fragment-p7jNlbJ3.js 0.96 kB │ gzip: 0.48 kB +dist/assets/mesh.vertexData.functions-ayNlGC5K.js 0.96 kB │ gzip: 0.49 kB +dist/assets/kernelBlur.vertex-C1stVEvV.js 0.98 kB │ gzip: 0.52 kB +dist/assets/bumpVertex-xey3jRrr.js 0.98 kB │ gzip: 0.42 kB +dist/assets/flowGraphPointerOutEventBlock-Dij88Phj.js 1.00 kB │ gzip: 0.52 kB +dist/assets/instancesDeclaration-CiPX0r45.js 1.01 kB │ gzip: 0.35 kB +dist/assets/glowMapMerge.fragment-C8lfIk_a.js 1.01 kB │ gzip: 0.53 kB +dist/assets/flowGraphPointerOverEventBlock-B7eLsWCb.js 1.01 kB │ gzip: 0.53 kB +dist/assets/flowGraphWhileLoopBlock-DwIhtyB5.js 1.02 kB │ gzip: 0.52 kB +dist/assets/fogFragment-aoAf_1GT.js 1.03 kB │ gzip: 0.46 kB +dist/assets/passCube.fragment-COwtw8Il.js 1.04 kB │ gzip: 0.46 kB +dist/assets/flowGraphGetPropertyBlock-MUQWJ2ON.js 1.06 kB │ gzip: 0.52 kB +dist/assets/flowGraphDataSwitchBlock-Ds7RELYC.js 1.07 kB │ gzip: 0.55 kB +dist/assets/flowGraphBezierCurveEasingBlock-CyHoXDYm.js 1.08 kB │ gzip: 0.52 kB +dist/assets/flowGraphTransformCoordinatesSystemBlock-Bg_8gNQT.js 1.09 kB │ gzip: 0.49 kB +dist/assets/color.fragment-BvQgLf6J.js 1.10 kB │ gzip: 0.52 kB +dist/assets/kernelBlur.vertex-Bc6f1XsW.js 1.13 kB │ gzip: 0.56 kB +dist/assets/defaultUboDeclaration-y8WwUG4S.js 1.15 kB │ gzip: 0.50 kB +dist/assets/webAudioMainBus-DJATPtiV.js 1.16 kB │ gzip: 0.54 kB +dist/assets/fogFragment-CKJ9Ukbr.js 1.16 kB │ gzip: 0.51 kB +dist/assets/clipPlaneFragment-CZF_ElOC.js 1.22 kB │ gzip: 0.34 kB +dist/assets/flowGraphConsoleLogBlock-B9INq6LA.js 1.27 kB │ gzip: 0.65 kB +dist/assets/glowMapMerge.fragment-CPeZihdh.js 1.27 kB │ gzip: 0.60 kB +dist/assets/flowGraphSwitchBlock-ZYyL5nuO.js 1.28 kB │ gzip: 0.58 kB +dist/assets/flowGraphForLoopBlock-SsdxdkCf.js 1.29 kB │ gzip: 0.60 kB +dist/assets/glowBlurPostProcess.fragment-V7Ua_Hon.js 1.33 kB │ gzip: 0.68 kB +dist/assets/passCube.fragment-D5VZqBPT.js 1.34 kB │ gzip: 0.51 kB +dist/assets/flowGraphReceiveCustomEventBlock-CrVAEwXW.js 1.40 kB │ gzip: 0.66 kB +dist/assets/color.vertex-kLvcTjUB.js 1.43 kB │ gzip: 0.63 kB +dist/assets/flowGraphTypeToTypeBlocks-XATrEim3.js 1.44 kB │ gzip: 0.54 kB +dist/assets/color.vertex-CBJnX0vf.js 1.44 kB │ gzip: 0.65 kB +dist/assets/depth.fragment-FGD1dOwG.js 1.47 kB │ gzip: 0.65 kB +dist/assets/ddsTextureLoader-BzK0zeVT.js 1.47 kB │ gzip: 0.73 kB +dist/assets/defaultUboDeclaration-BtBxA2oG.js 1.50 kB │ gzip: 0.48 kB +dist/assets/flowGraphThrottleBlock-BVsMvLuJ.js 1.51 kB │ gzip: 0.59 kB +dist/assets/flowGraphSetPropertyBlock-F5ANgGJ-.js 1.54 kB │ gzip: 0.74 kB +dist/assets/flowGraphSetVariableBlock-ChKIZjuE.js 1.56 kB │ gzip: 0.73 kB +dist/assets/projection-DMbgv_yw.js 1.62 kB │ gzip: 0.74 kB +dist/assets/glowBlurPostProcess.fragment-Cl5SE_Y_.js 1.62 kB │ gzip: 0.76 kB +dist/assets/flowGraphWaitAllBlock-Dn92i1yQ.js 1.68 kB │ gzip: 0.72 kB +dist/assets/flowGraphMeshPickEventBlock-COjgbcvb.js 1.68 kB │ gzip: 0.70 kB +dist/assets/pbrUboDeclaration-CDMRrdg6.js 1.69 kB │ gzip: 0.63 kB +dist/assets/flowGraphEasingBlock-DXQw-ViD.js 1.77 kB │ gzip: 0.82 kB +dist/assets/flowGraphMultiGateBlock-BQfi7GN5.js 1.82 kB │ gzip: 0.80 kB +dist/assets/glowMapGeneration.fragment-BmPU2EaX.js 1.93 kB │ gzip: 0.77 kB +dist/assets/flowGraphStopAnimationBlock-C98Uh40h.js 2.03 kB │ gzip: 0.75 kB +dist/assets/pbrUboDeclaration-UHmSlJwH.js 2.27 kB │ gzip: 0.61 kB +dist/assets/glowMapGeneration.vertex-D5mP5Uxj.js 2.29 kB │ gzip: 0.77 kB +dist/assets/depth.vertex-Uwn-9rST.js 2.30 kB │ gzip: 0.87 kB +dist/assets/kernelBlur.fragment-CoBLHfQ9.js 2.31 kB │ gzip: 0.80 kB +dist/assets/flowGraphInterpolationBlock-vxGmYWjx.js 2.38 kB │ gzip: 0.98 kB +dist/assets/webAudioBus-Cff5Aqp9.js 2.57 kB │ gzip: 0.89 kB +dist/assets/glowMapGeneration.fragment-f2l8QL38.js 2.60 kB │ gzip: 0.89 kB +dist/assets/hdrTextureLoader-CWy8wjpf.js 2.63 kB │ gzip: 1.27 kB +dist/assets/policeRaidEngine-ioCoSz4K.js 2.69 kB │ gzip: 1.11 kB +dist/assets/ShooterGraphicsLab-CkXB-r_H.js 2.77 kB │ gzip: 1.37 kB +dist/assets/glowMapGeneration.vertex-CcabOx3F.js 2.83 kB │ gzip: 0.89 kB +dist/assets/kernelBlur.fragment-jub5KOuX.js 2.88 kB │ gzip: 0.89 kB +dist/assets/iesTextureLoader-CYSyqIn6.js 2.91 kB │ gzip: 1.27 kB +dist/assets/AttackPlanner-DcLuLOOe.js 3.01 kB │ gzip: 1.11 kB +dist/assets/shadowMap.fragment-lKGm4HJ0.js 3.25 kB │ gzip: 1.17 kB +dist/assets/flowGraphJsonPointerParserBlock-DLY3kG-2.js 3.29 kB │ gzip: 1.37 kB +dist/assets/openpbrUboDeclaration-SHlmvirS.js 3.41 kB │ gzip: 0.91 kB +dist/assets/tgaTextureLoader-uqmIeSDA.js 3.74 kB │ gzip: 1.49 kB +dist/assets/flowGraphMatrixMathBlocks-BivBfV_i.js 3.84 kB │ gzip: 1.07 kB +dist/assets/PhoneApp-BIi-RrZB.js 3.86 kB │ gzip: 1.54 kB +dist/assets/flowGraphPlayAnimationBlock-D_9pxEI3.js 3.87 kB │ gzip: 1.30 kB +dist/assets/shadowMap.fragment-wRW7zWxx.js 3.88 kB │ gzip: 1.28 kB +dist/assets/Leaderboard-BXabzaeg.js 3.98 kB │ gzip: 1.62 kB +dist/assets/flowGraphSetDelayBlock-Cib4WGXS.js 4.34 kB │ gzip: 1.55 kB +dist/assets/morphTargetsVertex-Qcz80JZb.js 4.37 kB │ gzip: 0.94 kB +dist/assets/shadowMap.vertex-BvJTWqaj.js 4.43 kB │ gzip: 1.48 kB +dist/assets/openpbrUboDeclaration-9_h0Gary.js 4.61 kB │ gzip: 0.93 kB +dist/assets/shadowMap.vertex-BxmDIFq5.js 4.62 kB │ gzip: 1.49 kB +dist/assets/flowGraphVectorMathBlocks-BiNn0578.js 4.91 kB │ gzip: 1.57 kB +dist/assets/PoliceRaidGame-DrcQpilY.js 5.01 kB │ gzip: 2.11 kB +dist/assets/AddressSearchBar-vx2VYPdv.js 5.64 kB │ gzip: 2.51 kB +dist/assets/helperFunctions-DkpNEsbw.js 5.88 kB │ gzip: 1.97 kB +dist/assets/assetResolver-DnVK9bs6.js 6.03 kB │ gzip: 1.82 kB +dist/assets/helperFunctions-CfNJkEII.js 6.23 kB │ gzip: 2.09 kB +dist/assets/logDepthVertex-CgCCg9C1.js 6.82 kB │ gzip: 1.62 kB +dist/assets/dds-D5Z8HnXl.js 7.21 kB │ gzip: 2.57 kB +dist/assets/default.vertex-bWpUVwEj.js 7.41 kB │ gzip: 2.01 kB +dist/assets/marketMembersCatalog-DxBYOhdT.js 7.86 kB │ gzip: 3.80 kB +dist/assets/TrapApp-xzaP7J18.js 7.99 kB │ gzip: 2.73 kB +dist/assets/logDepthVertex-8i8LFtp7.js 8.07 kB │ gzip: 1.69 kB +dist/assets/default.vertex-DxUREBZX.js 8.11 kB │ gzip: 2.16 kB +dist/assets/flowGraphMathCombineExtractBlocks-pYXsuuJR.js 8.29 kB │ gzip: 1.22 kB +dist/assets/basisTextureLoader-Bg7eV9vE.js 8.44 kB │ gzip: 3.36 kB +dist/assets/CocaineCrush--fZzIrNK.js 8.94 kB │ gzip: 3.26 kB +dist/assets/openpbrMaterialLoadingAdapter-W4Oq_n7i.js 9.44 kB │ gzip: 1.71 kB +dist/assets/clipPlaneVertex-1YIDRY-_.js 9.47 kB │ gzip: 1.63 kB +dist/assets/PhotoMemberCreator-Du0vh86B.js 9.86 kB │ gzip: 3.78 kB +dist/assets/Casino-CG7qw9Ls.js 10.14 kB │ gzip: 2.96 kB +dist/assets/Missions-DXr1jWs9.js 10.59 kB │ gzip: 4.11 kB +dist/assets/pbrMaterialLoadingAdapter-DeqPweAp.js 11.79 kB │ gzip: 2.30 kB +dist/assets/BlockLoopDesk-BvKQ2sqP.js 11.85 kB │ gzip: 3.81 kB +dist/assets/prepareEncounter-CEGd9g36.js 12.12 kB │ gzip: 4.71 kB +dist/assets/harmonicsFunctions-C32nbP3Y.js 12.64 kB │ gzip: 4.30 kB +dist/assets/pbr.vertex-BHHV5guJ.js 13.06 kB │ gzip: 2.80 kB +dist/assets/harmonicsFunctions-DyQC8ael.js 13.68 kB │ gzip: 4.47 kB +dist/assets/GangManagement-NdqGOSLk.js 13.92 kB │ gzip: 4.71 kB +dist/assets/MostWantedApp-AoBA8ERh.js 14.68 kB │ gzip: 4.96 kB +dist/assets/ktxTextureLoader-D41g2l-O.js 14.79 kB │ gzip: 4.34 kB +dist/assets/Market-CFE6g9hQ.js 14.80 kB │ gzip: 4.80 kB +dist/assets/openpbr.vertex-Dg1uOMhP.js 15.15 kB │ gzip: 2.98 kB +dist/assets/BipNDipGame-C5xhlre-.js 15.48 kB │ gzip: 5.59 kB +dist/assets/UnifiedEncounter-DS32seyH.js 15.71 kB │ gzip: 5.63 kB +dist/assets/exrTextureLoader-YC_OvoR5.js 15.73 kB │ gzip: 5.91 kB +dist/assets/pbr.vertex-CQPucT39.js 16.40 kB │ gzip: 3.35 kB +dist/assets/TacticalDiorama-XAFy3V7X.js 16.84 kB │ gzip: 6.26 kB +dist/assets/Shoebox-Cg9Zo4sb.js 16.88 kB │ gzip: 4.90 kB +dist/assets/SlideGame-E7hqXgLs.js 18.59 kB │ gzip: 6.65 kB +dist/assets/openpbr.vertex-te_gc6og.js 18.75 kB │ gzip: 3.58 kB +dist/assets/flowGraphMathBlocks-BxOrM0I1.js 19.17 kB │ gzip: 3.94 kB +dist/assets/AlchemyLab-DfxSLnIH.js 19.43 kB │ gzip: 5.76 kB +dist/assets/WeeklyUpdateRoute-CzGx3fWU.js 19.53 kB │ gzip: 6.90 kB +dist/assets/DealtModeSelector-B9utRyqy.js 20.09 kB │ gzip: 6.35 kB +dist/assets/TopDownShooter-BUqri3qN.js 22.78 kB │ gzip: 7.14 kB +dist/assets/default.fragment-DIOvhN-l.js 23.34 kB │ gzip: 5.49 kB +dist/assets/default.fragment-CnptDvsm.js 24.95 kB │ gzip: 5.48 kB +dist/assets/GraffitiGame-C4jVwZXU.js 26.66 kB │ gzip: 8.36 kB +dist/assets/lightFragment-B4yuAgwy.js 27.15 kB │ gzip: 5.43 kB +dist/assets/lightFragment-DEejze27.js 30.36 kB │ gzip: 5.52 kB +dist/assets/animationGroup-DABv0Q-I.js 34.69 kB │ gzip: 8.87 kB +dist/assets/pbrDebug-Bq1oKL1w.js 40.54 kB │ gzip: 8.95 kB +dist/assets/worldActorResolver-DjZCQsrb.js 41.03 kB │ gzip: 4.61 kB +dist/assets/CanvasStreetRendererV3-CzJ8b5yi.js 41.27 kB │ gzip: 13.76 kB +dist/assets/pbrDebug-MILI8hzP.js 48.22 kB │ gzip: 10.49 kB +dist/assets/oitFragment-BE0cyzMj.js 49.79 kB │ gzip: 9.42 kB +dist/assets/oitFragment-CBTe4lAz.js 51.44 kB │ gzip: 9.60 kB +dist/assets/openpbrMaterial-pLxwSEUh.js 52.55 kB │ gzip: 12.28 kB +dist/assets/DriveByGame-Ctin24by.js 64.85 kB │ gzip: 21.75 kB +dist/assets/TerritoryMap-D3zK2nwT.js 70.05 kB │ gzip: 22.96 kB +dist/assets/openpbr.fragment-dOrsjuIZ.js 80.35 kB │ gzip: 15.63 kB +dist/assets/openpbr.fragment-D79kQFG9.js 81.65 kB │ gzip: 15.45 kB +dist/assets/pbr.fragment-CEATKGcR.js 89.63 kB │ gzip: 15.35 kB +dist/assets/pbr.fragment-Cp5e8aig.js 93.16 kB │ gzip: 16.79 kB +dist/assets/vendor-framer-suRT48ci.js 110.11 kB │ gzip: 37.36 kB +dist/assets/index-Bk_z8Iqo.js 138.75 kB │ gzip: 45.19 kB +dist/assets/vendor-supabase-BK2FJJ-F.js 219.36 kB │ gzip: 57.22 kB +dist/assets/App-CpgY_va9.js 385.28 kB │ gzip: 121.46 kB +dist/assets/vendor-maplibre-WbblP0ls.js 952.81 kB │ gzip: 250.65 kB +dist/assets/vendor-phaser-oG8Y5LC_.js 1,478.41 kB │ gzip: 339.66 kB +dist/assets/ModernOpsEncounter-FpOrtABo.js 2,076.30 kB │ gzip: 509.87 kB + +(!) Some chunks are larger than 500 kB after minification. Consider: +- Using dynamic import() to code-split the application +- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks +- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit. +✓ built in 25.47s + +Automated gates passed. +Manual evidence is still required for player-facing changes: +- real entry route at phone and desktop widths +- happy path and one realistic failure path +- page/console errors recorded +- screenshots attached to the PR diff --git a/docs/evidence/2026-10-15-inventory-transfer/independent-review.md b/docs/evidence/2026-10-15-inventory-transfer/independent-review.md new file mode 100644 index 0000000..87140f4 --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/independent-review.md @@ -0,0 +1,7 @@ +# Independent inventory-repair review + +**Result: No material findings.** + +Reviewed the uncommitted `gameStore.transferItemToMember`, `TrapApp` give flow, and demo reseed changes against `origin/main-tL2525` base `9eef5aa`, including the specified new regression tests. The repair validates finite whole requested quantities and current stock/recipient state, uses the selected source ID in the Trap path, preserves item metadata with a unique carried ID, keeps unsupported legacy weapons blocked, provides retryable denial feedback, prevents same-frame duplicate Give actions, and preserves carried demo inventory only for the pre-seed demo player plus matching demo gang records. + +No current production `useEconomyStore`/`useGangStore` subscription consumer makes the two synchronous store updates re-entrant. Id-less/fractional legacy stack concerns are not reachable through the current production economy-stack writers, so they are not blockers for this change. The pre-existing Contacts caller's ignored boolean result remains intentionally out of scope. diff --git a/docs/evidence/2026-10-15-inventory-transfer/inline-feedback-red.log b/docs/evidence/2026-10-15-inventory-transfer/inline-feedback-red.log new file mode 100644 index 0000000..0a06b82 --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/inline-feedback-red.log @@ -0,0 +1,745 @@ + +> dealt-slide-mvp@1.0.0 test +> vitest run src/components/trap/__tests__/TrapApp.transfer.test.tsx -t reports role denial + + + RUN v2.1.9 /home/ubuntu/projects/slide/frontend + + ❯ src/components/trap/__tests__/TrapApp.transfer.test.tsx (6 tests | 1 failed | 5 skipped) 334ms + × THE TRAP transfer confirmation > reports role denial without a success message and allows another eligible recipient 332ms + → Unable to find an accessible element with the role "alert" + +Here are the accessible roles: + + button: + + Name "BACK": +  + + Name "ALL": +  + + Name "WEAPONS": +  + + Name "ARMOR": +  + + Name "VEHICLES": +  + + Name "PRODUCT": +  + + Name "TOOLS": +  + + Name "CONSUMABLES": +  + + Name "-": +  + + Name "+": +  + + Name "GIVE": +  + + Name "CANCEL": +  + + -------------------------------------------------- + heading: + + Name "THE TRAP": +  + + Name "STASH": +  + + Name "CREW": +  + + -------------------------------------------------- + +Ignored nodes: comments, script, style + + 
 +  +  +  + BACK +  +  +  + THE TRAP +  +  + $210 +  in stash +  + 
 +  +  +  + ALL +  +  + WEAPONS +  +  + ARMOR +  +  + VEHICLES +  +  + PRODUCT +  +  + TOOLS +  +  + CONSUMABLES +  +  +  +  +  + STASH +  +  +  +  +  + DRU +  +  +  +  + River Cut +  +  + 72% pure · T2 +  +  +  +  + x + 3 +  +  + $210 +  +  +  +  +  +  +  + CREW +  +  +  +  + WE +  +  +  + Weezy +  +  + SHOOTER +  +  +  +  + LV + 1 +  +  +  +  +  + SL +  +  +  + Slim +  +  + DEALER +  +  +  +  + LV + 1 +  +  +  +  +  +  +  +  +  + River Cut +  +  + to +  +  + Weezy +  +  +  + Once given, this item belongs to them. Backdoor to recover. +  +  +  + - +  +  + 1 +  +  + + +  +  + GIVE +  +  + CANCEL +  +  +  +  +  + + +⎯⎯⎯⎯⎯⎯⎯ Failed Tests 1 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL src/components/trap/__tests__/TrapApp.transfer.test.tsx > THE TRAP transfer confirmation > reports role denial without a success message and allows another eligible recipient +TestingLibraryElementError: Unable to find an accessible element with the role "alert" + +Here are the accessible roles: + + button: + + Name "BACK": +  + + Name "ALL": +  + + Name "WEAPONS": +  + + Name "ARMOR": +  + + Name "VEHICLES": +  + + Name "PRODUCT": +  + + Name "TOOLS": +  + + Name "CONSUMABLES": +  + + Name "-": +  + + Name "+": +  + + Name "GIVE": +  + + Name "CANCEL": +  + + -------------------------------------------------- + heading: + + Name "THE TRAP": +  + + Name "STASH": +  + + Name "CREW": +  + + -------------------------------------------------- + +Ignored nodes: comments, script, style + + 
 +  +  +  + BACK +  +  +  + THE TRAP +  +  + $210 +  in stash +  + 
 +  +  +  + ALL +  +  + WEAPONS +  +  + ARMOR +  +  + VEHICLES +  +  + PRODUCT +  +  + TOOLS +  +  + CONSUMABLES +  +  +  +  +  + STASH +  +  +  +  +  + DRU +  +  +  +  + River Cut +  +  + 72% pure · T2 +  +  +  +  + x + 3 +  +  + $210 +  +  +  +  +  +  +  + CREW +  +  +  +  + WE +  +  +  + Weezy +  +  + SHOOTER +  +  +  +  + LV + 1 +  +  +  +  +  + SL +  +  +  + Slim +  +  + DEALER +  +  +  +  + LV + 1 +  +  +  +  +  +  +  +  +  + River Cut +  +  + to +  +  + Weezy +  +  +  + Once given, this item belongs to them. Backdoor to recover. +  +  +  + - +  +  + 1 +  +  + + +  +  + GIVE +  +  + CANCEL +  +  +  +  +  + + ❯ Object.getElementError node_modules/@testing-library/dom/dist/config.js:37:19 + ❯ node_modules/@testing-library/dom/dist/query-helpers.js:76:38 + ❯ node_modules/@testing-library/dom/dist/query-helpers.js:52:17 + ❯ node_modules/@testing-library/dom/dist/query-helpers.js:95:19 + ❯ src/components/trap/__tests__/TrapApp.transfer.test.tsx:52:19 + 50| expect(useEconomyStore.getState().inventory[0].quantity).toBe(3); + 51| expect(screen.getByRole('button', { name: 'GIVE' })).toBeInTheDocu… + 52| expect(screen.getByRole('alert')).toHaveTextContent("can't hold dr… + | ^ + 53| fireEvent.click(screen.getByText('Slim')); + 54| fireEvent.click(screen.getByRole('button', { name: 'GIVE' })); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯ + + Test Files 1 failed (1) + Tests 1 failed | 5 skipped (6) + Start at 13:47:45 + Duration 2.62s (transform 384ms, setup 126ms, collect 611ms, tests 334ms, environment 882ms, prepare 97ms) diff --git a/docs/evidence/2026-10-15-inventory-transfer/selected-batch-red.log b/docs/evidence/2026-10-15-inventory-transfer/selected-batch-red.log new file mode 100644 index 0000000..0130b9f --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/selected-batch-red.log @@ -0,0 +1,92 @@ + +> dealt-slide-mvp@1.0.0 test +> vitest run src/stores/__tests__/inventoryTransfer.test.ts src/components/trap/__tests__/TrapApp.transfer.test.tsx + + + RUN v2.1.9 /home/ubuntu/projects/slide/frontend + + ❯ src/stores/__tests__/inventoryTransfer.test.ts (19 tests | 1 failed) 25ms + × crew inventory transfer boundary > gives the explicitly selected second stack rather than the first batch with that item ID 10ms + → expected [ 2, 7 ] to deeply equal [ 3, 6 ] +stderr | src/components/trap/__tests__/TrapApp.transfer.test.tsx > THE TRAP transfer confirmation > gives the selected named batch when two stash rows share an item ID +Warning: Encountered two children with the same key, `river-cut`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version. + at div + at div + at div + at div + at TrapApp (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:47:44) +Warning: Encountered two children with the same key, `river-cut`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version. + at div + at div + at div + at div + at TrapApp (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:47:44) +Warning: Encountered two children with the same key, `river-cut`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version. + at div + at div + at div + at div + at TrapApp (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:47:44) +Warning: Encountered two children with the same key, `river-cut`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version. + at div + at div + at div + at div + at TrapApp (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:47:44) + + ❯ src/components/trap/__tests__/TrapApp.transfer.test.tsx (6 tests | 1 failed) 497ms + × THE TRAP transfer confirmation > gives the selected named batch when two stash rows share an item ID 51ms + → expected [ 2, 5 ] to deeply equal [ 3, 4 ] + +⎯⎯⎯⎯⎯⎯⎯ Failed Tests 2 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > gives the explicitly selected second stack rather than the first batch with that item ID +AssertionError: expected [ 2, 7 ] to deeply equal [ 3, 6 ] + +- Expected ++ Received + + Array [ +- 3, +- 6, ++ 2, ++ 7, + ] + + ❯ src/stores/__tests__/inventoryTransfer.test.ts:64:79 + 62| useEconomyStore.setState({ inventory: [product(), product({ id: 's… + 63| expect(useEconomyStore.getState().transferItemToMember('river-cut'… + 64| expect(useEconomyStore.getState().inventory.map((item) => item.qua… + | ^ + 65| expect(useGangStore.getState().members[0].inventory?.[0].quality).… + 66| }); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/2]⎯ + + FAIL src/components/trap/__tests__/TrapApp.transfer.test.tsx > THE TRAP transfer confirmation > gives the selected named batch when two stash rows share an item ID +AssertionError: expected [ 2, 5 ] to deeply equal [ 3, 4 ] + +- Expected ++ Received + + Array [ +- 3, +- 4, ++ 2, ++ 5, + ] + + ❯ src/components/trap/__tests__/TrapApp.transfer.test.tsx:100:79 + 98| fireEvent.click(screen.getByText('Weezy')); + 99| fireEvent.click(screen.getByRole('button', { name: 'GIVE' })); + 100| expect(useEconomyStore.getState().inventory.map((item) => item.qua… + | ^ + 101| expect(useGangStore.getState().members[0].inventory?.[0].quality).… + 102| }); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/2]⎯ + + Test Files 2 failed (2) + Tests 2 failed | 23 passed (25) + Start at 13:45:57 + Duration 2.58s (transform 430ms, setup 231ms, collect 719ms, tests 521ms, environment 1.70s, prepare 156ms) diff --git a/docs/evidence/2026-10-15-inventory-transfer/store-ui-red.log b/docs/evidence/2026-10-15-inventory-transfer/store-ui-red.log new file mode 100644 index 0000000..1b5db65 --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/store-ui-red.log @@ -0,0 +1,764 @@ + +> dealt-slide-mvp@1.0.0 test +> vitest run src/stores/__tests__/inventoryTransfer.test.ts src/components/trap/__tests__/TrapApp.transfer.test.tsx + + + RUN v2.1.9 /home/ubuntu/projects/slide/frontend + + ❯ src/stores/__tests__/inventoryTransfer.test.ts (18 tests | 18 failed) 31ms + × crew inventory transfer boundary > gives product without a CommonJS runtime failure and preserves its recorded metadata 12ms + → expected [Function] to not throw an error but 'Error: Cannot find module \'../config…' was thrown + × crew inventory transfer boundary > rejects invalid quantity 0 without inventory mutation 3ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + × crew inventory transfer boundary > rejects invalid quantity -1 without inventory mutation 1ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + × crew inventory transfer boundary > rejects invalid quantity 0.5 without inventory mutation 1ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + × crew inventory transfer boundary > rejects invalid quantity NaN without inventory mutation 1ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + × crew inventory transfer boundary > rejects invalid quantity Infinity without inventory mutation 2ms + → expected undefined to be false // Object.is equality + × crew inventory transfer boundary > rejects invalid quantity -Infinity without inventory mutation 1ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + × crew inventory transfer boundary > rejects invalid quantity 4 without inventory mutation 1ms + → expected undefined to be false // Object.is equality + × crew inventory transfer boundary > deducts from only the first matching source stack, not every variant of an item 1ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + × crew inventory transfer boundary > preserves recorded armor protection and gives unique carried-item IDs for repeated legitimate actions 1ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + × crew inventory transfer boundary > denies transfers after the recipient becomes hospitalized 1ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + × crew inventory transfer boundary > denies transfers after the recipient becomes jailed 1ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + × crew inventory transfer boundary > denies transfers after the recipient becomes missing 1ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + × crew inventory transfer boundary > rejects a role change to shooter instead of giving it dealer product 1ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + × crew inventory transfer boundary > rejects missing source and recipient records 1ms + → expected undefined to be false // Object.is equality + × crew inventory transfer boundary > does not invent an equipment category for unclassified legacy weapons 1ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + × crew inventory transfer boundary > rechecks current stock on retry and never transfers the same last unit twice 1ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + × crew inventory transfer boundary > restores transferred metadata and remaining stash through the existing local persistence 1ms + → Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts +stderr | src/components/trap/__tests__/TrapApp.transfer.test.tsx > THE TRAP transfer confirmation > gives the selected product, retains its stats, and reports actual success +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) + +stderr | src/components/trap/__tests__/TrapApp.transfer.test.tsx > THE TRAP transfer confirmation > reports role denial without a success message and allows another eligible recipient +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) + +stderr | src/components/trap/__tests__/TrapApp.transfer.test.tsx > THE TRAP transfer confirmation > submits a selected give once for two same-frame taps +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) + +stderr | src/components/trap/__tests__/TrapApp.transfer.test.tsx > THE TRAP transfer confirmation > permits another legitimate give after explicitly selecting the stash again +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + at Module._resolveFilename (node:internal/modules/cjs/loader:1564:15) + at wrapResolveFilename (node:internal/modules/cjs/loader:1118:27) + at defaultResolveImplForCJSLoading (node:internal/modules/cjs/loader:1142:10) + at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1169:12) + at Module._load (node:internal/modules/cjs/loader:1341:5) + at wrapModuleLoad (node:internal/modules/cjs/loader:261:19) + at Module.require (node:internal/modules/cjs/loader:1674:12) + at require (node:internal/modules/helpers:157:16) + at transferItemToMember (/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts:611:65) + at handleGift (/home/ubuntu/projects/slide/frontend/src/components/trap/TrapApp.tsx:128:5) + + ❯ src/components/trap/__tests__/TrapApp.transfer.test.tsx (5 tests | 5 failed) 630ms + × THE TRAP transfer confirmation > gives the selected product, retains its stats, and reports actual success 324ms + → expected 3 to be 2 // Object.is equality + × THE TRAP transfer confirmation > reports role denial without a success message and allows another eligible recipient 114ms + → expected [] to have a length of 1 but got +0 + × THE TRAP transfer confirmation > does not report success when stock changes after the gift panel opens 63ms + → expected [ { type: 'success', …(7) } ] to have a length of +0 but got 1 + × THE TRAP transfer confirmation > submits a selected give once for two same-frame taps 47ms + → expected 3 to be 2 // Object.is equality + × THE TRAP transfer confirmation > permits another legitimate give after explicitly selecting the stash again 80ms + → expected 3 to be 1 // Object.is equality + +⎯⎯⎯⎯⎯⎯ Failed Tests 23 ⎯⎯⎯⎯⎯⎯⎯ + + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > gives product without a CommonJS runtime failure and preserves its recorded metadata +AssertionError: expected [Function] to not throw an error but 'Error: Cannot find module \'../config…' was thrown + +- Expected: +undefined + ++ Received: +"Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts" + + ❯ src/stores/__tests__/inventoryTransfer.test.ts:37:12 + 35| expect(() => { + 36| result = useEconomyStore.getState().transferItemToMember('river-… + 37| }).not.toThrow(); + | ^ + 38| expect(result).toBe(true); + 39| expect(useEconomyStore.getState().inventory[0].quantity).toBe(2); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/23]⎯ + + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > rejects invalid quantity 0 without inventory mutation + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > rejects invalid quantity -1 without inventory mutation + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > rejects invalid quantity 0.5 without inventory mutation + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > rejects invalid quantity NaN without inventory mutation + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > rejects invalid quantity -Infinity without inventory mutation +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Object.transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ src/stores/__tests__/inventoryTransfer.test.ts:49:39 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/23]⎯ + + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > rejects invalid quantity Infinity without inventory mutation + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > rejects invalid quantity 4 without inventory mutation +AssertionError: expected undefined to be false // Object.is equality + +- Expected: +false + ++ Received: +undefined + + ❯ src/stores/__tests__/inventoryTransfer.test.ts:49:99 + 47| const stash = useEconomyStore.getState().inventory; + 48| const crew = useGangStore.getState().members; + 49| expect(useEconomyStore.getState().transferItemToMember('river-cut'… + | ^ + 50| expect(useEconomyStore.getState().inventory).toEqual(stash); + 51| expect(useGangStore.getState().members).toEqual(crew); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/23]⎯ + + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > deducts from only the first matching source stack, not every variant of an item +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Object.transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ src/stores/__tests__/inventoryTransfer.test.ts:56:39 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/23]⎯ + + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > preserves recorded armor protection and gives unique carried-item IDs for repeated legitimate actions +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Object.transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ src/stores/__tests__/inventoryTransfer.test.ts:63:39 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/23]⎯ + + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > denies transfers after the recipient becomes hospitalized + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > denies transfers after the recipient becomes jailed + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > denies transfers after the recipient becomes missing +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Object.transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ src/stores/__tests__/inventoryTransfer.test.ts:73:39 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/23]⎯ + + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > rejects a role change to shooter instead of giving it dealer product +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Object.transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ src/stores/__tests__/inventoryTransfer.test.ts:80:39 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/23]⎯ + + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > rejects missing source and recipient records +AssertionError: expected undefined to be false // Object.is equality + +- Expected: +false + ++ Received: +undefined + + ❯ src/stores/__tests__/inventoryTransfer.test.ts:87:90 + 85| + 86| it('rejects missing source and recipient records', () => { + 87| expect(useEconomyStore.getState().transferItemToMember('missing', … + | ^ + 88| expect(useEconomyStore.getState().transferItemToMember('river-cut'… + 89| expect(useEconomyStore.getState().inventory[0].quantity).toBe(3); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/23]⎯ + + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > does not invent an equipment category for unclassified legacy weapons +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Object.transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ src/stores/__tests__/inventoryTransfer.test.ts:96:39 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[9/23]⎯ + + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > rechecks current stock on retry and never transfers the same last unit twice +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Object.transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ src/stores/__tests__/inventoryTransfer.test.ts:103:39 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[10/23]⎯ + + FAIL src/stores/__tests__/inventoryTransfer.test.ts > crew inventory transfer boundary > restores transferred metadata and remaining stash through the existing local persistence +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Object.transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ src/stores/__tests__/inventoryTransfer.test.ts:110:39 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[11/23]⎯ + + FAIL src/components/trap/__tests__/TrapApp.transfer.test.tsx > THE TRAP transfer confirmation > gives the selected product, retains its stats, and reports actual success +AssertionError: expected 3 to be 2 // Object.is equality + +- Expected ++ Received + +- 2 ++ 3 + + ❯ src/components/trap/__tests__/TrapApp.transfer.test.tsx:40:62 + 38| render(); + 39| expect(() => fireEvent.click(selectGift())).not.toThrow(); + 40| expect(useEconomyStore.getState().inventory[0].quantity).toBe(2); + | ^ + 41| expect(useGangStore.getState().members[0].inventory?.[0]).toMatchO… + 42| expect(successMessages()).toHaveLength(1); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[12/23]⎯ + + FAIL src/components/trap/__tests__/TrapApp.transfer.test.tsx > THE TRAP transfer confirmation > reports role denial without a success message and allows another eligible recipient +AssertionError: expected [] to have a length of 1 but got +0 + +- Expected ++ Received + +- 1 ++ 0 + + ❯ src/components/trap/__tests__/TrapApp.transfer.test.tsx:54:31 + 52| fireEvent.click(screen.getByText('Slim')); + 53| fireEvent.click(screen.getByRole('button', { name: 'GIVE' })); + 54| expect(successMessages()).toHaveLength(1); + | ^ + 55| expect(useGangStore.getState().members.find((member) => member.id … + 56| }); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[13/23]⎯ + + FAIL src/components/trap/__tests__/TrapApp.transfer.test.tsx > THE TRAP transfer confirmation > does not report success when stock changes after the gift panel opens +AssertionError: expected [ { type: 'success', …(7) } ] to have a length of +0 but got 1 + +- Expected ++ Received + +- 0 ++ 1 + + ❯ src/components/trap/__tests__/TrapApp.transfer.test.tsx:63:31 + 61| act(() => useEconomyStore.setState({ inventory: [] })); + 62| fireEvent.click(give); + 63| expect(successMessages()).toHaveLength(0); + | ^ + 64| expect(useGangStore.getState().members[0].inventory).toEqual([]); + 65| expect(useNotificationStore.getState().notifications.some((notific… + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[14/23]⎯ + + FAIL src/components/trap/__tests__/TrapApp.transfer.test.tsx > THE TRAP transfer confirmation > submits a selected give once for two same-frame taps +AssertionError: expected 3 to be 2 // Object.is equality + +- Expected ++ Received + +- 2 ++ 3 + + ❯ src/components/trap/__tests__/TrapApp.transfer.test.tsx:75:62 + 73| fireEvent.click(give); + 74| }); + 75| expect(useEconomyStore.getState().inventory[0].quantity).toBe(2); + | ^ + 76| expect(useGangStore.getState().members[0].inventory).toHaveLength(… + 77| expect(successMessages()).toHaveLength(1); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[15/23]⎯ + + FAIL src/components/trap/__tests__/TrapApp.transfer.test.tsx > THE TRAP transfer confirmation > permits another legitimate give after explicitly selecting the stash again +AssertionError: expected 3 to be 1 // Object.is equality + +- Expected ++ Received + +- 1 ++ 3 + + ❯ src/components/trap/__tests__/TrapApp.transfer.test.tsx:86:62 + 84| fireEvent.click(container.querySelector('.trap-member-card')!); + 85| fireEvent.click(screen.getAllByRole('button', { name: 'GIVE' }).at… + 86| expect(useEconomyStore.getState().inventory[0].quantity).toBe(1); + | ^ + 87| expect(useGangStore.getState().members[0].inventory).toHaveLength(… + 88| expect(successMessages()).toHaveLength(2); + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[16/23]⎯ + +⎯⎯⎯⎯⎯⎯ Unhandled Errors ⎯⎯⎯⎯⎯⎯ + +Vitest caught 7 unhandled errors during the test run. +This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected. + +⎯⎯⎯⎯⎯ Uncaught Exception ⎯⎯⎯⎯⎯ +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Module._resolveFilename node:internal/modules/cjs/loader:1564:15 + ❯ wrapResolveFilename node:internal/modules/cjs/loader:1118:27 + ❯ defaultResolveImplForCJSLoading node:internal/modules/cjs/loader:1142:10 + ❯ resolveForCJSWithHooks node:internal/modules/cjs/loader:1169:12 + ❯ Module._load node:internal/modules/cjs/loader:1341:5 + ❯ wrapModuleLoad node:internal/modules/cjs/loader:261:19 + ❯ Module.require node:internal/modules/cjs/loader:1674:12 + ❯ require node:internal/modules/helpers:157:16 + ❯ transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ handleGift src/components/trap/TrapApp.tsx:128:5 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'MODULE_NOT_FOUND', requireStack: [ '/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts' ] } +This error originated in "src/components/trap/__tests__/TrapApp.transfer.test.tsx" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. +The latest test that might've caused the error is "gives the selected product, retains its stats, and reports actual success". It might mean one of the following: +- The error was thrown, while Vitest was running this test. +- If the error occurred after the test had been completed, this was the last documented test before it was thrown. + +⎯⎯⎯⎯⎯ Uncaught Exception ⎯⎯⎯⎯⎯ +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Module._resolveFilename node:internal/modules/cjs/loader:1564:15 + ❯ wrapResolveFilename node:internal/modules/cjs/loader:1118:27 + ❯ defaultResolveImplForCJSLoading node:internal/modules/cjs/loader:1142:10 + ❯ resolveForCJSWithHooks node:internal/modules/cjs/loader:1169:12 + ❯ Module._load node:internal/modules/cjs/loader:1341:5 + ❯ wrapModuleLoad node:internal/modules/cjs/loader:261:19 + ❯ Module.require node:internal/modules/cjs/loader:1674:12 + ❯ require node:internal/modules/helpers:157:16 + ❯ transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ handleGift src/components/trap/TrapApp.tsx:128:5 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'MODULE_NOT_FOUND', requireStack: [ '/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts' ] } +This error originated in "src/components/trap/__tests__/TrapApp.transfer.test.tsx" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. +The latest test that might've caused the error is "reports role denial without a success message and allows another eligible recipient". It might mean one of the following: +- The error was thrown, while Vitest was running this test. +- If the error occurred after the test had been completed, this was the last documented test before it was thrown. + +⎯⎯⎯⎯⎯ Uncaught Exception ⎯⎯⎯⎯⎯ +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Module._resolveFilename node:internal/modules/cjs/loader:1564:15 + ❯ wrapResolveFilename node:internal/modules/cjs/loader:1118:27 + ❯ defaultResolveImplForCJSLoading node:internal/modules/cjs/loader:1142:10 + ❯ resolveForCJSWithHooks node:internal/modules/cjs/loader:1169:12 + ❯ Module._load node:internal/modules/cjs/loader:1341:5 + ❯ wrapModuleLoad node:internal/modules/cjs/loader:261:19 + ❯ Module.require node:internal/modules/cjs/loader:1674:12 + ❯ require node:internal/modules/helpers:157:16 + ❯ transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ handleGift src/components/trap/TrapApp.tsx:128:5 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'MODULE_NOT_FOUND', requireStack: [ '/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts' ] } +This error originated in "src/components/trap/__tests__/TrapApp.transfer.test.tsx" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. +The latest test that might've caused the error is "reports role denial without a success message and allows another eligible recipient". It might mean one of the following: +- The error was thrown, while Vitest was running this test. +- If the error occurred after the test had been completed, this was the last documented test before it was thrown. + +⎯⎯⎯⎯⎯ Uncaught Exception ⎯⎯⎯⎯⎯ +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Module._resolveFilename node:internal/modules/cjs/loader:1564:15 + ❯ wrapResolveFilename node:internal/modules/cjs/loader:1118:27 + ❯ defaultResolveImplForCJSLoading node:internal/modules/cjs/loader:1142:10 + ❯ resolveForCJSWithHooks node:internal/modules/cjs/loader:1169:12 + ❯ Module._load node:internal/modules/cjs/loader:1341:5 + ❯ wrapModuleLoad node:internal/modules/cjs/loader:261:19 + ❯ Module.require node:internal/modules/cjs/loader:1674:12 + ❯ require node:internal/modules/helpers:157:16 + ❯ transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ handleGift src/components/trap/TrapApp.tsx:128:5 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'MODULE_NOT_FOUND', requireStack: [ '/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts' ] } +This error originated in "src/components/trap/__tests__/TrapApp.transfer.test.tsx" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. +The latest test that might've caused the error is "submits a selected give once for two same-frame taps". It might mean one of the following: +- The error was thrown, while Vitest was running this test. +- If the error occurred after the test had been completed, this was the last documented test before it was thrown. + +⎯⎯⎯⎯⎯ Uncaught Exception ⎯⎯⎯⎯⎯ +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Module._resolveFilename node:internal/modules/cjs/loader:1564:15 + ❯ wrapResolveFilename node:internal/modules/cjs/loader:1118:27 + ❯ defaultResolveImplForCJSLoading node:internal/modules/cjs/loader:1142:10 + ❯ resolveForCJSWithHooks node:internal/modules/cjs/loader:1169:12 + ❯ Module._load node:internal/modules/cjs/loader:1341:5 + ❯ wrapModuleLoad node:internal/modules/cjs/loader:261:19 + ❯ Module.require node:internal/modules/cjs/loader:1674:12 + ❯ require node:internal/modules/helpers:157:16 + ❯ transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ handleGift src/components/trap/TrapApp.tsx:128:5 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'MODULE_NOT_FOUND', requireStack: [ '/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts' ] } +This error originated in "src/components/trap/__tests__/TrapApp.transfer.test.tsx" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. +The latest test that might've caused the error is "submits a selected give once for two same-frame taps". It might mean one of the following: +- The error was thrown, while Vitest was running this test. +- If the error occurred after the test had been completed, this was the last documented test before it was thrown. + +⎯⎯⎯⎯⎯ Uncaught Exception ⎯⎯⎯⎯⎯ +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Module._resolveFilename node:internal/modules/cjs/loader:1564:15 + ❯ wrapResolveFilename node:internal/modules/cjs/loader:1118:27 + ❯ defaultResolveImplForCJSLoading node:internal/modules/cjs/loader:1142:10 + ❯ resolveForCJSWithHooks node:internal/modules/cjs/loader:1169:12 + ❯ Module._load node:internal/modules/cjs/loader:1341:5 + ❯ wrapModuleLoad node:internal/modules/cjs/loader:261:19 + ❯ Module.require node:internal/modules/cjs/loader:1674:12 + ❯ require node:internal/modules/helpers:157:16 + ❯ transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ handleGift src/components/trap/TrapApp.tsx:128:5 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'MODULE_NOT_FOUND', requireStack: [ '/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts' ] } +This error originated in "src/components/trap/__tests__/TrapApp.transfer.test.tsx" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. +The latest test that might've caused the error is "permits another legitimate give after explicitly selecting the stash again". It might mean one of the following: +- The error was thrown, while Vitest was running this test. +- If the error occurred after the test had been completed, this was the last documented test before it was thrown. + +⎯⎯⎯⎯⎯ Uncaught Exception ⎯⎯⎯⎯⎯ +Error: Cannot find module '../config/roleMechanics' +Require stack: +- /home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts + ❯ Module._resolveFilename node:internal/modules/cjs/loader:1564:15 + ❯ wrapResolveFilename node:internal/modules/cjs/loader:1118:27 + ❯ defaultResolveImplForCJSLoading node:internal/modules/cjs/loader:1142:10 + ❯ resolveForCJSWithHooks node:internal/modules/cjs/loader:1169:12 + ❯ Module._load node:internal/modules/cjs/loader:1341:5 + ❯ wrapModuleLoad node:internal/modules/cjs/loader:261:19 + ❯ Module.require node:internal/modules/cjs/loader:1674:12 + ❯ require node:internal/modules/helpers:157:16 + ❯ transferItemToMember src/stores/gameStore.ts:611:65 + 609| // ── Role-based inventory restriction ─────────────────────… + 610| // eslint-disable-next-line @typescript-eslint/no-var-requir… + 611| const { canRoleHoldItem, getEquipRejectionMessage } = requir… + | ^ + 612| const memberRole = (member.role ?? 'dealer') as any; + 613| const itemType = item.type as any; + ❯ handleGift src/components/trap/TrapApp.tsx:128:5 + +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ +Serialized Error: { code: 'MODULE_NOT_FOUND', requireStack: [ '/home/ubuntu/projects/slide/frontend/src/stores/gameStore.ts' ] } +This error originated in "src/components/trap/__tests__/TrapApp.transfer.test.tsx" test file. It doesn't mean the error was thrown inside the file itself, but while it was running. +The latest test that might've caused the error is "permits another legitimate give after explicitly selecting the stash again". It might mean one of the following: +- The error was thrown, while Vitest was running this test. +- If the error occurred after the test had been completed, this was the last documented test before it was thrown. +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ + + Test Files 2 failed (2) + Tests 23 failed (23) + Errors 7 errors + Start at 13:42:05 + Duration 3.03s (transform 409ms, setup 217ms, collect 674ms, tests 661ms, environment 1.97s, prepare 244ms) diff --git a/docs/evidence/2026-10-15-inventory-transfer/verification-summary.json b/docs/evidence/2026-10-15-inventory-transfer/verification-summary.json new file mode 100644 index 0000000..abcac22 --- /dev/null +++ b/docs/evidence/2026-10-15-inventory-transfer/verification-summary.json @@ -0,0 +1,210 @@ +{ + "date": "2026-10-15", + "branch": "fix/safe-crew-inventory-transfer", + "base_sha": "9eef5aac28a82275d7a2e1596e8658b167953ed7", + "source_sha256": { + "frontend/src/stores/gameStore.ts": "d1e3cae827a621e42d0d010a12a2df8ade6c7379606e070f22fd838c2fd25dc3", + "frontend/src/components/trap/TrapApp.tsx": "1f297256c76fe84319fcf38b51e2823e20c932bda3a88bb1c6de291da25d4814", + "frontend/src/utils/demoSeed.ts": "60df2eb9d5f869db7054f9b3bf42b3d60122deae3dc7da69ed9e7d517dbf6aed", + "frontend/src/stores/__tests__/inventoryTransfer.test.ts": "4f4eb6454be7b016c3d4f522e414ea70f1021e2e81235e800907620decf29d23", + "frontend/src/components/trap/__tests__/TrapApp.transfer.test.tsx": "7841da32127b0105b4de77f8a670278f4673972416f61606bc43a337f15f0bbf", + "frontend/src/utils/__tests__/demoSeedInventory.test.ts": "3c4ffd35fd7f48dd801b7506e7b13e280b39d48ed408e39ad9b755f88ae135e9" + }, + "new_regressions": 29, + "focused_plus_adjacent_passed": 35, + "frontend": { + "passed": 1062, + "skipped": 4, + "files": 94, + "lint_errors": 0, + "lint_baseline_warnings": 200, + "new_lint_warnings": 0, + "typecheck": "passed", + "production_build": "passed" + }, + "backend": { + "passed": 107, + "remote_credentials": "blank" + }, + "assets": { + "runtime_mb": 7.7, + "budget_mb": 20, + "audit_errors": 0, + "audit_warnings": 0, + "packages": 5, + "schemas": 4 + }, + "browser": [ + { + "name": "phone", + "viewport": { + "width": 390, + "height": 844 + }, + "mode": "built", + "url": "http://127.0.0.1:3001", + "before": 50, + "after": 49, + "scope": "inventory player path; not a clean-console or launch approval", + "giveControl": { + "x": 124, + "y": 800.5116577148438, + "width": 181.578125, + "height": 32, + "visible": true, + "hit": true + }, + "pageErrors": [], + "consoleErrors": [ + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)" + ], + "failedResources": [ + { + "url": "http://127.0.0.1:3001/favicon.svg", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/game_logo.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/generated/ui/icons/icon_news_v001.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/game_logo.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/generated/ui/icons/icon_news_v001.png", + "status": 404 + } + ], + "checks": [ + "real Trap give", + "stock deducted once", + "carried item persisted", + "role denial has no success", + "inline rejection visible", + "real reload retains exact carried record and stock" + ], + "pass": true + }, + { + "name": "small-phone", + "viewport": { + "width": 375, + "height": 812 + }, + "mode": "built", + "url": "http://127.0.0.1:3001", + "before": 50, + "after": 49, + "scope": "inventory player path; not a clean-console or launch approval", + "giveControl": { + "x": 124, + "y": 768.3202514648438, + "width": 166.578125, + "height": 32, + "visible": true, + "hit": true + }, + "pageErrors": [], + "consoleErrors": [ + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)" + ], + "failedResources": [ + { + "url": "http://127.0.0.1:3001/assets/game_logo.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/generated/ui/icons/icon_news_v001.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/game_logo.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/generated/ui/icons/icon_news_v001.png", + "status": 404 + } + ], + "checks": [ + "real Trap give", + "stock deducted once", + "carried item persisted", + "role denial has no success", + "inline rejection visible", + "real reload retains exact carried record and stock" + ], + "pass": true + }, + { + "name": "desktop", + "viewport": { + "width": 1440, + "height": 900 + }, + "mode": "built", + "url": "http://127.0.0.1:3001", + "before": 50, + "after": 49, + "scope": "inventory player path; not a clean-console or launch approval", + "giveControl": { + "x": 244, + "y": 856.4043579101562, + "width": 991.578125, + "height": 32, + "visible": true, + "hit": true + }, + "pageErrors": [], + "consoleErrors": [ + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)", + "Failed to load resource: the server responded with a status of 404 (File not found)" + ], + "failedResources": [ + { + "url": "http://127.0.0.1:3001/assets/game_logo.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/generated/ui/icons/icon_news_v001.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/game_logo.png", + "status": 404 + }, + { + "url": "http://127.0.0.1:3001/assets/generated/ui/icons/icon_news_v001.png", + "status": 404 + } + ], + "checks": [ + "real Trap give", + "stock deducted once", + "carried item persisted", + "role denial has no success", + "inline rejection visible", + "real reload retains exact carried record and stock" + ], + "pass": true + } + ], + "independent_review": "no material findings", + "merge": "not performed", + "production_deployment": "not performed", + "authenticated_saved_game_gate": "not executed; #175 remains open" +} diff --git a/frontend/src/components/trap/TrapApp.tsx b/frontend/src/components/trap/TrapApp.tsx index c25526d..9f3e779 100644 --- a/frontend/src/components/trap/TrapApp.tsx +++ b/frontend/src/components/trap/TrapApp.tsx @@ -21,7 +21,7 @@ // contribution. The member's contact card is marked backdoored. // ============================================================ -import React, { useState, useMemo } from 'react'; +import React, { useState, useMemo, useRef } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { useNavigationStore, @@ -90,6 +90,8 @@ const TrapApp: React.FC = () => { const [giftQty, setGiftQty] = useState(1); const [showBackdoorConfirm, setShowBackdoorConfirm] = useState(null); const [showMemberStash, setShowMemberStash] = useState(null); + const giftCommitted = useRef(false); + const [giftError, setGiftError] = useState(null); // ── Filtered inventory ───────────────────────────────────── @@ -114,8 +116,10 @@ const TrapApp: React.FC = () => { // ── Gift item to member ──────────────────────────────────── const handleGift = () => { - if (!selectedItem || !giftTarget || giftQty < 1) return; + if (giftCommitted.current || !selectedItem || !giftTarget || giftQty < 1) return; + setGiftError(null); if (giftQty > selectedItem.quantity) { + setGiftError(`You only have ${selectedItem.quantity} of that item.`); addNotification({ type: 'warning', title: 'Not Enough Stock', @@ -125,7 +129,13 @@ const TrapApp: React.FC = () => { }); return; } - transferItemToMember(selectedItem.itemId, giftTarget, giftQty); + giftCommitted.current = true; + if (!transferItemToMember(selectedItem.itemId, giftTarget, giftQty, selectedItem.id)) { + giftCommitted.current = false; + setGiftError(useNotificationStore.getState().notifications[0]?.message + ?? 'The item was not given. Check your stock and crew.'); + return; + } const member = members.find((m) => m.id === giftTarget); addNotification({ type: 'success', @@ -215,13 +225,15 @@ const TrapApp: React.FC = () => { ) : (
- {displayItems.map((item) => ( + {displayItems.map((item, index) => ( { - setSelectedItem(selectedItem?.itemId === item.itemId ? null : item); + giftCommitted.current = false; + setGiftError(null); + setSelectedItem(selectedItem === item ? null : item); setGiftTarget(null); setGiftQty(1); }} @@ -260,6 +272,7 @@ const TrapApp: React.FC = () => { whileTap={{ scale: 0.97 }} onClick={() => { if (selectedItem) { + setGiftError(null); setGiftTarget(giftTarget === m.id ? null : m.id); } else { setShowMemberStash(showMemberStash === m.id ? null : m.id); @@ -305,6 +318,7 @@ const TrapApp: React.FC = () => {
Once given, this item belongs to them. Backdoor to recover.
+ {giftError &&

{giftError}

}