Skip to content

[did2 #3] Flip NDI_DID2_NORMALIZE_ON_READ — always normalise on read#803

Open
stevevanhooser wants to merge 10 commits into
Vnextfrom
claude/776-flip-did2-normalize-gate
Open

[did2 #3] Flip NDI_DID2_NORMALIZE_ON_READ — always normalise on read#803
stevevanhooser wants to merge 10 commits into
Vnextfrom
claude/776-flip-did2-normalize-gate

Conversation

@stevevanhooser
Copy link
Copy Markdown
Contributor

Closes #776.

Summary

Flips the NDI_DID2_NORMALIZE_ON_READ gate ON unconditionally and removes the env-var plumbing. The compat layer is now demonstrably sufficient to support flipping the gate — proven by the symmetry test suite on PR #802 going green after the #801 follow-up work.

Compat layer coverage (now in place on Vnext)

Issue What it provides
#779 Read-time augmentation (ndi.compat.augmentRead) for legacy field paths
#780 Write-time reconciliation (ndi.compat.reconcileWrite)
#781 Query path translation (ndi.compat.translateQueryPaths)
#801 (PR #802) depends_on entry-key compat via ndi.document accessors + normalizeDependsOn, plus daqmetadatareader.reader_class alias row, daqreader_ndr reconstruction override, and a sweep of every direct .value read in src/ndi/
did-matlab #137/#138/#139 Tolerant did.document accessors, validator field-set + subfield V_alpha↔V_delta reverse lookup, doc2sql tolerant read

Cleanup performed (per #779 comment 4493101768)

  1. Delete the gate. Removed normalizationGateOn() and the if ~normalizationGateOn() short-circuit in ndi.database.internal.applyReadNormalization. Every read body is routed through did2.convert.v1_to_v2.
  2. Drop OFF-state tests. Removed testGateOffWrapsBodyUnchanged, testGateTruthyValues, and the TestMethodSetup / TestMethodTeardown env-var save/restore plumbing in TestApplyReadNormalization. Remaining tests renamed from testGateOn... to drop the gate-state prefix.
  3. Update docstring. Dropped the "gated by env var" paragraph and cross-referenced the four alias-shim helpers (augmentRead, normalizeDependsOn, reconcileWrite, translateQueryPaths) that make this default-on behaviour safe.

grep -rn NDI_DID2_NORMALIZE_ON_READ src/ tests/ now returns nothing.

Earlier attempt

PR #800 was closed without merging because its CI surfaced two compat-layer gaps the alias-table triad alone did not cover (depends_on struct-array schema fragility, and dropped ndi_<class>_class fields). Issue #801 tracked the audit; PR #802 + did-matlab #137/#138/#139 closed both gaps. This PR is the successor #800 was missing.

Test plan

CI MATLAB runs TestApplyReadNormalization plus every downstream test that touches ndi.database reads / writes / queries — including the full ndi.symmetry.makeArtifacts suite that previously surfaced the #801 issues.


Generated by Claude Code

Closes #776.

With the alias-table read augmentation (#779), write-time
reconciliation (#780), query path translation (#781), and the
issue-#801 follow-up that moved depends_on entry-key compat into
ndi.document accessors plus ndi.compat.translateQueryPaths -- all
landed on Vnext now -- every caller that still reads did_v1 field
names is covered without polluting the body's depends_on
struct-array schema. The env-var gate is therefore redundant.

Per the cleanup checklist on issue #779
(comment 4493101768):

1. Delete the NDI_DID2_NORMALIZE_ON_READ gate in
   ndi.database.internal.applyReadNormalization: removed the
   normalizationGateOn() helper and the `if ~normalizationGateOn()`
   short-circuit, so every read body is routed through
   did2.convert.v1_to_v2.

2. Drop the OFF-state and gate-truthy/falsy tests from
   TestApplyReadNormalization: removed testGateOffWrapsBodyUnchanged,
   testGateTruthyValues, and the TestMethodSetup /
   TestMethodTeardown env-var save/restore plumbing. Remaining
   tests renamed from "testGateOn..." to drop the gate-state
   prefix.

3. Update the docstring on applyReadNormalization: dropped the
   "gated by env var" paragraph and cross-referenced the four
   alias-shim helpers (augmentRead, normalizeDependsOn,
   reconcileWrite, translateQueryPaths) that make this default-on
   behaviour safe.

grep -rn NDI_DID2_NORMALIZE_ON_READ src/ tests/ returns nothing.

Note: an earlier attempt to flip this gate (PR #800) was closed
without merging because CI surfaced two compat-layer gaps the
alias-table triad did not cover. Those were tracked in #801 and
fully resolved by PR #802 + the cross-repo did-matlab #137/#138/
#139 chain. The compat layer is now sufficient.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 22, 2026

Vnext NDI unit test results

0 tests  ±0   0 ✅ ±0   0s ⏱️ ±0s
0 suites ±0   0 💤 ±0 
0 files   ±0   0 ❌ ±0 

Results for commit 51e1f18. ± Comparison against base commit 8a2e9da.

♻️ This comment has been updated with latest results.

github-actions Bot and others added 2 commits May 22, 2026 00:15
…epoch.clocks shape

did-schema reverted the V_delta renames for element.name/type,
daqreader_ndr.ndr_reader_string + ndi_daqreader_ndr_class, and
daqmetadatareader.ndi_daqmetadatareader_class, so the compat shims
added in #801 for those blocks become dead weight. Removed:

- ndi.compat.fieldAliases row mapping
  daqmetadatareader.reader_class <-> .ndi_daqmetadatareader_class
  (the field never moves now; no alias needed)
- ndi.database.fun.ndi_document2ndi_object: dropped the
  resolveReconstructorClass helper and the daqreader_ndr override.
  V_delta restored ndi_daqreader_ndr_class on the body, so the
  pre-#801 lookup of `<parent>.ndi_<parent>_class` works directly.
- Companion test deletions in AugmentReadTest and FieldAliasesTest.

For element_epoch the user elected to keep V_delta's new structural
shape (array-of-records `clocks` with name/t0/t1 fields) over a
revert: ndi.element/loadaddedepochs now reads clocks directly instead
of splitting epoch_clock CSV and indexing into the parallel t0_t1
matrix. This is the one reader site that exercises the V_delta
restructure; everything else is identity passthrough.

These three changes plus the did-schema revert and the did-matlab
migrator deletions close out the four CI failure categories surfaced
by the gate flip in eac9161.
else
obj_struct = getfield(ndi_document_obj.document_properties, obj_parent_string);
obj_string = resolveReconstructorClass(obj_parent_string, obj_struct);
obj_string = getfield(obj_struct,['ndi_' obj_parent_string '_class']);
Comment thread src/ndi/+ndi/element.m
ec{k} = ndi.time.clocktype(clock_types{k});
t0_t1{k} = vlt.data.rowvec(potential_epochdocs{i}.document_properties.element_epoch.t0_t1(:,k));
for k=1:numel(clocks_array)
ec{k} = ndi.time.clocktype(char(clocks_array(k).name));
Comment thread src/ndi/+ndi/element.m
t0_t1{k} = vlt.data.rowvec(potential_epochdocs{i}.document_properties.element_epoch.t0_t1(:,k));
for k=1:numel(clocks_array)
ec{k} = ndi.time.clocktype(char(clocks_array(k).name));
t0_t1{k} = vlt.data.rowvec([clocks_array(k).t0, clocks_array(k).t1]);
github-actions Bot and others added 6 commits May 22, 2026 00:56
Two follow-ups to PR #141 (did-matlab moves schema_version from base
to document_class) so the gate-on CI clears the remaining 13
structural failures.

(1) demoNDI / demoNDIMock schema classname

After flipping the did2 normalize gate, universalRenames snake-cases
the doc's document_class.class_name ('demoNDI' -> 'demo_ndi'). The
old did v1 validator (did.database/validate_doc_vs_schema:1228)
compares the schema's `classname` field against the doc's class_name
and threw `DID:Database:ValidationClassname` because the NDI-shipped
demoNDI_schema.json still declared classname 'demoNDI'.

V_delta convention is snake_case across the board (did-schema's
V_delta/index.json registers this class as `demo_ndi`). The fix is
local to NDI: update the inner classname (and property-block name)
on demoNDI_schema.json -> 'demo_ndi', and demoNDIMock.json ->
'demo_ndi_mock' with its superclass entry 'demoNDI' -> 'demo_ndi'.
File names stay as-is for now; renaming + updating the templates'
$NDISCHEMAPATH/$NDIDOCUMENTPATH references is a separate cleanup.

This clears the 11 `DID:Database:ValidationClassname` errors:
buildDataset / downloadIngested / blankSession* /
testConvertLinkedSessionToIngested / testDeleteIngestedSession* /
testSessionList / testUnlinkSession / testIsIngestedInDataset /
TestDeleteSession.

(2) NDI tests + cloud-migrate doc that read base.schema_version

did-matlab #141 moved schema_version to document_class. Three NDI
sites still read base.schema_version and need to follow:
- tests/+ndi/+unittest/+database/+internal/TestApplyReadNormalization.m
  (testConvertsV1StructToVDelta, testVDeltaBodyShortCircuits)
- tests/+ndi/+unittest/+migrate/TestMigrateCloud.m (makeVDeltaBody)
- src/ndi/+ndi/+migrate/cloud.m (doccomment only)

This clears the 2 `MATLAB:nonExistentField "schema_version"` errors
in TestApplyReadNormalization.

Remaining open after this commit:
- testCalcTuningCurve numeric failure (pre-existing, independent).
[did2 #4] aligned the demoNDI/demoNDIMock schema files with the V_delta
snake_case convention applied by did2.convert.universalRenames. The
write path doesn't normalize, so docs created with the legacy class
name reached the validator with class_name='demoNDI' and failed against
the new schemas.

Rename the class everywhere it's referenced from code: the document
templates (class_name, property_list_name, block keys), the document
attributes registry, the example calculator, and every test fixture
that builds documents via ndi.document('demoNDI') / newdocument or
pokes doc_props.demoNDI.value. The underlying JSON file names
(demoNDI.json, demoNDIMock.json) stay as-is — they're just the
on-disk locations, not the class identity.
mock_doc2_struct.demoNDI.value = 10;
mock_doc2 = ndi.document('demoNDIMock', 'demoNDI', mock_doc2_struct.demoNDI) + ndi_calculator_obj.session.newdocument();;
mock_doc2_struct.demo_ndi.value = 10;
mock_doc2 = ndi.document('demo_ndi_mock', 'demo_ndi', mock_doc2_struct.demo_ndi) + ndi_calculator_obj.session.newdocument();;
doc = E.database_search(ndi.query('demo_ndi.value','exact_number',5,''));
if numel(doc)~=1
error(['Found <1 or >1 document with demoNDI.value of 5; this means there is a database problem.']);
error(['Found <1 or >1 document with demo_ndi.value of 5; this means there is a database problem.']);
doc = E.database_search(ndi.query('','isa','demo_ndi',''));
if numel(doc)~=1
error(['Found <1 or >1 document of type demoNDI; this means there is a database problem.']);
error(['Found <1 or >1 document of type demo_ndi; this means there is a database problem.']);
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.

3 participants