✔ typed durable note calls retain CSRF, business, no-store and response epoch boundaries (6.241333ms)
✔ typed note flag does not disable ordinary idempotency on arbitrary routes (3.800292ms)
✔ old business response is discarded when the active membership changes (1.471125ms)
✔ private calls carry business context but session discovery can detect another-tab switch (0.433583ms)
✔ failed write retains retry id, while an account switch clears it (1.092083ms)
✔ portal requests are independent of staff context changes (0.355792ms)
✔ private image response is discarded across an account switch (0.668041ms)
✔ private image lease is revoked on context change and release is idempotent (1.209ms)
✔ staff switch does not revoke a customer portal image (0.280875ms)
✔ upload retry identity includes bytes, not just endpoint (11.73225ms)
✔ opening another preview does not announce an account switch; login does (1.752458ms)
✔ private PDF arriving after a customer session switch is discarded before download (0.235541ms)
✔ private PDF uses business context and only downloads confirmed PDF responses (20.665083ms)
✔ customer CSV cannot download after an owner business switch (0.1595ms)
✔ customer CSV enforces type and downloads the safe filename with credentials and business scope (1.513375ms)
✔ Week and day navigation cross months, years and UK clocks without shifting dates (15.672458ms)
✔ Midnight endings are exclusive while all-day end dates are inclusive (0.110209ms)
✔ Repeated UK hour shows distinguishable summer and winter clock labels (49.638ms)
✔ matching contacts never select identity; inactive records cannot be transfer choices (2.302916ms)
✔ confirmation uses the exact preview rather than later selection and preserves false acknowledgement (0.094333ms)
✔ export filter is encoded and completion rows contain only explicitly selected exact evidence (0.158583ms)
✔ correction freezes the reviewed body and validates the durable exact outcome (0.487542ms)
✔ retention stores only authenticated ciphertext, no key/text/job/account/URL (21.757875ms)
✔ reopening is locked; same authorized key unlocks after reconnect (2.642083ms)
✔ another exact scope cannot list, claim or decrypt actor ciphertext (1.295167ms)
✔ reload retries same operation after before failure (14.737625ms)
✔ reload retries same operation after after failure (4.956458ms)
✔ concurrent enqueue does not disappear when an older item is acknowledged (2.130583ms)
✔ two tabs cannot concurrently claim one retained note (0.833458ms)
✔ late response after sign-out or switching cannot unlock or acknowledge (3.275583ms)
✔ late unlock result is ignored after access changes (0.467042ms)
✔ expired lease cannot retain, read or send and no reconnect submits work (1.160875ms)
✔ invalid reply preserves note and operation (1.79675ms)
✔ stale reply preserves note and operation (2.59025ms)
✔ denied reply preserves note and operation (1.510583ms)
✔ quota failure never reports retained or sends without a durable sending marker (0.980666ms)
✔ lost correction reply retains both versions and recovers same identity (5.503583ms)
✔ confirmed earlier revision retains proposed correction without duplicate (5.356625ms)
✔ update is blocked while retaining or sending, durable idle notes permit update (2.612916ms)
✔ storage loss is not presented as a successful confirmation (0.52575ms)
✔ key failure preserves ciphertext instead of silently resetting the store (0.889167ms)
✔ late local retention reply keeps one durable identity when editor retries (1.074167ms)
✔ failed local acknowledgement after server commit is safely resolved after reload (1.694667ms)
✔ unavailable IndexedDB denies retention before requesting a key (0.21225ms)
✔ fractional lines round half up in integer pence before subtotal and VAT (0.821167ms)
✔ percentage deposit rounds half up and leaves the exact remaining pence (0.910416ms)
✔ invalid deposit percentages and sub-penny deposits are rejected (0.290375ms)
✔ stage editing cannot silently drop or add a penny (0.350291ms)
✔ opening a saved job and inspecting read-only history leaves editable facts clean (1.627042ms)
✔ job status changes and exact reversion are detected (0.650125ms)
✔ job notes changes and exact reversion are detected (0.20375ms)
✔ job scheduled_date changes and exact reversion are detected (0.164875ms)
✔ private job metadata priority stays protected (0.186291ms)
✔ private job metadata next_action stays protected (0.141459ms)
✔ private job metadata next_action_date stays protected (0.1685ms)
✔ private job metadata last_contact_date stays protected (0.106459ms)
✔ private job metadata completed_date stays protected (0.138416ms)
✔ private job metadata postcode_group stays protected (0.131208ms)
✔ private job metadata archived stays protected (0.69025ms)
✔ private job metadata followup_excluded stays protected (0.04125ms)
✔ valid equivalent tag case, spacing and order are clean; duplicate or invalid tags stay dirty (0.089375ms)
✔ a confirmed save advances only the saved snapshot, including after reopening (0.069958ms)
✔ failed and stale save attempts do not advance a draft baseline (0.647667ms)
✔ successful in-flight save accepts only the submitted values and preserves later text (0.500958ms)
✔ quote values cover each line, VAT, both dates and customer notes (0.238ms)
✔ opening or cancelling a time editor is clean; blank override differs from an explicit zero rate (0.124708ms)
✔ transfer selection, reason and confirmation matter; object property order does not (0.0965ms)
✔ file selections and photo sharing fields remain distinct from viewing a photo (0.071083ms)
✔ clean leave executes immediately without a pending confirmation (7.106542ms)
✔ Keep editing and Escape cancellation execute nothing and preserve the selected draft (0.108875ms)
✔ dirty leave has one owner and repeated requests retain the first intended destination (0.864334ms)
✔ clean repeated clicks and async discard cannot execute twice or start a background action (1.670166ms)
✔ a failed logout exposes its error without changing private draft values (0.576792ms)
✔ an identity reset cancels pending leave and ignores completion from its old context (1.083916ms)
✔ selection rejects unsafe names, empty and oversized files but accepts supported size boundaries (2.799667ms)
✔ real HEIC content is selected without a native browser decoder or a misleading preview (13.783666ms)
✔ HEIF header checks do not accept a renamed non-image or an AVIF brand (0.40025ms)
✔ photo rejection 413 preserves selected bytes and permits a corrected retry (1.108917ms)
✔ photo rejection 415 preserves selected bytes and permits a corrected retry (0.627125ms)
✔ photo rejection 422 preserves selected bytes and permits a corrected retry (0.244ms)
✔ selection checks image signatures instead of trusting extensions or declared MIME (0.110709ms)
✔ visitor sends without cookies; a successful result exposes no receipt or private references (0.366292ms)
✔ concurrent clicks coalesce into one logical request (0.130875ms)
✔ lost response retains exact payload/key; edits are blocked until the unchanged retry succeeds (0.247084ms)
✔ a stalled request times out and retries the identical logical enquiry (11.05325ms)
✔ ambiguous HTTP 408 retains the logical operation (0.635583ms)
✔ ambiguous HTTP 500 retains the logical operation (0.227ms)
✔ ambiguous HTTP 503 retains the logical operation (0.105375ms)
✔ malformed success is uncertain and never produces a successful-looking enquiry (0.21225ms)
✔ validation error allows correction without discarding the selected files or date (0.247ms)
✔ a deliberately separate matching-contact enquiry has a new operation identity (0.128958ms)
✔ public permission defaults to no projection and no rating (0.748083ms)
✔ approved statement retains exact customer text (0.093333ms)
✔ approval requires explicit boolean and nonempty exact fields (0.322041ms)
✔ projection bounds are enforced (0.136416ms)
✔ unconfirmed response does not produce a payload (0.190875ms)
✔ response keeps private answers separate from optional publication (0.176834ms)
✔ all four ratings and recommendation require a deliberate valid choice (0.279125ms)
✔ publication uses the exact current approved preview hash and version (0.175125ms)
✔ the repeated autumn hour requires the selected actual offset (17.786833ms)
✔ spring clock gap and seasonally incorrect offsets are rejected (1.452584ms)
✔ London date and intervals remain the same on a computer in another timezone (0.413292ms)
✔ incomplete, reversed and zero-duration correction inputs are rejected before saving (0.87975ms)
✔ customer price starts blank and no private source details become a document line (0.143959ms)
✔ timer display permits long captures but never negative elapsed time (0.072042ms)
✔ quoted commas, multiline text, escaped quotes, CRLF and blank lines (1.555625ms)
✔ auto mapping and preview require explicit valid prices; no NaN/default repairs (0.395292ms)
✔ column mapping, row limits, reviewed price overrides and invalid costs (0.180875ms)
✔ reopened saved rows and reordered object fields are clean (1.503ms)
✔ equivalent valid price and quantity spellings do not create unsaved changes (1.236292ms)
✔ every catalogue edit is protected and reverting to saved values is clean (0.32275ms)
✔ blank optional prices, zero and invalid numeric input remain distinct (0.418292ms)
✔ job selection, purchasing dates, notes and applied previous-price values are protected (0.426875ms)
✔ supplier reference edits, additions and removals are protected (0.33075ms)
✔ catalogue selection and CSV mapping or programmatic overrides are protected (0.164292ms)
✔ a persisted changed price becomes a clean reopened baseline (0.111291ms)
✔ merge correction selection uses exact IDs and current versions without inferred matches (1.124583ms)
✔ attempt freezes the reviewed selection, explanation and scope independently of edits (0.283125ms)
✔ only the complete exact outcome is accepted for reactivation only (1.276041ms)
✔ only the complete exact outcome is accepted for selected jobs (0.216833ms)
✔ comparison pairs render before then after without changing stored order (1.530917ms)
✔ reorder preserves identity and bounds (0.206334ms)
✔ public drafts and selected photos start with fresh public text (4.717458ms)
✔ response binds to displayed version and saved snapshot with deliberate confirmation (1.853ms)
✔ expired quote cannot produce a response payload (0.883ms)
✔ superseded quote cannot produce a response payload (0.11075ms)
✔ draft quote cannot produce a response payload (0.052458ms)
✔ already accepted quote cannot produce a response payload (0.04925ms)
✔ declined quote cannot produce a response payload (0.071708ms)
✔ missing snapshot review is rejected (0.104917ms)
✔ PDF links remain private and scoped to exact document or stage (0.096042ms)
✔ a preview never requests private draft content without valid matching owner access (2.962375ms)
✔ draft preview loads once under exact owner access; valid checks do not replace its saved content (1.067709ms)
✔ owner context changes clear a loaded preview while customer context changes do not (1.353958ms)
✔ preview invalidates changed owner context slug (2.06175ms)
✔ preview invalidates changed owner context role (2.442ms)
✔ preview invalidates changed owner context membership_id (1.336875ms)
✔ preview invalidates changed owner context csrf (1.737333ms)
✔ unavailable preview validation clears access and does not reload draft content (2.682ms)
✔ logout during an initial draft load prevents its late response from exposing content (5.881125ms)
✔ preview deadline fails closed, coalesces checks and ignores late success (21.903042ms)
✔ closing a preview cancels listeners and ignores a pending load without reporting lost access (19.279666ms)
✔ private gallery preview loads under owner access once and valid checks retain its saved content (13.14725ms)
✔ gallery preview clears all held draft content on owner logout or account broadcast (2.433458ms)
✔ gallery preview clears changed owner business_id (2.137875ms)
✔ gallery preview clears changed owner slug (1.05225ms)
✔ gallery preview clears changed owner role (0.718958ms)
✔ gallery preview clears changed owner membership_id (0.610083ms)
✔ gallery preview clears changed owner csrf (0.569417ms)
✔ gallery preview rejects staff access and an unavailable exact-business project (0.611542ms)
✔ gallery preview cannot reappear from a late private response after access ends (0.595958ms)
✔ gallery preview fails closed when validation is unavailable and leaves no active polling (0.589917ms)
✔ gallery preview deadline ignores late load and closing cancels pending access (1.457167ms)
✔ feedback validation is request-only and valid checks never replace draft inputs (4.650083ms)
✔ contact, transfer and feedback changes revalidate without broadcasting codes or private answers (2.869625ms)
✔ feedback validation failure 401 clears only the request view (3.122042ms)
✔ feedback validation failure 404 clears only the request view (0.909917ms)
✔ feedback validation failure 503 clears only the request view (1.721042ms)
✔ feedback checks coalesce, time out closed and cannot revive a view with a late result (1.132ms)
✔ stopped feedback checks ignore a late rejection and release all timers and listeners (2.917834ms)
✔ portal 401 clears private context and image leases, rejects old work and preserves staff access (2.92275ms)
✔ public credential errors and another customer document 404 do not end a valid portal context (2.147167ms)
✔ focus, visibility and visible periodic checks preserve a valid context without resetting forms (0.970042ms)
✔ owner revoke, reissue, contact update and legacy rotation revalidate without blindly signing out (7.3325ms)
✔ another-tab access notice checks the active account and clears it only when validation fails (142.23175ms)
✔ customer identity changes clear old content even if the browser cookie now authenticates successfully (16.446541ms)
✔ business identity changes clear old content even if the browser cookie now authenticates successfully (2.772333ms)
✔ unreachable validation fails closed and overlapping focus checks coalesce (2.246584ms)
✔ validation deadline clears content and a late successful response cannot restore it (1.444ms)
✔ stopping a watcher removes its deadline and ignores a late successful identity result (1.892583ms)
✔ apiImage clears current portal content on 401 but an old response cannot clear a newer session (2.889833ms)
✔ downloadPrivate clears current portal content on 401 but an old response cannot clear a newer session (2.43275ms)
✔ install verifies every exact asset, never caches HTML navigation, and never forces activation (28.496083ms)
✔ corrupt, missing, redirected and wrong-type shell responses fail installation without touching previous caches (14.269458ms)
✔ all mutations, APIs, private images/documents, queries, ranges and foreign requests bypass cache (5.33125ms)
✔ fresh navigations are network-only; offline and 503 return neutral fallback without recording URL or credentials (13.5135ms)
✔ old hashed bundles coexist; unknown assets are never learned or read from unrelated caches (138.727875ms)
✔ cleanup retains old/unresponsive tabs and removes only our obsolete namespace when all current (1525.249458ms)
✖ updates require every tab to prepare; dirty/uncertain/unresponsive/changed tab sets postpone (0.548ms)
✖ only a deliberate request from a window with all safe responses can activate (0.75375ms)
✔ switching between week and month rules keeps valid explicit choices (2.178541ms)
✔ all-day conversion clears incompatible clock inputs (0.1055ms)
✔ single visit proposal retains original identity and requires fresh acknowledgement (0.069625ms)
✔ booking edits send booleans and exclude server and history fields (0.134083ms)
✔ suggested window is inclusive and bounded through DST (0.128042ms)
✔ month views include leap days and cross-year navigation (0.171417ms)
✔ range rejects reversed or over-62-day windows (0.103292ms)
✔ weekly windows and DST remain London calendar dates (0.059583ms)
✔ excluded placeholder can propose a reviewed single-date override without assuming a booking (0.098334ms)
✔ new request, edited filter, context change and unmount reject late success and failure (0.741708ms)
✔ drills use exact customer/resource IDs and one metric, never matching names or allocating money (0.119166ms)
✔ supporting row pages disclose full totals and do not lose the final partial page (0.690208ms)
✔ exports bind applied filters and exact snapshot, not draft input; time displays exact minutes (0.400166ms)
✔ service enquiry uses only the exact published business service and keeps its canonical title (1.297ms)
✔ reordering is bounded, preserves identities and leaves the saved array untouched (0.863084ms)
✔ new page starts unpublished with independent editable content (3.887917ms)
✔ page and service routes resolve exactly and links retain the business prefix (0.103375ms)
✔ light and dark branding retain a contrasting button text colour (0.091709ms)
✔ draft, timer and in-flight blocks compose and are released independently (0.398958ms)
✔ new requests wait for the bounded update hold without starting or losing work (0.277291ms)
✔ unresolved ordinary saves block updates, reuse their operation ID, and known outcomes clear the block (2.927625ms)
✔ the form safety net detects edited mounted fields, accepts reversal and ignores removed forms (0.193625ms)
✔ registration does not reload on controller change; clean tab holds/release and old protocol is ignored (2.455875ms)
✔ dirty local page refuses update before contacting the worker and leaves current UI intact (0.472542ms)
✔ ready reviews exclude closed, snoozed and ineligible history (0.407458ms)
✔ snooze expiry uses the server effective state (0.085584ms)
✔ only preparation writes a draft and only snooze writes its date (0.621042ms)
✔ review confirmation is not inferred from a filled draft (0.092667ms)
✔ tag input retains duplicates for server validation (0.414583ms)
✔ all established workspace labels remain reachable alongside new sections (0.294041ms)
ℹ tests 210
ℹ suites 0
ℹ pass 208
ℹ fail 2
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 2030.934417

✖ failing tests:

test at src/pwa-worker.test.js:83:1
✖ updates require every tab to prepare; dirty/uncertain/unresponsive/changed tab sets postpone (0.548ms)
  Error: ENOENT: no such file or directory, open '/private/tmp/shs-v25-source/frontend/dist/assets/index-j9ihlpBS.js'
      at async open (node:internal/fs/promises:1345:25)
      at async readFile (node:internal/fs/promises:2003:14)
      at async fixture (file:///private/tmp/shs-v25-source/frontend/src/pwa-worker.test.js:13:55)
      at async TestContext.<anonymous> (file:///private/tmp/shs-v25-source/frontend/src/pwa-worker.test.js:84:44)
      at async Test.run (node:internal/test_runner/test:1409:7)
      at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
    errno: -2,
    code: 'ENOENT',
    syscall: 'open',
    path: '/private/tmp/shs-v25-source/frontend/dist/assets/index-j9ihlpBS.js'
  }

test at src/pwa-worker.test.js:88:1
✖ only a deliberate request from a window with all safe responses can activate (0.75375ms)
  Error: ENOENT: no such file or directory, open '/private/tmp/shs-v25-source/frontend/dist/assets/index-j9ihlpBS.js'
      at async open (node:internal/fs/promises:1345:25)
      at async readFile (node:internal/fs/promises:2003:14)
      at async fixture (file:///private/tmp/shs-v25-source/frontend/src/pwa-worker.test.js:13:55)
      at async TestContext.<anonymous> (file:///private/tmp/shs-v25-source/frontend/src/pwa-worker.test.js:89:11)
      at async Test.run (node:internal/test_runner/test:1409:7)
      at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
    errno: -2,
    code: 'ENOENT',
    syscall: 'open',
    path: '/private/tmp/shs-v25-source/frontend/dist/assets/index-j9ihlpBS.js'
  }
