fix: guard capability drift, explain empty missions, make audit verification runnable - #99
Conversation
Bootstrap's administrator grant was a hand-maintained array literal that had already drifted from @muster/authz (brolga.context.read was missing), and because bootstrap rewrites capability_assignments on every boot it silently reverts any migration backfill. Starter actor rows now live in seed-data.ts with the administrator grant derived from starterRoleCapabilities.administrator, guarded by a behavioural test that fails on drift and on any undeclared capability in a starter actor. The Missions empty state stated a fact and left the operator stuck. It now names the governed tool (muster_upsert_mission), the capability and scope its caller needs, the operator command that provisions an MCP installation, and links to Guides. No UI create path is introduced; ADR 0005 keeps mission creation on the governed server path. The audit verifier threw a raw error when MUSTER_AUDIT_ORGANISATION_ID was unset. It now accepts --organisation, lists the organisations in the connected database when none is supplied, prints an operator-readable interpretation alongside the JSON report, and separates usage (64) and unreachable-database (69) from a failed chain (1). No audit row is read differently or written; docs/operations/audit-chain-verification.md documents how to run it and how to interpret legacy-compatible-not-strict without ever repairing history. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 53 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (10)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Phase 5 of 6. Three unrelated carried-over defects.
1. Capability drift guard
bootstrap.tshand-maintainedadministratorCapabilitiesas a literal duplicate of the authz list, and rewritescapability_assignmentson every boot viaexcluded.capability_assignments— so any drift silently reverts the migration backfill too. That mechanism already ateagents.handoffearlier in this series.It had drifted again, undetected:
brolga.context.readwas missing, added to authz with the Brolga connector and never mirrored here.Starter actor rows moved into
seed-data.tsasstarterActorSeeds(email), following the existingbootstrap-connectors.tssplit (script imports a testable module —bootstrap.tsis top-level-await and can't be imported directly). The administrator grant is now derived:[...starterRoleCapabilities.administrator]. No list to keep in sync.starter-actors.test.tsis a real behavioural test, not a string match: administrator assignments must equal the authz capability set, no starter actor may hold an undeclared capability, agents must stay below administrator privilege. Verified it fails on reintroduced drift before landing.2. Missions empty state
"Created via governed MCP tools or bootstrap" was accurate and useless. Now names
muster_upsert_mission, states the caller needsworkflows.manageplus that tool in its installation scopes, gives the provisioning command, and links to Guides — whose "Missions and Audit" entry is genuinely relevant, checked before linking. Still says explicitly that there is no UI create path by design (ADR 0005), so nobody files it as a missing feature.3. Audit chain verification
Judgement: the strict failure needs no code fix, and making it pass would be wrong.
The events at and after sequence 136 are authentic. They were hashed with
approvalId: undefinedin metadata, which PostgreSQL JSONB drops on write. The only routes to a green strict result are rewriting stored hashes or rewriting metadata — both forbidden bypackages/audit, and both would destroy the property the chain exists to provide.legacy-compatible-not-strictis the correct permanent outcome for any workspace holding pre-normalisation events. No audit row is touched;packages/auditis unchanged.The real defect was operational. The verifier threw a raw unhandled
ErrorwhenMUSTER_AUDIT_ORGANISATION_IDwas unset — I hit this myself running it against the homelab. It now:--organisation=<uuid>64usage,69unreachable database,1genuinely invalid chainNew runbook at
docs/operations/audit-chain-verification.md, linked from the existingincident-recovery.mdattestation steps rather than duplicating them.The one thing worth watching, documented in the runbook: if a later run reports a legacy sequence that was not in the previous run, the writer is still emitting the old shape — that is a live regression to fix at the writer, not a historical artefact to accept.
🤖 Generated with Claude Code