Skip to content

Cost and Context Governance

Irlan Cidade edited this page Nov 1, 2026 · 2 revisions

Cost & Context Governance

This page documents the MiniCISO v0.7.6 operating contract. Canonical references are the v0.7.6 README, the governance design, the governance skill, and the runtime pinned in config/hermes-version.env.

Goal and operational threat model

Cost & Context Governance bounds model calls, context growth, tool use, delegation, retries, and elapsed work while preserving evidence quality and independent QA. It addresses runaway consumption, repeated no-progress work, excessive delegation, oversized tool surfaces, late context pressure, and loss of useful partial work at a stop boundary.

It is not provider billing, a general policy engine, or a replacement for normal context compression. Human authorization and accountable judgment remain mandatory.

Modes

Mode Behavior
disabled No active envelope is created. A small status artifact records the operator's choice.
observe The lifecycle, artifacts, and telemetry run, while enforcement decisions remain informational where the implementation permits continuation.
enforce Invalid or untrusted accounting, identity, decisions, schemas, or persistence fail closed before further provider or tool execution.

The mode is read when the agent is constructed. Restart the relevant processes and begin a new session after changing deployment configuration.

Request classes, identity, and budgets

Every governed request is classified as exactly one of:

  • conversational for normal chat and lightweight triage;
  • bounded for a contained implementation, review, or short investigation;
  • engagement for multi-step security work, longer research, or multi-lane delegation.

The selected budget profile can limit total model calls, calls per agent, calls per delegated task, input/output/total tokens, per-request context, wall-clock time, tool invocations, retries, delegation count, and iterations without progress. Delegated tasks receive bounded child envelopes instead of inheriting the full root budget.

A protected QA reserve is calculated separately for model calls and total tokens. Non-QA work cannot consume that reserve in enforce; a trusted QA lane can use its allocation but must stop when that allocation is exhausted.

Delegation uses explicit profile_routes. The named security SME profiles route to the sme governance role, while security-qa routes to the protected qa role. The runtime validates that QA authority belongs to the QA profile; a delegated lane cannot claim the role merely by supplying untrusted metadata.

The persisted identity chain is:

profile -> engagement -> task -> logical call -> attempt -> request

A retry or compaction attempt keeps the logical-call identity but receives new attempt and request identifiers. Profile, chat, engagement, and task scope are not interchangeable.

For a root session, v0.7.6 binds the profile and session identity to one engagement and persists that mapping. Reconstructing the controller or continuing the same session therefore reuses the engagement instead of silently creating a new budget root. Delegated children inherit the validated engagement identity. Invalid, conflicting, or path-escaping identities fail closed rather than becoming persistence paths.

Controlled lifecycle and accounting latch

Each outbound model or tool operation crosses the same boundary:

  1. Preflight: resolve identity, classification, envelope, projected usage, and progress.
  2. Reserve: atomically reserve a conservative estimate from the shared budget.
  3. Persisted dispatch: record the dispatch transition durably before invoking the provider or tool.
  4. Reconcile/finalize: normalize actual usage, reconcile once by request ID, release a reservation if dispatch never occurred, and write a terminal state.

Reconciliation is idempotent for a known request ID. An unknown request ID is an error, not a new accounting record.

If dispatch, reconciliation, or related persistence cannot be trusted, the accounting latch remains visible across controller reconstruction. In enforce, the latch blocks new outbound work until the incomplete operation is reconciled. Provider calls are blocked before dispatch, tool schemas are filtered before a provider can see them, and tool bodies are blocked before execution when their decision is invalid. Schema-filtering failure never falls back to an unfiltered tool set.

Context pressure and compaction

Governance checks context pressure before the next provider call. One continuous pressure episode receives at most one compaction attempt. Recovery rearms compaction for a later episode; loop iterations inside the same episode do not create new opportunities.

Before retrying, the original preflight reservation is released. The retry uses a new attempt and request ID while preserving the logical call. A review fork retains the initial brief and protected fields such as scope, decisions, evidence and claim IDs, QA obligations, artifact references, and open questions.

A compaction persistence failure produces a governed stop and accounting error. An unavailable auxiliary provider does not create a fictional provider call; the pre-dispatch reservation is released.

Human authorization and textual or Telegram decisions

When enforce reaches approval or hard_stop, the gateway creates a request-scoped authorization record and provides its opaque authorization ID. A trusted, authenticated textual control channel can submit exactly one of these commands:

!budget approve auth-<opaque-id>
!budget deny auth-<opaque-id>

The gateway intercepts an exact command before the next LLM call. The LLM does not interpret, approve, or deny the decision. Approval applies only to the proposed envelope already persisted with that authorization record; the user cannot replace it with an arbitrary budget or submit a client-defined envelope. The authorization is bound to the authenticated principal, profile, engagement, task, chat, logical call, and request scope.

Authorizations expire and are single-use. Replayed, malformed, expired, superseded, unauthenticated, or out-of-scope commands are rejected. A denial consumes the decision and leaves the paused execution stopped. An ordinary natural-language message, an untrusted event, or text that does not exactly match one of the commands is not a budget authorization decision.

Telegram approval and denial callbacks:

  • use an opaque value within Telegram's callback-data limit;
  • are bound server-side to profile, engagement, logical call, owner, chat, and request context;
  • expire, can be superseded, and are consumed atomically only once;
  • derive the decision from the stored envelope instead of accepting a client-supplied replacement;
  • are processed without an LLM call.

Textual decisions and Telegram callbacks are one-time operations. Unauthenticated, ambiguous, failed, expired, replayed, superseded, or scope-mismatched decisions deny access. An authorization error or persistence failure does not resume execution and does not fall through to allow-all settings, pairing, or another profile's configuration. This preserves isolation across profiles, engagements, chats, tasks, logical calls, and requests, including Telegram DM, group, and forum contexts.

Telegram inline approval and denial callbacks remain supported. The textual command path uses the same persisted authorization contract but is platform-independent, so another authenticated gateway transport can support it without asking an LLM to interpret the decision.

Artifacts and data minimization

Governance stores operational artifacts below the active profile's canonical Hermes home and the configured relative workspace, normally:

<profile Hermes home>/engagements/<engagement_id>/

The principal artifacts are:

  • .session-engagement-index.json at the configured workspace root for the validated profile/session-to-engagement mapping;
  • brief.json for request metadata, selected agents, the envelope, QA reserve, and preserved review fields;
  • budget.json for the shared budget, reservations, request states, child allocations, authorizations, and accounting latch;
  • governance_status.json for active/disabled state and identity;
  • checkpoints/ and partial_handoffs/ for bounded, resumable state;
  • telemetry.jsonl for append-only lifecycle events;
  • governance_artifact_errors.jsonl for sanitized invalid/unreadable artifact records.

Persisted governance payloads intentionally omit prompts, tool arguments and results, capability values, callback tokens, authorization headers, and raw exception text. Context and exception details are represented with bounded metadata such as hashes, counts, sizes, categories, fingerprints, and stable internal IDs.

An absent artifact may be created during legitimate initialization. Existing session mappings, briefs, budgets, authorization records, and other decision-bearing artifacts must have the expected structure, types, identity, and scope. A malformed, unreadable, conflicting, or scope-invalid artifact is not treated as a fresh default: the error is recorded in sanitized form and the affected provider/tool path fails closed in enforce. In observe, the condition remains visible without being presented as canonical accounting.

Rollout, diagnosis, and rollback

Recommended rollout:

  1. Start in observe.
  2. Validate the profile home, artifacts, telemetry, usage, reservations, child allocations, and QA reserve.
  3. Exercise a bounded delegated task and one context-pressure episode; verify narrowed child toolsets and rearming only after recovery.
  4. Move to enforce after the artifact lifecycle and accounting behavior are understood.

If the accounting latch is active, inspect the sanitized checkpoint, partial handoff, affected request state in budget.json, and its telemetry transition. Reconcile or discard the incomplete operation before resuming; do not manually mark a provider call successful.

Operational rollback is configuration-only: return to observe for diagnostic continuation or to disabled to turn off the active controller, then restart the affected runtime processes and begin a new session. v0.7.6 does not define a separate governance rollback command.

Clone this wiki locally