Skip to content

fix: audit parameter-level enums (close silent-drift blind spot)#31

Merged
amitray007 merged 2 commits into
masterfrom
fix/audit-parameter-enum-blind-spot
Jul 7, 2026
Merged

fix: audit parameter-level enums (close silent-drift blind spot)#31
amitray007 merged 2 commits into
masterfrom
fix/audit-parameter-enum-blind-spot

Conversation

@amitray007

Copy link
Copy Markdown
Owner

Summary

The SDK audit stopped reporting findings even though the Etsy spec changed. Investigation showed the maintenance tooling was structurally blind to the change, not that nothing changed.

What actually changed in the spec: Etsy removed Shipping and Inventory from the includes query-parameter enum on getListing (GET /v3/application/listings/{listing_id}) and getListingsByListingIds (GET /v3/application/listings/batch). They remain valid on getListingsByShop, which shares the same SDK enum.

Why nothing caught it — two blind spots (Must Fix):

  1. audit_sdk.get_spec_enums() only extracted enums from components/schemas, never from operation parameters. All 18 parameter-level enums (includes, state, sort_on, holiday_id, …) had never been audited. Now walks paths/*/*/parameters, covering both schema.enum and schema.items.enum (array params).
  2. diff_spec.diff_parameters() only compared schema.enum, missing schema.items.enum, so this change reported as "No changed endpoints". Now diffs items.enum too and reports added/removed values. (Side effect: the weekly maintenance workflow now escalates this class of change to medium severity instead of silently classifying it low/cosmetic.)

Latent bug exposed by the fix: scan_enum_values keyed SDK enums by class name alone, so Includes in ListingInventory.py (1 value) clobbered Includes in Listing.py (9 values). Now each name maps to a list of value-lists and compute_enum_findings picks the best-overlap candidate per spec enum.

Data decision (Should Fix → suppressed, non-breaking): The now-visible Includes drift is intentional — SHIPPING/INVENTORY are kept for backward compatibility and are still valid on getListingsByShop. Removing them would break callers. Documented inline in enums/Listing.py and suppressed in specs/audit-ignore.json (mirroring the existing State.REMOVED pattern). Param-side State.REMOVED and holiday_id findings mirror existing accepted decisions and are suppressed likewise. Baseline refreshed to the reviewed spec.

Findings tally: 2 Must Fix (tooling), 1 Should Fix (data, suppressed as intentional), 1 Informational (Etsy's spec is now internally inconsistent per-endpoint). All 7 prior suppressions re-verified as still valid; no stale ignores.

No SDK runtime behavior changes; no version bump (commit carries [skip ci]).

Test plan

  • pytest -q340 passed (was 334; +6 regression tests)
  • New tests lock in: parameter-enum extraction (scalar + items.enum), the duplicate-class-name collision fix, and the updated compute_enum_findings contract.
  • Verified diff_spec.py now reports includes (enum values changed (removed ['Inventory', 'Shipping'])) for both affected endpoints (previously "No changed endpoints").
  • Verified audit_sdk.py now surfaces the real Includes extras (inventory, shipping) and, after suppression, reports "All enum values are in sync" with no stale ignores.

🤖 Generated with Claude Code

@amitray007 amitray007 self-assigned this Jul 7, 2026
@amitray007 amitray007 requested a review from Copilot July 7, 2026 20:55

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.

@amitray007 amitray007 force-pushed the fix/audit-parameter-enum-blind-spot branch from 5c524f1 to c4e322d Compare July 7, 2026 21:09
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Test Coverage Report

Overall: 100% (1672/1672 statements covered)

Coverage by file
File Statements Missing Coverage
etsy_python/__init__.py 2 0 100%
etsy_python/_version.py 1 0 100%
etsy_python/v3/auth/OAuth.py 33 0 100%
etsy_python/v3/auth/__init__.py 1 0 100%
etsy_python/v3/common/Env.py 10 0 100%
etsy_python/v3/common/Request.py 3 0 100%
etsy_python/v3/common/Utils.py 31 0 100%
etsy_python/v3/enums/HolidayPreferences.py 29 0 100%
etsy_python/v3/enums/Language.py 12 0 100%
etsy_python/v3/enums/Listing.py 78 0 100%
etsy_python/v3/enums/ListingInventory.py 6 0 100%
etsy_python/v3/enums/ProcessingProfile.py 7 0 100%
etsy_python/v3/enums/ShippingProfile.py 261 0 100%
etsy_python/v3/enums/ShopReceipt.py 12 0 100%
etsy_python/v3/exceptions/BaseAPIException.py 10 0 100%
etsy_python/v3/exceptions/RequestException.py 8 0 100%
etsy_python/v3/exceptions/__init__.py 2 0 100%
etsy_python/v3/models/FileRequest.py 7 0 100%
etsy_python/v3/models/HolidayPreferences.py 8 0 100%
etsy_python/v3/models/Listing.py 150 0 100%
etsy_python/v3/models/Miscellaneous.py 8 0 100%
etsy_python/v3/models/ProcessingProfile.py 21 0 100%
etsy_python/v3/models/Product.py 7 0 100%
etsy_python/v3/models/Receipt.py 39 0 100%
etsy_python/v3/models/Request.py 22 0 100%
etsy_python/v3/models/ShippingProfile.py 85 0 100%
etsy_python/v3/models/Shop.py 24 0 100%
etsy_python/v3/models/ShopReturnPolicy.py 25 0 100%
etsy_python/v3/models/Utils.py 19 0 100%
etsy_python/v3/models/__init__.py 10 0 100%
etsy_python/v3/resources/HolidayPreferences.py 19 0 100%
etsy_python/v3/resources/Listing.py 81 0 100%
etsy_python/v3/resources/ListingFile.py 22 0 100%
etsy_python/v3/resources/ListingImage.py 22 0 100%
etsy_python/v3/resources/ListingInventory.py 20 0 100%
etsy_python/v3/resources/ListingOffering.py 12 0 100%
etsy_python/v3/resources/ListingProduct.py 12 0 100%
etsy_python/v3/resources/ListingTranslation.py 19 0 100%
etsy_python/v3/resources/ListingVariationImages.py 16 0 100%
etsy_python/v3/resources/ListingVideo.py 22 0 100%
etsy_python/v3/resources/Miscellaneous.py 16 0 100%
etsy_python/v3/resources/Payment.py 23 0 100%
etsy_python/v3/resources/PaymentLedgerEntry.py 15 0 100%
etsy_python/v3/resources/ProcessingProfile.py 26 0 100%
etsy_python/v3/resources/Receipt.py 25 0 100%
etsy_python/v3/resources/ReceiptTransactions.py 27 0 100%
etsy_python/v3/resources/Response.py 9 0 100%
etsy_python/v3/resources/Review.py 16 0 100%
etsy_python/v3/resources/Session.py 94 0 100%
etsy_python/v3/resources/ShippingProfile.py 58 0 100%
etsy_python/v3/resources/Shop.py 23 0 100%
etsy_python/v3/resources/ShopProductionPartner.py 11 0 100%
etsy_python/v3/resources/ShopReturnPolicy.py 28 0 100%
etsy_python/v3/resources/ShopSection.py 25 0 100%
etsy_python/v3/resources/Taxonomy.py 23 0 100%
etsy_python/v3/resources/User.py 14 0 100%
etsy_python/v3/resources/UserAddress.py 19 0 100%
etsy_python/v3/resources/__init__.py 29 0 100%
etsy_python/v3/resources/enums/RateLimit.py 8 0 100%
etsy_python/v3/resources/enums/Request.py 7 0 100%

Updated by PR Tests

…ip ci]

The SDK audit went silent on a real spec change: Etsy removed 'Shipping'
and 'Inventory' from the `includes` query-param enum on getListing and
getListingsByListingIds. Neither the audit nor the diff caught it.

Root causes (two blind spots in the maintenance tooling):

- audit_sdk.get_spec_enums() only extracted enums from components/schemas,
  never from operation parameters — so all 18 parameter-level enums
  (includes, state, sort_on, holiday_id, ...) were never audited. Now walks
  paths/*/*/parameters, covering both schema.enum and schema.items.enum
  (array params).
- diff_spec.diff_parameters() only compared schema.enum, missing
  schema.items.enum, so array-param enum changes read as "No changed
  endpoints". Now diffs items.enum too and reports added/removed values.

Surfacing parameter enums also exposed a latent collision: scan_enum_values
keyed SDK enums by class name alone, so Includes in ListingInventory.py
(1 value) clobbered Includes in Listing.py (9 values). Now each name maps to
a list of value-lists and compute_enum_findings picks the best-overlap
candidate per spec enum.

The now-visible Includes drift is intentional: SHIPPING/INVENTORY are kept
for backward compatibility and remain valid on getListingsByShop (which
shares the enum), so removing them would break callers. Documented inline in
enums/Listing.py and suppressed in specs/audit-ignore.json. The param-side
State.REMOVED and holiday_id findings mirror existing accepted decisions and
are suppressed likewise. Baseline refreshed to the reviewed spec.

Adds regression tests for parameter-enum extraction, the collision fix, and
updates existing compute_enum_findings tests to the new sdk_enums shape.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@amitray007 amitray007 force-pushed the fix/audit-parameter-enum-blind-spot branch from c4e322d to fb913f7 Compare July 7, 2026 21:12
PR Tests only triggered on pull_request events, and GitHub short-circuits
those before the workflow starts when the head commit carries a [skip ci]
marker — so a skip-ci PR silently got no test run at all. workflow_dispatch
is not subject to that short-circuit, so add it as a manual trigger to run
tests on demand for any ref, including skip-ci PRs.

- Add workflow_dispatch with an optional pr_number input.
- Guard the coverage-report job so a manual run without a PR number still
  runs tests but skips the PR comment.
- Resolve PR number and concurrency group from either the PR event or the
  dispatch input.

Note: workflow_dispatch only becomes available once this file is on the
default branch. Pairs with making Tests (Python 3.10/3.12) required status
checks in the branch ruleset so every PR must have them pass (or be run on
demand) before merge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@amitray007 amitray007 merged commit aed4d1a into master Jul 7, 2026
3 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.

2 participants