feat(products): live store readiness after apply + price equalization - #126
Conversation
DX-974 products store: post-apply readiness verification + subscription price equalization
From Product Catalog team feedback. The CLI already uses the Plans API (plan→apply with polling) — the gaps are verifying the live result and modeling equalization. #4 Post-apply readiness (the headline gap)Today
Overall verdict = worst product; never print generic success when any product isn't READY. Same summary in Agreements/tax/banking (account-level, one-time for new devs) are explicitly out of scope — not derivable from per-product state. #3 Equalization + availability-vs-pricing
Also
TestsPlan-not-direct, blocker prevents apply, apply waits/resumes, MISSING_METADATA → INCOMPLETE, APPROVED+priced → READY, WAITING_FOR_REVIEW → IN-PROGRESS, unpriced-territory → INCOMPLETE, applied-but-incomplete-live → not READY, equalize present in desired state, JSON + interactive. Blocked byDX-973 (needs |
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c007482. Configure here.
|
bugbot run |
c007482 to
e3ec2fb
Compare
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
1 issue from previous review remains unresolved.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit ed7cb62. Configure here.
|
bugbot run |
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 2cabff9. Configure here.
43375b7 to
2cabff9
Compare
ce4d427 to
7247adf
Compare
|
bugbot run |
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c2adaec. Configure here.
…ization apply/sync now read each affected product's live store state and report READY / IN_PROGRESS / INCOMPLETE / FAILED from raw_store_status + availability/ pricing, instead of a blanket success — so "RevenueCat accepted" is no longer mistaken for "Apple sellable." Adds --equalize-base-territory to fill missing subscription territory prices via common.pricing.equalize_missing_subscription_prices. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…xt actions Post-apply readiness now carries the live store warnings (the store's own remedy text) and derived next actions (unpriced -> --equalize-base-territory; MISSING_METADATA -> add metadata + attach a real screenshot) per product, in both JSON and interactive output, so a non-READY result names the fix instead of just the condition. Adds WAITING_FOR_UPLOAD to in-progress, documents the verdicts and --equalize-base-territory in help. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
--equalize-base-territory is App Store subscription equalization; a Play product with unpriced territories was being told to use it. Route Play to its own base-plan other-regions guidance and keep a neutral fallback, so readiness next-actions aren't Apple-only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both stores collapse into RevenueCat's normalized status enum; the classifier only handled ok/not_found and defaulted the rest to INCOMPLETE. Handle action_in_progress (in progress), needs_action/inactive_in_store/draft (incomplete), and could_not_check/unspecified/unknown (unknown). Play has no verbatim raw state, so this normalized layer is its primary readiness signal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A create apply can return plan items whose RevenueCat product ID is still unset. verifyStoreStateReadiness dropped those items, so a create-only apply left an empty product list and worstReadiness reported READY — printing success though no live store state was ever read. Record unreadable items as UNKNOWN and make an empty list UNKNOWN too, so readiness is never READY without a check. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The unpriced-territory next action told users to re-run with --equalize-base-territory, but that flag lives on products store plan/sync, not apply — following it on the apply path hits an unknown-flag error. Name the right commands. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
An apply whose plan already matched the desired state reported success and returned without reading live store state, so an in-sync but unsellable catalog (e.g. MISSING_METADATA) looked done. Run the same readiness check the normal apply path uses and surface its verdict. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
c2adaec to
32e7844
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 32e7844. Configure here.
| } | ||
| if pr.RawStoreStatus != nil && strings.EqualFold(*pr.RawStoreStatus, "MISSING_METADATA") { | ||
| actions = append(actions, "add the product's required metadata (localizations/review info) and re-apply; attach a real review screenshot with: rc products store screenshot <product-id> --file <path>") | ||
| } |
There was a problem hiding this comment.
Metadata hint points at re-apply
Medium Severity
The MISSING_METADATA next action tells users to add localizations or review info and re-apply. apply only replays the existing plan ID and never picks up new desired state, so that path cannot supply the missing metadata. Screenshot upload is a separate command and is fine; the rest of the hint sends agents back through the same incomplete plan.
Reviewed by Cursor Bugbot for commit 32e7844. Configure here.


Closes the Product Catalog team's #1 concern: "RevenueCat accepted the plan" was being reported as if "Apple has a sellable product." Now
products store apply/syncverify the live result.Stacked on #125 (which captures
raw_store_status).Post-apply readiness
After apply reaches
applied, it reads each affected product's live store state and classifies it — no longer a blanket "Applied to the stores":APPROVED+ every available territory priced → READYMISSING_METADATA/READY_TO_SUBMIT/DEVELOPER_ACTION_NEEDED(or any available-but-unpriced territory) → INCOMPLETE (lists the unpriced territories)WAITING_FOR_REVIEW/IN_REVIEW/PENDING_BINARY_APPROVAL→ IN PROGRESSnot_found/ apply failed → FAILEDOverall = worst product; a non-READY overall renders as a warning, not a success.
--jsongets areadinessobject (overall+ per-product{product_id, verdict, raw_store_status, unpriced_territories}) alongside the plan.syncgets this automatically (it calls the same apply path).Equalization
--equalize-base-territory USinjectscommon.pricing.equalize_missing_subscription_pricesinto each desired state (preserving any explicitterritory_prices), so missing App Store subscription prices get filled during apply.(Blocker-gating on
warnings[severity=blocker]already existed.)Agreements/tax/banking are intentionally out of scope — account-level, not derivable from per-product state.
Tests: classifier table (every verdict), worst-overall, equalization injection, and an apply→readiness integration test asserting a
MISSING_METADATAresult reports INCOMPLETE (not success).🤖 Generated with Claude Code
Note
Medium Risk
Changes apply/sync output and success signaling for agents (JSON envelope, warning vs success). Classification of store statuses could mis-report readiness, but apply itself is unchanged and live reads are best-effort.
Overview
products store apply/syncno longer treat a successful plan apply as a sellable product. After apply (including no-op plans), the CLI reads each product's live store state and reports READY / IN_PROGRESS / INCOMPLETE / FAILED / UNKNOWN, with overall = worst product. Non-READY is a warning, not success.--jsonadds areadinessobject (verdict,raw_store_status, unpriced territories, store warnings, next actions).Adds
--equalize-base-territoryon plan/sync so missing App Store subscription prices are filled from a base territory during apply, without overwriting existingterritory_prices. Next-action hints are store-specific (Play is not told to use the Apple flag).Reviewed by Cursor Bugbot for commit 32e7844. Bugbot is set up for automated code reviews on this repo. Configure here.