Draft the 2026-09-21 spend-envelope budget memo for SECRETS-WP-0009-T03
One unsigned memo, infd-20260921-b01, accepting the Glas Anthropic spend envelope. The approval-create tool now takes an explicit batch, receipt and expected count; defaults keep the 2026-09-14 sitting unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 272244@bnt-lap001 Assistant-Session: c8962fa7-b290-47df-865f-403ddb6c77e9
This commit is contained in:
parent
1bce7c663a
commit
c8c60ebc21
9 changed files with 366 additions and 3 deletions
47
docs/batches/2026-09-21/OPERATOR.md
Normal file
47
docs/batches/2026-09-21/OPERATOR.md
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Budget sitting — operator packet (SECRETS-WP-0009-T03)
|
||||||
|
|
||||||
|
Review group: `net-kingdom-admins`.
|
||||||
|
Surface: https://decisions.coulomb.social/
|
||||||
|
Contract: `docs/specs/CompactSignoffBatches.md`.
|
||||||
|
Generator: `tools/prepare_budget_batch.py` (re-running rewrites the same bytes).
|
||||||
|
|
||||||
|
An agent may draft, order, and record evidence. It may not `accept` / `decline` / `seal`.
|
||||||
|
|
||||||
|
## One unsigned memo
|
||||||
|
|
||||||
|
| n | memo_id | Blocking record |
|
||||||
|
| --: | --- | --- |
|
||||||
|
| 1 | `infd-20260921-b01` | SECRETS-WP-0009-T03 spend envelope (`authority_ref` for HFACT-WP-0001 SpendPolicy) |
|
||||||
|
|
||||||
|
Required acknowledgement: the EUR 100 monthly limit is recorded, not enforced.
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
1. **Create the native approval (attended).** Same contained reader as the
|
||||||
|
2026-09-14 sitting, with the batch selected explicitly:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tools/create_sitting_approvals.sh --sitting 2026-09-21 \
|
||||||
|
--receipt 2026-09-21-budget-approval-create.json --expect 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Check first without credentials:
|
||||||
|
`.venv/bin/python -B tools/create_sitting_approvals.py --dry-run --sitting 2026-09-21 --receipt 2026-09-21-budget-approval-create.json --expect 1`.
|
||||||
|
The receipt at `docs/evidence/2026-09-21-budget-approval-create.json` gives
|
||||||
|
`approval_id` and the engine-computed binding digest.
|
||||||
|
|
||||||
|
2. **Flex Auth admission as a visible version change.** In
|
||||||
|
`flex-auth/examples/informed-decision-sitting/policy.md`: `version: v1` → `v2`,
|
||||||
|
add `"memo:infd-20260921-b01"` to `records` with the receipt's `approval_id`,
|
||||||
|
`binding_digest`, `label: "b01"`, the binding from
|
||||||
|
`approval-create-intents.json`, `memo_version: 1`; mirror it in `records.json`.
|
||||||
|
Keep all seven v1 records. Do not add the record before step 1: an empty
|
||||||
|
approval id must never be a policy value. Build the image in CI, bump
|
||||||
|
`values/informed-decision-sitting.yaml` digest, deploy.
|
||||||
|
|
||||||
|
3. **Point Informed Decision at v2.** `deploy/sitting-admission.json`:
|
||||||
|
`version: v2`, new `package_digest`. Roll out the review service.
|
||||||
|
|
||||||
|
4. **Load and sit.** Attach the live KeyCape subject, load the memo
|
||||||
|
(`tools/load_sitting_memos.py`), and the human accepts at the surface.
|
||||||
|
The accepted approval id is recorded as `authority_ref` in the SpendPolicy.
|
||||||
28
docs/batches/2026-09-21/approval-create-intents.json
Normal file
28
docs/batches/2026-09-21/approval-create-intents.json
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"kind": "informed-decision-approval-create-intents",
|
||||||
|
"sitting_id": "infd-sitting-2026-09-21",
|
||||||
|
"status": "not-posted",
|
||||||
|
"posted": false,
|
||||||
|
"requester_client": "informed-decision-sitting-requester",
|
||||||
|
"human_control": true,
|
||||||
|
"pdp_path": false,
|
||||||
|
"required_count": 1,
|
||||||
|
"note": "Intents only. Digests are computed by approval-engine at create; do not invent them here.",
|
||||||
|
"intents": [
|
||||||
|
{
|
||||||
|
"memo_id": "infd-20260921-b01",
|
||||||
|
"create_client": "informed-decision-sitting-requester",
|
||||||
|
"binding": {
|
||||||
|
"action": "accept",
|
||||||
|
"actor": "informed-decision",
|
||||||
|
"principal": "helixforge-factory",
|
||||||
|
"purpose": "Accept the spend envelope for metered Glas runs on the Anthropic key",
|
||||||
|
"target": {
|
||||||
|
"id": "spend-envelope:hfact-glas-anthropic-2026-09",
|
||||||
|
"type": "spend-envelope",
|
||||||
|
"system": "rein-aharness"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
24
docs/batches/2026-09-21/budget/index.json
Normal file
24
docs/batches/2026-09-21/budget/index.json
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"kind": "informed-decision-batch",
|
||||||
|
"id": "infd-batch-2026-09-21-budget",
|
||||||
|
"review_group": "net-kingdom-admins",
|
||||||
|
"status": "draft-unsigned",
|
||||||
|
"submitted": false,
|
||||||
|
"one_question_per_memo": true,
|
||||||
|
"approve_all_forbidden": true,
|
||||||
|
"agent_disposition_forbidden": true,
|
||||||
|
"ordinal": [
|
||||||
|
{
|
||||||
|
"n": 1,
|
||||||
|
"memo_id": "infd-20260921-b01",
|
||||||
|
"workplan": "SECRETS-WP-0009",
|
||||||
|
"task": "SECRETS-WP-0009-T03",
|
||||||
|
"hub_task_prefix": "f8069c8a",
|
||||||
|
"question": "Accept the spend envelope for metered Glas runs on the Anthropic key (EUR 5 per run, 20 per day, 500 total, until 2027-01-31)?",
|
||||||
|
"memo": "infd-20260921-b01.memo.json",
|
||||||
|
"packet": "infd-20260921-b01.packet.md",
|
||||||
|
"packet_hash": "sha256:a3d3f4e33d75579795c0e407971c0d472432569ef68a9408e9897587a58f0deb",
|
||||||
|
"required_highlight": "infd-20260921-b01-h1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"approval_binding_digest":null,"approval_id":null,"binding":{"justification":null,"principal":{"display_name":"Named reviewer in net-kingdom-admins","id":"pending-human-session","identifiers":[],"kind":"person","role":"reviewer"},"target":{"environment":"prod","id":"spend-envelope:hfact-glas-anthropic-2026-09","kind":"spend-envelope","label":"Glas metered runs on the Anthropic key (railiance01)","requires_new_bind":false},"terms":null},"binding_level":"organizational","brief":"Sets the spending authority that rein-aharness MessagesOwner enforces before each metered Glas run on railiance01. Accepting it does not deliver the key, run a model or create an OpenBao policy; those are three separate SECRETS-WP-0009-T03 approvals. The EUR 100 monthly limit is recorded here but not enforced by the software.","highlights":[{"id":"infd-20260921-b01-h1","item_id":"infd-20260921-b01-packet","locator":{"kind":"work_record","task":"SECRETS-WP-0009-T03","workplan":"SECRETS-WP-0009"},"note":"The EUR 100 per month limit is NOT enforced: SpendPolicy has no monthly ceiling. Only EUR 5 per run, EUR 20 per day and EUR 500 total are enforced. Every completed run is charged its full reservation (EUR 4.9938), not its actual cost.","required_ack":true,"severity":"critical"}],"id":"infd-20260921-b01","locale":"en","packet":[{"hash":"sha256:a3d3f4e33d75579795c0e407971c0d472432569ef68a9408e9897587a58f0deb","item_id":"infd-20260921-b01-packet","label":"infd-20260921-b01-packet"}],"question":"Accept the spend envelope for metered Glas runs on the Anthropic key (EUR 5 per run, 20 per day, 500 total, until 2027-01-31)?","requested_act":"approve","sealed":false,"step_kind":"approve","ui_release":"informed-decision@0.2.0","version":1}
|
||||||
51
docs/batches/2026-09-21/budget/infd-20260921-b01.packet.md
Normal file
51
docs/batches/2026-09-21/budget/infd-20260921-b01.packet.md
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# SECRETS-WP-0009-T03 — spend envelope for metered Glas runs
|
||||||
|
|
||||||
|
Blocking workplan: SECRETS-WP-0009
|
||||||
|
Blocking task: SECRETS-WP-0009-T03 (hub prefix f8069c8a)
|
||||||
|
Related: HFACT-WP-0001-T01/T04 (SpendPolicy and owner config), GLAS-WP-0012
|
||||||
|
|
||||||
|
## Question
|
||||||
|
Accept the spend envelope for metered Glas runs on the Anthropic key (EUR 5 per run, 20 per day, 500 total, until 2027-01-31)?
|
||||||
|
|
||||||
|
## One act
|
||||||
|
Accept this envelope as the spend authority for rein-aharness MessagesOwner
|
||||||
|
`metered-once` runs on railiance01 using the Anthropic key of catalog lane
|
||||||
|
`glas-claude-agent-dev-anthropic`. The accepted approval id becomes the
|
||||||
|
SpendPolicy `authority_ref` for envelope `hfact-glas-anthropic-2026-09`.
|
||||||
|
|
||||||
|
## Enforced values (rein-aharness SpendPolicy, decimal strings)
|
||||||
|
|
||||||
|
| Field | Value | Note |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `per_run_eur` | 5 | Operator-stated |
|
||||||
|
| `daily_eur` | 20 | Operator-stated; timezone Europe/Berlin |
|
||||||
|
| `total_eur` | 500 | Operator-stated; over the whole envelope |
|
||||||
|
| `eur_per_usd` | 0.87 | Operator rate 1 EUR = 1.15 USD (1/1.15 = 0.8696), rounded up |
|
||||||
|
| `max_liability_usd` | 5.74 | Per run. Reserves ceil(5.74 x 0.87) = EUR 4.9938, inside EUR 5 |
|
||||||
|
| `max_budget_usd` | 5.00 | Per run. Claude CLI stop threshold, inside liability |
|
||||||
|
| `valid_from` | acceptance time | |
|
||||||
|
| `expires_at` | 2027-01-31T23:59:59+01:00 | Operator-stated |
|
||||||
|
|
||||||
|
Resulting capacity: at most 4 runs per day and 100 runs in total. A completed run
|
||||||
|
is charged its full reservation, not its reported cost. A failed, cancelled or
|
||||||
|
unaccounted run keeps its reservation and blocks further runs until reconciled.
|
||||||
|
Cost above liability permanently marks the envelope breached.
|
||||||
|
|
||||||
|
The operator's overall USD 600 budget and USD 800 liability caps are dominated
|
||||||
|
by `total_eur` 500 (= USD 575) and need no separate field.
|
||||||
|
|
||||||
|
## Recorded, not enforced
|
||||||
|
- EUR 100 per calendar month. SpendPolicy has no monthly ceiling; a rein-aharness
|
||||||
|
follow-up adds `monthly_eur`. Until then the operator reviews monthly use.
|
||||||
|
|
||||||
|
## Scope bound by the SpendPolicy, filled in before the private file is written
|
||||||
|
`worker_id`, `activity_definition_id`, `target_repo`, `project`, `profile_ref`,
|
||||||
|
`profile_sha256`, `descriptor_sha256`, `repository_grant_id`, `max_turns` come from
|
||||||
|
the admitted factory profile (HFACT-WP-0001-T01). They narrow this envelope; they
|
||||||
|
cannot widen the amounts above.
|
||||||
|
|
||||||
|
## Must not
|
||||||
|
- Deliver, read or display the Anthropic key
|
||||||
|
- Authorize the OpenBao apply, verify or exec actions (separate T03 approvals)
|
||||||
|
- Cover llm-connect or its DeepSeek default; that path is not this envelope
|
||||||
|
- Raise any amount or extend the expiry without a new memo
|
||||||
12
docs/batches/2026-09-21/sitting.json
Normal file
12
docs/batches/2026-09-21/sitting.json
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"kind": "informed-decision-sitting",
|
||||||
|
"id": "infd-sitting-2026-09-21",
|
||||||
|
"review_group": "net-kingdom-admins",
|
||||||
|
"status": "draft-unsigned",
|
||||||
|
"batches": [
|
||||||
|
"infd-batch-2026-09-21-budget"
|
||||||
|
],
|
||||||
|
"memo_count": 1,
|
||||||
|
"bind_path": "create approval (attended), Flex Auth exact-record admission, load store, human accept",
|
||||||
|
"note": "Unsigned draft. Live bind substitutes pending-human-session with the authenticated key-cape subject."
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ from urllib.request import HTTPRedirectHandler, ProxyHandler, Request, build_ope
|
||||||
ROOT = Path(__file__).resolve().parents[1]
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
INTENTS = ROOT / "docs" / "batches" / "2026-09-14" / "approval-create-intents.json"
|
INTENTS = ROOT / "docs" / "batches" / "2026-09-14" / "approval-create-intents.json"
|
||||||
RECEIPT = ROOT / "docs" / "evidence" / "2026-09-15-sitting-approval-creates.json"
|
RECEIPT = ROOT / "docs" / "evidence" / "2026-09-15-sitting-approval-creates.json"
|
||||||
|
EXPECTED = 7
|
||||||
POLICY = "workload-kv-read-informed-decision-sitting-requester-client"
|
POLICY = "workload-kv-read-informed-decision-sitting-requester-client"
|
||||||
KV = "platform/data/workloads/informed-decision/sitting-requester"
|
KV = "platform/data/workloads/informed-decision/sitting-requester"
|
||||||
SIBLING = "platform/data/workloads/secrets-engine/approval-requester"
|
SIBLING = "platform/data/workloads/secrets-engine/approval-requester"
|
||||||
|
|
@ -76,8 +77,8 @@ def existing_receipt_blocks() -> bool:
|
||||||
|
|
||||||
def postable_intents(data: dict) -> list[dict]:
|
def postable_intents(data: dict) -> list[dict]:
|
||||||
rows = [row for row in data.get("intents") or [] if row.get("create_client") == CLIENT_ID]
|
rows = [row for row in data.get("intents") or [] if row.get("create_client") == CLIENT_ID]
|
||||||
if len(rows) != 7:
|
if len(rows) != EXPECTED:
|
||||||
raise ValueError("expected seven postable sitting intents")
|
raise ValueError(f"expected {EXPECTED} postable sitting intents")
|
||||||
for row in rows:
|
for row in rows:
|
||||||
binding = row["binding"]
|
binding = row["binding"]
|
||||||
if binding.get("actor") != "informed-decision":
|
if binding.get("actor") != "informed-decision":
|
||||||
|
|
@ -116,7 +117,18 @@ def main() -> int:
|
||||||
parser = argparse.ArgumentParser(description=__doc__)
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
parser.add_argument("--dry-run", action="store_true", help="list postable memos; no credentials, no POST")
|
parser.add_argument("--dry-run", action="store_true", help="list postable memos; no credentials, no POST")
|
||||||
parser.add_argument("--approval-origin", help="approval-engine origin; or INFD_APPROVAL_ORIGIN")
|
parser.add_argument("--approval-origin", help="approval-engine origin; or INFD_APPROVAL_ORIGIN")
|
||||||
|
parser.add_argument("--sitting", help="batch date directory under docs/batches, e.g. 2026-09-21")
|
||||||
|
parser.add_argument("--receipt", help="receipt file name under docs/evidence; required with --sitting")
|
||||||
|
parser.add_argument("--expect", type=int, help="exact number of postable intents; required with --sitting")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
global INTENTS, RECEIPT, EXPECTED
|
||||||
|
if args.sitting:
|
||||||
|
if not args.receipt or not args.expect or "/" in args.sitting or "/" in args.receipt:
|
||||||
|
print("sitting_requires_receipt_and_expect", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
INTENTS = ROOT / "docs" / "batches" / args.sitting / "approval-create-intents.json"
|
||||||
|
RECEIPT = ROOT / "docs" / "evidence" / args.receipt
|
||||||
|
EXPECTED = args.expect
|
||||||
if args.dry_run:
|
if args.dry_run:
|
||||||
print(json.dumps(dry_run(), indent=2, ensure_ascii=False))
|
print(json.dumps(dry_run(), indent=2, ensure_ascii=False))
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,5 @@ set -euo pipefail
|
||||||
export INFD_APPROVAL_ORIGIN="${INFD_APPROVAL_ORIGIN:-http://127.0.0.1:18281}"
|
export INFD_APPROVAL_ORIGIN="${INFD_APPROVAL_ORIGIN:-http://127.0.0.1:18281}"
|
||||||
exec /home/worsch/informed-decision/.venv/bin/python -B \
|
exec /home/worsch/informed-decision/.venv/bin/python -B \
|
||||||
/home/worsch/informed-decision/tools/create_sitting_approvals.py \
|
/home/worsch/informed-decision/tools/create_sitting_approvals.py \
|
||||||
--approval-origin "$INFD_APPROVAL_ORIGIN" \
|
--approval-origin "$INFD_APPROVAL_ORIGIN" "$@" \
|
||||||
>/dev/null 2>&1
|
>/dev/null 2>&1
|
||||||
|
|
|
||||||
188
tools/prepare_budget_batch.py
Normal file
188
tools/prepare_budget_batch.py
Normal file
|
|
@ -0,0 +1,188 @@
|
||||||
|
"""Draft the unsigned 2026-09-21 spend-envelope budget memo (SECRETS-WP-0009-T03).
|
||||||
|
|
||||||
|
One question, one memo. No secret values. Does not submit, present, or bind.
|
||||||
|
The accepted approval id becomes the SpendPolicy ``authority_ref``.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||||
|
|
||||||
|
from prepare_compact_batches import REVIEW_GROUP, _memo, _sha # noqa: E402
|
||||||
|
|
||||||
|
from informed_decision.memo import Scope # noqa: E402
|
||||||
|
from informed_decision.records import dumps, memo_from # noqa: E402
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1] / "docs" / "batches" / "2026-09-21"
|
||||||
|
MEMO_ID = "infd-20260921-b01"
|
||||||
|
ENVELOPE_ID = "hfact-glas-anthropic-2026-09"
|
||||||
|
WORKPLAN = "SECRETS-WP-0009"
|
||||||
|
TASK = "SECRETS-WP-0009-T03"
|
||||||
|
HUB_TASK_PREFIX = "f8069c8a"
|
||||||
|
|
||||||
|
QUESTION = (
|
||||||
|
"Accept the spend envelope for metered Glas runs on the Anthropic key "
|
||||||
|
"(EUR 5 per run, 20 per day, 500 total, until 2027-01-31)?"
|
||||||
|
)
|
||||||
|
BRIEF = (
|
||||||
|
"Sets the spending authority that rein-aharness MessagesOwner enforces before each "
|
||||||
|
"metered Glas run on railiance01. Accepting it does not deliver the key, run a model "
|
||||||
|
"or create an OpenBao policy; those are three separate SECRETS-WP-0009-T03 approvals. "
|
||||||
|
"The EUR 100 monthly limit is recorded here but not enforced by the software."
|
||||||
|
)
|
||||||
|
HIGHLIGHT = (
|
||||||
|
"The EUR 100 per month limit is NOT enforced: SpendPolicy has no monthly ceiling. "
|
||||||
|
"Only EUR 5 per run, EUR 20 per day and EUR 500 total are enforced. Every completed "
|
||||||
|
"run is charged its full reservation (EUR 4.9938), not its actual cost."
|
||||||
|
)
|
||||||
|
TARGET = Scope(
|
||||||
|
kind="spend-envelope",
|
||||||
|
id=f"spend-envelope:{ENVELOPE_ID}",
|
||||||
|
label="Glas metered runs on the Anthropic key (railiance01)",
|
||||||
|
environment="prod",
|
||||||
|
)
|
||||||
|
BINDING = {
|
||||||
|
"action": "accept",
|
||||||
|
"actor": "informed-decision",
|
||||||
|
"principal": "helixforge-factory",
|
||||||
|
"purpose": "Accept the spend envelope for metered Glas runs on the Anthropic key",
|
||||||
|
"target": {
|
||||||
|
"id": f"spend-envelope:{ENVELOPE_ID}",
|
||||||
|
"type": "spend-envelope",
|
||||||
|
"system": "rein-aharness",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
PACKET = f"""# {TASK} — spend envelope for metered Glas runs
|
||||||
|
|
||||||
|
Blocking workplan: {WORKPLAN}
|
||||||
|
Blocking task: {TASK} (hub prefix {HUB_TASK_PREFIX})
|
||||||
|
Related: HFACT-WP-0001-T01/T04 (SpendPolicy and owner config), GLAS-WP-0012
|
||||||
|
|
||||||
|
## Question
|
||||||
|
{QUESTION}
|
||||||
|
|
||||||
|
## One act
|
||||||
|
Accept this envelope as the spend authority for rein-aharness MessagesOwner
|
||||||
|
`metered-once` runs on railiance01 using the Anthropic key of catalog lane
|
||||||
|
`glas-claude-agent-dev-anthropic`. The accepted approval id becomes the
|
||||||
|
SpendPolicy `authority_ref` for envelope `{ENVELOPE_ID}`.
|
||||||
|
|
||||||
|
## Enforced values (rein-aharness SpendPolicy, decimal strings)
|
||||||
|
|
||||||
|
| Field | Value | Note |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `per_run_eur` | 5 | Operator-stated |
|
||||||
|
| `daily_eur` | 20 | Operator-stated; timezone Europe/Berlin |
|
||||||
|
| `total_eur` | 500 | Operator-stated; over the whole envelope |
|
||||||
|
| `eur_per_usd` | 0.87 | Operator rate 1 EUR = 1.15 USD (1/1.15 = 0.8696), rounded up |
|
||||||
|
| `max_liability_usd` | 5.74 | Per run. Reserves ceil(5.74 x 0.87) = EUR 4.9938, inside EUR 5 |
|
||||||
|
| `max_budget_usd` | 5.00 | Per run. Claude CLI stop threshold, inside liability |
|
||||||
|
| `valid_from` | acceptance time | |
|
||||||
|
| `expires_at` | 2027-01-31T23:59:59+01:00 | Operator-stated |
|
||||||
|
|
||||||
|
Resulting capacity: at most 4 runs per day and 100 runs in total. A completed run
|
||||||
|
is charged its full reservation, not its reported cost. A failed, cancelled or
|
||||||
|
unaccounted run keeps its reservation and blocks further runs until reconciled.
|
||||||
|
Cost above liability permanently marks the envelope breached.
|
||||||
|
|
||||||
|
The operator's overall USD 600 budget and USD 800 liability caps are dominated
|
||||||
|
by `total_eur` 500 (= USD 575) and need no separate field.
|
||||||
|
|
||||||
|
## Recorded, not enforced
|
||||||
|
- EUR 100 per calendar month. SpendPolicy has no monthly ceiling; a rein-aharness
|
||||||
|
follow-up adds `monthly_eur`. Until then the operator reviews monthly use.
|
||||||
|
|
||||||
|
## Scope bound by the SpendPolicy, filled in before the private file is written
|
||||||
|
`worker_id`, `activity_definition_id`, `target_repo`, `project`, `profile_ref`,
|
||||||
|
`profile_sha256`, `descriptor_sha256`, `repository_grant_id`, `max_turns` come from
|
||||||
|
the admitted factory profile (HFACT-WP-0001-T01). They narrow this envelope; they
|
||||||
|
cannot widen the amounts above.
|
||||||
|
|
||||||
|
## Must not
|
||||||
|
- Deliver, read or display the Anthropic key
|
||||||
|
- Authorize the OpenBao apply, verify or exec actions (separate T03 approvals)
|
||||||
|
- Cover llm-connect or its DeepSeek default; that path is not this envelope
|
||||||
|
- Raise any amount or extend the expiry without a new memo
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
ROOT.mkdir(parents=True, exist_ok=True)
|
||||||
|
directory = ROOT / "budget"
|
||||||
|
directory.mkdir(exist_ok=True)
|
||||||
|
packet_path = directory / f"{MEMO_ID}.packet.md"
|
||||||
|
packet_path.write_text(PACKET, encoding="utf-8")
|
||||||
|
digest = _sha(PACKET)
|
||||||
|
memo = _memo(
|
||||||
|
memo_id=MEMO_ID,
|
||||||
|
question=QUESTION,
|
||||||
|
brief=BRIEF,
|
||||||
|
target=TARGET,
|
||||||
|
packet_id=MEMO_ID + "-packet",
|
||||||
|
packet_hash=digest,
|
||||||
|
highlight=HIGHLIGHT,
|
||||||
|
workplan=WORKPLAN,
|
||||||
|
task=TASK,
|
||||||
|
)
|
||||||
|
if memo_from(json.loads(dumps(memo))).question != QUESTION:
|
||||||
|
raise RuntimeError("round-trip failed")
|
||||||
|
memo_path = directory / f"{MEMO_ID}.memo.json"
|
||||||
|
memo_path.write_text(dumps(memo) + "\n", encoding="utf-8")
|
||||||
|
index = {
|
||||||
|
"kind": "informed-decision-batch",
|
||||||
|
"id": "infd-batch-2026-09-21-budget",
|
||||||
|
"review_group": REVIEW_GROUP,
|
||||||
|
"status": "draft-unsigned",
|
||||||
|
"submitted": False,
|
||||||
|
"one_question_per_memo": True,
|
||||||
|
"approve_all_forbidden": True,
|
||||||
|
"agent_disposition_forbidden": True,
|
||||||
|
"ordinal": [
|
||||||
|
{
|
||||||
|
"n": 1,
|
||||||
|
"memo_id": MEMO_ID,
|
||||||
|
"workplan": WORKPLAN,
|
||||||
|
"task": TASK,
|
||||||
|
"hub_task_prefix": HUB_TASK_PREFIX,
|
||||||
|
"question": QUESTION,
|
||||||
|
"memo": memo_path.name,
|
||||||
|
"packet": packet_path.name,
|
||||||
|
"packet_hash": digest,
|
||||||
|
"required_highlight": f"{MEMO_ID}-h1",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
(directory / "index.json").write_text(json.dumps(index, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
||||||
|
intents = {
|
||||||
|
"kind": "informed-decision-approval-create-intents",
|
||||||
|
"sitting_id": "infd-sitting-2026-09-21",
|
||||||
|
"status": "not-posted",
|
||||||
|
"posted": False,
|
||||||
|
"requester_client": "informed-decision-sitting-requester",
|
||||||
|
"human_control": True,
|
||||||
|
"pdp_path": False,
|
||||||
|
"required_count": 1,
|
||||||
|
"note": "Intents only. Digests are computed by approval-engine at create; do not invent them here.",
|
||||||
|
"intents": [{"memo_id": MEMO_ID, "create_client": "informed-decision-sitting-requester", "binding": BINDING}],
|
||||||
|
}
|
||||||
|
(ROOT / "approval-create-intents.json").write_text(json.dumps(intents, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
||||||
|
sitting = {
|
||||||
|
"kind": "informed-decision-sitting",
|
||||||
|
"id": "infd-sitting-2026-09-21",
|
||||||
|
"review_group": REVIEW_GROUP,
|
||||||
|
"status": "draft-unsigned",
|
||||||
|
"batches": [index["id"]],
|
||||||
|
"memo_count": 1,
|
||||||
|
"bind_path": "create approval (attended), Flex Auth exact-record admission, load store, human accept",
|
||||||
|
"note": "Unsigned draft. Live bind substitutes pending-human-session with the authenticated key-cape subject.",
|
||||||
|
}
|
||||||
|
(ROOT / "sitting.json").write_text(json.dumps(sitting, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
||||||
|
print(f"Wrote 1 unsigned memo under {ROOT}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue