Skip to content

feat(play): carry Google's structured error identifiers into failure receipts - #836

Merged
stamp-build[bot] merged 1 commit into
mainfrom
agent/codex-android-devops/play-error-identifiers
Oct 29, 2026
Merged

stamp-build[bot] merged 1 commit into
mainfrom
agent/codex-android-devops/play-error-identifiers

Conversation

@stamp-build

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

Copy link
Copy Markdown
Contributor

林舟 (Codex-Android-DevOPS) from slock-android opened this pull request through Stamp
View in Stamp →


Why

The resumable retry of the 1.17.0 mapping backfill failed (receipt 2d5a7891, play_upload_interrupted, http 400). The receipt only says provider_cause: VERSION_CODE_CONFLICT. That category matches any Google message that mentions a version code (provider_errors.ts, /version ?code/i), and Google's own identifiers were dropped. Nobody has adapter log access, so the real reason cannot be read. Volta chose option 2 in #joint-hands: carry Google's structured identifiers, keep prose out.

What

  • Adapter: playRejection attaches cause_detail.provider_identifiers, keeping the source field so a reader can see where Google named the condition:

    • status (error.status);
    • http_code (error.code, integer);
    • errors_reasons (errors[].reason);
    • details[] (@type/reason/domain).

    Every value is shape-checked: reasons/status must be camelCase or UPPER_SNAKE (no dots, hyphens or slashes, so token-shaped values such as ya29.…, 1//… or hidden-secret can never pass), domain must be *.googleapis.com, and @type must be type.googleapis.com/…. Lists are capped at 8. Google's prose is still only message_sha256 + message_length.

  • Worker: receiptCause re-validates provider_identifiers with the same rules before persisting; unknown keys are dropped. Upload-protocol failures (play_upload_*) carry it too, since they reuse playRejection's cause.

  • Contract change, deliberate: provider_errors.test.ts used to assert that the caller result does not contain validation reasons. It now asserts that identifiers are present and prose is not. The comment explains why.

Tests

  • play-adapter: 168/168. The new tests check that identifiers are kept per field and that prose, credential-shaped reasons, a foreign @type and metadata are all dropped. There is also a case for a body without identifiers.
  • worker google_play_distribution.test.ts: 119/119. A new case checks the receipt persists the identifiers and drops off-shape values and unknown keys.
  • tsc --noEmit is clean for adapter and worker.

After merge

Deploy adapter → worker. Then rerun the 11700009 upload-symbols commit once, for the sole purpose of reading the identifiers.

🤖 Generated with Claude Code

…receipts

A failed mapping upload on 2026-10-29 (receipt 2d5a7891) reported only
provider_cause VERSION_CODE_CONFLICT: the classifier matches any message that
mentions a version code, and Google's own identifiers were dropped, so the
real reason could not be read without log access (which nobody has).

The adapter now attaches provider_identifiers (error.status, error.code,
errors[].reason, details[].@type/reason/domain), each shape-checked as an
identifier (camelCase or UPPER_SNAKE; googleapis domain; google.rpc @type);
Google's prose is still only sha256 + length. The worker re-validates them
in receiptCause before persisting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@stamp-build
stamp-build Bot merged commit d1779aa 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