V3 Issue #236 — Execution Receipts and Task Association
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox syntax for tracking.
Goal: Make each tool receipt identify the exact call and authorized operation, associate tasks only by explicit identity in native execution, and record evidence from typed outcomes.
Architecture: Extend the existing ExecutionReceipt and shared AgentRuntime.execute_call() boundary. Keep TaskManager as the owner of Working Plan lifecycle and evidence, ToolRegistry as the owner of tool metadata, and EventStore as the durable receipt log. Preserve compatibility fields as bounded projections of the immutable tool result.
Tech Stack: Python 3.12–3.13, dataclasses, existing JSON-safe ToolResult, SQLite-backed event/task stores, unittest.
Spec: OpenKyrozen V3 GitHub issue #236, covering R026–R030 and R066.
Global Constraints
- No new dependency or paid provider call.
- A missing
task_idis permitted and cannot infer or advance a plan task. - A supplied
task_idmust identify a pending/running task in the active Working Plan and current user/workspace/session. - Execution success comes from
ToolResult; rendered wording never determines status. - A receipt or verified effect alone does not satisfy acceptance requirements or complete a task.
- Existing persisted receipts remain readable; audit/event projections remain bounded and redacted.
- Side-effect classification must not grant permissions or make a previously unsafe tool parallel-safe.
Review Focus
- Native call IDs must survive validation errors, denials, cancellations, and exceptions without executing a rejected call.
- Mutating caller-owned arguments or result snapshots after execution must not alter the receipt or its fingerprint.
- Invalid or stale task identity after an approval wait must prevent execution and leave task state unchanged.
- A pre-existing file or command output that looks successful must not count as verified effect without matching observed state/status.
- Historical receipts and custom/legacy ToolSpec side-effect metadata must remain readable and conservative.
Caller and Data Map
openkyrozen/agent/types.py: receipt contract, compatibility serialization, and defensive result snapshots.openkyrozen/agent/executor.py: operation identity, result-to-receipt construction, bounded redaction, persistence/event projections, and legacy adapter.openkyrozen/agent/runtime.py: nativeexecute_call()call/task identity, schema and approval failures, and task eligibility rechecks.openkyrozen/app/bootstrap.py: scope the default TaskManager to the initial session and workspace instead of its unscoped compatibility defaults.openkyrozen/tasks/engine.pyandopenkyrozen/tasks/runtime.py: explicit evidence association and active Working Plan checks; legacy inference remains available only to the legacy execution adapter.openkyrozen/agent/subagent_runtime.py,openkyrozen/learning/evolution.py,openkyrozen/tools/catalog.py, andopenkyrozen/tools/manifest.py: typed verification/acceptance inputs and refined metadata.tests/test_tool_results.py,tests/test_working_plans.py,tests/test_approval_request.py,tests/test_task_consistency.py, and new focused receipt tests: regressions for receipt identity, task scope, verification, projections, and compatibility.docs/security.md,docs/tasks-and-automation.md, anddocs/architecture.md: document the receipt and task-association boundary where current guidance discusses it.
Task 1: Receipt contract and stable operation identity
Files:
- Modify: openkyrozen/agent/types.py
- Modify: openkyrozen/agent/executor.py
- Test: tests/test_execution_receipts.py (create) and tests/test_tool_results.py
Interfaces:
- Consumes: ToolCall, ToolResult, and ToolError from the existing provider/tools contracts.
- Produces: immutable receipt fields for call_id, call_id_source (native, legacy, or synthetic), typed arguments, tool_result, user_id, workspace_id, session_id, plan_id, task_id, tool_version, tool_source, side_effects, and structured verification; as_dict() remains a bounded compatibility projection.
- [x] Write regressions that prove native call ID and typed arguments survive receipt creation, snapshots are defensive, projections redact/bound secrets, and operation IDs are stable across call IDs but distinct across sessions.
- [x] Run the focused receipt tests and confirm failures identify missing receipt fields/projection behavior.
- [x] Extend
ExecutionReceiptwith immutable JSON snapshots and compatibility properties; derivesuccessfromToolResultwhile retaining old constructor/payload compatibility. - [x] Extend receipt creation with call/scope/spec/verification identity and hash the full canonical arguments before any bounded projection.
- [x] Run focused receipt and tool-result tests.
- [x] Commit as
feat: complete execution receipt identity.
Task 2: Preserve call identity and enforce explicit task binding
Files:
- Modify: openkyrozen/agent/runtime.py
- Modify: openkyrozen/app/bootstrap.py
- Modify: openkyrozen/agent/executor.py
- Modify: task evidence owner under openkyrozen/tasks/
- Test: tests/test_execution_receipts.py, tests/test_working_plans.py, tests/test_approval_request.py
Interfaces:
- Consumes: Task 1 receipt fields.
- Produces: AgentRuntime.execute_call(..., *, task_id: str | None = None); explicit task identity flows to TaskManager.record_evidence(task_id=...); native calls with no task ID are unassociated. Legacy execute() supplies a marked synthetic call ID and retains heuristic task association through its compatibility adapter.
- [x] Write regressions for missing task IDs, valid explicit association, wrong plan/session/workspace/user, terminal tasks, task changes during approval, and call ID preservation on validation/denial/exception paths.
- [x] Run the focused tests and confirm native heuristic association is exposed by expected failures.
- [x] Add keyword-only task binding and revalidate active plan/task eligibility before invoking the executor after approval.
- [x] Thread call/task IDs through every receipt construction branch; isolate old inference to legacy
execute()/action execution. - [x] Run focused receipt, Working Plan, approval, and task consistency tests.
- [x] Commit as
fix: bind receipts to explicit tool calls and tasks(combined with Task 3 because both change the same receipt construction/evidence boundary).
Task 3: Typed verification, acceptance, and effect classes
Files:
- Modify: openkyrozen/agent/executor.py
- Modify: openkyrozen/agent/subagent_runtime.py
- Modify: openkyrozen/learning/evolution.py
- Modify: openkyrozen/tools/catalog.py and openkyrozen/tools/manifest.py
- Test: tests/test_execution_receipts.py, tests/test_tool_results.py, and affected task/registry tests
Interfaces:
- Consumes: typed receipt and task binding from Tasks 1–2; existing explicit ToolResult and CommandResult status.
- Produces: verification states verified, failed, unavailable, or not_applicable, including method/observed evidence; refined side-effect classes read_only, filesystem, process, remote, destructive, and internal (legacy registrations map conservatively).
- [x] Add failing tests for write verification against actual contents, mismatched pre-existing files, command status independent of text, no acceptance from success alone, and conservative legacy metadata.
- [x] Run the focused tests and verify they fail on current existence/text based checks.
- [x] Implement typed evidence based on the actual requested operation and observed state; keep unsupported verification explicit as unavailable.
- [x] Replace text-based command acceptance/failure classification with structured command status; preserve user-facing rendering.
- [x] Refine built-in side-effect classes without increasing capability or parallel-safety and preserve serialized historical specs.
- [x] Run focused receipts, tasks, subagent, learning, and registry tests.
- [x] Commit as
fix: verify tool effects from structured outcomes(combined with Task 2 because both change the same receipt construction/evidence boundary).
Task 4: Compatibility, documentation, and issue validation
Files:
- Modify: openkyrozen/agent/__init__.py and openkyrozen/__init__.py as needed for public exports.
- Modify: docs/security.md, docs/tasks-and-automation.md, docs/architecture.md, and receipt fixtures/callers as needed.
- Test: focused suites plus full repository targets.
Interfaces: - Consumes: completed receipt/evidence contract from Tasks 1–3. - Produces: documented, exported receipt API and compatible historical JSON event payloads, with native/MCP/subagent consumers using call identity and explicit task association.
- [x] Add compatibility regressions for historical receipt JSON, native/MCP IDs, legacy synthetic IDs, event redaction, and no inferred task assignment for native calls.
- [x] Run focused tests and resolve failures without weakening task, authorization, or secret boundaries.
- [x] Update caller projections and documentation, preserving old text/UI keys as render-only bounded fields.
- [x] Run focused tests on Python 3.12 and 3.13, then full tests,
make check,make lint,make docs-check, Go TUI tests,make agent-acceptance,make subagent-acceptance, andmake tui-acceptance; install the existing Playwright/Chromium support first. Final validation: full browser-enabled suites passed on both versions (779 tests each), focused receipts passed, generated tool inventory was refreshed, and all listed checks/acceptance targets passed. - [x] Resolve independent-review findings: gate explicit task completion on its declared command criterion; redact receipt result text and receipt-derived task/event projections while retaining raw in-memory snapshots and matching fingerprints; make command test fixtures use an existing temporary workspace so CI does not depend on the runner's home directory; require an exact single-criterion command match; redact JSON scalar result text and JSON-encoded object data in receipt projections.
- [x] Record PASS/FAIL/BLOCKED and skip reasons; independently review the complete diff and resolve material findings before publishing. Reviews found and fixed acceptance overmatching, raw/scalar JSON projections, projection over-budget output, workspace identity mismatch, browser snapshot classification, truncated failure rehydration, missing pre-dispatch ToolSpec provenance, mismatched rejected-subagent receipt IDs, and failure rehydration when both nested and compatibility error projections are truncated. The final review found a subagent test that missed one rejection branch; its fixture now exercises malformed supported arguments, and both rejection paths verify persisted receipt IDs and event scope. A final CI run exposed three receipt tests that assumed pytest was installed in the core environment; they now use Python's standard-library
unittest --helpcommand. All three regressions pass locally, and the final GitHub CI result passed. Full-python-312, tui-test, and deploy were skipped by workflow path conditions; equivalent full Python 3.12/3.13 suites, Go TUI tests, and local TUI acceptance passed. CodeRabbit's review was skipped because this OSS repository requires manual review; independent review confirmed the final fixture change. - [x] GPG-sign and locally verify commits, push
Evan/v3-236-execution-receipts, open and attach one PR, verify GitHub signatures and final-head CI, and leave the PR and issue open. PR #281 remains open and unmerged.