Autonomous Remediation Authority Standard
This is the contract every unattended actuator in pitlab conforms to: what an agent or automation may change in production without a human in the loop, and where that authority hard-stops. It exists because pitlab now actuates fixes autonomously in more than one place — autoheal restarts unhealthy containers, vulnscan edits and deploys production to clear CVEs, and the test-plan gate auto-reverts a regressing deploy — and each was re-deriving its own authority boundary, blast-radius cap, verify gate, and masking guard from scratch. Per Prime Directive 9, a pattern solved three times is a standard written once. The rationale and the decision to generalise live in ADR-0112; this is the enforceable shape. It is the autonomy companion to the Service Test Plan Standard (which supplies the verify gate) and the Alerting & Severity Standard (which supplies the masking-guard alerts). Actuators come in two authority-provenance tiers — standing (a permanent unattended grant: the original subjects) and delegated (a per-invocation human grant scoped to one named unit of work: the /go skill); the tier an actuator declares determines its envelope-and-cap rules, added by ADR-0121 and amended by ADR-0403, which added the circuit-breaker, no-self-authored-spec and independent-re-assertion clauses that bind a delegated actuator once it fans its authority out to workers.
An autonomous actuator is any automation that changes production state unattended
Section titled “An autonomous actuator is any automation that changes production state unattended”The standard governs any unattended process that mutates production — restarts a container, edits and deploys code, reverts a commit, upgrades a package, changes config — without a human approving that specific action at that moment. A read-only agent (a scan that only reports, a dashboard, an alert rule) is not an actuator and is out of scope; the line is does it act on production by itself. Detection without actuation is the pre-autonomy baseline this standard’s subjects were built to close: every one of them added the missing “act” half to a loop that already had the “detect” half.
An actuator declares a bounded authority envelope — in-bounds acted, out-of-bounds escalated
Section titled “An actuator declares a bounded authority envelope — in-bounds acted, out-of-bounds escalated”Every actuator MUST define, as code and in its ADR, an explicit in-bounds set (the exact change classes it may apply fully unattended) and an out-of-bounds set (everything else, which it MUST escalate — never apply). The envelope is a whitelist, not a blacklist: anything not named in-bounds is out-of-bounds by default. vulnscan’s in-bounds is pinned-tag patch/minor bumps, security-floor pins, and targeted OS-package upgrades; its out-of-bounds is major bumps, version migrations, and any fix needing behavioural testing. autoheal’s in-bounds is “restart a container carrying autoheal=true” and nothing else. An actuator that cannot classify an action into the envelope MUST treat it as out-of-bounds.
Authority comes in two provenance tiers — standing (whitelisted) and delegated (human-granted, Epic-scoped)
Section titled “Authority comes in two provenance tiers — standing (whitelisted) and delegated (human-granted, Epic-scoped)”The whitelist rule above is absolute for a standing actuator but not for a delegated one, and the difference is how authority is granted — the dimension the standard was originally silent on because all its first subjects shared one provenance. An actuator MUST declare which tier it is; the tier sets its envelope shape and cap rule:
- Standing autonomy (autoheal, vulnscan, test-plan gate): authority is permanent and unattended — no human confirms scope at run time. Therefore the envelope MUST be a narrow whitelist and a blast-radius cap is mandatory, exactly as above. This is the default tier; assume it unless a delegated grant is explicit.
- Delegated session-scoped autonomy (the
/goskill): authority is granted per invocation by the human, scoped to a single named unit of work (an Epic). Because a human authorises the specific scope at grant time, the envelope MAY be a broad grant bounded by the hard-stop set (a blacklist shape) rather than a narrow whitelist. The human-in-the-loop-at-grant is the compensating control that licenses the wider envelope — it is not an exception to the standard but a second, equally-bounded shape of it.
A delegated actuator that sub-delegates MUST carry a circuit breaker. Scope-binding to one human-named Epic was originally accepted in place of a blast-radius cap (ADR-0121), on the reasoning that a single agent working serially in one visible session is bounded by the human reading the run as it happens. That reasoning does not survive fan-out: when the work is done by disposable sub-agents whose reasoning is discarded and summarised, the human sees verdicts rather than the run. So where a delegated actuator delegates its granted authority onward to workers, scope-binding is necessary but not sufficient, and it MUST additionally halt after K failed-or-blocked units of work and escalate decision-ready. Two clauses bind the breaker:
- K MUST be derived from a measurement of the thing it governs, and the measurement stated — a threshold lifted from another actuator, a vendor default or a textbook is FC-16 (
borrowed-parameter), and produces a cap that looks canonical and cannot work. Where the derivation rests on an incomplete measurement, K is declared provisional and the recalibration point named. - The breaker MUST be enforced by the mechanism, not by the actuator’s diligence — an exit code, a lock, a refusal — because a blast-radius control that depends on an agent remembering to count is not a control. See ADR-0403.
A delegated actuator MUST NOT author the specification it then delivers. Where the unit of work is under-specified, the actuator fails closed, names the gap and refuses — it does not enrich the spec from surrounding context and proceed. An actuator grading its own homework produces a fluent, self-consistent, unfalsifiable result with no seam between inventing and building (FC-19, authored-not-observed). The machine-checkable expression of this clause for Epic children is the work-order contract in the ADO Work-Item Conventions Standard.
A worker’s self-report MUST NOT be the sole evidence that its work landed. Where a delegated actuator fans out, the orchestrator independently re-asserts before closing the unit of work — the service test plan where one exists, else the named acceptance assertion — from its own context. An agent’s account of its own success is FC-04 (proxy-not-artifact), the same class of evidence as “no errors in the logs”. Where re-assertion disagrees with the worker’s verdict, the re-assertion wins.
Where fan-out depends on an unpinned third-party behaviour, the verdict MUST be a fail-safe rather than an alert. The actuator degrades to the un-fanned-out path on a non-green conformance verdict, and the vendor’s own upgrade triggers the test so nothing depends on remembering.
For a delegated actuator, the standard’s other clauses map as follows, and all still bind: the rollout control (mode gate) is the per-invocation human grant itself — default state is no authority, and an ambiguous target forces a confirmation before authority is assumed (the delegated analogue of dryrun→live); the verify gate is the per-child prove-it acceptance test; reversibility is park-and-continue plus noted rollback handles plus the irreversible-without-safety-net hard stop; escalation is a parked item reported with exactly what the human must do to unblock; audit + notify by class is the end-of-run report as audit trail, Pushover only when the run needs attention, and the wrap-up report to email + blog. The hard stops are the envelope boundary, so they are load-bearing in a way they are not for a whitelisted actuator — a hard stop missing from a delegated actuator is an authority-boundary defect, not a cosmetic omission, and doubly so where many fanned-out workers read the same definition. A worker with no channel to reach the human MUST stop cleanly and escalate naming exactly what needs approving — never improvise one. See ADR-0403, superseding ADR-0121.
A delegated run may contain a standing sub-grant — anything it leaves to run unattended is standing-tier and carries standing-tier controls
Section titled “A delegated run may contain a standing sub-grant — anything it leaves to run unattended is standing-tier and carries standing-tier controls”The two tiers above classify an actuator. They are silent on the case where a delegated actuator produces something that runs later, unattended, with no human confirming scope at execution time — an emitted script, a queued job, a deferred batch. The human grant that licensed the delegated run was given to the run’s scope, not to whatever the run decides to leave behind, and by the time that artifact executes the human-in-the-loop-at-grant control is no longer present. Treating it as delegated because its parent was is how a broad hard-stop-bounded envelope silently becomes the envelope of an unattended executor.
So an artifact a delegated run leaves to execute unattended is a STANDING sub-grant, whatever the tier of the run that produced it, and the standing tier’s three controls are mandatory on it:
- A narrow enumerated whitelist, never the parent’s broad grant. Anything not named is not batchable, and an unrecognised class is refused rather than assumed benign — an enumerated set has no benign default.
- A blast-radius cap — the artifact carries only the work of the one run that produced it, never an accumulated queue.
- A fail-safe — an unreadable, absent or malformed envelope refuses everything rather than permitting everything. An absent envelope is not an empty one.
Two further clauses bind the sub-grant, because it executes without the parent’s supervision:
- The envelope is re-validated at emit time as well as at record time. The record of what to run is state, and state is a file that can be edited or corrupted between the two moments. One check is an assumption; two independent checks of the same envelope is the control.
- A unit of work closes only on its own re-asserted acceptance, run by the artifact itself. The artifact having executed is FC-04 (
proxy-not-artifact) — the same class of evidence as “no errors in the logs”. A failed action must not be able to launder itself into a green board, so the artifact re-runs the named acceptance assertion and closes nothing that does not pass.
Hard stops do not descend into a sub-grant at all. Any class resting on a prime directive that says a human decides — UDM/UniFi, Home Assistant, Cloudflare, external exposure, an irreversible operation with no safety net — is held out of the whitelist by construction, not merely discouraged. An unattended executor plus an unread artifact would otherwise turn those directives into advice as a side effect of an unrelated design. Where a delegated run cannot complete such an action, it escalates it by name as a decision-ready artifact and continues.
/go’s end-of-run deferred-action script is the first subject of this clause (ADR-0414).
A skill’s authority envelope follows its invocation — an attended behaviour is not an unattended one
Section titled “A skill’s authority envelope follows its invocation — an attended behaviour is not an unattended one”The clauses above classify an actuator, and the one before this classifies an artifact a delegated run leaves behind. Both assume the thing being governed exists to run unattended. They are silent on the case that produced this clause: one skill invoked in two provenances — interactively, with a human reading every step, and again as the proposal half of a standing actuator reading the same file.
So the envelope is a property of the INVOCATION, not of the skill. A behaviour a skill performs when a human is attending MUST NOT be assumed available when it is invoked unattended.
- A skill that acts on its own findings when attended MUST NOT act unattended unless a deterministic classifier stands between it and production. Where one does, the skill proposes and the classifier disposes — the standing tier’s controls apply to the classifier exactly as above. Where none does, the finding is reported rather than fixed.
- The invoking prompt is authoritative over the skill’s own text. A caller that constrains a run — “triage only”, “propose, do not act” — wins, and a skill may not treat its own emphasis as licence to override it. A boundary that depends on which of two conflicting instructions an agent finds more forceful is not a boundary.
- The unattended posture is proposing, not silence. Declining to name a finding is not the conservative default it resembles: a proposal the classifier never receives is a finding the estate never gets to clear, and is indistinguishable from a finding never had. A proposal refused by name costs nothing.
- A skill read by an unattended caller declares that dependency, and a change to its acting behaviour is communicated to that caller’s owner. The coupling is otherwise invisible in both directions — the skill does not know it has an unattended consumer, and the consumer does not know the file moved.
Why this needs saying at all, when the actuator’s own prompt already said “do not remediate”. It did, and it was not enough. On 2026-08-21 /investigate gained an unconditional “fix the quick wins before reporting, without asking” rule in its Phase 1, which is the phase the Dawn triage actuator (Epic #2604) pins its headless claude -p run to. That moved every mutation upstream of the actuator’s envelope classifier, blast cap, mute, verify gate and auto-revert, in a live unattended run against production. Three properties made it worse than a bad paragraph: there is no deploy step between saving a skill file and it governing every session plus the cron (one worktree, one inode, no propagation delay); claude-config-ci is a rule-inventory gate and deliberately blind to prose, so a semantic reversal changes no count and passes green; and the rule and the actuator depending on it live in different repos with nothing linking them (FC-13). Full record: ADR-0460.
The in-scope population is DERIVED, not recalled — matched from genuine claude -p invocations on non-comment lines across ansible/scripts and /usr/local/bin, resolved to the skill each names, and cross-checked against the crontab (2026-08-21):
| Skill | Unattended caller | Cadence | Reviewed against this clause? |
|---|---|---|---|
/investigate | dawn_triage.py | daily 06:50 AEST | Yes — the first subject |
/vulnscan | vulnscan_cron.sh | Mondays 09:00 AEST | No |
/gapanalysis | standards_gapanalysis_agent_cron.sh | 1st of the month, 11:00 AEST | No |
/health and /verify are NOT invoked headlessly — zero invocations, and /health’s absence is a deliberate decision rather than a gap (ADR-0166 chose fat-script/thin-LLM for the morning runbook and rejected an unattended agentic run of the skill). Eleven further claude -p call-sites pass a bare prompt and name no skill, so this clause has no attended behaviour to bind and they are out of scope by construction.
The strength of the mode gate scales with blast radius and reversibility
Section titled “The strength of the mode gate scales with blast radius and reversibility”The rollout control an actuator MUST carry is proportional to how much damage a wrong action does and how reversible it is — this is where the subjects legitimately diverge, not an inconsistency:
- High blast radius / code-mutating (vulnscan, test-plan-gate rollback): a dry-run → live mode gate is mandatory — a file (
/var/lib/pitlab/<actuator>/mode) holdingdryrun(default) orlive, Ansible-managed, that fails safe todryrunwhen absent. Indryrunthe actuator runs the entire loop but makes no production mutation, instead emitting the artifact it would have applied for owner validation. The owner flips toliveonly after the dry-run has earned trust empirically. - Low blast radius / idempotent-reversible (autoheal): a full mode file is disproportionate; a conservative opt-in (per-container
autoheal=truelabel) plus a start-period grace is the equivalent control — the action (a restart) is self-reversing and per-workload gated, so trust is granted per opt-in rather than per mode flip.
The rule is one contract with a tiered control, not two contracts: the more irreversible the action, the heavier the gate.
A change is closed only after a prove-it verify gate confirms the intended outcome
Section titled “A change is closed only after a prove-it verify gate confirms the intended outcome”No actuator may treat “applied” as “fixed” — Prime Directive 12. A mutating actuator MUST run an acceptance check of the intended behaviour after acting, and only record success if it passes. vulnscan closes a remediation Issue only after a targeted re-scan confirms the specific finding cleared in Dependency-Track and the target’s probe_success/Zabbix health did not regress. The test-plan gate proves the service’s functional golden-path (the Service Test Plan Standard supplies this). autoheal’s verify is the container’s own healthcheck returning to healthy. The verify gate is the definition of done, not an optional follow-up.
A mutating actuator reverts on regression; the action is always reversible
Section titled “A mutating actuator reverts on regression; the action is always reversible”If the verify gate fails after a mutation, the actuator MUST undo the change automatically, not leave a proven-broken change live awaiting a human. For a code-deploying actuator this is git revert of the offending commit + redeploy of last-good (vulnscan on a health regression; the test-plan gate on a functional-regression, generalising revert-on-regression to all deploys). For a restart actuator the action is inherently reversible (a restart that doesn’t help is re-attempted or escalated, not compounded). Fail-safe: a failed revert still fails the run and alerts, so enabling the auto-revert only ever adds recovery on top of detect-and-alert.
A blast-radius cap and a loop guard bound a bad run
Section titled “A blast-radius cap and a loop guard bound a bad run”An actuator MUST cap how much it can change in one run and MUST NOT be able to thrash. vulnscan caps at ≤10 auto-deploys per run, one stack/host per commit, serialised; beyond the cap the remainder is batched into one review Issue and remediation stops — bounding the damage of a bad Trivy DB update or a mass-CVE week. The test-plan gate carries a revert-loop guard (a gate failure on a commit that is itself a rollback is escalate-only, never re-reverted) so it cannot thrash git history. autoheal’s AUTOHEAL_START_PERIOD stops a slow cold start being mistaken for a hang and looping restarts on boot. A debounced re-check that gates a destructive action MUST back off before re-sampling so a transient blip is not read twice as a confirmed failure (Issue #1516 — an immediate retry re-sampled the same window and reverted a sound deploy).
Remediation that recurs is surfaced — the masking guard
Section titled “Remediation that recurs is surfaced — the masking guard”Auto-remediation can hide a recurring root cause; every actuator MUST make repeated intervention visible so the underlying fault stays driven, not silently masked. The guard is a long-window recurrence alert tuned to the actuator’s cadence: autoheal’s AutohealRepeatedIntervention fires on ≥3 unhealthy events in 3h (the deliberate slow-drip counterpart to the generic 15-minute ContainerCrashLooping, which a few-hourly recurrence never trips); the precedent is FreeScoutHealFlapping. A mutating actuator MUST similarly surface an attempted-but-reverted action as a confidence signal — a fix it tried and had to undo is exactly the case a human should see. “Auto-remediate, but alert when the remediation fires too often” is mandatory, not optional.
Out-of-bounds work escalates as a decision-ready artifact, not a stub
Section titled “Out-of-bounds work escalates as a decision-ready artifact, not a stub”When an actuator hits an out-of-bounds action it MUST hand the human a ready-to-execute artifact, not a one-line “needs attention” note. For an attended operation (a major upgrade, a stateful/DB-schema change, a coordinated multi-service bump) the actuator does the human legwork up front — reads the release notes, assesses the breaking-change surface, drafts the migration/rollback plan and the test plan the service needs — and creates a groomed, ready-to-execute Epic flagged “attended — needs maintenance window” (the agent-performed backlog-refinement / discovery-spike pattern, Issue #1493). For a decision (no-patch CRITICAL, EOL component, exploitability spike) it presents options plus a recommendation. The escalation carries enough context that the human acts without opening a second tool.
The actuator is itself monitored — a dead healer must be alertable
Section titled “The actuator is itself monitored — a dead healer must be alertable”An actuator that silently dies stops remediating silently, which is worse than never having automated. Every actuator MUST be covered by its own liveness signal: autoheal carries no self-label (self-monitoring would be circular) and rides the generic ContainerDown + Loki rules; vulnscan, a scheduled batch agent, has a freshness watchdog on /var/lib/pitlab/vulnscan/last-run (Zabbix alerts if >8 days stale). A scheduled actuator the reconciler cannot introspect (a cloud routine) still gets a freshness watchdog so a silent non-run is caught. This is the load-bearing safety net whenever an actuator absorbs a job that used to be independently scheduled.
Hard stops are absolute — no remediation demand overrides them
Section titled “Hard stops are absolute — no remediation demand overrides them”Prime Directive 3 (no UDM/UniFi network changes) and Prime Directive 4 (no unattended Home Assistant restart) are absolute regardless of what a vulnerability, health check, or regression demands. An actuator MUST NOT touch these surfaces even when its in-bounds logic would otherwise apply — the hard stop wins. Planned-maintenance discipline also applies: a mutating actuator MUST set scoped Alertmanager + Zabbix maintenance silences on the target before it acts, removed once metrics return to baseline.
Every autonomous action is audited and notified by class
Section titled “Every autonomous action is audited and notified by class”Every action an actuator takes — applied, reverted, escalated, or capped — MUST leave an audit trail (an ADO work-item transition, a DT annotation, a logged commit) and MUST notify by message class per the Notification Channel Policy (ADR-0033): an operational signal (a regression, a revert, a run failure, a net-new CRITICAL) goes to Pushover; a report (the weekly work-delivery digest) goes to email + the docs blog. An autonomous change that leaves no trace and no notification is non-conformant — bounded autonomy is only safe when it is auditable and visible.
Authority and escalation flow
Section titled “Authority and escalation flow”Autonomous Remediation Authority conformance checklist
Section titled “Autonomous Remediation Authority conformance checklist”An autonomous actuator conforms to this standard when all of the following hold — verify each before granting it live authority:
- Provenance tier declared: standing (permanent unattended grant) or delegated (per-invocation human grant scoped to one named Epic). The tier sets the envelope shape and cap rule (ADR-0121, amended by ADR-0403).
- Bounded envelope declared as code + in its ADR: a narrow in-bounds whitelist (standing tier), or a broad grant bounded by an explicit hard-stop set (delegated tier); everything outside the bound escalates.
- Rollout control tier matched to blast radius: a fail-safe-to-
dryrunmode file for code-mutating standing actuators, a conservative opt-in + grace for idempotent-reversible ones, or the per-invocation human grant (default = no authority) for a delegated actuator. - Run bounded: a blast-radius cap + loop guard (standing tier), or scope-binding to the one human-named Epic (delegated tier).
- Circuit breaker present where the actuator sub-delegates (delegated tier, fan-out only): halts after K failed units, with K derived from a stated measurement (never borrowed — FC-16) and enforced by the mechanism (exit code / lock / refusal), not by the actuator’s diligence. K’s input is failure, not friction — a unit blocked by a harness or policy gate is evidence about the gate, not about the run’s premise, and counting it halts a healthy run and pollutes the change-failure rate (ADR-0403, amended by ADR-0414).
- Anything a delegated run leaves to execute unattended is declared a STANDING sub-grant and carries the standing-tier controls: a narrow enumerated whitelist with no benign default, a blast-radius cap of one run’s work, a fail-safe that refuses everything on an unreadable envelope, envelope re-validation at emit time as well as record time, hard-stop classes excluded by construction, and closure only on the unit’s own re-asserted acceptance (ADR-0414).
- The actuator does not author the spec it delivers: an under-specified unit of work fails closed and names the gap, rather than being enriched from surrounding context (FC-19).
- A worker’s self-report is independently re-asserted before the unit of work closes — the service test plan where one exists, else the named acceptance assertion, run from the orchestrator’s own context (FC-04). Re-assertion wins over the verdict.
- Unpinned third-party dependencies carry a fail-safe verdict, not merely an alert: a non-green conformance test degrades the actuator to its un-fanned-out path, triggered by the vendor’s own upgrade.
- Verify gate proves the intended behaviour (not just “applied”) before any success is recorded (PD12).
- Reversible on failure: auto-revert of a regressing mutation, with a failed revert still failing + alerting.
- No thrash: a loop guard prevents re-acting on its own action, and a debounced destructive re-check backs off before re-sampling.
- Masking guard: a long-window recurrence alert tuned to cadence; attempted-but-reverted surfaced.
- Out-of-bounds escalates as a decision-ready artifact (groomed Epic / options + recommendation), not a stub.
- The actuator is itself monitored (liveness / freshness watchdog) so a silent death is caught.
- Hard stops honoured (PD3/PD4 absolute) and maintenance silences set before acting.
- Every action audited + notified by class (ops → Pushover, report → email, ADR-0033).
Enforcement
Section titled “Enforcement”This standard governs actuators (autoheal, vulnscan, the test-plan gate, /go), not a corpus artifact, so its obligations are enforced when an actuator is built or changed — there is no standing gate that enumerates every actuator, which is why the clauses are review/advisory rather than machine. The concrete checkpoint for every contract clause is the Autonomous Remediation Authority conformance checklist above, applied at /code-review and re-checked at /wrapup before an actuator is granted live authority, plus the actuator’s own ADR (ADR-0112, ADR-0403; ADR-0121 is superseded). Machine artifacts named below (a freshness dead-man, a masking-guard alert) are the per-actuator implementations the review confirms are present — they monitor an actuator, they do not enforce this standard across all of them, so they are cited as evidence in review rows, not claimed as machine gates over the standard.
| Obligation | Class | Layer | Mechanism | Dead-man |
|---|---|---|---|---|
| Each actuator declares its provenance tier — standing (permanent unattended grant) or delegated (per-invocation human grant scoped to one named Epic) — which sets its envelope shape and cap rule | review | — | /code-review ARA-conformance dimension on the actuator’s code + ADR (ADR-0121); re-checked at /wrapup before live authority | n/a |
| Each actuator declares a bounded authority envelope as code + in its ADR — a narrow in-bounds whitelist (standing) or a broad grant bounded by an explicit hard-stop set (delegated); everything outside escalates, never applies | review | — | /code-review of the declared in-bounds/out-of-bounds set against the actuator’s ADR; the whitelist-vs-hard-stop shape must match the declared tier | n/a |
The rollout control is matched to blast radius — a fail-safe-to-dryrun mode file for code-mutating standing actuators, a conservative opt-in + grace for idempotent-reversible ones, or the per-invocation human grant (default = no authority) for a delegated actuator | review | — | /code-review confirms the mode gate exists and fails safe (the dryrun default, the autoheal=true opt-in, or the delegated confirm-on-ambiguous-target) | n/a |
| Each run is bounded — a blast-radius cap + loop guard (standing) or scope-binding to the one human-named Epic (delegated) | review | — | /code-review of the cap constant + loop/thrash guard (e.g. vulnscan ≤10 auto-deploys/run; the test-plan gate’s revert-loop guard); /wrapup confirms a delegated run stayed Epic-scoped | n/a |
| A delegated actuator that sub-delegates carries a circuit breaker halting after K failed units — friction (a harness-blocked or deferred unit) is excluded from K’s input — with K derived from a stated measurement and enforced by the mechanism rather than the actuator’s diligence | review | — | /code-review confirms the breaker is a refusal/exit code (go_run.py child-done exits 3 at K), that the ADR states the measurement K was derived from, and that what K counts matches what that measurement measured; a borrowed threshold, or a K counting a class its derivation never observed, is a finding (FC-16 / ADR-0414) | the breaker’s own trip counter (go_run_breaker_trips_total) |
| Anything a delegated run leaves to execute unattended is a standing sub-grant: only a class on a narrow enumerated whitelist may be batched, an unrecognised class is refused rather than assumed benign, and hard-stop classes are excluded by construction | machine | pre-emit | go_run.py child-defer classifies against the committed routed-action register and exits non-zero on a policy-class, unrecognised or already-routed class; go_run.py script-emit re-validates every entry against the same register and writes nothing if any fails, so a hand-edited state file cannot smuggle one through. Fails closed: an unreadable register refuses every class rather than permitting all of them | the emitter’s own refusal is the gate; unactioned output is aged by the /go deferral dead-man (go_deferral_age_seconds, Zabbix trigger “/go deferred action unactioned >24h”) |
| An unattended artifact closes a unit of work only on that unit’s own re-asserted acceptance, never on the artifact having executed | machine | runtime | the script emitted by go_run.py script-emit runs each action, then re-runs that Issue’s named acceptance assertion, and issues the ADO close only on a zero exit; a failed action or a failed assertion leaves the Issue open and notifies at priority 0 (FC-04) | go_deferral_age_seconds keeps ageing anything that did not close, so a silently-failed artifact is caught rather than assumed |
| A skill that acts on its own findings when attended does not act when invoked unattended unless a deterministic classifier stands between it and production; the invoking prompt is authoritative over the skill’s own text, and the unattended posture is proposing rather than silence | advisory | — | justification: no committed-file signal distinguishes a skill that ACTS from one that DESCRIBES acting — both are prose in the same file — so no gate can enumerate the population. Bound at /code-review of any change to a skill’s acting behaviour, and at design time for any actuator invoking a skill as its proposal half; the actuator’s own envelope classifier is the compensating control that makes the clause survivable when it is missed (ADR-0460) | n/a |
| A delegated actuator never authors the specification it then delivers — an under-specified unit of work fails closed and names the gap | machine | pre-fan-out | go_workorder_check.py refuses any child Issue missing Goal/Change/Acceptance/Scope/Depends, or carrying a vacuous one, and the actuator does not fan out (FC-19) | n/a |
| A fanned-out worker’s self-report is independently re-asserted before its unit of work closes | review | — | /code-review + /wrapup confirm the orchestrator re-ran the service test plan (/verify) or the named acceptance assertion from its own context, and that a disagreement resolved in favour of the re-assertion (FC-04) | n/a |
| Fan-out that depends on an unpinned third-party behaviour degrades to the un-fanned-out path on a non-green conformance verdict | machine | runtime | cc_fork_resume_test.sh sub-agent conformance assertion on every claude version change writes /var/lib/pitlab/cc-pool.subagent_ok; 0 makes /go refuse to fan out and deliver inline | cc.subagent.age freshness watchdog |
| A prove-it verify gate confirms the intended behaviour (not merely “applied”) before any success is recorded (PD12) | review | — | /code-review + /wrapup acceptance-test check per Prime Directive 12; the actuator’s own verify gate (vulnscan re-scan + health, autoheal healthcheck, the Service Test Plan gate) | n/a |
| A mutating actuator auto-reverts a regressing mutation to last-good; a failed revert still fails the run and alerts | review | — | /code-review of the revert-on-regression path (git revert + redeploy) and the fail-safe that a failed revert reds + pages | n/a |
| No thrash — a loop guard prevents re-acting on the actuator’s own action, and a debounced destructive re-check backs off before re-sampling (Issue #1516) | review | — | /code-review of the loop/debounce guard against the back-off requirement | n/a |
| A masking guard surfaces recurring intervention — a long-window recurrence alert tuned to cadence; an attempted-but-reverted action is surfaced as a confidence signal | review | — | /code-review confirms a cadence-tuned recurrence alert exists (reference: AutohealRepeatedIntervention ≥3/3h, FreeScoutHealFlapping) and reds/pages on repeat | n/a |
| Out-of-bounds work escalates as a decision-ready artifact (groomed ready-to-execute Epic / options + recommendation), not a one-line stub | review | — | /code-review of the escalation path + /wrapup review of the produced artifact quality (the agent-performed backlog-refinement pattern, Issue #1493) | n/a |
| The actuator is itself monitored — a liveness/freshness watchdog so a silent death is caught | review | — | /code-review + /wrapup Pillar-1 check that the actuator carries its own liveness signal; reference implementations are the scheduled actuators’ registered freshness dead-men (e.g. vulnscan.run.age on /var/lib/pitlab/vulnscan/last-run) and autoheal riding the generic ContainerDown/Loki rules | n/a |
| Hard stops are honoured absolutely (PD3 no UDM/UniFi change, PD4 no unattended HA restart) and scoped Alertmanager + Zabbix maintenance silences are set on the target before acting | review | — | /code-review asserts the hard-stop set is present and load-bearing (especially for a delegated actuator) and that the mutate path sets the planned-maintenance silences first (Planned-Maintenance directive) | n/a |
| Every autonomous action — applied, reverted, escalated, or capped — leaves an audit trail and notifies by message class (operational → Pushover, report → email + blog, ADR-0033) | review | — | /code-review against the Notification Channel Policy; an action that leaves no ADO/DT/commit trace or mis-routes its notification class fails the review | n/a |