Overview
A CABMeeting is a scheduled review of a batch of changes by a designated group of stakeholders. CAB meetings exist when you want a human gate with a quorum — not a single approver clicking through a queue, but a room (physical or virtual) where several people walk an agenda, debate risk, and record a collective decision per change.
The CAB lives at /ws/{slug}/changes/cab. The list shows upcoming and past meetings; each meeting has its own detail page with agenda, attendees, chair, minutes, and the per-change decision log.
Why it exists
For high-risk, cross-team, or regulated changes, a single approver isn't enough. ITIL, SOX, and most enterprise change-management policies require a board review. Vigilo models the board as a first-class object so the board's decisions live next to the changes they decided, with the same audit trail and webhook surface as individual approvals.
CAB-as-gate ties the two together: an ApprovalPolicy stage with kind="cab" produces an ApprovalStep with stage_type='cab' that doesn't resolve until the relevant CABMeeting.record_decision() fires. The board's decision becomes the change's approval.
Key concepts
- CABMeeting — Workspace-scoped meeting record. Has
title,scheduled_at,duration_minutes(default 60),status, achair(FK to UserProfile),attendees(M2M to UserProfile), andchanges(M2M to ChangeRequest — the agenda). - status — One of
scheduled,in_progress,completed,cancelled. The status drives which actions appear on the toolbar. - agenda — The
changesM2M is the agenda. A change can be on multiple CABs (e.g. pre-CAB then formal CAB). Adding a change with a pending CAB-stageApprovalStepautomatically binds the step to this meeting viacab_meeting. - decisions — Free-form JSON dict keyed by change number, e.g.
{"CHG-00012": {"decision": "approved", "notes": "Hold for retest"}}. Updated by the Record decision action and used to driveApprovalStep.statusfor CAB-gated steps. - CAB stage type — Inside an
ApprovalPolicy, a stage withkind="cab"declares "this gate is a CAB decision". When the change submits, anApprovalStepwithstage_type='cab'is created; until the change appears on a CAB agenda and the meeting records a decision, the step stays pending and SLA accrues. - Workspace isolation — CAB meetings, their attendees, their changes, and their decisions all carry
workspaceFKs. RLS guarantees a CAB from workspace A is invisible to workspace B (test_cab_isolation.pyproves it; T3.2).
Common workflows
Scheduling a CAB
- Navigate to Changes → CAB → New meeting.
- Fill in title,
scheduled_at(date + time),duration_minutes, chair, and the initial attendee list. - Save. The meeting lands in
scheduledand acab.scheduledevent fires viadispatch_event, so chat integrations can post a calendar invite.
Building the agenda
- From the CAB detail page, click Add changes. The picker shows changes with
status='review'and at least one pendingApprovalStepofstage_type='cab'not yet bound to another meeting. - Pick the changes; save. Each change's CAB step is now bound to this meeting via
cab_meeting. - Optionally reorder the agenda by dragging items in the list — the order is preserved in the JSON payload that drives the meeting view.
Running the meeting
- On the day, the chair clicks Start meeting. Status moves to
in_progress. - Walk the agenda. For each change, the meeting view shows the change preview, the discussion area (
minutesfield appended to as a single textarea), and an inline Record decision widget. - Click Approve or Reject on each row, optionally with notes. The action calls
services.record_decision(step, ...)which sets the boundApprovalStep.statusanddecision_at, advances the change FSM if this was the last step, and writes{change_number: {decision, notes}}into the meeting'sdecisionsfield. - When every agenda item has a decision, click Complete meeting. Status moves to
completed. Acab.completedevent fires.
Per-meeting maintenance (PR2)
- Reschedule — Pick a new
scheduled_at. Available while status isscheduled. Attendees and agenda are preserved. - Cancel — Moves status to
cancelled. CAB-boundApprovalSteprows are released (set back to unbound) so the changes can be moved to another meeting without spawning new steps. - Delete — Removes the meeting record entirely. Refuses if status is
in_progressorcompleted(preserve the audit trail). Available to admins only.
Permissions
- Viewers can see CAB meetings on the calendar but not attend or vote.
- Attendees (anyone in the meeting's
attendeesM2M) can read the agenda, post minutes, and — if they also hold thechanges.approvepermission — record decisions. - Chairs can start, complete, reschedule, and cancel their own meetings.
- Admins / owners can delete meetings and reassign chair.
Troubleshooting
The change doesn't appear in the "Add changes" picker — Either it doesn't have a CAB-stage ApprovalStep (check the change's policy), the step is already bound to another meeting, or the change isn't in status='review'. Promote it to review first or re-issue the approval policy.
"Record decision" is greyed out — The change has been removed from this meeting's agenda, or the bound ApprovalStep has already been decided elsewhere (e.g. another meeting). Refresh; the row should disappear.
The CAB completed but the change is still in review — The change had additional non-CAB ApprovalStep rows that haven't been approved. Check the Approvals tab on the change for the full chain.
I can't see another workspace's CAB I was invited to — You can't. CAB meetings are workspace-scoped. You need to be a member of the workspace the CAB belongs to (WorkspaceMembership with is_active=True).