Overview
A Change Request (ChangeRequest, prefixed CHG-NNNNN per workspace) is the central artifact for any planned modification to your environment — a deploy, a config tweak, a firewall rule, a certificate rotation. Vigilo treats every change as a first-class object with its own finite state machine, an approval workflow, a runbook of child tasks, a rollback plan, and an immutable history that you can export as an evidence pack for auditors.
Changes live under /ws/{slug}/changes. The list view supports filtering by status, change type, priority, risk level, and assignee. The detail page splits across tabs for Details, Risk assessment, Implementation tasks, Approvals, Comments, Attachments, and Activity.
Why it exists
Every regulated environment — SOC 2, ISO 27001, ITIL, FedRAMP — requires that production changes be planned, reviewed, authorised, executed, and reviewed again. The ChangeRequest model collapses what is typically four separate tools (ticket, runbook, approval queue, audit pack) into one workspace-isolated record, so the auditor can follow a single CHG number from intent to outcome without manually correlating systems.
Key concepts
- change_type — One of
standard,normal,emergency. Standard changes (is_standard=True) are pre-approved templates that skip the review and approval gates entirely. Normal changes go through the full FSM. Emergency changes bypass lead-time enforcement but still require an approval step. - priority —
low,medium,high,critical. Drives policy matching and dashboard sort. - risk_level —
low,medium,high. Auto-suggested from the risk assessment questionnaire (see Risk auto-suggest below). - planned_start / planned_end — The intended execution window. Both are required before the change can move from
approvedtoscheduled. Used by conflict detection and freeze-window enforcement. - affected_assets — Many-to-many to
assets.Asset. Drives cross-change conflict detection and lets stakeholders subscribe to a service rather than to a specific change. - min_lead_time_hours — Minimum hours between submit and
planned_start. Defaults fromDEFAULT_LEAD_TIME_HOURSper change_type:emergency=0,normal=24,standard=4. - closure_code — Required at completion. One of
successful,successful_with_issues,unsuccessful. Drives DORA failure-rate metrics. - dependencies — Other CHGs this one waits on. The
start()transition refuses to advance if any upstream CHG isn't incompletedorcancelled.
The FSM
The status field is an FSMField with the following transitions, each guarded by the changes.create, changes.approve, or changes.execute permission:
draft → submit() → review → approve() → approved → schedule() → scheduled
↘ reject() → rejected ↘ start() ↘
in_progress
↓ complete() ↓ rollback()
completed rolled_back
↓ reopen()
in_progress
draft|review|approved|scheduled → cancel() → cancelled
rolled_back is a distinct terminal state, separate from cancelled: cancelled means we decided not to do it, rolled_back means we did it, it broke, we reversed it. DORA failure-rate scoring treats the two differently.
Common workflows
Submitting a change
- Click New change in the changes list. Fill in title, description, change type, priority, and
affected_assets. - Switch to the Risk assessment tab and answer the ServiceNow PPRB-style questionnaire. The score is normalised to 0-100; the system suggests a
risk_levelonce enough questions are answered (WA.2). - Use Suggest similar on the toolbar to see CHGs with overlapping affected_assets or similar titles (WA.1). Review their outcomes for hints on rollback and approvers.
- Add
planned_startandplanned_end. The conflict banner at the top of the detail page calls/changes/conflicts-summary/and lists any CHGs whose windows overlap your assets. - Add an
implementation_plan,rollback_plan, andtest_plan. Use Generate implementation tasks to materialise each runbook step as aChangeTaskrow with its own predecessors and FSM. - Click Submit for review. The FSM moves to
reviewandgenerate_approval_stepsfromapps/approvals/services.pyspawns one or moreApprovalSteprows from the matchingApprovalPolicy. If no policy matches, the legacy hardcoded matrix runs as a fallback.
Executing a scheduled change
- Open the change, confirm
planned_startis imminent, and click Start. The FSM enforces the dependency gate — any blocking CHG produces adependencies_unmeterror listing the blockers. - Walk down the runbook: open each
ChangeTaskin order, click Start, then Done when the step finishes. Skipped tasks must be explicitly markedskipand only count whenis_required=False. - On completion, click Close change. The action opens a closure dialog and requires
closure_codeandclosure_notes— both are mandatory and surfaced in the audit pack. The runbook gate (assert_required_tasks_done) refuses closure if anyis_required=TrueChangeTask isn't done or skipped.
Rolling back
When a change is in_progress and going wrong, click Roll back. A reason is mandatory (rollback_reason_required). The FSM moves the change to rolled_back, stamps rolled_back_at / rolled_back_by, and emits a webhook so chat integrations can ping the on-call.
Exporting an evidence pack
From the change detail page, click Export evidence pack to generate a PDF that includes the description, approval chain, audit history, closure block, and runbook. The export is locale-aware: a German workspace produces a German PDF (test_pdf_locale.py covers the contract).
Permissions
- Viewers can list and read changes but cannot edit or transition.
- Engineers (
changes.create,changes.execute) can create drafts, submit, schedule, start, and complete. - Approvers / admins (
changes.approve) can approve, reject, and roll back. - Admins / owners can override a freeze window when
allow_override=True.
Troubleshooting
lead_time_violation on submit — Your planned_start is closer than min_lead_time_hours from now. Either push the window out, lower the lead time on the change (engineers can edit this), or flip the change to emergency if it genuinely cannot wait.
no_eligible_approvers on submit — The workspace has no active members with approver, admin, or owner role. Invite one, promote an existing member, or flag the change as pre-approved (is_standard=True).
freeze_window_blocked on submit or schedule — Your planned window overlaps an active FreezeWindow. See Freeze and maintenance windows for override semantics.
closure_required on close — You called complete() without setting closure_code. Use the Close change dialog rather than the raw FSM action; the dialog enforces the closure block.
dependencies_unmet on start — One of the CHGs in dependencies is still active. The error payload lists each blocker by number and current status.