Decision pipeline
Purpose¶
Every consequential action a Chonk takes passes through one pipeline: Observe → Propose → Pre-check → Act (or route to a human) → Verify → Record. This document is the contract for that pipeline: the inputs and outputs of each stage, the receipts schema, the scoring functions the Pre-check depends on (confidence and its calibration, novelty, blast radius, budgets), dry-run and shadow execution, compensating actions, and the state machine and pseudocode an engineer needs to build it. The pipeline is where the PRD's "every decision has a why and a receipt" (§4.5) and "enforced in the harness, not in the prompt" (§10) become code.
Scope / Non-scope¶
In scope
- The definition of a consequential action and which path (full or read-only) it takes.
- Stage contracts, the decision state machine, and the pipeline pseudocode.
- Schemas:
Observation,Proposal,Precheck,ActResult,Verification,Receipt. - Scoring: blast radius, novelty, confidence and calibration, budgets.
- Dry-run, shadow execution, hold-before and undo-after reversal windows.
- Compensating actions and reversibility classes for every write.
Non-scope
- The rule language and precedence — Policy and Rule Engine.
- Human routing, expiries, quorum and the approvals inbox — Escalation and Human-in-the-Loop.
- Breakers, kill switch, trust budget — Closed-Loop Risk Mitigation.
- Connector implementations and idempotency support per system — Integrations Spec.
- How sub-agents produce proposals internally — Manager Agents.
1. Definitions and invariants¶
Run. One Harness invocation of one Chonk in response to one trigger (cadence tick, integration event, IC message, escalation, hand-off from another Chonk, or an explicit human request). A run pins org_model_version and ruleset_version at its start. A run yields zero or more decisions.
Decision. One instance of the pipeline for one proposed action. Decisions are the unit of receipts, audit, override and learning.
Consequential action. Any registered action type with write: true (doc 05 §2.3) — which includes every message delivered to a human — and any data.read.* outside the actor's charter or carrying a non-default purpose. Charter reads take the read path (Observe → Pre-check policy only → Act → Record); everything else takes the full path.
Invariants the pipeline guarantees:
| # | Invariant |
|---|---|
| I1 | No write reaches a connector without a Precheck record whose outcome is EXECUTE and a policy decision whose class is AUTONOMOUS, or a HumanDecision record approving a PROPOSE_CONFIRM item. |
| I2 | No action classified HUMAN_ONLY is ever executed by the Harness. The Harness prepares a packet and records the human's decision; the human performs the act in the system of record. |
| I3 | Policy is re-resolved immediately before Act with fresh context. The class at Act is never lower than the class at Pre-check. |
| I4 | Every write has a registered compensator or is explicitly marked irreversible, and irreversible writes are never AUTONOMOUS. |
| I5 | Every executed write is verified against its expected_effect or escalated; "unknown" is never treated as success. |
| I6 | The receipt for a decision is complete before the decision is considered closed, and the audit chain is append-only. |
| I7 | The pipeline is replayable: Observe, Propose and Pre-check are re-executable from stored inputs without contacting the world. |
2. State machine¶
stateDiagram-v2
[*] --> Observed
Observed --> NoAction: nothing to do
Observed --> Proposed: proposal emitted
Proposed --> Prechecked
Prechecked --> Rejected: DENY or validation failure
Prechecked --> Anomaly: HUMAN_ONLY without a human request
Prechecked --> Deferred: rate limit or quiet hours
Deferred --> Prechecked: window opens, re-observe
Deferred --> Withdrawn: max hold reached or observation no longer true
Prechecked --> Shadowed: mode shadow
Prechecked --> AwaitingHuman: PROPOSE_CONFIRM
Prechecked --> PacketPrepared: HUMAN_ONLY, requested by a human
Prechecked --> Holding: AUTONOMOUS, hold-before window
Prechecked --> Executing: AUTONOMOUS, live
AwaitingHuman --> Holding: approved, hold-before window
AwaitingHuman --> Executing: approved, revalidated
AwaitingHuman --> Overridden: rejected or edited
AwaitingHuman --> Expired: expiry reached, on_expiry applied
Holding --> Executing: window elapsed
Holding --> Withdrawn: undo tapped
PacketPrepared --> HumanDecided: human records decision
Executing --> Verifying: connector acknowledged
Executing --> Failed: connector error after retries
Failed --> Compensating
Verifying --> Verified
Verifying --> Mismatch
Mismatch --> Compensating
Compensating --> Compensated
Compensating --> RepairEscalated: no compensator or compensator failed
Verified --> Recorded
Compensated --> Recorded
RepairEscalated --> Recorded
Shadowed --> Recorded
Rejected --> Recorded
Anomaly --> Recorded
Withdrawn --> Recorded
Overridden --> Recorded
Expired --> Recorded
HumanDecided --> Recorded
NoAction --> Recorded
Recorded --> [*]
Every transition is an event in the event-sourced run log (decision.<state>), so any decision can be reconstructed to any point.
3. Stage contracts¶
3.1 Observe¶
Inputs. Trigger; pinned Org Model and ruleset versions; connector reads within the Chonk's charter; memory (visible to the person it is about).
Outputs. An Observation:
type Observation = {
observation_id: string; run_id: string; tenant_id: string; chonk: ChonkRole;
trigger: { kind: "cadence" | "event" | "message" | "escalation" | "handoff" | "human_request"; ref: string };
org_model_version: string; ruleset_version: string;
snapshots: { system: string; object_ref: string; hash: string; fetched_at: ISODate; staleness_s: number }[];
signals: { kind: string; subject: string; since?: ISODate; evidence: EvidenceRef[] }[]; // "stall", "coverage_gap", "envelope_90pct"
freshness_ok: boolean; // all snapshots within their staleness budget
};
Rules. Snapshots are content-addressed so Propose and Pre-check can be replayed against exactly what was seen. Each source has a staleness budget (work systems 15 min, comms 5 min, HRIS 24 h, ledger 1 h, POS and time clocks 5 min). A stale snapshot does not block observation; it sets freshness_ok = false, which Pre-check turns into an elevation for medium-or-higher blast radius (§5.4). Observe never writes.
Failure. A connector outage produces an observation with the affected snapshots missing; downstream rules that need them behave per on_missing (doc 05 §2.5). A missed cadence trigger is itself an incident (cadence.skip is DENY; the scheduler's watchdog raises E1 — doc 09).
3.2 Propose¶
Inputs. The Observation; the Chonk's charter and tool allowlist; function-service outputs (planning solver, capacity model, scheduling solver, calibration engine, budget ledger); the active ruleset (read-only, advisory).
Outputs. Zero or more Proposals:
type Proposal = {
proposal_id: string; run_id: string; observation_id: string;
action: { type: string; params: object; target: TargetRef };
intent: string; // one sentence a human can read
rationale: {
summary: string;
evidence: EvidenceRef[]; // every claim links to a snapshot object
function_outputs: { service: string; input_hash: string; output_ref: string }[];
model: { id: string; prompt_hash: string; temperature: number; tokens: number };
what_would_make_me_wrong: string; // required; feeds confidence review
};
expected_effect: Predicate[]; // machine-checkable postconditions
self_confidence: number; // 0..1, raw
alternatives: { action: string; why_not: string }[];
compensator: { type: string; params: object } | "irreversible";
requested_by_human?: { person_id: string; message_ref: string }; // required for HUMAN_ONLY packets
urgency: { deadline?: ISODate; reason?: string };
};
expected_effect predicates come from a small registry per action type, e.g. hris.pto_status(person, range) == "approved", ledger.entry(id).status == "approved", message.delivered(channel, msg_id), schedule.slot(shift_id).assignee == person, orgmodel.version(project) == v+1. A proposal without a valid predicate set fails validation for any write.
Rules. The model is told the active ruleset so it wastes fewer proposals, but nothing it says about class is trusted. Sub-agents may propose in parallel; the Harness serialises decisions per target to avoid conflicting writes (two Chonks re-planning the same project in the same minute).
3.3 Pre-check¶
Deterministic; no model calls. Sub-steps in order, short-circuiting on the first terminal result:
| Step | Check | Terminal outcomes |
|---|---|---|
| 1 | Validate: schema, registry membership, params, predicates, compensator declared or irreversible |
REJECT (validation) |
| 2 | Policy: resolve(request) (doc 05) with scores absent |
REJECT on DENY; ROUTE_PACKET on HUMAN_ONLY with requested_by_human; ANOMALY on HUMAN_ONLY without it |
| 3 | Budgets: model spend, outreach, money, connector quota (§5.4) | DEFER (model, outreach, quota) |
| 4 | Blast radius (§5.1), novelty (§5.2), confidence (§5.3) | — |
| 5 | Policy again with scores present: obligations max_blast_radius, max_novelty, min_confidence may elevate; graduation, breaker and kill-switch clamps; defer_until |
DEFER |
| 6 | Route: final class → EXECUTE, EXECUTE_SHADOW, ROUTE_PROPOSE, ROUTE_PACKET |
— |
Output. A Precheck:
type Precheck = {
proposal_id: string;
validation: { ok: boolean; errors: string[] };
policy: PolicyDecision; // final, with scores (doc 05 §5.3)
budget: { model_ok: boolean; outreach_ok: boolean; money_ok: boolean; quota_ok: boolean; detail: object };
blast_radius: { score: number; band: "low" | "medium" | "high" | "critical";
people: number; reversibility: number; money: number; visibility: number };
novelty: { score: number; shape_hash: string; tenant_successes: number; global_successes: number; first_of_kind: boolean };
confidence: { raw: number; calibrated: number; sample_size: number; bucket: string };
stale_inputs: boolean;
outcome: "EXECUTE" | "EXECUTE_SHADOW" | "ROUTE_PROPOSE" | "ROUTE_PACKET" | "DEFER" | "REJECT" | "ANOMALY";
route?: { to: string; expiry: ISODate; quorum: number; reversal_window: Duration };
reasons: string[]; // human-readable, one per elevation or clamp
};
Platform obligations applied here, on top of the tenant ruleset (they are platform rules R-PLAT-011..013 in the registry; listed here for readability):
| Rule | Obligation | Effect |
|---|---|---|
| R-PLAT-011 | max_blast_radius 0.5 elevate on every write; quorum 2 and route owner when band is critical |
High blast radius is never AUTONOMOUS |
| R-PLAT-012 | first_of_kind (tenant successes < 3) elevates AUTONOMOUS → PROPOSE_CONFIRM; global successes = 0 also raises E5 informational to Sea Suite ops |
The first three of any new action shape are human-confirmed |
| R-PLAT-013 | min_confidence 0.6 elevate on every write; stale_inputs with band ≥ medium elevates |
Low or unfounded confidence is never AUTONOMOUS |
3.4 Act¶
Act has five modes, chosen by Precheck.outcome:
- Execute. Re-validate (below), then call the connector with an idempotency key
hash(decision_id, attempt). Connectors that cannot be idempotent are wrapped in check-then-write using theexpected_effectpredicate as a precondition (if the effect is already true, the write is skipped and verification proceeds). - Execute shadow. Write the full
ActResultto the shadow log withmode: "shadow"; nothing reaches the world; the decision proceeds to Verify in shadow mode (§6). - Route propose. Create an approvals-inbox item (doc 09 §5) with the recommendation, receipts so far, dry-run preview, one-tap decision, expiry, quorum. The decision parks in
AwaitingHuman. - Route packet. Assemble the HUMAN_ONLY packet (facts, options, the relevant policy, the calibration context, never a recommendation on the protected decision itself) and deliver it to the human named in the request. The decision parks in
PacketPrepared; the Harness records but never executes. - Defer. Park until
defer_until; on wake, re-run Observe for the same trigger (the world may have moved), then Pre-check again.
Re-validation (I3). Immediately before any execution — including one a human just approved — Act rebuilds the context (counters, envelopes, breaker state, kill-switch level, time) and calls resolve again. If the class rose, the decision moves to the corresponding route instead of executing, and the approver is told why. If the result is DENY (a hard line landed, a breaker opened), the decision is withdrawn with an explanation. If the observation is older than the source's staleness budget, Act re-observes first; if the signal that motivated the proposal is gone (the PR got reviewed), the decision is withdrawn as no longer applicable — a good outcome, recorded as such.
Reversal windows. A reversal_window constraint means one of two things depending on the action's reversibility cost R (§5.1):
| Reversibility | Semantics | Example |
|---|---|---|
R ≤ 0.3 (clean compensator) |
Undo-after: execute now; an undo tap within the window runs the compensator | plan.rebalance (Org Model restore), shift.swap |
R > 0.3 (dirty or partial compensator) |
Hold-before: park in Holding; execute when the window elapses unless undone; approver may tap "now" |
spend.approve, external.publish, message.customer |
Output. An ActResult:
type ActResult = {
decision_id: string; mode: "live" | "shadow"; attempt: number;
connector: string; idempotency_key: string;
status: "acked" | "skipped_already_true" | "failed";
external_refs: { system: string; id: string }[];
before_snapshot_hash: string; error?: { code: string; retryable: boolean; message: string };
executed_at: ISODate; revalidation: PolicyDecision;
};
3.5 Verify¶
Immediate verification. Within the connector's verify_timeout (default 60 s; SMS 5 min; HRIS 15 min), re-read the touched objects and evaluate every expected_effect predicate. Also diff the before and after snapshots of touched objects to catch side effects (a duplicate message, a second ledger entry).
| Result | Condition | Next |
|---|---|---|
VERIFIED |
all predicates true, no unexpected diffs | Recorded |
MISMATCH |
any predicate false or unexpected diff | Compensating |
UNKNOWN |
source unreachable after 3 retries with backoff | treated as MISMATCH for routing (never as success); compensation is attempted only if the compensator is safe to run blind (Org Model restores), otherwise RepairEscalated to the MoR and ops |
Compensation. Run the registered compensator (§7) as its own decision through the pipeline with origin: compensation — it is policy-checked too, but with a platform obligation that a compensator for an executed action may never be classified higher than the original action (you must be able to undo what you were allowed to do). If compensation itself fails or no compensator exists, the decision goes to RepairEscalated: an E2 item to the MoR with the receipts and the exact external state (doc 09).
Delayed outcome verification. Many actions have a purpose observable only later: a chase should move the item within 24 h, a pto.approve should appear in the HRIS calendar, a plan.rebalance should attract no IC objection inside the cooling-off period, a shift.callout.fill should end with the person clocked in. Each action type registers an outcome_check { predicate, horizon }. A scheduled verifier evaluates it at the horizon and writes an outcome_label (positive, negative, unknown) into the receipt. The label is what calibration (§5.3) and the trust budget (doc 07) learn from.
3.6 Record¶
Record finalises the receipt, appends to the audit chain, and emits the learning signals:
- Receipt (§4) assembled incrementally through the stages and sealed with a hash chained to the previous receipt for the tenant (
prev_hash). Receipts are append-only; corrections are new receipts referencing the old one. - Audit events:
decision.*state transitions;data.accessevents for every read, with purpose. - Memory writes: any fact about a person learned during the run, written with source and visible on the "what my manager knows" page (R-DAT-004/005).
- Metrics: latency per stage, outcome counts, elevation reasons, verification results.
- Learning signals: calibration sample
(raw, calibrated, label); novelty counters; trust-budget delta (doc 07 §6); override record if a human changed anything (doc 09 §8).
Access to receipts is symmetric with the PRD's commitments: an IC can read every receipt whose target is them; an owner reads receipts routed to them and aggregate views; Sea Suite ops read redacted receipts unless an incident grants scoped access.
4. Receipts schema¶
type Receipt = {
receipt_id: string; tenant_id: string; run_id: string; decision_id: string;
chonk: ChonkRole; subagent?: string; action_type: string; created_at: ISODate; sealed_at?: ISODate;
sources: { system: string; object_ref: string; snapshot_hash: string; fetched_at: ISODate }[];
data_snapshot: { org_model_version: string; ruleset_version: string };
proposal: Proposal; // §3.2, verbatim
rule_evaluations: PolicyDecision["trace"]; // every candidate rule and its disposition
resolution: { effect: string; class: AutonomyClass; mode: string; winning: RuleRef[];
constraints: Constraint[]; clamps: object; elevations: string[] };
scores: { blast_radius: Precheck["blast_radius"]; novelty: Precheck["novelty"];
confidence: Precheck["confidence"]; budget: Precheck["budget"]; stale_inputs: boolean };
rationale: { summary: string; model_id: string; prompt_hash: string; reasoning_digest: string };
alternatives: Proposal["alternatives"];
expected_effect: Predicate[];
compensator: Proposal["compensator"];
human?: { routed_to: PersonId[]; item_id: string; decision: "approved" | "rejected" | "edited" | "expired";
decided_by?: PersonId[]; decided_at?: ISODate; override?: OverrideRef; quorum_met: boolean };
act?: ActResult;
verification?: { status: "VERIFIED" | "MISMATCH" | "UNKNOWN"; checked_at: ISODate;
observed: object; mismatch?: string; compensation_decision_id?: string };
outcome?: { label: "positive" | "negative" | "unknown"; horizon: Duration; checked_at: ISODate };
visibility: { ic_readable: boolean; owner_readable: boolean; redactions: string[] };
hash: string; prev_hash: string;
};
Receipts are the artefact the approvals inbox renders, the artefact the IC transparency page draws from, and the artefact the simulation harness replays. Nothing in the product shows a "why" that is not in a receipt.
5. Scoring¶
5.1 Blast radius¶
Four components, each in [0, 1], combined so that any single component can dominate (a small, cheap, internal action that is irreversible still scores high):
P = clamp( log2(1 + people_affected) / log2(1 + tenant_headcount), 0, 1 )
R = reversibility cost:
0.0 restore-from-version (Org Model, plan, growth plan)
0.3 compensable with a notice (retract or correct a message; swap back a shift)
0.6 partially compensable (money moved but refundable; HRIS write with revert)
1.0 irreversible (external publish; data export; message read by an external party; anything HUMAN_ONLY)
M = clamp( amount / tenant.money_ref, 0, 1 ) // money_ref = monthly discretionary envelope
X = external visibility:
0.0 one person 0.2 team 0.4 org-wide 0.7 known external party 1.0 public
BR = 1 − (1 − P)(1 − R)(1 − M)(1 − X)
Bands: low < 0.25, medium 0.25–0.5, high 0.5–0.75, critical > 0.75. Effects are in R-PLAT-011 (§3.3): high elevates once; critical also requires quorum and routes to the owner. people_affected is computed from the action's target closure (the recipients of a message; the people whose plan rows change; the staff on a published schedule).
5.2 Novelty¶
"Has the Harness ever done this action shape in this tenant?"
shape_hash = hash(action.type, target.kind, param_shape, org_path[0], channel, external)
// param_shape = sorted keys + value classes (money band, count band), never raw values
n_t = successes(shape_hash, tenant, 180d) // verified, not overridden, not reversed, outcome ≠ negative
n_g = successes(shape_hash, all tenants, 180d) // aggregate count only; no tenant data crosses
novelty = 0.7 · 1/(1 + n_t) + 0.3 · 1/(1 + n_g/10)
first_of_kind = n_t < 3
first_of_kind is the gate (R-PLAT-012): the first three instances of a new shape in a tenant are human-confirmed regardless of class, and a shape never seen anywhere raises an informational E5 to Sea Suite ops. The continuous novelty score feeds the inbox priority (doc 09 §7) and the confidence prior. A semantic variant — distance between this proposal's rationale embedding and the centroid of rationales for the same shape — is planned as an "unusual reasoning" flag (Open question 2).
5.3 Confidence and calibration¶
self_confidence is the model's own estimate, elicited in a fixed structured form alongside the mandatory what_would_make_me_wrong field. Raw self-reports are systematically overconfident, so the pipeline never gates on them directly.
Calibration. Per (tenant, action family, chonk) the Harness maintains an isotonic-regression map from raw to observed correctness, where the label for a past decision is:
label = 1 if verification == VERIFIED
and no human override within the reversal window
and no compensation
and outcome_label ∈ {positive, unknown-with-no-complaint}
= 0 otherwise
Cold start uses a global prior curve per action family (built from aggregate counts across tenants, not data) with shrinkage:
calibrated(raw) = ( n · tenant_curve(raw) + k · global_curve(raw) ) / (n + k), k = 30
Gates. min_confidence obligations (0.6 platform default; 0.75 for feedback.concern; 0.7 for autonomous vendor chases) compare against calibrated. Below the gate, the class elevates; the receipt says so; the inbox item says "the manager is not sure about this one" in plain words.
Monitoring. Expected calibration error (ECE) per family over a rolling 200-sample window. ECE > 0.10 is a drift signal (doc 07, RISK-06) and, at 0.15, clamps the family to PROPOSE until a human resets it. A model that always reports 1.0 is caught here rather than trusted: its calibrated value converges to its actual hit rate.
5.4 Budgets¶
| Budget | Unit | Default | On exhaustion |
|---|---|---|---|
| Model spend | per tenant per day; per managed person per month | 10% of price per person (PRD non-functional) | DEFER non-urgent runs; urgent runs continue; E5 to ops at 120% |
| Outreach | messages per person per day (policy counters); per tenant per day anti-runaway | 3 per person; 4 × managed people per tenant | DEFER per person; tenant cap trips BRK-OUT (doc 07) |
| Money | envelope remaining | from ledger | R-APR-004 elevates at 90%; over 100% is DENY by hard line if the owner set one |
| Connector quota | API calls per window | per integration | DEFER with backoff; reads preferred over writes when rationing |
stale_inputs (from Observe) is not a budget but is handled here: with band ≥ medium it elevates; with band critical it defers until fresh.
6. Dry-run and shadow execution¶
Dry-run is a per-connector capability used inside the full path for previews: the scheduling solver validates a swap without committing; the ledger simulates an approval and returns the post-state; messaging renders the exact text, recipients and channel. Dry-run results are attached to the proposal and shown in the approvals inbox, so a human approves what they see. Dry-run is mandatory before any hold-before execution and before any PROPOSE_CONFIRM routing where the connector supports it.
Shadow execution is a graduation and kill-switch mode (doc 05 §3.4). The whole pipeline runs; Act writes an ActResult with mode: "shadow"; Verify runs in agreement mode: at the outcome horizon it checks whether a human did the equivalent thing (the swap happened, the PTO was approved, a similar chase was sent) and records shadow_agreement ∈ {agree, disagree, no_human_action}. Shadow agreement rate over a window is the primary input to SHADOW → PROPOSE graduation (doc 07 §6). Shadow decisions appear in the owner's console as "what the manager would have done", never in IC threads.
7. Compensating actions¶
Every write registers a compensator (I4). The registry entry declares the compensator type, the reversibility cost R (used by blast radius and the reversal-window semantics), and any notice obligation.
| Action type | Compensator | R | Window semantics | Notes |
|---|---|---|---|---|
plan.rebalance, goal.set.*, growth_plan.update, capacity.assign |
orgmodel.restore_version(prev) |
0.0 | undo-after | The Org Model is versioned; restore carries reason: compensation and the original decision id |
brief.send, checkin.ask, chase.* (internal) |
message.retract + short correction ("ignore that — my mistake, receipt here") |
0.3 | undo-after | Never silently delete a message a person may have read |
feedback.concern, feedback.praise |
message.retract + memory.annotate(retracted) |
0.3 | undo-after; IC is told | A retracted concern is still visible to the IC as retracted (symmetry) |
shift.swap, shift.callout.fill |
shift.swap_back / shift.unassign + SMS to both |
0.3 | undo-after (before shift start); hold-before if < 4 h to start | Cannot compensate a shift already worked; becomes a records correction (HUMAN_ONLY packet) |
meeting.book |
meeting.cancel with reason |
0.3 | undo-after | – |
pto.approve, hris.write (self-service) |
hris.revert + notice to IC |
0.6 | hold-before PT1H | If the person already acted on the approval (booked travel), revert becomes an E2 to the MoR |
spend.approve, expense.reimburse |
ledger.void if not disbursed, else ledger.flag_clawback (HUMAN_ONLY packet) |
0.6 | hold-before PT1H | Disbursed money is never clawed back autonomously |
chase.vendor, message.customer |
message.correct (follow-up) |
0.6 | hold-before | External party may have read it; correction, not deletion |
announcement.*, message.group.announce |
message.delete + message.correct |
0.6 | hold-before | Correction is posted in the same channel |
external.publish |
post.unpublish + correction |
1.0 | hold-before PT24H | Public; treated as irreversible for scoring |
data.export |
none | 1.0 | hold-before | Irreversible; PROPOSE_CONFIRM floor |
policy.ruleset.activate |
ruleset.rollback |
0.0 | undo-after | Doc 05 §7.4 |
| HUMAN_ONLY set | none | 1.0 | n/a | Never executed by the Harness |
Compensators are themselves decisions (they carry receipts and are policy-checked), and a compensator cannot trigger further compensation more than once (compensation_depth ≤ 1); a failed compensator always escalates to a human rather than looping.
8. Pipeline pseudocode¶
function runDecision(proposal, obs):
d = Decision.new(proposal, obs); emit(d, "Proposed")
# ---- Pre-check ----
v = validate(proposal, registry)
if not v.ok: return finish(d, "Rejected", reasons=v.errors)
ctx0 = buildContext(obs, proposal, scores=none)
p0 = policy.resolve(ctx0)
if p0.effect == DENY: return finish(d, "Rejected", reasons=[p0.winning])
if p0.class == HUMAN_ONLY:
if proposal.requested_by_human: return routePacket(d, p0)
else: raiseAnomaly(d, p0); return finish(d, "Anomaly")
b = budgets.check(proposal, ctx0)
if not b.ok: return defer(d, b.retry_at)
s = { blast_radius: blastRadius(proposal, obs),
novelty: novelty(proposal, tenant),
confidence: calibrate(proposal.self_confidence, tenant, proposal.action.type, obs.chonk) }
ctx1 = buildContext(obs, proposal, scores=s, stale=not obs.freshness_ok)
p1 = policy.resolve(ctx1) # obligations + clamps applied; never lower than p0
assert p1.class >= p0.class
if p1.effect == DENY: return finish(d, "Rejected", reasons=[p1.winning])
if p1.defer_until: return defer(d, p1.defer_until)
d.precheck = Precheck(p1, b, s); emit(d, "Prechecked")
# ---- Act ----
if p1.mode == "shadow": return shadowExecute(d)
if p1.class == PROPOSE_CONFIRM: return routePropose(d, p1) # parks in AwaitingHuman
return execute(d)
function execute(d): # also entered from AwaitingHuman on approval
obs2 = maybeReobserve(d) # if stale, re-read; withdraw if signal gone
if obs2.signal_gone: return finish(d, "Withdrawn", reasons=["no_longer_applicable"])
p2 = policy.resolve(buildContext(obs2, d.proposal, scores=d.precheck.scores))
if p2.class > d.precheck.policy.class: # I3: class may only rise
if p2.effect == DENY: return finish(d, "Withdrawn", reasons=[p2.winning])
return routePropose(d, p2)
if reversalWindow(p2) and reversibility(d) > 0.3 and not d.human.now_tapped:
return hold(d, until = now + reversalWindow(p2)) # Holding; undo cancels
dry = connector.dryRun(d) if connector.supports_dry_run
res = connector.write(d, idempotency_key=hash(d.id, d.attempt)) with retries(3, backoff)
if res.status == "failed": emit(d, "Failed"); return compensate(d, reason="write_failed")
d.act = res; emit(d, "Executing")
return verify(d)
function verify(d):
r = evaluate(d.proposal.expected_effect, within=connector.verify_timeout, retries=3)
r.side_effects = diff(d.act.before_snapshot_hash, snapshot(touched(d)))
if r.status == VERIFIED and r.side_effects.empty: scheduleOutcomeCheck(d); return finish(d, "Verified")
return compensate(d, reason=r.status)
function compensate(d, reason):
if d.compensation_depth >= 1 or d.proposal.compensator == "irreversible":
escalate(d, class=E2, to=managerOfRecord(d) + ops); return finish(d, "RepairEscalated")
c = runDecision(compensatorProposal(d), observeNow(d)) # policy-checked, depth+1
return finish(d, c.state == "Verified" ? "Compensated" : "RepairEscalated")
function finish(d, state, reasons=[]):
emit(d, state); d.receipt.seal(prev_hash = tenantChain.head)
learning.record(d) # calibration sample, novelty, trust delta, override
return d
9. Sequence: a PROPOSE_CONFIRM spend approval¶
sequenceDiagram
participant CFO as Chief Fin Officer (agent)
participant H as Harness
participant P as Policy engine
participant S as Scoring
participant I as Approvals inbox
participant O as Owner
participant R as Ramp connector
CFO->>H: Proposal spend.approve $4,200 (intent, evidence, predicates, self_conf 0.86)
H->>P: resolve(ctx, no scores)
P-->>H: allow PROPOSE_CONFIRM (R-TP-017 elevate), route owner, expiry P5D, hold PT1H
H->>S: blast radius, novelty, calibrate
S-->>H: BR 0.31 medium, n_t 14, calibrated 0.79
H->>P: resolve(ctx + scores)
P-->>H: PROPOSE_CONFIRM unchanged
H->>R: dryRun(approve)
R-->>H: post-state preview
H->>I: item {recommendation, receipts, preview, one-tap, expires in 5d}
O->>I: Approve
I->>H: HumanDecision(approved)
H->>P: resolve(fresh ctx) — revalidate
P-->>H: PROPOSE_CONFIRM, still allowed
H->>H: Holding 1h (hold-before) — owner may tap "now" or "undo"
H->>R: write(approve, idempotency_key)
R-->>H: acked, entry id
H->>R: read entry
R-->>H: status approved
H->>H: Verified → Recorded (receipt sealed, calibration sample, trust +2)
10. Worked examples¶
10.1 Autonomous chase¶
Observe: cadence tick 09:00 for the Chief Build Officer in eng/platform; GitHub snapshot shows PR #412 with no review for 26 h; Linear shows it blocks TP-881. Signal stall(pr#412). Propose: chase.internal to Priya (the assigned reviewer), intent "ask Priya to review #412 today or say who should", evidence [PR snapshot, Linear link], expected_effect: message.delivered(slack, msg), outcome check pr.reviewed within 24h, self-confidence 0.9, compensator message.retract. Pre-check: policy R-OUT-003 → AUTONOMOUS, counters fine, not quiet hours; BR: P 0.02, R 0.3, M 0, X 0 → 0.31 medium; novelty n_t 61 → 0.02; calibrated 0.83; budgets ok; no elevation. Act: revalidate (unchanged), no reversal window, write to Slack, acked. Verify: message delivered → VERIFIED; outcome check scheduled for +24 h. Record: receipt sealed; Priya's "what my manager knows" page gains the entry "asked to review #412, because it blocks TP-881".
10.2 Call-out fill at 05:40 (Atoms)¶
Observe: SMS from Marco at 05:38 "can't make the 7am, sick". 7shifts snapshot: the 07:00–15:00 line shift now uncovered; availability pool has Dana and Luis with the same certification; Dana at 34 h this week, Luis at 39.5 h. Propose: shift.callout.fill → Dana, expected_effect: schedule.slot(s).assignee == dana and sms.reply(dana) == "yes", compensator shift.unassign. Pre-check: R-SCH-002 AUTONOMOUS; quiet hours waived because the shift starts in < 12 h; labor rules clean (overtime_delta 0); BR 0.28 medium; n_t 22; calibrated 0.81. Act: SMS to Dana with the ask; predicate waits for the reply (verify timeout 5 min for SMS, then a second candidate). Dana replies "yes" at 05:47 → write assignment to 7shifts → Verify slot assigned → VERIFIED. Marco's call-out is logged to the HRIS as sick time (hris.write, self-service field, requested by the IC — R-HR-008 AUTONOMOUS). Outcome check at 07:15: Dana clocked in → positive. Had Dana declined, the second candidate would be Luis — but at 39.5 h, filling him would push overtime, so that proposal resolves to overtime.assign → PROPOSE_CONFIRM to the location MoR with a 4-hour expiry (R-SCH-003), and the MoR gets one SMS with a one-tap decision.
10.3 A first-of-kind vendor chase¶
The Chief Build Officer wants to chase a new hosting vendor about an outage credit. chase.vendor with n_t = 0 → R-OUT-004 PROPOSE_CONFIRM to the MoR, plus R-PLAT-012 first-of-kind (redundant here, recorded anyway). The inbox item shows the rendered email (dry run). The MoR edits one sentence and approves. The edit creates a new proposal (the original is Overridden with reason EDITED), which is re-prechecked and executed with a hold-before window. After three such confirmations without edits, the shape's n_t reaches 3, the first-of-kind gate lifts, and R-OUT-004's second branch (AUTONOMOUS with the approved template) applies.
11. Edge cases¶
| ID | Scenario | Signal / detection | Rule | Action (class) | Escalation | Test |
|---|---|---|---|---|---|---|
| EC-PIPE-001 | Connector acks the write but verification source is unreachable | UNKNOWN after 3 retries |
I5, §3.5 | Treat as mismatch; run blind compensation only for Org Model restores; otherwise repair escalation (n/a) | E2 to MoR + ops | SIM-TP-051: block Slack reads after write |
| EC-PIPE-002 | Harness retries a write after a timeout that actually succeeded | Idempotency key hit or check-then-write finds effect true | §3.4 | skipped_already_true; proceed to Verify (n/a) |
None | Inject 504 after success in the Ramp stub |
| EC-PIPE-003 | Human approves a proposal whose observation is 3 days old | Staleness budget exceeded at Act | §3.4 re-observe | Re-observe; execute if signal persists, withdraw if gone; approver told (PROPOSE_CONFIRM) | None | Approve SIM-TP-014 after advancing the sim clock |
| EC-PIPE-004 | Compensator fails (HRIS revert rejected) | Compensation decision Failed |
§7 depth ≤ 1 | RepairEscalated with exact external state (n/a) |
E2 to MoR; E5 to ops if connector bug | Make HRIS stub reject reverts |
| EC-PIPE-005 | Human edits the amount in the inbox | HumanDecision.edited |
§10.3 | Original overridden; new proposal re-prechecked; class may rise (PROPOSE_CONFIRM) | Quorum if the new amount crosses quorum_limit |
Edit $4,200 → $26,000 in sim |
| EC-PIPE-006 | Model reports self_confidence 1.0 on every proposal |
Calibration curve flattens; ECE rises | §5.3 | Calibrated value tracks hit rate; family clamps to PROPOSE at ECE 0.15 (PROPOSE_CONFIRM) | RISK-06 loop (doc 07) | Replay 200 decisions with raw fixed at 1.0 |
| EC-PIPE-007 | Two Chonks propose conflicting writes to the same project in one minute | Per-target serialisation lock | §3.2 | Second decision re-observes after the first verifies; usually withdrawn as no longer applicable (n/a) | None | SIM-TP-052 |
| EC-PIPE-008 | Group message delivered to 3 of 5 recipients | Partial ack; predicate false for 2 | §3.5 | Retry the 2; if still failing, compensate with a correction to the 3 and route the 2 to Deferred (AUTONOMOUS) | E1 if the announcement was time-critical | Fail 2 recipients in the Slack stub |
| EC-PIPE-009 | HUMAN_ONLY packet requested by an IC (not a manager) — "I want to discuss a raise" | requested_by_human is the IC |
I2, R-PLAT-001 | Packet prepared for the MoR, IC told who will respond; nothing decided (HUMAN_ONLY) | E2 to MoR | SIM-TP-031 |
Open questions¶
- Should the hold-before window for money actions be waived below a small amount (say $50) to keep reimbursements feeling instant? Leaning yes, as a tenant parameter with a platform minimum of PT15M.
- Semantic novelty (rationale-embedding distance) — worth the cost in Phase 1, or defer to Phase 2 with the content engine?
- Outcome labels for feedback actions are weak (no objection is not the same as "correct"). Candidate: the IC's optional one-tap "useful / not useful" on feedback messages as the label source.
- Should shadow-mode HUMAN_ONLY packets be delivered to the shadow inbox at all, or suppressed entirely during listening? Currently delivered, marked shadow.
Related docs¶
- Policy and Rule Engine —
resolve, classes, constraints, the default rule set. - Closed-Loop Risk Mitigation — breakers, kill switch, trust budget, drift.
- Escalation and Human-in-the-Loop — inbox contract, expiry, quorum, override capture.
- Harness and Orchestration — runs, triggers, event sourcing, replay.
- Manager Agents — how sub-agents produce proposals.
- Integrations Spec — dry-run and idempotency support per connector.
- Observability and Runbooks — stage metrics and alarms.
- Data Model and API Reference — canonical types.