You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Version 0.3.0 cannot ship until command/API coverage is 100% across the supported Yandex Direct CLI surface. This issue is the release roadmap and gate. It links live model gaps, command contract, method correctness, write/integration coverage, and the documentation matrix.
Definition of 100% command coverage for 0.3.0
0.3.0 is releasable only when:
scripts/build_api_coverage_report.py reports summary.strict_parity_ok == true (✅ already true on main)
scripts/build_api_coverage_report.py reports summary.live_model_parity_ok == true (✅ already true on main)
SelectionCriteria required params verified (only for methods that take a SelectionCriteria). Source of truth: minOccurs=1 fields in the WSDL request schema.
⚠️ Integration test (tests/test_integration.py::TestReadOnlyAgencyClients) skips on HTTP 403 / Access denied for non-agency accounts; live coverage therefore depends on an agency token
✅ update · smoke: DANGEROUS
CLI command exists (method parity)
[n/a] FieldNames validation
[n/a] SelectionCriteria validation
Integration test passing (sandbox or prod)
✅ delete (CLI-only guard, no WSDL op) · smoke: DANGEROUS
CLI command exists
[n/a] FieldNames validation
[n/a] SelectionCriteria validation
[n/a] Integration test
Rationale: CLI guard command: the Yandex Direct API does not support deleting agency clients, so the command aborts with an explicit message.
Before this issue can be closed, #108 must be merged so that the tests/test_api_coverage.py::test_default_fieldnames_match_wsdl_enum test exists and passes for all services. The test parses every *FieldEnum from tests/wsdl_cache/*.xml and asserts that:
Each default FieldNames value (from direct_cli/utils.py:COMMON_FIELDS and from any hard-coded value inside direct_cli/commands/*.py) is a member of the corresponding WSDL enum.
Each get-method that has minOccurs=1SelectionCriteria fields in WSDL refuses to build a payload without them (no silent empty-SelectionCriteria requests).
Confirmed remaining schema-level work after #107 (driven by #108):
smartadtargets — drop Status, ServingStatus from default fields, add State.
adextensions — add State to default fields.
businesses — drop Type from COMMON_FIELDS (not in WSDL enum).
Add the test_default_fieldnames_match_wsdl_enum test in tests/test_api_coverage.py.
Integration-test correctness work
Independent of WSDL parity, several tests/test_integration.py cases pass the wrong CLI flags (root cause of the original audit complaint):
leads get — switch test from --campaign-ids to --turbo-page-ids (matches WSDL SelectionCriteria.TurboPageIdsminOccurs=1).
advideos get — pass --ids (WSDL marks IdsminOccurs=1).
agencyclients — treat live error_code=54 ("not an agency account") as expected outcome, not a failure.
These are issues with the tests, not the CLI. They are listed here because they are the visible symptoms users hit when running pytest -m integration -v.
Roadmap (existing phases — kept intact)
Phase 1 — Make coverage gaps machine-visible (#54)
Keep api_coverage_report.json as source of truth for the release gate
Expose declared vs live-discovered counts
Expose missing services/methods under model_gaps
Print values in GitHub Actions coverage summary
Keep tests/API_COVERAGE.md as the human-readable matrix
Status: ✅ done.
Phase 2 — Close live-discovered service gaps
Originally tracked the dynamicfeedadtargets (×6 methods) and strategies (×5 methods) live gaps.
Status: ✅ done — verified by the per-service status above.
Phase 3 — Fix known command-correctness blockers (#35, #33)
Fix keywordsresearch wire-method names (camelCase via METHOD_NAME_OVERRIDES).
Add request/dry-run assertions that catch wrong body["method"].
Resolve bidmodifiers toggle API ambiguity.
Status: ✅ done — bidmodifiers.toggle deprecated/removed (see comment & tests/API_ISSUE_AUDIT.md).
Every WSDL service block above shows ✅ at the service-level rollup
tests/API_COVERAGE.md lists every canonical command with classification
README API coverage and CLI contract match the CLI surface
All blocker issues closed or explicitly non-blocking with rationale
Exclusion policy (from earlier comment)
The 0.3.0 100% gate counts the supported live API surface only.
If an operation is officially deprecated/removed, absent from live WSDL, or contradicted by the official changelog, it must be recorded in tests/API_ISSUE_AUDIT.md before being excluded.
Such an operation is not a missing CLI command and must not block 0.3.0.
If official docs and live WSDL disagree, classify as docs-drift and resolve before implementing.
Worked example: bidmodifiers.toggle is deprecated since 2025-11-13; live WSDL exposes only bidmodifiers add/delete/get/set; #33 closed as not-planned and excluded from coverage counts.
Roadmap: 0.3.0 command coverage must reach 100%
Goal
Version
0.3.0cannot ship until command/API coverage is 100% across the supported Yandex Direct CLI surface. This issue is the release roadmap and gate. It links live model gaps, command contract, method correctness, write/integration coverage, and the documentation matrix.Definition of 100% command coverage for 0.3.0
0.3.0is releasable only when:scripts/build_api_coverage_report.pyreportssummary.strict_parity_ok == true(✅ already true onmain)scripts/build_api_coverage_report.pyreportssummary.live_model_parity_ok == true(✅ already true onmain)model_gaps.live_discovered_missing_services == [](✅)model_gaps.live_discovered_missing_methods == 0(✅)summary.schema_parity_ok == true(🟡 introduced by fix: WSDL FieldName enums not validated — default fields diverge from API schema #108) — everyget-method's defaultFieldNamesis a subset of the corresponding WSDL*FieldEnum, and everySelectionCriteriadefault satisfiesminOccurs=1n/arationale)Current baseline (snapshot 2026-04-25)
reports, JSON API)summary.strict_parity_ok: ✅truesummary.live_model_parity_ok: ✅truemodel_gaps.live_discovered_missing_services:[]model_gaps.live_discovered_missing_methods:0Per-method status criteria
For every WSDL operation (and every CLI-only guard) the issue tracks four checkboxes:
FieldNamesvalidated against WSDL*FieldEnum(only forget-methods). Source of truth:tests/wsdl_cache/<service>.xml. Driver: fix: WSDL FieldName enums not validated — default fields diverge from API schema #108.SelectionCriteriarequired params verified (only for methods that take aSelectionCriteria). Source of truth:minOccurs=1fields in the WSDL request schema.Service-level emoji rollup:
n/a).smokeannotation refers to the smoke-matrix category fromdirect_cli/smoke_matrix.py(SAFE,WRITE_SANDBOX,DANGEROUS).Service-by-service status
1/30.
adextensions🟡API service:
adextensions· CLI group:adextensions· WSDL ops: 3add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFEState(defined in WSDL FieldEnum, dropped from response) (fix: WSDL FieldName enums not validated — default fields diverge from API schema #108)2/30.
adgroups✅API service:
adgroups· CLI group:adgroups· WSDL ops: 4add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFEupdate· smoke:WRITE_SANDBOX3/30.
adimages✅API service:
adimages· CLI group:adimages· WSDL ops: 3add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFE4/30.
ads✅API service:
ads· CLI group:ads· WSDL ops: 9add· smoke:WRITE_SANDBOXarchive· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFEmoderate· smoke:WRITE_SANDBOXresume· smoke:WRITE_SANDBOXsuspend· smoke:WRITE_SANDBOXunarchive· smoke:WRITE_SANDBOXupdate· smoke:WRITE_SANDBOX5/30.
advideos🟡API service:
advideos· CLI group:advideos· WSDL ops: 2add· smoke:WRITE_SANDBOXget· smoke:SAFEIdsasminOccurs=1; integration test currently omits it6/30.
agencyclients🟡API service:
agencyclients· CLI group:agencyclients· WSDL ops: 5 + 1 CLI-only guardadd· smoke:DANGEROUSaddPassportOrganization(CLI:add-passport-organization) · smoke:DANGEROUSaddPassportOrganizationMember(CLI:add-passport-organization-member) · smoke:DANGEROUSget· smoke:SAFEtests/test_integration.py::TestReadOnlyAgencyClients) skips on HTTP 403 /Access deniedfor non-agency accounts; live coverage therefore depends on an agency tokenupdate· smoke:DANGEROUSdelete(CLI-only guard, no WSDL op) · smoke:DANGEROUS7/30.
audiencetargets✅API service:
audiencetargets· CLI group:audiencetargets· WSDL ops: 6add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFEresume· smoke:WRITE_SANDBOXsetBids(CLI:set-bids) · smoke:WRITE_SANDBOXsuspend· smoke:WRITE_SANDBOX8/30.
bidmodifiers🟡API service:
bidmodifiers· CLI group:bidmodifiers· WSDL ops: 4add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFELevels(e.g.["CAMPAIGN"]) in SelectionCriteriaset· smoke:WRITE_SANDBOX9/30.
bids✅API service:
bids· CLI group:bids· WSDL ops: 3get· smoke:SAFEset· smoke:WRITE_SANDBOXsetAuto(CLI:set-auto) · smoke:WRITE_SANDBOX10/30.
businesses🟡API service:
businesses· CLI group:businesses· WSDL ops: 1get· smoke:SAFETypewhich is not in WSDL FieldEnum (fix: WSDL FieldName enums not validated — default fields diverge from API schema #108 audit pending)11/30.
campaigns✅API service:
campaigns· CLI group:campaigns· WSDL ops: 8add· smoke:WRITE_SANDBOXarchive· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFEresume· smoke:WRITE_SANDBOXsuspend· smoke:WRITE_SANDBOXunarchive· smoke:WRITE_SANDBOXupdate· smoke:WRITE_SANDBOX12/30.
changes✅API service:
changes· CLI group:changes· WSDL ops: 3check· smoke:SAFEcheckCampaigns(CLI:check-campaigns) · smoke:SAFEcheckDictionaries(CLI:check-dictionaries) · smoke:SAFE13/30.
clients✅API service:
clients· CLI group:clients· WSDL ops: 2get· smoke:SAFEupdate· smoke:WRITE_SANDBOX14/30.
creatives✅API service:
creatives· CLI group:creatives· WSDL ops: 2add· smoke:WRITE_SANDBOXget· smoke:SAFE15/30.
dictionaries✅API service:
dictionaries· CLI group:dictionaries· WSDL ops: 2get· CLI helper aliases:list-names· smoke:SAFEgetGeoRegions(CLI:get-geo-regions) · smoke:SAFE16/30.
dynamicfeedadtargets✅API service:
dynamicfeedadtargets· CLI group:dynamicfeedadtargets· WSDL ops: 6add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFEresume· smoke:WRITE_SANDBOXsetBids(CLI:set-bids) · smoke:WRITE_SANDBOXsuspend· smoke:WRITE_SANDBOX17/30.
dynamictextadtargets✅API service:
dynamictextadtargets· CLI group:dynamicads· WSDL ops: 6add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFEresume· smoke:WRITE_SANDBOXsetBids(CLI:set-bids) · smoke:WRITE_SANDBOXsuspend· smoke:WRITE_SANDBOX18/30.
feeds🟡API service:
feeds· CLI group:feeds· WSDL ops: 4add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFEIdsasminOccurs=1update· smoke:WRITE_SANDBOX19/30.
keywordbids✅API service:
keywordbids· CLI group:keywordbids· WSDL ops: 3get· smoke:SAFEset· smoke:WRITE_SANDBOXsetAuto(CLI:set-auto) · smoke:WRITE_SANDBOX20/30.
keywords✅API service:
keywords· CLI group:keywords· WSDL ops: 6add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFEresume· smoke:WRITE_SANDBOXsuspend· smoke:WRITE_SANDBOXupdate· smoke:WRITE_SANDBOX21/30.
keywordsresearch🟡API service:
keywordsresearch· CLI group:keywordsresearch· WSDL ops: 2deduplicate· smoke:SAFEhasSearchVolume(CLI:has-search-volume) · smoke:SAFEKeywordsandRegionIds22/30.
leads🟡API service:
leads· CLI group:leads· WSDL ops: 1get· smoke:SAFETurboPageIds; integration test currently passes--campaign-ids(no such option) → exit_code=223/30.
negativekeywordsharedsets✅API service:
negativekeywordsharedsets· CLI group:negativekeywordsharedsets· WSDL ops: 4add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFEupdate· smoke:WRITE_SANDBOX24/30.
retargetinglists✅API service:
retargetinglists· CLI group:retargeting· WSDL ops: 4add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFEupdate· smoke:WRITE_SANDBOX25/30.
sitelinks✅API service:
sitelinks· CLI group:sitelinks· WSDL ops: 3add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFE26/30.
smartadtargets🟡API service:
smartadtargets· CLI group:smartadtargets· WSDL ops: 7add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFEStatus,ServingStatus— onlyStateexists in WSDL FieldEnum (fix: WSDL FieldName enums not validated — default fields diverge from API schema #108)resume· smoke:WRITE_SANDBOXsetBids(CLI:set-bids) · smoke:WRITE_SANDBOXsuspend· smoke:WRITE_SANDBOXupdate· smoke:WRITE_SANDBOX27/30.
strategies✅API service:
strategies· CLI group:strategies· WSDL ops: 5add· smoke:WRITE_SANDBOXarchive· smoke:WRITE_SANDBOXget· smoke:SAFEunarchive· smoke:WRITE_SANDBOXupdate· smoke:WRITE_SANDBOX28/30.
turbopages✅API service:
turbopages· CLI group:turbopages· WSDL ops: 1get· smoke:SAFE29/30.
vcards✅API service:
vcards· CLI group:vcards· WSDL ops: 3add· smoke:WRITE_SANDBOXdelete· smoke:WRITE_SANDBOXget· smoke:SAFE30/30.
reports✅API service:
reports· CLI group:reports· JSON API (no WSDL)Coverage policy: contract tests + spec snapshot. Source of truth:
tests/reports_cache/spec.json, drift script:scripts/check_reports_drift.py.reports.get· smoke:SAFEtests/reports_cache/spec.jsonscripts/check_reports_drift.pyreports.list-types· smoke:SAFESchema validation gate (driven by #108)
Before this issue can be closed, #108 must be merged so that the
tests/test_api_coverage.py::test_default_fieldnames_match_wsdl_enumtest exists and passes for all services. The test parses every*FieldEnumfromtests/wsdl_cache/*.xmland asserts that:FieldNamesvalue (fromdirect_cli/utils.py:COMMON_FIELDSand from any hard-coded value insidedirect_cli/commands/*.py) is a member of the corresponding WSDL enum.get-method that hasminOccurs=1SelectionCriteriafields in WSDL refuses to build a payload without them (no silent empty-SelectionCriteriarequests).Confirmed remaining schema-level work after #107 (driven by #108):
smartadtargets— dropStatus,ServingStatusfrom default fields, addState.adextensions— addStateto default fields.businesses— dropTypefromCOMMON_FIELDS(not in WSDL enum).test_default_fieldnames_match_wsdl_enumtest intests/test_api_coverage.py.Integration-test correctness work
Independent of WSDL parity, several
tests/test_integration.pycases pass the wrong CLI flags (root cause of the original audit complaint):leads get— switch test from--campaign-idsto--turbo-page-ids(matches WSDLSelectionCriteria.TurboPageIdsminOccurs=1).advideos get— pass--ids(WSDL marksIdsminOccurs=1).agencyclients— treat liveerror_code=54("not an agency account") as expected outcome, not a failure.These are issues with the tests, not the CLI. They are listed here because they are the visible symptoms users hit when running
pytest -m integration -v.Roadmap (existing phases — kept intact)
Phase 1 — Make coverage gaps machine-visible (#54)
api_coverage_report.jsonas source of truth for the release gatemodel_gapstests/API_COVERAGE.mdas the human-readable matrixStatus: ✅ done.
Phase 2 — Close live-discovered service gaps
Originally tracked the
dynamicfeedadtargets(×6 methods) andstrategies(×5 methods) live gaps.Status: ✅ done — verified by the per-service status above.
Phase 3 — Fix known command-correctness blockers (#35, #33)
keywordsresearchwire-method names (camelCase viaMETHOD_NAME_OVERRIDES).body["method"].bidmodifiers toggleAPI ambiguity.Status: ✅ done —
bidmodifiers.toggledeprecated/removed (see comment &tests/API_ISSUE_AUDIT.md).Phase 4 — Finish canonical command contract & docs (#42, #44)
Status: 🟡 in progress.
Phase 5 — Complete coverage matrix beyond contract parity (#41, #28)
tests/API_COVERAGE.md.Status: 🟡 in progress.
Release gate checklist
pytest -q tests/test_api_coverage.py tests/test_reports_drift.py tests/test_dry_run.py tests/test_cli.py tests/test_comprehensive.pypassespython3 scripts/build_api_coverage_report.pyreportsstrict_parity_ok: truepython3 scripts/build_api_coverage_report.pyreportslive_model_parity_ok: truemodel_gaps.live_discovered_missing_servicesis emptymodel_gaps.live_discovered_missing_methodsis0summary.schema_parity_ok == trueafter fix: WSDL FieldName enums not validated — default fields diverge from API schema #108 mergestests/API_COVERAGE.mdlists every canonical command with classificationExclusion policy (from earlier comment)
The 0.3.0 100% gate counts the supported live API surface only.
tests/API_ISSUE_AUDIT.mdbefore being excluded.docs-driftand resolve before implementing.Worked example:
bidmodifiers.toggleis deprecated since 2025-11-13; live WSDL exposes onlybidmodifiers add/delete/get/set; #33 closed as not-planned and excluded from coverage counts.Related issues
strategies,turbopages,businesses.keywords archive/unarchive(API method does not exist).