#!/usr/bin/env python3 """Close a workplan task: flip the file, read the measured cost, tell the hub. CB-WP-0004 T02. Replaces three things that were done by hand on every task close, at a measured 46 turns and $11.52 per pass (CB-RES-0003 candidates 3 and 5): 1. a heredoc doing `s.replace("status: todo", "status: done")` on the workplan file — which silently did nothing on a typo'd task id or an already-closed task; 2. a hand-written `update_task_status` hub call; 3. **hand-typed `tokens_in` / `tokens_out`**, in a project whose central finding is that estimated token counts are worthless. Every hub token event this repo produced before T02 was an estimate. This tool reads the measured figure from the transcripts via cb-cost, or refuses. Ordering matters and is enforced, not assumed. Attribution is by commit subject (CA-08), so the work commit naming the task must exist *before* the close: otherwise the spend still sits in OPEN (uncommitted) and there is nothing measured to report. The usual sequence is git commit -m "CB-WP-0004 T02: ..." # subject names the task make task-done T=CB-WP-0004-T02 # measures, flips, pushes git commit -m "chore: mark T02 done (measured: ...)" Usage: python3 tools/task-done.py CB-WP-0004-T02 python3 tools/task-done.py CB-WP-0004-T02 --dry-run # measure, change nothing python3 tools/task-done.py CB-WP-0004-T02 --no-hub # file only python3 tools/task-done.py --self-test """ import glob import json import os import re import subprocess import sys import urllib.error import urllib.request from repo import ROOT, enter_root HUB = os.environ.get("CUSTODIAN_HUB", "http://127.0.0.1:8000") AGENT = "custodian" TASK_ID_RE = re.compile(r"^(?PCB-WP-\d+)-(?P