Files
orca/src/main/codex/codex-session-backfill-scan-dates.test.ts
T
Neil 015f904fca fix(codex): stop re-scanning all Codex session history on every launch (#16251) (#16593)
* fix(codex): stop re-scanning all Codex session history on every launch (#16251)

A launch deleted the backfill completion marker, and a marker could never
be written while a Codex pane was open, so every launch re-derived
"needs full scan" and walked the entire .codex/sessions tree — on Windows
with a large history that read as a hung window.

- v4 marker keeps a durable full-history baseline plus a bounded set of
  pending dates. v3 is read as a baseline, so upgrades pay no full scan.
- A launch now marks dates pending instead of deleting the marker, and a
  full pass certifies the baseline even while a pane is still running;
  the live pane's own date just stays pending.
- Pending dates are persisted, so an abnormal exit or a cross-midnight
  pane recovers a bounded window instead of a full walk.
- A date-limited pass can only extend an existing baseline, never create
  one, so it can no longer certify history it never looked at.
- Marker and index-heal target roots compare through
  normalizeRuntimePathForComparison, so Windows spellings of one
  directory stop invalidating each other.
- Both append-only ledgers stream instead of readFileSync + whole-file
  JSON.parse, keeping the main thread responsive on large histories.

* fix(codex): keep the backfill marker's full-scan demand durable

Review follow-ups on the v4 backfill marker:

- markCodexSessionBackfillMarkerPending no longer erases a persisted
  needsFullScan; the demand survives until a generation-current full walk
  retires it, and the function now reports it so the launch path folds it
  into its own in-memory flag (as @rumoii's #16252 does).
- A full pass settles the whole pending set instead of subtracting the
  empty set, so a date a full walk provably covered stops forcing an extra
  bounded pass on every startup.
- isCodexSessionBackfillDate does a real calendar check, so a corrupted
  marker cannot carry 2026/99/99. No age or future bound: the same guard
  gates rollout publication and a clock-skewed directory holds real
  sessions.
- 'scans only the current date once a baseline exists' now has a second
  date directory, so it fails on a full walk instead of passing either way.
2026-08-26 15:42:54 -07:00

103 lines
3.5 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
compareCodexSessionBackfillDates,
expandCodexSessionBackfillDatesThroughToday,
getCodexSessionBackfillDate,
getCodexSessionBackfillDatesBetween,
isCodexSessionBackfillDate,
mergeCodexSessionBackfillDates,
parseCodexSessionBackfillDates,
subtractCodexSessionBackfillDates
} from './codex-session-backfill-scan-dates'
describe('codex session backfill scan dates', () => {
it('reads UTC parts so a local evening never lands on the wrong directory', () => {
expect(getCodexSessionBackfillDate(new Date('2026-08-05T23:59:59Z'))).toEqual([
'2026',
'08',
'05'
])
expect(getCodexSessionBackfillDate(new Date('2026-01-02T00:00:00Z'))).toEqual([
'2026',
'01',
'02'
])
})
it('rejects anything that is not a zero-padded YYYY/MM/DD triple', () => {
expect(isCodexSessionBackfillDate(['2026', '08', '05'])).toBe(true)
expect(isCodexSessionBackfillDate(['2026', '8', '05'])).toBe(false)
expect(isCodexSessionBackfillDate(['2026', '08'])).toBe(false)
expect(isCodexSessionBackfillDate('2026-08-05')).toBe(false)
})
it('rejects dates the calendar never produced', () => {
expect(isCodexSessionBackfillDate(['2026', '99', '99'])).toBe(false)
expect(isCodexSessionBackfillDate(['2026', '02', '30'])).toBe(false)
expect(isCodexSessionBackfillDate(['2025', '02', '29'])).toBe(false)
expect(isCodexSessionBackfillDate(['2026', '00', '10'])).toBe(false)
expect(isCodexSessionBackfillDate(['2024', '02', '29'])).toBe(true)
expect(isCodexSessionBackfillDate(['2026', '12', '31'])).toBe(true)
})
it('merges and subtracts date sets by identity, not by reference', () => {
const merged = mergeCodexSessionBackfillDates(
[
['2026', '08', '06'],
['2026', '08', '05']
],
[['2026', '08', '06']],
undefined
)
expect(merged).toEqual([
['2026', '08', '05'],
['2026', '08', '06']
])
expect(subtractCodexSessionBackfillDates(merged, [['2026', '08', '05']])).toEqual([
['2026', '08', '06']
])
expect(compareCodexSessionBackfillDates(merged[0], merged[1])).toBeLessThan(0)
})
it('discards unparseable persisted dates instead of scanning bogus roots', () => {
expect(parseCodexSessionBackfillDates([['2026', '08', '05'], 'nope', ['2026'], null])).toEqual([
['2026', '08', '05']
])
expect(parseCodexSessionBackfillDates('not an array')).toEqual([])
})
it('walks every date a launch could have spanned, including across a month end', () => {
expect(
getCodexSessionBackfillDatesBetween(
new Date('2026-07-31T23:00:00Z'),
new Date('2026-08-02T01:00:00Z')
)
).toEqual([
['2026', '07', '31'],
['2026', '08', '01'],
['2026', '08', '02']
])
})
it('widens a pending set into the contiguous window that ends today', () => {
expect(
expandCodexSessionBackfillDatesThroughToday([['2026', '08', '05']], ['2026', '08', '07'], 31)
).toEqual([
['2026', '08', '05'],
['2026', '08', '06'],
['2026', '08', '07']
])
})
it('leaves an empty pending set empty rather than inventing today', () => {
expect(expandCodexSessionBackfillDatesThroughToday([], ['2026', '08', '07'], 31)).toEqual([])
})
it('gives up on a window wider than the bound so a full walk can recertify', () => {
expect(
expandCodexSessionBackfillDatesThroughToday([['2026', '01', '01']], ['2026', '08', '07'], 31)
).toBeNull()
})
})