Differential testing harness comparing CBDB Avalonia desktop queries against the CBDB Access automated test results, ensuring both stacks return identical results when fed from the same Datadump.
Scope contract (see
WORK_PLAN.md §0):§0.a — No upstream modifications. This repository is a detection / parity test harness. It surfaces and documents Avalonia ↔ Access disagreements via
reports/known_issues.md; it MUST NOT modify the upstream Avalonia codebase (cbdb-desktop-app) or any other repository. The right action chain is: (1) write/run the parity test, (2) record the divergence inreports/known_issues.mdwith aSuppress until …clause, (3) let the test skip gracefully until upstream patches.§0.b — No transcription. This repo never re-implements upstream logic in Python. Avalonia-side tests call
cbdb-desktop-app's real services throughCbdb.App.ParityHost; Access-side tests callcbdb-user-mdb-tests'scbdb_replay.lookat*modules directly. Hand-extracted SQL or hand-ported state machines on either side are forbidden.
For every query feature implemented in the CBDB Avalonia desktop app, this harness:
- Builds an Access stack (generated
cbdb_data.mdb+ fixedCBDB_BJ_User.mdb) and an Avalonia SQLite database from the same Datadump, so any difference observed is logic, not data. - Runs the equivalent query against both stacks.
- Normalises and diffs the two result sets.
- Records each Access ↔ Avalonia disagreement together with a root cause.
The harness reuses the differential-testing pattern pioneered in cbdb-user-mdb-tests.
┌───────────────────────────┐
│ Datadump (latest .tar.gz)│
└────────────┬──────────────┘
│
┌──────────┴───────────┐
│ │
▼ ▼
┌───────────────────┐ ┌─────────────────────┐
│ build_mdb (py) │ │ build_sqlite (py) │
│ Datadump → mdb │ │ Datadump → sqlite │
│ (MariaDB cache) │ │ (MariaDB cache) │
└─────────┬─────────┘ └──────────┬──────────┘
│ │
▼ ▼
┌───────────────────┐ ┌─────────────────────┐
│ cbdb_data.mdb │ │ cbdb.sqlite │
└─────────┬─────────┘ └──────────┬──────────┘
│ │
▼ ▼
┌───────────────────┐ ┌─────────────────────┐
│ cbdb_replay. │ │ Cbdb.App.ParityHost │
│ lookat* (Python │ │ (.NET console → │
│ bridge via │ │ upstream services │
│ pyodbc + sys.path)│ │ via ProjectRef) │
└─────────┬─────────┘ └──────────┬──────────┘
│ │
└──────────┬─────────────┘
▼
┌─────────────────────┐
│ Differential diff │
│ reports/<query_id> │
└─────────────────────┘
Both arms call upstream code directly per WORK_PLAN.md §0.b:
the Avalonia arm invokes cbdb-desktop-app's real
Sqlite*QueryService / SqlitePersonBrowserService via the
ParityHost console (Phase 5); the Access arm invokes
cbdb-user-mdb-tests's VBA-historical cbdb_replay.lookat*
scripts via Python (Phase 3c/3d/3e + Phase 6a).
Phases 1–9 landed (2026-05-27 → 2026-05-30). Current suite:
387 passed, 7 skipped, 1 xfailed. Implementation is tracked
phase-by-phase in WORK_PLAN.md (English) and
WORK_PLAN.zh-CN.md (Chinese, authoritative for project
decisions made in Chinese). Both WORK_PLAN.md §9 and
WORK_PLAN.zh-CN.md §9 carry a Post-Phase-9 status block
enumerating the active suppressions and their re-arm
conditions.
ParityHost runs in two modes (Phase 7h + Phase 8a binding):
one-shot via dotnet run for ad-hoc callers, and a
long-lived NDJSON daemon that the
parity_host_daemon pytest fixture binds for the whole
session — the host-using subset of the suite drops from
~150s to ~61s under the binding.
§0.b-compliant cross-engine pair tests at HEAD:
- Tier 1:
entry,office,status(each viacbdb_replay.lookat*). - Tier 2:
kinships(1-hop direct branch viacbdb_replay.lookatkinship; Phase 6a rewire).
Avalonia-side correctness for every other PersonBrowser surface is
gated by tests/test_phase5c_person_mirror_vs_host.py, which calls
the real upstream service through the ParityHost. See
reports/known_issues.md for the surfaces (12 + associations) that
have no §0.b-compliant Access oracle.
# 1. Configure local paths
Copy-Item .env.sample .env
# edit .env with the real paths on your machine
# 2. Install (uv-managed venv recommended; the [access] extra
# pulls in pypyodbc + pywinauto + pyodbc; the first two are
# Windows-only, the third is cross-platform but binds to the
# Windows-only Access ODBC/ACE driver in this codebase)
uv venv --python 3.12 .venv
uv pip install --python .venv/Scripts/python.exe -e ".[dev,harness,access]"
# 3. Build both databases from the latest Datadump.
# `build-all` refreshes the four external repos, picks the newest
# cbdb_data_YYYYMMDD.tar.gz, then writes cbdb.sqlite AND cbdb_data.mdb
# to .env's BUILD_OUTPUT_DIR. SHA-anchored — re-runs are cached.
cbdb-parity-build-all
# or, individual sub-builders:
# cbdb-parity-build-sqlite
# cbdb-parity-build-mdb
# 4. Run the differential harness. Per-query reports under reports/.
# The entry-pair smoke test requires both DBs to be present AND
# anchored to the same Datadump SHA per build_manifest.json
# (the strict-pipeline rule from WORK_PLAN §1); it skips cleanly
# otherwise.
pytest tests/The pre-flight cbdb-parity-refresh is still callable on its own if you
just want to git pull --ff-only the four external repos without
building anything.
After a parity run, regenerate the top-level dashboard with:
cbdb-parity-summary # writes reports/SUMMARY.md from cwd
# or
cbdb-parity-summary --reports-dir <path>reports/known_issues.md is hand-maintained and is not regenerated.
| Key | What it is |
|---|---|
DATADUMP_DIR |
Folder of cbdb_data_YYYYMMDD.tar.gz archives. Latest is picked automatically. |
CBDB_USER_MDB |
Fixed path to CBDB_BJ_User.mdb (Access UI front-end). |
ACCESS_TESTS_REPO |
Local clone of cbdb-user-mdb-tests. |
AVALONIA_REPO |
Local clone of cbdb-desktop-app. |
ONLINE_SERVER_REPO |
Local clone of cbdb-online-main-server. |
MYSQL2ACCESS_DIR |
Local mysql2access working folder (Datadump → Access port). |
ACCESS_MYSQL_TRANSFER_REPO |
Local clone of accessAndMySQLTransfer. |
BUILD_OUTPUT_DIR |
Scratch folder for generated cbdb_data.mdb and cbdb.sqlite (gitignored). |
cbdb-parity-build-all defaults to importing the Datadump
into a Docker MariaDB container and reading from there into
both builders. Eight env keys configure that:
| Key | What it is |
|---|---|
MARIADB_HOST |
Hostname of the MariaDB instance (default localhost). |
MARIADB_PORT |
Port (default 3306). |
MARIADB_USER |
User with CREATE / DROP / INSERT on MARIADB_DATABASE. |
MARIADB_PASSWORD |
Password. Required; fail-loud if absent. |
MARIADB_DATABASE |
Database name the Datadump imports into. |
MARIADB_CONTAINER_NAME |
Informational; used only when auto-launch is on. |
MARIADB_FORCE_REIMPORT |
1 = drop and reimport even when the in-DB SHA matches; 0 = trust the cache. |
MARIADB_AUTO_LAUNCH |
1 = docker start <CONTAINER_NAME> if the container is found stopped; 0 = require the user to bring it up. |
The MariaDB cache is part of OUR pipeline; it does NOT relax
the "never substitute pre-existing user mdb files" rule from
WORK_PLAN §1 — we populate the cache from the Datadump
ourselves, gated by an in-DB SHA provenance row. The pre-1.6
direct path (source='datadump') is retained as a fallback for
non-Docker hosts.
.env.sample is committed with placeholder values; .env is gitignored.
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
(CC BY-NC-SA 4.0). See LICENSE.