Skip to content

Governance Model

KCP Harness enforces a deterministic, fail-closed governance model. This page explains the principles and mechanics.

Fail-Closed

The default posture is deny. If any of the following are true, knowledge access is blocked:

  • The manifest can't be loaded
  • The plan rejects all units
  • A unit fails any of the 14 gates
  • The budget ceiling is exceeded
  • The temporal validity check fails

There is no "best-effort" mode. Either the request is explicitly approved through the gate cascade, or it's blocked.

The 14-Gate Cascade

Every knowledge unit is evaluated through 14 deterministic gates, in order (kcp-agent v0.16.0, skill_eligibility added #100/#101):

#GateWhat it checks
1audienceIs the requester in the target audience?
2not_forIs the requester explicitly excluded?
3temporalIs the unit valid at the current time?
4deprecatedHas the unit been deprecated?
5supersessionHas a newer unit superseded this one?
6relevanceIs the unit relevant to the task?
7skill_eligibilityFor a kind: skill unit: does it carry an explicit load_eligible: true grant?
8attestationDoes the unit have required attestations?
9paymentDoes access require payment?
10accessDoes the requester have access rights?
11strictIn strict mode, is relevance high enough?
12max_unitsWould this exceed the unit count limit?
13money_budgetWould this exceed the monetary budget?
14context_budgetWould this exceed the token budget?

A unit must pass all gates to be included in the plan. The gate that blocks it is recorded in the decision trace. See Governed Skills below for what happens once a kind: skill unit clears gate 7 and is actually invoked.

Decision Traces

Every plan produces a decision trace — a structured record of which gates each unit passed or failed. Traces are:

  • Deterministic — same inputs produce identical traces
  • Complete — every unit in the manifest is evaluated
  • Timestamped — temporal gates are evaluated against a pinned time
  • Replayable — traces can be re-evaluated against different parameters

Budget Enforcement

The harness tracks spend via an append-only ledger:

  • Each kcp_load records the cost of loaded units
  • Running totals are maintained per currency
  • If a load would exceed the budget ceiling, the entire load is rejected (no partial loads)
  • The ledger can be queried via harness_budget

Temporal Governance

Knowledge units can have temporal constraints (valid-from, valid-until, embargo dates). The harness:

  1. Pins the evaluation time when a plan is created
  2. Registers the plan with the temporal watcher
  3. On subsequent calls, re-evaluates plans against current time
  4. If units have drifted (expired, newly valid), emits a temporal_drift event
  5. The agent can check drift via harness_temporal_check

Human-Approval Gates

Some governed actions must not be decided by the automated cascade alone: org policy demands a named human sign off, and that can take minutes or days. Calls matching a governance.approvals rule enter a durable ticket state machine:

pending_review ──▶ approved   (terminal, named reviewer)
       │─────────▶ dismissed  (terminal, named reviewer)
       └─────────▶ expired    (terminal, TTL — fail-closed)

Three invariants:

  1. Approval rules outrank every automated path. An approved plan cannot bypass a human gate — the rule check runs first.
  2. Resolutions are never anonymous. A resolution requires a named reviewer and a policy citation (policyRef). approved: true alone is rejected as evidence. The evidence is generated at approval time, never reconstructed from logs.
  3. Tickets survive restarts. Sessions are ephemeral; human review is not. The default file provider persists every ticket, and a CLI in another process resolves it.

MCP has no async answer, so a pending call is denied with a structured reason carrying the ticket id and required role. The agent re-tries after approval (or checks harness_approvals). On retry the governor honors the resolution: approved → allowed with the resolution attached; dismissed → terminal block.

The provider interface (submit / check / resolve / list) is channel-agnostic — Slack, email, or ticketing integrations are org-side implementations of the same surface the built-in kcp-harness approvals CLI uses.

Post-Synthesis Confidence Gate

The 14 gates all evaluate declared unit properties before anything is generated. Confidence is a property of the model's output — so it is a separate, later stage, downstream of synthesis:

The planner decides what may be loaded; grounding decides what may be asserted; harness_assess decides what may be acted on.

The harness calls kcp-agent's assess(): confidence is a proposal (the answer's self-report, or an injected evaluator); the gate adjudicates deterministically against the configured threshold. The verdict is binary with a written, specific reason — the same contract as the 13 pre-selection gates.

  • Strictest threshold wins — a caller may tighten org policy, never loosen it
  • Fail-closed — no obtainable confidence signal fails the gate with a specific reason
  • Route-to-human — a failed verdict on a route_to_role config opens an approval ticket with the full verdict embedded as evidence ("below threshold on critical → route to a human" is a pending approval)
  • Every adjudication is a confidence_verdict audit event — score, threshold, reasoning; never the answer text

Governed Skills — the harness enforces skill_eligibility

A kind: skill unit (spec §4.3a) is a procedure, not a document — something an agent could do. When a governed tool call is classified as a skill invocation, the harness runs kcp-agent's skill_eligibility gate itself, before the skill's tool call is ever forwarded downstream:

  • Ineligible → refused, fail-closed. No load_eligible: true grant means the call never reaches the downstream tool. A skill_loaded audit event with eligible: false records the gate's exact written reason.
  • Eligible → loaded, and its action_scope becomes binding. The skill's declared action_scope (tools/paths/capabilities) is attached to the session as the active skill — every subsequent governed call in that session is now checked against it (see Procedural Conformance, next). A skill with no declared scope binds an empty one — fail-closed, not permissive.
  • Skill invocations skip the generic plan governor entirely — a skill id is not a file path to plan against, so skill_eligibility is the whole story for whether it runs.

Every verdict is a skill_loaded (eligible: true or false) audit event, carrying the skill's id, the deciding gate, its written reason, and its action_scope.

Authoring skill units: the conventions for what a good kind: skill + action_scope looks like, the SK001–SK008 linter, the conformance vectors (canonical fixtures for testing any producer or consumer of skill units — including this harness's gate), and a curated library of governed playbooks live in Cantara/kcp-skill. Lint a manifest's skill units with npx kcp-skill-lint knowledge.yaml.

Procedural Conformance — grounding for actions

Loading a skill is not a blank check. Once one is active, every subsequent governed tool call in that session is adjudicated against that skill's declared action_scope before the generic governor runs — the same "cite it or it doesn't count" discipline kcp-agent's answer-grounding applies to claims, applied to actions:

  • A call that stays within the active skill's tools/paths/capabilities proceeds.
  • A call that strays outside it is held fail-closed — surfaced as a gap, routed to a human, never silently narrowed or silently allowed. The reviewer role and policy citation come from governance.conformance — falling back to governance.confidence's routing if that block is absent, then to a hardcoded default role (governance-reviewer) with no policy citation (#43).
  • This check runs before plan governance: a scope violation is decided by the loaded skill alone, independent of whether a plan would otherwise have approved the call.

Every adjudication is a conformance_verdict audit event, naming the active skill, the tool invoked, the deciding target (the violating one, on a hold), and — on a hold — a ticket id if the violation was routed for review.

Decision-Record Correlation

Every tool call the harness intercepts produces a chain of verdicts as it moves through classification, governance, skill-gating, and confidence adjudication. A single correlation id ties that whole chain together in the audit log, so a reviewer (or an export) can reconstruct exactly which verdicts belong to which action instead of correlating timestamps by hand.

Per the KCP spec (§3.2 propagation / §17 observability), the harness reuses an incoming W3C traceparent when the caller supplies one — its trace-id becomes the correlation id, its span-id becomes the parent — so harness records stitch directly into the caller's own distributed trace. Absent a valid traceparent, the harness mints a fresh id. Every audit event in a chain carries correlationId (and parentId, when derived from an incoming trace).

Session Dedup

The harness tracks which units have been loaded in the current session. If an agent requests a unit that's already loaded (same SHA-256 hash), the harness returns an "unchanged" stub instead of re-loading the content. This prevents:

  • Redundant knowledge loading
  • Double-counting in the budget ledger
  • Context window waste

Released under the Apache 2.0 License.