Context
During the VCR cassette recording session for PR #17 / #14, several write-commands failed against the sandbox with specific payload errors. Tests were hardened to pytest.fail on unknown errors and only pytest.skip on a narrow _is_sandbox_error pattern — so each item below currently skips at replay time via a known error pattern captured in its cassette.
This is an umbrella issue tracking those 6 outstanding payload issues. They split roughly into two groups: 3 real CLI bugs (direct-cli builds a wrong payload) and 3 test-fixture gaps (my integration test sends JSON missing required fields). Both categories convert a skipped test into a passing one once fixed, which in turn strengthens the regression guard.
Why cassettes are regression guards for this work
For each item below, PR #17 committed a YAML cassette that freezes the current broken request → error response pair. The fix workflow is the same shape every time:
- Edit the offending file (CLI code or test payload) so the request body changes.
pytest -m integration_write -v — the existing cassette will immediately fail to match, because vcrpy's body matcher sees the new request.
- Re-record with real sandbox token:
set -a && source .env && set +a
pytest -m integration_write --record-mode=rewrite -v -k <TestClass>
- Audit the new cassette for token/login leaks:
grep -r "$YANDEX_DIRECT_TOKEN" tests/cassettes/ # must be empty
grep -r "$YANDEX_DIRECT_LOGIN" tests/cassettes/ # must be empty
- Remove the now-obsolete
extra_patterns=(...) from the test's skip branch, so the test now asserts the API accepted the payload instead of silently skipping.
- Commit both: the source fix AND the regenerated cassette.
If anyone later reintroduces the old broken payload, body matching will fail and CI will flag it — that is the regression guard.
Real CLI bugs (3)
Test-fixture payload gaps (3)
Done-when
Links
Context
During the VCR cassette recording session for PR #17 / #14, several write-commands failed against the sandbox with specific payload errors. Tests were hardened to
pytest.failon unknown errors and onlypytest.skipon a narrow_is_sandbox_errorpattern — so each item below currently skips at replay time via a known error pattern captured in its cassette.This is an umbrella issue tracking those 6 outstanding payload issues. They split roughly into two groups: 3 real CLI bugs (direct-cli builds a wrong payload) and 3 test-fixture gaps (my integration test sends JSON missing required fields). Both categories convert a skipped test into a passing one once fixed, which in turn strengthens the regression guard.
Why cassettes are regression guards for this work
For each item below, PR #17 committed a YAML cassette that freezes the current broken request → error response pair. The fix workflow is the same shape every time:
pytest -m integration_write -v— the existing cassette will immediately fail to match, because vcrpy's body matcher sees the new request.extra_patterns=(...)from the test's skip branch, so the test now asserts the API accepted the payload instead of silently skipping.If anyone later reintroduces the old broken payload, body matching will fail and CI will flag it — that is the regression guard.
Real CLI bugs (3)
1.
feeds add— hardcodes unknown fieldSourceTypedirect_cli/commands/feeds.py:75feed_data = {"Name": name, "Source": url, "SourceType": "URL"}error_code=8000, error_detail=An item in the Feeds array contains the unknown parameter SourceTypetests/cassettes/test_integration_write/TestWriteFeeds.test_add_update_delete.yamlSourceTypekey. Feed kind is inferred from the nestedBusinessType/FileFeedstructure per Yandex Direct API docs. Verify via Context7 docs before removing.TestWriteFeeds.test_add_update_delete— dropextra_patterns=("unknown parameter",)afterwards.2.
adextensions add— sends duplicate top-levelTypefielddirect_cli/commands/adextensions.py:75ext_data = {"Type": ext_type}before merging user JSONerror_code=8000, error_detail=An item in the AdExtensions array contains the unknown parameter Typetests/cassettes/test_integration_write/TestWriteAdExtensions.test_add_delete.yamlext_datawithType. The API derives extension type from the nested field name (Callout/Sitelinks/ ...). Drop the CLI--typeoption or make it dry-run-only.ads/smartadtargets). Re-use the same fix pattern.TestWriteAdExtensions.test_add_delete.3.
bidmodifiers setcannot create new modifiersdirect_cli/commands/bidmodifiers.py:79setbuilds{CampaignId, Type, BidModifier}with noId.error_code=8000, error_detail=The required field Id is omitted in an item in the BidModifiers array— thesetmethod UPDATES existing modifiers only.tests/cassettes/test_integration_write/TestWriteBidModifiersSet.test_set_without_id_is_rejected.yaml(frozen as a regression anchor by PR test: VCR cassette replay + regression guards for integration_write #17)bidmodifiers addsubcommand backed by the API'saddmethod (structuredBidAdjustmentspayload per API docs). Keepsetworking with--idfor updates.TestWriteBidModifiersAdd.test_add_deletethat creates aMOBILE_ADJUSTMENTmodifier and deletes it. The currenttest_set_without_id_is_rejectedstays as a regression anchor for the update path.Test-fixture payload gaps (3)
4.
TestWriteDynamicAds.test_add_update_delete— payload missingOperandtests/test_integration_write.py— the test passes--json '{"Name":"Test Webpage","Conditions":[{"Operator":"CONTAINS","Arguments":["test"]}]}'required field Operand is omitted in an item in the Conditions arraytests/cassettes/test_integration_write/TestWriteDynamicAds.test_add_update_delete.yamlOperandexplicitly, e.g."Operand": "URL"with"Operator": "CONTAINS"and"Arguments": ["test"].dynamicads addis a pass-through for user JSON — the CLI isn't wrong, my test payload was incomplete.dynamicads add → update → delete.5.
TestWriteSmartAdTargets.test_add_update_delete— payload missingNametests/test_integration_write.py— the test passes--json '{"Subtype":"UNIQUE","Priority":3}'required field Name is omittedtests/cassettes/test_integration_write/TestWriteSmartAdTargets.test_add_update_delete.yaml"Name": "test-smart-target"to the payload (or whatever the spec calls for — verify field name via Context7 docs).6.
TestWriteRetargeting.test_add_delete—Rules[0]missingArgumentstests/test_integration_write.py— the test passes--json '{"Rules":[{"LowerBound":1,"UpperBound":365}]}'required field Arguments is omitted in an itemtests/cassettes/test_integration_write/TestWriteRetargeting.test_add_delete.yamlAUDIENCE_SEGMENTretargeting lists need anArgumentsarray of goal/segment IDs. Verify structure via Context7.Done-when
pytest -m integration_write -v(replay) shows 6 additional passing tests — none of items 1–6 skip anymore.Links