Historic / archived. This page is preserved as a record of the Batch 1–4 fix campaign (29–30 May 2026). All 22 ISS items below resolved through Batches 1–6; Batch 5–7 closure (hot-spot fixes, divergences, scout build-out) lives on Roadmap. Where resolution paragraphs reference the old rotate-clawpilot-role skill, the live skill is now generic rotate-role (workflow.json-driven; old name is a deprecated forwarding shim).

Where the plan and reality disagree

Open issues & fix list.

The rest of this site documents how the ring is meant to work and, honestly, how much of it actually runs today. This page pulls every one of those gaps into a single worklist: bugs where the code and the schema contradict each other, paths that are designed but not yet wired, configuration that points somewhere other than the docs claim, and decisions that are still open. It is built to be handed straight to the Chief of Staff as a backlog.

How to read this. Every item is verified — cross-checked against the on-disk SQL DDL and confirmed live by the CoS and Steward sessions on 29 May 2026. Nothing here is speculation. Each entry states the symptom, the evidence, a proposed fix, and where in the repo to make it.

The whole list at a glance

Worklist

Priority is about correctness risk, not effort. P0 means the system is silently doing the wrong thing right now. P1 means a documented capability simply does not run. P2 means hygiene or a decision that can wait. Legend for type: bug code vs schema contradict · gap designed, not wired · discrepancy config vs intent · deferred intentionally past the MVP · question needs a decision.

Three kinds of mismatch. After reconciling against the original build plan, the items below sort into three buckets: bug/gap — something is genuinely wrong or unbuilt; discrepancy — the running config drifted from the plan or the docs; and deferred — the plan deliberately pushed it past the MVP, so it's a known, intentional absence rather than a defect. See Plan vs. Reality for the full scorecard.

IDAreaIssueTypePriority
ISS-01ADO + commsdraft_pending_charlie is written to both the ADO queue and comms_drafts, but it's in neither enumresolvedP0
ISS-01bADO write-backCreate-path hardcodes queued, overriding the pending_approval default — enqueues without explicit status skip the approval gateresolvedP0
ISS-02ADO write-backThe drain path now exists — the ado-scribe drainer consumes queued rows and applies them to ADOresolvedP1
ISS-03ADO write-backNo sp_update_ado_writeback — no supported way to advance statusresolvedP1
ISS-04Skills"ADO Scribe" now has a real SKILL.md — the lease-guarded drainer that consumes only queued rows and applies them to ADOresolvedP2
ISS-05ADO configThe ADO target is now configurable via the azure_devops MCP (single source of truth); the skill no longer hardcodes a targetresolvedP1
ISS-06AuditEvery role now writes a required agent_runs spine row per meaningful turn (class discriminator + session_turn_seq gap-detection); multi-writer, Steward auditsresolvedP1
ISS-07Telemetrycost_telemetry now populated by sp_rollup_cost_telemetry (idempotent whole-UTC-day grid cells), wired into daily-briefresolvedP2
ISS-08Rotationrotation_log table built + wired — the rotation skill now writes a DB handover record each rotationresolvedP2
ISS-09Snapshotsagent_snapshots table built + wired — snapshots now have a dedicated home (transcript_id soft-ref kept)resolvedP2
ISS-10SchedulingTick cadence built & staged — core-tick (health/drain/rollup, 15-min, tick_lease) split from scout-sweep (Signal Scout, 2h, hard caps + cost breaker); live schedule deferred to Charlie (posture call)resolvedP2
ISS-11DecisionShould the Charlie gate stay procedural, or become a DB-backed approval flag?resolvedP1
ISS-12DecisionDecided (D4): build all — cost_telemetry producer, rotation_log and agent_snapshots all builtresolvedP2
ISS-13Briefsslot=evening is not in the brief_slot enum — the EOD brief slot is silently wrongresolvedP0
ISS-14Decisionsdecisions now carries routing columns (decision_class, adr_id, narrative, owning_peer) — routing is queryable data, not just a procedural conventionresolvedP1
ISS-15Auditagent_runs formally documented as multi-writer with a class discriminator; Steward audits (gap-scan + cross-ref), not exclusive authorresolvedP2
ISS-16Decisionsdecision-capture remapped to the real entities/columns — decision_class, adr_id, narrative, owning_peer now exist (ISS-14); no nonexistent-column writes remainresolvedP1
ISS-17SkillsThe cowork skill (7th on disk) is now documented in the skill matrix as a non-delivery utility skillresolvedP2
ISS-18DecisionsWrite-shims built for Adr + ComplianceState (v_adr_in/sp_create_adr/sp_update_adr, v_compliance_state_in/sp_create_compliance_state) — ADR & compliance work persists through the normal patternresolvedP1
ISS-19Decisionsadrs now has a review_stage column (draft → reviewed → compliance-checked → ratified) — an advanceable, DB-backed gate axis distinct from statusresolvedP1
ISS-20Schema opsShim drift is now tracked — schema_version records each bundle's name + SHA256 checksum (sp_record_migration); a checksum mismatch flags drift on re-applyresolvedP2
ISS-21MCP configm365-softeria MCP removed — the ring uses native m365_* (a builtin, not an MCP), so only the unused extended-Graph surface was dropped; reversibleresolvedP2
ISS-22DB permsAnonymous role tightened to least-privilege — every base table is now read-only (writes flow solely through the validating *In shims); the dead enum/jsonb create grants were revoked; authenticated=* documented as the dormant production postureresolvedP2

Dependency order matters. ISS-01 and ISS-11 decide the semantics of the queue; ISS-03 (the update function) and ISS-02 (the drainer) implement them. Settle the two decisions before building the drainer, or you will build against a status model that is about to change.

Code and schema contradict each other

Bugs

ISS-01 draft_pending_charlie is not a valid status value resolved P0

Resolution
RESOLVED — both halves. Comms: the ado-bulk-triage skill now writes the existing awaiting_signoff to comms_drafts (no DDL needed), and the CoS role brief's comms_draft_status vocabulary was corrected. ADO queue (per decision D3, which resolves ISS-11 toward a DB-backed approval): the Steward applied ALTER TYPE ado_writeback_status ADD VALUE 'pending_approval' and flipped the ado_writeback_queue.status default to pending_approval; the skill now enqueues at pending_approval. Charlie's approval flips a row to queued, and the future write-back drainer (ISS-02) must consume only queued rows. Verified live: ado_writeback_status = {queued, in_flight, committed, failed, pending_approval}; draft_pending_charlie = 0 hits across skill + brief. CoS acknowledged.
Symptom
The ado-bulk-triage skill instructs the agent to write status='draft_pending_charlie' to two tables — the ADO write-back queue and comms_drafts. That value exists in neither enum: ado_writeback_status = {queued, in_flight, committed, failed} and comms_draft_status = {drafted, awaiting_signoff, signed_off, sent, rejected}. A row literally cannot hold it in either place.
Effect
The intended status is silently dropped: the ADO row lands at its column default (queued), and the comms-draft write fails its enum cast (SQLSTATE 42804). The "pending Charlie's sign-off" intent exists only in the skill prose — it is invisible in the data. The correct comms value is awaiting_signoff; the ADO queue has no equivalent.
Evidence
Both enums confirmed in haleon-schema-ddl.sql; the dual write confirmed in the ado-bulk-triage SKILL.md; behaviour confirmed live by CoS, SA, and Steward (no row has ever carried that value).
Proposed fix
For comms_drafts: correct the skill to write the existing awaiting_signoff. For the ADO queue: pick one and apply consistently — (a) ALTER TYPE ado_writeback_status ADD VALUE 'pending_approval' and teach the drainer to skip it; or (b) keep the enum as-is and move "awaiting Charlie" onto a separate boolean/timestamp column (see ISS-11). Then correct the skill text in both places.
Where
~/.copilot/m-skills/ado-bulk-triage/SKILL.md · enum in the schema DDL · coordinate with ISS-11.

ISS-01b Create-path hardcodes queued — bypasses the pending_approval gate resolved P0

Resolution
RESOLVED (Batch 2). Steward applied the gate-by-default fix on Charlie's first-hand authorization: COALESCE(NEW.status,'pending_approval') in tg_v_ado_writeback_in_insert, and DEFAULT 'pending_approval' + COALESCE(p_status,'pending_approval') in sp_create_ado_writeback. Verified live: an enqueue with no explicit status now lands at pending_approval (attempts 0), the approval step pending_approval→queued sets approved_by/approved_at, and the claim queued→in_flight succeeds — restoring the D3 gate-by-default invariant end to end. The gate can no longer be silently bypassed by an enqueue that omits status.
Symptom
An ADO write-back enqueued without an explicit status lands at queued, not pending_approval — so the subsequent "approve" step fails as an illegal queued→queued transition, and the row was never gated in the first place. Surfaced by the ISS-03 verification harness.
Root cause
Two layers both hardcode 'queued' and override the Batch-1 base-table default of pending_approval: the insert trigger tg_v_ado_writeback_in_insert calls sp_create_ado_writeback(…, COALESCE(NEW.status,'queued')), and sp_create_ado_writeback itself has p_status text DEFAULT 'queued' with an inner COALESCE(p_status,'queued').
Effect
The approval gate (ISS-01 / decision D3 / ISS-11) is only enforced if every caller remembers to pass pending_approval explicitly. The ado-bulk-triage skill was updated in Batch 1 to do so, so the primary caller is safe — but any other enqueue path silently skips the gate. Gate-by-default is what D3 intends; the current default defeats it.
Proposed fix
Two one-line changes (staged with the Steward, held for explicit first-hand authorization because it is a semantic change to enqueue default behaviour, outside routine/additive scope): COALESCE(NEW.status,'pending_approval') in tg_v_ado_writeback_in_insert, and DEFAULT 'pending_approval' (plus inner COALESCE(p_status,'pending_approval')) in sp_create_ado_writeback.
Where
haleon-sp-views-triggers.sqlsp_create_ado_writeback + tg_v_ado_writeback_in_insert.

ISS-13 slot=evening is not a valid brief_slot resolved P0

Resolution
RESOLVED (decision D2). The Steward applied ALTER TYPE brief_slot ADD VALUE 'evening' to the live DB; the daily-brief skill keeps writing slot='evening' for the 17:00 run, which is now valid. Verified live: brief_slot = {morning, afternoon, adhoc, evening}. The docs' interim "afternoon stand-in" wording (skills.html, plan-vs-reality.html) was reverted to evening; the CoS brief already used evening (no touch-up needed). CoS acknowledged.
Symptom
The daily-brief skill writes the 17:00 end-of-day brief with slot='evening', but the brief_slot enum is {morning, afternoon, adhoc}. evening is not a member.
Effect
Same failure class as ISS-01: the enum cast fails (SQLSTATE 42804) / the slot is silently wrong, so the EOD brief isn't reliably distinguishable from the morning one in the data. The docs now show the EOD brief as slot=afternoon as the enum-valid stand-in.
Evidence
Enum confirmed in haleon-schema-ddl.sql; slot=evening confirmed in the daily-brief SKILL.md; raised by CoS. Notably the build plan chose "evening brief" specifically to avoid slot-enum risk — so the plan's own mitigation introduced the bug.
Proposed fix
Either ALTER TYPE brief_slot ADD VALUE 'evening', or change the skill to write afternoon (or adhoc) for the 17:00 run. Then align the docs.
Where
~/.copilot/m-skills/daily-brief/SKILL.md · enum in the schema DDL.

ISS-16 decision-capture writes columns that don't exist resolved P1

Resolution
RESOLVED (Batch 4 / D5). Per D5 the decision was to add the columns rather than drop the skill's writes: decision_class, adr_id, narrative and owning_peer now exist on decisions (ISS-14). The decision-capture skill was remapped to the real shim entities (DecisionIn, AdrIn, ComplianceStateIn) and real columns (two-axis review_stage vs status, narrative, adr_id as a string soft-ref). No nonexistent-column writes remain.
Symptom
The decision-capture skill writes decision_class, adr_id, and narrative to the decisions entity, but the table has none of those columns — its body fields are body and adr_repo_path.
Effect
Those writes fail or are silently dropped by the shim, so engagement-decision capture doesn't persist the way the skill claims. Decision metadata the briefs rely on isn't actually stored.
Evidence
Column set confirmed in haleon-schema-ddl.sql; skill text in decision-capture SKILL.md; raised by SA + CoS.
Proposed fix
Reconcile the skill to the real columns (map to body / adr_repo_path, or add the missing columns + shim coverage if they're genuinely needed). Coordinate with ISS-14 and ISS-19.
Where
~/.copilot/m-skills/decision-capture/SKILL.md · schema DDL.

Designed in the schema, not actually running

Not yet wired

ISS-02 The ADO drain path does not exist resolved P1

Resolution
RESOLVED (Batch 2). The drain path now exists: the ado-scribe skill (ISS-04) is the CoS-owned drainer. It selects queued rows (FIFO by enqueued_at, with per-target serialization so same-work-item changes never apply out of order), applies each via the azure_devops wit_* MCP, and advances status through in_flight → committed/failed via sp_update_ado_writeback (CAS-guarded), recording attempts, last_attempt_at, last_error, committed_at. A single-row drainer_lease mutex makes single-claimer real; transient failures auto-requeue (cap 5), permanent ones dead-letter; stale in_flight rows are reconciled against ADO rather than blindly re-applied. Built on ISS-03 and the ISS-11/D3 gate. Design and build validated by the delivery-workflows design session. Manual trigger today; autonomous 15-min cadence will be enabled under ISS-10, and the canonical ADO target is confirmed under ISS-05.
Symptom
The enqueue half is fully built and proven — AdoWritebackInv_ado_writeback_in → INSTEAD OF trigger → sp_create_ado_writebackINSERT … ON CONFLICT (idempotency_key) DO NOTHING. But nothing ever consumes the queue.
Effect
No agent, skill, script, or automation reads queued rows or calls the ADO wit_* MCP tools. Rows sit at queued indefinitely. ADO is updated by hand by Charlie; the queue is, in practice, a write-only inbox.
Evidence
Confirmed by filesystem search (no consumer), by CoS (owns ADO; says no drainer), and by Steward (has never audited a row leaving queued).
Proposed fix
Build a drainer — a CoS-owned skill or a scheduled automation — that selects queued rows ordered by idx_ado_q_status, applies each via the ADO MCP, and advances status through in_flightcommitted/failed, recording attempts, last_attempt_at, last_error, committed_at. Depends on ISS-03 and the decisions in ISS-11.
Where
New skill under ~/.copilot/m-skills/ and/or an automation; ADO MCP (azure_devops) — first reconcile ISS-05.

ISS-03 No sp_update_ado_writeback function resolved P1

Symptom
Only sp_create_ado_writeback exists. There is no supported write-path to flip a row from queued to any other status.
Effect
The attempts, last_attempt_at, last_error, committed_at columns plus the idx_ado_q_status(status, enqueued_at) index are "drainer-shaped scaffolding" with nothing able to use them. Even if a drainer existed, it would have no sanctioned way to update a row through the DAB shim.
Evidence
The live sp_create_ado_writeback lives in haleon-sp-views-triggers.sql (the …-wrappers.sql file is superseded); there is no sp_update_ado_writeback and no *In update view/trigger for the queue. Confirmed by CoS + Steward.
Proposed fix
Add sp_update_ado_writeback(...) plus the matching update path on v_ado_writeback_in (INSTEAD OF UPDATE trigger), casting text → enum for the new status the same way the create path does.
Where
haleon-sp-views-triggers.sql (current source of the queue's sp_* + triggers).
Resolution
Resolved (Batch 2). Steward applied sp_update_ado_writeback(...) plus the INSTEAD OF UPDATE path on v_ado_writeback_in (with approved_by/approved_at appended as cols 13–14 and the payload::text jsonb-as-text contract preserved). The function is a compare-and-swap state machine: every transition is guarded on the row's expected current status (WHERE id = p_id AND status = v_current_status), so a lost race returns no-row ("claim lost") rather than double-writing — this is the drainer's concurrency backstop, since FOR UPDATE SKIP LOCKED is not reachable through the DAB/MCP boundary. Legal arc: queued→in_flight (claim, increments attempts), in_flight→committed (sets committed_at), in_flight→failed (preserves last_error), and failed→queued re-queue capped at MAX_ATTEMPTS=5; committed is terminal and failed→in_flight / queued→committed / pending_approval→in_flight raise. Verified by a 9-step harness: insert 0 → approve 0 → claim 1 → fail 1 → requeue 1 → claim 2 → commit 2, with payload left unchanged on status-only updates and the cap raising at attempts ≥ 5. This unblocks ISS-02 (the drainer consumes only queued via this function).

ISS-06 agent_runs audit trail is not reliably written resolved P1

Resolution
RESOLVED (Batch 3, decision D4). SA designed and the Steward applied an audit-spine upgrade to agent_runs: a class discriminator (default 'turn', backfilled across existing rows) plus detail_ref / session_id / session_turn_seq columns. Writing an AgentRun is now a required close-out on every meaningful turn (baked into the role briefs; multi-writer per ISS-15), and the (session_id, session_turn_seq) pair makes a missing row detectable via the Steward's gap-scan — verified live (a 1,2,3,5 sequence surfaces missing seq 4). The two-phase lifecycle (insert at spawn, update-for-completion-fill) is preserved. Validated by the Brainstorming designer session.
Symptom
The agent_runs table and its AgentRunIn write-view exist and are meant to be the durable per-turn audit trail, but agents do not consistently write a run row.
Effect
There is no dependable DB-backed record of which agent did what, when. The rows present today are a mix of smoke-test artefacts and a one-off shakedown-replay batch the CoS wrote by hand — there is no automated writer, so the table is not yet a reliable audit trail.
Evidence
Documented on Logging & Audit; confirmed by CoS (wrote the shakedown-replay rows manually) and Steward (durable audit presently lives in the plan.md ledger, not the DB). Note agent_runs is written by multiple roles, not Steward-only (see ISS-15).
Proposed fix
Have every role write an AgentRun on each meaningful turn/decision (with a class discriminator so rotation and ADO-drain events can reuse it). Bake it into the skill wrappers so it is not optional.
Where
Role briefs in ~/.copilot/m-role-briefs/ · the common skill scaffolding.

ISS-07 cost_telemetry is dark resolved P2

Resolution
RESOLVED (Batch 3, decision D4). The Steward applied sp_rollup_cost_telemetry(start, end), which aggregates agent_runs token counts per agent into cost_telemetry via an idempotent upsert on the UNIQUE(period_start, period_end, agent_name) key. A whole-UTC-day window guard (RAISE 22023 on any non-day-aligned span) makes overlapping double-counts structurally impossible. Wired into the daily-brief skill (rolls up the prior UTC day each morning, via the CostRollupIn action-view). estimated_cost_usd uses published list-price per-model $/1K rates. Decision (Charlie, 30 May): real contract/internal rates will not be available for this engagement, so these estimates are accepted as the permanent basis — the figure is a directional trend signal, not an invoice, by design. Verified live: re-running the same day cell is idempotent (7→7).
Symptom
The cost_telemetry table exists but is never populated with per-run cost data.
Proposed fix
Emit a cost row per run once ISS-06 plumbing lands (it is the natural place to attach token/cost figures). Until then, document it as deliberately empty.
Where
Same plumbing as ISS-06.

ISS-08 No rotation_log table resolved P2

Resolution
RESOLVED (Batch 3, decision D4). The Steward created the rotation_log table (with an FK to agent_snapshots) and a full write shim (v_rotation_log_insp_create_rotation_log). The rotate-clawpilot-role skill now writes a DB handover record (from/to role, outgoing/incoming agent, reason, snapshot_id) on every rotation, plus an agent_runs spine row with class='rotation' cross-referencing it via detail_ref. plan.md remains the human-readable ledger; the DB is now the system-of-record. Verified live.
Symptom
The rotation ceremony records handovers in the runtime ledger (plan.md), not in a dedicated DB table. A rotation_log table does not exist.
Proposed fix
Decide via ISS-12: either add a rotation_log table (or write rotation events into agent_runs with a class discriminator), or formally accept ledger-only rotation audit and stop implying a DB table exists.
Where
Schema DDL · ~/.copilot/m-skills/rotate-clawpilot-role/SKILL.md.

ISS-09 No agent_snapshots table resolved P2

Resolution
RESOLVED (Batch 3, decision D4). The Steward created the agent_snapshots table with a full write shim (v_agent_snapshots_insp_create_agent_snapshot); the rotation/Historian path now writes snapshots here rather than into transcripts, with transcript_id retained as a soft back-reference. Migration: transcripts is the meeting-transcript table and carried no snapshot-shaped rows (0 rows), so a clean cutover was taken — 0 ambiguous rows, cutover 2026-05-29T20:46Z. Verified live.
Symptom
Snapshots taken during rotation are written into transcripts; there is no dedicated agent_snapshots table despite references implying one.
Proposed fix
Folded into ISS-12: build the dedicated table or accept the transcripts-backed approach and align the docs/briefs to it.
Where
Schema DDL · rotation skill · Historian behaviour.

ISS-10 The 15-minute health-tick is not enabled resolved P2

Resolution
RESOLVED (Batch 4) — built & staged; live schedule deferred to Charlie. The tick was split by failure-domain (validated by the design peer): core-tick (health-check + ADO drain + cost rollup; 15-min; single-flighted on a dedicated tick_lease with re-acquire renewal at TTL/2 and abort-on-lost-lease) is isolated from scout-sweep (Signal Scout only for shakedown; 2-hour cadence; its own scout_lease) which is caged behind hard structural caps — a cost circuit-breaker (sp_check_cost_breaker, now defaulting to a nominal $50/day baseline ±20% → $60/day ceiling; Charlie, 30 May — a starting guess to tune by observation, since no hard budget exists), a 1-child spawn ceiling, watermark-bounded scans (scout_watermark), a 5-min wall-clock budget, and enqueue idempotency. Cost rollup uses a settling-window finalize (sp_rollup_cost_day): recompute-until-settled, then mark final and skip. The ring-tick skill + the CoS brief are wired. The recurring schedule itself is intentionally OFF — turning it on is a Charlie posture call (it crosses from "runs when invoked" to "acts unprompted while spending"), gated on three greens: breaker live, drain proven manually, Signal Scout proven manually.
Symptom
The ring is described as having a 15-minute health-tick automation, but it is not enabled. The ring is currently manually driven, not scheduled.
Proposed fix
If autonomous cadence is wanted, enable the heartbeat/automation; otherwise document the ring as intentionally on-demand and drop the "scheduled" framing.
Where
Clawpilot automations / heartbeat settings (m_* self-control).

ISS-18 No write-shim for Adr / ComplianceState resolved P1

Resolution
RESOLVED (Batch 4 / D5). Built the missing write-shims following the existing *In view → INSTEAD OF trigger → sp_* pattern: v_adr_in + sp_create_adr (auto-assigns adr_number) + sp_update_adr (COALESCE-preserving, so a stage-only update doesn't null other fields) + insert/update triggers; and v_compliance_state_in + sp_create_compliance_state (an upsert, since re-evaluation is the dominant write) + trigger. DAB can now bind text → enum/jsonb on both entities, so ADRs and compliance states persist through the sanctioned path. Pairs with ISS-19.
Symptom
There is no *In view + INSTEAD OF trigger + sp_* function for the Adr or ComplianceState entities, even though the SA's day-1 job is ADR work.
Effect
DAB can't bind text → enum/jsonb on these entities, so there is no sanctioned write path. ADRs and compliance states can't be persisted through the normal shim until one is built.
Evidence
Shim inventory (12 *In views) confirmed against the DDL; neither entity has one. Raised by SA.
Proposed fix
Add v_adr_in / v_compliance_state_in views, INSTEAD OF triggers, and sp_create_adr / sp_create_compliance_state functions following the existing pattern. Pair with ISS-19.
Where
haleon-sp-views-triggers.sql · schema DDL.

ISS-19 ADR review lifecycle has no DB column resolved P1

Resolution
RESOLVED (Batch 4 / D5). Added a dedicated review_stage column to adrs (CHECK-constrained to draft → reviewed → compliance-checked → ratified) as the DB-backed, advanceable gate axis — distinct from status (the decision_status disposition axis). The sp_update_adr shim (ISS-18) advances it with column-preservation; you can now query "which ADRs have passed compliance" directly. The SA brief was updated to make review_stage authoritative and clarify the two axes; the Reviewer-mandatory / never-self-ratify rules remain enforced by the skill, audited by the Steward.
Symptom
The briefs/examples describe an ADR moving through draft → reviewed → compliance-checked → ratified, but adrs.status is the decision_status enum {proposed, accepted, superseded, rejected} — none of those review stages is a stored value.
Effect
The Reviewer and Compliance-Checker gates are tracked only procedurally; you can't query "which ADRs have passed compliance" from the data. The docs now flag these as illustrative stages.
Evidence
decision_status confirmed in the DDL; lifecycle wording in the SA brief + examples. Raised by SA.
Proposed fix
Add a dedicated review_stage column (or a small side table) if the gates need to be auditable; otherwise document them as procedural and stop implying enum values. Coordinate with ISS-11 (procedural-vs-DB pattern).
Where
Schema DDL · ~/.copilot/m-role-briefs/SOLUTIONARCHITECT.md.

ISS-20 SP↔trigger version coupling is untracked resolved P2

Resolution
RESOLVED (Batch 4). Extended the existing schema_version table with a migration_name (UNIQUE) + checksum column and an sp_record_migration upsert (+ a v_schema_migration_in shim so it's DAB-callable). Each shim bundle now records a row stamping its filename and a SHA256 of the source file; the apply protocol computes a fresh hash and compares it to the stored one, so a partial or out-of-sync re-apply surfaces as a checksum mismatch rather than silent drift. The drift baseline was back-populated by retro-stamping the already-applied bundles (sp-views-triggers, batch3-d4, iss10-tick, batch4-d5, iss20-plus) — six rows total. The in-band mechanism stores the checksum; the out-of-band comparison (Get-FileHash -Algorithm SHA256, lowercase hex) lives in the documented apply protocol.
Symptom
The INSTEAD OF triggers and their sp_* functions are tightly coupled but versioned only by living in the same hand-applied SQL file. There is no migration/version record.
Proposed fix
Track the shim under a lightweight migration tool (or at least a version stamp + checksum) so a partial re-apply can't leave triggers and functions out of sync. Raised by SA.
Where
haleon-sp-views-triggers.sql · DB ops.

Config points somewhere other than the docs claim

Discrepancies

ISS-04 "ADO Scribe" skill — now built resolved P2

Resolution
RESOLVED (Batch 2) — built, not deferred. Per the campaign mandate (nothing deferred-by-design), the CoS authored a real ~/.copilot/m-skills/ado-scribe/SKILL.md: the lease-guarded ADO write-back drainer (the build-out of ISS-02). It consumes only queued rows, applies them to the configured azure_devops project, and advances each through the live state machine via AdoWritebackIn (sp_update_ado_writeback, CAS-guarded) — never pending_approval, never raw UPDATE. Supporting schema applied live by the Steward: a single-row drainer_lease mutex (sp_acquire_drainer_lease / sp_release_drainer_lease + v_drainer_lease_in shim, exposed as DrainerLeaseIn) giving a real single-holder lease (unique per-instance token, CAS acquire, TTL-expiry steal, re-entrant renewal). The tick: acquire lease → re-queue transient failures / dead-letter permanent ones → reconcile stale in_flight against ADO (no blind re-apply) → select queued FIFO with per-target serialization → claim/write/commit-or-fail → release lease. Idempotency: unique idempotency_key for rows; an invisible <!-- idk:KEY --> HTML marker on add-comment ops (reconciled via wit_list_work_item_comments); a shared enqueue-side invariant added to ado-bulk-triage. Manual trigger now; 15-min cadence later via ISS-10. Design and build both validated by the delivery-workflows design session; CoS brief updated to register the skill.
Symptom
An "ADO Scribe" is named in decision-capture (step 11) and in the CoS brief, implying a dedicated skill. No SKILL.md for it exists on disk — but the build plan explicitly lists ADO Scribe among five helpers demoted to "future work, not in MVP scope". So its absence is a deliberate deferral, not an accidental gap.
Effect
Readers of the briefs expect a scribe skill to handle ADO drafting; in reality the CoS does that inline, as planned for the MVP. The lingering reference is what's misleading — not the missing file — and it compounds the missing-drainer confusion (ISS-02).
Evidence
Filesystem search finds only the references, no file; confirmed by CoS + Steward. Deferral confirmed against the build plan (helper-tier demotions).
Proposed fix
Short term: delete/clarify the references so the briefs stop implying a live skill, and note ADO drafting is inline-by-CoS for now. Longer term: if/when the deferred helper tier is built, author a real ado-scribe and pair it with the drainer (ISS-02).
Where
~/.copilot/m-skills/decision-capture/SKILL.md (step 11) · ~/.copilot/m-role-briefs/CHIEFOFSTAFF.md.

ISS-05 ADO org/project: the MCP points at the shakedown repo, not the canonical target resolved P1

Resolution
RESOLVED (per decision D8 — no repoint). The azure_devops MCP is now the single source of truth for the ADO org/project/area path, and the ado-bulk-triage skill was de-hardcoded — it now references "the configured azure_devops project" instead of naming MicrosoftMcCormickTesting/Loom/SEE-44471 (grep: 0 hits for the old hardcoded target). The current pointer smccormick0886/Haleon-AIAQ intentionally stays and is documented as environment config that will change per deployment (see Configuration → MCP topology). The CoS brief never hardcoded a target — confirmed clean. CoS acknowledged.
Symptom
The azure_devops MCP is pointed at smccormick0886/Haleon-AIAQ (a live shakedown project, reachable), while the ado-bulk-triage skill text names MicrosoftMcCormickTesting/Loom, area path SEE-44471 (the intended target, which is not wired).
Effect
The plan, the skill text, and the validation step all name MicrosoftMcCormickTesting/Loom as the intended target — only the live MCP differs. So this is deployment drift in one place (the MCP), not a genuine three-way disagreement. Any future drainer would currently write to the shakedown repo.
Evidence
MCP config in ~/.copilot/m-mcp-servers.json; skill text in ado-bulk-triage; confirmed by CoS + Steward.
Proposed fix
Confirm MicrosoftMcCormickTesting/Loom / SEE-44471 is the real target, then repoint the azure_devops MCP to it (the skill text already matches). If the shakedown repo is intentional for now, say so explicitly in the skill + docs. Update Configuration either way.
Where
~/.copilot/m-mcp-servers.json · ~/.copilot/m-skills/ado-bulk-triage/SKILL.md.

ISS-14 decisions has no routing column resolved P1

Resolution
RESOLVED (Batch 4 / D5). Added four routing columns to decisions: decision_class (technical|engagement, CHECK-constrained), adr_id (soft cross-ref to adrs.id), narrative, and owning_peer (SA|CoS, CHECK-constrained), threaded through v_decision_in + sp_create_decision. Routing is now queryable data — you can ask "decisions owned by SA" or "engagement decisions with no ADR" — not a procedural convention.
Symptom
The workflow describes decisions being "routed" (e.g. to the SA for technical ADRs vs. the CoS for engagement calls), implying a routing state on the row. The decisions table has no routing column, and decision_status ({proposed, accepted, superseded, rejected}) contains no routing states.
Effect
Routing is a procedural convention, not data — you can't query "decisions awaiting SA routing". The docs now carry a caveat wherever routing is mentioned.
Evidence
Table + enum confirmed in the DDL; raised by CoS.
Proposed fix
If routing must be queryable, add a routing/owning_peer column; otherwise document it as a procedural convention. Coordinate with ISS-16.
Where
Schema DDL · decision-capture skill · workflow docs.

ISS-15 agent_runs is multi-writer, not Steward-only resolved P2

Resolution
RESOLVED (Batch 3). agent_runs is now formally documented as multi-writer: every role writes its own runs (with class + agent_name + session discriminators); the Steward audits rather than exclusively authors — gap-scanning session_turn_seq, cross-checking class='rotation'/'snapshot' rows against rotation_log/agent_snapshots, and recording its own findings as class='audit' rows (corrections are class='correction' appends, never in-place rewrites). The role briefs (CoS/SA/Steward) were aligned to this model.
Symptom
The briefs imply the Steward owns the agent_runs audit trail. In practice any role can (and the CoS did) write to it via AgentRunIn.
Effect
Ownership/authority over the audit trail is ambiguous, which matters once it becomes the real audit record (ISS-06). Multi-writer is fine, but it should be stated, not implied otherwise.
Evidence
Confirmed by CoS (wrote rows) + Steward; DAB grants are role-wide.
Proposed fix
Document agent_runs as multi-writer with a class/agent discriminator; let the Steward audit rather than exclusively author. Align briefs.
Where
Role briefs · Logging & Audit.

ISS-17 The cowork skill is undocumented resolved P2

Resolution
RESOLVED (Batch 4) — doc-only. The skill matrix now documents cowork (the seventh skill on disk — a browser-automation bridge to the M365 Cowork agent) explicitly as a general-purpose utility skill that is not part of the ring-coordination delivery set, so the inventory is complete and the capability is no longer invisible.
Symptom
There are seven skill directories on disk; cowork (a browser-automation bridge to the M365 Cowork agent) is the seventh and isn't covered in the briefs or the skill matrix's delivery set.
Effect
Minor: a real capability is invisible in the docs. The skill matrix now notes it as a non-delivery utility skill, but the briefs don't mention it.
Evidence
Directory listing of ~/.copilot/m-skills/ (7 dirs); confirmed against the matrix.
Proposed fix
Add a one-line entry for cowork (and any other utility skills) so the inventory is complete, clearly flagged as not part of the delivery ceremony set.
Where
~/.copilot/m-skills/cowork/ · skill matrix / briefs.

ISS-21 m365-softeria MCP is wired despite being deferred resolved P2

Symptom
The build plan defers the Softeria M365 integration in favour of native m365_* tools, yet m365-softeria is present and active in the live m-mcp-servers.json.
Effect
Deployment drift: an MCP the plan said to skip is loaded each session. Not harmful, but it's surface area and config the plan doesn't account for.
Evidence
Present in ~/.copilot/m-mcp-servers.json; plan defers it. Flagged as possibly non-live by Steward.
Proposed fix
Confirm whether Softeria is actually used; if not, remove it from the MCP config (or update the plan to adopt it). Update Configuration.
Where
~/.copilot/m-mcp-servers.json · plan.
Status
resolved Resolved 30 May with Charlie's explicit first-hand authorization (D7). The m365-softeria server block was removed from m-mcp-servers.json (a filesystem config edit — not DB DDL, so it did not route through the Steward). Correcting the earlier record: native m365_* tools (Outlook mail, Teams DMs, calendar, OneDrive) are a builtin Clawpilot capability, not an MCP entry — which is why they never appeared in m-mcp-servers.json and survive the removal untouched. The peer ring references M365 only via those native tools (e.g. CHIEFOFSTAFF.md, daily-brief); a fresh grep across m-skills/ and m-role-briefs/ found zero references to any Softeria-only capability. Removal therefore dropped only the unused extended-Graph surface (Excel-as-API, OneNote, Planner, To-Do, contacts, mail-rules) that no agent uses, and is fully reversible by re-adding the block. Verified: JSON parses; softeria/ms-365-mcp = 0 hits in the config; the other servers (filesystem, filesystem_extra, playwright, azure_devops, haleon-aiac-db) remain intact.

ISS-22 DAB runs as anonymous with write grants resolved P2

Symptom
The build plan intended anonymous = read-only and an authenticated role for writes. In the live config DAB launches as anonymous, which actually carries CRUD grants (writes still fail at the enum/jsonb cast — see ISS-01).
Effect
The intended read/write role separation isn't enforced. Low risk on a single-user local DB, but it's a security-posture drift from the plan.
Evidence
DAB host role in m-mcp-servers.json; grants in the DDL; raised by SA.
Proposed fix
Either implement the authenticated write-role split as planned, or formally accept the single-role local model and update the plan + Configuration.
Where
~/.copilot/m-mcp-servers.json · schema grants · plan.
Status
resolved Resolved 30 May via Option A — Tighten + document (Charlie's pick over the two-instance split). Rather than flip the launch role — which on this Simulator-provider, single-user, single-transport setup would add no real principal separation — we removed the privilege the anonymous role never legitimately used. In dab-config.json all 12 base tables that previously carried anonymous write grants were tightened: the enum/jsonb create action — provably dead (it fails at the cast, SQLSTATE 42804) — was revoked on every one, so the only sanctioned write path is now the validating *In shim views (which apply the INSTEAD OF triggers and sp_* functions). Six tables whose shim covers the full create+update path (ado_writeback_queue, agent_runs, comms_drafts, decisions, recipient_registry, risks_issues_blockers) are now read-only. Six whose shim is currently create/read-only (briefs, meeting_preps, pd_sync_preps, quiet_watch_state, signals, steerco_preps) retain update on the base entity so no live skill breaks — a documented residual to close later by giving those five-plus-one shims an update path. authenticated=* stays defined on every entity as the dormant production posture; one role:anonymous instance keeps running. No skill rewiring; reversible via the dab-config.json.bak-iss22-* backup. Takes effect on the next haleon-aiac-db MCP respawn (host action — folded into the pending MCP-restart item).

Decisions only Charlie / the CoS can make

Open questions

ISS-11 Procedural gate, or DB-backed approval? resolved P1

Decision
RESOLVED — option (b), DB-backed (decision D3). The Charlie gate is now an explicit, auditable state in the database, not merely the absence of a drainer. A row lands at pending_approval (the new ado_writeback_queue.status default); Charlie's approval flips it to queued; the write-back drainer (ISS-02) must consume only queued rows. This is implemented via the enum value added in ISS-01 and the status-advance function in ISS-03. Whether to also persist approved_by/approved_at audit columns is folded into the ISS-03 design. Authorised by Charlie 2026-05-29.
The question
Today, "nothing reaches ADO without Charlie" is enforced purely by the absence of a drainer — it is procedural, not represented in the data. Should the approval become an explicit, auditable signal in the database?
Why it matters
It determines the status model the drainer (ISS-02) is built against and how ISS-01 is resolved. Building the drainer first would risk reworking it.
Options
(a) Keep it procedural — accept that the queue holds only queued and a human is always the trigger. (b) Add an explicit approved_by / approved_at column (or a dedicated status) the drainer must see before acting — gives a real audit trail of who approved what, when.
Owner
Chief of Staff, with Charlie's call on policy.

ISS-12 Build the deprecated-table features, or retire the tables? resolved P2

Resolution
RESOLVED (decision D4 — build all). The question is settled: the producers are built, not retired. cost_telemetry now has sp_rollup_cost_telemetry (ISS-07), rotation_log exists and is wired (ISS-08), and agent_snapshots exists and is wired (ISS-09). No table is left dark-but-implied.
The question
Several tables exist in the schema but have no producer: cost_telemetry (ISS-07), and the implied-but-absent rotation_log (ISS-08) and agent_snapshots (ISS-09). Are these on the roadmap, or should they be formally retired?
Why it matters
Empty/absent tables that the briefs imply are populated create a false sense of an audit trail. A clear "build it" or "drop it / it's ledger-only" removes the ambiguity.
Options
(a) Commit to building the producers (cost emission, rotation logging, snapshot rows). (b) Formally accept ledger-/transcript-only behaviour and align the schema, briefs, and these docs so nothing implies a DB-backed feature that does not exist.
Owner
Steward (governance) + CoS.

Handoff note for the CoS. The P0 bug (ISS-01) and the two decisions (ISS-11, ISS-12) are the right place to start — they unblock everything downstream. Once the status model is settled, ISS-03ISS-02ISS-04/ISS-05 are a clean, ordered build sequence for the ADO write-back path.

See what the ring produces today →