IR-WP-0006-T01/T02: billing reconciliation contract and settlement mechanism
Spec and implement external-evidence settlement for pending trial reservations, so the USD 0.023712 HTTP-401 reservation (and future ones) can be resolved without fabricating a completed trial or treating a failed request as zero-charge proof. intelligence_radar.trials.reconcile (+ CLI reconcile) is write-once under the existing trials lock, rejects unknown reservations, duplicate/conflicting settlement, cross-campaign references, invalid amounts and budget overrun, and records reviewer attribution plus an evidence pointer rather than any secret value. 9 new tests; full suite (48 tests) and repository check pass. T03 (applying this to the real reservation) stays blocked on authoritative provider billing evidence. ADR-0003 closes the IR-WP-0007-T03 uptime question: retain the local systemd timer, no hosted worker, since nothing here needs sub-day freshness and the scheduler already tolerates downtime. Mark IR-WP-0005/0006/0007 workplan status blocked: each still has at least one task genuinely blocked on an external party (secrets-engine human approval, authoritative billing evidence, and paid-execution outcomes respectively) rather than anything actionable in this repo. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: sonnet Assistant-Process: 8472@bnt-lap001 Assistant-Session: 1cac6b6d-c1a5-4a04-a950-c4febb8d3f67
This commit is contained in:
parent
7d03727945
commit
710b2ebbb5
8 changed files with 312 additions and 6 deletions
|
|
@ -185,6 +185,12 @@ def main(argv=None):
|
|||
trials_command.add_argument('--suite', type=Path, required=True)
|
||||
trials_command.add_argument('--pilot', action='store_true')
|
||||
trials_command.add_argument('--plan', action='store_true', help='review request identities and budget without calls or writes')
|
||||
reconcile_command = commands.add_parser('reconcile', help='settle a pending trial reservation from reviewed external billing evidence')
|
||||
reconcile_command.add_argument('--campaign', required=True)
|
||||
reconcile_command.add_argument('--run-id', required=True)
|
||||
reconcile_command.add_argument('--actual-usd', required=True)
|
||||
reconcile_command.add_argument('--evidence-ref', required=True, help='pointer (hash or path) to retained evidence, not a credential')
|
||||
reconcile_command.add_argument('--reviewer', required=True)
|
||||
args = parser.parse_args(argv)
|
||||
try:
|
||||
if args.command == 'trials':
|
||||
|
|
@ -192,6 +198,10 @@ def main(argv=None):
|
|||
action = plan if args.plan else run
|
||||
print(json.dumps(action(args.root, json.loads(args.config.read_text()),
|
||||
json.loads(args.suite.read_text()), args.pilot), indent=2))
|
||||
elif args.command == 'reconcile':
|
||||
from .trials import reconcile
|
||||
print(reconcile(args.root, args.campaign, args.run_id, args.actual_usd,
|
||||
args.evidence_ref, args.reviewer))
|
||||
elif args.command == 'export':
|
||||
from .bundles import export_bundle
|
||||
print(json.dumps(export_bundle(args.root, args.id, args.output), indent=2))
|
||||
|
|
|
|||
|
|
@ -168,6 +168,52 @@ def execute(root, config, case, model, opener=urlopen):
|
|||
return trial
|
||||
|
||||
|
||||
def reconcile(root, campaign, run_id, actual_usd, evidence_ref, reviewer):
|
||||
"""Settle a pending reservation from reviewed external billing evidence.
|
||||
|
||||
Never fabricates a completed trial: only a settlement event is written.
|
||||
evidence_ref is a pointer (hash or path) to retained evidence, not a
|
||||
credential or raw authenticated provider response.
|
||||
"""
|
||||
root = Path(root)
|
||||
if not isinstance(evidence_ref, str) or not evidence_ref.strip():
|
||||
raise ValueError('evidence_ref is required')
|
||||
if not isinstance(reviewer, str) or not reviewer.strip():
|
||||
raise ValueError('reviewer is required')
|
||||
actual = money(actual_usd)
|
||||
lockpath = root / '.runtime/trials.lock'
|
||||
lockpath.parent.mkdir(parents=True, exist_ok=True)
|
||||
with lockpath.open('a') as lock:
|
||||
fcntl.flock(lock, fcntl.LOCK_EX)
|
||||
events = all_records(root, 'trial-events')
|
||||
reservations = {i: e for i, e in events if e['kind'] == 'reserved'}
|
||||
settled = {e['reservation_id']: e for _, e in events if e['kind'] == 'settled'}
|
||||
match = next(((i, e) for i, e in reservations.items() if e.get('run_id') == run_id), None)
|
||||
if match is None:
|
||||
raise ValueError('unknown reservation: no matching run_id in trial-events')
|
||||
reservation_id, reservation = match
|
||||
if reservation['campaign'] != campaign:
|
||||
raise ValueError('cross-campaign reference: reservation belongs to a different campaign')
|
||||
if reservation_id in settled:
|
||||
raise ValueError('reservation already settled; duplicate or conflicting settlement refused')
|
||||
other_settled = sum((money(e['actual_usd']) for rid, e in settled.items()
|
||||
if reservations[rid]['campaign'] == campaign), Decimal(0))
|
||||
other_pending = sum((money(e['reserved_usd']) for i, e in reservations.items()
|
||||
if e['campaign'] == campaign and i != reservation_id and i not in settled),
|
||||
Decimal(0))
|
||||
limit = money(reservation['budget_usd'])
|
||||
if other_settled + other_pending + actual > limit:
|
||||
raise ValueError('settlement exceeds campaign budget authorization')
|
||||
stamp = datetime.now(timezone.utc).isoformat()
|
||||
event = {'kind': 'settled', 'campaign': campaign, 'run_id': run_id,
|
||||
'reservation_id': reservation_id, 'actual_usd': str(actual),
|
||||
'reserved_usd': reservation['reserved_usd'],
|
||||
'discrepancy_usd': str(actual - money(reservation['reserved_usd'])),
|
||||
'settlement_method': 'external_evidence', 'evidence_ref': evidence_ref,
|
||||
'reviewer': reviewer, 'settled_at': stamp}
|
||||
return put(root, 'trial-events', event)
|
||||
|
||||
|
||||
def run(root, config, suite, pilot=False):
|
||||
rows=[]
|
||||
selected=suite['cases'][:2] if pilot else suite['cases']
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue