Where the work is recorded
Status doesn't live in a chat.
It propagates.
Every meaningful thing the ring does is recorded somewhere durable, then radiated outward to the places humans look: the shared database is the system of record; Loop carries the human-readable status; Azure DevOps holds the backlog truth; Teams carries the pings. This page traces each surface — and is candid about which links are wired today and which are still aspirational.
The shape of it
One source of truth, four surfaces
The Postgres database is the only place that is the truth. Loop, ADO and Teams are projections of it — convenient windows for humans. Nothing is "logged to Loop" as a primary record; Loop reflects a row that already exists in the database.
Surface 1 — the database
The system of record wired
Every brief, decision, risk, comms draft and prep doc is a row in the
haleon schema before it is anything else. Status is a column, not a message:
a comms draft sits at awaiting_signoff; an ADR's status is one of
proposed → accepted → superseded/rejected (the finer Reviewer/Compliance lifecycle
stages are a procedural workflow, not values of adrs.status — see
Open Issues); a write-back op carries an
explicit status enum. Because the row exists first, the audit trail is
a side-effect of doing the work, not a separate logging step.
Why a database and not a log file? A log is append-only narration; a row is
queryable state. The ring can ask "what is still awaiting_signoff?"
or "which ADRs are proposed but not accepted?" — questions a chat
transcript can't answer.
Surface 2 — Loop
Human-readable status to Loop partial
Loop is where Charlie's wider audience reads status in prose. It is a Chief-of-Staff function, tied to briefs and ceremony prep documents — not a standalone "Loop logger" agent. The database backs the link directly:
briefs.delivered_to_loopmeeting_preps.loop_page_urlpd_sync_preps.loop_page_urlsteerco_preps.loop_page_url
So "status to Loop" means the CoS writing brief/prep content and flagging delivery — not a
separate heartbeat. The exact firing cadence lives in the daily-brief and prep
skill files; confirm there before relying on it.
Two operational caveats. (1) The Loop sandbox page in use for the current shakedown is reached by an access-bearing tokenised link; it is configured per-environment and is deliberately not reproduced anywhere in this documentation — get it from Charlie or the CoS handoff ledger. (2) Charlie's corporate network blocks Loop's Fluid Framework sync, so Loop writes may need a non-corporate network or phone tether to save.
Surface 3 — Azure DevOps
The ADO write-back queue enqueue wired drain built
The ring keeps ADO up to date through an enqueue-then-drain pattern rather than writing to
the board directly: any agent that wants to change a work item appends an operation to a queue table at
pending_approval; Charlie's approval flips it to queued; the ado-scribe
drainer (built Batch 2) consumes only queued rows and applies them to ADO via the
wit_* MCP tools, advancing each row through the CAS-guarded
sp_update_ado_writeback state machine.
The enqueue path fully built & proven
A write travels:
DAB entity AdoWritebackIn → view haleon.v_ado_writeback_in →
INSTEAD OF INSERT trigger → haleon.sp_create_ado_writeback(…) →
INSERT into the queue at status='pending_approval' (gate-by-default) with
ON CONFLICT (idempotency_key) DO NOTHING.
-- one row per pending ADO change (idempotency_key UNIQUE) id uuid -- gen_random_uuid() idempotency_key text -- UNIQUE → ON CONFLICT DO NOTHING target_work_item_id bigint operation text -- e.g. add-comment, set-state payload jsonb -- the change body; left UNCHANGED on status-only updates status ado_writeback_status -- enum, DEFAULT 'pending_approval' -- = {pending_approval, queued, in_flight, committed, failed} attempts int -- incremented on *→in_flight; cap=5 last_attempt_at timestamptz last_error text -- cleared on failed→queued retry as hygiene committed_at timestamptz approved_by text -- set on pending_approval→queued (Charlie); RAISE if NULL approved_at timestamptz enqueued_by_agent text -- INDEX idx_ado_q_status (status, enqueued_at) ← drives drainer FIFO
decision-capture on a ratified ADR with linked work items)ado-bulk-triage sweep enqueues recommended state changes in bulk, all at pending_approvalazure_devops MCP project — single source of truth for org/project/area path (ado-bulk-triage and ado-scribe no longer hardcode a target, ISS-05 resolved). Currently smccormick0886/Haleon-AIAQ; the pointer is environment config.The drain path built Batch 2
The ado-scribe drainer is live as an on-demand CoS skill;
its 15-minute cadence is the declared intent for core-tick step 4 and will activate when Charlie
enables the recurring ring-tick timer. One tick acquires the single-holder drainer_lease
(re-entrant same-holder CAS; renew at TTL/2; abort immediately on lost re-acquire), reclassifies
failed rows (transient → re-queue capped at MAX_ATTEMPTS=5; permanent → dead-letter;
rescue via sp_reset_ado_writeback), reconciles stale in_flight against ADO using an
invisible <!-- idk:KEY --> marker (required for every op — field-set AND add-comment — so an
external setter can't produce a false commit), selects queued with per-target serialisation, claims
queued → in_flight → committed/failed via CAS-guarded UPDATE. A lost CAS race returns no row =
silent skip, never a double-write.
Charlie's approval is now DB-backed, not "absence of a drainer." A row lands at
pending_approval; Charlie's approval flips it to queued (sets
approved_by + approved_at; sp_update_ado_writeback RAISEs if
approved_by is NULL on that transition). The drainer consumes only queued — it
cannot touch pending_approval. The gate is auditable, not implicit (ISS-11 D3 resolved).
Surface 4 — Teams & the internal audit
Acks, briefs, and the agent_runs trail
Teams partial
Teams carries the pings: the twice-daily 5-3-2-1 brief lands as a DM, and Charlie acks rotations over Teams DM. The exact relay/bot implementation is owned outside the Steward's view and should be confirmed with Charlie before documenting its mechanics.
agent_runs built
The internal audit trail: one required row per meaningful turn, with a
7-member class discriminator (CHECK constraint agent_runs_class_check:
{turn, rotation, snapshot, ado_drain, audit, correction, scout_sweep}) plus
detail_ref and a (session_id, session_turn_seq) gap-detection key (partial UNIQUE).
Multi-writer — every role writes its own runs; the Steward audits (gap-scan,
open-run scan via v_open_agent_runs, cross-ref check for class IN ('rotation','snapshot'),
proxy-authorship scan on created_by_agent <> agent_name). Corrections are appends
(class='correction' pointing at the bad row via detail_ref), never in-place
rewrites. Seq allocation is auto-allocated via sp_next_session_turn_seq under
pg_advisory_xact_lock.
Surface 5 — Scouts & the cadence substrate
Scout audit footprint & the 3-greens DB gate built recurring schedule deferred
When ring-tick's recurring cadence is enabled (Charlie's posture call), each
scout-sweep tick spawns up to five scouts under a shared scout_lease. Every scout
writes its own two-phase agent_runs row with class='scout_sweep', enqueues observations
to signals through the idempotent sp_create_signal (K1: never NULL, never 23505;
partial unique index signals_source_extid_uq is the DB-side backstop), and advances its watermark
via ScoutWatermarkIn only after every enqueue in the unit-of-progress succeeds.
sp_check_scout_enabled() reads scout_enable_flags and returns enabled = cost_breaker_live AND drain_proven AND scout_proven. Every scout pre-checks via ScoutEnabledCheckIn at step 0 and aborts if red — audit row closes success=true, skipped_reason='scout-gate-red:<flag>'. Programmatic; not prose.tick_lease (Job A core-tick), drainer_lease (nested under A, owned by ado-scribe), scout_lease (Job B). Re-entrant same-holder CAS; per-instance token (never a constant); TTL-expiry steal; abort-on-lost-renewal.sp_check_cost_breaker(today, baseline, band) reads today's UTC-day rollup (calls sp_rollup_cost_day(today, 2) first — B3 fix, no more structurally-cold $0) AND sp_check_cost_breaker_rolling(24, baseline, band) sums overlapping cells across the rolling 24h window (m7 fix — UK-evening UTC-day-boundary split). EITHER tripping disables the sweep. Baseline = $50/day ±20% → $60/day ceiling (Charlie's tunable starting guess; no hard budget for this engagement).OpenAgentRun (DAB read-view over v_open_agent_runs — completed_at IS NULL AND spawned_at < now() - interval '15 min') and writes class='audit' findings with triggered_by = 'open:'||session_id||':'||session_turn_seq. An open run is a degradation signal — the spawn row exists (gap-scan green) but completion never landed.scout_watermark holds last_scanned_at + last_watermark_ref per source key (signal-scout, backlog-sentinel, pipeline-watcher, reuse-scout, intake-triage). Reuse Scout and Intake Triage use a single shared watermark per source for v1; per-handler sub-keys are a deferred K-extension.Recurring schedule status. All three greens are earned in DB-substrate terms
(cost breaker arms, drain proven manually, Signal Scout proven Unit J 30 May 2026). But
sp_check_scout_enabled() still returns enabled=false because Charlie hasn't flipped
the three ScoutEnableFlagsIn booleans (one at a time, for per-green audit attribution) — and
enabling the recurring 15-min / 2h timer is a separate second posture call. Until both, the ring is
on-demand only.
Be honest about the gaps
What is not wired yet
The ADO write-back drain is built (Batch 2). The ado-scribe skill is a
lease-guarded drainer that reads queued rows, applies them to ADO via the wit_* MCP
tools and advances their status through CAS-guarded sp_update_ado_writeback (legal arc:
queued→in_flight→committed|failed; failed→queued retry capped at 5;
committed is terminal). Dead-lettered rows can be rescued back to pending_approval
via sp_reset_ado_writeback. Manual today; 15-min cadence wires in via core-tick when
Charlie's posture call enables the recurring schedule.
The Steward's audit trail is now DB-backed (Batch 3, D4). Dedicated
rotation_log and agent_snapshots tables exist and are wired: the
rotate-role skill (workflow.json-driven; old rotate-clawpilot-role is a deprecated
shim) writes a rotation record + snapshot on each handover, and an agent_runs spine row
(class='rotation') cross-references them via detail_ref in detail-row-first
order (Step 9b, HS-4): the detail rows are INSERTed first, ids captured, then the spine row INSERTs
with detail_ref already populated. Completion-fill (sp_update_agent_run) never
touches detail_ref — it is immutable post-INSERT; corrections are appends
(class='correction'), never in-place rewrites. plan.md remains the human-readable
ledger; the DB is the system-of-record.
Cost telemetry is now wired (Batch 3, D4; HS-5/HS-6/HS-10 hardened, Batch 5).
sp_rollup_cost_telemetry aggregates agent_runs token counts per agent into
cost_telemetry on idempotent whole-UTC-day grid cells (overlap-proof; non-grid windows RAISE
22023; serialised by pg_advisory_xact_lock). The rollup excludes
class IN ('audit','correction') AND any row that has been corrected (a later
class='correction' row points at it via detail_ref), so writing corrections is
structurally safe — they do not inflate cost cells. 'scout_sweep' rows are included in cost cells
like 'turn'. core-tick step 5 calls the rollup on a rolling 2-day window
(today-1 AND today) every tick to recapture late-arriving completions. estimated_cost_usd uses
published list-price per-model rates; real contract rates are unavailable for this engagement, so these are
accepted as the permanent basis — a directional trend signal, not an invoice.
The ring-tick is built and staged; the recurring schedule is deferred to Charlie. The
tick mechanics exist and are verified — core-tick (health/drain/cost-rollup, 15-min, on
tick_lease) and scout-sweep (5 scouts, 2-hourly, on scout_lease,
caged behind the 3-greens DB gate + dual cost circuit-breakers + spawn ceiling + watermark + wall-clock
caps) — wired in the ring-tick skill. The recurring schedule itself is intentionally off:
enabling it is a Charlie posture call gated on three greens (breaker live, drain proven, Signal Scout
proven — all earned in DB-substrate terms as of 30 May 2026 but the booleans aren't flipped). Until then
the ring is invoked on demand — see Roadmap.