net-kingdom/tools/execution-attribution-receipt/README.md
tegwick d7133e3a04 NK-WP-0056-T15: receipt schema v0.1, validator and executor fixtures; audit sender exercise
- canon/schemas/execution-attribution-receipt_v0.1.schema.json: the bounded-executor profile
  of the PCC v0.2 receipt, both audit-core events (started, receipt), every object closed.
- tools/execution-attribution-receipt: EAR-1..EAR-10 validator, fixtures generated from the
  real executor (completed, reverted, completed-on-retry) with a drift check.
- executor: started carries receipt_version, digests, steps_planned and data.window.not_after
  (audit-core AUDIT-WP-0018-T03 request); receipt carries receipt_version and initiator.iss
  (configured approver_issuer, else unknown).
- bounded-executor/exercise_audit_sender.py: real executor and client against audit-core's
  real ingestion and the Git scope overlay: 202, duplicate 200, conflict 409 as a defect,
  wrong source/tenant/token refused and not stored, a receipt-less start flagged by its own
  window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 523928@bnt-lap001
Assistant-Session: 6c737afb-9c14-4152-9f02-477214b9c350
2026-11-04 01:39:57 +01:00

2.2 KiB

Execution Attribution Receipt validator (NK-WP-0056-T15)

Schema canon/schemas/execution-attribution-receipt_v0.1.schema.json covers the bounded-executor profile of the Playbook Capability Contract v0.2 receipt: the two events one executor run emits to audit-core, in audit-core's ingest envelope.

  • execution.run.started is sent after consume, before the first step. It carries data.window.not_after, so audit-core holds the run to its own admission window (AUDIT-WP-0018-T03).
  • execution.attribution.receipt is one per run, with every step, check result, revert and the budget used.
python3 tools/execution-attribution-receipt/validate.py validate EVENT.json...        # EAR-1..EAR-9 per event
python3 tools/execution-attribution-receipt/validate.py pair STARTED.json RECEIPT.json # plus EAR-10 across the pair
python3 tools/execution-attribution-receipt/generate_fixtures.py [--check]            # fixtures from the real executor
make execution-attribution-receipt-test

The rules are listed in validate.py. Findings name a rule and a location, never a value. The schema closes every object (additionalProperties: false), so no field can carry a value an operation handled. Steps record identifiers, outcomes, check results and an error type only.

fixtures/valid/ holds three scenarios: completed, reverted and completed-on-retry. They are generated by running executor.Run on in-memory fakes, and a test fails when they drift from what the executor emits. audit-core can use them for AUDIT-WP-0014-T02 (canonical receipt validation).

Profile decisions (audit-core's open points in docs/bounded-executor-receipts.md):

  • target is admission:<id> and action is bounded-execution at receipt level. Per-step targets stay in steps[].
  • decision_refs are exactly admission, admission_digest and approval, as {label, ref}.
  • initiator.iss is the approvers' issuer when configured, else the explicit unknown.
  • delegation is absent: the pilot has no delegated initiator.
  • tenant is the audit-core tenant (platform) and must equal the envelope tenant.
  • pdp is not-evaluated in the pilot.

Not covered: the railiance-infra S1 runner profile (NK-WP-0040-T02), which waits on its own emitter decision.