What
scripts/nightly-audit.sh computes its "24 hours ago" cutoff in local time but compares it lexicographically against GitHub's UTC (Z-suffixed) timestamps. Line 44 reads YESTERDAY=$(date -v-24H +%Y-%m-%dT%H:%M:%S 2>/dev/null || date -d '24 hours ago' +%Y-%m-%dT%H:%M:%S) — neither invocation passes -u, so on the Mac mini running in CET/CEST the string is 1–2 hours ahead of UTC. The jq filters select(.createdAt >= $since) (lines 52–53, "Support issues created in last 24h") and select(.mergedAt >= $since) (lines 115–116, "PRs merged to main in last 24h") then silently drop everything from the first ~1–2 hours of the true window: at the 05:00 CEST launchd run (03:00 UTC), an issue created at 03:30 UTC the previous day is excluded, so attachment-failure detection (line 58) and the post-merge main-CI check (lines 121–129) can miss real events. Other scripts in the repo already avoid this trap (scripts/support-agent.sh:663-667 uses TZ=UTC; scripts/factory-agent.sh uses date -u throughout). Once fixed, the audit window is a true 24 hours regardless of the machine's timezone or DST state.
Acceptance criteria
- The
YESTERDAY= computation on line 44 of scripts/nightly-audit.sh produces a UTC timestamp: both the macOS branch (date -u -v-24H +%Y-%m-%dT%H:%M:%S) and the GNU fallback (date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%S) carry the -u flag.
- The resulting
$YESTERDAY string remains correctly comparable (lexicographically, via jq >=) against GitHub's Z-suffixed createdAt/mergedAt values used at lines 52–53 and 115–116 — either keep the suffix-less %Y-%m-%dT%H:%M:%S format (which compares correctly as a prefix of the Z-suffixed form) or append a literal Z; the jq filters themselves need no behavioral change.
- Regression test: a new test file in
scripts/__tests__/ (e.g. nightly-audit-window.test.mjs, picked up by the existing node --test __tests__/*.test.mjs runner via pnpm test in scripts/) reads scripts/nightly-audit.sh and asserts that every date invocation on the YESTERDAY= line includes the -u flag, so a future edit cannot silently reintroduce a local-time window.
bash -n scripts/nightly-audit.sh passes after the change.
- All existing tests in
scripts/__tests__/ still pass (cd scripts && pnpm test).
Affected platforms
Schema changes?
no
UI design (if applicable)
No UI change.
Out of scope
- Changing date/timezone handling in any other script (
support-agent.sh, factory-agent.sh, nightly-support.sh already use UTC or epoch-seconds arithmetic where it matters).
- Converting
nightly-audit.sh's human-facing local-time usages — the audit-$(date +%Y-%m-%d).log filename, TODAY, and the log() timestamps — which are intentionally local for the operator and not compared against API timestamps.
- Any change to the audit's check logic, problem-signature/idempotency mechanism, or issue-body format.
- Refactoring the script into a sourceable library for deeper unit testing; the text-level regression test is sufficient.
- Changes to the launchd schedule (the 05:00 local run time stays as is).
What
scripts/nightly-audit.shcomputes its "24 hours ago" cutoff in local time but compares it lexicographically against GitHub's UTC (Z-suffixed) timestamps. Line 44 readsYESTERDAY=$(date -v-24H +%Y-%m-%dT%H:%M:%S 2>/dev/null || date -d '24 hours ago' +%Y-%m-%dT%H:%M:%S)— neither invocation passes-u, so on the Mac mini running in CET/CEST the string is 1–2 hours ahead of UTC. The jq filtersselect(.createdAt >= $since)(lines 52–53, "Support issues created in last 24h") andselect(.mergedAt >= $since)(lines 115–116, "PRs merged to main in last 24h") then silently drop everything from the first ~1–2 hours of the true window: at the 05:00 CEST launchd run (03:00 UTC), an issue created at 03:30 UTC the previous day is excluded, so attachment-failure detection (line 58) and the post-merge main-CI check (lines 121–129) can miss real events. Other scripts in the repo already avoid this trap (scripts/support-agent.sh:663-667usesTZ=UTC;scripts/factory-agent.shusesdate -uthroughout). Once fixed, the audit window is a true 24 hours regardless of the machine's timezone or DST state.Acceptance criteria
YESTERDAY=computation on line 44 ofscripts/nightly-audit.shproduces a UTC timestamp: both the macOS branch (date -u -v-24H +%Y-%m-%dT%H:%M:%S) and the GNU fallback (date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%S) carry the-uflag.$YESTERDAYstring remains correctly comparable (lexicographically, via jq>=) against GitHub's Z-suffixedcreatedAt/mergedAtvalues used at lines 52–53 and 115–116 — either keep the suffix-less%Y-%m-%dT%H:%M:%Sformat (which compares correctly as a prefix of the Z-suffixed form) or append a literalZ; the jq filters themselves need no behavioral change.scripts/__tests__/(e.g.nightly-audit-window.test.mjs, picked up by the existingnode --test __tests__/*.test.mjsrunner viapnpm testinscripts/) readsscripts/nightly-audit.shand asserts that everydateinvocation on theYESTERDAY=line includes the-uflag, so a future edit cannot silently reintroduce a local-time window.bash -n scripts/nightly-audit.shpasses after the change.scripts/__tests__/still pass (cd scripts && pnpm test).Affected platforms
apps/web)apps/mobile)apps/desktop)Schema changes?
no
UI design (if applicable)
No UI change.
Out of scope
support-agent.sh,factory-agent.sh,nightly-support.shalready use UTC or epoch-seconds arithmetic where it matters).nightly-audit.sh's human-facing local-time usages — theaudit-$(date +%Y-%m-%d).logfilename,TODAY, and thelog()timestamps — which are intentionally local for the operator and not compared against API timestamps.