Lesson 184: ICS Rehearsal Hold Conflict Detector vs Leadership Offsite Calendar (2026)
Direct answer: Lesson 181 exported ICS rehearsal holds into shared calendars. Lesson 184 imports leadership offsite blocks, runs a mechanical overlap detector, and blocks publish while any cert_rehearsal_hold row overlaps an offsite event on the same room resource—so October 2026 planning decks cannot silently delete your only tabletop slot.

Why this matters now (October 2026 leadership offsites)
October 2026 is when companies book annual planning offsites—often the same conference room engineering reserved for Q1 2027 mock-audit rehearsals:
- Leadership calendars show “Strategy offsite — all day” while engineering still has a T-14 rehearsal UID from Lesson 181.
- Lesson 182 attendance receipts never fire because nobody showed up—the room was physically booked for slides, not tabletop.
- Lesson 183 exports deficiencies from scored logs that never happened—garbage-in for Block 6.
- Partner readbacks ask “show the calendar evidence”—not “we forgot.”
A conflict detector turns calendar politics into a red dashboard row before cert week.
Lesson objectives
You will implement:
leadership_offsite_eventingest table (ICSVEVENTsubset)cert_rehearsal_holdview aligned to Lesson 181cert_window_calendarrehearsal_hold_conflictmaterialized view + nightly refreshrehearsal_hold_conflict_runjob metadata- Publish-gate
rehearsal_hold_conflict_open - Waive path with
signer_ack_event+conflict_waive_id
Prerequisites
- Lesson 181 — ICS export + stable
ics_uidper hold - Lesson 182 — attendance only after holds are real
- Lesson 171 — publish gate extension pattern
- Optional: Operating review template blog — Friday calendar hygiene
leadership_offsite_event table
CREATE TABLE leadership_offsite_event (
offsite_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ics_uid TEXT NOT NULL UNIQUE,
summary TEXT NOT NULL,
location_resource TEXT NOT NULL, -- e.g. 'conf-room-a', 'zoom-bridge-1'
starts_at_utc TIMESTAMPTZ NOT NULL,
ends_at_utc TIMESTAMPTZ NOT NULL,
organizer_email TEXT NOT NULL,
imported_at_utc TIMESTAMPTZ NOT NULL DEFAULT now(),
source_calendar TEXT NOT NULL
CHECK (source_calendar IN ('leadership_exec','facilities_shared'))
);
Ingest weekly from leadership’s exported .ics (read-only feed). Do not mutate engineering holds here—detect only.
cert_rehearsal_hold view
CREATE VIEW cert_rehearsal_hold AS
SELECT
c.cert_window_id,
c.ics_uid,
c.hold_type, -- 'T-14' | 'T-3'
c.starts_at_utc,
c.ends_at_utc,
c.location_resource,
c.rubric_version
FROM cert_window_calendar c
WHERE c.hold_status = 'active';
location_resource must match facilities naming—normalize in Lesson 181 README (GOVERNANCE_REHEARSAL_README.md).
Overlap detector
CREATE MATERIALIZED VIEW rehearsal_hold_conflict AS
SELECT
h.cert_window_id,
h.ics_uid AS rehearsal_ics_uid,
o.offsite_id,
o.ics_uid AS offsite_ics_uid,
h.location_resource,
GREATEST(h.starts_at_utc, o.starts_at_utc) AS overlap_start_utc,
LEAST(h.ends_at_utc, o.ends_at_utc) AS overlap_end_utc,
EXTRACT(EPOCH FROM (
LEAST(h.ends_at_utc, o.ends_at_utc) -
GREATEST(h.starts_at_utc, o.starts_at_utc)
)) / 60 AS overlap_minutes
FROM cert_rehearsal_hold h
JOIN leadership_offsite_event o
ON h.location_resource = o.location_resource
AND h.starts_at_utc < o.ends_at_utc
AND h.ends_at_utc > o.starts_at_utc
WHERE EXTRACT(EPOCH FROM (
LEAST(h.ends_at_utc, o.ends_at_utc) -
GREATEST(h.starts_at_utc, o.starts_at_utc)
)) / 60 >= 15;
15-minute floor ignores back-to-back buffer noise; tabletop needs 90 minutes contiguous—flag any overlap ≥ 15 until human review.
Refresh after each offsite import:
REFRESH MATERIALIZED VIEW CONCURRENTLY rehearsal_hold_conflict;
Waive path (rare, audited)
When leadership intentionally shares the room (split morning/afternoon):
INSERT INTO rehearsal_hold_conflict_waive (
conflict_key, conflict_waive_id, signer_role, ack_at_utc, rationale
) VALUES (
'h.ics_uid|o.ics_uid', 'waive-2026-10-12-a',
'governance_owner', now(), 'Offsite ends 12:00 UTC; T-14 starts 13:00 — facilities confirmed flip'
);
Publish gate ignores waived rows only when conflict_waive_id present and overlap_minutes < 90 after waive review.
Publish-gate extension
Add to Lesson 171 block_reason allow-list:
rehearsal_hold_conflict_open— any non-waived row inrehearsal_hold_conflictfor the publishingcert_window_id.
Conflict resolution procedure (same day)
| Step | Owner | Action |
|---|---|---|
| 1 | Governance owner | Run import + REFRESH after leadership calendar publish |
| 2 | Scribe | Open conflict export JSON in evidence folder |
| 3 | Leadership delegate | Rebook offsite or move rehearsal hold (new ICS UID → Lesson 181 re-export) |
| 4 | Engineering | Verify rehearsal_hold_conflict count = 0 |
| 5 | Governance owner | Clear publish gate; notify Lesson 182 scribe |
Target same business day—do not let conflicts sit over a weekend before October room locks.
Export artifact
release-evidence/05-operations/REHEARSAL_CONFLICT_YYYYMMDD.json:
{
"schema": "rehearsal_hold_conflict_v1",
"run_at_utc": "2026-10-05T18:00:00Z",
"conflicts": [
{
"cert_window_id": "q1_2027_meta",
"rehearsal_ics_uid": "uid-t14-q1-meta",
"offsite_ics_uid": "uid-offsite-strategy-oct",
"location_resource": "conf-room-a",
"overlap_minutes": 120
}
],
"sha256": "…"
}
Integration chain
flowchart LR
L181[Lesson 181 ICS holds] --> HOLD[cert_rehearsal_hold]
OFF[Leadership offsite ICS] --> DETECT[rehearsal_hold_conflict]
HOLD --> DETECT
DETECT -->|open| GATE[Publish blocked]
DETECT -->|clear| L182[Lesson 182 attendance]
L182 --> L183[Lesson 183 CSV export]
Common mistakes
- Comparing calendars in local time without UTC storage.
- Different
location_resourcestrings (Conference Room Avsconf-room-a). - Waiving without signer ack—partner readback treats as silent drop.
- Re-exporting Lesson 181 ICS without new UID when moving holds (Lesson 182 receipt breaks).
- Ignoring Zoom bridge offsites that still block the physical room resource.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| False green, room empty | Offsite on wrong calendar feed | Import leadership_exec not facilities_shared |
| Conflict never clears | Stale materialized view | REFRESH CONCURRENTLY |
| 14-minute overlap flagged | Floor too low | Keep 15m; document waive for buffers only |
| Gate blocks whole quarter | One window conflict | Filter publish by cert_window_id |
| Duplicate offsite rows | Re-imported ICS | UNIQUE (ics_uid) upsert |
Verification checklist
- [ ] Overlapping test events produce a conflict row
- [ ] Non-overlapping same-room back-to-back (14m gap) does not fire
- [ ] Waive + signer ack suppresses gate for approved case
- [ ]
REHEARSAL_CONFLICT_*.jsonin evidence with SHA-256 - [ ] Lesson 182 bootstrap blocked while conflict open (deliberate test)
Mini exercise (25 minutes)
- Create two fake ICS events sharing
conf-room-awith 60-minute overlap. - Insert into
leadership_offsite_event+cert_window_calendarstub rows. - Write expected
rehearsal_hold_conflictoutput row. - Draft one waive JSON with rationale for a split-day resolution.
Continuity
- Lesson 181 — source holds; re-export when rescheduling.
- Lesson 182 — do not bootstrap attendance while conflicts open.
- Lesson 183 — export only after scored tabletop exists.
- Next: Lesson 185 — rubric semver drift blocks calendar re-export.
- Guide: Spline embed preflight unrelated; calendar discipline pairs Friday Block 5 ritual blog.
FAQ
Can we use Google Calendar API instead of ICS files?
Yes—normalize into the same tables. Keep ICS export as disaster recovery.
Remote-only panels?
Set location_resource = 'zoom-bridge-1' for rehearsals; only compare offsites that claim the same bridge resource.
Does this replace facilities booking?
No—it detects drift between leadership and engineering calendars; facilities may still be source of truth for keys.
Conflict on T-3 only—block T-14?
Gate is per cert_window_id; any hold overlap blocks the window until cleared.
Calendar silence killed more 2026 mock audits than bad rubric scores. Detect overlaps mechanically, rebook before October offsites freeze, then let Lessons 182–183 run on real tabletop proof.