calendar-ics-normalizer-integration.test.mjs
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd
feat(calendar): enforce agent context tiers in retrieval AP…
Human
minor
⚠ breaking
1 day ago
| 1 | /** |
| 2 | * Tier 2 — INTEGRATION: parse real fixture ICS files end-to-end through parseIcsToEvents. |
| 3 | * Reference: docs/CALENDAR-EVENTS-V0-SPEC.md — Phase 1A |
| 4 | */ |
| 5 | import { describe, it } from 'node:test'; |
| 6 | import assert from 'node:assert/strict'; |
| 7 | import fs from 'node:fs'; |
| 8 | import path from 'node:path'; |
| 9 | import { fileURLToPath } from 'node:url'; |
| 10 | import { parseIcsToEvents } from '../lib/calendar/ics-normalizer.mjs'; |
| 11 | import { buildSourceCalendarDefaults, isAgentTierAllowed } from '../lib/calendar/source-calendar-defaults.mjs'; |
| 12 | import { redactEventForAgentTier } from '../lib/calendar/agent-context-tier.mjs'; |
| 13 | |
| 14 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); |
| 15 | const fixtureDir = path.join(__dirname, 'fixtures', 'calendar'); |
| 16 | |
| 17 | /** |
| 18 | * @param {string} name |
| 19 | * @returns {string} |
| 20 | */ |
| 21 | function loadFixture(name) { |
| 22 | return fs.readFileSync(path.join(fixtureDir, name), 'utf8'); |
| 23 | } |
| 24 | |
| 25 | describe('Fixture: simple-utc.ics', () => { |
| 26 | it('parses UTC timed event', () => { |
| 27 | const events = parseIcsToEvents(loadFixture('simple-utc.ics')); |
| 28 | assert.equal(events.length, 1); |
| 29 | assert.equal(events[0].external_uid, '[email protected]'); |
| 30 | assert.equal(events[0].start, '2026-06-18T17:00:00.000Z'); |
| 31 | assert.equal(events[0].end, '2026-06-18T17:30:00.000Z'); |
| 32 | assert.equal(events[0].summary, 'Team standup'); |
| 33 | }); |
| 34 | }); |
| 35 | |
| 36 | describe('Fixture: all-day.ics', () => { |
| 37 | it('parses VALUE=DATE all-day span', () => { |
| 38 | const events = parseIcsToEvents(loadFixture('all-day.ics')); |
| 39 | assert.equal(events.length, 1); |
| 40 | assert.equal(events[0].start, '2026-06-20T00:00:00.000Z'); |
| 41 | assert.equal(events[0].end, '2026-06-21T00:00:00.000Z'); |
| 42 | }); |
| 43 | }); |
| 44 | |
| 45 | describe('Fixture: tzid-pacific.ics', () => { |
| 46 | it('honors TZID for local wall time', () => { |
| 47 | const events = parseIcsToEvents(loadFixture('tzid-pacific.ics')); |
| 48 | assert.equal(events.length, 1); |
| 49 | assert.equal(events[0].timezone, 'America/Los_Angeles'); |
| 50 | assert.equal(events[0].start, '2026-06-18T16:00:00.000Z'); |
| 51 | assert.equal(events[0].end, '2026-06-18T17:00:00.000Z'); |
| 52 | }); |
| 53 | }); |
| 54 | |
| 55 | describe('Fixture: folded-summary.ics', () => { |
| 56 | it('unfolds summary and preserves RRULE', () => { |
| 57 | const events = parseIcsToEvents(loadFixture('folded-summary.ics')); |
| 58 | assert.equal(events.length, 1); |
| 59 | assert.match(events[0].summary ?? '', /RFC 5545 folding/); |
| 60 | assert.equal(events[0].status, 'tentative'); |
| 61 | assert.equal(events[0].busy, false); |
| 62 | assert.equal(events[0].recurrence_rule, 'FREQ=WEEKLY;BYDAY=TH'); |
| 63 | }); |
| 64 | }); |
| 65 | |
| 66 | describe('Fixture: multi-event.ics', () => { |
| 67 | it('parses multiple VEVENT components', () => { |
| 68 | const events = parseIcsToEvents(loadFixture('multi-event.ics')); |
| 69 | assert.equal(events.length, 2); |
| 70 | const cancelled = events.find((e) => e.external_uid === '[email protected]'); |
| 71 | const duration = events.find((e) => e.external_uid === '[email protected]'); |
| 72 | assert.ok(cancelled); |
| 73 | assert.equal(cancelled.status, 'cancelled'); |
| 74 | assert.ok(duration); |
| 75 | assert.equal(duration.end, '2026-06-23T10:45:00.000Z'); |
| 76 | }); |
| 77 | }); |
| 78 | |
| 79 | describe('Defaults + tier redaction integration', () => { |
| 80 | it('new calendar defaults block agent summary at tier 2', () => { |
| 81 | const cal = buildSourceCalendarDefaults(); |
| 82 | const events = parseIcsToEvents(loadFixture('simple-utc.ics')); |
| 83 | assert.equal(isAgentTierAllowed(cal, 2), false); |
| 84 | assert.equal(redactEventForAgentTier(events[0], 2)?.summary, 'Team standup'); |
| 85 | assert.equal(redactEventForAgentTier(events[0], 1)?.summary, undefined); |
| 86 | assert.equal(redactEventForAgentTier(events[0], 0), null); |
| 87 | }); |
| 88 | |
| 89 | it('opt-in calendar allows tier up to cap', () => { |
| 90 | const cal = buildSourceCalendarDefaults({ |
| 91 | enabled_for_agents: true, |
| 92 | agent_context_tier_max: 2, |
| 93 | }); |
| 94 | assert.equal(isAgentTierAllowed(cal, 2), true); |
| 95 | assert.equal(isAgentTierAllowed(cal, 3), false); |
| 96 | }); |
| 97 | }); |
File History
1 commit
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd
feat(calendar): enforce agent context tiers in retrieval AP…
Human
minor
⚠
1 day ago