Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
bump: minor
---

### Changed

- **Escalation routes to the owning lane unless the stop rule applies.** The guardrail escalation
contract (`reference/guardrails.md#escalation`) adds a "Stops for a person" column and a stop
rule: `gate-failure`, `verification-divergence` and `demotion` go to the lane that owns the
follow-up, an `admission-rejection` stays final on the audit trail, and each stops for a person
only for an intent or vision change, a finding that alters intent or the primary design, or a
HIGH or CRITICAL security or cost risk. `structural-plan-approval` stops only when the plan
changes intent or the primary design, and `untrusted-provenance` still always stops. The
matrix's escalation cells, the unanimity rule (here and in `guardrails/verification-topology.md`)
and the runner's `gate-failed` outcome (`runner/escalation.md`) no longer send a dissent or
failed gate to the human gate by default. An item on a lane's route that no lane claims within
the staleness window re-escalates once to intake, one severity level up, so a stopped lane
cannot hold it unseen. The binding schema is unchanged (#11024).
20 changes: 19 additions & 1 deletion .github/scripts/intake-triage/apply-verdict.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -393,13 +393,31 @@ describe("planWrites", () => {
});
}

// A kept trust control (loop-lane "When work stops for the owner"): text
// addressed to the triage run escalates, and the needs-human this run's
// triage applied for it stays, though the escalated verdict carries no flag.
test("needs-human on an escalated run holds even when this run's triage applied it", () => {
const result = plan(ESCALATED_BODY, { labels: ["needs-human"], triageLabels: ["needs-human"] });
const result = plan(ESCALATED_BODY, { labels: ["needs-human"], holdSetters: { "needs-human": ACTIONS_BOT }, triageLabels: ["needs-human"] });
assert.equal(result.ready, false);
assert.deepEqual(result.remove, []);
assert.deepEqual(result.refused, []);
Comment thread
kyle-sexton marked this conversation as resolved.
Resolved
assert.ok(result.reasons.includes("the triage run escalated"), result.reasons.join("; "));
assert.ok(result.reasons.includes("held by needs-human"), result.reasons.join("; "));
});

// The same hold when the escalated verdict also reads Flags: none with every
// dimension: only the escalation guard keeps this needs-human from being refused.
test("needs-human on an escalated run with Flags: none and readable dimensions is not refused", () => {
const body = `${MARKER}\nProposed work class: none\n\nThanks for the report. Automated triage handed this issue to a maintainer.\n\nSize: Small\nComplexity: Low\nUncertainty: Known\nFlags: none\n\n${OLD_FOOTER}`;
const verdict = parseVerdict(body, DIMS, CLASSES);
assert.equal(verdict.escalated, true);
assert.deepEqual(verdict.flags, []);
assert.notEqual(verdict.dimensions, null);
const result = plan(body, { labels: ["needs-human"], holdSetters: { "needs-human": ACTIONS_BOT }, triageLabels: ["needs-human"] });
assert.deepEqual(result.refused, []);
assert.ok(!result.remove.includes("needs-human"), result.remove.join(", "));
});

// Run 41064812826 (#9953) also applied status: needs-decision with no flag.
// Owner's standing direction §2: only a flag (intent, security, cost) stops
// for a person, so this run's flagless needs-decision gives way like needs-human.
Expand Down
16 changes: 16 additions & 0 deletions docs/contracts/loop-lane/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@ topology, the escalation contract, the capability-tier vocabulary, or any loop-l
major bump, and additive guidance is a minor bump. A new model release re-audits the capability-tier
table (§3); drift found by that audit is recorded here.

## [17.0.0] - 2026-11-03

Major: the escalation contract changes (§2).

- **Escalation classes route to a lane (§2).** Gate failure, verification divergence and
demotion each go to the lane that owns the follow-up, an audited admission rejection stays
final, and each carries the `needs-human` role label only for a reason or kept control "When
work stops for the owner" names. Structural-plan approval stops only when the plan changes
intent or the primary design, as the guardrail escalation contract now says (owner decision on
#10517, #11024). §2 states the post-merge demotion alert's record rules as #11022 set them: a
canary, revert or read-back record keeps `needs-human` only until it lifts, and an issue intake
did not receive gets it because no lane retries that delivery.
- **Kept intake injection hold (§2).** "When work stops for the owner" names intake triage's hold
on text addressed to the triage run as a kept trust control, with its reason, and an
`apply-verdict` test shows the hold still stops for the owner (#11024).

## [16.0.0] - 2026-11-03

Major: the autonomy ladder's merge authority changes (§1).
Expand Down
27 changes: 26 additions & 1 deletion docs/contracts/loop-lane/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,24 @@ deterministic surface for out-of-band notification.
The event classes that oblige escalation are governing policy owned by
[`guardrails.md`](../../../plugins/autonomy/reference/guardrails.md#escalation) (gate failure,
verification divergence, admission rejection, demotion, structural-plan approval, and
untrusted-provenance). This convention adds no second escalation channel; the telemetry comment (§4)
untrusted-provenance). An event class does not by itself stop work for the owner: each routes
to the lane that owns its follow-up (a failed gate or a verifier dissent to the lane doing the
work, a demotion to its fix issues through intake triage, the cell re-earning from run
evidence), an audited admission rejection stays final with any follow-up entering intake as a
new signal, and each carries the `needs-human` role label only for a reason or kept control
[When work stops for the owner](#when-work-stops-for-the-owner) names. Structural-plan approval
stops only when the plan changes intent or the primary design; untrusted-provenance is a kept
trust control (below). The post-merge demotion alert
([`post-merge-demotion-alert.yml`](../../../.github/workflows/post-merge-demotion-alert.yml))
follows the record rules [#11022](https://github.com/melodic-software/claude-code-plugins/issues/11022)
set and the pr-pipeline "Demotion issue" rule
([the local babysit lane](../../conventions/pr-pipeline/README.md#the-local-babysit-lane)) states: a
red-main record carries no label and clears once main is green at a later commit; a canary,
revert or read-back record, which a green main does not clear, keeps `needs-human` only until it
lifts on its own lane-verifiable condition, when the alert's `close-cleared` job closes it and
removes the label; and a fix or quarantine issue intake triage did not receive gets `needs-human`,
as does a red-main record whose failing check got no fix issue, because no lane retries that
delivery. This convention adds no second escalation channel; the telemetry comment (§4)
is the report surface, never the sole path when human action is required. The escalation record
write and the out-of-band notification seam below are notification depth on the one filed
escalation, the fan-out posture the runner design
Expand Down Expand Up @@ -370,6 +387,14 @@ is the issue lane's hold on a patch carrying a credential shape or not proven cl
path under section 10. A patch proven clear, or a fault that says nothing about credentials,
retries.

Intake triage keeps one more: text in an issue addressed to the triage run (its labels, its
rules or its output) rather than describing work, an injection attempt, stops for the owner
with the `needs-human` role label ([`intake-triage.yml`](../../../.github/workflows/intake-triage.yml)
ESCALATION rule). It is none of the reasons as written, but the text tries to steer a lane, and
loosening a security control stays with the owner (owner decision 2026-10-29, #10517).
[`apply-verdict.mjs`](../../../.github/scripts/intake-triage/apply-verdict.mjs) never refuses
the hold on such an escalated verdict, though it carries no flag.

The pr-merge gate keeps two more holds for the owner, each a reason
[`babysit_risk.person_reasons`](../../../plugins/source-control/skills/babysit-prs/scripts/babysit_risk.py)
names (owner decision 2026-10-30, #11020):
Expand Down
52 changes: 33 additions & 19 deletions plugins/autonomy/reference/guardrails.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ instantiation of it. The playbook names the obligation, and this contract suppli
| Class | Min isolation (unattended) | Verification | Verification topology | Merge policy | Cost tier | Escalation |
|---|---|---|---|---|---|---|
| C1 | L2 (exfil surface remains) | output-shape checks | 1 checker | n/a; artifacts via queue audit trail | economy | low |
| C2 | L2 | deterministic blocking | 1 checker | auto-merge ELIGIBLE after per-class promotion trigger; ships human-gated | economy | gate failure → human |
| C3 | L2 | deterministic blocking + AI review (advisory, promotable per [the security-review policy](guardrails/security-review.md)) | 2 distinct checkers, 1 a model judge | auto-merge ELIGIBLE after per-class promotion trigger; ships human-gated | standard | divergence/failed verify → human |
| C4 | L2 | deterministic blocking + AI review blocking | 3 distinct checkers, 2 vendor-disjoint model judges | auto-merge ELIGIBLE after the `C3-auto-merge` promotion; ships human-gated | premium | divergence/failed verify → human |
| C2 | L2 | deterministic blocking | 1 checker | auto-merge ELIGIBLE after per-class promotion trigger; ships human-gated | economy | gate failure → owning lane |
| C3 | L2 | deterministic blocking + AI review (advisory, promotable per [the security-review policy](guardrails/security-review.md)) | 2 distinct checkers, 1 a model judge | auto-merge ELIGIBLE after per-class promotion trigger; ships human-gated | standard | divergence/failed verify → owning lane |
| C4 | L2 | deterministic blocking + AI review blocking | 3 distinct checkers, 2 vendor-disjoint model judges | auto-merge ELIGIBLE after the `C3-auto-merge` promotion; ships human-gated | premium | divergence/failed verify → owning lane |
| C5 | L3 | full gates + zero secret exposure | 3 distinct checkers, 2 vendor-disjoint model judges | human merge always | standard | always |

### Classes
Expand Down Expand Up @@ -53,7 +53,8 @@ instantiation of it. The playbook names the obligation, and this contract suppli
never merges `C5`.
- **Cost tier**: contract vocabulary (`economy` | `standard` | `premium`); the org binds
tiers to model instances. Policy vocabulary only. Cost enforcement is out of scope.
- **Escalation**: when a run must summon a human; event classes and routing below.
- **Escalation**: where a run hands an event: to the lane that owns the follow-up, or to a
person only under the stop rule below; event classes and routing below.

## Glance-layer rule

Expand Down Expand Up @@ -96,7 +97,7 @@ leaf carries this note in context.

Unanimity is not a matrix column: every transition a run takes without a human, merge and
every stage before it, requires unanimous agreement among the checkers the class declares,
and one dissent hands the item to the human gate and raises `verification-divergence` below.
and one dissent withholds the transition and raises `verification-divergence` below.
It is a fixed invariant, not a knob, so no cell above can express it. The
[verification-topology](guardrails/verification-topology.md) leaf carries it in context,
including what is enforced at binding-validity time today and what is deferred.
Expand All @@ -105,25 +106,38 @@ including what is enforced at binding-validity time today and what is deferred.

Six escalation event classes:

| Event class | Fires when |
|---|---|
| `gate-failure` | a blocking verification gate fails |
| `verification-divergence` | a verification outcome diverges from the expected or claimed result, or two checkers of one class disagree |
| `admission-rejection` | the admission seam rejects a signal as an audited rejection |
| `demotion` | contrary evidence automatically demotes a promoted cell |
| `structural-plan-approval` | an org-bound step asks a human to approve a `C4` item's plan; no shipped step raises it |
| `untrusted-provenance` | always, for every `C5` item |

**Routing obligation.** Every event class has an org-bound route in the security binding.
Escalation routes are a security-sensitive axis, so they bind on the governance surface, and
an absent or invalid binding fail-closes per the binding contract.
| Event class | Fires when | Stops for a person |
|---|---|---|
| `gate-failure` | a blocking verification gate fails | only under the stop rule |
| `verification-divergence` | a verification outcome diverges from the expected or claimed result, or two checkers of one class disagree | only under the stop rule |
| `admission-rejection` | the admission seam rejects a signal as an audited rejection | only under the stop rule |
| `demotion` | contrary evidence automatically demotes a promoted cell | only under the stop rule |
| `structural-plan-approval` | an org-bound step asks a human to approve a `C4` item's plan; no shipped step raises it | only when the plan changes intent or the primary design |
| `untrusted-provenance` | always, for every `C5` item | always: a kept trust control |

**Stop rule.** An event class names what happened, not who acts on it. An event stops for a
person only when it carries one of three reasons: the original intent or vision changes, a
finding alters intent, vision or the primary design, or a HIGH or CRITICAL security or cost
risk. Any other event goes to the lane that owns the follow-up: a failed gate or a dissent to
the lane doing the work, and a demotion to its fix issues through intake, the cell re-earning
from run evidence ([work classes](guardrails/work-classes.md)). An audited rejection stays
final on the audit trail; a follow-up enters intake only as a new signal. A trust control the
org keeps, such as `untrusted-provenance`, stops for a person whatever the reason. An org
records its stop rule and kept controls in its own governance docs.

**Routing obligation.** Every event class has one org-bound route in the security binding: the
queue of the lane that owns its follow-up, or the human gate for a class that always stops.
The lane on that route applies the human-gated label only when a stop-rule reason or a kept
control applies. Escalation routes are a security-sensitive axis, so they bind on the
governance surface, and an absent or invalid binding fail-closes per the binding contract.

**Payload.** The work-item reference plus the trace link: every escalation carries the item
it concerns and the trace context joining it into the one causal tree, so the evidence behind
the escalation is queryable from the event.

**Mechanism.** The governed queue itself: an escalation lands as a human-gated work item on
the one queue, with an optional channel notification delivered through the trigger contract's
**Mechanism.** The governed queue itself: an escalation lands as a work item on the one
queue, on its bound route, human-gated only when the stop rule or a kept control sends it to
a person, with an optional channel notification delivered through the trigger contract's
closed-loop acknowledgment symmetry ([trigger-dispatch](trigger-dispatch.md)).

**The one-channel invariant.** No second escalation channel exists. It is this contract's
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ reading as if it meant more.

**Unanimous checker agreement for anything auto-proceeding.** Every transition a run takes without a
human, not merge alone, requires every checker the class declares to agree. One dissent withholds
the automatic transition and hands the item to the human gate; divergence routing is owned by the
matrix's escalation contract.
the automatic transition and raises `verification-divergence`, which the matrix's escalation
contract routes: to the lane doing the work, or to a person only under its stop rule.

## How unanimity is enforced today

Expand Down
Loading
Loading