Adaptation Budget

Harmovela Adaptation Budget Specification

> Status: draft. Part of the 0.5 Adaptation Preview.

Purpose

Define budget authority (who may establish a budget), the enforcement point (where the budget is checked), and the events emitted when a budget limit is approached or exceeded. Budget semantics provide the economic boundary for L3 production autonomy: a system that adapts must do so within declared, enforced resource limits.

This specification builds on the L1 advisory budget surface in L1 policy surface and makes it enforceable at L3. The shape of the budget declaration is the same; the difference is that the runtime now checks, enforces, and emits structured events at the protocol boundary.

Budget Authority

Who Sets the Budget

Budget authority follows the delegation chain. The delegating agent (the agent that dispatches a task to a bounded agent) is the budget authority for that task. This mirrors the ownership model in the coordination profile: the delegator owns the task and sets its resource boundaries.

digraph budget_authority {
    rankdir=LR;
    delegator [label="Delegating Agent\n(budget authority)"];
    delegate [label="Bounded Agent\n(budget consumer)"];
    delegator -> delegate [label="task.submitted\n+budget declaration"];
}

A bounded agent may propose a budget in its own session.ready capabilities, but the effective budget is always the stricter intersection of the delegator's requirement and the delegate's self-declared limits. The delegator has final authority: if the delegate proposes no budget, the delegator's budget applies; if the delegator proposes no budget, the task is unbounded (advisory at L1, rejected at L3 unless explicitly allowed).

Budget Establishment Event

The adaptation.budget.established event is emitted when an effective budget is agreed for a task or goal. It serves as the authoritative record of the resource contract.

{
  "type": "adaptation.budget.established",
  "id": "evt_budget_est_01",
  "source": "harness:adaptation",
  "created_at": "2026-07-14T10:00:00Z",
  "payload": {
    "scope_type": "task",
    "scope_id": "task_01",
    "goal_id": "goal_ping_cycle_01",
    "budget": {
      "max_cost_usd_millicents": 100000,
      "max_duration_ms": 300000,
      "max_actions": 50
    },
    "authority": {
      "issuer": "agent:supervisor",
      "capability": "budget.establish",
      "granted_at": "2026-07-14T10:00:00Z"
    },
    "delegation_chain": [
      { "agent_id": "agent:supervisor", "role": "delegator" },
      { "agent_id": "agent:pinger",    "role": "delegate" }
    ],
    "established_at": "2026-07-14T10:00:00Z"
  }
}
FieldTypeRequiredDescription
payload.scope_typestringyesThe scope of the budget: task, goal, or session.
payload.scope_idstringyesIdentifier of the scoped entity.
payload.goal_idstringnoThe goal identifier if the task serves a declared goal.
payload.budgetobjectyesThe effective budget limits. Same shape as capabilities.budget.
payload.authorityobjectyesThe authority under which the budget was established.
payload.authority.issuerstringyesThe agent that authorized the budget.
payload.authority.capabilitystringyesMust be budget.establish.
payload.authority.granted_atstringyesISO 8601 timestamp of the grant.
payload.delegation_chainarrayyesOrdered delegation path.
payload.established_atstringyesISO 8601 timestamp of establishment.

Budget Change

A budget may be changed after establishment only by the delegating agent that set it, through a new adaptation.budget.established event with an updated budget payload. The new event references the prior event via causation_id. A bounded agent may request a budget increase through task.progress with a budget_increase_requested detail, but only the delegator may grant it.

Enforcement Point

Where the Budget Is Checked

Budget enforcement is a runtime-level check that occurs at the protocol boundary, not in application logic. The enforcement point is the harness (orchestrator) that mediates between the delegating agent and the bounded agent:

digraph enforcement {
    rankdir=TB;
    delegate [label="Bounded Agent"];
    harness [label="Harness\n(enforcement point)", shape=box, style=filled, fillcolor=lightgrey];
    delegator [label="Delegating Agent"];

    delegate -> harness [label="action events\n(task.progress, tool.call.*)"];
    harness -> delegator [label="budget exceeded\nevents"];
    harness -> delegate [label="enforcement\n(task.cancelled,\nsession.error)"];
}

The harness maintains a resource counter per scoped budget. Before dispatching each action event from the bounded agent, the harness checks the current counter against the declared budget:

1. If the counter is below the limit, the action proceeds. 2. If the counter is approaching the limit (within the warning threshold), the harness emits adaptation.budget.limit_approaching and lets the action proceed. 3. If the counter exceeds the limit, the harness emits adaptation.budget.limit_exceeded, blocks the action, and enforces the termination declared in capabilities.termination.on_budget_exhausted.

Per-action checks:

Warning Threshold

Each budget dimension has a configurable warning ratio (default 0.8). When consumption reaches the warning threshold, adaptation.budget.limit_approaching is emitted. The warning ratio may be configured per budget at establishment time:

{
  "payload": {
    "budget": {
      "max_cost_usd_millicents": 100000,
      "max_duration_ms": 300000,
      "max_actions": 50,
      "warning_ratio": 0.75
    }
  }
}

A warning_ratio of 1.0 disables the warning event (only the exceedance event fires). A warning_ratio of 0.0 emits the warning immediately upon the first consumption.

Budget Events

adaptation.budget.limit_approaching

Emitted when consumption on any budget dimension reaches the warning threshold. This is an advisory signal: the bounded agent is approaching its limit but is not yet blocked.

{
  "type": "adaptation.budget.limit_approaching",
  "id": "evt_budget_app_01",
  "source": "harness:adaptation",
  "created_at": "2026-07-14T10:28:00Z",
  "correlation_id": "task_01",
  "payload": {
    "scope_type": "task",
    "scope_id": "task_01",
    "goal_id": "goal_ping_cycle_01",
    "dimension": "max_actions",
    "declared": 50,
    "consumed": 40,
    "warning_ratio": 0.8,
    "remaining": 10,
    "approaching_at": "2026-07-14T10:28:00Z"
  }
}
FieldTypeRequiredDescription
payload.scope_typestringyestask, goal, or session.
payload.scope_idstringyesIdentifier of the scoped entity.
payload.goal_idstringnoThe goal identifier, if applicable.
payload.dimensionstringyesThe budget dimension approaching its limit.
payload.declarednumberyesThe declared limit.
payload.consumednumberyesCurrent consumption.
payload.warning_rationumberyesThe warning threshold ratio used.
payload.remainingnumberyesdeclared - consumed.
payload.approaching_atstringyesISO 8601 timestamp when the warning threshold was crossed.

adaptation.budget.limit_exceeded

Emitted when consumption on any budget dimension exceeds the declared limit. This is an enforcement event: the runtime blocks further consumption and enforces the configured termination behavior.

{
  "type": "adaptation.budget.limit_exceeded",
  "id": "evt_budget_exc_01",
  "source": "harness:adaptation",
  "created_at": "2026-07-14T10:32:00Z",
  "correlation_id": "task_01",
  "causation_id": "task_01",
  "payload": {
    "scope_type": "task",
    "scope_id": "task_01",
    "goal_id": "goal_ping_cycle_01",
    "dimension": "max_actions",
    "declared": 50,
    "consumed": 51,
    "enforcement_action": "task_failed",
    "budget_established_event_id": "evt_budget_est_01",
    "exceeded_at": "2026-07-14T10:32:00Z"
  }
}
FieldTypeRequiredDescription
payload.scope_typestringyestask, goal, or session.
payload.scope_idstringyesIdentifier of the scoped entity.
payload.goal_idstringnoThe goal identifier, if applicable.
payload.dimensionstringyesThe budget dimension that was exceeded.
payload.declarednumberyesThe declared limit.
payload.consumednumberyesConsumption at the point of exceedance.
payload.enforcement_actionstringyesAction taken by the runtime: task_failed, task_cancelled, task_escalated, session_quarantined.
payload.budget_established_event_idstringyesThe id of the adaptation.budget.established event that set this budget.
payload.exceeded_atstringyesISO 8601 timestamp of exceedance.

Budget Exhaustion Outcome

When a budget is exceeded, the runtime also emits the more general adaptation.cost.exceeded event defined in adaptation feedback. The adaptation.budget.limit_exceeded is the enforcement signal; adaptation.cost.exceeded is the feedback signal — they carry overlapping but distinct information and serve different consumers.

EventPurposePrimary consumer
adaptation.budget.limit_exceededRuntime enforcement recordHarness, delegator (immediate action)
adaptation.cost.exceededFeedback/correlation recordGoal evaluator, audit system (post-hoc analysis)

Enforcement Actions

When a budget limit is exceeded, the runtime takes the action configured in capabilities.termination.on_budget_exhausted:

on_budget_exhaustedRuntime actionEmitted task event
failMark the task as failed. Block further actions for this task.task.failed with code budget_exceeded
cancelCancel the task and propagate cancellation to child tasks.task.cancelled
escalateEscalate the task back to the delegating agent.task.escalated

At L3, ignore is not a valid on_budget_exhausted value. An implementation that declares ignore for budget exhaustion must be rejected during capability negotiation with code invalid_capability.

Multi-Scope Budgets

Goal-Scoped Budgets

A budget may be established for a goal rather than a single task. A goal-scoped budget is shared across all tasks dispatched toward that goal. The counter accumulates across all tasks:

{
  "type": "adaptation.budget.established",
  "payload": {
    "scope_type": "goal",
    "scope_id": "goal_backup_cycle_01",
    "budget": {
      "max_cost_usd_millicents": 500000,
      "max_duration_ms": 3600000,
      "max_actions": 200
    }
  }
}

When a goal-scoped budget is exceeded, all in-flight tasks for that goal are terminated with the configured enforcement action.

Session-Scoped Budgets

A session-scoped budget is established at session.ready negotiation and applies to all tasks within that session. Session-scoped budgets are additive with task-scoped budgets: each task must respect both its own budget and the remaining session budget.

When a session-scoped budget is exceeded, the session enters a terminal state. No new tasks may be accepted. In-flight tasks are terminated per capabilities.termination.on_budget_exhausted.

Budget Precedence

When multiple budget scopes apply, the tightest effective remaining limit for each dimension applies. For example, if a task has max_actions: 50 and the session has 3 actions remaining, the effective limit is 3.

Audit Trail

All budget events are governance-audited events. The audit record for each budget event includes:

FieldSource
Event idEnvelope
Event typeEnvelope
scope_type and scope_idPayload
dimensionPayload
declared limitPayload
consumed amountPayload
authority.issuerPayload
Actor identity (transport)Transport binding
Budget establishment event idPayload (limit_exceeded only)

L1 → L3 Migration

AspectL1 (advisory)L3 (enforced)
Budget declarationcapabilities.budget in session.readySame shape; also emitted as adaptation.budget.established
Enforcement pointAgent self-checksHarness checks before each action dispatch
Warning signalNot definedadaptation.budget.limit_approaching
Exceedance signaltask.failed with budget_exceeded (voluntary)adaptation.budget.limit_exceeded + adaptation.cost.exceeded (enforced)
Authority verificationNot checkedbudget.establish capability required
Multi-scope budgetsNot definedGoal-scoped and session-scoped budgets with precedence rules
QuarantineNot definedRuntime may quarantine sessions that exceed budgets

Dependencies