Update README tree (compare.py + domain.py), CLAUDE.md module refs, and the three docs/ deep-dives to the current inbound_verify package (compare/domain/sites/cli). Correct the statistics review report's methodology to the current 口径 (应到=交接件数, 实到=直接数单号去重, 未到=应到−实到) per compare.py docstring; remove ghost-script references in the CDP guide.
Co-Authored-By: Claude <noreply@anthropic.com>
Third launch failure this session (after two 顺心 load-timeouts and a 中通 ERR_NAME_NOT_RESOLVED) — each a transient network blip that killed the whole worker because launch_and_prepare opened sites with no retry. Wrap each site open+goto in _open_page: up to 3 attempts (2s apart) on domcontentloaded, so transient DNS/timeout is absorbed; only persistent failure (all 3) aborts. All 5 sites + 安能 now launch clean.
Co-Authored-By: Claude <noreply@anthropic.com>
launch_and_prepare opened each site with Playwright's default wait_until='load', which waits for every resource (ads/trackers/images). sxne.sxjdfreight.com (顺心) reliably takes >30s to fire load, so its goto timed out and — launch not being retried — killed the whole worker, leaving only one page open. Switch the two launch gotos to wait_until='domcontentloaded' (return as soon as the DOM is ready; the readiness polling still gates login). Behavior for already-fast sites unchanged.
Co-Authored-By: Claude <noreply@anthropic.com>
git mv expected_undelivered.py -> compare.py; update the 3 importers (store/runtime/router) to import compare. All public names (main, write_site_file, _read_business_dates) unchanged. Also add the Tier 2 plan doc.
Co-Authored-By: Claude <noreply@anthropic.com>
Move ALL_REPORT_SITES / SITE_UNDELIVERED_FILE / BAISHI_FILE / BAISHI_COLUMNS / arrived_pieces_* / STATIONS / _site_cfg out of expected_undelivered into a new leaf module inbound_verify/domain.py. store.py and runtime.py now read site/file config from domain directly instead of through the compare engine (store keeps eu only for _read_business_dates). Behavior identical.
Co-Authored-By: Claude <noreply@anthropic.com>
Remove the duplicate BASE/DOWNLOADS/OUTPUT self-anchor (the one that caused the Tier 1 hotfix bug when the file moved into the package). DOWNLOADS/OUTPUT now come from paths.py; OUTFILE derives from OUTPUT_DIR. Behavior identical.
Co-Authored-By: Claude <noreply@anthropic.com>
Tier 1 regression: expected_undelivered.py carries its own BASE=dirname(__file__) anchor (a duplicate of paths.py). The package move dropped the file one level deeper, so BASE resolved to inbound_verify/ and DOWNLOADS/OUTPUT pointed at non-existent inbound_verify/downloads|output — while site downloads write to the project-root dirs via paths.py. process()/write_site_file() thus skipped the compare with '[跳过] downloads 下缺少 ...', returned None/False, and every undelivered task for the 4 web/app sites reported failed (重试耗尽) despite the files downloading fine. Fix: anchor BASE two levels up (mirrors paths.py). Verified: write_site_file returns True; all 4 undelivered tasks now success with 未到 files generated.
Co-Authored-By: Claude <noreply@anthropic.com>
Replace pre-rename references (main_router, db_store, server.py) in code comments and docstrings with their new locations (cli/router, store, cli/server, runtime). Comment-only; no behavior change.
Co-Authored-By: Claude <noreply@anthropic.com>
Rewrite run commands to python -m inbound_verify.* (and console_script aliases); add pip install -e . to env prep; refresh the directory tree. Also commit the design spec and Tier 1 implementation plan under docs/superpowers/.
Co-Authored-By: Claude <noreply@anthropic.com>
Relocate 12 root .py modules into inbound_verify/ (sites/, cli/ subpackages). Rewrite all internal imports to package-qualified; drop the site_ prefix on the 5 site modules and their 28 call sites. Fix paths.py BASE_DIR to anchor at the project root. Add main() entry wrappers (cli/router, cli/server, store). No behavior change.
Co-Authored-By: Claude <noreply@anthropic.com>
Empty package markers (inbound_verify/, sites/, cli/) plus pyproject.toml with console_scripts entry points and dependency floors.
Co-Authored-By: Claude <noreply@anthropic.com>
- Add a two-layer reset engine to the export dialog (both expected and
actual arrival): an outer 3x reopen loop with a field-list presence
check (交接单号 / 扫描类型 as per-page anchor), and an inner 4x
submit loop that distinguishes a missed field (re-click 全选) from a
vanished field list (reopen the whole dialog), recovering from
empty/ghost-cleared export dialogs
- Keep log/comment wording plain and factual (no hyperbole)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add _close_tab(page, tab_name) for Baishi's tab close affordance
(li>span text + i[title='关闭标签页']), matching the other sites
- Close the 扫描综合查询 tab both on the empty-data early return and
after a successful download; return True on completion
Co-Authored-By: Claude <noreply@anthropic.com>
- site_shunxin: replace the hardcoded 1天 radio with config-driven
shunxin.query_days, set the date range via the ant-picker, and add a
two-pass query/retry to clear stale "暂无数据" DOM state; return True
on completion
- config.example.yaml: add the shunxin section (query_days) so the
example matches what the code reads
Co-Authored-By: Claude <noreply@anthropic.com>
- config.example.yaml: add the yunda section (username/password for
auto-login, query_days) and list 韵达 as a valid debug target_site
- Delete main_task.py: early single-site (顺心-only) prototype whose
every function is superseded by main_router.py + site_shunxin.py;
nothing imports it, and it predates paths.py / multi-site / the
automation test
Co-Authored-By: Claude <noreply@anthropic.com>
- main_router: add run_automation_test that runs each site's download
flows in a cross sequence (expected/actual) plus a pass/fail report
with timings; expose it as menu [8]
- Site download functions now return False on their exception paths so
the test harness can record failures (baishi also flags config-read
failure)
- Replace overblown log/comment phrasing across all modules with plain
statements; trim docstrings
Co-Authored-By: Claude <noreply@anthropic.com>
- Add paths.py: BASE_DIR/DOWNLOAD_DIR/CONFIG_PATH anchored on __file__
so paths resolve regardless of the launch cwd
- Route main_router and all site modules through DOWNLOAD_DIR/CONFIG_PATH,
replacing os.getcwd()-based download dirs and the "config.yaml" literal
- main_router compare engine: read Excel as str with keep_default_na,
strip/normalize 运单号, drop blanks, and isin against a set so
int/float-vs-str mismatches no longer produce false "undelivered"
- Shunxin: give downloaded files unique microsecond temp names and read
Excel as str to preserve long-waybill precision
- Normalize bare except: to except Exception: across affected files
Co-Authored-By: Claude <noreply@anthropic.com>
- Add _close_tab(page, tab_name) for closing Ant Design Tabs by label
- Close 运单列表 / 车辆点到 in the expected-arrival flow after export
submission, and 数据导出 after download/merge
- Close 卸车扫描记录 and 数据导出 likewise in the actual-arrival flow
- Renumber step comments
Co-Authored-By: Claude <noreply@anthropic.com>
- Add yunda_login: probe the login page, fill credentials from
config.yaml (yunda.username/password), submit; no-op if already
logged in
- main_router: register per-site READY_SELECTORS and replace the
blocking input() with a ready-guard poll loop; invoke Yunda
auto-login up front; simplify site-init cleanup
- site_yunda: drop the custom frame probes in favor of native
frame_locator("section iframe")
- Skip handover rows already marked 已绑定; abort the export harvest
when no tasks were submitted
- Fix NameError from undefined username/password fallback
Co-Authored-By: Claude <noreply@anthropic.com>
- Rewrite yunda_smart_menu_click to check each parent submenu's
is-opened state before clicking (skip if already open), using XPath
parent-child isolation to avoid collapsing accordion menus
- Scope the expected/actual-arrival loading mask, #sum panel, and
empty-record hint to #tab-1 and add .first to fix Playwright Strict
Mode (5 elements found) leaks across multiple open tabs
- Move _yunda_poll_and_download_tasks above yunda_actual_download for
definition order
Co-Authored-By: Claude <noreply@anthropic.com>
- Implement yunda_actual_download via the 报表管理 -> 扫描记录查询
menu: set date range, switch scan type to 到件, then reuse the
shared poll/download/merge engine
- Add a three-stage query buffer (yield, wait for the Bootstrap Table
loading mask, settle) before the data/empty verdict to avoid stale
DOM reads in the expected-arrival flow
- Trim the offline-export retry state machine's verbose logs
- Fix a typo (研编 -> 研判) and drop the 待开发 tag on menu [7]
Co-Authored-By: Claude <noreply@anthropic.com>
- Add site_yunda.py: Yunda expected-arrival download (进站交接单查询)
with Layui date-range setup, row double-click export, a retry state
machine for the offline-export dialog, and a shared poll/download/
merge engine; actual-arrival is a placeholder
- Wire Yunda into main_router: site URL, login detection, menu items,
and read yunda.query_days from config.yaml
- Rework the hub menu: drop the standalone Shunxin local-compare entry,
renumber modules (百世 3, 中通 4/5, 韵达 6/7), keep global compare [9]
- Streamline site-init cleanup and log wording
Co-Authored-By: Claude <noreply@anthropic.com>
- Poll #inEwbCount until it updates before reading the result, then
branch on zero-count (confirm empty-data area vs missing flag)
- Wait for real grid rows to render in the expected-arrival flow
- Close the active site tab (进站交接单查询 / 到件扫描监控 / 导出任务管理)
after each stage completes to reset the page state
- Tighten export-task time-match window from 60s to 20s
- Trim verbose log messages and stale comments
Co-Authored-By: Claude <noreply@anthropic.com>