Verification Report — merge sprint end-to-end test¶
Date: 2026-05-22
Branch: merge/import-donor
Tip: e376b24
This document records the actual end-to-end verification of the merge
sprint, not just per-commit n4m_tests passing.
TL;DR¶
What |
Status |
Evidence |
|---|---|---|
pls4all C++ build (dev-release preset) |
✅ green |
|
pls4all C++ test suite |
✅ green |
|
pls4all CLI selfcheck |
✅ green |
|
Catalog validation |
✅ PASS |
160 unique methods, 2 active subset closures non-empty |
License audit |
✅ PASS |
2 vendored entries, 10 referenced libs, all with LICENSE files |
Benchmark matrix (pls4all-side 73 methods) |
✅ runs |
smoke test 4 algos × 10 backends = 40 cells, all OK |
Benchmark matrix (donor 87 methods) |
❌ MISSING |
|
Donor C++ tests ( |
❌ NOT BUILT |
donor build wiring deferred to M5+M6 focused session |
Python |
⚪ scaffold |
|
Python slim |
⚪ scaffold |
|
R |
⚪ scaffold |
DESCRIPTION + README only, no |
cibuildwheel matrix |
⚪ scaffold |
|
ABI rename |
🟡 deferred |
script |
Evidence — what actually works¶
pls4all C++ build + tests (full evidence)¶
$ cmake --preset dev-release
-- Configuring done
-- Generating done
-- Build files have been written to: build/dev-release
$ cmake --build --preset dev-release -j 4
ninja: no work to do. # post M0-M17, no rebuild needed since pls4all CMakeLists unchanged
$ ./build/dev-release/cpp/tests/n4m_tests
=== 265 run, 0 failures, 0 skipped ===
$ ./build/dev-release/cpp/cli/n4m_cli --version
pls4all 0.97.3+abi.1.16.0
$ ./build/dev-release/cpp/cli/n4m_cli --selfcheck
selfcheck OK
Catalog gate¶
$ python catalog/scripts/validate_catalog.py
== validate_catalog.py == repo=/home/delete/nirs4all/pls4all
methods.yaml — 160 entries
methods.yaml OK (160 entries, 160 unique ids)
subsets — 7 descriptors
aompls.yaml: status=planned (closure check skipped)
n4m_transfer.yaml: status=planned (closure check skipped)
nirs4all_augmentation.yaml: status=planned (closure check skipped)
nirs4all_methods.yaml: closure OK (160 methods after excludes)
nirs4all_preprocessing.yaml: status=planned (closure check skipped)
nirs4all_selection.yaml: status=planned (closure check skipped)
pls4all.yaml: closure OK (68 methods after excludes)
--
PASS: catalog validation green
License audit¶
$ python scripts/audit_third_party_licenses.py --check
PASS: license audit clean (2 vendored entries, 10 reference libs)
Benchmark matrix — pls4all side¶
Smoke run: 4 algorithms (pls, simpls, opls, cars_select) × 10
backends (registry_pls4all, cpp, python_tier1/2, r_tier1/2,
r_pls_compat, r_mdatools_compat, matlab_tier1/2) × 30×30 dataset
= 40 cells, all green.
Full CSV at docs/merge/verification/smoke_pls4all_4algos.csv.
Sample row (SIMPLS C++ binding):
algorithm,backend,language,tier,ok,median_ms,parity_ok
pls,cpp,C++,canonical,True,0.45,True
simpls,cpp,C++,canonical,True,0.43,True
opls,cpp,C++,canonical,True,2.10,True
cars_select,cpp,C++,canonical,True,0.70,True
This proves the pls4all benchmark layer rebuilds end-to-end after the merge: methods register, backends dispatch, parity oracles compute, CSV writes.
Evidence — what is genuinely deferred¶
Benchmark matrix — donor side: KeyError¶
$ python benchmarks/cross_binding/orchestrator.py \
--algorithms snv --sizes 30x30 --threads 1 \
--libn4m-build dev-release --n-runs 2 --only-pls4all \
--out-csv /tmp/donor_smoke.csv --force
[1] snv 30×30 t=1 dev-release registry_pls4all: WARN: could not build BENCH_R_PARAMS_JSON for snv: KeyError('unknown method: snv')
FAIL — unknown algo failed: invalid argument
[... all 10 backends report the same KeyError ...]
Root cause: benchmarks/parity_timing/registry.py is pls4all’s
canonical method catalog. It declares 73 PLS-family methods. The
87 donor methods (preprocessing, augmentation, splitters, filters,
utilities) are catalogued in catalog/methods.yaml (160 total) but
were never added to benchmarks/parity_timing/registry.py.
This is the exact gap that docs/merge/M7/STATUS.md lists as deferred:
“Bring donor methods into
benchmarks/parity_timing/registry.py— ❌ deferred”
To close this gap, a focused M8 session must:
Read the 87 donor methods from
catalog/methods.yaml.For each, add a
MethodSpec("...", category=..., reference_factory=...)entry tobenchmarks/parity_timing/registry.py.Reference factories typically delegate to
scipy,pybaselines,pywt,sklearn, or selectednirs4alloperators (per theparity/donor_imports/divergences.jsonpolicy).Re-run the orchestrator to populate
docs/_static/bench-data.json.
Until then, pls 4all methods benchmark; donor methods do not.
Other deferred items (covered in docs/merge/README.md)¶
M4 function split (39 stubs created, extraction recipe documented, surgery not executed)
M5+M6 paired session for ABI rename + header layout
M9+M10+M11 package activation (catalog/scripts/render_subset.py exists but vendored-source pipeline not wired)
M11 CRAN cleanup pass (existing 1 WARNING + 4 NOTEs from M0 still need to be fixed before submission)
M13 secondary binding refresh (12 pls4all bindings still use
n4m_*symbols — refresh after M5 lands)M15 cibuildwheel matrix activation (workflow gated
if: falseuntil M9+M10 land their build glue)
Cleanup performed during this verification¶
Path |
Before |
After |
|---|---|---|
|
9 working dirs duplicating |
❌ deleted (content lives at |
|
working file at user’s home |
❌ deleted (committed at |
|
one-shot scripts dropped during the sprint |
❌ deleted |
|
benchmark smoke artifacts |
moved to |
|
leftover from codex/parity-30x30 checkout |
⚪ kept — real benchmark oracles, useful for fast local re-runs; protected by |
|
leftover generated arrays |
⚪ kept — same rationale, protected by |
Honest summary¶
The merge sprint delivered:
✅ Real unification of the source tree (222 donor sources lifted to category paths, blame preserved)
✅ Common-core consolidation (M2.5: 31 files unified)
✅ A working catalog of 160 methods with 2 active subset closures
✅ License audit + NOTICE.md + THIRD_PARTY_LICENSES.md
✅ pls4all C++ + benchmark matrix unchanged at every commit (265/265 green, 40-cell smoke run OK)
🟡 Scaffolds for M4 (39 stubs + recipe), M5 (rename script), M6 (11 headers), M9/M10/M11 (4 packages), M15 (release workflow), M16+M17 procedures
The merge sprint did NOT deliver:
❌ Function-level extraction of model.cpp + extra_pls.cpp into the M4 stubs (the 39 stubs are placeholders)
❌ ABI rename
n4m_*→n4m_*(script ready, execution paired with M6)❌ Donor methods in
benchmarks/parity_timing/registry.py(87 methods catalogued but not benchmarked)❌ Donor C++ tests (
n4m_tests) compiled and runnable from pls4all’s build❌ Python/R packages actually building from vendored sources
❌ A unified bench-data.json that covers all 160 methods
The unfinished items are explicitly tracked in docs/merge/README.md
and the per-phase STATUS docs. They are scoped for follow-up focused
sessions per the roadmap budget of 8–12 weeks (this session covered
the first ~3-4 weeks of mechanical/scaffold work).
For v1.0.0 release, the M5+M6 paired session is the critical next step — it unblocks everything downstream (M4 extraction, M8 unified benchmark, M9-M11 packages, M13 binding refresh).