Fix run_rule(): clicking the menu item only opens a confirmation modal, never runs anything
All checks were successful
Deploy / deploy (push) Successful in 25s
All checks were successful
Deploy / deploy (push) Successful in 25s
The user reported runs logged as "success" locally weren't showing up
in MassPrice's own Activity Log. Live-debugged directly against
production: clicking the dropdown's "Run Rule" item opens a
confirmation modal ("Are you sure you want to continue?") rather than
running the rule immediately. Confirmed by network capture — without
clicking the modal's #Confirmation_Run button, zero requests fire, no
error is thrown, and the rule silently never runs. Every prior
"success" in run_history.json for real production traffic was
therefore a false positive.
Verified the fix live: clicking through #ConfirmationModal's
#Confirmation_Run now fires a real POST /Rule/Run request.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6TgffxTvYhqxykAbVQg2v
This commit is contained in:
parent
63e2296d1c
commit
988db5d5c4
4 changed files with 41 additions and 7 deletions
|
|
@ -76,6 +76,13 @@ deploy rsync (which runs `--delete`) and from git.
|
||||||
## If scheduled runs stop working
|
## If scheduled runs stop working
|
||||||
|
|
||||||
Check, in order:
|
Check, in order:
|
||||||
|
0. **Local Activity says success but nothing shows up in MassPrice's own
|
||||||
|
Activity Log** — this exact symptom happened in production once
|
||||||
|
already: `run_rule()` was only opening MassPrice's "Are you sure?"
|
||||||
|
confirmation modal, never clicking its `#Confirmation_Run` button, so
|
||||||
|
zero requests ever fired despite no error being thrown. Fixed, but if
|
||||||
|
it recurs (e.g. a MassPrice redesign changes the modal/selectors),
|
||||||
|
this is the first thing to suspect — see `CLAUDE.md`.
|
||||||
1. **Dashboard banner / Activity page** — a "session expired or missing"
|
1. **Dashboard banner / Activity page** — a "session expired or missing"
|
||||||
message means go log in again via the Session page. "rule id not
|
message means go log in again via the Session page. "rule id not
|
||||||
found" means a rule was renamed/deleted on MassPrice — click "Refresh
|
found" means a rule was renamed/deleted on MassPrice — click "Refresh
|
||||||
|
|
|
||||||
23
CLAUDE.md
23
CLAUDE.md
|
|
@ -44,12 +44,25 @@ tool is confirmed working, so there's exactly one thing triggering runs.
|
||||||
id/name pairs (cached to `rules_cache.json`, refreshed via the
|
id/name pairs (cached to `rules_cache.json`, refreshed via the
|
||||||
Dashboard's "Refresh Rules" button or on first boot). `run_rule(id)`
|
Dashboard's "Refresh Rules" button or on first boot). `run_rule(id)`
|
||||||
finds that rule's `li.rule.widget-rule` row, clicks its
|
finds that rule's `li.rule.widget-rule` row, clicks its
|
||||||
`.dropdown-ellipsis` three-dot toggle, then clicks the row's
|
`.dropdown-ellipsis` three-dot toggle, clicks the row's
|
||||||
`a.run-rule[data-rule-id=...]` item — mirroring exactly what a human
|
`a.run-rule[data-rule-id=...]` item — mirroring exactly what a human
|
||||||
does in the UI. **No public API was found or used** — the "Run Rule"
|
does in the UI — **then must click through a confirmation modal**
|
||||||
click handler is JS/AJAX-bound (no plain href) and its request is
|
(`#ConfirmationModal` → `#Confirmation_Run`; the same generic modal
|
||||||
almost certainly anti-forgery-token protected, so automation drives
|
is reused for Delete Rule etc., so the confirm click is scoped to
|
||||||
the real page rather than replaying a raw HTTP POST.
|
that specific modal instance). That confirmation step is not
|
||||||
|
optional or cosmetic: confirmed by live testing that skipping it
|
||||||
|
fires **zero** network requests and the rule silently never runs,
|
||||||
|
even though the initial dropdown click "succeeds" with no error —
|
||||||
|
an earlier version of this code did exactly that and every reported
|
||||||
|
"success" was a false positive for a real stretch of production use.
|
||||||
|
If a future site redesign changes this modal, watch for the same
|
||||||
|
symptom: local history says success, MassPrice's own Activity Log
|
||||||
|
never gets a matching entry. **No public API was found or used** —
|
||||||
|
the "Run Rule" click handler is JS/AJAX-bound (no plain href, a
|
||||||
|
delegated jQuery handler on `document.body`, not the element itself)
|
||||||
|
and its request (`POST /Rule/Run`, confirmed by live network capture)
|
||||||
|
is almost certainly anti-forgery-token protected, so automation
|
||||||
|
drives the real page rather than replaying a raw HTTP POST.
|
||||||
- **Session persistence** — a Playwright `storage_state` (cookies +
|
- **Session persistence** — a Playwright `storage_state` (cookies +
|
||||||
localStorage) is saved to `/data/auth_state.json` and reused across
|
localStorage) is saved to `/data/auth_state.json` and reused across
|
||||||
runs: scheduled runs never touch the login form at all, they just load
|
runs: scheduled runs never touch the login form at all, they just load
|
||||||
|
|
|
||||||
2
app.py
2
app.py
|
|
@ -8,7 +8,7 @@ import automation
|
||||||
import scheduler
|
import scheduler
|
||||||
import storage
|
import storage
|
||||||
|
|
||||||
APP_VERSION = "0.5.0"
|
APP_VERSION = "0.6.0"
|
||||||
APP_VERSION_DATE = "2026-09-01"
|
APP_VERSION_DATE = "2026-09-01"
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,21 @@ def run_rule(rule_id, rule_name=None):
|
||||||
run_link = row.first.locator(run_selector)
|
run_link = row.first.locator(run_selector)
|
||||||
run_link.wait_for(state="visible", timeout=5000)
|
run_link.wait_for(state="visible", timeout=5000)
|
||||||
run_link.click()
|
run_link.click()
|
||||||
page.wait_for_timeout(1500) # let the click's AJAX call fire
|
|
||||||
|
# Clicking the dropdown item only opens a confirmation modal
|
||||||
|
# ("You are about to run the rule ... Are you sure?") — it
|
||||||
|
# does not trigger the run itself. Confirmed by live testing:
|
||||||
|
# without this step, zero network requests ever fire and the
|
||||||
|
# rule silently never runs, despite the initial click
|
||||||
|
# "succeeding" with no error. #ConfirmationModal / its
|
||||||
|
# #Confirmation_Run button are used generically across the
|
||||||
|
# site (also for Delete Rule etc.), so scope the confirm
|
||||||
|
# click narrowly to this specific modal instance.
|
||||||
|
modal = page.locator("#ConfirmationModal")
|
||||||
|
modal.wait_for(state="visible", timeout=5000)
|
||||||
|
modal.locator("#Confirmation_Run").click()
|
||||||
|
modal.wait_for(state="hidden", timeout=10000)
|
||||||
|
page.wait_for_timeout(1000) # let the confirmed run's request land
|
||||||
|
|
||||||
status = "success"
|
status = "success"
|
||||||
message = "Run Rule clicked"
|
message = "Run Rule clicked"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue