Skip to content

Commit 48bec97

Browse files
authored
ci(temporal): the non-SQL backends run under a skewed process zone too (#4180)
The temporal-conformance job pinned TZ: America/New_York on the live Postgres/MySQL sweep only. core, formula, driver-memory, driver-mongodb and service-analytics kept running in the runner's default UTC, where every offset bug is invisible because the offset is zero. They now run in the same skewed zone, and both TZ-skewed steps carry a non-vacuity guard that fails the job if the process zone is UTC or the offset is zero, so the coverage cannot silently evaporate if the runner image changes.
1 parent 2cb6d3c commit 48bec97

2 files changed

Lines changed: 77 additions & 2 deletions

File tree

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
---
3+
4+
ci(temporal): run the non-SQL temporal backends under a skewed process zone too (#4081)
5+
6+
The `temporal-conformance` job pinned `TZ: America/New_York` on the live
7+
Postgres/MySQL sweep only. `core`, `formula`, `driver-memory`, `driver-mongodb`
8+
and `service-analytics` — the backends where a stray `getFullYear()` or a
9+
local-midnight `new Date(y, m, d)` is easiest to write and hardest to see — kept
10+
running in the runner's default UTC, where every offset bug is invisible because
11+
the offset is zero.
12+
13+
They now run in the same skewed zone, and both TZ-skewed steps carry a
14+
non-vacuity guard that fails the job if the process zone is UTC or the offset is
15+
zero, so the coverage cannot silently evaporate if the runner image changes.
16+
17+
CI configuration only; releases nothing.

.github/workflows/ci.yml

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,17 @@ jobs:
213213
# Every timezone here is deliberately DIFFERENT: servers at +08:00, the Node
214214
# process at America/New_York, assertions in UTC. Both suites assert they
215215
# are pointed at a non-UTC server, so a mis-provisioned service fails loudly
216-
# instead of letting the job pass vacuously.
216+
# instead of letting the job pass vacuously — and each test step now asserts
217+
# the PROCESS zone too, which nothing did before: a dropped `TZ:` line
218+
# silently returned the whole job to UTC coverage with everything still
219+
# green.
220+
#
221+
# The job also carries the non-SQL half of that axis (core, formula,
222+
# driver-memory, driver-mongodb, service-analytics) — the other backends the
223+
# temporal conformance matrix holds to one standard. Its NAME still says
224+
# "live PG + MySQL" on purpose: the name IS the required check, so renaming
225+
# it would silently drop the gate wherever branch protection lists it — the
226+
# same trap the dogfood shards note below.
217227
temporal-conformance:
218228
name: Temporal Conformance (live PG + MySQL)
219229
needs: filter
@@ -317,7 +327,55 @@ jobs:
317327
TZ: America/New_York
318328
OS_TEST_POSTGRES_URL: postgres://postgres:postgres@127.0.0.1:5432/postgres
319329
OS_TEST_MYSQL_URL: mysql://root:root@127.0.0.1:3306/conformance
320-
run: pnpm --filter @objectstack/driver-sql test
330+
run: |
331+
# The axis is only real if the zone actually took. Without this, a
332+
# dropped `TZ:` line silently returns the job to UTC coverage and
333+
# everything still passes — the same vacuous-pass hole the live-server
334+
# suites close by asserting a non-UTC SERVER.
335+
node -e "const tz=Intl.DateTimeFormat().resolvedOptions().timeZone,off=new Date().getTimezoneOffset();if(!tz||tz==='UTC'||off===0){console.error('process zone is '+tz+' (offset '+off+') — this job must run skewed');process.exit(1)}console.log('process zone: '+tz+' (offset '+off+')')"
336+
pnpm --filter @objectstack/driver-sql test
337+
338+
# The non-SQL half of the same axis. `driver-sql` has run under a skewed
339+
# process zone since #3979, but the other backends the temporal
340+
# conformance matrix holds to that standard never did — and they are the
341+
# ones whose correctness rests ENTIRELY on process-zone independence,
342+
# since they have no server to blame: `storageDatetimeValue` /
343+
# `storageTimeValue` fold an instant through UTC getters, the filter-token
344+
# resolver derives "today" from UTC calendar parts, and the analytics
345+
# bucketer does the same. Swap one `getUTC*` for its local twin and every
346+
# one of those silently shifts by the host's offset — the exact defect
347+
# ADR-0053 D-C1 records for a `Date` bound to a Postgres TIME column.
348+
#
349+
# Measured before adding this: all five suites already pass under
350+
# America/New_York (-5/-4, with DST), Asia/Kolkata (+05:30) and
351+
# Pacific/Chatham (+12:45). So this found nothing on the day it landed,
352+
# which is what a ratchet is for — it makes the property enforced rather
353+
# than incidental.
354+
- name: Build the non-SQL temporal backends
355+
run: >-
356+
pnpm exec turbo run build
357+
--filter=@objectstack/service-analytics...
358+
--filter=@objectstack/driver-memory...
359+
--filter=@objectstack/driver-mongodb...
360+
--filter=@objectstack/formula...
361+
--concurrency=4
362+
363+
- name: Run the non-SQL temporal backends under the skewed process zone
364+
env:
365+
TZ: America/New_York
366+
run: |
367+
# The axis is only real if the zone actually took. Without this, a
368+
# dropped `TZ:` line silently returns the job to UTC coverage and
369+
# everything still passes — the same vacuous-pass hole the live-server
370+
# suites close by asserting a non-UTC SERVER.
371+
node -e "const tz=Intl.DateTimeFormat().resolvedOptions().timeZone,off=new Date().getTimezoneOffset();if(!tz||tz==='UTC'||off===0){console.error('process zone is '+tz+' (offset '+off+') — this job must run skewed');process.exit(1)}console.log('process zone: '+tz+' (offset '+off+')')"
372+
pnpm \
373+
--filter @objectstack/core \
374+
--filter @objectstack/formula \
375+
--filter @objectstack/driver-memory \
376+
--filter @objectstack/driver-mongodb \
377+
--filter @objectstack/service-analytics \
378+
test
321379
322380
dogfood:
323381
# Sharded 2-way: the suite is ~60 independent test files, each booting its

0 commit comments

Comments
 (0)