Lesson 191: Follow-the-Sun Panel Attendance Quorum Crosswalk — ICS UID and Roster Slot Parity (2026)

Direct answer: Lesson 186 locks who must attend each follow-the-sun slot (mock_audit_panel_roster_slot + ics_uid). Lesson 182 records who actually attended (cert_rehearsal_attendance keyed by the same ics_uid). Lesson 191 crosswalks the two—exporting PANEL_QUORUM_MANIFEST.json and fail-closing publish on panel_quorum_gap_open when roster and receipt diverge.

Lesson hero for follow-the-sun panel attendance quorum crosswalk

Why this matters now (Q1 2027 follow-the-sun mock audits)

Q1 2027 intake replays added a standing question after Lessons 186 and 182 shipped separately:

“Show UID parity between the locked panel roster and completed attendance receipts for every US/EU/Asia slot in the handoff week—not panel ‘present’ on paper with no receipt.”

Failure mode in late 2026 planning:

  • Roster row lists Asia governance_owner; attendance panel_present_json substitutes US owner “because they joined the call.”
  • Lesson 181 re-exported ICS with a new UID; roster still references the old UID—crosswalk shows orphan roster + orphan attendance.
  • Lesson 179 handoff manifest is green while EU T-3 slot has roster but no completed attendance—false quorum on the leadership dashboard.

This lesson makes the crosswalk view the mechanical proof partners expect beside Lesson 176 reply packets.

Lesson objectives

You will implement:

  • panel_attendance_quorum_crosswalk — SQL view joining roster, attendance, and handoff week
  • UID parity checks (roster_ics_uid = attendance.ics_uid)
  • Signer parity checks (four Lesson 172 roles: roster binding vs panel_present_json)
  • PANEL_QUORUM_MANIFEST.json evidence extension on regional_panel_quorum_manifest.json
  • Publish-gate panel_quorum_gap_open (extends Lesson 171 / 186 panel_roster_gap_open)
  • Nightly job after attendance bootstrap (Lesson 182)

Prerequisites

  • Lesson 186mock_audit_panel_roster_slot, panel_roster_signer_binding, locked roster
  • Lesson 182cert_rehearsal_attendance, panel_present_json, completed status
  • Lesson 181cert_rehearsal_event.ics_uid source of truth
  • Lesson 179regional_handoff_week + handoff_week_id
  • Lesson 171 — active publish_tuple_hash

panel_attendance_quorum_crosswalk view

CREATE VIEW panel_attendance_quorum_crosswalk AS
SELECT
  s.roster_slot_id,
  s.handoff_week_id,
  s.cert_window_id,
  s.cert_rehearsal_label,
  s.slot_region,
  s.ics_uid                    AS roster_ics_uid,
  s.roster_status,
  s.publish_tuple_hash,
  a.attendance_id,
  a.ics_uid                    AS attendance_ics_uid,
  a.attendance_status,
  a.panel_present_json,
  (s.ics_uid IS NOT DISTINCT FROM a.ics_uid) AS uid_parity_ok,
  roster_signer_parity_ok(s.roster_slot_id, a.panel_present_json) AS signer_parity_ok,
  CASE
    WHEN s.roster_status <> 'locked' THEN 'roster_not_locked'
    WHEN a.attendance_id IS NULL THEN 'missing_attendance'
    WHEN a.attendance_status <> 'completed' THEN 'attendance_not_completed'
    WHEN s.ics_uid IS DISTINCT FROM a.ics_uid THEN 'ics_uid_mismatch'
    WHEN NOT roster_signer_parity_ok(s.roster_slot_id, a.panel_present_json) THEN 'signer_mismatch'
    ELSE 'ok'
  END AS crosswalk_status
FROM mock_audit_panel_roster_slot s
LEFT JOIN cert_rehearsal_attendance a
  ON a.ics_uid = s.ics_uid
 AND a.cert_window_id = s.cert_window_id
WHERE s.roster_status = 'locked';

Pass row: crosswalk_status = 'ok'.

Gap rows: everything else feeds panel_quorum_gap_open.

roster_signer_parity_ok function (sketch)

CREATE OR REPLACE FUNCTION roster_signer_parity_ok(
  p_roster_slot_id TEXT,
  p_panel_present JSONB
) RETURNS BOOLEAN AS $$
  SELECT NOT EXISTS (
    SELECT 1
    FROM panel_roster_signer_binding b
    WHERE b.roster_slot_id = p_roster_slot_id
      AND COALESCE(
        p_panel_present -> b.panel_role ->> 'signer_id',
        ''
      ) <> b.signer_id
  );
$$ LANGUAGE sql STABLE;

Policy: backups may attend only when backup_promote_event from Lesson 174 is attached to the attendance receipt metadata—otherwise primary signer_id must match.

UID parity checks (batch)

-- Orphan roster: locked slot, no attendance row for ICS UID
SELECT roster_slot_id, roster_ics_uid
FROM panel_attendance_quorum_crosswalk
WHERE crosswalk_status = 'missing_attendance';

-- Orphan attendance: completed receipt UID not on locked roster
SELECT a.attendance_id, a.ics_uid
FROM cert_rehearsal_attendance a
JOIN cert_rehearsal_event e USING (ics_uid)
LEFT JOIN mock_audit_panel_roster_slot s
  ON s.ics_uid = a.ics_uid AND s.roster_status = 'locked'
WHERE a.attendance_status = 'completed'
  AND s.roster_slot_id IS NULL
  AND e.cert_window_id = :window;

-- UID mismatch (should be impossible if JOIN keys align—catches manual SQL edits)
SELECT roster_slot_id, roster_ics_uid, attendance_ics_uid
FROM panel_attendance_quorum_crosswalk
WHERE crosswalk_status = 'ics_uid_mismatch';

Run all three after every Lesson 182 bootstrap job for the active cert_window_id.

PANEL_QUORUM_MANIFEST.json (extension)

Extends Lesson 186 regional_panel_quorum_manifest.json:

{
  "schema": "panel_quorum_manifest_v2",
  "handoff_week_id": "hw_2027_q1_meta",
  "publish_tuple_hash": "c4e8…",
  "generated_at_utc": "2027-01-09T06:00:00Z",
  "slots": [
    {
      "roster_slot_id": "rs_us_t14",
      "roster_ics_uid": "[email protected]",
      "attendance_id": "a1b2…",
      "crosswalk_status": "ok",
      "uid_parity_ok": true,
      "signer_parity_ok": true
    },
    {
      "roster_slot_id": "rs_asia_t3",
      "roster_ics_uid": "[email protected]",
      "crosswalk_status": "missing_attendance",
      "uid_parity_ok": false,
      "signer_parity_ok": false
    }
  ],
  "gap_count": 1,
  "manifest_sha256": "…"
}

Store under release-evidence/05-operations/follow-the-sun-quorum/.

Pin manifest_sha256 in BUILD_RECEIPT.json when gap_count = 0.

Publish gate: panel_quorum_gap_open

-- block_reason = 'panel_quorum_gap_open'
WHEN EXISTS (
  SELECT 1 FROM panel_attendance_quorum_crosswalk c
  JOIN regional_handoff_week w USING (handoff_week_id)
  WHERE w.active_publish_tuple_hash = :active_tuple
    AND c.crosswalk_status <> 'ok'
)
OR EXISTS (
  SELECT 1 FROM cert_rehearsal_attendance a
  JOIN cert_rehearsal_event e USING (ics_uid)
  WHERE e.publish_tuple_hash = :active_tuple
    AND a.attendance_status = 'completed'
    AND NOT EXISTS (
      SELECT 1 FROM mock_audit_panel_roster_slot s
      WHERE s.ics_uid = a.ics_uid AND s.roster_status = 'locked'
    )
);

Pairs with Lesson 186 panel_roster_gap_open (roster incomplete before ICS export). 191 catches drift after attendance exists.

Clears when crosswalk shows zero gap rows and manifest gap_count = 0.

Nightly crosswalk job (after attendance bootstrap)

def nightly_panel_quorum_crosswalk(handoff_week_id: str) -> None:
    rows = fetch_crosswalk(handoff_week_id)
    gaps = [r for r in rows if r.crosswalk_status != "ok"]
    manifest = build_panel_quorum_manifest_v2(rows, len(gaps))
    write_manifest(manifest)
    if gaps:
        page_oncall("panel_quorum_gap_open", gap_count=len(gaps))

Schedule 30 minutes after Lesson 182 attendance ingest cron for the same cert_window_id.

Common mistakes

  • Validating panel_present_json without comparing to roster bindings—receipt passes, quorum fails.
  • Re-exporting ICS (Lesson 181) without updating roster ics_uid—orphan rows overnight.
  • Treating scheduled attendance as quorum—only completed counts.
  • Crosswalking against draft roster—must be locked.
  • Ignoring orphan attendance query—partners find receipts with no roster during US→Asia handoff weeks.

Troubleshooting

Symptom Likely cause Fix
panel_quorum_gap_open Any crosswalk_status <> ok Complete attendance or fix roster UID
signer_mismatch Backup attended without promote event Attach Lesson 174 event or fix JSON
missing_attendance No-show or bootstrap not run Run Lesson 182 job; mark no_show explicitly
ics_uid_mismatch Manual UID edit Re-lock roster; re-export ICS
Manifest gap_count > 0 but gate clear Stale BUILD_RECEIPT Pin new manifest SHA

Verification checklist

  • [ ] Locked roster + completed attendance with same UID → crosswalk_status = ok
  • [ ] Deliberately change attendance UID → ics_uid_mismatch or orphan attendance
  • [ ] Substitute wrong signer_id in JSON → signer_mismatch
  • [ ] PANEL_QUORUM_MANIFEST.json lists every locked slot for the week
  • [ ] Gate clears only when gap_count = 0 and manifest SHA pinned

Mini exercise (25 minutes)

  1. Lock two roster slots (US + EU) for a test handoff_week_id.
  2. Bootstrap completed attendance for US only.
  3. Run crosswalk job; capture manifest with gap_count = 1.
  4. Complete EU attendance with matching signers.
  5. Re-run; confirm panel_quorum_gap_open clears.

Continuity

  • Lesson 186 — roster contract and ICS UID assignment.
  • Lesson 182 — attendance receipts and panel_present_json.
  • Lesson 179 — regional handoff week ownership.
  • Lesson 190 — nightly bind reconcile (orthogonal; run both jobs).
  • Next: Lesson 192 — rubric emergency weight hotfix without breaking Lesson 185 pins.
  • Help: OpenXR governance rollup mismatch — dashboard quorum adjacent discipline.

FAQ

Does this replace Lesson 186 roster lock?
No. 186 blocks ICS export without roster; 191 proves attendance matched roster after the tabletop.

What about cancelled slots?
Set roster_status = 'cancelled' and exclude from manifest; do not expect attendance rows.

Can one attendance cover two roster slots?
No—one ics_uid per slot. Split combined tabletops into separate calendar holds.

EU slot green in Lesson 179 but gap here?
Handoff ownership ≠ attendance quorum—fix crosswalk before leadership readback.


Q1 2027 partners trust follow-the-sun rehearsals when UID and signer parity are machine-checkable. Run the crosswalk nightly, export the manifest, and treat panel_quorum_gap_open like a release blocker—not a spreadsheet cleanup task.