VV: Compute Feature Phases Full V&V#1672
Conversation
f0eb230 to
09d3d7a
Compare
There was a problem hiding this comment.
V&V Adversarial Review — ComputeFeaturePhasesFilter
Full adversarial review of the code, tests, and the three vv/ deliverables, plus an independent re-run of the legacy A/B comparison (the committed deviations table was treated as a claim to falsify, not as evidence). Verdict at the bottom.
Independent verification results (all pass)
- ✅ All 9
ComputeFeaturePhasesFiltertests pass on the in-core build (macOS ARM, Release) - ✅ All 9 tests pass on the out-of-core build
- ✅ Error codes verified against source:
-5351/-5355(DataArrayUtilities.cpp:184-195),-61860/-61861(algorithm); both new codes are unique in the codebase - ✅ D1's "always 0" premise verified:
CreateArrayAction→CoreDataIOManagerconstructsInt32DataStorewithinitValue = 0, so the never-written index 0 (and any gap features) are deterministically zero - ✅ Core loop semantics verified identical to 6.5.171
FindFeaturePhases::execute()forfeaturePhases[1..N]: conflict detection against the first phase seen per feature, last-cell-wins assignment
A/B re-run (fresh evidence, not a re-read of the deviations table)
Legacy-native inputs for Cases A/B/C were minted fresh and run through the DREAM3D 6.5.171 PipelineRunner (FindFeaturePhases) and this branch's nxrunner (ComputeFeaturePhasesFilter):
| Case | 6.5.171 FeaturePhases |
SIMPLNX FeaturePhases |
[1..N] |
index 0 |
|---|---|---|---|---|
| A | [0, 1, 1, 2, 2] |
[0, 1, 1, 2, 2] |
bit-identical | equal |
| B | [0, 2, 1, 2, 2] |
[0, 2, 1, 2, 2] |
bit-identical | equal |
| C | [2, 1, 2, 1] |
[0, 1, 2, 1] |
bit-identical | 6.5.171 = 2, SIMPLNX = 0 → D1 confirmed |
The deviations file's 2026-07-10 comparison table is reproduced exactly. A/B testing claim: validated.
Blocking — factual errors in the V&V deliverables
- D4 mischaracterizes 6.5.171.
vv/deviations/…D4states: "SIMPL: Single generic message with no feature ID list." The 6.5.171 source (FindFeaturePhases.cpp, warning block) emits one line per conflicting feature:"Phase Feature <id> created <N> warnings."— it lists feature IDs and per-feature conflict counts. Confirmed empirically: the Case B legacy run printedPhase Feature 1 created 1 warnings.Rewrite D4 as: SIMPLNX consolidates into a single warning, truncates at 15 IDs, and drops the per-feature conflict counts (also note: 6.5.171 can warn for feature 0; SIMPLNX never does). - D3 mischaracterizes 6.5.171. The entry states: "SIMPL: No check; mismatch would result in an out-of-bounds read." 6.5.171
dataCheck()callsvalidateNumberOfTuples()overFeatureIds+CellPhasesand errors out at preflight time. The real deviation is when (preflight vs. execute) and the error code — not the presence of the guard. Rewrite accordingly. - Wrong branch attribution. Deviations header says the hardening landed on "branch
vv/fill_bad_data, 2026-07-10". It landed in this PR's commit 47f04a1 onvv/compute_feature_phases. Also resolve the internal contradiction: the header says "All four deviations were introduced in post-Phase-9 algorithm cleanup" while D4's body says "Introduced at port time (PR #1455)". - "Open items: None" is false.
vv/provenance/…records "Second-engineer oracle review: Not yet conducted." Either conduct it (the file itself argues it is a <5-minute derivation) or list it as an open item in the report's At-a-glance table. - Cancel-path wording. Report path 3 says cancel is "Not tested (cancel-signal injection not supported)". Per project V&V convention the cancel path is intentionally untested (meaningful mid-flight cancellation would require a second thread, and the mechanism is known-working); reword the report to say that rather than "not supported" —
IFilter::executedoes accept ashouldCancelflag (IFilter.hpp:233), so "not supported" is not the accurate rationale. No test required. - Test-count inconsistency. Summary and Oracle sections say "7 inline" tests; At-a-glance and provenance say 8. There are 8 new
TEST_CASEs (Cases 1–8). Fix the "7"s. - Exemplar-archive claim is stale. Report says
6_6_stats_test_v2.tar.gzis still "Use[d] for …SIMPL Backwards Compatibilitytest". That test reads localtest/simpl_conversion/*.jsonfixtures — after retiring(Valid Parameters), no test of this filter touches the archive (it stays intest/CMakeLists.txtfor other filters). Correct the report and provenance rows. - Cross-doc test-name drift. Deviations refer to "
Background Feature Skip", "Inconsistent Phase Warning", "Warning Truncation"; actualTEST_CASEnames areValid: Feature 0 Skip,Valid: Mixed Phase Warning,Valid: Truncated Mixed Feature Warning. Align the names. -
Verified commit: pending— fill in before merge.
Algorithm — correctness-adjacent
- Negative phase on background cells is not caught. The
-61861guard (ComputeFeaturePhases.cpp:63) runs after thefeatureId == 0skip (line 56), socellPhases = -5on a background cell passes silently. The new docs paragraph ("halts with an error if any cell phase value is negative") overstates. Either move the check above the skip, or scope the docs/D2 text to "cells belonging to a valid feature (featureId > 0)". - Size-mismatch check belongs in preflight. Tuple counts are static metadata; checking
featureIdsvs.cellPhasesinpreflightImplrestores parity with 6.5.171 (which fails this atdataChecktime) and gives users the error before execution. Keep the execute-time guard if desired, but preflight should catch it first.
Senior-engineer nits (code)
-
ComputeFeaturePhases.cpp:83—warnStris built unconditionally even when there are no conflicts; construct it inside thecount != 0branch. - Lines 90/104 — magic number
15appears twice; hoistconstexpr usize k_MaxListedFeatures = 15;. - Line 107 — "and N more occurrence(s)": the count is of features, not occurrences; "and N more feature(s)" is accurate. Also "Affected Phase Features:" reads oddly — "Affected Feature IDs:" is clearer. (Warning text only; Case 3/4 assertions must be updated in lockstep.)
- Lines 68–78 —
initialFeaturePhase[featureId]indexes with a rawint32while line 78 usesstatic_cast<usize>(featureId); make them consistent.storedPhaseIdcan beconst. - Line 30 comment — the validator enforces non-negative feature ids (0 is allowed and then skipped), not "all positive".
- No progress messaging in the per-cell loop, and
m_ShouldCancelis loaded every iteration; on large volumes the filter is silent. Consider theThrottledMessenger/MessageHelperpattern. Optional follow-on: track last-seen phase in the local vector and bulk-writefeaturePhasesonce after the loop — removes the per-cellsetValueinto the store entirely (also friendlier to OOC stores).
Senior-engineer nits (tests)
- Validation-section
getDataRefAs<Int32Array>()calls (Cases 1, 2, 3) are not wrapped inREQUIRE_NOTHROW()— project testing convention requires it for everygetDataRefAs. - Error tests (Cases 5–8) omit
UnitTest::CheckArraysInheritTupleDims(dataStructure);— convention says everyTEST_CASE. - New
TEST_CASEs omitUnitTest::LoadPlugins(). Harmless here (filters are constructed directly), but inconsistent with the suite convention — confirm intentional or add it. - Case 3's assertion
warnMsg.find("Features: 1")is brittle against message rewording (see warning-text nit above); prefer asserting the exact ID list segment after any text change. - Case 4 asserts the truncation suffix but not that exactly 15 IDs are listed — cheap to add (
"1, 2, …, 15"substring or count commas). - Suggested additional cases: (a) cancel path (see blocking item), (b) gap feature — a feature index with no cells stays
0(currently untested; documents the zero-init contract D1 relies on), (c) negative phase on a background cell (locks in whichever resolution is chosen for the docs/behavior gap above).
Suggested surgical patch — DREAM3D 6.5.171 (root-cause proof only)
D1 is the only deviation that changes an output array, and the only patch worth minting. Applied to a local build of the legacy source (proof tooling, not a shipping fix — feature 0 is invalid by convention, so the 6.5.171 output is not demonstrably wrong):
// FindFeaturePhases::execute(), inside the per-cell loop
gnum = m_FeatureIds[i];
if(gnum == 0) // match SIMPLNX: background cells do not contribute a phase
{
continue;
}Expected proof: Case C FeaturePhases[0] becomes 0, and the A/B diff goes to zero across all three cases. D2/D3/D4 are error/warning-path only — no output arrays to reconcile, no patches warranted.
Verdict
Algorithm is a faithful port with sensible hardening; featurePhases[1..N] is independently confirmed bit-identical to 6.5.171 across all three deviation-file cases, and D1 reproduces exactly as documented. The blocking list is entirely documentation accuracy in the vv/ deliverables (two deviations mischaracterize the legacy behavior, plus internal contradictions) and one wrong testability claim. Fix those, decide the background-negative-phase question, and this is ready to sign off.
- edge case hardening - new test cases - V&V FIles
- Added test case
09d3d7a to
903ebbf
Compare
Naming Conventions
Naming of variables should descriptive where needed. Loop Control Variables can use
iif warranted. Most of these conventions are enforced through the clang-tidy and clang-format configuration files. See the filesimplnx/docs/Code_Style_Guide.mdfor a more in depth explanation.Filter Checklist
The help file
simplnx/docs/Porting_Filters.mdhas documentation to help you port or write new filters. At the top is a nice checklist of items that should be noted when porting a filter.Unit Testing
The idea of unit testing is to test the filter for proper execution and error handling. How many variations on a unit test each filter needs is entirely dependent on what the filter is doing. Generally, the variations can fall into a few categories:
Code Cleanup