Changes reference

The change ledger record field by field — sources, statuses, classes, risk tiers, windows, last-known-good records, rollback paths, harvest sources and the audit actions a change emits.

Reference · Updated 2026-10-28 · Describes release 0.1.164

Exact facts about the change ledger. Procedures live in Change windows, emergency changes and rollback, Review execution in Changes, Runbooks and automatic fixes and Automatic API fixes; the approval rules are owned by Approval policy and change tiers.

The change record

One row per change the platform executed, prepared, declared or observed. GET /api/aiops/{workspace}/changes returns the public copy of each row (credentials masked structurally, the platform's own webhook token redacted, the internal execution_intent / rollback_intent keys removed from meta). On screen a change is quoted as CHG- plus the first 8 characters of its id.

Field Meaning Set by
id Row id; the display id is CHG-<first 8> platform
source Where the row came from — see Sources, origins and modes the minting path
origin_type, origin_id What the change is about (incident + the incident id for cross-links, finding, control, …) the minting path
service Primary target service — the key the incident card and change_lookup query by; never rewritten after the fact the mint; a harvest links extra services instead
services Every service the change touches: impacted services of the origin incident, or the services a resource map / self link tied a harvested write to. Only the second kind pins an alert's incident on the change or folds an alert by change-window: a platform change's impacted services are what it may affect, not what it changed, so it pins and folds on its own service and resource only the mint, change_resource_map, the self link
title, summary What and why, PII-scrubbed at write the mint
status Lifecycle state — see Statuses the lifecycle
risk_tier L0–L3, stamped at plan time; a class or a reclassify may raise it tiers.classify, the class
plan The remediation plan (steps, commands, execution_steps, file_changes, manual_commands, verification, rollback, generated_by, plan_investigation_id); a released change also carries _execution_review (the reviewed action, shown only while its digest is the approved one) the wrap-up, the operator handoff, the review
execution_spec The compiled executable specification of a prepared plan: steps[] (operation, target, mode, params, connection), selected_connections, change_window, risk_tier, verification_checks, rollback_commands, impact planned_execution.review
lkg The last-known-good capture — see Last-known-good records the capture before the write
rollback The rollback the platform holds — see Rollback paths synthesized at execution
route_id The remediation route used (empty for a prepared plan or an observed change) a route run
mode Execution channel or ingested event kind — see Sources, origins and modes the mint
approved_by Distinct user ids that released the current reviewed action the release
approvals_required Quorum for risk_tier (1, or 2 at L3) the tier policy
authorized, authorization_note false = an unauthorized external change (denied write, freeze window, principal check, no reference) or a refused release; the note says why; a change kept as legitimate turns true with the keeper's note the harvest, authorize(), Keep this change (legitimate)
executed_at When the write happened (for an observed change: the event time, which may be days before the row) execution / the event
execute_result {ok, detail, uncertain, …} from the executor execution
verify_verdict cleared, still_present or uncertain the recheck, a human verify
verify_ref The IncidentRecheck id, a verify investigation id, or manual:<user id> the verdict
external_key Dedupe key of an observed change (commit sha, PR id, sync revision, audit event id) the harvest / webhook
external_url Link to the PR, commit or ticket (sanitised before store) the harvest / webhook
actor A user id, system:auto (an automatic lane), agent:<pillar> (a drafted request) the mint
meta Side facts — the keys below several
created_at, updated_at Row times platform

meta keys the API exposes:

Key Meaning
change_class, change_class_source, change_class_reason, release_class, change_class_auto, class_overrides[], class_signature The change class and its provenance — see Change classes
proposed_from_wrapup The request an escalated analysis minted (id derived from the investigation, so a Request click never opens a second row)
scope[], scope_total, scope_fixes The alerts and findings the request covers (at most 50 listed, excluded and left-out ones first) and how many of them the fix covers
scope_deferred[] The resources a person left out of the run the request was drafted from, in full; the review, the automatic runbook lane and a later Generate plan read it here
approvals[] The approval ledger: {user_id, kind, at, digest, note?} with kind = requested, approved (a vote that did not run the change: short of the quorum, or an Approve without running it), released (the person who released it to run: the vote that completed the quorum and ran it, or the run of an approved change by someone else, recorded when it dispatches), rejected or lapsed. Approved by one person and released by another is two entries, two people. An operator release records note: standard change released by an operator; its review digest binds that release policy.
approved_action_digest The reviewed action the votes belong to; a different review clears the votes
impact Blast radius from the estate ontology (basis: estimated < runtime < computed < certified), computed lazily when the request is opened. basis_reason is the one sentence on what the numbers rest on — for an estimate, computed from the target's direct neighbours in the estate map; this operation has no exact before/after delta. unless a more specific reason applies (the target not found, the scope too large to reason over); the page and the document show it once, as Estimate: …, the specific reason instead of the default (a report stored before 0.1.161 that joined both reads Estimate: target not found in the harvested estate). coverage_gaps[] are the map's gaps in words, one line per kind and only when non-zero, each against the whole map: N of M resources in the estate map: no relationship model yet (types without a typed reader: …), … stale after the last harvest, left out of reasoning, … inconsistent between sources, left out of reasoning, never overlapping (a report stored before 0.1.161 folded them into N entities and M relations flagged inconsistent or stale left out of reasoning: its relations read in the per-kind line, its entities — stale and inconsistent counted together, with no total — as Coverage gap recorded before 0.1.161, not split by kind: N resources in the estate map stale or inconsistent between sources, left out of reasoning); a gap on the touched resource itself comes first and makes the basis an estimate. An estimate's affected list is the target's direct neighbours — unmodelled or unexpanded ones included, stale or inconsistent ones left out — never the account, subscription, team or owner it is co-located under. mode is cheap on the report computed when the request is first opened; the reviewed one has none
window_bypassed {at, by, window, quorum} — an emergency released through a closed window
window_exception {requested_by, requested_at, start, end, reason, status, decided_by, decided_at, action_digest, used_at, used_by} — a separate, digest-bound one-time window; approval is not a release vote
pir The post-implementation review: {status, opened_at, due_at, owner, note, trigger, landed_at, outcome}
principal Who made an observed cloud write — see Principal classes
detail The harvested event: provider, operation, resource id, region, request parameters, the before/after diff, before_source, link
route_revision For a route run: the route revision, who certified it and the release kind (person, auto_pr, auto_direct)
validation, verify The post-change metric window and the recheck's evidence stamped on the change
snapshots[] {after_step, operation, at, resources[{step, target, operation, status, image, note, read_at, artifact_id}], not_read?, note?} — every resource the plan writes, read again after each write step of a multi-step plan (at most 10 per step, 40 per change; evidence only) — see Resource snapshots
post_state {captured_at, steps[]} — the post-change read the last-known-good record takes once the change is verified
rollback_intent, rollback_result, rollback_receipt_recorded, rollback_reconciled, rollback_uncertain Rollback bookkeeping; any of them means the sweep will not replay a rollback
rollback_attempts Rollbacks that wrote nothing for certain — the provider refused the call before acting (a 4xx other than 408/409), or the release stopped before dispatch: {at, released_at, by, reserved_at, ok: false, detail} (at = the refused release, released_at = when the reservation was given back), the last 10. Such an attempt gives its reservation back, so the change offers Roll back again (same tier gate) — the rollback sweep never replays it either; an uncertain or partial rollback keeps its reservation until it is reconciled
reverts, undone_by The re-break link: this captured write put back what a platform fix cleared, or this fix was undone by that write (within 14 days)
deploys, sync_status, application For an observed deployment: the platform change it deployed, the sync state, the application evidence
reference What accounted for an applied write the audit log captured, while incidents for changes with no reference are on: {kind: platform, receipt}, {kind: allowlist, pattern}, {kind: itsm, change_id, ref, title} or {kind: change_request, change_id} — see Unauthorized changes and denied access
itsm An ITSM change ticket's {state, ci, start, end}, refreshed by every re-send of the ticket
unauthorized_incident The incident an unauthorized change or a denied attempt opened or joined
kept {by, at, note, incident_id} — an approver kept this unauthorized change as legitimate

What the detail endpoint adds

GET /api/aiops/{workspace}/changes/{id} (incidents.view) returns:

Key Content
change The public record above, plus execution_review when the approved digest matches
rollback_first The pinned change's rollback when the workspace's rollback-first switch is on and this request is not that change
approvals meta.approvals with user ids resolved to emails
route_certifier Who certified the route revision a route run used
artifacts Last-known-good captures, rollback plans, PR evidence (kind = lkg, rollback, …)
incident The origin incident, when origin_type is incident; for an unauthorized change or a denied attempt, the incident it opened (meta.unauthorized_incident)
external_executions Operator reports of work done outside the platform (computer-assist mode): performed_by, executed_at, outcome succeeded / failed / unknown, summary, evidence links — reported, never verified
tier_policy {approvals, permission, label} for risk_tier
snapshots Every resource the plan writes: its before-state, the read after each step, the post-change read — {phase, label, step, target, status, state, at, changed, artifact_id}, changed against the before-state (null = not comparable)
upgrade_warning An upgrade's warning (section 2.4 of its change request document): the change management agent's words, else exactly unknown, not checked; null for a change that is no upgrade
verify `{kind: manual
trail Every audit event targeting this change (newest 200), plus the origin incident's remediation.pr_merged

Sources, origins and modes

source Written by Typical origin_type
incident An escalated analysis (the proposed change request), a route run from the incident page, a prepared plan released from the incident incident
manual POST …/changes — a declared change request (incidents.act), optionally copying an investigation's recorded plan; the Test Lab manual, incident, testfactory
compliance A control's "request a change" and the fix risk decision (avoid; mitigate on decisions made before fix / suppress) (through the change hub; compliance holds no write path) control, finding
lkg_draft The revert draft the incident's last-known-good record offers incident
ingested The harvest (cloud audit logs, watched repositories) and the change webhooks; status recorded, no lifecycle webhook

mode on a platform change is the execution channel: gitops_pr, api, cli, mcp, network, or external (an operator reported it). On an ingested row it is the event kind:

Kind Source
push A commit pushed to a watched repository, or sent by the GitHub / Gitea / GitLab / Azure DevOps webhook
pr_merged A pull request merged (same senders)
deploy A deployment reported to the change webhook
sync An Argo CD sync or drift event (argocd:<app>@<revision>; :drift when OutOfSync)
ticket_change A change ticket from ServiceNow or Jira
cloud-write A write read from CloudTrail, the EKS audit log, the Azure activity log or the Kubernetes audit webhook
config A setting changed inside an application, posted to the change webhook (detail {key, old, new}; a secret-looking key keeps only its name)

List filters: kind=push,pr_merged,deploy,sync (the Deployments chip; an unknown kind is a 400), mode=platform (everything the platform executed, i.e. not cloud-write), source=, status=, service=, unauthorized=true (unauthorized changes, the Unauthorized chip; never a denied call), denied=true (calls the cloud refused — unauthorized access, the Denied attempts chip), requests=true (every request, proposals included, the ones waiting on a person first), include_proposed=true, q= (display id, title or service).

Statuses

Status Meaning On screen (Requests view)
draft Declared without a plan —
planned A plan exists; nobody has asked for approval yet Awaiting request
pending_approval Requested; the quorum is not complete Awaiting approval
approved Quorum complete, not yet dispatched —
dispatching The write was reserved and sent —
executing The write ran; a pull request is open —
verifying Waiting for the post-fix verdict. Its incident stays remediating meanwhile: a scanner clear or an alert that resolves at its source does not resolve the incident by itself — it lets the platform read the validation plan at once (below), the change's verdict decides, the change completes and the incident resolves after it (observed live: a scanner clear at 20:49Z, the resolve at 20:55Z) —
completed Verified cleared, or the PR merged and validated. A change whose every step acted on the resource of an alert merged into the incident, none on its own, completes with the verdict uncertain when the incident clears (meta.cleared_externally, shown as the change's note): the clear is not credited to it —
failed Execution failed, verification said still_present, or it stopped without a verdict (the verification ran out, or a person closed it without one) —
not_needed The run stopped because its only target already complied (an EC2 instance Patch Manager reads compliant): nothing was changed, so nothing rolls back. The reason is on the change page, the incident's remediation history and the change request (Not needed — <reason>) —
rolling_back, rolled_back A rollback is running / landed —
rejected Refused by an approver or by a structural check —
recorded An observed external change (never moves) —

Terminal states: completed, rolled_back, not_needed, rejected, recorded. A release is only possible from draft, planned, pending_approval or approved; an operator may report an external execution from those plus failed and verifying.

Change classes

The class is ITIL vocabulary decided in code at wrap-up, never by the model, and stamped as meta.change_class with change_class_source and a plain-words change_class_reason.

Class Tier floor What it changes
standard L1 A matched-runbook standard fix at L1/L2 may be released by an operator (incidents.act) or an approver — a certified runbook route's at any priority, P1 included; other standard requests and L3 still need approvers. No automatic standard-release lane.
normal L2 The default for everything else
emergency L3 Two distinct approvers; a closed change window yields once both have approved (meta.window_bypassed, audit change.window_bypassed); a post-implementation review opens when the write lands (or at submission with aiops_pir_at_submission: true), due in aiops_pir_due_h hours (72)

Derivation rules

Evaluated in this order; the first rule that applies decides. change_class_source names it.

Order Condition Class change_class_source
1 settings['change_class_policy'] = "standard_default" the inherited class if one exists, else standard inherited:<CHG id> / policy_default
2 aiops_runbook_standard_change on and a certified remediate-… route declares every typed operation of the plan (each one also on aiops_preapproved_operations, no raw command or file change beside them, any manual_commands only restating a typed step) the inherited class if one exists, else standard — released under the standard rules even for a P1 or critical incident (no two-approver rule; an older request that recorded meta.release_class = emergency keeps it) inherited:… / runbook_route
3 The incident is P1 or its severity is critical emergency rule
4 A person set a class on an earlier request with the same operations (meta.class_signature) that class inherited:<CHG id>
5 aiops_runbook_standard_change off, a runbook skill (not a process skill) was fetched during the analysis, the plan has typed execution_steps, every operation is on aiops_preapproved_operations, and there are no commands or file_changes — with the switch on (the default) a fetched skill alone never makes a change standard standard rule
6 Anything else normal rule

A runbook route's standard class holds only while the runbook does. When the route is deleted, disabled, demoted, loses its certification or is edited before the request is released, the request reads as the class it has without the runbook (normal, or emergency for a P1 or critical incident) with source runbook_withdrawn on the incident and the change page — the class cell and the Timeline heading say why, in one vocabulary with the route row and the runbook catalog (meta.change_class_cause): certification withdrawn by a person, runbook demoted after a rollback, after a failed validation or after a fix that did not hold, runbook disabled, deleted, no longer certified or changed since the request was drafted; a row from before 0.1.159 carries no cause and reads runbook no longer backs it — at the tier that class raises it to (an emergency is L3, two approvers), the review releases it at that class, and the drop is recorded on the row (audit change.class_dropped, votes cleared) when a person next requests, approves or reclassifies it. An executed change keeps the class it ran under. A request is never stuck on its runbook: when the platform can no longer compile its steps without it — the runbook was deleted or disabled and its steps need it (an EC2 patch's isolation and patch steps run only inside a runbook), whatever the class — the release dialog shows Runbook no longer backs it — run it by hand with the runbook's steps in order: each check, the backup as its CLI command, each change as the command you run with your own access, each validate criterion and the rollback. Run them, then record what you did (on an incident, mark it resolved). A demoted or uncertified runbook still expands its steps: the request is a normal change the platform runs once a person releases it. A planned patch run whose runbook was deleted or disabled reads the same.

A route run from the incident page records standard with source runbook_route only when the run stays inside the route's declared scope (a GitOps route editing the file it declares, any other route running its own configured call); otherwise the row carries no class. The class only ever raises the release tier: risk_tier = max(intrinsic tier, class floor).

Standard by default

Guardrails offers two policies for change_class_policy:

Policy Wording on Guardrails
derived (unset) Emergency for P1/critical, standard when a pre-approved runbook fix, otherwise normal (people may raise a request, never lower it).
standard_default Every request starts standard; people raise it to normal or emergency, and a class someone set on an earlier request with the same operations is inherited.

The pre-approved operation list (aiops_preapproved_operations) is validated against the typed operation vocabulary (the cloud and Kubernetes operations plus the repository edit); whoever may edit routes cannot make a fix standard alone, because the owner's list on Guardrails must also name every operation.

Reclassifying

POST …/changes/{id}/class with {change_class, note} (incidents.act, note at least 5 characters):

Rule Effect
Allowed while status is planned, pending_approval or approved and the row carries a class Otherwise 409
Only a raise: normal → emergency, or a standard no runbook backs (the "Standard by default" policy, an inherited or a skill-rule class) → normal / emergency Any lowering is a 409 A person may only raise a change class (normal → emergency) …
A certified runbook route's standard (change_class_source = runbook_route) 409 Standard because the certified runbook … covers this fix. To make it normal, demote or disable that runbook
A runbook withdrawn since the draft The drop to the class without it is recorded first (change.class_dropped), then the raise is judged
A route run's record (change_class_source runbook_route / runbook_route_auto without proposed_from_wrapup) Refused: its class records what ran
The new class is a new approval basis approved_by cleared; planned stays planned, anything else goes back to pending_approval
meta.release_class dropped, change_class_source = reclassified, the derived class kept once in change_class_auto, the override appended to class_overrides[] with the source it replaced The window bypass and the review follow the new class
Raising a submitted request to emergency Its review is owed from now (change.pir_scheduled, when aiops_pir_at_submission is on)
Audit change.reclassified with from, to, tier_from, tier_to, approvals_required

Validation plan

Every change request an analysis drafts carries the list L6 checks, fixed at the draft (meta.validation_plan) and bound into the approval digest by the review (execution_spec.validation_plan) with the expected blast radius from the impact data (expected_blast_radius: the intended resources and the lost facts, never the affected list, so a harvest cannot stale an approval). At most 10 items, each {id, target, read, expected, group, direction, hops}:

Group Items
primary Each changed resource (a typed step's target) with the read that observes it and what it must show, then the plan's declared criterion with its read-only commands. An isolation the same change restores (aws.ec2.isolate followed by aws.ec2.restore_sgs on the instance) is a phase, not an end state: only the restore is listed
neighbour Every one-hop neighbour of the changed service on the dependency map, both ways: upstream = it calls the service, downstream = the service calls it; labelled with the edge's origin

The post-fix recheck runs exactly that list: each changed resource whose executed step compiled a read is read first, by code, on the step's own connection (no sooner than 30 s after the write) — a start or reboot by its power state, the groups an isolation recorded by every network interface listing them again (an isolation left in place: only the isolation group), a patch by its own command's status (ssm:GetCommandInvocation) and Patch Manager's missing and failed counts (ssm:DescribeInstancePatchStates), a Lambda runtime upgrade by its function's configuration (lambda:GetFunctionConfiguration: the runtime the step sent, LastUpdateStatus Successful, State Active or Inactive) and by its alias (lambda:GetAlias: the version the run published), and a read that cannot answer is not observed, never pass; the verify turn is told only the listed items, with no web research; a row it adds for anything else is dropped; every item ends with a row (item = its id), observed or not; and a listed resource the platform read as failing decides the verdict (still_present). The verdict rests on the listed rows only: a still_present the turn based on a row it was not asked for reads uncertain, and so does a cleared turn while a listed item — a neighbour included — reads fail. A failing neighbour never makes the change still_present on its own. Once every alert of the incident cleared at its source after the write, the platform reads the list without a verify turn — when the alert source's clear arrives, and on each scheduled check after it — and lands cleared at $0 when every listed changed resource reads pass and no neighbour probe fails; anything else leaves the verdict to the turn (switch verify_typed_check). A standard change runs it too. A change drafted before the validation plan existed carries no list and is verified as before.

Pre-change backups

With aiops_backup_before_change on (the default), the review puts a backup step before every reboot-type step on a stateful target — aws.ec2.reboot gets aws.ec2.create_image (an AMI with NoReboot=true), azure.vm.restart gets azure.compute.disk_snapshot (a snapshot of the VM's OS disk) — once per target, through that step's own write connection. aws.ec2.create_snapshot (an EBS volume) is the same kind of step for a runbook to declare. A step runbook's own backup step is compiled the same way at its place in the runbook, bound to the write connection of the change step after it, even with the switch off; a target it already backs up gets no second backup. Backup operations are compiled by code and never offered to the analysis. A backup needs the native API connection: over a CLI connection the review refuses the plan and says why.

Stage What happens
Release The backup step is reviewed and approved with the change; its tags are filled in when it runs: aiops:retain-until (today + aiops_backup_retention_days) and aiops:change (the change id)
Execution The create call, then read-only reads until the image or snapshot is available (at most 30 minutes). Not available, failed or refused: the change stops before anything is written
Record meta.backups[] {step, operation, kind, source, backup_id, state, retain_until}, the step's last-known-good capture (method = backup) and the rollback section (rollback.backups, rollback.restore)
Restore One AWS image backup makes aws.ec2.restore_root_volume (CreateReplaceRootVolumeTask, the replaced volume kept) the rollback a person releases (generated_by = backup_restore); the sweep never runs it. An EBS or Azure disk snapshot restores through the operator lines shown (a new volume or disk, then the swap with the VM stopped)

The platform never deletes a backup, expired or not: removing old images and snapshots is the workspace's own lifecycle rule. The write role needs ec2:CreateImage, ec2:CreateSnapshot, ec2:CreateTags, ec2:CreateReplaceRootVolumeTask, ec2:DescribeImages, ec2:DescribeSnapshots, ec2:DescribeReplaceRootVolumeTasks on AWS and Microsoft.Compute/disks/read, Microsoft.Compute/snapshots/read, Microsoft.Compute/snapshots/write on Azure (re-run the setup to add them). The restore reads its image or snapshot only when it carries the aiops:change tag, a backup the platform made: an AMI that exists is authorized by its own tags, never by the request tag the restore puts on its task.

Risk tiers

The tier stamped on a change is tiers.classify over the execution channel, the incident's production labels and its trusted blast radius, raised by the route's tier_override and by the change class; the policy per tier (approvers, permission, on-screen definition) is the table in Approval policy and change tiers. What this page adds: where each tier is computed.

Change Tier computed by
Proposed change request (wrap-up) classify_planned at the mint from the plan's inferred channel; planned_execution.review recomputes the release tier as the maximum of the intrinsic tier, the class floor and every compiled step's own tier
Route run from the incident tiers.classify(route.mode, labels, impacted, tier_override) at the Remediate click or the automatic lane
Declared change (POST …/changes with a plan) classify_planned from the plan
Observed change None (risk_tier empty)

Change and freeze windows

Both windows share one shape and one matcher; they read opposite policies off the same answer.

Part Rule
Shape {"days": ["mon", "tue", …], "hours": "HH:MM-HH:MM"}, UTC; day names are matched on their first three letters
Days only The whole of each listed day
Hours only Every day, inside the range
Both Both must match
Overnight range ("22:00-06:00") Wraps midnight
Empty / missing A change window is always open; a freeze window never flags
Malformed hours A change window fails open (a typo must never lock remediation out — the approval is still the gate); a freeze window errs toward flagging
Window Lives on Checked by Not checked by
Change window params.change_window of a route; settings['change_windows'] first matching service glob, then settings['change_window'] (or legacy aiops_change_window) for prepared plans — compliance control CHG-03 asks every live-infra route at L2/L3 to declare one The human release of a legacy route at L2/L3 (403, audited change.release_refused); authorize() for every api / cli / mcp / network change at L2/L3 — at the request, the dispatch re-check and each step; the direct API lane before it releases A pull request (inert until merged, so the auto path may open it any time; the human release of a gitops_pr change is gated only at the incident endpoint); the rollback sweep
One-time exception meta.window_exception on one change, bound to action_digest; requested/decided on the change routes The active UTC interval for that change only, with the same tier/class/quorum and emergency policy Other changes, release votes and class/tier derivation
Freeze window settings['change_freeze'] record_external for every observed change Platform changes

The emergency bypass: a change whose release class is emergency passes a closed change window once its full quorum is collected (L3 = two distinct people); the first pass stamps meta.window_bypassed and audits change.window_bypassed once, so the re-checks at dispatch and at each step are idempotent. A route run's row is never waved through: it carries no class, or a standard nobody can reclassify.

Last-known-good records

Before a platform write the state it is about to change is captured and stored as an append-only artifact (kind: lkg); the change's lkg field says what was captured and how. The incident page's "Last-known-good record" card (Read an incident and its analysis) reads the same versions.

Capture methods

lkg.method What was captured Restorable
gitops_file The file body the GitOps provider read before applying the edit (with path, repo, sha, sha256 of the stored body) Yes — the full-file restore PR
gitops_derived The pre-image derived for a step of a prepared repository plan Yes, unless the reviewed plan carries private values (then the capture is withheld with an honest receipt)
gitops_create The file did not exist: prestate_status: absent, completeness: complete, no artifact No content to restore (revert = delete, which the platform does not perform)
route_snapshot The output of the route's declared read-only params.snapshot call As a reference; the compiled inverse uses it for posture steps
step_prestate A compiled step's pre-state read (one entry per step in lkg.captures[]) Feeds the compiled inverse
none Nothing capturable; note says why (a 404 on the exact target, a refused snapshot call, a redacted capture, a read that failed) No

Fields on a capture: artifact_id, path, repo, sha, captured_at, prestate_status (present / absent / unknown), source_observed_at, source_version, completeness (complete / partial / unknown), health ({status: unverified} until a verify reads it), sha256, restorable: false when the stored evidence is not byte-exact, and evidence_artifact_id for a redacted receipt. Compliance control CHG-02 counts a change as covered only with a real method (gitops_file, gitops_create, route_snapshot, or any captures[] entry other than none).

Version sources

Every ledger row yields resource versions (lkg.versions_of); the source says where the before-state came from and the record card labels it.

source Label Before-state Which rows
platform platform pre-read The capture above Platform changes
aws_config AWS Config The configuration item AWS Config recorded before the write (detail.before_state, before_captured_at, before_version); the after-state is the write's diff applied to it Harvested CloudTrail writes of a connection with config_history: true — detail.before_source = "aws-config"
ledger earlier recorded change For an RDS parameter-group write: the values earlier recorded writes set (only the parameters this write changed; before_unknown names the rest; a redacted value is unknown, never set back) Harvested ModifyDBParameterGroup / ModifyDBClusterParameterGroup — detail.before_source = "ledger"
change_analysis Azure Change Analysis The previousValue of every property in the Resource Graph change diff; a truncated or redacted diff yields none; all-null = the resource was created Harvested Azure activity writes
git git The parent commit (before_sha) of a harvested push Watched-repository pushes
reported webhook report None — a sender's claim is never a restore source Webhook-reported pushes, cloud writes and application settings

A harvested AWS write without Config history reads "external AWS write — no before-state captured (AWS Config history off for this connection)"; one where Config answered but every capture it returned was after the write says so too.

The before-state rule

settings['aiops_require_before_state']: true — a write whose before-state cannot be captured never runs on the platform: the review refuses it up front (manual_only, with the operator-run steps), and a read that fails at execution stops before the write (audit change.prestate_blocked). On by default since 0.1.163 (null follows the platform default AIOPS_REQUIRE_BEFORE_STATE); false lets the write proceed with an honest none. A pull request is exempt: the repository's base commit is its before-state.

Rollback paths

rollback.kind and rollback.generated_by say what the platform holds. A rollback is never auto-executed unless the sweep's matrix below says execute; a human releases one with POST …/changes/{id}/rollback (approvals.decide; an L3 rollback needs a second distinct approver; the original route must still exist, be enabled and keep its mode).

kind generated_by What it is
gitops_restore code The reversed find/replace of the applied edit (edit) and the full-file restore from the LKG artifact (artifact_id) — a restore pull request, inert until merged
script operator The route's declared params.rollback command template
script compiled_inverse One posture step with a captured pre-image: the exact authorize / put that re-creates what the step removed (operation, params); human-released on the change page, the same read re-runs afterwards
manual code No executable rollback; note says why (a created file, no pre-image, a multi-step plan, a recovery operation whose inverse recreates the outage); commands lists the operator lines, last step first
manual lkg_draft, wrapup, operator_review_required A drafted plan or guidance for a person — never run by the platform

An agent may draft a rollback for a manual change (the plan runner); the draft is shown, never executed. Every non-manual rollback also gets a kind: rollback artifact with the plan rendered for people (artifact_id_doc).

The automatic rollback sweep

Scheduler tick over platform changes with status failed updated in the last aiops_rollback_sweep_window_h hours (24), 50 per tick, each decided once (audit markers change.auto_rollback, change.rollback_escalated, change.rollback_skipped). The decision is pure:

Kind How it failed Decision
any mode: external escalate — an operator reviews and performs it
any computer-assist mode escalate
any execution still dispatching, or its outcome uncertain wait — reconcile the stopped execution first
any a rollback already reserved, attempted or reconciled skip — never replayed
gitops_restore execution failed before a PR existed skip — nothing went live
any the provider refused the request before acting (a 4xx-before-write) skip
any a prepared plan stopped at its backup: every step receipt is a backup, no write step ran, and no person reconciled the write as executed skip — nothing was applied
any live change verify_verdict: uncertain wait for a real verdict
gitops_restore no failed verification skip
gitops_restore verification still_present, tier L3 escalate — two people release an L3
gitops_restore verification still_present, tier ≤ L2 execute — the restore PR opens
script / compiled_inverse aiops_auto_rollback_cloud is L1 or L2, the tier is within it, verification still_present and meta.validation.status = failed execute — the captured before-state is restored
script / compiled_inverse otherwise escalate — human-released on the Changes page
script / operator the forward action was a recovery operation escalate
script / operator aiops_auto_rollback off escalate
script / operator tier L3 escalate
script / operator on, tier ≤ L2 execute
manual / missing — escalate — a human performs it
any the change belongs to an unauthorized-change incident escalate — a person rolls it back

Escalation pushes the rollback notification event. The sweep deliberately re-checks no change window. After a rollback of a run executed through a pre-approved route, settings['aiops_demote_on_rollback']: true takes that route's pre-approval away at the first rollback (Needs you: route_demoted; audit route.demoted).

Harvest sources

The scheduled harvest reads every eligible connection's write events since its last marker minus a 20-minute overlap (the ledger dedupes on the event id, and a re-seen event carrying a diff the first sighting lacked enriches its row). Interval: aiops_change_harvest_interval_s = 900 s platform default; settings['aiops_change_harvest_interval_s'] overrides it, 0 or less disables the scheduled harvest for the workspace. Per-connection opt-out: harvest_changes: false. A write-role connection is never harvested.

Source Connection What is read Notes
AWS CloudTrail aws, read role Completed write events, per region: every region the connection declares (scope.regions, else region) plus us-east-1 always (IAM, STS, CloudFront, Route 53 and the other global services write their trail there) Noise (session plumbing, and every STS call: temporary credentials, never a resource change), service-identity (AWSService), read and failed events are dropped and counted; a denied write is kept as a denied attempt — unauthorized access, never an unauthorized change (denied); invokedBy is tagged actor_kind: service
AWS Config aws with config_history: true The configuration item before and after each harvested write (before_source: aws-config) At most 50 Config calls per connection per tick, 4 history pages (28 days) back
EKS control-plane audit log aws with k8s_audit: true kube-apiserver-audit-* streams in CloudWatch Logs (/aws/eks/<cluster>/cluster), one Logs Insights query per cluster per tick Completed write verbs (never a dryRun=All) by non-system: principals, and by the service accounts of the CI/CD namespaces in k8s_ci_namespaces (CI/CD service accounts); a 401/403 is a denied attempt. EKS's own service-linked role (AWSServiceRoleForAmazonEKS, the EKS Auto Mode controllers, matched on the identity the authenticator attaches as well as the user name) and EKS's reserved eks: users are the AWS service itself: dropped and counted as service, like CloudTrail's AWSService rows. Access reviews (kubectl auth whoami, can-i) are never a change
Azure activity log azure, read role Write operations per subscription, joined with the Resource Graph change diff of the same resource within 10 minutes Read operations are dropped; a deployment validate / write counts only as a denied attempt (a Reader's portal create dies there, before any resource write); the diff gives the before-state
Watched repositories github, gitea, gitlab, azure-devops with repos Pushes and merges of up to 25 repositories per connection, paced by the provider's poll header A repository connection with no repos is a credential (GitOps PRs), not a feed
Kubernetes audit webhook POST /webhook/kubernetes-audit/<slug>/<token>/<cluster> with that cluster's audit token (POST /api/aiops/{workspace}/k8s-audit-token/<cluster>), never the webhook token The API server's audit EventList (self-managed / on-prem clusters) Treated as the platform's own audit (trusted_audit); the same people and CI/CD service-account rules as the EKS log
Change webhook POST /webhook/change/<slug>/<token> {source?, events: [{kind, service?, repo?, ref?, sha?, id?, author?, title?, url?, at?, detail?}]} with kind ∈ push, pr_merged, deploy, sync, config Nothing is polled; a reported before-state is never a restore source
Source webhooks POST /webhook/<source>/<slug>/<token> for azure-devops (git.push, git.pullrequest.merged), argocd (sync, drift), github / gitea, gitlab, servicenow, jira The sender's own payload, mapped to the event kinds above A payload that yields no change event falls through to the alert adapter of the same source

CI/CD service accounts on Kubernetes

A pipeline that applies manifests with its own service account releases a change the same way a person running kubectl does, so its writes are recorded with actor_kind: service and the namespace as ci_namespace. Which namespaces count is the workspace setting k8s_ci_namespaces; the platform default is flux-system, jenkins, gitlab-runner and tekton (a Tekton pipeline often runs as a service account in its own pipeline namespace: add that namespace). argocd cannot be listed, because Argo CD syncs arrive on /webhook/change/<slug> and would be recorded twice, and kube-system, kube-public and kube-node-lease never can. Every other system: identity (nodes, controllers, other service accounts) stays plumbing.

What a pipeline writes that is not its change is left out: the pods and runs it spawns (pods, taskruns, pipelineruns, customruns, runs), status writes, objects of its own controller (*.fluxcd.io, *.tekton.dev) and the per-job objects GitLab Runner names runner-<token>-project-<id>-concurrent-<n>… (build pods, registry secrets, services). A server-side dry run (dryRun=All — Flux compares every object it manages this way on every reconcile) is never a change, for a person or a pipeline. On EKS the query leaves all of these out, so they are not counted. Per pull, an object the same account wrote many times is one row (the newest write). At most 50 objects are recorded per cluster, service account and clock hour (UTC), counted after the ledger's dedupe — what an earlier, overlapping pull already recorded in that hour counts first, in time order — so overlapping pulls agree on which 50; the rest are counted as noise, and the pull that reaches the cap writes the marker note once. A denied attempt (401/403) is never left out as one of the objects above, folded or counted toward the cap: it is recorded as a denied attempt and reaches SecOps like a person's (a pipeline refused creating pods in kube-system included). The audit webhook applies the same rules and has no marker: what it folds goes to the platform log. People and pipelines share the 1,000 audit rows one pull reads per cluster.

A pipeline's change is checked against freezes and references like any other; to let it through without a ticket, add system:serviceaccount:<namespace>:* to change_authorized_principals.

Caps per connection per tick: 500 rows recorded (1,500 raw read), request parameters and diffs scrubbed then cut at 2,048 characters; values written to Parameter Store, Secrets Manager, AppConfig or a Lambda / ECS environment are stored as [not stored] (which key changed is kept). The manual pull (POST …/changes/harvest, pillars.manage, "last N minutes") ignores the interval and lands under its own marker so it never blinds the next scheduled tick.

Service resolution for an observed change: the event's own service → settings['change_service_map'] ({repo_glob: service}) → unmapped (recorded, listed under an empty service). settings['change_resource_map'] ({resource_glob: service | [services]}, at most 200 globs, 10 services each) only adds linked services; editing it relinks the rows of the last 48 hours; a cloud write to an EC2 instance, a volume, an SQS queue or an SNS topic also links itself to a service named after the resource.

Principal classes and unauthorized changes

For every harvested cloud write that is not the echo of a platform receipt, meta.principal says who made it:

principal.kind Meaning
platform The platform's own credential: an AWS role or access key it holds, or its Azure application. receipt = time (a typed platform step on the same resource within 10 minutes), route (a route change naming the resource or its service), action (an approved action inside an analysis, a route snapshot, a source-side suppression), or none
outside A person or workload the platform does not hold a credential for
unknown No identity in the event

A row is flagged authorized: false when one of these holds. The last two are unauthorized changes (audit change.unauthorized_detected, the Unauthorized chip); a denied call is unauthorized access, not a change (audit change.denied_attempt, the Denied attempts chip), and the change statistics count it apart: never in the change total, a source, a service or the unauthorized changes:

Rule Note on the row
The cloud denied the write (denied) "unauthorized access attempt: denied by the cloud provider (<code>) — attempted, never applied, so not an unauthorized change"
settings['change_freeze'] matches and no platform change for the service is in flight (approved … verifying, not external). A write an audit log captured (CloudTrail, the Azure activity log, the Kubernetes API server) is judged at the time the log recorded it, so a write made during the freeze is flagged when a later pull reads it, and one made before the freeze is not flagged by a pull during it. Any other change (a push, a sync, your own feed) is judged at the time it arrived: a commit dated before the freeze never clears a push received during it, and one dated inside it never flags a push received after it "external change during a declared freeze window with no in-flight platform change for this service"
settings['aiops_change_principal_check']: true and the principal is platform with receipt: none Made with the platform's own cloud credential, but no platform change explains it
settings['aiops_unauthorized_change_incidents']: true and nothing accounts for an applied write — see Unauthorized changes and denied access "no reference found (no ticket, approval or signed change request)"

A platform write seen back in the audit log within 10 minutes becomes the receipt of its change (change.confirmed_by_audit_log), never a second row. Only the platform's own harvest may fold a write this way; a webhook sender cannot stamp "confirmed by the cloud audit log" on a change.

Unauthorized changes and denied access

The method per change source, in prose, with a sandbox demo: How unauthorized changes are detected.

Off by default. aiops_unauthorized_change_incidents (platform default AIOPS_UNAUTHORIZED_CHANGE_INCIDENTS, off; the workspace's own true/false on Guardrails → Unmanaged changes → Open an incident for every change with no reference) makes every applied write the audit log captures — AWS CloudTrail, the Azure activity log, the EKS audit log or the Kubernetes audit webhook — need a reference. A busy account records thousands of writes a day made outside the platform: fill change_authorized_principals with your CI/CD roles before turning it on. Denied attempts are never judged by this rule; the existing noise, service-identity, read and failed-event filters still apply first.

A write has a reference when, checked in this order:

Reference meta.reference.kind Rule
The platform made it platform The platform's own credential with a receipt (time, route, approval, suppression)
An automation principal allowlist The AWS role, user, Azure caller or Kubernetes user matches a glob of settings['change_authorized_principals'] (case-insensitive; at most 100 globs, each naming at least 3 letters or digits besides glob characters and arn:<partition>:)
An approved ITSM change ticket itsm A ServiceNow or Jira change ticket in the ledger whose state is one of the approved values, whose CI names a service the write is linked to or the resource itself, and whose planned window covers the event time. A ticket without a planned start and end never matches. Only a ticket your ServiceNow or Jira webhook posted with the workspace's ITSM webhook token counts (see the note below the field table): one posted with the shared webhook token, or sent through your own change feed, is recorded and never covers a write.
A signed change request change_request A platform change request a person approved (approved or later) whose typed steps, reviewed action or operator commands name the resource (never only its service), opened before the write and updated within 24 hours of it. One the platform executed itself covers writes only until its execution ended (a minute of clock skew allowed): a later write on the resource is not its own

With none, the row is flagged authorized: false with "no reference found (no ticket, approval or signed change request)" (audit change.unauthorized_detected).

ITSM ticket fields (settings['itsm_change_match'], each optional; a ticket's re-send refreshes the fields on its row, so a ticket approved after it was raised counts from then on):

Field ServiceNow default Jira default
state_field approval status
approved_values ["approved"] ["approved", "awaiting implementation", "implementing", "scheduled"]
ci_field cmdb_ci customfield_service
start_field, end_field start_date, end_date none — set your instance's planned start and end custom field ids

Times without a zone are read as UTC.

The ITSM webhook token. The shared webhook token is held by every alert and change integration, so it cannot vouch for an approval. POST /api/aiops/{workspace}/itsm-webhook-token (members.manage, MCP mint_itsm_webhook_token; audit tenant.itsm_webhook_token) returns a separate token once and stores only its hash; minting again invalidates the previous one. A personal access token needs the admin scope for this call. Send it from the ServiceNow or Jira webhook (Authorization: Bearer <token> on /webhook/servicenow/<workspace-slug> or /webhook/jira/<workspace-slug>, which also accept it for their alerts). A ticket and its re-sends refresh the ticket fields only when they carry this token. Tickets recorded before the workspace had one are not references: the next re-send with the token makes them count.

What an unauthorized change opens:

Fact Value
Grouping One incident per action: the same principal and the same account (AWS account, Azure subscription, Kubernetes cluster) within 10 minutes of the action's first write. A later pull joins the open incident of its action.
Alerts One alert row per resource (source unauthorized-change); a second write to the same resource adds its change id to that row
Incident Pillar change, correlation key unauthorized_change=<account>/<principal>@<epoch>, the incident's change_refs list every change
Priority From the touched resources' criticality (criticality_map): mission-critical = P1, high = P2, otherwise P3
Analysis None started — the receipt incident.not_actioned says why; a person may still use Analyse
Ticket Filed through the first enabled on-open ticket route whose selector matches, whatever pillars a preset route covers. settings['unauthorized_change_ticket'] = {"assignment_group": "<group>"} names the group on the ticket and, on ServiceNow, sets the incident's assignment group (looked up by name; the ticket is filed without one when the name is not exactly one group). No one is assigned. Without a ticket system the incident still opens.
Rollback A revert drafted per change when the incident opens (at most 20; the rest from Probable cause): typed from the recorded before-state where it exists (a security group — a removed ingress rule re-created with its description, an added one revoked by the rule id CloudTrail's response named — an NSG, an RDS parameter group and the other inverses of the last-known-good draft), otherwise one manual step naming why. Status planned — it waits for an approver. The platform drafts the revert itself; with Let the change management agent draft change requests on, the agent then writes the request's narrative around it, as for any change request.
Never automatic No pre-approved route, direct API fix or rollback sweep acts on it, whatever runbook is certified (skip reason unauthorized_change; the sweep escalates)

The person's two answers, on the incident's Unauthorized change card (approvals.decide):

Denied attempts (unauthorized access): with aiops_denied_access_to_secops on (platform default AIOPS_DENIED_ACCESS_TO_SECOPS, on) and the SecOps agent enabled, every denied attempt opens or joins one SecOps incident per principal, account and clock hour — one alert row per attempt (source denied-access), correlation key denied_access=<account>/<principal>@<hour>, P3, no analysis started, no rollback (nothing changed). Its Denied access attempts card lists the refused calls.

On a workspace with a tag scope (the workspace scope, or a connection's finding_tag_scope), an AWS or Azure attempt opens a report only when it was made as the identity of one of the workspace's connections, or its target is an estate resource inside the scope: one account shared by several teams, another team's role refused on another team's resource is theirs. The rest stay on the ledger as denied attempts and are counted on the harvest's report (denied_out_of_scope). Kubernetes audit attempts come from the workspace's own cluster and always count.

What is never captured

The incident card, change_lookup and the last-change-check skill say this, so an empty list reads as "nothing in what we can see":

Post-implementation review

Fact Value
When it opens An emergency change's write lands: a direct mode at close of execution, a pull request at merge; or at submission when settings['aiops_pir_at_submission']: true
Owner The releasing approver
Due aiops_pir_due_h hours after opening (72); 0 turns reviews off
Where it waits Needs you, source pir (overdue past the due date)
Closing POST …/changes/{id}/pir/close with a note of at least 10 characters (approvals.decide); outcome implemented, not_implemented (refused, or the write failed before landing) or pending
Audit change.pir_opened, change.pir_scheduled, change.pir_withdrawn, change.pir_closed

Audit actions

Every row targets the change id (the incident Timeline and /audit show the same rows with the labels below).

Action Label Emitted when
change.open Change request opened A request, route run or declared change is minted
change.proposed Change request drafted The wrap-up mints the proposed request
change.plan Change plan drafted The change agent drafts a plan for a declared change
change.cr_drafted Change request document drafted The change management agent's draft of the change request document landed (ok, plan = Phase 2 plan landed, cost_usd)
change.cr_draft_requested Change request document draft requested A person asked the change management agent to draft the document again
change.approval_requested Change approval requested The operator's Request approval
change.approved Change approved The vote that completed the quorum
change.approval_lapsed Approval no longer counts A click on the change found a vote whose approver may no longer release the tier (role changed, member removed, support access ended): the vote is dropped, listed among the approvals as lapsed, and an approved change short of its quorum goes back to pending_approval (payload: lapsed people, tier, approvals, required, was and status)
approval.released Approval recorded A vote short of the quorum
change.pending Parked — more approvals needed A release parked at pending_approval
change.rejected Change rejected An approver refused, or a structural check failed
change.closed_without_verdict Closed without a verdict An approver closed a released change that went 24 hours without a verdict — none, or uncertain only (payload: the reason and since when it waited)
change.release_refused Change release refused Outside the window, missing permission, or the re-check at dispatch refused the release (detail = refused at dispatch: … with the reason; nothing was executed)
change.reclassified Change reclassified A person raised the class
change.class_dropped Standard class dropped — runbook no longer backs it The runbook a standard request rested on no longer holds before release; the heading says why (payload cause: certification withdrawn by a person, runbook demoted after a rollback / a failed validation / a fix that did not hold, runbook disabled, deleted, no longer certified, changed since the request was drafted) and the class without it was recorded
change.class_restored Change class restored — the runbook was certified again A late outside write gave a demoted runbook its certification back, and a request nobody has requested yet, classed normal while it was demoted, is standard again (payload from, to, tier_from, tier_to, reason; see Runbook library)
change.window_bypassed Change window bypassed — emergency An emergency released through a closed window
change.prestate_blocked Write refused — no before-state captured The before-state rule stopped a write
change.dispatching Approved change sent to run The write was reserved
change.executed Change executed The write returned; Change execution failed when it failed (ok: false); Change outcome unknown when no receipt came back (uncertain: true, the change stays dispatching until a person reconciles it)
change.execution_reconciled Change outcome recorded by a person A stopped execution was reconciled
change.external_execution_reported Operator reported external execution Computer-assist report
change.operator_handoff Operator handoff prepared A plan was handed to an operator
change.pr_merged, change.pr_closed, remediation.pr_merged Pull request merged / closed The PR poll saw the change
change.application_observed, change.application_reported Change seen applied / Deployment evidence recorded An Argo CD sync or a person tied the deployment to the change
change.post_state_captured Post-change state captured The after-state read landed
change.verify_requested, change.verified Verification requested / Change verified A verify was asked for / its verdict landed
change.rollback, change.rollback_dispatching, change.rollback_merged, change.rollback_verified, change.rollback_cancelled Rollback … The human rollback path
change.auto_rollback, change.rollback_escalated, change.rollback_skipped — The sweep's one decision per failed change
change.pir_opened, change.pir_scheduled, change.pir_withdrawn, change.pir_closed Post-implementation review … The review lifecycle
change.recorded — An observed change landed
change.unauthorized_detected — An observed change was flagged unauthorized
change.denied_attempt Denied access attempt recorded The cloud refused a call: unauthorized access, never an applied change
change.kept Change kept as legitimate An approver kept an unauthorized change (target = the change)
incident.change_kept Unauthorized change kept — incident closed The same decision on the incident (target = the incident)
change.confirmed_by_audit_log — A platform write was seen back in the audit log
change.harvested, change.harvested_manual — The scheduled / manual harvest markers (target = the connection)
change.relinked — A resource-map edit reached recorded rows
change.compliance_flagged, change.evaluated, change.reverts, change.undone_by_external — Change-triggered compliance (see the Compliance reference)
change.lkg_draft, lkg.anchor — The revert draft / the last-known-good record anchor on an incident
route.match_skipped Pre-approved route matched — not run A pre-approved route matched but did not run (one row per route and reason)
route.demoted — A rollback took a route's pre-approval away

Settings

Workspace settings that change how the ledger behaves (Guardrails unless noted). Platform defaults are the control plane's environment.

Setting Default Effect
change_class_policy derived standard_default = every request starts standard
aiops_preapproved_operations [] Typed operations a standard change may contain
aiops_runbook_standard_change on A certified remediate-… route's declared operations record a standard change even at P1
change_window / aiops_change_window none Release window for prepared plans
change_freeze none Freeze window for observed changes
aiops_require_before_state on No platform write without a captured before-state
aiops_auto_rollback off The sweep executes an operator-declared rollback script (≤ L2)
aiops_auto_rollback_cloud unset L1 or L2: the sweep restores a captured before-state after a failed metric window
aiops_demote_on_rollback off The first rollback of a pre-approved route's run drops its pre-approval
aiops_demote_on_deviation on A certified runbook whose run fails its validation, or whose fix does not hold, loses its certification (audit route.demoted_deviation) — unless the platform's own cloud audit harvest recorded an outside write on the same resource between the fix and the recurrence: then it keeps it (audit route.deviation_explained); a write harvested after the recurrence opened gives back the certification that recurrence took (route.deviation_explained with restored: true, and lkg_record.outside_explained on the record)
aiops_pir_at_submission on An emergency request's review is owed from submission
aiops_backup_before_change on A reboot-type step on an EC2 instance or an Azure VM is preceded by a backup (AMI / OS-disk snapshot); see Pre-change backups
aiops_backup_retention_days 7 The value of a new backup's aiops:retain-until tag, in days (1–365); nothing deletes a backup
aiops_pir_due_h (platform) 72 Review due time; 0 = reviews off
aiops_rollback_sweep_window_h (platform) 24 How far back the sweep looks
aiops_change_harvest_interval_s 900 (platform) Scheduled harvest interval; ≤ 0 off
aiops_change_principal_check on A platform-credential write with no receipt is flagged unauthorized
aiops_unauthorized_change_incidents off An applied write with no reference is flagged and opens an incident per action
aiops_denied_access_to_secops on A denied attempt opens a SecOps incident per principal, account and hour (SecOps agent enabled)
change_authorized_principals, itsm_change_match, unauthorized_change_ticket [], defaults above, {} The automation allowlist, the ITSM ticket fields, the ticket's group
change_service_map, change_resource_map {} Service resolution and linking of observed changes
aiops_rollback_first on The incident's change request leads with the pinned change's rollback
aiops_change_agent_cr on The change management agent drafts the narrative sections of the change request document
aiops_change_agent_owns_plan off Phase 2: the analysis drafts no plan; the change management agent drafts it
cr_template {} organization and logo_text of the change request document
execution_mode standard computer_assist = no platform write

API summary

Method and path Permission Purpose
GET …/changes, GET …/changes/{id}, GET …/changes/stats, GET …/changes/harvest, GET …/changes/watched-repos incidents.view List, detail, 30-day statistics, harvest reports, watched repositories
POST …/changes/stats incidents.view The statistics saved as a markdown report artifact (Export report); a write operation, so a read-scope token cannot call it
POST …/changes incidents.act Declare a change (title, summary, service, plan, or incident_id + investigation_id to copy a recorded plan)
POST …/changes/harvest pillars.manage Pull now — last N minutes
POST …/changes/{id}/plan incidents.act Ask the change agent for a plan
GET …/changes/{id}/document incidents.view The change request document: format=json (sections + Markdown), markdown or docx
POST …/changes/{id}/document/draft incidents.act Ask the change management agent to draft the document again
POST …/changes/{id}/execution-preview incidents.act The apply preview (always runs; refusals carry every write connection and its status)
POST …/changes/{id}/class incidents.act Reclassify
POST …/changes/{id}/approve approvals.decide Vote / release
POST …/changes/{id}/execute approvals.decide Release and run the reviewed action (review_digest)
POST …/changes/{id}/reconcile-execution incidents.act or approvals.decide Record the outcome of a stopped execution
POST …/changes/{id}/application incidents.act Record deployment evidence (merge_identity, evidence_ref, note)
POST …/changes/{id}/verify, …/rollback-verify incidents.act Ask for verification / re-read after a rollback
POST …/changes/{id}/external-executions incidents.act or approvals.decide Report work done outside the platform (computer-assist)
POST …/changes/{id}/rollback approvals.decide Release the stored rollback
POST …/changes/{id}/pir/close approvals.decide Close the post-implementation review
POST /webhook/change/<slug>/<token> webhook token Report changes
POST …/incidents/{id}/keep-change approvals.decide Keep an unauthorized change as legitimate (note, 10–2000 characters) and close its incident

Next steps