Skip to content

feat: read-only /@user/receipts projection of stored OperationResults - #184

Merged
LIghtJUNction merged 1 commit into
integrate/all-open-20260929from
feat/subject-receipts-20260929
Sep 29, 2026
Merged

LIghtJUNction merged 1 commit into
integrate/all-open-20260929from
feat/subject-receipts-20260929

Conversation

@LIghtJUNction

Copy link
Copy Markdown
Member

Summary

  • Closes the gap noted at the end of docs/DESIGN_CONTRACT_INVENTORY.md: design 154 requires a /@user/receipts/ read-only view. The signed OperationResult rows the executor already persists in results (keyed by subject, request_id) are the real receipt facts, so this only projects them. There is no new table, no receipt state machine and no writable receipt resource. Stored result bytes and signatures are never rewritten.
  • New read operations communication.receipt_list (limit 1..200, cursor) and communication.receipt_get (request_id), both effect='read', registered alongside the other communication ops (new plugin module src/msg/plugins/receipts.py). Existing short codes are untouched; the new ops get codes the same way other ops missing from the packaged snapshot do.
  • HTTP: GET/HEAD /@handle/receipts[/json] and /@handle/receipts/<request_id>[/json]. Pagination uses the inbox convention (limit/cursor). Any other query parameter is rejected, and so is any query on the detail path.

Access and projection

  • Only the path subject can read. A different authenticated subject gets permission_denied (403), even when asking about its own request ID or an unknown one, so existence is never revealed. Anonymous callers get authentication_required (401). An unknown ID for the owner returns not_found.
  • Each item contains request_id, operation, status, committed_at, resources (only references the caller can read now), signed (a boolean) and error_code when there is one. data, output, cli_url, actor/subject and the raw signature are omitted, because data can carry delivered credentials, and the signature can't be verified without the full result bytes anyway.
  • Items are ordered by request_id. The cursor is HMAC-bound to the subject, so reusing one under another subject fails with cursor_query_mismatch.
  • Reads write nothing: no change to results, no events, audit entries, jobs or messages, and no generation changes.

Not included: communication.receipt_* is not added to TEMPORARY_OPERATIONS, so temporary identities cannot use the view yet. DESIGN_CONTRACT_INVENTORY.md is left as the audit snapshot it is.

Test plan

  • New tests/test_subject_receipts.py (2 tests): owner list and detail (including /json, HEAD, ETag 304), exact projection keys, other subject denied (their own, the owner's and unknown IDs), anonymous denied, unknown ID not_found, bad query or limit rejected, POST rejected, limit=1 paging that visits each row exactly once in order, a cursor reused by another subject rejected, and table row counts plus a digest of results unchanged after all reads. Also checks that resources whose access was revoked drop out of the projection while the stored result bytes stay identical.
  • Related suites (dictionary, capabilities, registry, route effect matrix, passive GET guard, subject aliases, collaboration and watch surfaces, issue_78_80, …): 483 passed. The only 2 failures, test_read_entry_contract_matrix[discovery.read_query-*], also fail on the base commit without this change.
  • Full suite, run as 8 file shards: all tests in the files that pass cleanly pass. Every file that errored in a shard was rerun on its own and passed (166 passed), except test_hosting_runtime_isolation (it needs sudo/cross-UID socket access on this machine) and test_legacy_ledger_snapshot (it needs MSG_TEST_LEGACY_SOURCE). Both are environment requirements unrelated to this change.

Made with Cursor

…ults

Design 154 requires a /@user/receipts/ view. The signed OperationResult rows
the executor already persists in `results` (subject, request_id) are the real
receipt facts, so this adds communication.receipt_list / receipt_get as pure
reads over them instead of a new receipt table, state machine or writable
resource. Stored result bytes and signatures are never rewritten.

Only the path subject can read: other subjects get permission_denied (even
for their own or unknown request IDs), anonymous callers get
authentication_required. The projection is request_id, operation, status,
committed_at, currently readable resources, a signed flag and error_code;
data/output/cli_url are omitted because they can carry delivered
credentials. Listing uses the inbox-style limit (1..200) and an HMAC cursor
bound to the subject, ordered by request_id. Reads write nothing.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI balanced review requested due to automatic review settings September 29, 2026 14:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review ✅ Completed 2026-09-29T15:08:40.206176Z 4d3f3c0 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@LIghtJUNction
LIghtJUNction merged commit 8b4c807 into integrate/all-open-20260929 Sep 29, 2026
11 of 15 checks passed
LIghtJUNction added a commit that referenced this pull request Sep 29, 2026
Preserves the current integration branch plus main 22b5e86 and #182 bf1a166. The tree is the previously reviewed pre-quality integration tree; only pyproject.toml required explicit conflict resolution. #183 and #184 are already present through the first parent.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants