# Reconcile planned bookings against a current schedule

Artifact: AX064 v2, 2026-10-08 (original v1 published 2026-10-07). Audience: schedule coordinators comparing planned and current bookings.

Browser job: https://bulldo.gs/jobs/calendar-reconciliation/?via=llms

Local module: https://bulldo.gs/downloads/calendar-reconciliation.mjs

Module contract and executable example: https://bulldo.gs/downloads/calendar-reconciliation-README.md

## Optional current-list preparation

[Calendar input helper instructions](https://bulldo.gs/jobs/calendar-export-README.md) and [Apps Script source](https://bulldo.gs/jobs/calendar-export.gs): AC013 v1. The user may manually run this in their own account with an explicit Calendar read-only scope, one calendar and a timezone-explicit window. The browser job never connects to Calendar. No live Google execution, installation or time saving is established.

Use the same calendar, window and resource label for a retained baseline and a later snapshot. Exporting current events does not create an independent expected plan; map separately planned booking IDs manually. Nonrecurring event IDs persist across time changes; recurring instances use the series ID plus UTC start, so moved recurring starts appear as missing plus unexpected. All-day entries and excessive output reject the whole export, rather than silently dropping rows. Read the full instructions before running; identifiers/times are private data in the user's Google log. Never paste them into a support email.

## Prepare the two inputs

Manually prepare expected and scheduled lists with exactly four literal tab-separated columns in this order: stable booking ID, resource/person, start timestamp, end timestamp. Copy the four columns from a table you already maintain, without a header. This is not a native Google Calendar export or an ICS parser. Do not paste an ICS file, event URL, event description or an unconverted export.

Use the same stable ID for the same booking in both lists. IDs must be unique within each list. IDs and resource names must be nonblank; case and spaces remain significant. No resource aliases are resolved. Internal blank lines, extra columns, multiline cells and control characters are rejected. CRLF/CR become LF; one final newline is allowed. Expected needs at least one booking. Scheduled may be an empty string only when there are no scheduled bookings in the checked scope.

Start and end use YYYY-MM-DDTHH:mm[:ss[.SSS]] with Z or an explicit ±HH:mm offset. Valid local and UTC years are 0001–9999; offset range is -14:00 through +14:00, and unknown offset -00:00 is rejected. End must be later than start. Equivalent timezone spellings compare as the same UTC instant. Touching intervals do not overlap. No local timezone or daylight-saving offset is guessed.

Match the calendars and date window yourself. Include bookings that cross either edge of the window, including when splitting into smaller batches. Recurring events require one explicitly timed row and distinct stable ID per instance; the tool does not expand recurrence rules or process exceptions. All-day events require manually chosen explicit start/end instants and correct offsets; the tool does not infer local midnight or all-day semantics. Attendee availability, omitted calendars/events, cancellations and resource aliases are not detected.

Maximum 100,000 characters and 500 rows per list, 1,000 scheduled conflict pairs and 300,000 draft characters. Validation and limit failures return no partial result. Conflicts are checked only within the scheduled list, including unexpected bookings, for the same exact resource. Missing, unexpected and changed bookings plus conflict pairs comprise the issue count; categories may involve the same booking.

## Fictional acceptance example

The browser's “Load a fictional example” uses these rows. The code below is also runnable after downloading the module into the same directory. The README uses a separate fictional fixture with the same acceptance counts.

```js
import { buildCalendarReconciliation } from './calendar-reconciliation.mjs';
const expected = [
  'booking-1\tRoom A\t2026-10-07T09:00:00-04:00\t2026-10-07T10:00:00-04:00',
  'booking-2\tRoom A\t2026-10-07T10:00:00-04:00\t2026-10-07T11:00:00-04:00',
  'booking-3\tRoom B\t2026-10-07T14:00:00Z\t2026-10-07T15:00:00Z',
].join('\n');
const scheduled = [
  'booking-1\tRoom A\t2026-10-07T13:00:00Z\t2026-10-07T14:00:00Z',
  'booking-2\tRoom A\t2026-10-07T13:30:00Z\t2026-10-07T14:30:00Z',
  'booking-4\tRoom B\t2026-10-07T15:00:00Z\t2026-10-07T16:00:00Z',
].join('\n');
const result = buildCalendarReconciliation(expected, scheduled);
console.log(JSON.stringify(result.counts));
console.log(`Checked: ${result.checked}; issues: ${result.issues}`);
// Review result.draft in full; result.findings retains the structured evidence.
```

Expected console output:

```text
{"expected":3,"scheduled":3,"missing":1,"unexpected":1,"changed":1,"unchanged":1,"normalizedMatches":1,"conflicts":1}
Checked: 6; issues: 4
```

The report must show booking-3 missing, booking-4 unexpected, booking-2 with changed start/end, and booking-1 unchanged despite its equivalent offset spelling. Scheduled booking-1 and booking-2 overlap from 13:30 to 14:00 UTC. The draft includes source rows, literal cells, UTC times and a manual-review checklist. This fixture is QA, not evidence of an independent scheduling task or actual Calendar changes.

## Complete the user's reconciliation job

1. Open the browser page, which starts empty. Optionally load the fictional example to learn the format; editing it remains sample use.
2. Choose “Start with my own booking lists” before entering real work. This clears the fictional inputs and result. Prepare the user's actual expected and scheduled lists with matching scope and stable IDs.
3. Create the reconciliation draft. Resolve validation errors before proceeding. Inspect every missing, unexpected, changed and conflicting booking against the actual source. An unchanged row confirms only the supplied resource and UTC interval.
4. Confirm offsets, recurrence instances, all-day boundaries, cancellations, resource names, permissions and attendee availability manually. Confirm intended changes before the user applies them through their normal scheduling process.
5. Copy and review the complete draft before sharing it. After resolving differences in the source, refresh both pasted lists and rerun. A clean result only covers those rows.
6. Confirm whether this completed the user's actual reconciliation task. Building or copying a draft does not establish changed events, sent invitations, completed scheduling, repeat use or a purchase.

For an agent without browser access, download the module and README and call `buildCalendarReconciliation(expectedText, scheduledText)` with the user's authorized, manually prepared lists. It returns `{ draft, checked, issues, counts, findings }`; consume the full draft and findings, not just the sample summary. `normalizedMatches` is a subset of unchanged bookings. Invalid data throws before any result is returned. The module has no implicit clock, network, filesystem access, telemetry or sends. Logging in the example is performed by the caller and is optional.

## Privacy and completion boundaries

The browser compares locally; usage events exclude booking IDs, resources, timestamps and draft text. The module has no runtime dependencies and performs no I/O, but an external agent, logger or surrounding app may retain or transmit its inputs. Choose an appropriate local environment for private schedules. No credentials are needed for this drafting job.

Neither route accesses Calendar, imports ICS, creates or changes events, sends invitations or installs Apps Script. Comparing the two lists manually is the existing alternative; no time saving has been measured. The separate Calendar event-creation guide at https://bulldo.gs/create-a-calendar-event-from-a-spreadsheet-row-in-google-calendar/ concerns a different action and is not executed by this job.

Source availability and successful fictional execution do not establish independent agent retrieval or execution. Keep eligible exposure, own-input use, user-confirmed useful completion and later real reuse separate. No paid offer, paid outcome or repeat-use claim accompanies this packet.
