Skip to content

v0.14.0: tool gate freeze, definition pins, policy compare and cost reservation - #18

Merged
renezander030 merged 2 commits into
masterfrom
release/v0.14.0
Oct 31, 2026
Merged

renezander030 merged 2 commits into
masterfrom
release/v0.14.0

Conversation

@renezander030

Copy link
Copy Markdown
Owner

Features

  • Freeze the tool gate. /freeze [reason] and /unfreeze in Telegram, or draftcat gate freeze|unfreeze|status, stop every gated tool call at once. While the gate is frozen it denies each call with "tool gate frozen by operator", refuses to consume issued permits and leaves standing grants unused. The freeze is stored, holds across a restart and reaches a running engine on its next call.
  • Pin a tool's definition. Set definition_sha256 on a tool rule. The harness sends the tool's definition with the call, and a missing or changed definition is handled like an argument mismatch. draftcat gate hash-definition prints the value; gate check --definition and definition: in test cases decide it offline.
  • Compare two policies. draftcat gate test cases.yaml --config new.yaml --compare old.yaml prints only the cases that decide differently and exits 1 when any does.
  • Reserve a call's worst-case cost. With budgets.reserve_max_cost: true, or the same key on a pipeline's budget, a model call is admitted only if settled spend plus the call's maximum cost stays within per_day_cost. The actual cost replaces the reservation when the call settles.
  • Daily digest of what needs a person. telegram.digest: {at: "08:00", timezone: Europe/Berlin} sends one message a day listing approvals waiting over an hour, a frozen gate and failed tool outcomes of the last day. On a day with none of these, nothing is sent.
  • Tidy-up, as the first commit. The tool gate answers unknown and unavailable actions from one place, sorted keys come from the standard library, and a test pins how a config reload treats every config section.

Evidence

  • go build ./..., go vet ./... and go vet -tags voice ./... pass.
  • go test -short ./..., go test -short -tags voice ./..., go test -race -short ./... and the full non-short suite (three consecutive runs) pass.
  • go run . validate reports 0 errors. npm ci --ignore-scripts && npm test && npm pack --dry-run and the teams-relay build pass. golangci-lint run --new-from-rev on master reports 0 issues.
  • The help and usage texts of 21 command forms were compared before and after the refactors, and so were the import graph and 41 read-only command outputs (empty store, populated store, the new commands); they match. An engine smoke run passes all 17 checks: caller tokens, grants, consume, revoke and complete, webhook schema, receipt anchor and redaction.
  • New tests cover the freeze (deny, consume refused, grants unused, survives a reopen, CLI round trip, non-operator refused), the definition pin (match, key order, changed or missing definition per on_mismatch, no pin unchanged, policy hash), compare mode, cost reservation (cap edge, concurrent calls, settlement, reopen) and the digest (silent day, once per day across a restart, retry).

Door

Two-way. Every new setting is optional, and a configuration without it decides exactly as before. Rules without definition_sha256 keep their policy hashes, and the golden hash tests are unchanged. The state changes are additive: the gate_freeze and operator_digest tables and two columns on budget_calls, all created at first start. Older binaries ignore them.

Blast radius

  • Touched: the tool gate decision path (freeze check first, definition match inside the existing mismatch branch), budget admission (one extra clause, active only with reserve_max_cost), the gate CLI (new subcommands and flags), the Telegram command list, the engine loop (digest tick), internal/state migrations, validation, and docs (docs/tool-gate.md, docs/governance-lifecycle.md, docs/operations.md).
  • Untouched: receipt formats and signatures, the relay protocol, webhook handling, the scheduler, and the help text of existing commands. The gate usage gains its new lines, and one sentence about the state store now names the subcommands it applies to.

Review notes

  • Base: master a9697f8.
  • The first commit is a behavior-preserving tidy-up and can be reviewed on its own. The second commit holds the features.
  • No other open pull requests overlap.

- tool gate: one accessor for the in-memory action ticket and one answer
  for a failed state-store read (unknown action 404, store unavailable 503)
- sorted map keys come from the standard library (slices.Sorted over
  maps.Keys); three local helpers removed
- a test pins how config reload treats every config section: applied on
  reload or kept until restart

No change to commands, output, configuration or stored data.
…eservation

- Freeze the tool gate from Telegram (/freeze, /unfreeze) or with
  draftcat gate freeze|unfreeze|status; a frozen gate denies every call,
  refuses to consume permits and leaves standing grants unused
- Pin a tool's definition with definition_sha256 on a rule; a missing or
  changed definition is handled like an argument mismatch; gate
  hash-definition prints the value
- gate test --compare old.yaml prints the cases that decide differently
- budgets.reserve_max_cost admits a model call only if its worst-case
  cost fits the daily cost cap
- telegram.digest sends one daily message with what needs a person, and
  nothing on a day without
@renezander030
renezander030 merged commit c757b57 into master Oct 31, 2026
@renezander030
renezander030 deleted the release/v0.14.0 branch October 31, 2026 09:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant