Skip to content

#560: port arbin_res to the two-stage design#608

Merged
jepegit merged 1 commit into
masterfrom
issue-560-parse-arbin-res
Jul 21, 2026
Merged

#560: port arbin_res to the two-stage design#608
jepegit merged 1 commit into
masterfrom
issue-560-parse-arbin-res

Conversation

@jepegit

@jepegit jepegit commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Part of #560. Off master, not stacked. Overlaps slightly with #607 (pec) — see the note at the end.

What

arbin_res was the tier-1 loader I flagged as awkward: Access .res via ODBC on Windows, mdbtools on posix, multi-test files, aux-table joins. Two facts made it tractable:

  • CI can check it. The loader_arbin_res golden runs green on Linux CI — mdbtools is installed there — so the parity case runs in CI, not only locally. Where no backend exists, the parity test skips gracefully, mirroring the golden's skip_reason.
  • The vendor stage is thin. get_headers_normal() is already a {cellpy attr → Arbin column} map — the same shape the configuration loaders carry — so declarations() reuses derive_column_maps and inherits the provenance rule (Test_ID dropped, not mapped onto the framework test_id) for free. parse() is just the database read via _loader_win/_loader_posix, stopping before the rename and the Excel-serial datetime conversion that harmonize() now owns. It shares loader()'s read path, so the two cannot drift.

Scope

Single test: the golden fixture is single-test with no aux columns, and loader() still handles the multi-test split and aux joins. A multi-test .res — where Test_ID is nonzero and harmonize()'s framework test_id differs from the vendor value — is the switchover's concern. In this fixture Test_ID is 0, so the agreement holds by the file's value, not by construction (noted for the switchover).

Verification

  • Value parity on all 17 shared measurement columns; only date_time excused, as everywhere.
  • Mutation-checked: swapping the charge/discharge vendor names is caught. A column-drop mutation is not caught by this oracle (shared-columns-only) — but the loader_arbin_res golden pins the full column set, so that's layered.
  • tests/test_arbin_two_stage.py pins the decisions and skips without a backend.
  • Full suite under PYTHONUTF8=1: 1241 passed, 0 failed.

Merge-order note

Two small changes here also appear in #607 (pec), because both are the first non-config loaders: the parity oracle reading loader.config_params via getattr, and the per-case backend skip. If #607 merges first, PARITY_CASES conflicts trivially (both append a case) — resolvable in seconds. The getattr line is identical in both and merges cleanly.

🤖 Generated with Claude Code

@cursor

cursor Bot commented Jul 21, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

…ODBC on

Windows, mdbtools on posix. Two facts made it tractable:

- CI can check it. The arbin golden runs green on Linux CI (mdbtools is
  installed), so the parity case runs there, not only locally. Where no backend
  exists the parity test skips gracefully, mirroring the golden's skip_reason.
- The vendor stage is thin. get_headers_normal() is already a
  {cellpy attr -> Arbin column} map - the same shape the config loaders carry -
  so declarations() reuses derive_column_maps and gets the provenance rule
  (Test_ID dropped, not mapped onto the framework test_id) for free. parse() is
  just the database read via _loader_win/_loader_posix, stopping before the
  rename and the Excel-serial datetime conversion that harmonize() now owns. It
  shares loader()'s read path, so the two cannot drift.

Scoped to a single test: the golden fixture is single-test, no aux columns, and
loader() still handles the multi-test split and aux joins. A multi-test .res -
where Test_ID is nonzero and harmonize()'s framework test_id would differ from
the vendor value - is the switchover's concern. In this fixture Test_ID is 0, so
the stamped test_id agrees; that agreement is a value coincidence, not a
guarantee for multi-test files (noted for the switchover).

Value parity holds on all 17 shared measurement columns; only date_time is
excused. Mutation-checked: swapping the charge/discharge vendor names is caught
(both capacities flag). A column-drop mutation is NOT caught by this oracle
(shared-columns-only), but the loader_arbin_res golden pins the full column set -
layered coverage.

tests/test_arbin_two_stage.py pins the decisions and skips without a backend.
Full suite under PYTHONUTF8=1: 1241 passed, 0 failed.

Also carried here (needed for any non-config loader, first used by pec): the
parity oracle reads loader.config_params via getattr so loaders without one work,
and skips a case whose backend is unavailable.

Loader plan §2.6b updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jepegit
jepegit force-pushed the issue-560-parse-arbin-res branch from 439d5f4 to bd7603a Compare July 21, 2026 08:28
@jepegit
jepegit merged commit f7c4e38 into master Jul 21, 2026
4 checks passed
@jepegit
jepegit deleted the issue-560-parse-arbin-res branch July 21, 2026 09:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant