From 9ee6a915c949beda870003a04ba65fd4d40ad1d2 Mon Sep 17 00:00:00 2001 From: NewWorldVenture Date: Fri, 9 Oct 2026 13:13:36 -0400 Subject: [PATCH] Preserve calendar edit timestamps and exact supported-year time conversions --- components/i18n/use-format.ts | 6 +- components/modules/calendar-module.tsx | 4 +- finalaudit.md | 50 +++-- lib/briefing/calendar-window.ts | 5 +- lib/schedule/zoned.ts | 6 +- lib/time/local-input.ts | 17 +- lib/time/zoned.ts | 31 ++- ...gnores-the-devices-daylight-saving.test.ts | 2 +- ...date-handoff-keeps-supported-years.test.ts | 91 ++++++++ ...lendar-window-normalization-domain.test.ts | 202 ++++++++++++++++++ .../e2e/local-input-unchanged-instant.spec.ts | 76 +++++++ ...endar-event-leaves-it-where-it-was.test.ts | 8 +- tests/local-input-unchanged-instant.test.ts | 154 +++++++++++++ tests/schedule-zoned-clock-contracts.test.ts | 121 +++++++++++ tests/time-zoned-offset-seconds.test.ts | 174 +++++++++++++++ 15 files changed, 911 insertions(+), 36 deletions(-) create mode 100644 tests/calendar-date-handoff-keeps-supported-years.test.ts create mode 100644 tests/calendar-window-normalization-domain.test.ts create mode 100644 tests/e2e/local-input-unchanged-instant.spec.ts create mode 100644 tests/local-input-unchanged-instant.test.ts create mode 100644 tests/schedule-zoned-clock-contracts.test.ts create mode 100644 tests/time-zoned-offset-seconds.test.ts diff --git a/components/i18n/use-format.ts b/components/i18n/use-format.ts index fa072b041..b81710968 100644 --- a/components/i18n/use-format.ts +++ b/components/i18n/use-format.ts @@ -194,7 +194,11 @@ export function useFamilyClock(): FamilyClock { /** A `YYYY-MM-DD` day key as the local-calendar Date the date-only helpers read. */ export function calendarDayOfKey(key: string): Date { const [y, m, d] = key.split('-').map(Number); - return new Date(y, m - 1, d); + if (!Number.isInteger(y) || y < 1 || y > 9999) return new Date(y, m - 1, d); + const date = new Date(0); + date.setFullYear(y, m - 1, d); + date.setHours(0, 0, 0, 0); + return date; } /** diff --git a/components/modules/calendar-module.tsx b/components/modules/calendar-module.tsx index 42b350578..f6bc3d897 100644 --- a/components/modules/calendar-module.tsx +++ b/components/modules/calendar-module.tsx @@ -1071,8 +1071,8 @@ function NewEventModal({ existing, onClose, onSaved }: { // device skips (its own DST gap) moves (#688 comment 5922125002). // `eventSchema` already rejected a blank start, so the `?? ''` is for the // type and cannot fire. - const startsAt = fromLocalInput(parsed.data.starts_at, timeZone) ?? ''; - const endsAt = fromLocalInput(parsed.data.ends_at, timeZone) ?? null; + const startsAt = fromLocalInput(parsed.data.starts_at, timeZone, existing?.starts_at) ?? ''; + const endsAt = fromLocalInput(parsed.data.ends_at, timeZone, existing?.ends_at) ?? null; // End must be after start when both are provided. if (endsAt && new Date(endsAt) <= new Date(startsAt)) { setErrors({ ends_at: tr('calendarModule.endAfterStart') }); diff --git a/finalaudit.md b/finalaudit.md index eba1c98b3..025bb41f4 100644 --- a/finalaudit.md +++ b/finalaudit.md @@ -1,4 +1,20 @@ # Final Production Audit +## In-progress documentation and five reviewed fixes prepared for publication — 2026-10-09T17:06:32.207Z + +Last Updated:2026-10-09T17:06:32.207Z. Root-owned isolated branchcodex/calendar-ip-fixes-20261009 starts from main46abfa249be63525444ec6624a530f81d35978e3. Clock invalid/UTC formatting, final normalized UTC domain validation, supported-year DATE handoff, exact historical offset-second resolution, and unchanged calendar edit timestamp/fold/precision preservation are integrated there. Actual installed combined118completefiles2904PASS/noFAIL/noSKIP in EACHUTC/LA/Tokyo, full project typesPASS and changed-source/new-tests lintPASS; frozen operation9b4fdf123b808face3dc210835d40cda5ccd81fbaef59162e92712ed714d18f0. Independent strict-hint32native, historical64native and DATE209 checksPASS; rejected optional-hint v1 remainsuninstalled. Six lasting files inventoried with bounded full-test scope, no complete test markedclosed before fresh exact committed-head CI/build/browser/Auth/database/owned cleanup. + +The source is prepared for a normal PR; merge and production source readback are pending. Original shared49be source unchanged; sole dirty root file isfinalaudit. Five completed original closures are already published on main46ab. Remaining full original services/UI scopes are explicit: schedule today/invalid-domain policy, time helper layout/date-input/midnight/role workflows, calendar/Auth/RLS lifecycle, and a NEW confirmed second-scale gap in whole-clock normalization(Colombo1880 +8s,Caracas1890 +4s). General historical minute drift is repaired, while that validseconds-after-gap case remainsRED f6e3af9. No closure is awarded to broad rows from narrow helper checks. Production00361 source was verified earlier; no subsequent docs/source revision is claimedserved. + +Counts14,735 =11,566 NOT STARTED +2,815 IN PROGRESS +187 PASS +161 FIXEDPASS +6 BLOCKED;348verifiedclosed(2.36%),zero blockedcredit. Three additional permanent repository files raise inventory; original IDs/order/status/history retained. PRODUCTION READY:NO; SEC001 privacy/schema/config/provider gates remain separate. Preserved migration map runnable451/highwater0476/next0477/held0488/0490/0492–0494. No production config/DDL/provider/money execution. + +## In-progress findings reproduced and three fixes integrated in isolated candidate — 2026-10-09T16:50:31.128Z + +Last Updated: 2026-10-09T16:50:31.128Z. Root-owned branchcodex/calendar-ip-fixes-20261009 under G:/Bubaly-migration-20261008/receipts/calendar-ip-fixes-release-20261009/source starts from documentation main46abfa249be63525444ec6624a530f81d35978e3. Clock formatting, final normalized-instant domain admission and supported-year DATE handoff fixes are integrated there, with three lasting regression files inventoried below. Actual combined63files1801PASS/noFAIL/noSKIP eachUTC/LA/Tokyo and full project typesPASS. They are UNCOMMITTED/UNRELEASED at this checkpoint; main/source production readiness is not inferred. Root original worktree remains49be with onlyauditdirty. Prior publication46ab preserved verified runtime00361; no later docs revision is claimed served. + +Full schedule helper staysIP for today/AD0/civil-time policy; briefing normalizer staysIP for historicalIANA-second drift; full wall/TIME003 and formatcomponent consumer workflows remain open. Untouched calendar fold/precision drift is reproduced by native helpers and caller composition. Its first optional-original hint proposal is under HOLD after independent malformed/nonabsolute timestamp counterexamples, before root integration; original two-argument grammar/fold policy must remain unchanged. These are specific fixes/remaining tests, not closures of the entire services or UI. Production schema/configuration, provider and RLS claims remain separate. + +Counts:14,732 =11,566 NOT STARTED +2,812 IN PROGRESS +187 PASS +161 FIXEDPASS +6 BLOCKED;348 verified closures(2.36%). Three newly authored owned repository regression files increase inventory; no new closure credit or blocked credit. PRODUCTION READY:NO. Original statuses/order/history preserved; new permanent IDs9285EEEF0F4C/E1F850EBB1FE/3752656BDF3E correspond to complete45/74/38-test files. Source candidate1801 proof78de8e1328e26455744ba5840ef4de640d6f4c5742490dadcc594638a62f9086; exact review/raw/source hashes and preserved preparation/expectation failures remain under G receipts. Normal productionconfig/DDL/provider/money and reserved migration451/highwater0476/next0477/holds0488/0490/0492–0494 unchanged. + ## Three billing in-progress rows refreshed; clock repair qualified — 2026-10-09T15:53:57.469Z Last Updated: 2026-10-09T15:53:57.469Z. SUPPORT-7758D5A9AD48, SUPPORT-D2428C6C4B2E and SUPPORT-3A3D4CFE3122 retain their full original calendar/history/bill/rail/production-installation scope and IN PROGRESS status. Current Tests/Fix/Retest now replace stale Node24.19-only, Docker-readiness/ECONNREFUSED/all14SKIP and collected-only old/modern browser descriptions with genuine current49be Node24.21 acceptance: owned DockerPG17/PostgREST16.4 realSDK/HTTP14PASS, relayclosed/labelguardeddeleteSUCCESS, plus separate realGoTrue/ownedPG15 old+modern browser accepted on firstattempt and actual ownedstop. Historic fields and earlier failed runs remain explicitly dated history. No fixture modeledAuth or public anonymous source-smoke is transferred to full productionRLS/private-finance acceptance. Remaining exact gates are rail raw-loader/authenticated-history fullstack verification and separately authorized productioncatalog/policy/held0488 installation, preserving main reserved allocations. @@ -2498,15 +2514,15 @@ The TLS problem was a missing Node system-CA setting, not a reason to disable ce - Current2026-10-08 source-foundation inventory adds ten retained file obligations, all IN PROGRESS;14,571 unique rows,344 historical closures, no closure credit. Older dated recount explanations below remain historical. - Recounted row by row on 2026-10-04 from Register B itself (`node scripts/audit-register-counts.mjs`; `tests/the-audit-summary-counts-its-register.test.ts` now fails when this section and the rows disagree). The register holds 14,538 unique IDs with no duplicates and no unrecognised status. The previous 11,701 NOT STARTED / 2,484 IN PROGRESS tally predated LIBRARY-2E628A2A31CE's evidenced move from NOT STARTED to IN PROGRESS; the 15:39 UTC checkpoint already carried 11,700 / 2,485, and the rows confirm it. -- Total Audit Items: **14,729**. Prior count explanations are preserved in the dated status summary below. +- Total Audit Items: **14,735**. Prior count explanations are preserved in the dated status summary below. - Not Started: **11,566**. Recounted on 2026-10-09 after relationship/source inventory reconciliation; prior dated tallies remain below. -- In Progress: **2,809**. Recounted on 2026-10-09 after relationship/source inventory reconciliation; prior dated tallies remain below. +- In Progress: **2,815**. Recounted on 2026-10-09 after relationship/source inventory reconciliation; prior dated tallies remain below. - Passed: **187**. Prior count explanations are preserved in the dated status summary below. - Fixed + Passed: **161**. Prior count explanations are preserved in the dated status summary below. - Blocked: **6**. Prior count explanations are preserved in the dated status summary below. - Failed: **0 register rows**. SEC-001 production privacy remains **FAIL**. The earlier Mobile failure on bf8063e7/10df62eb is retained; its repaired aa5b84b9 candidate passed all hosted gates and merged as bc147c76. This is not a production-readiness declaration. -- Verified closure coverage: **2.36%** (348/14,729); five full original-scope corrective/test obligations closed 2026-10-09T15:45:41.083Z; zero blocked credit pending eligibility review. -- Overall Completion under the adopted target: **2.36% credited**, calculated as ((PASS + FIXED_PASS + eligible_external_BLOCKED) / Total) ×100, with zero blocked items credited. If all six qualify, coverage would be2.40%; that credit has not been awarded. Prior stale2.34% with343 closures corrected in this recount. +- Verified closure coverage: **2.36%** (348/14,735); five published original-scope closures retained; six owned regression files now IN PROGRESS pending exact-head hosted acceptance; zero blocked credit. +- Overall Completion under the adopted target: **2.36% credited**, using348 PASS/FIXEDPASS and zero eligible_external_BLOCKED credit out of14,735. If all six external blockers qualify, coverage would be2.40%; no such credit is awarded. ## Current source audit checkpoint — 2026-10-03 15:37 UTC, Codex/root review coordination @@ -10509,7 +10525,7 @@ not read the same on this page.* hosted-CI/deployed-release evidence this session had no credentials to produce. The two share zero finding IDs. Neither is discarded. --> -# Register B - parallel session inventory (14,729 items) +# Register B - parallel session inventory (14,735 items) - PROD-ENV (owner, measured 2026-09-26 19:13Z): production's `/api/health` reports `CRON_SECRET`, `CHILD_LOGIN_SECRET`, `MARKETING_UNSUB_SECRET` and `GUARDIAN_INTERNAL_SECRET` unset. Per `lib/health/status.ts`, `hasCronAuthorization` is fail-closed, so without `CRON_SECRET` every one of the 24 scheduled jobs in `vercel.json` answers 401 (nightly notifications, wallet allowance, chore reminders, the weekly digest, …); without `CHILD_LOGIN_SECRET` no child in any family can sign in; the other two gate provider ingress and signed links and fail closed. Setting them in the Vercel production environment is the owner's action; the four `ENV-*` rows are BLOCKED on it. Also unset, per the same check: `RESEND_API_KEY`, `INTERNAL_SECRET`, `CONTACT_CENTER_INBOUND_SECRET` were NOT in the missing list, so those are set. > Current reconciliation: the following dated PROD-DB-0177 narrative is retained as historical evidence, not a current operator plan. Later read-only metadata found some later schema effects despite absent history; its blanket "none applied" claim is superseded. Do not execute the historical timeout/repair/backlog instructions under this audit authorization. Bounded history/effect reconciliation and explicit production-operation authorization remain separate requirements. - PROD-DB-0177 (owner, measured 2026-09-27 01:15Z on the replayed schema; the failure itself recorded by the #579 session from the owner's "Supabase production migrations" runs on `533554be`, `7e54596d` and `671c5f6a`): production's migration ledger stops at `0176`, so **none of 0177–0387 is applied** and every boundary those migrations close is held in production only by application code. The cause is one statement: `0177_remove_synthetic_auth_users.sql` is a single `DO` block that, for EVERY single-column foreign key to `auth.users`, runs `delete from where = any()`. On the replayed schema that is **493** foreign keys, **481** of them with no index on the referencing column, so the block is hundreds of sequential scans inside one statement and Supabase's `statement_timeout` cancels it (SQLSTATE 57014) — production at 0176 has fewer keys but the same shape. It is idempotent and best-effort by design (a per-table failure is noticed and skipped), so it is safe to run outside the workflow. **The operator remedy, in order**: (1) in the Supabase SQL editor or `psql` against production, `set statement_timeout = 0;` (session-local) and run the body of 0177 once — expect the `Retired synthetic Auth users: N removed, M still referenced` notice; (2) `supabase migration repair --status applied 0177` so the ledger agrees; (3) re-run the "Supabase production migrations" workflow, which will then apply 0178 onward in order (each already replayed by CI on a fresh database). Alternatively delete the `onb…@seed-onb.bubaly.test` / `person…@seed.bubaly.test` users through the Auth admin API first, which makes 0177 a no-op, then repair and re-run. **No agent applied, retried or altered how the workflow applies anything**, and none will: applying migrations to production is the owner's action, and a change that made 0177 pass inside the workflow would apply 0178–0387 on the next push to `main` by proxy. Until this is done, `PRODUCTION READY` cannot move, whatever the code says. @@ -15920,7 +15936,7 @@ not read the same on this page.* | CONTROL-0D7B0F500ED2 | CONTROL | button at line 101 | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | | CONTROL-FB4D0AC3315F | CONTROL | Link at line 112 | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | | CONTROL-ECF4AFEB5D64 | CONTROL | Link at line 113 | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | -| COMPONENT-58F072E654BC | COMPONENT | components/modules/calendar-module.tsx | 🔄 IN PROGRESS | Medium | #796 original actual callbacks three failures/four controls; published actual React19 browser ten pass, including year/leap boundaries and family recurrence | Draft #796 24b9b5eb4f6ee788456ac4cc0eefa33909f594b1: adjacent-month first Monday and matching mini-calendar labels; source 81d46fab | Author 162 tests/six files in Windows forks, types/lint pass; root mounted browser ten pass e0601f | Scoped navigation acceptance only; CSS/responsive, Auth, database/provider and complete calendar workflow remain open. | +| COMPONENT-58F072E654BC | COMPONENT | components/modules/calendar-module.tsx | 🔄 IN PROGRESS | Medium | Full calendar module scope retained; unchanged event title edit now keeps each original timestamp/fold/precision, including valid fold-spanning start/end. | Only matching existing?.starts_at/ends_at passed into new strict optional hint gate; actor/family authority remains server-owned. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim. Actual extracted modal/native DOM18PASS with synthetic boundaries, zero console/page warnings in those fixtures. | Current five-fix checkpoint2026-10-09T17:06:32.207Z:Keep full page/module IP; existing lifecycle/recurrence/provider/role/persistence/time-boundary/midnight/layout obligations remain. New scalar short-gap followup is separate. No source or action authorization loosened. Historical cells preserved before 2026-10-09T17:06:32.207Z: Tests=#796 original actual callbacks three failures/four controls; published actual React19 browser ten pass, including year/leap boundaries and family recurrence; Fix=Draft #796 24b9b5eb4f6ee788456ac4cc0eefa33909f594b1: adjacent-month first Monday and matching mini-calendar labels; source 81d46fab; Retest=Author 162 tests/six files in Windows forks, types/lint pass; root mounted browser ten pass e0601f. Historical notes retained:Scoped navigation acceptance only; CSS/responsive, Auth, database/provider and complete calendar workflow remain open. | | CONTROL-9023A06A37DD | CONTROL | button at line 116 | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | | CONTROL-48D00564720F | CONTROL | button at line 117 | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | | CONTROL-64895819FC56 | CONTROL | button at line 129 | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | @@ -20243,7 +20259,7 @@ not read the same on this page.* | LIBRARY-22A01E69B766 | LIBRARY | lib/blog/search-index-loader.ts | 🔄 IN PROGRESS | Medium | 709 retained independent62-case source/client/cache suite and exact candidate CI36794014420; bounded public search/filter/reset/empty receipt at4ae | Shared client loader distinguishes failed index reads from valid empty results, with bounded retry ownership | Scoped synthetic and public interaction dimensions pass; full lifecycle/network acceptance pending | Discovered shipped helper from709; canonical SHA256 path ID, linked to existing API-9158428527C6 and LIBRARY-60DCC5C37007, not a duplicate logical workflow. Public Chromium149 desktop/phone dimensions are qualified above; client fetch/body deadline and all outage/browser-navigation/device/accessibility states are not certified. | | LIBRARY-6B129F7404FB | LIBRARY | lib/briefing/build.ts | 🔄 IN PROGRESS | Unassessed | Pending | Briefing adoption: seven engine suites156 and twenty-two caller/related suites699 PASS each UTC/LA/Tokyo; independent36 controls per zone. | Synthetic scope; source capability false. Remaining conflict/cards/export/replay, schema installation and production acceptance held. | Frozen receipts and selected352-suite 6865PASS UTC reconciled; no closure credit. | | LIBRARY-2F721B344497 | LIBRARY | lib/briefing/cache-isolation.ts | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | -| LIBRARY-55A8599007F2 | LIBRARY | lib/briefing/calendar-window.ts | 🔄 IN PROGRESS | Unassessed | Complete file-level scope retained; supported-domain regression subset accepted but whole obligation not closed. Lower/upper-domain defects are repaired and deployed with strong causal evidence, but this review has not completed every exported formatter/normalizer/open-window contract and dependent raw-clock admission scope. Do not equate supported-boundary subset to complete file-level acceptance. Eligible for a separate full pure-helper closure review without requiring unrelated provider work. | Scoped Gregorian/boundary/read-order repair installed49be/00361; remaining exported/consumer/source-activation obligations need complete acceptance. | Next closure gate: Lower/upper-domain defects are repaired and deployed with strong causal evidence, but this review has not completed every exported formatter/normalizer/open-window contract and dependent raw-clock admission scope. Do not equate supported-boundary subset to complete file-level acceptance. Eligible for a separate full pure-helper closure review without requiring unrelated provider work. Review3f694c30; provider/production/RLS and held source activation receive no synthetic credit. | Current closure review 2026-10-09T15:45:41.083Z: Keep IN PROGRESS, no closure credit. Full original scope independently read; Lower/upper-domain defects are repaired and deployed with strong causal evidence, but this review has not completed every exported formatter/normalizer/open-window contract and dependent raw-clock admission scope. Do not equate supported-boundary subset to complete file-level acceptance. Eligible for a separate full pure-helper closure review without requiring unrelated provider work. Historical cells preserved before 2026-10-09T15:45:41.083Z: Tests=Pending; Fix=None; Retest=Pending. Historical notes retained: Current cycle 2026-10-08: Bounded pure-helper review found a preexisting lower-supported-year defect: briefingCalendarBounds(0001-01-01,UTC,0,1) rejects because the BCE search bracket loses era information. Year1Jan2 healthy control passes; no modern-date or current9file causality is claimed. Witness retained in pure-calendar-helper-eligibility-20261008; repair/retest outstanding. Full-item status remains IN PROGRESS. Later isolated cycle2026-10-09UTC: Year-boundary proposal remains isolated. Original copied modules58PASS/8RED; firstcandidate66PASS perzone. Broader independent combined peer84PASS/2RED perUTC/Los_Angeles/Tokyo: upper exclusive DATE emits +010000-01 and minimum-year overlap fallback crosses formatter domain. Every final childVitest exits1. No integration, domain closure or appPASS. Current root cycle2026-10-09UTC: claimed on owned main-c67 branch codex/calendar-worker-boundaries-20261009 before integration. Private supported-year evidence is not installed acceptance: AD1 wall constructor maps1901, local input loses zero-padding, and one-hour query lookback emits year0 in native/school/sports filters; strict installed-SDK synthetic rejection reproduces db refusal. Complete extension and independent regression review are in progress. Public AD1..9999/119 validation and family authorization are unchanged. Full workflow/hosted acceptance remains open; no closure credit. Root local acceptance2026-10-09UTC: complete calendar/worker fix is now integrated on owned main-c67 branch. Exact shared15source/test pins pass2668tests/noSKIP/noFAIL in eachUTC/LosAngeles/Tokyo, full project types and lint, plus audit reconciliation. New calendar fixture uses canonical minimum .000Z so the lexical transport cannot hide strict-vs-inclusive lower-edge mistakes. Permanent API spies prove refusal before factory and context-family filters; mocked Auth is not RLS acceptance. Worker86 inherited/new controls and60 native promise-boundary probes support cancellation/cleanup repair; real provider activation remains off. Fresh hosted build/browser/Auth/database and deployment gates are still pending; full-item status remains IN PROGRESS and no closure credit. | +| LIBRARY-55A8599007F2 | LIBRARY | lib/briefing/calendar-window.ts | 🔄 IN PROGRESS | Unassessed | All8exports and native/SDK raw/expanded normalization checked. Final UTC domain validation and historical IANA offset-second drift corrected in owned candidate. | 7d023556 normalizer +86cefc0c resolver installed; existing grammar/fractions/offset policy retained. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim. Supplemental9SDKcasesPASS×3/original6RED and independent64nativePASS×3. | Current five-fix checkpoint2026-10-09T17:06:32.207Z:Keep full row IP: narrow second-scale gap remains independently RED in valid Colombo1880 00:00:42→00:00:50 and Caracas1890→00:00:46. f6e3af9 documents minute-first normalization plus later seconds. Prior general historical drift0f042 is corrected by86ce; original evidence retained. Separate whole-clock repair in progress, not installed. Historical cells preserved before 2026-10-09T17:06:32.207Z: Tests=All8exports inspected. Original normalization can produce AD0 and raw searchEvents(expandSeries:false) can send it to SDK; expanded normalizer bounds reparse safely. Historical IANA offset seconds remain inaccurate.; Fix=Candidate7d023556 adds existing parseExactInstant validation to both final UTC normalization branches; grammar/fractions/offset policy unchanged.; Retest=New74+23 related677PASS×3; original68PASS6RED,7mutants fail; independent31PASS×3/12baselineRED/floating8RED/absolute4RED. Combined1801PASS×3/full typesPASS. Historical seconds drift remains RED in original/candidate; full row remains IP.. Historical notes retained:Current candidate review 2026-10-09T16:50:31.128Z: Isolated owned candidate only:1801 assertions across63 complete files PASS/noSKIP/noFAIL in eachUTC/LA/Tokyo; full project typesPASS. Source is not committed, hosted or released at this checkpoint. Fresh candidate build/lint/CI and exact production-source readback remain required. Full-scope hold6a719 preserves earlier0487 conditional-closure overstatement. Native38 fraction controlsPASS, historicalNYAD1/99 andKathmandu1900 drift preserved0f042; no productionAuth/RLS leak claim. Original scopes read through RegisterB parser. Historical cells preserved before 2026-10-09T16:50:31.128Z: Tests=Complete file-level scope retained; supported-domain regression subset accepted but whole obligation not closed. Lower/upper-domain defects are repaired and deployed with strong causal evidence, but this review has not completed every exported formatter/normalizer/open-window contract and dependent raw-clock admission scope. Do not equate supported-boundary subset to complete file-level acceptance. Eligible for a separate full pure-helper closure review without requiring unrelated provider work.; Fix=Scoped Gregorian/boundary/read-order repair installed49be/00361; remaining exported/consumer/source-activation obligations need complete acceptance.; Retest=Next closure gate: Lower/upper-domain defects are repaired and deployed with strong causal evidence, but this review has not completed every exported formatter/normalizer/open-window contract and dependent raw-clock admission scope. Do not equate supported-boundary subset to complete file-level acceptance. Eligible for a separate full pure-helper closure review without requiring unrelated provider work. Review3f694c30; provider/production/RLS and held source activation receive no synthetic credit.. Historical notes retained: Current closure review 2026-10-09T15:45:41.083Z: Keep IN PROGRESS, no closure credit. Full original scope independently read; Lower/upper-domain defects are repaired and deployed with strong causal evidence, but this review has not completed every exported formatter/normalizer/open-window contract and dependent raw-clock admission scope. Do not equate supported-boundary subset to complete file-level acceptance. Eligible for a separate full pure-helper closure review without requiring unrelated provider work. Historical cells preserved before 2026-10-09T15:45:41.083Z: Tests=Pending; Fix=None; Retest=Pending. Historical notes retained: Current cycle 2026-10-08: Bounded pure-helper review found a preexisting lower-supported-year defect: briefingCalendarBounds(0001-01-01,UTC,0,1) rejects because the BCE search bracket loses era information. Year1Jan2 healthy control passes; no modern-date or current9file causality is claimed. Witness retained in pure-calendar-helper-eligibility-20261008; repair/retest outstanding. Full-item status remains IN PROGRESS. Later isolated cycle2026-10-09UTC: Year-boundary proposal remains isolated. Original copied modules58PASS/8RED; firstcandidate66PASS perzone. Broader independent combined peer84PASS/2RED perUTC/Los_Angeles/Tokyo: upper exclusive DATE emits +010000-01 and minimum-year overlap fallback crosses formatter domain. Every final childVitest exits1. No integration, domain closure or appPASS. Current root cycle2026-10-09UTC: claimed on owned main-c67 branch codex/calendar-worker-boundaries-20261009 before integration. Private supported-year evidence is not installed acceptance: AD1 wall constructor maps1901, local input loses zero-padding, and one-hour query lookback emits year0 in native/school/sports filters; strict installed-SDK synthetic rejection reproduces db refusal. Complete extension and independent regression review are in progress. Public AD1..9999/119 validation and family authorization are unchanged. Full workflow/hosted acceptance remains open; no closure credit. Root local acceptance2026-10-09UTC: complete calendar/worker fix is now integrated on owned main-c67 branch. Exact shared15source/test pins pass2668tests/noSKIP/noFAIL in eachUTC/LosAngeles/Tokyo, full project types and lint, plus audit reconciliation. New calendar fixture uses canonical minimum .000Z so the lexical transport cannot hide strict-vs-inclusive lower-edge mistakes. Permanent API spies prove refusal before factory and context-family filters; mocked Auth is not RLS acceptance. Worker86 inherited/new controls and60 native promise-boundary probes support cancellation/cleanup repair; real provider activation remains off. Fresh hosted build/browser/Auth/database and deployment gates are still pending; full-item status remains IN PROGRESS and no closure credit. | | LIBRARY-3B6E2F78C25A | LIBRARY | lib/briefing/decisions.ts | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | | LIBRARY-0EC3959FCAA5 | LIBRARY | lib/briefing/deliver.ts | 🔄 IN PROGRESS | Unassessed | Pending | Briefing adoption: seven engine suites156 and twenty-two caller/related suites699 PASS each UTC/LA/Tokyo; independent36 controls per zone. | Synthetic scope; source capability false. Remaining conflict/cards/export/replay, schema installation and production acceptance held. | Frozen receipts and selected352-suite 6865PASS UTC reconciled; no closure credit. | | LIBRARY-ED1A9CA3C11B | LIBRARY | lib/briefing/response-schema.ts | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | @@ -20654,7 +20670,7 @@ not read the same on this page.* | LIBRARY-0BE489B37606 | LIBRARY | lib/routines/detect.ts | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | | LIBRARY-39B3A2472810 | LIBRARY | lib/schedule/intelligence-server.ts | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | | LIBRARY-773D143576D6 | LIBRARY | lib/schedule/intelligence.ts | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | -| LIBRARY-E6A19A80898B | LIBRARY | lib/schedule/zoned.ts | 🔄 IN PROGRESS | Unassessed | Complete schedule helper obligation retained. Clock-only documented empty-on-unparseable and valid-Date UTC fallback have a private reviewed repair; today/DATE-domain/two-pass policy obligations remain open. | PRIVATE/UNINSTALLED candidate87eff58b validates one Date before Intl/fallback and formats padded UTC fields without ISO year-offset slicing. Only clockInZone changes; all neighboring exports byte-identical. | Actual private baseline/exact reversion37PASS8RED; proposed45 lasting cases plus40 unchanged permanent files1200PASS/noSKIP/noFAIL in UTC/LosAngeles/Tokyo underNode24.21. Independent11 actual-source controlsPASS eachzone; admission/slice/device-zone causal mutants fail. Scoped stricttypes/lint pass. Integrate on owned branch and require fresh final-source CI/production acceptance before claiming installed repair; whole today invalid-supplied-clock/unsupportedAD0 and legacy two-pass policy still require complete specification/acceptance. | Current followup 2026-10-09T15:53:57.469Z: Original installed sourceb018 still retains clock defect; private proposal.patch5c72ce4c/review2571734f and independentreviewf715c7eb are accepted within clock-only scope. First copied-location42ENOENT failures perzone retained and explained; corrected fixtures use actual original paths, without counting harness failure as product defect. Mandatory clocks never readDate.now; invalid input returns empty, unusable IANA fallback usesUTC minute fields even for signed/extended Dateyears. todayInZone explicit invalidclock stillthrowsRangeError and AD0fallback0000-12-31 remains a whole-module hold; no current-clock substitution/domain-policy invention. No full-module, Auth/RLS/provider or production reachability closure. Historical cells preserved before 2026-10-09T15:53:57.469Z: Tests=Complete file-level scope retained; supported-domain regression subset accepted but whole obligation not closed. Whole helper file includes clockInZone/todayInZone/zonedTimeMs beyond repaired dayKeyInZone. Actual current clockInZone finite out-of-Date-range fallback violates documented empty-on-unparseable contract (two RED/three healthy refusal/control PASS). No demonstrated production reachability; retained pure source gap must not be hidden by closing the day-key subset.; Fix=Deployed day-key domain repair accepted; separate clockInZone invalid-Date fallback throws RangeError. Private clock proposal under retest; UNINSTALLED.; Retest=Next closure gate: Whole helper file includes clockInZone/todayInZone/zonedTimeMs beyond repaired dayKeyInZone. Actual current clockInZone finite out-of-Date-range fallback violates documented empty-on-unparseable contract (two RED/three healthy refusal/control PASS). No demonstrated production reachability; retained pure source gap must not be hidden by closing the day-key subset. Review3f694c30; provider/production/RLS and held source activation receive no synthetic credit.. Historical notes retained: Current closure review 2026-10-09T15:45:41.083Z: Keep IN PROGRESS, no closure credit. Full original scope independently read; Whole helper file includes clockInZone/todayInZone/zonedTimeMs beyond repaired dayKeyInZone. Actual current clockInZone finite out-of-Date-range fallback violates documented empty-on-unparseable contract (two RED/three healthy refusal/control PASS). No demonstrated production reachability; retained pure source gap must not be hidden by closing the day-key subset. Current installed source pure clock receipt603883e5:2RED/3PASS; finite out-of-Date-range clock expected empty throwsRangeError, including invalid IANA fallback. No production reachability established. Historical cells preserved before 2026-10-09T15:45:41.083Z: Tests=Pending; Fix=None; Retest=Pending. Historical notes retained: Current root cycle2026-10-09UTC: claimed on owned main-c67 branch codex/calendar-worker-boundaries-20261009 before integration. Private supported-year evidence is not installed acceptance: AD1 wall constructor maps1901, local input loses zero-padding, and one-hour query lookback emits year0 in native/school/sports filters; strict installed-SDK synthetic rejection reproduces db refusal. Complete extension and independent regression review are in progress. Public AD1..9999/119 validation and family authorization are unchanged. Full workflow/hosted acceptance remains open; no closure credit. Root local acceptance2026-10-09UTC: complete calendar/worker fix is now integrated on owned main-c67 branch. Exact shared15source/test pins pass2668tests/noSKIP/noFAIL in eachUTC/LosAngeles/Tokyo, full project types and lint, plus audit reconciliation. New calendar fixture uses canonical minimum .000Z so the lexical transport cannot hide strict-vs-inclusive lower-edge mistakes. Permanent API spies prove refusal before factory and context-family filters; mocked Auth is not RLS acceptance. Worker86 inherited/new controls and60 native promise-boundary probes support cancellation/cleanup repair; real provider activation remains off. Fresh hosted build/browser/Auth/database and deployment gates are still pending; full-item status remains IN PROGRESS and no closure credit. PR978 source49be/tree15566 normally merged as 00361e9de5b7ed1899c8a9513c5286747729b6bf; exact current-head terminal CI accepted with ordered three-zone unit reports, build/types, genuine browser/Auth and owned-stack cleanup. Canonical production revision and anonymous cache/login/redirect contracts independently verified; production receipt 97e740efc87021f1ab52c061112cfcca37ba4693f477e188c94766c27d8b9dd4. Scoped calendar/worker/test fixes are installed, but these broad audit obligations remain IN PROGRESS; private persistent-session proposals, provider/native/RLS and production schema/configuration gaps receive no closure credit. | +| LIBRARY-E6A19A80898B | LIBRARY | lib/schedule/zoned.ts | 🔄 IN PROGRESS | Unassessed | Complete original helper scope retained; empty-on-invalid and valid extended-year UTC clock fallback corrected. | 87eff58b candidate installed in owned source;45 lasting cases and neighbor bodies intact. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim. | Current five-fix checkpoint2026-10-09T17:06:32.207Z:Full row remains IP: today explicit invalid clock and AD0 fallback/civil-time policy need separately specified acceptance; earlier exact8RED retained. Historical cells preserved before 2026-10-09T17:06:32.207Z: Tests=Complete schedule helper scope retained; clock empty-on-unparseable and UTC fallback repaired in isolated candidate.; Fix=Candidate87eff58b clock validates one Date and formats UTC fields; neighbors byte-identical.; Retest=Clock45+40 related1200PASS×3 and full typesPASS; combined63files1801PASS×3/typePASS. Unchangedtoday invalid explicitclock/AD0/two-pass full-module policy still open.. Historical notes retained:Current candidate review 2026-10-09T16:50:31.128Z: Isolated owned candidate only:1801 assertions across63 complete files PASS/noSKIP/noFAIL in eachUTC/LA/Tokyo; full project typesPASS. Source is not committed, hosted or released at this checkpoint. Fresh candidate build/lint/CI and exact production-source readback remain required. No full-row closure; original RangeError and8RED controls retained. Real provider/Auth/RLS/reachability not claimed. Historical cells preserved before 2026-10-09T16:50:31.128Z: Tests=Complete schedule helper obligation retained. Clock-only documented empty-on-unparseable and valid-Date UTC fallback have a private reviewed repair; today/DATE-domain/two-pass policy obligations remain open.; Fix=PRIVATE/UNINSTALLED candidate87eff58b validates one Date before Intl/fallback and formats padded UTC fields without ISO year-offset slicing. Only clockInZone changes; all neighboring exports byte-identical.; Retest=Actual private baseline/exact reversion37PASS8RED; proposed45 lasting cases plus40 unchanged permanent files1200PASS/noSKIP/noFAIL in UTC/LosAngeles/Tokyo underNode24.21. Independent11 actual-source controlsPASS eachzone; admission/slice/device-zone causal mutants fail. Scoped stricttypes/lint pass. Integrate on owned branch and require fresh final-source CI/production acceptance before claiming installed repair; whole today invalid-supplied-clock/unsupportedAD0 and legacy two-pass policy still require complete specification/acceptance.. Historical notes retained: Current followup 2026-10-09T15:53:57.469Z: Original installed sourceb018 still retains clock defect; private proposal.patch5c72ce4c/review2571734f and independentreviewf715c7eb are accepted within clock-only scope. First copied-location42ENOENT failures perzone retained and explained; corrected fixtures use actual original paths, without counting harness failure as product defect. Mandatory clocks never readDate.now; invalid input returns empty, unusable IANA fallback usesUTC minute fields even for signed/extended Dateyears. todayInZone explicit invalidclock stillthrowsRangeError and AD0fallback0000-12-31 remains a whole-module hold; no current-clock substitution/domain-policy invention. No full-module, Auth/RLS/provider or production reachability closure. Historical cells preserved before 2026-10-09T15:53:57.469Z: Tests=Complete file-level scope retained; supported-domain regression subset accepted but whole obligation not closed. Whole helper file includes clockInZone/todayInZone/zonedTimeMs beyond repaired dayKeyInZone. Actual current clockInZone finite out-of-Date-range fallback violates documented empty-on-unparseable contract (two RED/three healthy refusal/control PASS). No demonstrated production reachability; retained pure source gap must not be hidden by closing the day-key subset.; Fix=Deployed day-key domain repair accepted; separate clockInZone invalid-Date fallback throws RangeError. Private clock proposal under retest; UNINSTALLED.; Retest=Next closure gate: Whole helper file includes clockInZone/todayInZone/zonedTimeMs beyond repaired dayKeyInZone. Actual current clockInZone finite out-of-Date-range fallback violates documented empty-on-unparseable contract (two RED/three healthy refusal/control PASS). No demonstrated production reachability; retained pure source gap must not be hidden by closing the day-key subset. Review3f694c30; provider/production/RLS and held source activation receive no synthetic credit.. Historical notes retained: Current closure review 2026-10-09T15:45:41.083Z: Keep IN PROGRESS, no closure credit. Full original scope independently read; Whole helper file includes clockInZone/todayInZone/zonedTimeMs beyond repaired dayKeyInZone. Actual current clockInZone finite out-of-Date-range fallback violates documented empty-on-unparseable contract (two RED/three healthy refusal/control PASS). No demonstrated production reachability; retained pure source gap must not be hidden by closing the day-key subset. Current installed source pure clock receipt603883e5:2RED/3PASS; finite out-of-Date-range clock expected empty throwsRangeError, including invalid IANA fallback. No production reachability established. Historical cells preserved before 2026-10-09T15:45:41.083Z: Tests=Pending; Fix=None; Retest=Pending. Historical notes retained: Current root cycle2026-10-09UTC: claimed on owned main-c67 branch codex/calendar-worker-boundaries-20261009 before integration. Private supported-year evidence is not installed acceptance: AD1 wall constructor maps1901, local input loses zero-padding, and one-hour query lookback emits year0 in native/school/sports filters; strict installed-SDK synthetic rejection reproduces db refusal. Complete extension and independent regression review are in progress. Public AD1..9999/119 validation and family authorization are unchanged. Full workflow/hosted acceptance remains open; no closure credit. Root local acceptance2026-10-09UTC: complete calendar/worker fix is now integrated on owned main-c67 branch. Exact shared15source/test pins pass2668tests/noSKIP/noFAIL in eachUTC/LosAngeles/Tokyo, full project types and lint, plus audit reconciliation. New calendar fixture uses canonical minimum .000Z so the lexical transport cannot hide strict-vs-inclusive lower-edge mistakes. Permanent API spies prove refusal before factory and context-family filters; mocked Auth is not RLS acceptance. Worker86 inherited/new controls and60 native promise-boundary probes support cancellation/cleanup repair; real provider activation remains off. Fresh hosted build/browser/Auth/database and deployment gates are still pending; full-item status remains IN PROGRESS and no closure credit. PR978 source49be/tree15566 normally merged as 00361e9de5b7ed1899c8a9513c5286747729b6bf; exact current-head terminal CI accepted with ordered three-zone unit reports, build/types, genuine browser/Auth and owned-stack cleanup. Canonical production revision and anonymous cache/login/redirect contracts independently verified; production receipt 97e740efc87021f1ab52c061112cfcca37ba4693f477e188c94766c27d8b9dd4. Scoped calendar/worker/test fixes are installed, but these broad audit obligations remain IN PROGRESS; private persistent-session proposals, provider/native/RLS and production schema/configuration gaps receive no closure credit. | | LIBRARY-404441D70362 | LIBRARY | lib/school/timetable.ts | 🔄 IN PROGRESS | Unassessed | Pending | None | Pending | | | LIBRARY-1C237C551BED | LIBRARY | lib/screen-time/insights.ts | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | | LIBRARY-D52F335672FC | LIBRARY | lib/search/rank.ts | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | | @@ -24767,7 +24783,7 @@ not read the same on this page.* | LIBRARY-94AB0D35DA7D | LIBRARY | lib/supabase/escape-like.ts | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | Discovered 2026-09-26: source file present with no ledger row (see Q56). | | LIBRARY-2C48109D7D67 | LIBRARY | lib/supabase/read-all.ts | 🔄 IN PROGRESS | Medium | Pending; Current scoped checkpoint: Source7792a478 reviewed; safe helper regressions pending. Complete Inventory read will use existing empty-page traversal.; Current malformed-response review: Unchanged7792 helper, actualSDK2.108.2/custom inert ordinary inventory GET, finite max3/at most2requests: root7=2 desired failures/5 controls b92b2b. Successful200 object length0 falsely completes empty; length1 noniterable rejects at spread outside awaited-page catch. Original7 frozen060a89a9; root peer 106a94a5701867b31f44a86f3ae4db2c0f21b0f821fa460addcc8a540903459f.; Current published checkpoint: Published draft8405b69eb5c mainbased; exact2 owned files. Root frozen same33 candidate33PASS22db30 versus parent21 desiredFAIL12controls43e421; original7 complete assertion block retained. Independent0f6deb3d accepts all22 artifact hashes, safe26/types/lint. One collection-shape defect, not21bugs. Frozenb1d5fd66/published863c51a5. | None; Current scoped checkpoint: No helper source change allocated; existing readAllAsQuery reused for Inventory complete retrieval.; Current malformed-response review: Allocate exact two-file same-helper array-shape guard plus new SDK test separately from Inventory; no source edits before this marker/ownership claim.; Current published checkpoint: Require Array.isArray before length/empty/spread, reuse existing unavailable Error; every other source byte and original array/null/error/max/wrapper contract retained. | Pending; Current scoped checkpoint: Mark before narrow synthetic helper/API-range tests; full contract closure pending.; Current malformed-response review: Original readonly7 preserved; healthy scoped array/empty/null/403/later403 controls pass; candidate pending.; Current published checkpoint: Fresh combined45 566/44 unit,23 browser, fulltypes and native compile-only pass. Gate packet ad5f44043e44ba86a50805d9444f3cf0dad84fa3a943ee3d82da3083ddd2380c. | Discovered 2026-09-26: source file present with no ledger row (see Q56).; Current scoped checkpoint: Advance by actual rows; empty terminates; errors discard partial query result. No directDB/Auth/provider execution or closure credit.; Current malformed-response review: Malformed successful-response model only; no observed live/attacker/Auth/provider/privacy/RLS claim. Separate helper followup; Inventory three-file candidate keeps its old helper bytes frozen. No source/parent-test overlap and no production configuration, migrations or money.; Current published checkpoint: Synthetic local runtime only; no live production cap, Auth, RLS, PostgreSQL, provider, privacy, data-loss or full-workflow claim. Stable ordered offset traversal is not a concurrent-edit snapshot. Source45 compile-only is not full production build; middleware deprecation remains. No new closure/blocked credit. | | LIBRARY-0056DCF9E763 | LIBRARY | lib/sync/audit.ts | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | Discovered 2026-09-26: source file present with no ledger row (see Q56). | -| LIBRARY-CC76B9A33321 | LIBRARY | lib/time/zoned.ts | 🔄 IN PROGRESS | Unassessed | Complete file-level scope retained; supported-domain regression subset accepted but whole obligation not closed. Original row expressly leaves complete layout/consumer, remaining date inputs, midnight refresh and full role workflows open. The deployed Gregorian reconstruction is a scoped repair; no whole row redefinition is justified. | Scoped Gregorian/boundary/read-order repair installed49be/00361; remaining exported/consumer/source-activation obligations need complete acceptance. | Next closure gate: Original row expressly leaves complete layout/consumer, remaining date inputs, midnight refresh and full role workflows open. The deployed Gregorian reconstruction is a scoped repair; no whole row redefinition is justified. Review3f694c30; provider/production/RLS and held source activation receive no synthetic credit. | Current closure review 2026-10-09T15:45:41.083Z: Keep IN PROGRESS, no closure credit. Full original scope independently read; Original row expressly leaves complete layout/consumer, remaining date inputs, midnight refresh and full role workflows open. The deployed Gregorian reconstruction is a scoped repair; no whole row redefinition is justified. Historical cells preserved before 2026-10-09T15:45:41.083Z: Tests=#728 scoped source review,151 relevant combined cases and exact all-four CI; Fix=#728 integrated c2582f20; retained in served d1b0a569; Retest=Historical scoped checks retained; complete layout/consumer acceptance pending. Historical notes retained: Discovered 2026-09-26: source file present with no ledger row (see Q56). Current 2026-10-01 05:29 receipt: Append integrated TIME-003 source review and scoped test receipts to existing file row. Remaining date inputs, midnight refresh and full role workflows are not closed. Current root cycle2026-10-09UTC: claimed on owned main-c67 branch codex/calendar-worker-boundaries-20261009 before integration. Private supported-year evidence is not installed acceptance: AD1 wall constructor maps1901, local input loses zero-padding, and one-hour query lookback emits year0 in native/school/sports filters; strict installed-SDK synthetic rejection reproduces db refusal. Complete extension and independent regression review are in progress. Public AD1..9999/119 validation and family authorization are unchanged. Full workflow/hosted acceptance remains open; no closure credit. Root local acceptance2026-10-09UTC: complete calendar/worker fix is now integrated on owned main-c67 branch. Exact shared15source/test pins pass2668tests/noSKIP/noFAIL in eachUTC/LosAngeles/Tokyo, full project types and lint, plus audit reconciliation. New calendar fixture uses canonical minimum .000Z so the lexical transport cannot hide strict-vs-inclusive lower-edge mistakes. Permanent API spies prove refusal before factory and context-family filters; mocked Auth is not RLS acceptance. Worker86 inherited/new controls and60 native promise-boundary probes support cancellation/cleanup repair; real provider activation remains off. Fresh hosted build/browser/Auth/database and deployment gates are still pending; full-item status remains IN PROGRESS and no closure credit. | +| LIBRARY-CC76B9A33321 | LIBRARY | lib/time/zoned.ts | 🔄 IN PROGRESS | Unassessed | Full module/consumer scope retained; exact historical offset seconds, milliseconds, short gaps/folds, public shape and modern policy independently checked. | 86cefc0c exact private civil milliseconds replaces minute-truncated offset; strict scalar verification and existing RFC reading use it; LocalParts still exactlyfivefields/eight other public bodies identical. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim. Lasting46 original23PASS23RED; selective scalar/civil guards1/3RED; independent64nativePASS×3/original42RED/ms mutant25RED. | Current five-fix checkpoint2026-10-09T17:06:32.207Z:Keep IP for original full layout/date-input/midnight-refresh/role workflows; no pure-helper-only scope narrowing. Existing strict/routine/RFC distinctions, unsupported input/fallback characterization retained. Historical cells preserved before 2026-10-09T17:06:32.207Z: Tests=Complete file-level scope retained; supported-domain regression subset accepted but whole obligation not closed. Original row expressly leaves complete layout/consumer, remaining date inputs, midnight refresh and full role workflows open. The deployed Gregorian reconstruction is a scoped repair; no whole row redefinition is justified.; Fix=Scoped Gregorian/boundary/read-order repair installed49be/00361; remaining exported/consumer/source-activation obligations need complete acceptance.; Retest=Next closure gate: Original row expressly leaves complete layout/consumer, remaining date inputs, midnight refresh and full role workflows open. The deployed Gregorian reconstruction is a scoped repair; no whole row redefinition is justified. Review3f694c30; provider/production/RLS and held source activation receive no synthetic credit.. Historical notes retained:Current closure review 2026-10-09T15:45:41.083Z: Keep IN PROGRESS, no closure credit. Full original scope independently read; Original row expressly leaves complete layout/consumer, remaining date inputs, midnight refresh and full role workflows open. The deployed Gregorian reconstruction is a scoped repair; no whole row redefinition is justified. Historical cells preserved before 2026-10-09T15:45:41.083Z: Tests=#728 scoped source review,151 relevant combined cases and exact all-four CI; Fix=#728 integrated c2582f20; retained in served d1b0a569; Retest=Historical scoped checks retained; complete layout/consumer acceptance pending. Historical notes retained: Discovered 2026-09-26: source file present with no ledger row (see Q56). Current 2026-10-01 05:29 receipt: Append integrated TIME-003 source review and scoped test receipts to existing file row. Remaining date inputs, midnight refresh and full role workflows are not closed. Current root cycle2026-10-09UTC: claimed on owned main-c67 branch codex/calendar-worker-boundaries-20261009 before integration. Private supported-year evidence is not installed acceptance: AD1 wall constructor maps1901, local input loses zero-padding, and one-hour query lookback emits year0 in native/school/sports filters; strict installed-SDK synthetic rejection reproduces db refusal. Complete extension and independent regression review are in progress. Public AD1..9999/119 validation and family authorization are unchanged. Full workflow/hosted acceptance remains open; no closure credit. Root local acceptance2026-10-09UTC: complete calendar/worker fix is now integrated on owned main-c67 branch. Exact shared15source/test pins pass2668tests/noSKIP/noFAIL in eachUTC/LosAngeles/Tokyo, full project types and lint, plus audit reconciliation. New calendar fixture uses canonical minimum .000Z so the lexical transport cannot hide strict-vs-inclusive lower-edge mistakes. Permanent API spies prove refusal before factory and context-family filters; mocked Auth is not RLS acceptance. Worker86 inherited/new controls and60 native promise-boundary probes support cancellation/cleanup repair; real provider activation remains off. Fresh hosted build/browser/Auth/database and deployment gates are still pending; full-item status remains IN PROGRESS and no closure credit. | | LIBRARY-C57404E4E963 | LIBRARY | lib/ui/gallery.ts | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | Discovered 2026-09-26: source file present with no ledger row (see Q56). | | MIGRATION-2BFE0CE0B23C | MIGRATION | supabase/migrations/0285_conflict_targets_inferable.sql | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | Discovered 2026-09-26: no ledger row existed (Q56). Replays cleanly in a fresh 346-migration bootstrap; production application and deployed behaviour unverified. | | MIGRATION-8FF24A0E7DA7 | MIGRATION | supabase/migrations/0286_blog_updated_at_is_a_content_date.sql | ⬜ NOT STARTED | Unassessed | Pending | None | Pending | Discovered 2026-09-26: no ledger row existed (Q56). Replays cleanly in a fresh 346-migration bootstrap; production application and deployed behaviour unverified. | @@ -24870,7 +24886,7 @@ not read the same on this page.* | SUPPORT-D1BFE4A72EF8 | SUPPORT | tests/two-widgets-on-one-table-do-not-share-a-channel.test.ts | 🔄 IN PROGRESS | Medium | New source/coverage inventory; combined integration is not yet published or fully accepted. | Integrate reviewed585/598 fixes with matching regression coverage. | Combined focused unit230/230 and browser44/44 pass; these are suite scopes, not a claim that every new source has a full workflow test. Canonical full gates and hosted acceptance pending. | Added2026-09-27 by canonical path hash; API hashes route:method. No extra product-workflow completion. | | SUPPORT-6184F8927CFB | SUPPORT | tests/a-sidebar-layout-we-could-not-read-is-not-one-we-may-overwrite.test.ts | 🔄 IN PROGRESS | Medium | Current main e96 source restored unchanged; blob 418e10ff3ab1c1af44add11530bd3a1ddb929bdd. | Preserve the existing sidebar preference-read contract while reconciling concurrent main. | Read-only source/inventory review complete; current combined canonical execution and hosted acceptance pending. | Added2026-09-27 by canonical-path SHA-256 to inventory an already tracked test. Simulated React hooks/browser storage are unit coverage, not a live navigation/provider journey. No application change or workflow closure is claimed. | | SUPPORT-EDFC5692FF80 | SUPPORT | tests/e2e/framework-hydration-replay.spec.ts | 🔄 IN PROGRESS | High | C:/Users/Daniel/AppData/Local/Temp/bubaly-framework-release-20260927/renderer-old-red.log; bubaly-framework-combined52d-20260927/browser-receipt.json. | Retain actual installed compiled-renderer sync, immediate lazy-child replay and delayed controls. No framework/vendor patch or app server. | CurrentNext16 replay fixture3/3 within combined278/278 browserPASS; same fixture oldNext15 has one desired immediate-replay#418 RED and two passingcontrols. Full f9 local gates pass; updated hosted acceptance pending. | Added2026-09-27 by canonical path hash; blob 614ad3e16a24ae03f2b6c9af3a0601c6a47fe229. Renderer mechanism coverage, not a live eight-page recrawl or complete product workflow. Existing page OWNER claims remain. | -| COMPONENT-10BFCB70C689 | COMPONENT | components/i18n/use-format.ts | 🔄 IN PROGRESS | Medium | #728 family-clock/DST/hydration source and relevant tests;23,203 units+2 expected perTZ | #728 integrated with DATE-label #733; source served | Candidate all-four CI PASS; complete consumer workflow pending | Integrated path: components/i18n/use-format.ts. Inventory gap for a previously existing file; not new source. 2026-09-30: #688838280f2 fixes original device-DST gap (52 tests pass), but detect/save/apply mixes device-derived routine fields with family-zone interpretation. Review5371688966 has UTC-family LA/Tokyo counterexamples; no broad timezone PASS. Previous checkpoint columns (historical): 2026-09-27 local controls checkpoint: 24/24 retained browser and 53/53 guard checks on the frozen 44-path integration; full combined/hosted gates pending. Exact source map: C:/Users/Daniel/AppData/Local/Temp/bubaly-next-controls-audit-20260927/integrity.json.; Selected localization, message ownership, date/layout or stale-chunk recovery path.; IN PROGRESS: bounded local source/fixture proof; no workflow or page closure.. Current 2026-10-01 05:29 receipt: No automatic idle-screen midnight refresh claim. Existing ID/status retained; #741 family-day selection remains a separate candidate. | +| COMPONENT-10BFCB70C689 | COMPONENT | components/i18n/use-format.ts | 🔄 IN PROGRESS | Medium | Full format/family-clock/DATE handoff scope retained; AD1 constructor century defect fixed without changing unsupported/overflow legacy behavior. | Explicit supported-year local setter f9326859 installed;38 lasting native/provider cases baseline10RED. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim. Independent209source/native six-zone checksPASS; raw/LF/EOF normalization preserved. | Current five-fix checkpoint2026-10-09T17:06:32.207Z:Keep full component IP pending complete role/consumer/mobile/browserworkflow and fresh production-source acceptance. Historical cells preserved before 2026-10-09T17:06:32.207Z: Tests=Family-clock/DATE handoff full component scope retained. Actual React providers derive correct AD1 wall key but old calendarDayOfKey maps1→1901.; Fix=Isolated calendarDayOfKey uses explicit local year setter for integerAD1..9999 then midnight. Unsupported/noninteger/malformed legacy results and calendar overflow unchanged.; Retest=Lasting38 native/actualReact cases original28PASS10RED×3→candidate195PASS×3 with4 preserved caller files; combined1801PASS×3/full typesPASS. Independent source review and fresh hosted/deployed complete consumer acceptance pending.. Historical notes retained:Current candidate review 2026-10-09T16:50:31.128Z: Isolated owned candidate only:1801 assertions across63 complete files PASS/noSKIP/noFAIL in eachUTC/LA/Tokyo; full project typesPASS. Source is not committed, hosted or released at this checkpoint. Fresh candidate build/lint/CI and exact production-source readback remain required. Private rawsource488cd8 normal Git LFsourcef9326859 identical after oneCRLF normalization; private test2646cfa1 becomesGit365dc909 after oneEOF newline only. These preparation refusals are preserved; assertion bodies unchanged. Full component not closed. Historical cells preserved before 2026-10-09T16:50:31.128Z: Tests=#728 family-clock/DST/hydration source and relevant tests;23,203 units+2 expected perTZ; Fix=#728 integrated with DATE-label #733; source served; Retest=Candidate all-four CI PASS; complete consumer workflow pending. Historical notes retained: Integrated path: components/i18n/use-format.ts. Inventory gap for a previously existing file; not new source. 2026-09-30: #688838280f2 fixes original device-DST gap (52 tests pass), but detect/save/apply mixes device-derived routine fields with family-zone interpretation. Review5371688966 has UTC-family LA/Tokyo counterexamples; no broad timezone PASS. Previous checkpoint columns (historical): 2026-09-27 local controls checkpoint: 24/24 retained browser and 53/53 guard checks on the frozen 44-path integration; full combined/hosted gates pending. Exact source map: C:/Users/Daniel/AppData/Local/Temp/bubaly-next-controls-audit-20260927/integrity.json.; Selected localization, message ownership, date/layout or stale-chunk recovery path.; IN PROGRESS: bounded local source/fixture proof; no workflow or page closure.. Current 2026-10-01 05:29 receipt: No automatic idle-screen midnight refresh claim. Existing ID/status retained; #741 family-day selection remains a separate candidate. | | SUPPORT-399582262447 | SUPPORT | tests/i18n-ungated-surface-ratchet.test.ts | 🔄 IN PROGRESS | Medium | 2026-09-27 local controls checkpoint: 24/24 retained browser and 53/53 guard checks on the frozen 44-path integration; full combined/hosted gates pending. Exact source map: C:/Users/Daniel/AppData/Local/Temp/bubaly-next-controls-audit-20260927/integrity.json. | Selected localization, message ownership, date/layout or stale-chunk recovery path. | IN PROGRESS: bounded local source/fixture proof; no workflow or page closure. | Integrated path: tests/i18n-ungated-surface-ratchet.test.ts. Inventory gap for a previously existing file; not new source. | | SUPPORT-51C089F60FE9 | SUPPORT | tests/medications-fixture-module-graph.test.ts | 🔄 IN PROGRESS | Medium | 2026-09-27 local controls checkpoint: 24/24 retained browser and 53/53 guard checks on the frozen 44-path integration; full combined/hosted gates pending. Exact source map: C:/Users/Daniel/AppData/Local/Temp/bubaly-next-controls-audit-20260927/integrity.json. | Selected localization, message ownership, date/layout or stale-chunk recovery path. | IN PROGRESS: bounded local source/fixture proof; no workflow or page closure. | Integrated path: tests/medications-fixture-module-graph.test.ts. Inventory gap for a previously existing file; not new source. | | SUPPORT-74DB39BAF195 | SUPPORT | tests/the-shared-formatter-follows-the-locale.test.ts | 🔄 IN PROGRESS | Medium | 2026-09-27 local controls checkpoint: 24/24 retained browser and 53/53 guard checks on the frozen 44-path integration; full combined/hosted gates pending. Exact source map: C:/Users/Daniel/AppData/Local/Temp/bubaly-next-controls-audit-20260927/integrity.json. | Selected localization, message ownership, date/layout or stale-chunk recovery path. | IN PROGRESS: bounded local source/fixture proof; no workflow or page closure. | Integrated path: tests/the-shared-formatter-follows-the-locale.test.ts. Inventory gap for a previously existing file; not new source. | @@ -24887,15 +24903,15 @@ not read the same on this page.* | SUPPORT-F142EA58E984 | SUPPORT | tests/pricing-public-tier-budget.test.ts | 🔄 IN PROGRESS | Medium | #729/#732 scoped local and hosted evidence above | Shipped in2630e42e | Candidate checks PASS; complete workflow pending | New file-level inventory obligation, not a new logical workflow. Pricing-only capability presentation deadline controls; no entitlement acceptance. | | SUPPORT-45CFE517B52A | SUPPORT | tests/marketing-testimonial-read-availability.test.ts | 🔄 IN PROGRESS | Medium | #729/#732 scoped local and hosted evidence above | Shipped in2630e42e | Candidate checks PASS; complete workflow pending | New file-level inventory obligation, not a new logical workflow. 31 synthetic cases; original21 failures/10 controls; no full homepage acceptance. | | LIBRARY-981F43BABF91 | LIBRARY | lib/server/family-time-zone.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | newly shipped TIME-003 source/test; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | -| LIBRARY-6F37A5743ADF | LIBRARY | lib/time/local-input.ts | 🔄 IN PROGRESS | Medium | Complete file-level scope retained; supported-domain regression subset accepted but whole obligation not closed. AD1 padding/native setter and existing valid roundtrip controls pass, but original scope is the complete two-function input module and every accepted passthrough/seconds/fraction/reader-family conversion branch; this review has not independently closed that complete contract. Existing no-family/native-input convention remains explicit. | Scoped Gregorian/boundary/read-order repair installed49be/00361; remaining exported/consumer/source-activation obligations need complete acceptance. | Next closure gate: AD1 padding/native setter and existing valid roundtrip controls pass, but original scope is the complete two-function input module and every accepted passthrough/seconds/fraction/reader-family conversion branch; this review has not independently closed that complete contract. Existing no-family/native-input convention remains explicit. Review3f694c30; provider/production/RLS and held source activation receive no synthetic credit. | Current closure review 2026-10-09T15:45:41.083Z: Keep IN PROGRESS, no closure credit. Full original scope independently read; AD1 padding/native setter and existing valid roundtrip controls pass, but original scope is the complete two-function input module and every accepted passthrough/seconds/fraction/reader-family conversion branch; this review has not independently closed that complete contract. Existing no-family/native-input convention remains explicit. Historical cells preserved before 2026-10-09T15:45:41.083Z: Tests=Scoped source/fixture evidence in 05:29 checkpoint; Fix=Integrated source retained in d1b0a569; Retest=Relevant candidate checks PASS; full obligation pending. Historical notes retained: existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. Current root cycle2026-10-09UTC: claimed on owned main-c67 branch codex/calendar-worker-boundaries-20261009 before integration. Private supported-year evidence is not installed acceptance: AD1 wall constructor maps1901, local input loses zero-padding, and one-hour query lookback emits year0 in native/school/sports filters; strict installed-SDK synthetic rejection reproduces db refusal. Complete extension and independent regression review are in progress. Public AD1..9999/119 validation and family authorization are unchanged. Full workflow/hosted acceptance remains open; no closure credit. Root local acceptance2026-10-09UTC: complete calendar/worker fix is now integrated on owned main-c67 branch. Exact shared15source/test pins pass2668tests/noSKIP/noFAIL in eachUTC/LosAngeles/Tokyo, full project types and lint, plus audit reconciliation. New calendar fixture uses canonical minimum .000Z so the lexical transport cannot hide strict-vs-inclusive lower-edge mistakes. Permanent API spies prove refusal before factory and context-family filters; mocked Auth is not RLS acceptance. Worker86 inherited/new controls and60 native promise-boundary probes support cancellation/cleanup repair; real provider activation remains off. Fresh hosted build/browser/Auth/database and deployment gates are still pending; full-item status remains IN PROGRESS and no closure credit. | -| LIBRARY-518B659656DE | LIBRARY | lib/time/wall-clock.ts | 🔄 IN PROGRESS | Medium | Complete file-level scope retained; supported-domain regression subset accepted but whole obligation not closed. All changed supported-minimum public keys/instants and existing calendar layout consumers pass, but a complete public wallDate/parts/day/month/week/zone resolution module audit is distinct from the new28-case regression scope. No full module closure is claimed from a subset; eligible for focused complete pure-helper review. | Scoped Gregorian/boundary/read-order repair installed49be/00361; remaining exported/consumer/source-activation obligations need complete acceptance. | Next closure gate: All changed supported-minimum public keys/instants and existing calendar layout consumers pass, but a complete public wallDate/parts/day/month/week/zone resolution module audit is distinct from the new28-case regression scope. No full module closure is claimed from a subset; eligible for focused complete pure-helper review. Review3f694c30; provider/production/RLS and held source activation receive no synthetic credit. | Current closure review 2026-10-09T15:45:41.083Z: Keep IN PROGRESS, no closure credit. Full original scope independently read; All changed supported-minimum public keys/instants and existing calendar layout consumers pass, but a complete public wallDate/parts/day/month/week/zone resolution module audit is distinct from the new28-case regression scope. No full module closure is claimed from a subset; eligible for focused complete pure-helper review. Historical cells preserved before 2026-10-09T15:45:41.083Z: Tests=Scoped source/fixture evidence in 05:29 checkpoint; Fix=Integrated source retained in d1b0a569; Retest=Relevant candidate checks PASS; full obligation pending. Historical notes retained: newly shipped TIME-003 source/test; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. Current root cycle2026-10-09UTC: claimed on owned main-c67 branch codex/calendar-worker-boundaries-20261009 before integration. Private supported-year evidence is not installed acceptance: AD1 wall constructor maps1901, local input loses zero-padding, and one-hour query lookback emits year0 in native/school/sports filters; strict installed-SDK synthetic rejection reproduces db refusal. Complete extension and independent regression review are in progress. Public AD1..9999/119 validation and family authorization are unchanged. Full workflow/hosted acceptance remains open; no closure credit. Root local acceptance2026-10-09UTC: complete calendar/worker fix is now integrated on owned main-c67 branch. Exact shared15source/test pins pass2668tests/noSKIP/noFAIL in eachUTC/LosAngeles/Tokyo, full project types and lint, plus audit reconciliation. New calendar fixture uses canonical minimum .000Z so the lexical transport cannot hide strict-vs-inclusive lower-edge mistakes. Permanent API spies prove refusal before factory and context-family filters; mocked Auth is not RLS acceptance. Worker86 inherited/new controls and60 native promise-boundary probes support cancellation/cleanup repair; real provider activation remains off. Fresh hosted build/browser/Auth/database and deployment gates are still pending; full-item status remains IN PROGRESS and no closure credit. | +| LIBRARY-6F37A5743ADF | LIBRARY | lib/time/local-input.ts | 🔄 IN PROGRESS | Medium | Unchanged edit fold/seconds/offset/micro/nanosecond identity and strict optional original admission now implemented; two-argument grammar/projection/conversion byte-preserved. | Strict v2 e138920a with parseExactInstant +matching same-zone display, actual calendar caller passes matching owned existing start/end hints. Rejected v1 e998/9b926 remains immutable/uninstalled. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim.54 lasting348affectedPASS×3,17originalRED/9strict-admission-mutantRED/3caller-mutantRED. Independent32nativePASS×3; original12PASS9RED root witness retained. | Current five-fix checkpoint2026-10-09T17:06:32.207Z:Keep full row IP for broad calendar/Auth/RLS/workflow gates. Actual extracted modal/React/native Intl/DOM/FormData/helpers18ChromePASS firstattempt across3devicezones, synthetic widgets/schema/action endpoints, actual server actions separately modeled Auth/inmemorySDK; no production or real authorization proof. Historical cells preserved before 2026-10-09T17:06:32.207Z: Tests=Full two-direction local-input/source/consumer contract remains IP. Actual native original pair12PASS9RED×3 runtime zones: unchanged NYsecondfold moves-1hour, Londonfirstfold+1hour, imported seconds drop29.456s.; Fix=Private originalInstant-hint proposal under independent review; NOT integrated. Firstv1 Date-only validation admits malformed/nonabsolute hints and is HOLD pending strict absolute-original admission.; Retest=Root original witnessffc9a114 preserves ordinary positive controls and actual caller source composition. Author328PASS×3/15ChromePASS used synthetic widget/schema/actions; peer malformedFeb30/date-only/naive/RFC admission finding requires corrected lasting controls and combined/source release acceptance.. Historical notes retained:Current candidate review 2026-10-09T16:50:31.128Z: Keep IP, no closure credit. Main originaltwo-arg conversion is unchanged. Existing calendar EventModal passes no original stored timestamp/fold identity. Newest private proposal not automatically trusted; original parser/DST/passthrough/reader-family semantics must remain. No actual Auth/RLS/production write proof claimed. Historical cells preserved before 2026-10-09T16:50:31.128Z: Tests=Complete file-level scope retained; supported-domain regression subset accepted but whole obligation not closed. AD1 padding/native setter and existing valid roundtrip controls pass, but original scope is the complete two-function input module and every accepted passthrough/seconds/fraction/reader-family conversion branch; this review has not independently closed that complete contract. Existing no-family/native-input convention remains explicit.; Fix=Scoped Gregorian/boundary/read-order repair installed49be/00361; remaining exported/consumer/source-activation obligations need complete acceptance.; Retest=Next closure gate: AD1 padding/native setter and existing valid roundtrip controls pass, but original scope is the complete two-function input module and every accepted passthrough/seconds/fraction/reader-family conversion branch; this review has not independently closed that complete contract. Existing no-family/native-input convention remains explicit. Review3f694c30; provider/production/RLS and held source activation receive no synthetic credit.. Historical notes retained: Current closure review 2026-10-09T15:45:41.083Z: Keep IN PROGRESS, no closure credit. Full original scope independently read; AD1 padding/native setter and existing valid roundtrip controls pass, but original scope is the complete two-function input module and every accepted passthrough/seconds/fraction/reader-family conversion branch; this review has not independently closed that complete contract. Existing no-family/native-input convention remains explicit. Historical cells preserved before 2026-10-09T15:45:41.083Z: Tests=Scoped source/fixture evidence in 05:29 checkpoint; Fix=Integrated source retained in d1b0a569; Retest=Relevant candidate checks PASS; full obligation pending. Historical notes retained: existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. Current root cycle2026-10-09UTC: claimed on owned main-c67 branch codex/calendar-worker-boundaries-20261009 before integration. Private supported-year evidence is not installed acceptance: AD1 wall constructor maps1901, local input loses zero-padding, and one-hour query lookback emits year0 in native/school/sports filters; strict installed-SDK synthetic rejection reproduces db refusal. Complete extension and independent regression review are in progress. Public AD1..9999/119 validation and family authorization are unchanged. Full workflow/hosted acceptance remains open; no closure credit. Root local acceptance2026-10-09UTC: complete calendar/worker fix is now integrated on owned main-c67 branch. Exact shared15source/test pins pass2668tests/noSKIP/noFAIL in eachUTC/LosAngeles/Tokyo, full project types and lint, plus audit reconciliation. New calendar fixture uses canonical minimum .000Z so the lexical transport cannot hide strict-vs-inclusive lower-edge mistakes. Permanent API spies prove refusal before factory and context-family filters; mocked Auth is not RLS acceptance. Worker86 inherited/new controls and60 native promise-boundary probes support cancellation/cleanup repair; real provider activation remains off. Fresh hosted build/browser/Auth/database and deployment gates are still pending; full-item status remains IN PROGRESS and no closure credit. | +| LIBRARY-518B659656DE | LIBRARY | lib/time/wall-clock.ts | 🔄 IN PROGRESS | Medium | All10 wall-clock exports53nativeDate/Intl controlsPASS each3zones;4 unchanged actual caller suites157PASS×3. Full TIME003 consumer scope retained. | Wall-clock module216e source unchanged; its external calendarDayOfKey/calendarToday supported-year handoff has a separate isolated setter fix. | Existing49be per-file hosted acceptance supersedes historical pending gates. External actualReactAD1 baseline2RED/1modernPASS; lasting38+157 caller195PASS×3. Combined1801PASS×3/typesPASS. Full consumer/workflow and fresh release acceptance remain open. | Current candidate review 2026-10-09T16:50:31.128Z: Isolated owned candidate only:1801 assertions across63 complete files PASS/noSKIP/noFAIL in eachUTC/LA/Tokyo; full project typesPASS. Source is not committed, hosted or released at this checkpoint. Fresh candidate build/lint/CI and exact production-source readback remain required. Corrected full-register scope review756b preserves flawedcb6b two-column-summary capture; runtime evidence unaffected. LocalParts intentionally has minute precision/fold ambiguity, separate from untouched edit identity. No silent pure-only scope narrowing. Historical cells preserved before 2026-10-09T16:50:31.128Z: Tests=Complete file-level scope retained; supported-domain regression subset accepted but whole obligation not closed. All changed supported-minimum public keys/instants and existing calendar layout consumers pass, but a complete public wallDate/parts/day/month/week/zone resolution module audit is distinct from the new28-case regression scope. No full module closure is claimed from a subset; eligible for focused complete pure-helper review.; Fix=Scoped Gregorian/boundary/read-order repair installed49be/00361; remaining exported/consumer/source-activation obligations need complete acceptance.; Retest=Next closure gate: All changed supported-minimum public keys/instants and existing calendar layout consumers pass, but a complete public wallDate/parts/day/month/week/zone resolution module audit is distinct from the new28-case regression scope. No full module closure is claimed from a subset; eligible for focused complete pure-helper review. Review3f694c30; provider/production/RLS and held source activation receive no synthetic credit.. Historical notes retained: Current closure review 2026-10-09T15:45:41.083Z: Keep IN PROGRESS, no closure credit. Full original scope independently read; All changed supported-minimum public keys/instants and existing calendar layout consumers pass, but a complete public wallDate/parts/day/month/week/zone resolution module audit is distinct from the new28-case regression scope. No full module closure is claimed from a subset; eligible for focused complete pure-helper review. Historical cells preserved before 2026-10-09T15:45:41.083Z: Tests=Scoped source/fixture evidence in 05:29 checkpoint; Fix=Integrated source retained in d1b0a569; Retest=Relevant candidate checks PASS; full obligation pending. Historical notes retained: newly shipped TIME-003 source/test; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. Current root cycle2026-10-09UTC: claimed on owned main-c67 branch codex/calendar-worker-boundaries-20261009 before integration. Private supported-year evidence is not installed acceptance: AD1 wall constructor maps1901, local input loses zero-padding, and one-hour query lookback emits year0 in native/school/sports filters; strict installed-SDK synthetic rejection reproduces db refusal. Complete extension and independent regression review are in progress. Public AD1..9999/119 validation and family authorization are unchanged. Full workflow/hosted acceptance remains open; no closure credit. Root local acceptance2026-10-09UTC: complete calendar/worker fix is now integrated on owned main-c67 branch. Exact shared15source/test pins pass2668tests/noSKIP/noFAIL in eachUTC/LosAngeles/Tokyo, full project types and lint, plus audit reconciliation. New calendar fixture uses canonical minimum .000Z so the lexical transport cannot hide strict-vs-inclusive lower-edge mistakes. Permanent API spies prove refusal before factory and context-family filters; mocked Auth is not RLS acceptance. Worker86 inherited/new controls and60 native promise-boundary probes support cancellation/cleanup repair; real provider activation remains off. Fresh hosted build/browser/Auth/database and deployment gates are still pending; full-item status remains IN PROGRESS and no closure credit. | | SUPPORT-CBA7216421B1 | SUPPORT | tests/a-blank-social-links-form-is-not-a-cleared-one.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | | SUPPORT-F3BDD83A01B1 | SUPPORT | tests/a-calendar-day-is-the-readers-day.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | | SUPPORT-6ED9D65BAD4B | SUPPORT | tests/a-client-clock-reads-the-familys-zone.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | newly shipped TIME-003 source/test; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | | SUPPORT-710F87D30EFA | SUPPORT | tests/a-dashboard-setting-we-could-not-read-is-not-a-yes.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | | SUPPORT-9956410C36AA | SUPPORT | tests/a-date-renders-the-same-on-the-server-and-at-hydration.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | | SUPPORT-A862E4A33F99 | SUPPORT | tests/a-dismissed-moment-is-quiet-for-the-familys-day.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | -| SUPPORT-B11CC8C4E35D | SUPPORT | tests/a-family-wall-clock-ignores-the-devices-daylight-saving.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | newly shipped TIME-003 source/test; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | +| SUPPORT-B11CC8C4E35D | SUPPORT | tests/a-family-wall-clock-ignores-the-devices-daylight-saving.test.ts | 🔄 IN PROGRESS | Medium | Complete file 96 assertions executePASS each3zones in actual candidate. | Only independently reversible intent-preserving caller/guard changes adopt matching existing original timestamps; every other assertion/callback preserved. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim. | Current five-fix checkpoint2026-10-09T17:06:32.207Z:Keep IP pending original-scope independent closure review and exact committed-head full hosted file execution. Existing two wall-clock wrapper lint diagnostics preserved/qualified; targeted lint does not claim they passed. Historical cells preserved before 2026-10-09T17:06:32.207Z: Tests=Scoped source/fixture evidence in 05:29 checkpoint; Fix=Integrated source retained in d1b0a569; Retest=Relevant candidate checks PASS; full obligation pending. Historical notes retained:newly shipped TIME-003 source/test; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | | SUPPORT-19115DF183A7 | SUPPORT | tests/a-moment-never-guesses-what-the-family-already-did.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | | SUPPORT-78E39B0E5267 | SUPPORT | tests/a-moment-tap-saves-only-what-it-knows.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | | SUPPORT-86AA1AF989CF | SUPPORT | tests/a-rebuilt-graph-is-on-screen-before-the-toast-says-so.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | @@ -24905,7 +24921,7 @@ not read the same on this page.* | SUPPORT-7BB095D64BC2 | SUPPORT | tests/a-shortcut-layout-we-could-not-read-is-not-replaced-by-the-starter-set.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | | SUPPORT-B0F70D0BDE99 | SUPPORT | tests/a-visit-is-recorded-only-against-the-browser-that-sent-it.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | | SUPPORT-3ACD154B480C | SUPPORT | tests/an-edit-in-settings-keeps-the-pins-settings-cannot-offer.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | -| SUPPORT-2A6EF9BC2FB3 | SUPPORT | tests/editing-a-calendar-event-leaves-it-where-it-was.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | +| SUPPORT-2A6EF9BC2FB3 | SUPPORT | tests/editing-a-calendar-event-leaves-it-where-it-was.test.ts | 🔄 IN PROGRESS | Medium | Complete file 14 assertions executePASS each3zones in actual candidate. | Only independently reversible intent-preserving caller/guard changes adopt matching existing original timestamps; every other assertion/callback preserved. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim. | Current five-fix checkpoint2026-10-09T17:06:32.207Z:Keep IP pending original-scope independent closure review and exact committed-head full hosted file execution. Existing two wall-clock wrapper lint diagnostics preserved/qualified; targeted lint does not claim they passed. Historical cells preserved before 2026-10-09T17:06:32.207Z: Tests=Scoped source/fixture evidence in 05:29 checkpoint; Fix=Integrated source retained in d1b0a569; Retest=Relevant candidate checks PASS; full obligation pending. Historical notes retained:existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | | SUPPORT-B114F37F415C | SUPPORT | tests/family-timezone-optional-read-deadline.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | newly shipped TIME-003 source/test; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | | SUPPORT-ABE279625AE5 | SUPPORT | tests/finance-views-read-boundary.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | | SUPPORT-047549A09B6F | SUPPORT | tests/guardian-read-boundary.test.ts | 🔄 IN PROGRESS | Medium | Scoped source/fixture evidence in 05:29 checkpoint | Integrated source retained in d1b0a569 | Relevant candidate checks PASS; full obligation pending | existing-source inventory gap; file-level obligation, not a new logical workflow. Existing source and author history preserved; complete acceptance remains pending. | @@ -25752,6 +25768,12 @@ deliberately breaking the thing being guarded. | LIBRARY-52D3E0E24F63 | LIBRARY | lib/claude-fleet/worker.ts | 🛠 FIXED + PASS | High | Complete original worker settlement/cancellation/owned-cleanup defect scope:86 preserved/appended controls,60 native promise-boundary probes and actual worker→adapter→service→twoSQLite-client integration; five safety-removal mutants detect regressions. | Installed by PR978/49be, normally merged00361: final acceptance fences, native queued-abort ownership and memoized owned-resource cleanup. Late unconfirmed resource remains quarantined; exact confirmed stop releases its slot. | Exact49be hosted core113861300724: inherited66 and new20 each PASS in UTC/LosAngeles/Tokyo, no file skips/expected failures; related service36/adapter28/store26 each pass. Build/types and canonical00361 production source verified. | Current closure review 2026-10-09T15:45:41.083Z: Closure2026-10-09UTC applies to the original bounded corrective row, not full fleet activation. Original baseline86 cases11RED→86PASS;60 native controls42 pending18 healthy-late-abort, one stop per opened resource. Pending-ID cleanup can return stopConfirmedfalse before a later callback; quarantine persists until confirmed stop. Independent full-scope review95PASS/0FAIL42d4e2a and exact hosted-per-file1a0fd2c1. Real Vercel OIDC/header broker/Anthropic provider/workspace/snapshots/costs, remote libSQL/process/deployment restart, lost unknown-resource-ID operator recovery remain unverified. Nine synthetic SQLite directories retain WindowsEBUSY cleanup qualification; no cleanup success claimed. Historical cells preserved before 2026-10-09T15:45:41.083Z: Tests=Synthetic evidence under independent review; complete acceptance pending.; Fix=Root-owned proposed source fix; not installed yet.; Retest=Project and full workflow gates pending.. Historical notes retained: Discovered 2026-10-09T13:00:28.498Z: Private original worker reproduction5RED then deeper queued-cancellation controls exposed outer acceptance and cleanup gaps; robust integration/retest remains open. API/provider activation remains disabled. No closure credit. Root local acceptance2026-10-09UTC: complete calendar/worker fix is now integrated on owned main-c67 branch. Exact shared15source/test pins pass2668tests/noSKIP/noFAIL in eachUTC/LosAngeles/Tokyo, full project types and lint, plus audit reconciliation. New calendar fixture uses canonical minimum .000Z so the lexical transport cannot hide strict-vs-inclusive lower-edge mistakes. Permanent API spies prove refusal before factory and context-family filters; mocked Auth is not RLS acceptance. Worker86 inherited/new controls and60 native promise-boundary probes support cancellation/cleanup repair; real provider activation remains off. Fresh hosted build/browser/Auth/database and deployment gates are still pending; full-item status remains IN PROGRESS and no closure credit. PR978 source49be/tree15566 normally merged as 00361e9de5b7ed1899c8a9513c5286747729b6bf; exact current-head terminal CI accepted with ordered three-zone unit reports, build/types, genuine browser/Auth and owned-stack cleanup. Canonical production revision and anonymous cache/login/redirect contracts independently verified; production receipt 97e740efc87021f1ab52c061112cfcca37ba4693f477e188c94766c27d8b9dd4. Scoped calendar/worker/test fixes are installed, but these broad audit obligations remain IN PROGRESS; private persistent-session proposals, provider/native/RLS and production schema/configuration gaps receive no closure credit. | | SUPPORT-359773A26583 | SUPPORT | tests/claude-fleet-worker-settlement-race.test.ts | ✅ PASS | High | Whole permanent20-case cancellation/timeout/settlement/cleanup regression file reviewed, with original66 worker tests byte-identical. Causal removal controls expose acceptance, ownership, memoization and outer settlement defects. | Permanent regression file installed in49be/00361; no test removal, added skip or expected-failure waiver. | All20 tests execute and PASS exactly once in each ordered UTC/LosAngeles/Tokyo core phase on49be; original66 also PASS each zone. Full build/types and source production acceptance completed. | Current closure review 2026-10-09T15:45:41.083Z: Complete test-file obligation closed. Independent95-check review42d4e2a and raw hosted per-file1a0fd2c1 establish meaningful assertions and exact source pins. Synthetic worker/runtime/database integration does not activate a real provider or close the whole fleet feature; broader holds remain unchanged. Historical cells preserved before 2026-10-09T15:45:41.083Z: Tests=Synthetic evidence under independent review; complete acceptance pending.; Fix=Root-owned proposed source fix; not installed yet.; Retest=Project and full workflow gates pending.. Historical notes retained: Discovered 2026-10-09T13:00:28.498Z: Planned permanent regression controls for synthetic cancellation, timeout and resource cleanup; inherited66 worker tests retained. No provider execution. No closure credit. Root local acceptance2026-10-09UTC: complete calendar/worker fix is now integrated on owned main-c67 branch. Exact shared15source/test pins pass2668tests/noSKIP/noFAIL in eachUTC/LosAngeles/Tokyo, full project types and lint, plus audit reconciliation. New calendar fixture uses canonical minimum .000Z so the lexical transport cannot hide strict-vs-inclusive lower-edge mistakes. Permanent API spies prove refusal before factory and context-family filters; mocked Auth is not RLS acceptance. Worker86 inherited/new controls and60 native promise-boundary probes support cancellation/cleanup repair; real provider activation remains off. Fresh hosted build/browser/Auth/database and deployment gates are still pending; full-item status remains IN PROGRESS and no closure credit. PR978 source49be/tree15566 normally merged as 00361e9de5b7ed1899c8a9513c5286747729b6bf; exact current-head terminal CI accepted with ordered three-zone unit reports, build/types, genuine browser/Auth and owned-stack cleanup. Canonical production revision and anonymous cache/login/redirect contracts independently verified; production receipt 97e740efc87021f1ab52c061112cfcca37ba4693f477e188c94766c27d8b9dd4. Scoped calendar/worker/test fixes are installed, but these broad audit obligations remain IN PROGRESS; private persistent-session proposals, provider/native/RLS and production schema/configuration gaps receive no closure credit. | | SUPPORT-7E81C8029566 | SUPPORT | tests/calendar-supported-boundary-callers.test.ts | ✅ PASS | Medium | All28 permanent date-form/wall-clock/installed-SDK boundary cases reviewed: canonical .000Z minimum/null-end occupancy, invalid/BCE refusal before SDK, actual supported family predicates and modern positive controls. | Permanent28-case regression installed49be/00361; original canonical source24RED/4PASS and wall/local/day reversions3/5/4RED retained. Strict/inclusive/underflow query mutants detected. | Whole28-case file PASS without skipped/expected-failure cases in all three ordered exact49be UTC/LosAngeles/Tokyo hosted unit phases. Build/types/source deployment accepted. | Current closure review 2026-10-09T15:45:41.083Z: Complete synthetic test-file obligation closed, independent review3f694c30. Actual installed SDK uses synthetic transport; capabilityfalse and parent scope are explicit. No production SQL/Auth/RLS, external provider or broad calendar source-activation acceptance is inferred. Historical cells preserved before 2026-10-09T15:45:41.083Z: Tests=Synthetic evidence under independent review; complete acceptance pending.; Fix=Root-owned proposed source fix; not installed yet.; Retest=Project and full workflow gates pending.. Historical notes retained: Discovered 2026-10-09T13:00:28.498Z: Planned actual date-form/wall-clock/installed-SDK boundary controls including exact-minimum null-end retention; existing calendar assertions retained. No live Auth/RLS acceptance. No closure credit. Root local acceptance2026-10-09UTC: complete calendar/worker fix is now integrated on owned main-c67 branch. Exact shared15source/test pins pass2668tests/noSKIP/noFAIL in eachUTC/LosAngeles/Tokyo, full project types and lint, plus audit reconciliation. New calendar fixture uses canonical minimum .000Z so the lexical transport cannot hide strict-vs-inclusive lower-edge mistakes. Permanent API spies prove refusal before factory and context-family filters; mocked Auth is not RLS acceptance. Worker86 inherited/new controls and60 native promise-boundary probes support cancellation/cleanup repair; real provider activation remains off. Fresh hosted build/browser/Auth/database and deployment gates are still pending; full-item status remains IN PROGRESS and no closure credit. PR978 source49be/tree15566 normally merged as 00361e9de5b7ed1899c8a9513c5286747729b6bf; exact current-head terminal CI accepted with ordered three-zone unit reports, build/types, genuine browser/Auth and owned-stack cleanup. Canonical production revision and anonymous cache/login/redirect contracts independently verified; production receipt 97e740efc87021f1ab52c061112cfcca37ba4693f477e188c94766c27d8b9dd4. Scoped calendar/worker/test fixes are installed, but these broad audit obligations remain IN PROGRESS; private persistent-session proposals, provider/native/RLS and production schema/configuration gaps receive no closure credit. | +| SUPPORT-9285EEEF0F4C | SUPPORT | tests/schedule-zoned-clock-contracts.test.ts | 🔄 IN PROGRESS | High | Complete bounded file 45 assertionsPASS×3, original/causal controls retained. | Reviewed exact source/test patch installed in isolated candidate; whole source file/module not redefined. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim. | Current five-fix checkpoint2026-10-09T17:06:32.207Z:No closure credit before exact committed-head hosted acceptance; private control failures and source/test raw→Git normalization remain preserved. Historical cells preserved before 2026-10-09T17:06:32.207Z: Tests=45 native helper contracts; exact baseline/reversion37PASS8RED; selective admission/slice/device-zone mutants fail.; Fix=Added only in owned isolated uncommitted source candidate; authored assertions retained.; Retest=Complete current file executed in combined1801PASS×3; full typesPASS; fresh committed-source hosted/build/release acceptance pending.. Historical notes retained:Discovered 2026-10-09T16:50:31.128Z: permanent repository candidate file inventoried before publication, not a private fixture counted as deployed source. No closure credit. Isolated owned candidate only:1801 assertions across63 complete files PASS/noSKIP/noFAIL in eachUTC/LA/Tokyo; full project typesPASS. Source is not committed, hosted or released at this checkpoint. Fresh candidate build/lint/CI and exact production-source readback remain required. | +| SUPPORT-E1F850EBB1FE | SUPPORT | tests/calendar-window-normalization-domain.test.ts | 🔄 IN PROGRESS | High | Complete bounded file 74 assertionsPASS×3, original/causal controls retained. | Reviewed exact source/test patch installed in isolated candidate; whole source file/module not redefined. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim. | Current five-fix checkpoint2026-10-09T17:06:32.207Z:No closure credit before exact committed-head hosted acceptance; private control failures and source/test raw→Git normalization remain preserved. Historical cells preserved before 2026-10-09T17:06:32.207Z: Tests=74 full normalization/SDK domain controls; baseline68PASS6RED;23 original files retained; historical local-second drift explicitly outside this bounded regression scope.; Fix=Added only in owned isolated uncommitted source candidate; authored assertions retained.; Retest=Complete current file executed in combined1801PASS×3; full typesPASS; fresh committed-source hosted/build/release acceptance pending.. Historical notes retained:Discovered 2026-10-09T16:50:31.128Z: permanent repository candidate file inventoried before publication, not a private fixture counted as deployed source. No closure credit. Isolated owned candidate only:1801 assertions across63 complete files PASS/noSKIP/noFAIL in eachUTC/LA/Tokyo; full project typesPASS. Source is not committed, hosted or released at this checkpoint. Fresh candidate build/lint/CI and exact production-source readback remain required. | +| SUPPORT-3752656BDF3E | SUPPORT | tests/calendar-date-handoff-keeps-supported-years.test.ts | 🔄 IN PROGRESS | High | Complete bounded file 38 assertionsPASS×3, original/causal controls retained. | Reviewed exact source/test patch installed in isolated candidate; whole source file/module not redefined. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim. | Current five-fix checkpoint2026-10-09T17:06:32.207Z:No closure credit before exact committed-head hosted acceptance; private control failures and source/test raw→Git normalization remain preserved. Historical cells preserved before 2026-10-09T17:06:32.207Z: Tests=38 nativeDate/actualReact-provider DATE handoff cases; baseline28PASS10RED×3; legacy admission/calendar overflow retained.; Fix=Added only in owned isolated uncommitted source candidate; authored assertions retained.; Retest=Complete current file executed in combined1801PASS×3; full typesPASS; fresh committed-source hosted/build/release acceptance pending.. Historical notes retained:Discovered 2026-10-09T16:50:31.128Z: permanent repository candidate file inventoried before publication, not a private fixture counted as deployed source. No closure credit. Isolated owned candidate only:1801 assertions across63 complete files PASS/noSKIP/noFAIL in eachUTC/LA/Tokyo; full project typesPASS. Source is not committed, hosted or released at this checkpoint. Fresh candidate build/lint/CI and exact production-source readback remain required. | +| SUPPORT-3D4C6E164D9C | SUPPORT | tests/time-zoned-offset-seconds.test.ts | 🔄 IN PROGRESS | High | 46 actual native/installedSDK helper contracts; baseline23RED, exactscalar/civil guardmutants1/3RED; publicshape/fraction/shortgap/fold controls. | New owned repository candidate regression file; authored assertions retained. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim. | Discovered2026-10-09T17:06:32.207Z: permanent inventoried before source publication; no closure credit. Pure/synthetic transport/browser proof is not real Auth/RLS/provider/production acceptance. | +| SUPPORT-FFF59165062B | SUPPORT | tests/local-input-unchanged-instant.test.ts | 🔄 IN PROGRESS | High | 54 lasting native/helper/actual-action-with-modeled-Auth contracts; baseline17RED, strictadmission9RED and caller3RED. | New owned repository candidate regression file; authored assertions retained. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim. | Discovered2026-10-09T17:06:32.207Z: permanent inventoried before source publication; no closure credit. Pure/synthetic transport/browser proof is not real Auth/RLS/provider/production acceptance. | +| SUPPORT-624C9B58A81D | SUPPORT | tests/e2e/local-input-unchanged-instant.spec.ts | 🔄 IN PROGRESS | High | Six browser cases per device-zone;18 actual extracted modal/React/native DOM/FormData/helper cases firstattemptPASS across3zones, with synthetic widgets/schema/action endpoints. | New owned repository candidate regression file; authored assertions retained. | Actual installed isolated candidate118completefiles2904PASS/noFAIL/noSKIP eachUTC/LA/Tokyo, full project typesPASS, changed source/new tests lintPASS. Fresh committed-source hosted/build/browser/Auth/DB/cleanup and production readback remain pending; no whole feature or real Auth/RLS closure claim. | Discovered2026-10-09T17:06:32.207Z: permanent inventoried before source publication; no closure credit. Pure/synthetic transport/browser proof is not real Auth/RLS/provider/production acceptance. | # 1. Executive Summary diff --git a/lib/briefing/calendar-window.ts b/lib/briefing/calendar-window.ts index e1f09b458..40106a362 100644 --- a/lib/briefing/calendar-window.ts +++ b/lib/briefing/calendar-window.ts @@ -126,9 +126,12 @@ export function normalizeCalendarWindowInstant(value: string, timezone = 'UTC'): if (!resolved) throw new RangeError('Invalid calendar local time'); const exact = BigInt(resolved.getTime()) * 1_000_000n + BigInt(second) * 1_000_000_000n + BigInt(fraction.padEnd(9, '0') || '0'); const normalized = formatExactInstant(exact); + parseExactInstant(normalized); return normalized.slice(0, 20) + normalized.slice(20, -1).padEnd(Math.max(3, fraction.length), '0') + 'Z'; } - return normalizeExactInstant(value); + const normalized = normalizeExactInstant(value); + parseExactInstant(normalized); + return normalized; } /** The PostgREST OR filter for a window's two halves, for the rows that are NOT series. */ diff --git a/lib/schedule/zoned.ts b/lib/schedule/zoned.ts index 31c04f719..34843bc92 100644 --- a/lib/schedule/zoned.ts +++ b/lib/schedule/zoned.ts @@ -60,10 +60,12 @@ export function zonedTimeMs(dayKey: string, hour: number, minute: number, tz: st /** "6:00 PM" for an instant, on the family's wall clock. Empty when unparseable. */ export function clockInZone(ms: number, tz: string): string { if (!Number.isFinite(ms)) return ''; + const instant = new Date(ms); + if (!Number.isFinite(instant.getTime())) return ''; try { - return new Intl.DateTimeFormat('en-US', { timeZone: tz, hour: 'numeric', minute: '2-digit' }).format(new Date(ms)); + return new Intl.DateTimeFormat('en-US', { timeZone: tz, hour: 'numeric', minute: '2-digit' }).format(instant); } catch { - return new Date(ms).toISOString().slice(11, 16); + return `${String(instant.getUTCHours()).padStart(2, '0')}:${String(instant.getUTCMinutes()).padStart(2, '0')}`; } } diff --git a/lib/time/local-input.ts b/lib/time/local-input.ts index e42aa8c4e..e3623a10b 100644 --- a/lib/time/local-input.ts +++ b/lib/time/local-input.ts @@ -51,6 +51,7 @@ // Framework-free and safe in a client bundle: no `server-only`, no DOM. The // zoned half uses `Intl` through `lib/time/zoned.ts`. import { instantForLocalTime, isValidTimezone, localPartsAt } from '@/lib/time/zoned'; +import { parseExactInstant } from '@/lib/calendar/exact-instant'; /** * The naive wall clock that a `datetime-local` box shows for an instant, as the @@ -95,12 +96,26 @@ const NAIVE = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3}) * dropping the event out of the day. From that instant on the round trip is * closed as usual, because the box then shows the hour that does exist. */ -export function fromLocalInput(value: string | null | undefined, timeZone?: string): string | undefined { +export function fromLocalInput( + value: string | null | undefined, timeZone?: string, originalInstant?: string | null, +): string | undefined { if (value == null) return undefined; const v = value.trim(); if (!v) return undefined; const m = NAIVE.exec(v); if (!m || Number(m[1]) < 1) return v; + // A minute-only box cannot distinguish both occurrences of a repeated hour + // or carry the stored seconds. An unchanged edit retains its own original + // instant, only when it is valid and displays this exact box in this zone. + // Changed values and callers without a hint keep the existing resolution. + if (originalInstant) { + try { + parseExactInstant(originalInstant); + if (toLocalInput(originalInstant, timeZone) === v) return originalInstant; + } catch { + // A malformed or non-absolute hint cannot change the legacy resolution. + } + } if (timeZone && isValidTimezone(timeZone)) { // The family's clock, the same frame `toLocalInput(iso, timeZone)` read the // prefill in. Seconds and milliseconds are carried on top of the minute the diff --git a/lib/time/zoned.ts b/lib/time/zoned.ts index 120cc58a7..4e32d63c1 100644 --- a/lib/time/zoned.ts +++ b/lib/time/zoned.ts @@ -44,17 +44,22 @@ function formatterFor(timezone: string): Intl.DateTimeFormat { if (!dtf) { dtf = new Intl.DateTimeFormat('en-US', { timeZone: timezone, hour12: false, - era: 'short', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', + era: 'short', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', }); partsCache.set(timezone, dtf); } return dtf; } -/** The wall-clock reading an observer in `timezone` sees at `instant`. */ -export function localPartsAt(instant: Date, timezone: string): LocalParts { +function formattedPartsAt(instant: Date, timezone: string): Record { const parts: Record = {}; for (const part of formatterFor(timezone).formatToParts(instant)) parts[part.type] = part.value; + return parts; +} + +/** The wall-clock reading an observer in `timezone` sees at `instant`. */ +export function localPartsAt(instant: Date, timezone: string): LocalParts { + const parts = formattedPartsAt(instant, timezone); return { // Intl numbers BC years from one; Date uses astronomical year zero. year: parts.era === 'BC' ? 1 - Number(parts.year) : Number(parts.year), @@ -90,10 +95,19 @@ export function dayKeyIn(instant: Date, timezone: string): string { } } +/** Internal exact civil clock; public LocalParts intentionally stays minute-only. */ +function wallMillisecondsAt(instant: Date, timezone: string): number { + const parts = formattedPartsAt(instant, timezone); + const year = parts.era === 'BC' ? 1 - Number(parts.year) : Number(parts.year); + const wall = new Date(0); + wall.setUTCFullYear(year, Number(parts.month) - 1, Number(parts.day)); + wall.setUTCHours(Number(parts.hour) % 24, Number(parts.minute), Number(parts.second), instant.getUTCMilliseconds()); + return wall.getTime(); +} + /** Zone offset in ms at a given instant (positive east of UTC). */ function offsetMsAt(instant: Date, timezone: string): number { - const p = localPartsAt(instant, timezone); - return utcMilliseconds(p.year, p.month - 1, p.day, p.hour, p.minute) - instant.getTime(); + return wallMillisecondsAt(instant, timezone) - instant.getTime(); } /** @@ -118,7 +132,7 @@ export function zonedLocalToInstant( const check = localPartsAt(new Date(ts), timezone); const matches = check.year === year && check.month === month && check.day === day && check.hour === hour && check.minute === minute; - return matches ? new Date(ts) : null; + return matches && wallMillisecondsAt(new Date(ts), timezone) === naive ? new Date(ts) : null; } /** @@ -172,10 +186,7 @@ export function instantForIcsLocalTime( ): Date | null { const wall = utcMilliseconds(year, month - 1, day, Math.floor(minutes / 60), minutes % 60); if (!Number.isFinite(wall)) return null; - const reads = (instant: number) => { - const p = localPartsAt(new Date(instant), timezone); - return utcMilliseconds(p.year, p.month - 1, p.day, p.hour, p.minute); - }; + const reads = (instant: number) => wallMillisecondsAt(new Date(instant), timezone); const offsets = new Set([-2, -1, 0, 1, 2].map((days) => offsetMsAt(new Date(wall + days * DAY_MS), timezone))); const candidates = [...offsets].map((offset) => wall - offset).sort((a, b) => a - b); const exact = candidates.find((instant) => reads(instant) === wall); diff --git a/tests/a-family-wall-clock-ignores-the-devices-daylight-saving.test.ts b/tests/a-family-wall-clock-ignores-the-devices-daylight-saving.test.ts index 33d2938ce..fe8aaed33 100644 --- a/tests/a-family-wall-clock-ignores-the-devices-daylight-saving.test.ts +++ b/tests/a-family-wall-clock-ignores-the-devices-daylight-saving.test.ts @@ -427,7 +427,7 @@ describe('the calendar form compares the times it will save (#688 comment 592212 it('NewEventModal resolves both boxes on the family\'s clock before comparing them, and saves those', () => { const src = readFileSync(join(__dirname, '..', 'components/modules/calendar-module.tsx'), 'utf8'); const submit = between(src, 'const parsed = eventSchema.safeParse(input);', 'const result = existing'); - expect(submit).toContain('const startsAt = fromLocalInput(parsed.data.starts_at, timeZone)'); + expect(submit).toContain('const startsAt = fromLocalInput(parsed.data.starts_at, timeZone, existing?.starts_at)'); expect(submit).toContain('if (endsAt && new Date(endsAt) <= new Date(startsAt))'); expect(submit).not.toMatch(/new Date\(parsed\.data\./); expect(at(submit, 'const startsAt')).toBeLessThan(at(submit, 'new Date(endsAt)')); diff --git a/tests/calendar-date-handoff-keeps-supported-years.test.ts b/tests/calendar-date-handoff-keeps-supported-years.test.ts new file mode 100644 index 000000000..811af4b07 --- /dev/null +++ b/tests/calendar-date-handoff-keeps-supported-years.test.ts @@ -0,0 +1,91 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { createElement, type ComponentProps } from 'react'; +import { renderToString } from 'react-dom/server'; +import { FamilyTimeZoneProvider, LocaleProvider } from '@/components/i18n/locale-provider'; +import { calendarDayOfKey, useFamilyClock, type FamilyClock } from '@/components/i18n/use-format'; +import { localeOrDefault } from '@/lib/i18n/locales'; + +// A DATE-only handoff is a device-local calendar Date, not a wall reading or +// an instant. Use its local fields; the helper's calendar overflow remains +// unchanged. These native Date and real React-provider checks do not claim +// browser hydration, provider, authorization, API or production acceptance. +const supportedDays = ['0001-01-01', '0004-02-29', '0099-12-31', '0100-03-01', '0400-02-29', '2026-10-09', '9999-12-31']; +const parts = (date: Date) => [date.getFullYear(), date.getMonth() + 1, date.getDate()]; +const expectedParts = (day: string) => day.split('-').map(Number); + +function clockFor(timeZone: string): FamilyClock { + let clock: FamilyClock | undefined; + const Probe = () => { clock = useFamilyClock(); return null; }; + renderToString(createElement(LocaleProvider, { + locale: localeOrDefault('en-US'), source: 'default', messages: {}, + } as ComponentProps, + createElement(FamilyTimeZoneProvider, { timeZone } as ComponentProps, createElement(Probe)))); + if (!clock) throw new Error('The actual provider did not produce a family clock'); + return clock; +} + +afterEach(() => vi.restoreAllMocks()); + +describe('the DATE-only constructor keeps supported Gregorian years', () => { + it.each(supportedDays)('%s retains its local calendar fields', day => { + expect(parts(calendarDayOfKey(day))).toEqual(expectedParts(day)); + }); + + it.each([ + ['0001-12-32', [2, 1, 1]], + ['0004-02-30', [4, 3, 1]], + ['0099-13-01', [100, 1, 1]], + ['0100-02-29', [100, 3, 1]], + ['0400-02-30', [400, 3, 1]], + ['2026-02-30', [2026, 3, 2]], + ['2026-00-00', [2025, 11, 30]], + ['9999-12-00', [9999, 11, 30]], + ['9999-13-01', [10000, 1, 1]], + ] as const)('%s keeps the existing constructor calendar overflow', (key, expected) => { + // Public DATE admission is validated separately. An internal constructor + // rollover must not silently return a different century or adopt a new + // strict-date policy here. + expect(parts(calendarDayOfKey(key))).toEqual(expected); + }); + + it.each(['bad', '', '2026-01', '2026/01/01', '2026-01-notday', 'Infinity-01-01'])('%s remains unparseable', key => { + expect(Number.isNaN(calendarDayOfKey(key).getTime())).toBe(true); + }); + + it.each(['0000-01-01', '10000-01-01', '-000001-01-01', '1.5-01-01', '0-00-00'])('%s retains its unsupported or legacy constructor result', key => { + // Preserve the prior result without admitting this input as a supported + // public day or changing the existing invalid-input policy. + const [year, month, day] = key.split('-').map(Number); + expect(calendarDayOfKey(key).getTime()).toBe(new Date(year, month - 1, day).getTime()); + }); +}); + +describe('the actual family clock hands off the family date unchanged', () => { + it.each(supportedDays)('%s stays the same through the React-provider DATE handoff', day => { + const now = new Date(day + 'T12:30:00Z'); + const clock = clockFor('UTC'); + expect(clock.todayKey(now)).toBe(day); + expect(clock.wallKey(clock.wallNow(now))).toBe(day); + expect(parts(clock.calendarToday(now))).toEqual(expectedParts(day)); + }); + + it.each([ + ['America/Los_Angeles', '2026-10-09T01:30:00Z', '2026-10-08'], + ['Asia/Tokyo', '2026-10-09T23:30:00Z', '2026-10-10'], + ['America/Santiago', '2026-09-06T15:00:00Z', '2026-09-06'], + ])('%s hands off its own day rather than the UTC day', (zone, instant, day) => { + const clock = clockFor(zone); + const now = new Date(instant); + expect(clock.todayKey(now)).toBe(day); + expect(clock.wallKey(clock.wallNow(now))).toBe(day); + expect(parts(clock.calendarToday(now))).toEqual(expectedParts(day)); + }); + + it('uses the supplied AD1 clock without reading Date.now', () => { + const clock = clockFor('UTC'); + const now = new Date('0001-01-01T12:30:00Z'); + const read = vi.spyOn(Date, 'now').mockImplementation(() => { throw new Error('Unexpected ambient clock read'); }); + expect(parts(clock.calendarToday(now))).toEqual([1, 1, 1]); + expect(read).not.toHaveBeenCalled(); + }); +}); diff --git a/tests/calendar-window-normalization-domain.test.ts b/tests/calendar-window-normalization-domain.test.ts new file mode 100644 index 000000000..24088e0bb --- /dev/null +++ b/tests/calendar-window-normalization-domain.test.ts @@ -0,0 +1,202 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { createClient } from '@supabase/supabase-js'; +import { + briefingCalendarBounds, briefingCalendarWindow, calendarOpenWindowFilter, + calendarOverlapWindowFilter, calendarWindowFilter, estimatedEndLookback, + instantCalendarBounds, normalizeCalendarWindowInstant, +} from '@/lib/briefing/calendar-window'; +import { parseExactInstant } from '@/lib/calendar/exact-instant'; +import { searchEvents } from '@/lib/services/calendar'; +import { orPredicate } from './helpers/in-memory-supabase'; + +// Native Date/Intl and the installed SDK with a synthetic, read-only transport. +// The service scope is supplied, so this is not real authentication/RLS proof. +const FAMILY = '10000000-0000-4000-8000-000000000001'; +function sdk(rows: Record[] = []) { + const calls: URL[] = []; + const db = createClient('https://calendar-window.synthetic.invalid', 'synthetic-key', { + auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false }, + global: { fetch: async (input, init) => { + const url = new URL(String(input)); calls.push(url); + expect(url.origin).toBe('https://calendar-window.synthetic.invalid'); + expect(url.pathname).toBe('/rest/v1/calendar_events'); + expect(init?.method ?? 'GET').toBe('GET'); + expect(url.searchParams.get('family_id')).toBe('eq.' + FAMILY); + const filter = url.searchParams.get('or'); + const selected = filter ? rows.filter(orPredicate(filter.slice(1, -1))) : rows; + return Response.json(selected, { headers: { 'content-range': `0-${Math.max(0, selected.length - 1)}/${selected.length}` } }); + } }, + }); + return { db, calls }; +} +afterEach(() => vi.restoreAllMocks()); + +describe('calendar window final normalized instant domain', () => { + it.each([ + ['0001-01-01T00:00', 'Asia/Tokyo'], + ['0001-01-01T00:00:00.000000001', 'Asia/Tokyo'], + ['0001-01-01T00:00:00+01:00', 'UTC'], + ])('refuses a supported input whose normalized instant escapes below AD1: %s %s', (input, zone) => { + expect(() => normalizeCalendarWindowInstant(input, zone)).toThrow(); + expect(() => instantCalendarBounds(input, input, zone)).toThrow(); + }); + + it.each([ + ['0001-01-01T00:00', 'Asia/Tokyo'], + ['0001-01-01T00:00:00.000000001', 'Asia/Tokyo'], + ['0001-01-01T00:00:00+01:00', 'UTC'], + ])('refuses the same invalid normalized raw-row search before SDK transport: %s %s', async (from, tz) => { + const probe = sdk(); + const scope = { db: probe.db, familyId: FAMILY, userId: 'synthetic-user', memberId: 'synthetic-member', role: 'parent' as const, actorKind: 'member' as const, tz }; + const result = await searchEvents(scope, { from, expandSeries: false }); + expect(result.ok).toBe(false); + expect(probe.calls).toEqual([]); + }); + + it.each([ + ['0001-01-01T00:00:00Z', 'UTC', '0001-01-01T00:00:00.000Z'], + ['0001-01-01', 'Asia/Tokyo', '0001-01-01T00:00:00.000Z'], + ['2026-10-09', 'America/Los_Angeles', '2026-10-09T00:00:00.000Z'], + ['2026-10-09T12:30', 'America/New_York', '2026-10-09T16:30:00.000Z'], + ['2026-10-09T12:30:42.123456789', 'America/New_York', '2026-10-09T16:30:42.123456789Z'], + ['2026-10-09T12:30:42.100000000', 'America/New_York', '2026-10-09T16:30:42.100000000Z'], + ['2026-10-09T12:30:42.000001+05:45', 'UTC', '2026-10-09T06:45:42.000001Z'], + ['2026-10-09T12:30:42-03:30', 'Asia/Tokyo', '2026-10-09T16:00:42.000Z'], + ['0001-01-01T23:59:00+23:59', 'UTC', '0001-01-01T00:00:00.000Z'], + ['9999-12-31T00:00:00Z', 'UTC', '9999-12-31T00:00:00.000Z'], + ])('retains accepted bare/floating/absolute clock and declared precision: %s', (value, zone, expected) => { + const normalized = normalizeCalendarWindowInstant(value, zone); + expect(normalized).toBe(expected); + expect(parseExactInstant(normalized)).toBe(parseExactInstant(expected)); + }); + + it('keeps the normalizer default UTC independent of host time', () => { + expect(normalizeCalendarWindowInstant('2026-10-09T12:30')).toBe('2026-10-09T12:30:00.000Z'); + }); + + it.each([ + ['2026-03-08T02:30:42.000001', 'America/New_York', '2026-03-08T07:30:42.000001Z'], + ['2026-11-01T01:30:42.000001', 'America/New_York', '2026-11-01T05:30:42.000001Z'], + ['2011-12-30T12:30:00', 'Pacific/Apia', '2011-12-30T22:30:00.000Z'], + ])('retains RFC pre-gap offset and earliest fold resolution: %s', (input, zone, expected) => { + expect(normalizeCalendarWindowInstant(input, zone)).toBe(expected); + }); + + it.each(['', 'bad', '0000-12-31', '2026-02-30', '2026-10-09T24:00', '2026-10-09T12:60', '2026-10-09T12:30:60', '2026-10-09T12:30:00.1234567890', '2026-10-09T12:30:00+24:00', '2026-10-09T12:30:00+01:60', ' 2026-10-09T12:30:00Z ', '+010000-01-01T00:00:00Z'])('does not invent a clock for malformed token %s', value => { + expect(() => normalizeCalendarWindowInstant(value, 'UTC')).toThrow(); + }); + + it.each(['', 'Not/AZone', ' Mars/Olympus '])('refuses unusable zones before a normalizer clock is admitted: %s', zone => { + expect(() => normalizeCalendarWindowInstant('2026-10-09', zone)).toThrow(); + expect(() => briefingCalendarBounds('2026-10-09', zone, 0, 1)).toThrow(); + expect(() => instantCalendarBounds('2026-10-09T00:00:00Z', '2026-10-09T01:00:00Z', zone)).toThrow(); + }); +}); + +describe('all public calendar bounds and formatter contracts', () => { + it.each([ + ['UTC', '2026-10-09', '2026-10-09T00:00:00.000Z', '2026-10-10T00:00:00.000Z'], + ['America/New_York', '2026-03-08', '2026-03-08T05:00:00.000Z', '2026-03-09T04:00:00.000Z'], + ['America/New_York', '2026-11-01', '2026-11-01T04:00:00.000Z', '2026-11-02T05:00:00.000Z'], + ['Asia/Kathmandu', '2026-10-09', '2026-10-08T18:15:00.000Z', '2026-10-09T18:15:00.000Z'], + ['Pacific/Apia', '2011-12-30', '2011-12-30T10:00:00.000Z', '2011-12-30T10:00:00.000Z'], + ['UTC', '0001-01-01', '0001-01-01T00:00:00.000Z', '0001-01-02T00:00:00.000Z'], + ['UTC', '9999-12-30', '9999-12-30T00:00:00.000Z', '9999-12-31T00:00:00.000Z'], + ])('uses complete family-day bounds %s %s', (zone, day, from, to) => { + const bounds = briefingCalendarBounds(day, zone, 0, 1); + expect(bounds.timedFrom).toBe(from); expect(bounds.timedTo).toBe(to); + expect(bounds.allDayFromDay).toBe(day); + expect(briefingCalendarWindow(day, zone, 0, 1)).toBe(calendarWindowFilter(bounds)); + }); + + it('offsets the window by calendar days and keeps a single bounded formatter search', () => { + const parts = vi.spyOn(Intl.DateTimeFormat.prototype, 'formatToParts'); + const bounds = briefingCalendarBounds('2026-03-07', 'America/New_York', 1, 2); + expect(bounds).toEqual({ timedFrom: '2026-03-08T05:00:00.000Z', timedTo: '2026-03-10T04:00:00.000Z', allDayFromDay: '2026-03-08', allDayToDay: '2026-03-10' }); + expect(parts.mock.calls.length).toBeLessThanOrEqual(62); + }); + + it.each([['2026-02-30', 0, 1], ['0000-12-31', 0, 1], ['9999-12-31', 0, 1], ['2026-10-09', -1, 1], ['2026-10-09', 0, 0], ['2026-10-09', 0.5, 1], ['2026-10-09', 0, Number.NaN], ['2026-10-09', 0, Number.POSITIVE_INFINITY], ['2026-10-09', Number.MAX_SAFE_INTEGER, 1]] as const)('refuses an unrepresentable DATE window %s %s %s', (day, offset, count) => { + expect(() => briefingCalendarBounds(day, 'UTC', offset, count)).toThrow(); + }); + + it.each([ + ['2026-10-09T12:30:00Z', '2026-10-09T12:30:00.001Z'], + ['2026-10-09T12:30:00.000000Z', '2026-10-09T12:30:00.000001Z'], + ['2026-10-09T12:30:00.000000000Z', '2026-10-09T12:30:00.000000001Z'], + ['2026-10-09T23:59:59.999999999Z', '2026-10-10T00:00:00.000Z'], + ])('advances inclusive endpoint only by its declared unit %s', (last, exclusive) => { + const bounds = instantCalendarBounds('2026-10-09T00:00:00Z', last, 'UTC'); + expect(bounds.timedTo).toBe(exclusive); + expect(bounds.allDayFromDay).toBe('2026-10-09'); expect(bounds.allDayToDay).toBe('2026-10-10'); + }); + + it('uses the exact family day while preserving a submillisecond lower endpoint', () => { + expect(instantCalendarBounds('2026-10-09T01:00:00.000000001Z', '2026-10-09T02:00:00.000000009Z', 'America/Los_Angeles')).toEqual({ timedFrom: '2026-10-09T01:00:00.000000001Z', timedTo: '2026-10-09T02:00:00.00000001Z', allDayFromDay: '2026-10-08', allDayToDay: '2026-10-09' }); + }); + + it.each([ + ['2026-10-09T12:30:00.000009Z', '2026-10-09T12:30:00.000001Z', 'UTC'], + ['9999-12-31T00:00:00Z', '9999-12-31T00:00:00Z', 'UTC'], + ['0001-01-01T00:00:00Z', '0001-01-01T00:30:00Z', 'America/New_York'], + ['9999-12-31T23:59:59Z', '9999-12-31T23:59:59Z', 'Asia/Tokyo'], + ])('refuses reversed/exclusive/projected-domain overflow %s %s %s', (from, to, zone) => { + expect(() => instantCalendarBounds(from, to, zone)).toThrow(); + }); + + it.each([ + ['0001-01-01T00:00:00Z', '0001-01-01T00:00:00.000Z', 'gte'], + ['0001-01-01T00:59:59.999999999Z', '0001-01-01T00:00:00.000Z', 'gte'], + ['0001-01-01T01:00:00Z', '0001-01-01T00:00:00.000Z', 'gt'], + ['0001-01-01T01:00:00.000000001Z', '0001-01-01T00:00:00.000000001Z', 'gt'], + ['2026-10-09T12:34:56.123456789Z', '2026-10-09T11:34:56.123456789Z', 'gt'], + ])('keeps a precise one-hour estimate and clamps only underflow %s', (from, start, comparison) => { + expect(estimatedEndLookback(from)).toEqual({ start, comparison }); + }); + + it.each(['bad', '0000-12-31T23:59:59Z', '0001-01-01T00:00:00+01:00', '9999-12-31T23:59:59-01:00'])('refuses unsupported raw lookback %s', from => { + expect(() => estimatedEndLookback(from)).toThrow(); + }); + + it.each(['start', 'open', 'overlap'])('serializes %s filters through the SDK and retains the intended boundary rows', async kind => { + const row = (id: string, start: string, end: string | null, allDay = false) => ({ id, starts_at: start, ends_at: end, all_day: allDay }); + const rows = [ + row('ongoing', '2026-10-09T11:00:00.000Z', '2026-10-09T12:30:00.000Z'), + row('inside', '2026-10-09T12:00:00.000Z', '2026-10-09T12:30:00.000Z'), + row('upper-edge', '2026-10-09T13:00:00.000Z', '2026-10-09T14:00:00.000Z'), + row('point-before', '2026-10-09T11:59:00.000Z', '2026-10-09T11:59:00.000Z'), + row('point-inside', '2026-10-09T12:15:00.000Z', '2026-10-09T12:15:00.000Z'), + row('missing-exact-hour', '2026-10-09T11:00:00.000Z', null), + row('missing-after-hour', '2026-10-09T11:00:00.001Z', null), + row('missing-inside', '2026-10-09T12:15:00.000Z', null), + row('all-current', '2026-10-09T00:00:00.000Z', null, true), + row('all-ongoing', '2026-10-08T00:00:00.000Z', '2026-10-10T00:00:00.000Z', true), + row('all-ended', '2026-10-08T00:00:00.000Z', '2026-10-09T00:00:00.000Z', true), + row('all-upper-edge', '2026-10-10T00:00:00.000Z', null, true), + ]; + const bounds = { timedFrom: '2026-10-09T12:00:00.000Z', timedTo: '2026-10-09T13:00:00.000Z', allDayFromDay: '2026-10-09', allDayToDay: '2026-10-10' }; + const filter = kind === 'start' ? calendarWindowFilter(bounds) : kind === 'open' ? calendarOpenWindowFilter(bounds) : calendarOverlapWindowFilter(bounds); + const probe = sdk(rows); + const result = await probe.db.from('calendar_events').select('*').eq('family_id', FAMILY).or(filter); + expect(result.error).toBeNull(); + expect(result.data?.map(row => row.id)).toEqual(kind === 'start' + ? ['inside', 'point-inside', 'missing-inside', 'all-current'] + : kind === 'open' + ? ['inside', 'upper-edge', 'point-inside', 'missing-inside', 'all-current', 'all-upper-edge'] + : ['ongoing', 'inside', 'point-inside', 'missing-after-hour', 'missing-inside', 'all-current', 'all-ongoing']); + expect(probe.calls).toHaveLength(1); + expect(probe.calls[0].searchParams.get('or')).toBe('(' + filter + ')'); + }); + + it('uses no ambient current clock in any exported helper', () => { + const now = vi.spyOn(Date, 'now').mockImplementation(() => { throw new Error('Ambient clock is not a calendar bound'); }); + const bounds = briefingCalendarBounds('2026-10-09', 'UTC', 0, 1); + expect(briefingCalendarWindow('2026-10-09', 'UTC', 0, 1)).toBe(calendarWindowFilter(bounds)); + expect(calendarOpenWindowFilter(bounds)).toContain('2026-10-09T00:00:00.000Z'); + expect(calendarOverlapWindowFilter(bounds)).toContain('2026-10-08T23:00:00.000Z'); + expect(estimatedEndLookback(bounds.timedFrom).comparison).toBe('gt'); + expect(instantCalendarBounds(bounds.timedFrom, '2026-10-09T12:00:00Z', 'UTC').allDayToDay).toBe('2026-10-10'); + expect(normalizeCalendarWindowInstant('2026-10-09')).toBe(bounds.timedFrom); + expect(now).not.toHaveBeenCalled(); + }); +}); diff --git a/tests/e2e/local-input-unchanged-instant.spec.ts b/tests/e2e/local-input-unchanged-instant.spec.ts new file mode 100644 index 000000000..88d038a7e --- /dev/null +++ b/tests/e2e/local-input-unchanged-instant.spec.ts @@ -0,0 +1,76 @@ +import fs from 'node:fs'; +import ts from 'typescript'; +import {test,expect,type Page} from '@playwright/test'; +import {reactBrowserScripts} from './helpers/react-browser'; + +const scripts=reactBrowserScripts('development'); +const files=['lib/time/zoned.ts','lib/time/local-input.ts','lib/utils/submission-id.ts','lib/calendar/exact-instant.ts','lib/onboarding/ics-time.ts']; +const sources=Object.fromEntries(files.map(file=>['@/'+file.replace(/\.ts$/,''),ts.transpileModule(fs.readFileSync(file,'utf8'),{compilerOptions:{target:ts.ScriptTarget.ES2022,module:ts.ModuleKind.CommonJS}}).outputText])); +sources['../onboarding/ics-time']=sources['@/lib/onboarding/ics-time']; +const modalSource=fs.readFileSync('components/modules/calendar-module.tsx','utf8'); +const marker='function NewEventModal('; +if(modalSource.indexOf(marker)<0)throw Error('Actual modal not found'); +const modal=ts.transpileModule(modalSource.slice(modalSource.indexOf(marker)),{compilerOptions:{target:ts.ScriptTarget.ES2022,module:ts.ModuleKind.CommonJS,jsx:ts.JsxEmit.React}}).outputText; +const browserErrors=new WeakMap(); + +async function mount(page:Page,existing:unknown,zone:string){ + const errors:string[]=[];browserErrors.set(page,errors);page.on('pageerror',e=>errors.push(e.message));page.on('console',m=>{if(m.type()==='error'||m.type()==='warning')errors.push(m.text());}); + await page.route('**/*',route=>route.request().url()==='https://local-input-fixture.invalid/'?route.fulfill({contentType:'text/html',body:'
'}):route.abort()); + await page.goto('https://local-input-fixture.invalid/');await page.addScriptTag({content:scripts.react});await page.addScriptTag({content:scripts.reactDom}); + await page.evaluate(({sources,modal,existing,zone})=>{ + const w=window as any,React=w.React; + const cache:Record={}; + function load(name:string):any{if(cache[name])return cache[name];if(!sources[name])throw Error(`Unexpected module ${name}`);const exports={};new Function('exports','require',sources[name])(exports,load);return cache[name]=exports;} + w.__calls=[];w.__saved=0;w.__errors=[]; + const {fromLocalInput,toLocalInput}=load('@/lib/time/local-input'); + const {newSubmissionId,submissionSettled}=load('@/lib/utils/submission-id'); + const Input=(props:any)=>React.createElement('input',props),Select=(props:any)=>React.createElement('select',props),Textarea=(props:any)=>React.createElement('textarea',props); + let field=0;const Field=({children}:any)=>React.createElement('div',{},typeof children==='function'?children(`field-${++field}`):children); + const Modal=({children}:any)=>React.createElement('section',{},children); + const Button=({children,loading,variant,size,...props}:any)=>React.createElement('button',{...props,disabled:loading},children); + const useFamilyClock=()=>({timeZone:zone}),useTranslations=()=>(key:string)=>key,useToast=()=>({error:(message:string)=>w.__errors.push(message)}); + // Only schema validation and server-action boundaries are synthetic. The + // actual modal, helpers, React, browser Intl/Date and native FormData execute. + // Existing action tests separately exercise real server actions with modeled Auth. + const eventSchema={safeParse:(input:unknown)=>({success:true,data:input})}; + const fieldErrors=()=>({}),describeDbError=(e:unknown)=>String(e); + const updateCalendarEventAction=async(id:string,fields:unknown)=>{w.__calls.push({mode:'update',id,fields});return{ok:true};}; + const createCalendarEventAction=async(fields:unknown)=>{w.__calls.push({mode:'create',fields});return{ok:true};}; + const useState=React.useState,useRef=React.useRef; + const component=new Function('React','useState','useRef','useFamilyClock','useTranslations','useToast','eventSchema','fieldErrors','describeDbError','updateCalendarEventAction','createCalendarEventAction','newSubmissionId','submissionSettled','fromLocalInput','toLocalInput','Modal','Input','Field','Select','Textarea','Button',`${modal};return NewEventModal;`)(React,useState,useRef,useFamilyClock,useTranslations,useToast,eventSchema,fieldErrors,describeDbError,updateCalendarEventAction,createCalendarEventAction,newSubmissionId,submissionSettled,fromLocalInput,toLocalInput,Modal,Input,Field,Select,Textarea,Button); + w.__root=w.ReactDOM.createRoot(document.getElementById('root'));w.__root.render(React.createElement(component,{existing,onClose:()=>{},onSaved:()=>w.__saved++})); + },{sources,modal,existing,zone}); + await expect(page.locator('form')).toBeVisible(); +} + +const cases=[ + ['New York both fold occurrences','America/New_York','2026-11-01T05:30:00.000Z','2026-11-01T06:30:00.000Z'], + ['London both fold occurrences','Europe/London','2026-10-25T00:30:00.000Z','2026-10-25T01:30:00.000Z'], + ['imported fractional precision','UTC','2026-10-09T12:30:29.456Z','2026-10-09T13:30:42.789Z'], + ['declared nanosecond precision','UTC','2026-10-09T12:30:29.456789012Z','2026-10-09T13:30:42.789123456Z'], +] as const; +for(const [name,zone,start,end]of cases)test(name,async({page})=>{ + await mount(page,{id:'synthetic-event',title:'Synthetic event',starts_at:start,ends_at:end,category:'general',recurrence:'none'},zone); + await page.locator('[name=title]').fill('Unrelated title edit');await page.getByRole('button',{name:'Save Changes'}).click(); + await expect.poll(()=>page.evaluate(()=>(window as any).__calls.length),{timeout:1500}).toBe(1); + const observed=await page.evaluate(()=>({call:(window as any).__calls[0],saved:(window as any).__saved,errors:(window as any).__errors})); + expect(observed.call.mode).toBe('update');expect(observed.call.id).toBe('synthetic-event'); + expect(observed.call.fields.startsAt).toBe(start);expect(observed.call.fields.endsAt).toBe(end);expect(observed.call.fields.title).toBe('Unrelated title edit'); + expect(observed.call.fields).not.toHaveProperty('family_id');expect(observed.call.fields).not.toHaveProperty('created_by'); + expect(observed.saved).toBe(1);expect(observed.errors).toEqual([]);expect(browserErrors.get(page)).toEqual([]); +}); + +test('changed wall boxes retain inherited conversion and end-order refusal',async({page})=>{ + await mount(page,{id:'synthetic-event',title:'Synthetic',starts_at:'2026-10-09T12:30:29.456Z',ends_at:'2026-10-09T13:30:42.789Z'},'UTC'); + await page.locator('[name=starts_at]').fill('2026-10-09T13:31');await page.getByRole('button',{name:'Save Changes'}).click(); + await expect(page.locator('form')).toBeVisible();expect(await page.evaluate(()=>(window as any).__calls.length)).toBe(0); + await page.locator('[name=starts_at]').fill('2026-10-09T12:31');await page.getByRole('button',{name:'Save Changes'}).click(); + await expect.poll(()=>page.evaluate(()=>(window as any).__calls.length),{timeout:1500}).toBe(1); + const call=await page.evaluate(()=>(window as any).__calls[0]);expect(call.fields.startsAt).toBe('2026-10-09T12:31:00.000Z');expect(call.fields.endsAt).toBe('2026-10-09T13:30:42.789Z');expect(browserErrors.get(page)).toEqual([]); +}); + +test('new form has no original to preserve',async({page})=>{ + await mount(page,null,'UTC');await page.locator('[name=title]').fill('New synthetic event');await page.locator('[name=starts_at]').fill('2026-10-09T12:30');await page.locator('[name=ends_at]').fill('2026-10-09T13:30');await page.getByRole('button',{name:'Add Event'}).click(); + await expect.poll(()=>page.evaluate(()=>(window as any).__calls.length),{timeout:1500}).toBe(1); + const call=await page.evaluate(()=>(window as any).__calls[0]);expect(call.mode).toBe('create');expect(call.fields.startsAt).toBe('2026-10-09T12:30:00.000Z');expect(call.fields.endsAt).toBe('2026-10-09T13:30:00.000Z');expect(call.fields.submissionId).toMatch(/^[\da-f-]{36}$/);expect(browserErrors.get(page)).toEqual([]); +}); diff --git a/tests/editing-a-calendar-event-leaves-it-where-it-was.test.ts b/tests/editing-a-calendar-event-leaves-it-where-it-was.test.ts index f29c2f7d9..997bbaf6c 100644 --- a/tests/editing-a-calendar-event-leaves-it-where-it-was.test.ts +++ b/tests/editing-a-calendar-event-leaves-it-where-it-was.test.ts @@ -115,8 +115,8 @@ async function saveWithNothingEdited(eventId: string) { const startsBox = toLocalInput(stored('starts_at')); const endsBox = toLocalInput(stored('ends_at')); const result = await updateCalendarEventAction(eventId, { - startsAt: fromLocalInput(startsBox) ?? '', - endsAt: fromLocalInput(endsBox) ?? null, + startsAt: fromLocalInput(startsBox, undefined, stored('starts_at')) ?? '', + endsAt: fromLocalInput(endsBox, undefined, stored('ends_at')) ?? null, }); expect(result.ok, result.ok ? '' : result.error).toBe(true); return { startsBox, endsBox }; @@ -232,8 +232,8 @@ describe('the modal hands the action an instant, not a box value', () => { // side, so the round trip is closed in the family's frame. // Resolved once, compared (end after start) and saved as those same values // (#688 comment 5922125002). - expect(src()).toMatch(/const startsAt = fromLocalInput\(parsed\.data\.starts_at, timeZone\)/); - expect(src()).toMatch(/const endsAt = fromLocalInput\(parsed\.data\.ends_at, timeZone\)/); + expect(src()).toMatch(/const startsAt = fromLocalInput\(parsed\.data\.starts_at, timeZone, existing\?\.starts_at\)/); + expect(src()).toMatch(/const endsAt = fromLocalInput\(parsed\.data\.ends_at, timeZone, existing\?\.ends_at\)/); expect(src()).toMatch(/title: parsed\.data\.title,\n\s*startsAt,\n\s*endsAt,/); expect(src()).toMatch(/defaultValue=\{toLocalInput\(existing\?\.starts_at \?\? null, timeZone\)\}/); }); diff --git a/tests/local-input-unchanged-instant.test.ts b/tests/local-input-unchanged-instant.test.ts new file mode 100644 index 000000000..61765aa40 --- /dev/null +++ b/tests/local-input-unchanged-instant.test.ts @@ -0,0 +1,154 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import type { SupabaseClient } from '@supabase/supabase-js'; +import type { Database } from '@/lib/database.types'; +import { createInMemorySupabase } from './helpers/in-memory-supabase'; +import { fromLocalInput, toLocalInput } from '@/lib/time/local-input'; + +const mocks=vi.hoisted(()=>({requireUserContext:vi.fn(),createServer:vi.fn(),revalidatePath:vi.fn()})); +vi.mock('@/lib/supabase/auth',()=>({requireUserContext:mocks.requireUserContext})); +vi.mock('@/lib/supabase/server',()=>({createServer:mocks.createServer})); +vi.mock('next/cache',()=>({revalidatePath:mocks.revalidatePath})); +import {createCalendarEventAction,updateCalendarEventAction} from '@/app/(app)/dashboard/calendar/actions'; + +const instants=[ + ['New York first fold','2026-11-01T05:30:00.000Z','America/New_York'], + ['New York second fold','2026-11-01T06:30:00.000Z','America/New_York'], + ['London first fold','2026-10-25T00:30:00.000Z','Europe/London'], + ['London second fold','2026-10-25T01:30:00.000Z','Europe/London'], + ['Los Angeles first fold','2026-11-01T08:30:00.000Z','America/Los_Angeles'], + ['Los Angeles second fold','2026-11-01T09:30:00.000Z','America/Los_Angeles'], + ['Lord Howe first half-hour fold','2026-04-04T14:45:00.000Z','Australia/Lord_Howe'], + ['Lord Howe second half-hour fold','2026-04-04T15:15:00.000Z','Australia/Lord_Howe'], + ['UTC seconds and milliseconds','2026-10-09T12:30:29.456Z','UTC'], + ['original offset spelling','2026-11-01T01:30:29.456-05:00','America/New_York'], + ['PostgreSQL microseconds','2026-10-09T12:30:29.456789Z','UTC'], + ['declared nanoseconds','2026-10-09T12:30:29.456789012Z','UTC'], + ['AD1 exact original','0001-01-01T12:30:29.456789012Z','UTC'], + ['AD9999 exact original','9999-12-31T12:30:29.456789012Z','UTC'], +] as const; + +describe('unchanged minute boxes retain their own original instant',()=>{ + it.each(instants)('%s preserves exact original bytes through three saves',(_name,original,zone)=>{ + let stored:string=original; + for(let save=0;save<3;save++){ + const box=toLocalInput(stored,zone); + expect(box).not.toBe(''); + const next=fromLocalInput(box,zone,stored); + expect(next).toBe(original);stored=next!; + } + }); + it('the same repeated box can retain two distinct owned instants',()=>{ + const first='2026-11-01T05:30:00.000Z',second='2026-11-01T06:30:00.000Z'; + const box=toLocalInput(first,'America/New_York'); + expect(box).toBe(toLocalInput(second,'America/New_York')); + expect(fromLocalInput(box,'America/New_York',first)).toBe(first); + expect(fromLocalInput(box,'America/New_York',second)).toBe(second); + expect(Date.parse(fromLocalInput(box,'America/New_York',second)!)-Date.parse(fromLocalInput(box,'America/New_York',first)!)).toBe(3600000); + }); + it('without a family zone, matching device prefill preserves stored seconds',()=>{ + const original='2026-10-09T12:30:29.456Z'; + expect(fromLocalInput(toLocalInput(original),undefined,original)).toBe(original); + }); + it('only the submitted box is trimmed before comparison',()=>{ + const original='2026-10-09T12:30:29.456Z'; + expect(fromLocalInput(' 2026-10-09T12:30 ','UTC',original)).toBe(original); + }); +}); + +describe('hint admission does not change the existing two-argument policy',()=>{ + it.each(['UTC','America/New_York','Europe/London','not/a-zone'])('changed wall minute uses the inherited resolution in %s',zone=>{ + const original='2026-11-01T06:30:29.456Z',changed=toLocalInput(original,zone).replace(/:30$/,':31'); + expect(fromLocalInput(changed,zone,original)).toBe(fromLocalInput(changed,zone)); + expect(fromLocalInput(changed,zone,original)).not.toBe(original); + }); + it.each([undefined,null,'','not an instant','0000-01-01T00:00:00Z'])('unusable hint %s cannot override the two-argument result',hint=>{ + expect(fromLocalInput('2026-10-09T12:30','UTC',hint)).toBe(fromLocalInput('2026-10-09T12:30','UTC')); + }); + it('a seconds edit is resolved, rather than hidden by the old minute prefill',()=>{ + const original='2026-10-09T12:30:29.456Z'; + expect(fromLocalInput('2026-10-09T12:30:45.250','UTC',original)).toBe('2026-10-09T12:30:45.250Z'); + }); + it.each([null,undefined,'',' '])('blank %s keeps leave-alone semantics',box=>{ + expect(fromLocalInput(box,'UTC','2026-10-09T12:30:29.456Z')).toBeUndefined(); + }); + it.each(['2026-11-01T01:30:29.456-05:00','2026-10-09T12:30:29.456Z','0000-01-01T12:30'])('existing absolute or unsupported naive passthrough remains %s',value=>{ + expect(fromLocalInput(value,'UTC','2026-10-09T12:30:29.456Z')).toBe(value); + }); + it('spring-gap edits keep the existing family-zone choice',()=>{ + expect(fromLocalInput('2026-03-08T02:30','America/Los_Angeles','2026-03-07T10:30:00Z')).toBe(fromLocalInput('2026-03-08T02:30','America/Los_Angeles')); + }); +}); + +let db:ReturnType>>; +beforeEach(()=>{ + vi.clearAllMocks(); + db=createInMemorySupabase>({defaults:{calendar_events:{description:null,location:null,ends_at:null,all_day:false,category:'general',recurrence:'none',recurrence_until:null,assignee_id:null,idempotency_key:null}},uniques:{calendar_events:[['family_id','idempotency_key']]}}); + mocks.requireUserContext.mockResolvedValue({user:{id:'synthetic-user'},active:{familyId:'synthetic-family',role:'parent',family:{name:'Synthetic',timezone:'America/New_York'},member:{id:'synthetic-member'}}}); + mocks.createServer.mockResolvedValue(db); +}); + +describe('real calendar action with synthetic Auth and in-memory SDK storage',()=>{ + it.each([ + ['fold spanning identical boxes','2026-11-01T05:30:00.000Z','2026-11-01T06:30:00.000Z'], + ['sub-minute imported row','2026-10-09T12:30:29.456Z','2026-10-09T13:30:42.789Z'], + ])('%s preserves both fields on three unrelated-title edits',async(_name,start,end)=>{ + const created=await createCalendarEventAction({title:'Synthetic event',startsAt:start,endsAt:end,submissionId:'11111111-1111-4111-8111-111111111111'}); + expect(created.ok).toBe(true);if(!created.ok)throw Error(created.error); + for(let n=0;n<3;n++){ + const row=db.table('calendar_events').find(r=>r.id===created.id)!; + const ownStart=row.starts_at as string,ownEnd=row.ends_at as string; + const startBox=toLocalInput(ownStart,'America/New_York'),endBox=toLocalInput(ownEnd,'America/New_York'); + const result=await updateCalendarEventAction(created.id,{title:`Synthetic title ${n}`,startsAt:fromLocalInput(startBox,'America/New_York',ownStart)!,endsAt:fromLocalInput(endBox,'America/New_York',ownEnd)!}); + expect(result.ok).toBe(true); + const saved=db.table('calendar_events').find(r=>r.id===created.id)!; + expect(saved.starts_at).toBe(start);expect(saved.ends_at).toBe(end); + expect(saved.family_id).toBe('synthetic-family'); + } + }); + it('the actual modal passes each existing field to its matching helper',()=>{ + const source=readFileSync(join(process.cwd(),'components/modules/calendar-module.tsx'),'utf8'); + expect(source).toContain('fromLocalInput(parsed.data.starts_at, timeZone, existing?.starts_at)'); + expect(source).toContain('fromLocalInput(parsed.data.ends_at, timeZone, existing?.ends_at)'); + expect(source).toContain('defaultValue={toLocalInput(existing?.starts_at ?? null, timeZone)}'); + expect(source).toContain('defaultValue={toLocalInput(existing?.ends_at ?? null, timeZone)}'); + expect(source).not.toContain('family_id: existing'); + }); +}); + + +describe('optional hints require strict valid absolute instants only',()=>{ + it.each([ + '2026-02-30T12:30:29.456Z', + '2026-10-09', + '2026-10-09T12:30:29.456', + 'Fri, 09 Oct 2026 12:30:29 GMT', + '2026-10-09T12:30:29.456z', + '2026-10-09 12:30:29.456Z', + '2026-10-09T12:30:29.456+0000', + '2026-10-09T12:30:29.456Z ', + '2026-10-09T12:30:29.1234567890Z', + '2026-10-09T24:00:00.000Z', + '0000-01-01T12:30:29.456Z', + ])('rejects original hint %s without changing the existing submitted-value resolution',hint=>{ + const box=toLocalInput(hint,'UTC')||'2026-10-09T12:30'; + expect(fromLocalInput(box,'UTC',hint)).toBe(fromLocalInput(box,'UTC')); + expect(fromLocalInput(box,'UTC',hint)).not.toBe(hint); + }); + it.each(['America/New_York','Asia/Tokyo','Europe/London'])('a box rendered in UTC is not preserved under a shifted %s frame',zone=>{ + const original='2026-10-09T12:30:29.456789012Z',box=toLocalInput(original,'UTC'); + expect(box).not.toBe(toLocalInput(original,zone)); + expect(fromLocalInput(box,zone,original)).toBe(fromLocalInput(box,zone)); + expect(fromLocalInput(box,zone,original)).not.toBe(original); + }); + it('an invalid zone preserves only the matching device-frame prefill',()=>{ + const original='2026-10-09T12:30:29.456789012Z',box=toLocalInput(original,'invalid/zone'); + expect(fromLocalInput(box,'invalid/zone',original)).toBe(original); + }); + it('valid hint admission never reads the ambient clock',()=>{ + const original='2026-10-09T12:30:29.456789012Z',box=toLocalInput(original,'UTC'); + const ambient=vi.spyOn(Date,'now').mockImplementation(()=>{throw Error('Unexpected ambient clock');}); + try{expect(fromLocalInput(box,'UTC',original)).toBe(original);expect(ambient).not.toHaveBeenCalled();}finally{ambient.mockRestore();} + }); +}); diff --git a/tests/schedule-zoned-clock-contracts.test.ts b/tests/schedule-zoned-clock-contracts.test.ts new file mode 100644 index 000000000..b738c4174 --- /dev/null +++ b/tests/schedule-zoned-clock-contracts.test.ts @@ -0,0 +1,121 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { clockInZone, dayKeyInZone, todayInZone, zonedTimeMs } from '@/lib/schedule/zoned'; + +// These are pure helper contracts using synthetic instants. Related caller +// suites cover their existing composition; this file makes no Auth/RLS, +// provider, browser, or production-reachability claim. +describe('schedule clock formatting', () => { + it.each([Number.NaN, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY])('returns empty for a non-finite clock %s', ms => { + expect(clockInZone(ms, 'UTC')).toBe(''); + expect(clockInZone(ms, 'Not/AZone')).toBe(''); + }); + + it.each([8_640_000_000_000_001, -8_640_000_000_000_001, 1e30, -1e30])('returns empty when a finite clock cannot construct a Date: %s', ms => { + expect(clockInZone(ms, 'UTC')).toBe(''); + expect(clockInZone(ms, 'Not/AZone')).toBe(''); + expect(dayKeyInZone(ms, 'UTC')).toBeNull(); + }); + + it.each(['2026-10-09T12:30:00Z', '1791549000000', 'bad', '', null, undefined])('does not coerce runtime input %s to a clock', ms => { + expect(clockInZone(ms as unknown as number, 'UTC')).toBe(''); + }); + + it.each([ + ['UTC', '12:30 PM'], + ['America/Los_Angeles', '5:30 AM'], + ['Asia/Tokyo', '9:30 PM'], + ['Asia/Kathmandu', '6:15 PM'], + ['Australia/Lord_Howe', '11:30 PM'], + ])('formats the family clock in %s without seconds', (zone, expected) => { + expect(clockInZone(Date.parse('2026-10-09T12:30:59.999Z'), zone)).toBe(expected); + }); + + it.each(['Not/AZone', '', 'Mars/Olympus'])('keeps a padded UTC minute fallback for unusable IANA zone %s', zone => { + expect(clockInZone(Date.parse('2026-10-09T00:05:59.999Z'), zone)).toBe('00:05'); + expect(clockInZone(Date.parse('2026-10-09T12:30:00.001Z'), zone)).toBe('12:30'); + }); + + it.each([ + ['0001-01-01T12:30:59.999Z', '12:30'], + ['0099-01-01T00:05:00.001Z', '00:05'], + ['9999-12-31T23:59:59.999Z', '23:59'], + ['+010000-01-01T12:30:59.999Z', '12:30'], + ['-000001-01-01T12:30:59.999Z', '12:30'], + ['+275760-09-13T00:00:00.000Z', '00:00'], + ['-271821-04-20T00:00:00.000Z', '00:00'], + ])('preserves a valid Date clock across ISO year spelling %s', (iso, expected) => { + const ms = Date.parse(iso); + expect(Number.isFinite(ms)).toBe(true); + expect(clockInZone(ms, 'Not/AZone')).toBe(expected); + expect(clockInZone(ms, 'UTC')).toMatch(/^\d{1,2}:\d{2} [AP]M$/); + }); + + it('keeps distinct instants in the repeated hour on the same wall clock', () => { + expect(clockInZone(Date.parse('2026-11-01T05:30:00Z'), 'America/New_York')).toBe('1:30 AM'); + expect(clockInZone(Date.parse('2026-11-01T06:30:00Z'), 'America/New_York')).toBe('1:30 AM'); + }); +}); + +describe('unchanged neighboring schedule exports', () => { + afterEach(() => vi.restoreAllMocks()); + + it.each(['0001-01-01', '0099-12-31', '9999-12-31'])('retains supported day key %s and UTC fallback', key => { + const ms = Date.parse(key + 'T12:30:00Z'); + expect(dayKeyInZone(ms, 'UTC')).toBe(key); + expect(dayKeyInZone(ms, 'Not/AZone')).toBe(key); + expect(zonedTimeMs(key, 12, 30, 'UTC')).toBe(ms); + expect(zonedTimeMs(key, 12, 30, 'Not/AZone')).toBe(ms); + }); + + it.each(['0000-12-31T12:30:00Z', '+010000-01-01T12:30:00Z', '-000001-01-01T12:30:00Z'])('does not turn unsupported era %s into a supported day', iso => { + expect(dayKeyInZone(Date.parse(iso), 'UTC')).toBeNull(); + expect(dayKeyInZone(Date.parse(iso), 'Not/AZone')).toBeNull(); + }); + + it('refuses a projected day outside the supported AD range', () => { + expect(dayKeyInZone(Date.parse('0001-01-01T00:00:00Z'), 'America/New_York')).toBeNull(); + expect(dayKeyInZone(Date.parse('9999-12-31T23:59:59Z'), 'Asia/Tokyo')).toBeNull(); + }); + + it.each(['', 'bad', '2026-13-01', '2026-01-32'])('keeps malformed day-string %s unparseable', key => { + expect(zonedTimeMs(key, 12, 30, 'UTC')).toBeNaN(); + expect(zonedTimeMs(key, 12, 30, 'Not/AZone')).toBeNaN(); + }); + + it('retains family-local midnight, offset minutes and precision', () => { + expect(zonedTimeMs('2026-10-09', 0, 5, 'Asia/Kathmandu')).toBe(Date.parse('2026-10-08T18:20:00Z')); + expect(zonedTimeMs('2026-10-09', 0, 5, 'America/Los_Angeles')).toBe(Date.parse('2026-10-09T07:05:00Z')); + expect(zonedTimeMs('2026-10-09', 0, 5, 'UTC') % 60_000).toBe(0); + }); + + it('retains the existing two-pass spring-gap and autumn-fold policy', () => { + // This deliberately pins the existing two-pass rule; it does not claim + // that the helper exposes a strict civil-time/fold disambiguation API. + expect(zonedTimeMs('2026-03-08', 2, 30, 'America/New_York')).toBe(Date.parse('2026-03-08T06:30:00Z')); + expect(zonedTimeMs('2026-11-01', 1, 30, 'America/New_York')).toBe(Date.parse('2026-11-01T05:30:00Z')); + }); + + it('uses an explicit today clock without reading the ambient clock', () => { + const now = vi.spyOn(Date, 'now').mockImplementation(() => { throw new Error('Unexpected ambient clock read'); }); + const ms = Date.parse('2026-10-09T01:30:00Z'); + expect(todayInZone('America/Los_Angeles', ms)).toBe('2026-10-08'); + expect(todayInZone('Not/AZone', ms)).toBe('2026-10-09'); + expect(now).not.toHaveBeenCalled(); + }); + + it('reads the current clock only when today has no supplied instant', () => { + const now = vi.spyOn(Date, 'now').mockReturnValue(Date.parse('2026-10-09T01:30:00Z')); + expect(todayInZone('America/Los_Angeles')).toBe('2026-10-08'); + expect(todayInZone('UTC', undefined)).toBe('2026-10-09'); + expect(now).toHaveBeenCalledTimes(2); + }); + + it('does not read the ambient clock for the three mandatory-clock helpers', () => { + const now = vi.spyOn(Date, 'now').mockImplementation(() => { throw new Error('Unexpected ambient clock read'); }); + const ms = Date.parse('2026-10-09T12:30:00Z'); + expect(clockInZone(ms, 'UTC')).toBe('12:30 PM'); + expect(dayKeyInZone(ms, 'UTC')).toBe('2026-10-09'); + expect(zonedTimeMs('2026-10-09', 12, 30, 'UTC')).toBe(ms); + expect(now).not.toHaveBeenCalled(); + }); +}); diff --git a/tests/time-zoned-offset-seconds.test.ts b/tests/time-zoned-offset-seconds.test.ts new file mode 100644 index 000000000..06a583c72 --- /dev/null +++ b/tests/time-zoned-offset-seconds.test.ts @@ -0,0 +1,174 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { createClient } from '@supabase/supabase-js'; +import { + asWallClockIn, asWallClockUtc, dayKeyIn, daysInMonth, instantForIcsLocalTime, + instantForLocalTime, isValidTimezone, localPartsAt, startOfLocalDay, + startOfNextLocalDay, zonedLocalToInstant, +} from '@/lib/time/zoned'; +import { normalizeCalendarWindowInstant } from '@/lib/briefing/calendar-window'; +import { searchEvents } from '@/lib/services/calendar'; +import { parseExactInstant } from '@/lib/calendar/exact-instant'; + +// Synthetic instants and actual native Intl provide the independent wall-clock +// oracle. Supabase uses a read-only synthetic transport and supplied scope; +// this does not establish real Auth/RLS or production/provider execution. +const FAMILY = '10000000-0000-4000-8000-000000000001'; +function clockParts(instant: Date, timezone: string) { + const formatter = new Intl.DateTimeFormat('en-US', { timeZone: timezone, era: 'short', year: 'numeric', month: '2-digit', day: '2-digit', hourCycle: 'h23', hour: '2-digit', minute: '2-digit', second: '2-digit' }); + const parts = formatter.formatToParts(instant); + const get = (type: string) => Number(parts.find(part => part.type === type)?.value); + return { year: parts.find(part => part.type === 'era')?.value === 'BC' ? 1 - get('year') : get('year'), month: get('month'), day: get('day'), hour: get('hour'), minute: get('minute'), second: get('second') }; +} +function sdk() { + const calls: URL[] = []; + const db = createClient('https://historical-offset.synthetic.invalid', 'synthetic-key', { auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false }, global: { fetch: async (input, init) => { + const url = new URL(String(input)); calls.push(url); + expect(url.origin).toBe('https://historical-offset.synthetic.invalid'); + expect(url.pathname).toBe('/rest/v1/calendar_events'); + expect(init?.method ?? 'GET').toBe('GET'); + expect(url.searchParams.get('family_id')).toBe('eq.' + FAMILY); + return Response.json([], { headers: { 'content-range': '0-0/0' } }); + } } }); + return { db, calls }; +} +afterEach(() => vi.restoreAllMocks()); + +describe('historical IANA seconds reach the exact civil reading', () => { + it.each([ + [1, 1, 1, 0, 0, 'America/New_York'], + [99, 1, 1, 12, 30, 'America/New_York'], + [1900, 1, 1, 12, 30, 'Asia/Kathmandu'], + [1850, 1, 1, 12, 30, 'Europe/Paris'], + [1900, 1, 1, 12, 30, 'Africa/Monrovia'], + ] as const)('resolves %i-%i-%i %i:%i in %s without borrowing a minute', (year, month, day, hour, minute, zone) => { + const expected = { year, month, day, hour, minute, second: 0 }; + for (const resolver of [zonedLocalToInstant, instantForLocalTime, instantForIcsLocalTime]) { + const at = resolver(year, month, day, hour * 60 + minute, zone); + expect(at).not.toBeNull(); + expect(clockParts(at!, zone)).toEqual(expected); + expect(at!.getUTCMilliseconds()).toBe(0); + } + }); + + it.each([ + ['0001-01-01T00:00:42', 'America/New_York', '0001-01-01T04:56:44.000Z'], + ['0099-01-01T12:30:42', 'America/New_York', '0099-01-01T17:26:44.000Z'], + ['1900-01-01T12:30:42', 'Asia/Kathmandu', '1900-01-01T06:49:26.000Z'], + ])('normalizes historical wall seconds through the actual shared resolver: %s', (input, zone, expected) => { + const normalized = normalizeCalendarWindowInstant(input, zone); + expect(normalized).toBe(expected); + expect(clockParts(new Date(normalized), zone)).toMatchObject({ hour: Number(input.slice(11, 13)), minute: Number(input.slice(14, 16)), second: Number(input.slice(17, 19)) }); + }); + + it.each(Array.from({ length: 10 }, (_, digits) => digits))('retains fractional unit length %i with historical second offsets', digits => { + for (const fraction of digits === 0 ? [''] : ['0'.repeat(digits), '1'.padEnd(digits, '0')]) { + const input = '1900-01-01T12:30:42' + (fraction ? '.' + fraction : ''); + const expected = '1900-01-01T06:49:26.' + fraction.padEnd(Math.max(3, digits), '0') + 'Z'; + const normalized = normalizeCalendarWindowInstant(input, 'Asia/Kathmandu'); + expect(normalized).toBe(expected); + expect(parseExactInstant(normalized)).toBe(parseExactInstant(expected)); + } + }); + + it.each([ + ['0001-01-01T00:00:42.000001', 'America/New_York', '0001-01-01T04:56:44.000001Z'], + ['0099-01-01T12:30:42.000000001', 'America/New_York', '0099-01-01T17:26:44.000000001Z'], + ['1900-01-01T12:30:42.123456789', 'Asia/Kathmandu', '1900-01-01T06:49:26.123456789Z'], + ])('sends the exact normalized historical clock through the installed SDK: %s', async (from, tz, expected) => { + const probe = sdk(); + const scope = { db: probe.db, familyId: FAMILY, userId: 'synthetic-user', memberId: 'synthetic-member', role: 'parent' as const, actorKind: 'member' as const, tz }; + expect(await searchEvents(scope, { from, expandSeries: false })).toMatchObject({ ok: true, data: [] }); + expect(probe.calls).toHaveLength(1); + expect(probe.calls[0].searchParams.get('starts_at')).toBe('gte.' + expected); + }); + + it.each(['0001-01-01T00:00', '0001-01-01T00:00:42.000001', '0001-01-01T00:00:00+01:00'])('keeps canonical AD1 refusal before SDK: %s', async from => { + const probe = sdk(); + const scope = { db: probe.db, familyId: FAMILY, userId: 'synthetic-user', memberId: 'synthetic-member', role: 'parent' as const, actorKind: 'member' as const, tz: 'Asia/Tokyo' }; + expect(await searchEvents(scope, { from, expandSeries: false })).toMatchObject({ ok: false }); + expect(probe.calls).toEqual([]); + }); +}); + +describe('unchanged public resolver contracts', () => { + it('keeps the exact public LocalParts shape without second or offset fields', () => { + const parts = localPartsAt(new Date('2026-10-09T12:30:42.123Z'), 'America/New_York'); + expect(parts).toEqual({ year: 2026, month: 10, day: 9, hour: 8, minute: 30 }); + expect(Object.keys(parts).sort()).toEqual(['day', 'hour', 'minute', 'month', 'year']); + }); + + it.each([ + [2026, 3, 8, 2, 30, 'America/New_York', '2026-03-08T07:30:00.000Z', '2026-03-08T07:00:00.000Z'], + [2026, 10, 4, 2, 15, 'Australia/Lord_Howe', '2026-10-03T15:45:00.000Z', '2026-10-03T15:30:00.000Z'], + ] as const)('retains distinct RFC gap and routine-forward choices in %s', (year, month, day, hour, minute, zone, rfc, routine) => { + expect(zonedLocalToInstant(year, month, day, hour * 60 + minute, zone)).toBeNull(); + expect(instantForIcsLocalTime(year, month, day, hour * 60 + minute, zone)?.toISOString()).toBe(rfc); + expect(instantForLocalTime(year, month, day, hour * 60 + minute, zone)?.toISOString()).toBe(routine); + }); + + it.each([ + [2026, 11, 1, 1, 30, 'America/New_York', '2026-11-01T05:30:00.000Z'], + [2026, 10, 25, 1, 30, 'Europe/London', '2026-10-25T00:30:00.000Z'], + [2026, 4, 5, 1, 45, 'Australia/Lord_Howe', '2026-04-04T14:45:00.000Z'], + ] as const)('keeps RFC earliest fold in %s', (year, month, day, hour, minute, zone, expected) => { + expect(instantForIcsLocalTime(year, month, day, hour * 60 + minute, zone)?.toISOString()).toBe(expected); + }); + + it.each([ + [1880, 'Asia/Colombo', '1879-12-31T18:40:36.000Z', 8, '1879-12-31T18:41:28.000Z'], + [1890, 'America/Caracas', '1890-01-01T04:27:44.000Z', 4, '1890-01-01T04:28:40.000Z'], + ] as const)('distinguishes a historical second-only gap from an exact midnight in %s', (year, zone, rfc, gapSeconds, routine) => { + expect(zonedLocalToInstant(year, 1, 1, 0, zone)).toBeNull(); + const imported = instantForIcsLocalTime(year, 1, 1, 0, zone); + expect(imported?.toISOString()).toBe(rfc); + expect(clockParts(imported!, zone)).toMatchObject({ year, month: 1, day: 1, hour: 0, minute: 0, second: gapSeconds }); + const scheduled = instantForLocalTime(year, 1, 1, 0, zone); + expect(scheduled?.toISOString()).toBe(routine); + expect(clockParts(scheduled!, zone)).toMatchObject({ year, month: 1, day: 1, hour: 0, minute: 1, second: 0 }); + }); + + it('retains a skipped whole date RFC interpretation while the routine cannot schedule it', () => { + expect(instantForIcsLocalTime(2011, 12, 30, 9 * 60, 'Pacific/Apia')?.toISOString()).toBe('2011-12-30T19:00:00.000Z'); + expect(instantForLocalTime(2011, 12, 30, 9 * 60, 'Pacific/Apia')).toBeNull(); + }); + + it.each([1, 4, 99, 100, 2026, 9999])('retains Gregorian year %i during both constructor passes', year => { + const expected = `${String(year).padStart(4, '0')}-12-30T09:30:00.000Z`; + expect(zonedLocalToInstant(year, 12, 30, 570, 'UTC')?.toISOString()).toBe(expected); + expect(instantForIcsLocalTime(year, 12, 30, 570, 'UTC')?.toISOString()).toBe(expected); + expect(daysInMonth(year, 2)).toBe(year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28); + }); + + it.each([[2026, 13, 1], [2026, 2, 30], [2026, 1, 0]] as const)('does not broaden strict civil input admission %i-%i-%i', (year, month, day) => { + expect(zonedLocalToInstant(year, month, day, 9 * 60, 'UTC')).toBeNull(); + }); + + it.each(['2026-03-08T16:00:00Z', '2026-11-01T16:00:00Z'])('retains local day duration on DST date %s', input => { + const instant = new Date(input); + const first = startOfLocalDay(instant, 'America/New_York'); + const next = startOfNextLocalDay(instant, 'America/New_York'); + expect(next.getTime() - first.getTime()).toBe(input.startsWith('2026-03') ? 23 * 3_600_000 : 25 * 3_600_000); + expect(clockParts(first, 'America/New_York')).toMatchObject({ hour: 0, minute: 0, second: 0 }); + }); + + it('preserves unusable-zone and reader-clock fallback behavior', () => { + const instant = new Date('2026-10-09T12:30:42.123Z'); + expect(isValidTimezone('Not/AZone')).toBe(false); + expect(isValidTimezone('Asia/Kathmandu')).toBe(true); + expect(dayKeyIn(instant, 'Not/AZone')).toBe('2026-10-09'); + const midnight = new Date(instant); midnight.setHours(0, 0, 0, 0); + expect(startOfLocalDay(instant, 'Not/AZone').getTime()).toBe(midnight.getTime()); + expect(startOfNextLocalDay(instant, 'Not/AZone').getTime()).toBe(midnight.getTime() + 86_400_000); + expect(() => instantForIcsLocalTime(2026, 10, 9, 570, 'Not/AZone')).toThrow(); + }); + + it('retains minute-only wall bridges and makes no ambient clock read', () => { + const now = vi.spyOn(Date, 'now').mockImplementation(() => { throw new Error('Unexpected current-clock dependency'); }); + const instant = new Date('2026-10-09T12:30:42.123Z'); + expect(asWallClockUtc(instant, 'Asia/Kathmandu').toISOString()).toBe('2026-10-09T18:15:00.000Z'); + const local = asWallClockIn(instant, 'Asia/Kathmandu'); + expect([local.getFullYear(), local.getMonth() + 1, local.getDate(), local.getHours(), local.getMinutes(), local.getSeconds(), local.getMilliseconds()]).toEqual([2026, 10, 9, 18, 15, 0, 0]); + expect(dayKeyIn(instant, 'Asia/Kathmandu')).toBe('2026-10-09'); + expect(now).not.toHaveBeenCalled(); + }); +});