references/approval_claims.py
"""SQLite dispatch-permission reference, not a sender or approval authority.
The trusted decision writer supplies immutable approval snapshots. This module
never creates decisions/snapshots or calls transport. It assumes a trusted local
database, all writers honoring schema guards, and callers checking permission.
Unknown outcomes stay held; receipt evidence is supplied by a trusted caller.
"""
from contextlib import contextmanager
import hashlib
from pathlib import Path
import secrets
import sqlite3
class ClaimError(Exception):
"""No dispatch permission or state transition was granted."""
def connect(path):
"""Open an existing caller-selected database; never apply schema/migrations."""
uri = Path(path).resolve().as_uri() + '?mode=rw'
db = sqlite3.connect(uri, uri=True, isolation_level=None, timeout=5)
db.row_factory = sqlite3.Row
db.execute('PRAGMA foreign_keys=ON')
db.execute('PRAGMA recursive_triggers=ON')
return db
@contextmanager
def _transaction(db, now):
# Never return permission whose commit belongs to an outer caller transaction.
if db.in_transaction:
raise ClaimError('a top-level committed transaction is required')
if type(now) is not int or now < 0:
raise ClaimError('now must be a nonnegative integer')
if any(db.execute(f'PRAGMA {name}').fetchone()[0] != 1
for name in ('foreign_keys', 'recursive_triggers')):
raise ClaimError('required SQLite guards are disabled')
try:
db.execute('BEGIN IMMEDIATE')
yield
db.commit()
except BaseException as error:
db.rollback()
if isinstance(error, sqlite3.Error):
raise ClaimError('claim transaction failed; no permission granted') from error
raise
def _snapshot(db, obligation_id, decision_id):
row = db.execute('''SELECT * FROM approval_bound_drafts
WHERE obligation_id=? AND decision_id=?''', (obligation_id, decision_id)).fetchone()
if row is None:
raise ClaimError('a current bound approved draft is required')
try:
digest = hashlib.sha256(row['draft_text'].encode('utf-8')).hexdigest()
except (AttributeError, UnicodeError) as error:
raise ClaimError('approved text must be valid UTF-8 text') from error
stored_digest = row['draft_sha256']
if (not isinstance(stored_digest, str) or len(stored_digest) != 64
or any(character not in '0123456789abcdef' for character in stored_digest)):
raise ClaimError('approved hash must be lowercase SHA-256 hexadecimal')
if not secrets.compare_digest(digest, stored_digest):
raise ClaimError('approved text hash does not match')
return dict(row)
def _claim_row(db, token):
if not isinstance(token, str) or not token:
raise ClaimError('a claim token is required')
row = db.execute('SELECT * FROM obligation_delivery_claims WHERE token=?', (token,)).fetchone()
if row is None:
raise ClaimError('unknown claim token')
return row
def claim(db, obligation_id, decision_id, *, now):
"""Reserve one already-authorized decision; return only a random claim token."""
with _transaction(db, now):
_snapshot(db, obligation_id, decision_id)
token = secrets.token_hex(32)
db.execute('''INSERT INTO obligation_delivery_claims
(obligation_id,decision_id,token,state,created_ts,updated_ts)
VALUES (?,?,?,'claimed',?,?)''', (obligation_id, decision_id, token, now, now))
return token
def begin_dispatch(db, token, *, now):
"""Return bound payload once, only after dispatching state has committed.
A crash after this boundary is uncertain even if transport has not started.
Do not cache/reuse this return value for another attempt.
"""
with _transaction(db, now):
row = _claim_row(db, token)
if row['state'] != 'claimed':
raise ClaimError('claim cannot grant another dispatch')
payload = _snapshot(db, row['obligation_id'], row['decision_id'])
changed = db.execute('''UPDATE obligation_delivery_claims SET state='dispatching',updated_ts=?
WHERE token=? AND state='claimed' ''', (now, token)).rowcount
if changed != 1:
raise ClaimError('dispatch transition lost')
return payload
def cancel(db, token, *, now):
"""Cancel only a not-yet-dispatched claim. Never reopen its decision key."""
with _transaction(db, now):
row = _claim_row(db, token)
if row['state'] != 'claimed':
raise ClaimError('only a pre-dispatch claim can be cancelled')
db.execute("UPDATE obligation_delivery_claims SET state='cancelled',updated_ts=? WHERE token=?",
(now, token))
def mark_unknown(db, token, *, now):
"""Record uncertainty, including a restarted worker's dispatching claim."""
with _transaction(db, now):
row = _claim_row(db, token)
if row['state'] == 'unknown':
return
if row['state'] != 'dispatching':
raise ClaimError('only a dispatched attempt can become unknown')
db.execute("UPDATE obligation_delivery_claims SET state='unknown',updated_ts=? WHERE token=?",
(now, token))
def _finish(db, token, coordinate, now, evidence):
if not isinstance(coordinate, str) or not coordinate.strip():
raise ClaimError('a confirmed nonempty coordinate is required')
with _transaction(db, now):
row = _claim_row(db, token)
receipt = db.execute('''SELECT * FROM obligation_deliveries
WHERE obligation_id=? AND decision_id=?''',
(row['obligation_id'], row['decision_id'])).fetchone()
if row['state'] == 'delivered':
if receipt is None or receipt['coordinate'] != coordinate or receipt['kind'] != 'draft_sent':
raise ClaimError('completion contradicts the existing receipt')
return False
expected_state = 'dispatching' if evidence is None else 'unknown'
if row['state'] != expected_state:
raise ClaimError('completion requires the correct dispatch/reconciliation state')
_snapshot(db, row['obligation_id'], row['decision_id'])
db.execute('''INSERT INTO obligation_deliveries
(obligation_id,decision_id,kind,coordinate,delivered_ts) VALUES (?,?,'draft_sent',?,?)''',
(row['obligation_id'], row['decision_id'], coordinate, now))
db.execute('''UPDATE obligation_delivery_claims
SET state='delivered',updated_ts=?,reconciliation_evidence=? WHERE token=?''',
(now, evidence, token))
changed = db.execute("UPDATE obligations SET status='sent' WHERE id=? AND status='approved'",
(row['obligation_id'],)).rowcount
if changed != 1:
raise ClaimError('obligation completion failed')
return True
def complete(db, token, coordinate, *, now):
"""Atomically record a confirmed result; identical duplicate completion is a no-op."""
return _finish(db, token, coordinate, now, None)
def reconcile(db, token, coordinate, evidence, *, now):
"""Trusted caller supplies verified outcome evidence; this does not verify it.
No cancellation/retry of unknown claims is provided: a paused original
executor could still act. Operator authentication is outside this reference.
"""
if not isinstance(evidence, str) or not evidence.strip():
raise ClaimError('trusted reconciliation evidence is required')
return _finish(db, token, coordinate, now, evidence)
references/approval-ledger.sql
-- Reference schema for the operator approval loop.
-- SQLite dialect; adapt types for other engines.
CREATE TABLE IF NOT EXISTS obligations (
id INTEGER PRIMARY KEY,
counterparty TEXT NOT NULL,
source TEXT NOT NULL, -- origin platform
channel TEXT NOT NULL,
direction TEXT NOT NULL, -- 'we_owe_them' | 'they_owe_us' | 'none'
status TEXT NOT NULL, -- 'open' | 'drafted' | 'approved' | 'rejected' | 'sent' | 'closed'
summary TEXT NOT NULL,
opened_ts INTEGER NOT NULL,
last_touch_ts INTEGER NOT NULL,
updated_at INTEGER NOT NULL -- decision epoch; advances on every re-file
);
-- Only one obligation may occupy a counterparty/channel draft queue at a time.
-- This is independent of delivery-claim uniqueness. Existing duplicate drafts
-- make schema application fail: stop startup and reconcile them explicitly before
-- retrying. Never delete, merge or change their status automatically on upgrade.
CREATE UNIQUE INDEX IF NOT EXISTS one_drafted_obligation_per_counterparty_channel
ON obligations(counterparty, channel) WHERE status='drafted';
-- Exact draft text plus origin coordinates. One per obligation; replaced on re-file.
CREATE TABLE IF NOT EXISTS obligation_drafts (
obligation_id INTEGER PRIMARY KEY REFERENCES obligations(id),
draft_text TEXT NOT NULL,
context TEXT,
origin_platform TEXT NOT NULL,
origin_channel TEXT NOT NULL,
origin_thread TEXT,
origin_user TEXT,
priority TEXT NOT NULL DEFAULT 'P2', -- P0..P3
draft_sha256 TEXT NOT NULL,
created_ts INTEGER NOT NULL,
updated_ts INTEGER NOT NULL,
auto_send_after INTEGER, -- NULL = hard gate
signal_obligation_id INTEGER REFERENCES obligations(id)
);
-- Operator (or auto-ttl) decisions, keyed to the draft epoch they were made against.
CREATE TABLE IF NOT EXISTS obligation_decisions (
id INTEGER PRIMARY KEY,
obligation_id INTEGER NOT NULL REFERENCES obligations(id),
decision TEXT NOT NULL CHECK (decision IN ('approve', 'reject')),
operator TEXT NOT NULL,
decided_ts INTEGER NOT NULL,
nonce TEXT NOT NULL UNIQUE,
draft_updated_ts INTEGER NOT NULL -- must equal obligations.updated_at to be valid
);
-- Completed receipts only. Uniqueness deduplicates rows, not external side effects.
CREATE TABLE IF NOT EXISTS obligation_deliveries (
id INTEGER PRIMARY KEY,
obligation_id INTEGER NOT NULL REFERENCES obligations(id),
decision_id INTEGER NOT NULL REFERENCES obligation_decisions(id),
kind TEXT NOT NULL CHECK (kind IN ('draft_sent', 'reject_notice', 'manual_notice')),
coordinate TEXT NOT NULL, -- where it landed: message id, email id, thread ts
delivered_ts INTEGER NOT NULL,
UNIQUE(obligation_id, decision_id)
);
-- Additive reference schema for NEW, already-authorized decisions. No legacy backfill.
-- Every connection must enable foreign_keys and recursive_triggers.
PRAGMA foreign_keys = ON;
PRAGMA recursive_triggers = ON;
-- Eligible current records are not authority by themselves: the trusted decision
-- writer must persist an approval snapshot in its decision transaction.
CREATE VIEW IF NOT EXISTS approval_current_drafts AS
SELECT dec.id AS decision_id, o.id AS obligation_id, o.updated_at AS draft_epoch,
d.draft_text, d.draft_sha256, d.origin_platform, d.origin_channel, d.origin_thread
FROM obligation_decisions dec
JOIN obligations o ON o.id=dec.obligation_id
JOIN obligation_drafts d ON d.obligation_id=o.id
WHERE dec.decision='approve' AND o.status='approved' AND o.direction='we_owe_them'
AND dec.draft_updated_ts=o.updated_at AND d.updated_ts=o.updated_at
AND o.source=d.origin_platform AND o.channel=d.origin_channel;
CREATE TABLE IF NOT EXISTS obligation_approval_snapshots (
decision_id INTEGER PRIMARY KEY REFERENCES obligation_decisions(id),
obligation_id INTEGER NOT NULL REFERENCES obligations(id),
draft_epoch INTEGER NOT NULL,
draft_text TEXT NOT NULL,
draft_sha256 TEXT NOT NULL,
origin_platform TEXT NOT NULL CHECK(length(trim(origin_platform))>0),
origin_channel TEXT NOT NULL CHECK(length(trim(origin_channel))>0),
origin_thread TEXT,
kind TEXT NOT NULL CHECK(kind='draft_sent'),
UNIQUE(obligation_id, decision_id)
);
CREATE TRIGGER IF NOT EXISTS approval_snapshot_insert BEFORE INSERT ON obligation_approval_snapshots
WHEN EXISTS (SELECT 1 FROM obligation_approval_snapshots WHERE decision_id=NEW.decision_id)
OR NOT EXISTS (
SELECT 1 FROM approval_current_drafts d
WHERE d.decision_id=NEW.decision_id AND d.obligation_id=NEW.obligation_id
AND d.draft_epoch=NEW.draft_epoch AND d.draft_text=NEW.draft_text
AND d.draft_sha256=NEW.draft_sha256 AND d.origin_platform=NEW.origin_platform
AND d.origin_channel=NEW.origin_channel AND d.origin_thread IS NEW.origin_thread)
BEGIN SELECT RAISE(ABORT,'approval snapshot must match a current authorized decision'); END;
CREATE TRIGGER IF NOT EXISTS approval_snapshot_update BEFORE UPDATE ON obligation_approval_snapshots
BEGIN SELECT RAISE(ABORT,'approval snapshots are immutable'); END;
CREATE TRIGGER IF NOT EXISTS approval_snapshot_delete BEFORE DELETE ON obligation_approval_snapshots
BEGIN SELECT RAISE(ABORT,'approval snapshots are immutable'); END;
CREATE VIEW IF NOT EXISTS approval_bound_drafts AS
SELECT s.* FROM obligation_approval_snapshots s
JOIN approval_current_drafts d ON d.decision_id=s.decision_id AND d.obligation_id=s.obligation_id
WHERE d.draft_epoch=s.draft_epoch AND d.draft_text=s.draft_text
AND d.draft_sha256=s.draft_sha256 AND d.origin_platform=s.origin_platform
AND d.origin_channel=s.origin_channel AND d.origin_thread IS s.origin_thread;
CREATE TABLE IF NOT EXISTS obligation_delivery_claims (
obligation_id INTEGER NOT NULL,
decision_id INTEGER NOT NULL,
token TEXT NOT NULL UNIQUE CHECK(length(token)>0),
state TEXT NOT NULL CHECK(state IN ('claimed','dispatching','unknown','delivered','cancelled')),
created_ts INTEGER NOT NULL CHECK(typeof(created_ts)='integer' AND created_ts>=0),
updated_ts INTEGER NOT NULL CHECK(typeof(updated_ts)='integer' AND updated_ts>=created_ts),
reconciliation_evidence TEXT,
PRIMARY KEY(obligation_id, decision_id),
FOREIGN KEY(obligation_id, decision_id)
REFERENCES obligation_approval_snapshots(obligation_id, decision_id)
);
CREATE UNIQUE INDEX IF NOT EXISTS one_active_claim_per_obligation
ON obligation_delivery_claims(obligation_id) WHERE state IN ('claimed','dispatching','unknown');
CREATE TRIGGER IF NOT EXISTS approval_claim_insert BEFORE INSERT ON obligation_delivery_claims
WHEN NEW.state!='claimed' OR NEW.reconciliation_evidence IS NOT NULL
OR EXISTS (SELECT 1 FROM obligation_delivery_claims
WHERE obligation_id=NEW.obligation_id AND decision_id=NEW.decision_id)
OR EXISTS (SELECT 1 FROM obligation_deliveries
WHERE obligation_id=NEW.obligation_id AND decision_id=NEW.decision_id)
OR NOT EXISTS (SELECT 1 FROM approval_bound_drafts
WHERE obligation_id=NEW.obligation_id AND decision_id=NEW.decision_id)
BEGIN SELECT RAISE(ABORT,'claim requires an unused bound approval'); END;
CREATE TRIGGER IF NOT EXISTS approval_claim_delete BEFORE DELETE ON obligation_delivery_claims
BEGIN SELECT RAISE(ABORT,'claims cannot be erased or reused'); END;
CREATE TRIGGER IF NOT EXISTS approval_claim_update BEFORE UPDATE ON obligation_delivery_claims
BEGIN
SELECT CASE WHEN NEW.obligation_id IS NOT OLD.obligation_id OR NEW.decision_id IS NOT OLD.decision_id
OR NEW.token IS NOT OLD.token OR NEW.created_ts IS NOT OLD.created_ts OR NEW.updated_ts<OLD.updated_ts
THEN RAISE(ABORT,'immutable claim identity or invalid clock') END;
SELECT CASE WHEN NOT (
(OLD.state='claimed' AND NEW.state IN ('dispatching','cancelled')) OR
(OLD.state='dispatching' AND NEW.state IN ('unknown','delivered')) OR
(OLD.state='unknown' AND NEW.state='delivered'))
THEN RAISE(ABORT,'claim transition forbidden') END;
SELECT CASE WHEN OLD.state='unknown' AND NEW.state='delivered'
AND (NEW.reconciliation_evidence IS NULL OR length(trim(NEW.reconciliation_evidence))=0)
THEN RAISE(ABORT,'reconciliation evidence required') END;
SELECT CASE WHEN NOT (OLD.state='unknown' AND NEW.state='delivered')
AND NEW.reconciliation_evidence IS NOT OLD.reconciliation_evidence
THEN RAISE(ABORT,'evidence only belongs to reconciliation') END;
SELECT CASE WHEN NEW.state='dispatching' AND NOT EXISTS (
SELECT 1 FROM approval_bound_drafts WHERE obligation_id=NEW.obligation_id AND decision_id=NEW.decision_id)
THEN RAISE(ABORT,'approval binding changed') END;
SELECT CASE WHEN NEW.state='delivered' AND NOT EXISTS (
SELECT 1 FROM obligation_deliveries WHERE obligation_id=NEW.obligation_id AND decision_id=NEW.decision_id
AND kind='draft_sent' AND length(trim(coordinate))>0 AND delivered_ts=NEW.updated_ts)
THEN RAISE(ABORT,'confirmed receipt required') END;
END;
-- Legacy receipts remain readable/importable when there is no claim. The
-- reference cannot claim an already receipted decision. Claimed receipts are immutable.
CREATE TRIGGER IF NOT EXISTS claimed_receipt_insert BEFORE INSERT ON obligation_deliveries
WHEN EXISTS (SELECT 1 FROM obligation_delivery_claims WHERE obligation_id=NEW.obligation_id)
AND (NEW.kind!='draft_sent' OR length(trim(NEW.coordinate))=0 OR NOT EXISTS (
SELECT 1 FROM obligation_delivery_claims WHERE obligation_id=NEW.obligation_id
AND decision_id=NEW.decision_id AND state IN ('dispatching','unknown'))
OR EXISTS (SELECT 1 FROM obligation_deliveries
WHERE id=NEW.id OR (obligation_id=NEW.obligation_id AND decision_id=NEW.decision_id)))
BEGIN SELECT RAISE(ABORT,'receipt requires a matching dispatched claim'); END;
CREATE TRIGGER IF NOT EXISTS claimed_receipt_update BEFORE UPDATE ON obligation_deliveries
WHEN EXISTS (SELECT 1 FROM obligation_delivery_claims
WHERE obligation_id IN (OLD.obligation_id,NEW.obligation_id))
BEGIN SELECT RAISE(ABORT,'claimed receipts are immutable'); END;
CREATE TRIGGER IF NOT EXISTS claimed_receipt_delete BEFORE DELETE ON obligation_deliveries
WHEN EXISTS (SELECT 1 FROM obligation_delivery_claims WHERE obligation_id=OLD.obligation_id)
BEGIN SELECT RAISE(ABORT,'claimed receipts are immutable'); END;
-- All writers must preserve active approval binding, including INSERT OR REPLACE.
CREATE TRIGGER IF NOT EXISTS freeze_obligations_insert BEFORE INSERT ON obligations
WHEN EXISTS (SELECT 1 FROM obligation_delivery_claims
WHERE obligation_id IN (NEW.id) AND state IN ('claimed','dispatching','unknown'))
BEGIN SELECT RAISE(ABORT,'active claim freezes approval records'); END;
CREATE TRIGGER IF NOT EXISTS freeze_obligations_update BEFORE UPDATE ON obligations
WHEN EXISTS (SELECT 1 FROM obligation_delivery_claims
WHERE obligation_id IN (OLD.id,NEW.id) AND state IN ('claimed','dispatching','unknown'))
BEGIN SELECT RAISE(ABORT,'active claim freezes approval records'); END;
CREATE TRIGGER IF NOT EXISTS freeze_obligations_delete BEFORE DELETE ON obligations
WHEN EXISTS (SELECT 1 FROM obligation_delivery_claims
WHERE obligation_id IN (OLD.id) AND state IN ('claimed','dispatching','unknown'))
BEGIN SELECT RAISE(ABORT,'active claim freezes approval records'); END;
CREATE TRIGGER IF NOT EXISTS freeze_obligation_drafts_insert BEFORE INSERT ON obligation_drafts
WHEN EXISTS (SELECT 1 FROM obligation_delivery_claims
WHERE obligation_id IN (NEW.obligation_id) AND state IN ('claimed','dispatching','unknown'))
BEGIN SELECT RAISE(ABORT,'active claim freezes approval records'); END;
CREATE TRIGGER IF NOT EXISTS freeze_obligation_drafts_update BEFORE UPDATE ON obligation_drafts
WHEN EXISTS (SELECT 1 FROM obligation_delivery_claims
WHERE obligation_id IN (OLD.obligation_id,NEW.obligation_id) AND state IN ('claimed','dispatching','unknown'))
BEGIN SELECT RAISE(ABORT,'active claim freezes approval records'); END;
CREATE TRIGGER IF NOT EXISTS freeze_obligation_drafts_delete BEFORE DELETE ON obligation_drafts
WHEN EXISTS (SELECT 1 FROM obligation_delivery_claims
WHERE obligation_id IN (OLD.obligation_id) AND state IN ('claimed','dispatching','unknown'))
BEGIN SELECT RAISE(ABORT,'active claim freezes approval records'); END;
CREATE TRIGGER IF NOT EXISTS freeze_obligation_decisions_insert BEFORE INSERT ON obligation_decisions
WHEN EXISTS (SELECT 1 FROM obligation_delivery_claims
WHERE obligation_id IN (NEW.obligation_id) AND state IN ('claimed','dispatching','unknown'))
BEGIN SELECT RAISE(ABORT,'active claim freezes approval records'); END;
CREATE TRIGGER IF NOT EXISTS freeze_obligation_decisions_update BEFORE UPDATE ON obligation_decisions
WHEN EXISTS (SELECT 1 FROM obligation_delivery_claims
WHERE obligation_id IN (OLD.obligation_id,NEW.obligation_id) AND state IN ('claimed','dispatching','unknown'))
BEGIN SELECT RAISE(ABORT,'active claim freezes approval records'); END;
CREATE TRIGGER IF NOT EXISTS freeze_obligation_decisions_delete BEFORE DELETE ON obligation_decisions
WHEN EXISTS (SELECT 1 FROM obligation_delivery_claims
WHERE obligation_id IN (OLD.obligation_id) AND state IN ('claimed','dispatching','unknown'))
BEGIN SELECT RAISE(ABORT,'active claim freezes approval records'); END;
-- Candidate discovery grants no dispatch permission. claim() validates the hash
-- and reserves in BEGIN IMMEDIATE; begin_dispatch() must then win its own CAS.
-- SELECT b.obligation_id,b.decision_id FROM approval_bound_drafts b
-- WHERE NOT EXISTS (SELECT 1 FROM obligation_delivery_claims c
-- WHERE c.obligation_id=b.obligation_id AND
-- (c.decision_id=b.decision_id OR c.state IN ('claimed','dispatching','unknown')))
-- AND NOT EXISTS (SELECT 1 FROM obligation_deliveries r
-- WHERE r.obligation_id=b.obligation_id AND r.decision_id=b.decision_id);
-- claimed -> dispatching | cancelled; dispatching -> delivered | unknown;
-- unknown -> delivered by explicit reconciliation only. No expiry or retry.
SKILL.md
---
name: operator-approval-loop
description: Operator approval contract with internal filing notices for agent-drafted outbound messages, hashed drafts, epoch-keyed decisions, durable delivery claims and receipts, and a pre-draft baseline gate. Use when an agent drafts messages to external counterparties and a human operator must approve, reject, or steer each send before it leaves.
---
# Operator Approval Loop
An agent that talks to external counterparties should never send on its own
judgment and should keep the operator informed internally. This skill defines
the contract: every outbound draft is filed as an obligation, an operator
decides on the exact text, and a delivery ledger proves what went out.
## When to Use
- An agent drafts replies to customers, suppliers, investors, or partners in
a shared channel, email, or chat, and a human must approve before send.
- You need an audit trail that links each sent message to the exact draft
text, the operator who approved it, and the decision time.
- You have seen a stale approval release a rewritten draft, or two workers
deliver the same approved message twice.
- Drafts keep re-asking counterparties for facts the ledger already holds.
## How It Works
### Objects
| Object | Meaning |
| --- | --- |
| Obligation | One thing we owe a counterparty. Status moves `drafted`, then `approved` or `rejected`, then `sent`. Carries `direction`, `counterparty`, `channel`, and an `updated_at` epoch. |
| Draft | Sidecar row holding the exact draft text, a sha256 of that text, origin coordinates (platform, channel, thread, user), and priority (P0 to P3). One per obligation, replaced on re-file. |
| Decision | An operator's approve or reject, recorded with the operator id, a nonce, and the draft epoch it was made against. |
| Approval snapshot | Immutable text, hash, epoch and destination recorded by the already-authorized decision writer. Missing snapshots cannot grant dispatch. |
| Claim | Durable reservation with a random token and state; at most one active claim per obligation. |
| Delivery | Ledger row proving one send or notice for one (obligation, decision) pair. |
The reference schema is in [references/approval-ledger.sql](references/approval-ledger.sql).
### Filing a draft
1. Clean inputs. Strip control characters, collapse whitespace in single-line
fields, and enforce length caps (draft, summary, context, counterparty).
Empty or oversized fields are refused, not truncated silently.
2. Run the baseline gate (below). It may refuse the filing.
3. Hash the draft text with sha256. The hash prefix goes into the summary so
the approval panel shows which text it is approving.
4. Upsert. If an open drafted obligation already exists for the same
(counterparty, channel), replace the draft sidecar and advance the
obligation's `updated_at`. That advance is the epoch rotation: any
decision keyed to the old epoch can no longer release the new text.
Otherwise insert a new obligation with status `drafted`.
5. Route the filing receipt only to a configured, verified internal ops
destination. If the origin is that internal destination, acknowledge there.
Never-silent means internal reporting, not an automatic external reply.
Keep draft hashes, approval status, operator identity and workflow metadata
out of counterparty-visible channels. Unknown or unclassified origins stay
quiet; a direct message is not automatically internal.
If a verified internal destination is unavailable, retain the filing result
in the internal tool result or operator surface. Never fall back to an external
or unknown origin. A tool result exposed to outsiders is not an internal surface.
Filing a draft does not authorize an external response. Any policy-permitted
clarifying question or neutral response is a separate outbound decision, subject
to the existing mention, channel, draft-only, frozen and never constraints in
counterparty-channel-discipline. It must not disclose internal approval metadata.
### Baseline gate
Before any draft is filed, query the current baseline for the counterparty
(a temporal ledger, contract store, or CRM):
- Signed or delivered contract on record: refuse the filing with the evidence
and a recommendation. Asking a counterparty about specs after signing is the
exact failure this gate exists to stop.
- Operator override: `force_despite_signed_contract` lets the filing through
and stamps `[BASELINE_OVERRIDE_SIGNED_CONTRACT]` into the draft context.
- Gate service unreachable: the filing proceeds and the context is stamped
`[BASELINE_CHECK_UNAVAILABLE]`. The panel sees that the guard was off.
Failures never silently disable the gate.
- When facts are available, attach the freshest few to the context as a
`[BASELINE FACTS: ...]` digest so the draft lands with current truth.
### Deciding
The approval panel lists obligations with status `drafted` and direction
`we_owe_them`. Approve or reject writes a decision row carrying the draft
epoch (`draft_updated_ts`) and flips the obligation status in the same
transaction. A decision whose epoch does not match the current `updated_at`
is stale and must not release anything.
For an already-authorized approve decision, the same transaction inserts an
immutable `obligation_approval_snapshots` row: decision and obligation IDs,
current draft epoch, exact text and SHA-256, platform/channel/thread, and kind
`draft_sent`. The decision writer must establish authorization before writing;
the reference never authenticates an operator or manufactures a decision.
Automatic approval policy is not enabled or expanded by the reference.
Legacy decisions without snapshots require explicit reconciliation or a new
approval; never backfill permission from the current mutable draft.
### Delivering
The SQLite reference is [references/approval_claims.py](references/approval_claims.py).
It grants dispatch permission but never calls transport. Use an existing local
reference database initialized from the SQL fixture; the module does not apply
schema or production migrations. Only a trusted decision writer may populate
approval records. All writers must enable foreign keys and recursive triggers
and honor the schema guards; administrative database tampering is outside this model.
1. Discover bound approved drafts. Discovery is not permission. `claim()` opens
its own `BEGIN IMMEDIATE` transaction, validates the current approved epoch,
exact text, computed SHA-256 and full destination against the snapshot, and
inserts a unique claim before returning its token. A conflict stops the worker
before transport. Completed receipts cannot be claimed again.
2. `begin_dispatch()` revalidates the binding and atomically changes `claimed`
to `dispatching` using the token. Only its winning caller receives
the exact `draft_text` and destination after commit. Never regenerate text, reread a
mutable sidecar for transport, or reuse the payload for another attempt.
A nested caller transaction is refused; permission cannot depend on a later
caller commit. No database transaction remains open across transport.
3. A confirmed successful result goes to `complete()`, which atomically records
the delivery coordinate, marks the claim delivered and flips the obligation
to `sent`. Identical completion is a no-op; conflicting coordinates fail.
The receipt UNIQUE key deduplicates records, not prior external effects.
4. Exceptions, timeouts, worker death after begin-dispatch, or failed receipt
persistence leave a blocked attempt. `mark_unknown()` records uncertainty.
Unknown claims never expire, reopen, auto-retry or allow another decision for
that obligation to bypass them. A trusted caller may use `reconcile()` with
confirmed successful coordinate and evidence; the module does not verify
that evidence. An absent receipt is not proof of non-delivery.
The guarantee is one automatic dispatch attempt per approved decision, not
exactly-once external delivery. A crash after begin-dispatch but before transport
can leave zero sends and a held claim. Releasing an unknown outcome for a new
attempt would require fencing the original executor and verifying provider
semantics; this reference deliberately provides no such retry operation.
| Claim state | Allowed next states |
| --- | --- |
| claimed | dispatching or cancelled before dispatch |
| dispatching | delivered or unknown |
| unknown | delivered through trusted reconciliation only |
| delivered, cancelled | terminal; decision key cannot be reused |
While a claim is active, database guards freeze obligation, draft and decision
writes, including replacements. Snapshots and claims cannot be erased. Cancel a
claimed operation with its token before re-filing; the stale token then grants
nothing. After dispatch begins, hold new edits or revocation for reconciliation.
This serializes changes instead of pretending to recall an in-flight operation.
Rejected decisions and legacy rows without draft sidecars/snapshots never enter
this external draft-send path. Report them on the internal operator surface for
manual handling. Internal receipt footers remain internal:
`approved by <operator> · receipt <decision_id> · draft sha256 <prefix>`.
Never alter already-approved external text to append workflow metadata.
Focused local validation uses temporary databases, separate connections and a
simulated attempt counter, not a provider or real message:
`python3 -m unittest discover -s tests/skills -p 'test_approval_delivery_claims.py'`.
The tests require Python 3.11+ with SQLite serialization support; the reference
uses only the standard library. The existing desk-pattern contract checks remain
a separate compatibility check.
### Time-boxed auto-approval (optional)
A draft may carry `auto_send_after` (epoch seconds). A sweep approves drafts
whose deadline passed with no decision, recording operator `auto-ttl`, then
delivery proceeds through the normal path. Operator actions always win: a
decision flips status before the sweep sees it, and a re-file rotates the
epoch and moves or clears the deadline. The sweep re-checks status and epoch
inside the write transaction so a race resolves as a no-op. Drafts without a
deadline stay hard-gated forever.
### Signal linkage
A draft can name the inbound obligation it answers (`signal_obligation_id`).
This is the only truthful link for latency measurement (inbound signal to
drafted response) and lets the SLA scan treat that inbound item as answered.
Reject the filing if the referenced row does not exist.
## Examples
### File a draft
```text
file_request(
draft="Thanks, we can hold the slot until Friday. Which start date works?",
counterparty="acme-supplier",
context="reply to delivery window question",
origin_platform="slack", origin_channel="#acme-shared",
origin_thread="1712345678.000100", priority="P1",
signal_obligation_id=412)
-> {obligation_id: 431, draft_sha256: "9f2c...", refiled: false}
```
The configured, verified internal ops destination sees:
`Draft filed for approval (P1, sha 9f2c8a1b). Waiting on operator.`
The counterparty-visible origin channel receives no filing notice. If no verified
internal destination is available, the receipt stays in the internal tool result
or operator surface, with no external fallback.
### Re-file after a steer
The operator asks for a shorter draft. Filing again for the same
(counterparty, channel) returns `refiled: true`, the sidecar text and hash
change, and `updated_at` advances. An approve clicked on the old panel row
carries the old epoch and is ignored.
### Gate refusal
```text
DeskApprovalError: baseline gate refused this draft: the ledger shows a
signed contract for 'acme-supplier'. Evidence: master agreement executed
2026-08-14. Recommendation: do not ask. Re-file with
force_despite_signed_contract=true if this is genuinely a new thread.
```
### Delivery footer in an internal channel
```text
Confirmed for Friday, start date 2026-09-08.
approved by operator-a · receipt 118 · draft sha256 9f2c8a1b2d3e4f50
```
## Invariants to test
- Filing receipts go only to configured, verified internal ops; the origin
receives one only when it is that verified internal destination.
- An unknown origin stays quiet. An unavailable internal destination uses the
internal tool result or operator surface, with no external fallback.
- Same (counterparty, channel) filed twice yields one obligation, two epochs.
- A decision with a stale epoch never results in a delivery row.
- Two concurrent claimants yield one dispatch permission; losers never attempt transport.
- Unknown outcomes and failed receipt persistence never enable an automatic retry.
- Successful completion records the receipt and sent status in one transaction.
- An altered epoch, text, hash or destination cannot acquire or begin a claim.
- Active claims block re-file; only pre-dispatch cancellation can release that hold.
- Gate unavailable stamps the marker; gate signed refuses without force.
- Auto-ttl never fires against text the operator has since re-filed.