"""Draft the unsigned 2026-10-14 three-attempt spend memo (REINAH-WP-0008-T07). 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-10-14-three-attempts" MEMO_ID = "infd-20261014-b01" ENVELOPE_ID = "hfact-glas-tool-proof-20261014-three-attempts" WORKPLAN = "REINAH-WP-0008" TASK = "REINAH-WP-0008-T07" HUB_TASK_PREFIX = "80318842" EXPIRES_AT = "2026-10-31T23:59:59Z" QUESTION = ( "Authorize up to three disposable Glas tool/commit attempts, EUR 10 in total " "and EUR 5 per attempt, charged at metered usage, until 2026-10-31?" ) BRIEF = ( "Replaces the exhausted one-attempt envelope hfact-glas-tool-proof-20260927-renewed-" "one-attempt (run 6efa9436 failed before any provider request and was reconciled on " "2026-10-13). Attempts run on the corrected runtime only after its free rehearsal " "passes. Credential apply/verify/exec and human review remain separate exact actions. " "No publication or automatic retry. Daily EUR 20 and lifetime EUR 500 ceilings " "retain previous liabilities." ) HIGHLIGHT = ( "New accounting rule: a completed provider request is charged its metered cost " "(provider-reported tokens at the admitted rates), not its full USD 4.64 hold. This " "trusts provider-reported usage until you compare it with billing. Unfinished " "requests still count at full hold; any overrun freezes the envelope. Accepting this " "memo is the owner acceptance asked for in hub decision a93619a9. EUR/USD 1.00 is an " "accounting treatment; confirm fees and taxes fit before executing." ) TARGET = Scope( kind="spend-envelope", id=f"spend-envelope:{ENVELOPE_ID}", label="Up to three metered Glas proof attempts (railiance01)", environment="prod", ) BINDING = { "action": "accept", "actor": "informed-decision", "principal": "helixforge-factory", "purpose": "Accept a three-attempt spend envelope for metered Glas proof runs", "target": { "id": f"spend-envelope:{ENVELOPE_ID}", "type": "spend-envelope", "system": "rein-aharness", }, } PACKET = f"""# {TASK} — three-attempt spend envelope for the metered Glas proof Blocking workplan: {WORKPLAN} Blocking task: {TASK} (hub prefix {HUB_TASK_PREFIX}) Related: REINAH-WP-0003-T05/T06, REINAH-WP-0008-T02 (settlement rule), hub decision a93619a9, previous memo infd-20260927-b02 ## Question {QUESTION} ## One act Accept this envelope as the spend authority for rein-aharness MessagesOwner `metered-once` attempts 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}`. The owner writes it with `rein-aharness owner renew`. ## Why a new envelope The previous one-attempt envelope (memo infd-20260927-b02) is exhausted. Its run 6efa9436 failed with launcher exit 127 before any provider request. The owner reconciled it on 2026-10-13 at an estimated USD 0.05, and the full EUR 10 hold stays charged under that envelope's full-hold rule. The launcher defect is fixed in runtime ee3d0a53, and a free bwrap rehearsal now runs before any paid attempt. ## Enforced values (rein-aharness SpendPolicy, decimal strings) | Field | Value | Note | | --- | --- | --- | | `settlement` | observed-usage | New. See the accounting rule below | | `max_runs` | 3 | New. A fourth attempt is refused | | `per_run_eur` | 5 | Per attempt | | `daily_eur` | 10 | Timezone Europe/Berlin | | `total_eur` | 10 | Over the whole envelope | | `eur_per_usd` | 1 | Accounting treatment, as in infd-20260927-b02 | | `max_liability_usd` | 5 | Per attempt; reserves EUR 5 at admission | | `max_budget_usd` | 5.00 | Claude CLI stop; must equal the Glas profile limit | | `valid_from` | acceptance time | | | `expires_at` | {EXPIRES_AT} | | Worker, target repository, project, profile and grant pins carry over unchanged from the previous envelope. They narrow this envelope; they cannot widen it. ## Accounting rule (observed-usage) - Each provider request holds USD 4.64 while in flight (1M context at USD 4/M plus 64k output at USD 10/M). With a USD 5 attempt cap, one request is in flight at a time. - A request whose stream completes is charged its metered cost: provider-reported input, cache and output tokens at the admitted rates. - An attempt is charged the larger of its metered requests and the cost the CLI reports, at completion and at owner reconciliation. - A request whose stream never completes stays at its full hold. Cost above a hold marks the envelope breached and stops all attempts. ## Resulting capacity Each attempt reserves EUR 5 at admission, so a new attempt starts only while settled attempts total at most EUR 5. Expected attempts cost cents to about a euro, so three attempts fit. If the first two settle above EUR 5 together, the third cannot start. A failed attempt blocks the next one until it is observed or reconciled. ## Must not - Deliver, read or display the Anthropic key - Authorize the OpenBao apply, verify or exec actions (separate approvals) - Publish, schedule or automatically retry - Raise any amount, add attempts or extend the expiry without a new memo """ def main() -> None: directory = ROOT / "budget" directory.mkdir(parents=True, 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-10-14-three-attempts-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-10-14-three-attempts", "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-10-14-three-attempts", "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()