Skip to content

feat(play): carry cause_source so a receipt can vouch for its classification - #837

Merged
stamp-build[bot] merged 2 commits into
mainfrom
agent/receipt-cause-source
Oct 29, 2026
Merged

stamp-build[bot] merged 2 commits into
mainfrom
agent/receipt-cause-source

Conversation

@stamp-build

@stamp-build stamp-build Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

Volta from botiverse opened this pull request through Stamp
View in Stamp →


Problem

A receipt records provider_cause but not whether that cause was read from a Google identifier or inferred from the message text. Today's upload_mapping failure shows why the difference matters: FAILED_PRECONDITION is not in the structured vocabulary, so VERSION_CODE_CONFLICT was inferred from prose — and the receipt presents that inference exactly like a fact Google stated.

The adapter already emits cause_source: "structured" | "message" (provider_errors.ts:75). The worker's receiptCause picked only stage and provider_cause, so it was dropped.

Changes

cause_source is carried on both paths that build a cause — the promote rejection and the mapping-file rejection — bounded to those two values rather than passed through as free text.

AdapterDeobfuscationFile now declares the field. That was not optional: without it tsc rejects the access while vitest stays green.

Testing

  • Worker suite 1210 passed.
  • The mapping-path test asserts cause_source survives; removing the field from the builder fails it.
  • tsc reports no cause_source diagnostics (the Env binding noise in that file comes from a locally generated type file and is pre-existing).

Follow-up

This does not change any classification. It makes existing receipts honest about which of two very different things they contain, so a future reader does not treat an inferred cause as a provider-confirmed one.

Volta added 2 commits October 29, 2026 14:55
…ication

A receipt records provider_cause but not whether that cause came from a Google identifier
or was inferred from the message text. Today's upload_mapping failure shows why that
matters: FAILED_PRECONDITION is not in the structured vocabulary, so VERSION_CODE_CONFLICT
came from prose, and the receipt presents that guess exactly like a stated fact.

The adapter already emits cause_source (structured | message); the worker dropped it. It
is now carried on both paths that build a cause -- the promote rejection and the
mapping-file rejection -- and bounded to those two values rather than passed through as
free text.

The type addition was not optional: without declaring the field on
AdapterDeobfuscationFile, tsc rejects the access, which vitest does not check. That is the
gate that caught it, and the reason a deploy dispatch follows worker changes.

Tests assert the field survives on the mapping path and that removing it fails.

worker suite 1210 passed.
Codex's review is right: I pinned cause_source only on the deobfuscation-file
rejection. The path that produced the real receipt -- play_upload_interrupted through
receiptCause -- had no cause_source in its fixture, so deleting the new code would have
left every test green. That is the vacuous-assertion shape again, in my own work.

The receiptCause fixture now carries cause_source: "message" plus an out-of-vocabulary
value that must be dropped, and the toEqual pins the field. Removing the new code fails
that test.

Also widens the trailing type assertion on receiptCause's return, which narrowed away the
field the declared return type already named -- a cast that silently hides a value.

worker suite 1210 passed.
@stamp-build
stamp-build Bot merged commit 83e5237 into main Oct 29, 2026
11 checks passed
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.

0 participants