feat(masters): add direct masters update — Этап A (issue #631) - #646
Conversation
Review summary — PR #646 (issue #631, masters update Stage A)Проведено ревью ( 1. HIGH —
|
Addresses cycle-review findings on PR #646: - update_master no longer reports success on the click alone. After clicking save, it re-navigates to the edit page and re-reads every requested field (_verify_saved) — a mismatch after reload raises BrowserSessionError instead of a false success. This mirrors _suspend_or_resume's existing "never trust the click alone" convention, which update_master previously did not follow for the whole-form save. - _click_save and _set_promotion_goal's option click now use get_by_role(..., exact=True) instead of get_by_text(..., exact=False) — the substring match risked hitting an ancestor container instead of the actual button/option element. _set_promotion_goal's post-click verification is now an exact string comparison for the same reason. - FakePage gained a get_by_role() that honors role/name/exact the same way real Playwright does, so tests can no longer pass on a selector that wouldn't actually match in a real browser. - CHANGELOG corrected: the "click, then verify" convention only ever applied to the individual field setters, not the final save — now explicit that update_master's whole-form save is verified too. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XrEMYPNW55Ywi6eQL8EA8K
Review summary — PR #646, verification round 2 (commit b7f685d)Findings 1, 2, 3, 4 from round 1 are genuinely fixed and verified: 3 new findings surfaced during verification. HIGH — promotion-goal verification may compare against a value the page never shows
If the static reading is correct, Caveat: Needs one live read-only check before merge: open an edit page, open the dropdown, print MEDIUM —
|
Adds `update_master(page, campaign_id, ...)` and CLI `masters update` covering the three simplest scalar fields of the Мастер кампаний edit page: --weekly-budget, --promotion-goal, --directs-helps/--no-directs-helps. Live investigation (tests/fixtures/masters_wizard_edit_stage_a.html) confirmed the edit page is a single form with one save button — no per-section independent save — so a partial update leaves untouched fields at their current value rather than sending a partial payload. Later stages (headline/text lists, sitelinks, audience, media uploads) remain tracked in issue #631 and are not implemented here. Classified DANGEROUS in smoke_matrix.py (no --sandbox equivalent for browser-driven mutations, same as masters suspend/resume from #630). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XrEMYPNW55Ywi6eQL8EA8K
Addresses cycle-review findings on PR #646: - update_master no longer reports success on the click alone. After clicking save, it re-navigates to the edit page and re-reads every requested field (_verify_saved) — a mismatch after reload raises BrowserSessionError instead of a false success. This mirrors _suspend_or_resume's existing "never trust the click alone" convention, which update_master previously did not follow for the whole-form save. - _click_save and _set_promotion_goal's option click now use get_by_role(..., exact=True) instead of get_by_text(..., exact=False) — the substring match risked hitting an ancestor container instead of the actual button/option element. _set_promotion_goal's post-click verification is now an exact string comparison for the same reason. - FakePage gained a get_by_role() that honors role/name/exact the same way real Playwright does, so tests can no longer pass on a selector that wouldn't actually match in a real browser. - CHANGELOG corrected: the "click, then verify" convention only ever applied to the individual field setters, not the final save — now explicit that update_master's whole-form save is verified too. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XrEMYPNW55Ywi6eQL8EA8K
Live re-investigation (claude-in-chrome, campaign 107707079, read-only — see updated tests/fixtures/masters_wizard_edit_stage_a.html) confirmed Playwright's Locator.inner_text() on the "Цель продвижения" trigger is TWO lines: the static section label, then the current selection on its own line. The prior cycle-review fix that switched from a substring check to an exact-equality check compared the WHOLE two-line string against the bare one-line label — which could never succeed, making --promotion-goal fail on every real save despite the click landing correctly. Fixed by comparing only the LAST line of inner_text() (the live selection), via a new _trigger_shows_selection helper shared by _set_promotion_goal and _read_promotion_goal_label/_verify_saved. Tests now model the trigger's inner_text() as two lines, matching the live-confirmed shape, so this class of bug is caught rather than passing by coincidence on a single-line fake. Also: - New TestClickSave with a decoy-element test proving get_by_role's exact=True actually matters (mutating it back to exact=False now fails a test, closing the coverage gap the second review round flagged). - CHANGELOG rewritten to describe current behavior (save verification is implemented) instead of the stale "known gap" wording from the previous round. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XrEMYPNW55Ywi6eQL8EA8K
7559609 to
9a5c1df
Compare
Summary
Implements Этап A of issue #631 —
direct masters update, editing the three simplest scalar fields on the Мастер кампаний (Campaign Wizard) settings page:--weekly-budget(Недельный бюджет)--promotion-goal(max-conversions/max-clicks, Цель продвижения)--directs-helps/--no-directs-helps(Директ помогает — auto-apply recommendations)Later stages (headline/text variant lists, sitelinks, audience, Metrika counters/goals, budget adaptation, images/video) remain tracked in #631 and are not implemented here — this PR closes only the Этап A portion.
Live investigation (Step 0)
Drove
/wizard/campaigns/{id}/edit/live viaclaude-in-chromeagainst campaign 107707079 (stopped, non-critical). Findings captured intests/fixtures/masters_wizard_edit_stage_a.html:update_mastersubmits the whole form on every call; fields not passed as flags are left at their current on-page value simply by never touching their input.Implementation
direct_cli/browser/masters.py:update_master(page, campaign_id, *, weekly_budget=None, promotion_goal=None, directs_helps=None)plus private_set_weekly_budget/_set_directs_helps/_set_promotion_goal/_click_save, following the module's existing "click, then verify it actually took effect" convention (mirrors_suspend_or_resume).direct_cli/commands/masters.py: newmasters update <campaign_id>command; requires at least one of the three flags.direct_cli/smoke_matrix.py:masters.updateclassifiedDANGEROUS(no--sandboxequivalent for browser-driven mutations, same rationale asmasters suspend/resumefrom direct masters suspend/resume — остановка и возобновление Мастера кампаний #630).scripts/test_dangerous_commands.sh,README.md(EN+RU),CHANGELOG.mdupdated.tests/test_cli_contract.py: addedmasters.updatetoDRY_RUN_EXCEPTIONS(browser click, no request payload to preview).Test plan
pytest(offline suite) — 2689 passed, 8 skipped (pre-existingtest_read_cassettes.py/test_integration_write.pyerrors are an unrelated environment issue:vcrpy/aiohttpincompatibility, confirmed present onmaintoo viagit stash)_set_*function plusupdate_master(partial updates, multi-field updates, error paths) and CLI wiringblack --check/flake8clean on all changed filesCloses #631 (Этап A only — B/C/D remain open as follow-up work per the issue's own staged plan)
🤖 Generated with Claude Code
https://claude.ai/code/session_01XrEMYPNW55Ywi6eQL8EA8K