Repository navigation
fix(backend): validate non-negative prices, bounds, and typing in storefront models ($25 bounty proposal) - #21514
aiwithrajan wants to merge 2 commits into
Conversation
…refront models ($25 bounty proposal)
Git-on-my-level
left a comment
There was a problem hiding this comment.
Thanks @aiwithrajan — the non-negative bounds you added are largely right, and I appreciate the hermetic tests. One blocking issue before this can merge.
Blocking: the 100 cap on usage percent breaks the exhausted-budget surface
- backend/models/storefront.py:
percent: Optional[int] = Field(default=None, ge=0, le=100)— but percent at and above 100 is a documented state, not invalid data. backend/docs/storefront-contract.md defines the exhausted surface asusage_budgetwith "usage percent at least 100" (the same split that selects theYou've used all of this month's usageheader). - Production source: backend/routers/storefront.py
_usageacceptsbudget_percentfrom the usage projection guarded only bypercent >= 0and finiteness — there is no upper clamp anywhere, and backend/utils/storefront_copy.pypresent_usage/_wire_percentround but never clamp. - Effect on this head: backend/tests/unit/test_storefront_presentation.py parametrizes the cap surface with percent=140 (test_pro_budget_cap_recommends_architect_checkout, test_legacy_price_pro_at_cap_lists_architect_without_checkout, test_pro_at_cap_without_purchasable_architect_price_is_not_recommended) via
StorefrontUsage(**present_usage(...)), which now raises ValidationError. In production, the broad except in_usagewould catch that and degrade an over-budget user tokind: "unavailable"— showing the 80% header instead of the exhausted-budget surface and hiding the Architect upgrade card exactly for the users who need it.
Requested change: remove le=100 and keep ge=0. If you believe the wire should cap at 100, that's a product/contract decision — it needs a clamp at the presentation layer plus contract and test updates, so please raise it with a maintainer rather than encoding it in the model.
What looks good
amount_minor: ge=0: matches every producer (paid rows are filtered tounit_amount > 0in_valid_price_rows; the Free tier is intentionally 0 — your zero-amount test covers that correctly).months_free ge=0andcatalog_revision ge=0: producers aremonths_free()(>=1 or None) and CATALOG_REVISION (currently 7) — safe.currencymin_length=1/max_length=10: fine for ISO codes; producers are Stripe'susdor the ladder config.- backend/tests/unit/test_storefront_validation.py: hermetic, and the
from models.storefront import ...convention matches the existing suite. One note on the test plan: running only this file shows 9/9 green, but the checks on this PR only include the AI reviewer — the backend unit suite hasn't run. It would have caught the percent=140 failures above; please run the full backend unit suite (or push so CI picks it up) after the change.
Minor, non-blocking: the str | None to Optional[str] swap is behaviorally identical but reverses the file's (and the surrounding backend's) PEP 604 style; consider dropping that churn so the diff is only the validation change.
The non-negative bounds are a genuine hardening win — with the le=100 cap removed this is in good shape.
by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.
… bounty proposal) Failure-Class: validation-gap
|
Updated: removed the |
Dismissed: the blocking concern (le=100 cap on StorefrontUsage.percent breaking the documented exhausted-budget surface, where usage percent at least 100 is valid per backend/docs/storefront-contract.md) is resolved at 183a54d — percent is now Field(default=None, ge=0) with no upper cap, and the boundary test asserts percent 0/100/140 all validate.
|
Thanks @aiwithrajan — this follow-up resolves the blocking issue from my earlier review.
One remaining gate: no checks have run on this head yet (183a54d). Please make sure the backend unit suite runs green here — in particular backend/tests/unit/test_storefront_presentation.py, which parametrizes percent=140 through The With CI green this is in good shape for a maintainer to pick up. by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with |
|
Hey @aiwithrajan 👋 Thank you so much for taking the time to contribute to Omi! We truly appreciate you putting in the effort to submit this pull request. After careful review, we've decided not to merge this particular PR. Please don't take this personally — we genuinely try to merge as many contributions as possible, but sometimes we have to make tough calls based on:
Before your next PR, please skim:
If this was declined for direction or taste, maintainers should cite an invariant ID or open a proposed one — ask if that citation is missing. Your contribution is still valuable to us, and we'd love to see you contribute again in the future! If you'd like feedback on how to improve this PR or want to discuss alternative approaches, please don't hesitate to reach out. Thank you for being part of the Omi community! |
Description
Validates non-negative prices, bounds, and typing in storefront models.
Currently:
StorefrontPricedefinesamount_minor: intwithout lower-bound constraints, allowing negative price amounts to be deserialized.months_freeinStorefrontPriceandcatalog_revisioninStorefrontResponselack non-negative bounds (ge=0).percentinStorefrontUsagelacks range bounds (ge=0, le=100).Optional[...]across storefront models for typing consistency.This change:
ge=0bounds toamount_minor,months_free, andcatalog_revision.percentinStorefrontUsageto[0, 100].currencystrings (min_length=1, max_length=10).backend/tests/unit/test_storefront_validation.py.Test Plan