返回 CodeWhale
RECEIPTS.md
根目录 / docs / RECEIPTS.md
1 # Runtime Receipts
2
3 This document sketches a future read-only receipt export for completed runtime
4 turns. It is a protocol note, not an implemented endpoint.
5
6 The goal is to let a local supervisor audit one completed turn without
7 screen-scraping the terminal transcript. A receipt should summarize the durable
8 runtime records that Codewhale already owns: thread metadata, turn status, turn
9 items, event sequence lineage, usage when available, approval decisions, and
10 side-effect boundaries.
11
12 ## Non-Goals
13
14 A receipt is not a safety certification, provider compatibility certification,
15 or hosted attestation. It must not call providers, execute tools, write memory,
16 write project files, mutate runtime state, or expose API keys.
17
18 Receipts should not export raw chain-of-thought or private reasoning by default.
19 When reasoning custody is represented, use stable item ids, counts, hashes, or
20 explicit `unavailable` fields rather than raw hidden content.
21
22 ## Candidate Surfaces
23
24 Potential local-only surfaces:
25
26 ```text
27 codewhale receipt export --thread <thread_id> --turn <turn_id> --format json
28 GET /v1/threads/{thread_id}/turns/{turn_id}/receipt
29 ```
30
31 Both surfaces should share the existing runtime API auth boundary. They should
32 only read persisted runtime records and append-only events.
33
34 ## Review Receipts
35
36 `codewhale review --write-receipt` writes a local JSON receipt for the reviewed
37 diff under the Codewhale state directory (`review-receipts/`) unless
38 `--receipt-path <path>` is provided. This is a pre-push handoff artifact: it
39 records what diff was reviewed and what the review reported, without pushing,
40 tagging, opening a PR, or claiming to replace maintainer review.
41
42 The current receipt includes:
43
44 - `diff_fingerprint`: SHA-256 of the reviewed diff.
45 - `provider` and `model`: the routed review provider/model.
46 - `checks_run`: local checks attached to the receipt when available. Empty
47 means no checks were attached; attached checks must report a passing status.
48 - `findings`: structured issue/suggestion counts and issue locations when the
49 review output is structured.
50 - `unresolved_risk`: a conservative summary derived from unresolved findings.
51 - `review_content_sha256`: SHA-256 of the review text.
52 - `coverage` (PR receipts): the exact base/head and complete-diff
53 fingerprint, ordered per-pass diff fingerprints/file counts, and one
54 response-content hash for every completed pass. Manifest-backed PR receipts
55 use schema version 2 so older readers reject rather than misinterpret them.
56
57 The receipt deliberately does not include the raw diff body. Re-run
58 `codewhale review --write-receipt` after changing the diff; reviewers should
59 compare the `diff_fingerprint` before reusing a receipt in a PR handoff.
60
61 `codewhale review --check-receipt` is the local pre-push gate. It does not call
62 a model; it compares the current diff fingerprint with a supplied receipt
63 (`--receipt-path <path>`) or the latest matching local receipt. The check exits
64 nonzero when the diff no longer matches, the receipt schema is unsupported, the
65 receipt has unresolved risk, or an attached check did not pass.
66
67 By default receipt generation rejects a PR that needs more than one
68 `--max-chars` pass before calling a model. An explicit `--max-passes N` admits
69 at most N complete ordered PR passes; any missing, malformed, reordered or
70 stale pass prevents a receipt. Receipt checking is provider-free and validates
71 the exact stored manifest without authorizing another run. Neither mode
72 fingerprints a truncated prefix. A receipt for
73 `review --base <base-sha> --path <path>` covers only that selected path at the
74 checked-out revision; validate it with the same base, path, and input limit.
75 It does not cover the rest of a pull request or prove that separately reviewed
76 changes work together.
77
78 ## Current Data Sources
79
80 The current runtime store already persists the core inputs a receipt builder
81 would need:
82
83 - `ThreadRecord`: model, workspace, mode, shell/trust/auto-approve flags,
84 title, task linkage, and latest turn metadata.
85 - `TurnRecord`: turn status, input summary, timestamps, duration, usage, error,
86 steer count, and item ids.
87 - `TurnItemRecord`: item kind, lifecycle status, summary, optional detail,
88 metadata, artifact refs, and item timestamps.
89 - `RuntimeEventRecord`: thread id, turn id, item id, event name, JSON payload,
90 timestamp, and monotonic `seq` values per runtime store.
91
92 Not every receipt field can be filled from those records today. If a provider or
93 store does not persist a value, the receipt should say `available: false` or
94 `unavailable`, not infer it from UI text.
95
96 ## Draft Schema Shape
97
98 ```json
99 {
100 "schema_id": "codewhale.conformance-receipt/v0",
101 "thread": {
102 "id": "thr_...",
103 "model": "deepseek-v4-pro",
104 "mode": "agent",
105 "auto_approve": false,
106 "trust_mode": false,
107 "allow_shell": false
108 },
109 "turn": {
110 "id": "turn_...",
111 "status": "completed",
112 "started_at": "2026-06-02T01:00:00Z",
113 "ended_at": "2026-06-02T01:00:12Z",
114 "duration_ms": 12000
115 },
116 "reasoning_custody": {
117 "raw_reasoning_exported": false,
118 "available": false,
119 "reason": "reasoning blocks are not persisted as receipt-ready records"
120 },
121 "tool_lineage": {
122 "tool_call_count": 1,
123 "tool_result_count": 1,
124 "unmatched_tool_call_ids": [],
125 "unmatched_tool_result_ids": []
126 },
127 "usage_evidence": {
128 "available": true,
129 "usage": {
130 "prompt_tokens": 123,
131 "completion_tokens": 45
132 },
133 "provider_cache_breakdown_available": false
134 },
135 "source_event_lineage": {
136 "first_seq": 10,
137 "last_seq": 42,
138 "event_count": 33,
139 "missing_event_ranges": []
140 },
141 "side_effect_boundary": {
142 "approval_required_count": 1,
143 "approval_allowed_count": 0,
144 "approval_denied_count": 1,
145 "command_execution_count": 0,
146 "file_change_count": 0,
147 "sandbox_denied_count": 0
148 },
149 "claim_ceiling": [
150 "local_receipt_only",
151 "not_safety_certification",
152 "not_provider_compatibility_certification"
153 ]
154 }
155 ```
156
157 ## Builder Rules
158
159 A receipt builder should be deterministic and conservative:
160
161 1. Load the thread and turn by id, then reject mismatched `thread_id` values.
162 2. Load only item ids referenced by the turn.
163 3. Read event records for the thread and filter by `turn_id`.
164 4. Preserve event sequence boundaries with `first_seq`, `last_seq`, and any
165 detected gaps.
166 5. Count approval, command, file, sandbox, and tool events from typed records or
167 known event names only.
168 6. Mark unavailable evidence explicitly instead of deriving it from free-form
169 summaries.
170 7. Emit no raw tool output beyond existing item summaries unless a later schema
171 adds a separate redaction policy.
172
173 ## Incremental Implementation Path
174
175 The safest implementation path is:
176
177 1. Land this protocol note and settle field names/non-goals.
178 2. Add protocol structs and JSON snapshot fixtures for completed, failed, and
179 approval-denied turns.
180 3. Add a pure builder over `ThreadRecord`, `TurnRecord`, `TurnItemRecord`, and
181 `RuntimeEventRecord`.
182 4. Expose the local runtime API endpoint.
183 5. Add the CLI export command and optional validation mode.
184
184 lines MARKDOWN