calendar-ics-normalizer-data-integrity.test.mjs
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd
feat(calendar): enforce agent context tiers in retrieval AP…
Human
minor
⚠ breaking
1 day ago
| 1 | /** |
| 2 | * Tier 5 — DATA INTEGRITY: dedup keys, timezone boundaries, deterministic output. |
| 3 | */ |
| 4 | import { describe, it } from 'node:test'; |
| 5 | import assert from 'node:assert/strict'; |
| 6 | import { parseIcsToEvents, zonedLocalToUtc } from '../lib/calendar/ics-normalizer.mjs'; |
| 7 | |
| 8 | describe('Data integrity — deterministic parse', () => { |
| 9 | const ics = `BEGIN:VCALENDAR |
| 10 | BEGIN:VEVENT |
| 11 | UID:dedup@x |
| 12 | DTSTART:20260308T080000Z |
| 13 | DTEND:20260308T090000Z |
| 14 | SUMMARY:Same |
| 15 | END:VEVENT |
| 16 | END:VCALENDAR`; |
| 17 | |
| 18 | it('returns identical output on repeated parse', () => { |
| 19 | const a = parseIcsToEvents(ics); |
| 20 | const b = parseIcsToEvents(ics); |
| 21 | assert.deepEqual(a, b); |
| 22 | }); |
| 23 | |
| 24 | it('preserves external_uid for dedup', () => { |
| 25 | const [event] = parseIcsToEvents(ics); |
| 26 | assert.equal(event.external_uid, 'dedup@x'); |
| 27 | }); |
| 28 | }); |
| 29 | |
| 30 | describe('Data integrity — timezone boundary (DST spring forward)', () => { |
| 31 | it('maps ambiguous local time consistently via IANA zone', () => { |
| 32 | // Second Sunday in March 2026 — US DST begins 2026-03-08 |
| 33 | const utc = zonedLocalToUtc( |
| 34 | { year: 2026, month: 3, day: 8, hour: 3, minute: 30, second: 0 }, |
| 35 | 'America/Los_Angeles', |
| 36 | ); |
| 37 | assert.equal(utc.toISOString(), '2026-03-08T10:30:00.000Z'); |
| 38 | }); |
| 39 | }); |
| 40 | |
| 41 | describe('Data integrity — all-day exclusive DTEND', () => { |
| 42 | it('end instant is after start for single-day event', () => { |
| 43 | const ics = `BEGIN:VCALENDAR |
| 44 | BEGIN:VEVENT |
| 45 | UID:day@x |
| 46 | DTSTART;VALUE=DATE:20260601 |
| 47 | DTEND;VALUE=DATE:20260602 |
| 48 | END:VEVENT |
| 49 | END:VCALENDAR`; |
| 50 | const [event] = parseIcsToEvents(ics, { defaultTimezone: 'UTC' }); |
| 51 | assert.ok(new Date(event.end) > new Date(event.start)); |
| 52 | }); |
| 53 | }); |
| 54 | |
| 55 | describe('Data integrity — cancelled events retain status without dropping row', () => { |
| 56 | it('keeps cancelled events for tombstone indexing', () => { |
| 57 | const ics = `BEGIN:VCALENDAR |
| 58 | BEGIN:VEVENT |
| 59 | UID:c@x |
| 60 | DTSTART:20260601T120000Z |
| 61 | DTEND:20260601T130000Z |
| 62 | STATUS:CANCELLED |
| 63 | END:VEVENT |
| 64 | END:VCALENDAR`; |
| 65 | const [event] = parseIcsToEvents(ics); |
| 66 | assert.equal(event.status, 'cancelled'); |
| 67 | }); |
| 68 | }); |
File History
1 commit
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd
feat(calendar): enforce agent context tiers in retrieval AP…
Human
minor
⚠
1 day ago