fix: stop sending 'legacy' param removed from 8 listing endpoints (#34) - #35
Merged
Conversation
Etsy's 2026-07-27 spec removed the `legacy` query parameter from 8 listing endpoints with no deprecation period. It remains valid on 14 other operations (receipts, transactions, getListingsByListingIds, ...), so this is a targeted removal, not a global one. The `legacy` keyword argument is retained on the affected methods so existing callers don't break, but passing it now emits a DeprecationWarning and the value is no longer forwarded to the API. Plan to drop the kwarg in the next major version. Affected: createDraftListing, getListingsByShop, getListing, findAllListingsActive, findAllActiveListingsByShop, updateListing, getListingInventory, updateListingInventory. Also route parameter drift through the audit suppression engine. It previously rendered straight from raw data, so param findings could not be suppressed at all — the 8 deliberate back-compat kwargs would have been flagged as noise on every weekly run. Findings now carry (type, key, direction, values) like enum findings, so an ignore suppresses only the reviewed parameter names and newly drifted params on the same operation still surface (verified by test and by temporarily introducing a bogus param). Report output is unchanged when no param_drift ignores are configured. Note: specs/baseline.json refreshed; `add_on_price` on PersonalizationQuestion needs no SDK change (response-only field, and questions are typed as List[Dict[str, Any]]). All 11 pre-existing suppressions re-verified as still valid. Pre-existing unrelated drift: .bumpversion.cfg (1.0.19) is behind _version.py (1.1.10). Closes #34 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Correction to the previous commit message: `add_on_price` is NOT response-only. The 2026-07-27 spec added it to the updateListingPersonalization *request* body too, as an optional nullable float per question (only supported for optional text_input questions). The conclusion is unchanged — no SDK change is required — but for a different reason than stated: `personalization_questions` is typed List[Dict[str, Any]], so the field already serializes through to the API. This test pins that pass-through so the behaviour is deliberate rather than incidental. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adversarial probing of the extended suppression engine surfaced two sharp edges. Both are pre-existing properties of the enum design, but adding param_drift makes them reachable for a new finding type, so pin them: - A `"*"` wildcard on a param_drift entry would hide unreviewed parameter drift on that operation, defeating the self-verifying property. - partition_findings applies only the FIRST ignore matching a given (type, key, direction). A duplicate entry would silently suppress part of a finding while reporting itself as stale. Both guards were mutation-tested: each fails when the condition is injected into the shipped file and passes once reverted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Independent code review found two mutants surviving the 370-test suite plus
a suppression-engine sharp edge. All three verified and fixed:
1. `legacy is not None` guard had zero coverage. No test passed legacy=False,
so mutating the guard to `if legacy:` (which stops warning on False) passed
all tests. Parametrized every legacy warn-and-drop test over [True, False]
so explicit False is now pinned. Mutant now fails 8 tests.
2. pytest.warns(match=...) is re.search, and operation ids are prefixes of
one another ("getListing" ⊂ "getListingsByShop"/"getListingInventory",
"updateListing" ⊂ "updateListingInventory"). Five of eight warn assertions
could not tell the operations apart — swapping the op id inside get_listing
passed all tests. Anchored every match to `from {op} by Etsy`. Mutant now
fails 2 tests.
3. Warning message reworded to state that any explicit value, incl. False, is
discarded — legacy=False previously sent ?legacy=false on the wire, so
dropping it is a request-shape change, not a no-op. Docstring documents the
deliberate is-not-None guard. (Release notes are generated from commits, so
this message is the changelog entry for that wire change.)
4. partition_findings defaulted a valued ignore's missing `values` to "*",
so an entry that OMITTED values silently suppressed everything — reachable
by omission, defeating the "prefer explicit values" guarantee for the newly
added param_drift type. Default is now [] (suppress nothing, self-report
stale); an explicit "*" still works. Guarded by two new tests.
Not changed: the add_on_price test (review agreed it earns its place),
_norm_values on a stray string (fails safe), and the 8x-duplicated ignore
reason (JSON has no shared constant; low value).
380 tests pass, 100% coverage retained.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
Test Coverage ReportOverall: 100% (1701/1701 statements covered) Coverage by file
Updated by PR Tests |
amitray007
force-pushed
the
fix/sdk-audit-2026-07-30
branch
from
July 30, 2026 08:16
e3d5b57 to
41c7943
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resolves the spec-drift reported in #34 (Etsy OAS spec, 2026-07-27).
The drift: Etsy removed the
legacyquery parameter from 8 listing endpoints with no deprecation period —createDraftListing,getListingsByShop,getListing,findAllListingsActive,findAllActiveListingsByShop,updateListing,getListingInventory,updateListingInventory. It remains valid on 14 other operations (receipts, transactions,getListingsByListingIds, …), so this is a targeted removal, not a global one.Approach (non-breaking): the
legacykeyword is kept on the 8 affected methods so no caller breaks, but passing it now emits aDeprecationWarningand the value is no longer forwarded to the API. Any explicit value — includinglegacy=False, which previously sent?legacy=falseon the wire — is discarded. Plan to drop the kwarg in the next major version. The 14 still-valid sites are untouched.Also in this PR (found during the work):
param_driftentries tospecs/audit-ignore.json.add_on_pricewas added to thePersonalizationQuestionschema (incl. theupdateListingPersonalizationrequest body). No SDK change needed —personalization_questionsis typedList[Dict[str, Any]]and passes it through; pinned by a test..bumpversion.cfg(had drifted to 1.0.19) up to_version.py(1.1.10) so the consistency check passes.Code review
An independent review pass found two mutants surviving the test suite plus a suppression edge; all fixed in
41c7943:legacy is not Noneguard had nolegacy=Falsecoverage → parametrized over[True, False].pytest.warns(match=...)prefix-matched sibling operations (getListing⊂getListingsByShop) → anchored all matches.valuessilently defaulted to wildcard → now defaults to "suppress nothing / self-report stale".Test plan
Closes #34
🤖 Generated with Claude Code