Status: active (HIER-P3, 2026-09-04) Audience: platform operators reviewing the Platform Architect's offers Prerequisites:
ai.agents.manage(the approver on thePlatform Architect Actionschain), the Autonomy panel Runtime: ~5 min per offer
The platform reports its own governance drift. On every fleet tick
GovernanceGapSensor compares the declarations the agent hierarchy is built
from (System::Governance::PolicyDeclarations, SkillBindings,
DecisionEngine::SIGNAL_BINDINGS, HierarchyReconciler) with the running
database and emits one system.governance_gap signal per gap. The
DecisionEngine routes it to the Platform Architect, which files ONE
Ai::ImprovementRecommendation per gap — the offer you review here — and, for
the gaps the runtime can close, materialises the fix under the approval gates
the operator rulings of 2026-09-03 set (skill and prompt refinements auto-apply
on a trusted agent; structural changes always wait for you).
Every gap kind is one the 2026-09-03 hierarchy audit found by hand. The sensor exists so the next one is found by the tick, not by the next audit.
gap_kind |
The gap | Offer type | Closes by |
|---|---|---|---|
category_unowned |
A system. / sdwan. category is registered (tunable in the Autonomy panel) but no PolicyDeclarations set declares it, so no agent owns it and PolicyReconciler never writes its row |
capability_gap |
Code: declare it in the owning agent's set (extensions/system/server/app/services/system/governance/policy_declarations.rb) or deregister it |
agent_without_skills |
A declared agent carries a policy set and binds no skill | skill_creation |
Code (a binds_to + a catalog row), or materialised when the registry already declares pairs for it |
binding_without_skill |
A SIGNAL_BINDINGS lane is bound to skill: nil with no applier and no declaration that it is notify-only |
capability_gap |
Code: an executor, an applier, or a DECLARED exemption in RemediationValidator |
executor_without_skill_row |
An executor's binds_to names a skill slug with no global Ai::Skill row — the strict bindings seed would abort |
skill_creation |
Code: the catalog entry in system_skills_seed.rb |
binding_agent_unknown |
An executor's binds_to names no global agent |
capability_gap |
Code: the alias or the agent seed |
skill_binding_missing |
The registry declares an (agent, skill) pair and no Ai::AgentSkill row exists |
skill_creation |
Materialised (the boot reconcile writes it too) |
lineage_edge_missing |
A canonical has no active lineage edge under System Concierge | team_composition |
Materialised (structural — always parks) |
delegation_policy_missing |
A canonical has no delegation policy on this account | team_composition |
Materialised (structural — always parks) |
policy_owner_undeclared |
A declared category's agent-shape row sits on an agent the declarations do not know; the reconciler never touches it | capability_gap |
Operator: re-home or deactivate the row (record a move in PolicyReconciler::FORMER_OWNERS) |
tool_family_unregistered |
A canonical's tool_families entry matches no registered action (exact or <family>_ prefix) |
capability_gap |
Code: the agent's seed |
The offer's evidence carries the fingerprint (governance_gap:<kind>:<subject>),
the concrete subject and ids, the files a code fix touches, the number of
ticks that re-detected it and, when one exists, the materialization the
Platform Architect proposed and its status. recommended_config.fix is the
reviewable fix in one paragraph.
- Find it.
platform.list_improvements(or the Improvements page) with the offer type; the title readsGovernance gap (<kind>): <subject>andevidence.proposed_byisplatform-architect. - Read the fix and the files. A code fix names the file it lands in; a
materialised fix names the seam (
HierarchyWriter,Ai::AgentSkill,Ai::SkillVersion) and the deferred operation, if it parked. - Decide.
- Approve a code-path offer (
capability_gap, and anyskill_creation/team_compositionwithout a materialisation): it becomes work for the Platform Developer or a Claude Code session. Note thatplatform.approve_improvementpromotes only the code-quality types into a dev-improve task; a governance offer is approved through the recommendations API (POST /api/v1/ai/learning/recommendations/:id/apply) or by handing the offer id to the executor of your choice — see the open question recorded for HIER-P3 in the proposal's ruling record. - Approve the parked materialisation (an
Ai::DeferredOperationon thePlatform Architect Actionschain — the Autonomy panel's pending operations, orplatform.approve_deferred_operation): the operation replays as the Platform Architect, applies the write, and closes the offer asapplied. - Dismiss an offer you do not want. A dismissed gap that is still
present is re-filed as a NEW offer on the next tick — dismissal records
your decision on that offer, it does not silence the sensor; close the
gap, or declare the condition deliberate in code (the
binding_without_skillkind, for example, is exactly a missing declaration).
- Approve a code-path offer (
- Watch it clear. The sensor stops emitting the fingerprint the moment the gap closes; nothing needs cleaning up.
| Materialisation | Gate | trusted Platform Architect |
Below trusted |
|---|---|---|---|
skill_binding — an Ai::AgentSkill row |
dev.skill_refine (core's trust-conditioned pair, or the account-wide floor — see below) |
applies at once | parks only where the pair is seeded |
prompt_refinement (seam only — no sensor detector produces it yet) — a new active Ai::SkillVersion on an existing skill, the previous prompt kept in the version's metadata |
dev.prompt_refine (core's trust-conditioned pair, or the account-wide floor) |
applies at once | parks only where the pair is seeded |
lineage_edge — HierarchyWriter#attach! under System Concierge |
dev.governance_materialize (require_approval, PLATFORM_ARCHITECT_POLICIES) |
parks | parks |
delegation_policy — HierarchyWriter#ensure_delegation_policy! with the declared attributes |
dev.governance_materialize |
parks | parks |
The refine rows are not trust-conditioned on every account (IMP-a51963f8717f,
proposal §5 ruling 11c). Core writes a scope-global, agent-less auto_approve
FLOOR for dev.skill_refine and dev.prompt_refine on EVERY account
(Ai::Engineering::ReleaseDispatchFloorSeeder), so that the MCP principals that
own no policy row — an operator's mcp_client identity, a dev-cell instance
principal — keep refining instead of parking. The trust-conditioned PAIR that
outranks a floor is seeded only on the Powernode Admin account's
canonicals. On any other account the acting Platform Architect owns no refine
row, so the floor decides and a binding or prompt refinement applies at every
trust tier, including supervised.
To restore the fail-safe on an account, give that account's Platform Architect
its own row for the category — an agent-scoped row outranks a global one at any
priority (Ai::InterventionPolicy#specificity_key), so priority cannot do it:
Ai::InterventionPolicy.create!(
account: account, scope: "agent", ai_agent_id: architect.id,
action_category: "dev.skill_refine", policy: "require_approval",
priority: 10, is_active: true, conditions: {}
)The STRUCTURAL kinds are unaffected: nothing writes a floor for
dev.governance_materialize, so a lineage edge or delegation policy parks on
every account whatever the tier.
prompt_refinement is WIRED but UNPRODUCED: every materialization hash
GovernanceGapSensor stamps today is skill_binding, lineage_edge or
delegation_policy — there is no prompt-drift detector, so no offer reaches an
operator carrying a prompt refinement. The arm exists so a future detector (or
the Platform Architect's own offer) has a gated, versioned path to refine a
canonical skill's prompt rather than writing ai_skills.system_prompt in place.
Do not read the row above as something the loop does unattended today.
The gate is the policy row, not the code: an account with no row for a
category meets the require_approval default and parks. Every applied
materialisation writes one AuditLog row (system.governance.gap_materialized)
and one fleet.governance_gap_materialized event, both naming the offer.
To let refinements apply unattended, raise the Platform Architect's trust
tier to trusted (platform.update_agent_trust_score on the account's clone,
never the global canonical — see the canonical rule in
docs/concepts/platform-engineering-agents.md). Structural changes never
unlock by trust: that is operator ruling #3.
The lane is SCORED: filing the offer is the remediation, and the gap's
persistence across settle windows is what the validate arc measures. A gap
that stands STUCK_STREAK_THRESHOLD (3) settle windows (90 s each) without
closing escalates as a HIGH fleet.governance_gap_stuck event — the same
mechanics as fleet.remediation_stuck, under its own kind — and the lane is
forced to require_approval, which mints ONE Ai::ApprovalRequest on the
Platform Architect Actions chain. That request is the terminal state: the
lane stays quiet while it is open.
What it means: the offer for this gap is still pending (nobody approved, dismissed or materialised it). What to do: review the offer exactly as above. Approving the approval request itself replays the propose executor (it re-files or refreshes the same offer); rejecting it suppresses the escalation for the ordinary rejection cooldown and the gap re-escalates if it still stands. Neither replaces reviewing the offer.
platform.system_update_sensor_config({ sensor: "governance_gap", config: { max_per_tick: 50 } })— the per-tick cap (default 25, highest severity first).- The lane's verbs are the Platform Architect's rows in the Autonomy panel:
dev.campaign_propose(proposing; retuning it torequire_approvalmakes the executor run plan-only into the request),dev.governance_materialize(structural materialisations), and core'sdev.skill_refine/dev.prompt_refinepair (refinements).
- Sensor:
extensions/system/server/app/services/system/fleet/sensors/governance_gap_sensor.rb - Binding and the scoring applier:
extensions/system/server/app/services/system/fleet/decision_engine.rb - Propose executor:
extensions/system/server/app/services/system/ai/skills/governance_gap_propose_executor.rb - Materialiser and its gates:
extensions/system/server/app/services/system/governance/gap_materializer.rb - The versioned prompt path:
server/app/services/ai/self_improvement/skill_refinement_service.rb - The declared set and the core-canonical identity:
extensions/system/server/app/services/system/governance/policy_declarations.rb - Concept:
docs/concepts/platform-engineering-agents.md(parent tree)