Repository navigation
Symmetry Stage 3: MATLAB cannot read Python-generated artifacts — .ndi is missing the object-type marker #73
Description
What is wrong
The cross-language symmetry job runs three gated stages. Stage 3 — MATLAB readArtifacts, reading artifacts Python generated — fails: 23 passed, 11 failed, and every single failure is SourceType=pythonArtifacts. The paired SourceType=matlabArtifacts variant of each one passes.
MATLAB reading its own artifacts is fine. MATLAB reading Python's is not.
Why this has never been seen
Stage 3 is gated behind Stage 2, and Stage 2 has been failing since June. On main (c7fd864) the job records:
| Step | Result |
|---|---|
| Stage 1: MATLAB makeArtifacts | success |
| Stage 2: Python symmetry tests (make + read) | failure |
| Stage 3: MATLAB readArtifacts | skipped |
Stage 2's failure was the daqSystemNames 8-vs-9 mismatch — #71. With that fixed in #72, Stage 2 passes and Stage 3 ran for the first time, exposing this. These failures are revealed, not caused, by that PR.
This is the same shape as #71 itself: a real failure invisible because it was unreachable.
Eight of the failures are one message
Field filesInDotNDI has different lengths in summary1 (5) and summary2 (3)
Identical, verbatim, in all eight of:
session.blankSessionKjnielsenlab/testBlankSessionKjnielsenlabsession.blankSessionMarderlab/testBlankSessionMarderlabsession.blankSessionRayolab/testBlankSessionRayolabsession.blankSessionVhlab/testBlankSessionVhlabsession.buildSession/testBuildSessionArtifactssession.ingestionAxonNDR/testIngestionAxonNDRArtifactssession.ingestionIntan/testIngestionIntanArtifactssession.ingestionIntanNDR/testIngestionIntanNDRArtifacts
So this is one root cause repeated eight times, not eight problems. Note the field: filesInDotNDI, not daqSystemNames — the DAQ-system counts now agree, which is what #71 asked for.
The ninth failure names the likely cause
ndi.session.dir.directorytype returned 'session' for the pythonArtifacts dataset
artifact directory; expected 'dataset'. A dataset that has never been opened
since markers were introduced reports 'unknown'.
(session.objectTypeMarker/testDatasetDirectoryType)
MATLAB records what a directory holds in a marker file inside .ndi. From ndi.session.dir.objecttypemarkerfilename():
fname = 'ndi_object_type.txt';NDI-python never writes it. grep -rn "ndi_object_type\|object_type" --include=*.py src/ returns nothing.
What Python actually writes
summary filesInDotNDI : ['did-sqlite.sqlite', 'reference.txt', 'unique_reference.txt']
on disk .ndi : ['did-sqlite.sqlite', 'reference.txt', 'unique_reference.txt']
Three entries, and the summary agrees with the disk — so Python is self-consistent. MATLAB expects five.
Hypothesis, not verified: the two missing entries are ndi_object_type.txt (confirmed absent) and DID's files/ directory, which after #70 is created lazily. That accounts for 3 vs 5. Writing the marker would fix the ninth failure outright and plausibly the eight filesInDotNDI ones with it — but the second half of the arithmetic is a guess, and someone with MATLAB should confirm by listing a MATLAB-generated .ndi before anyone writes code against it.
The rest
Two errored (not verification failures), both dataset-level, cause not yet established:
dataset.buildDataset/testBuildDatasetArtifacts(pythonArtifacts)dataset.downloadIngested/testDownloadIngestedArtifacts(pythonArtifacts)
Four skipped, because the artifacts simply are not there — Python's makeArtifacts never produces them:
Test Diagnostic: pythonArtifacts pathSafeName artifact missing. Skipping.
Test Diagnostic: pythonArtifacts whatVaries artifact missing. Skipping.
fun.pathSafeName/testMatlabPythonSymmetry,fun.pathSafeName/testInputsAgreefun.whatVaries/testMatlabPythonSymmetry,fun.whatVaries/testKnownDivergencesAreStillReal
These are separate from the marker problem: two artifact generators are missing on the Python side. They are skips today, so they do not fail the job, but they mean four symmetry checks are silently not running.
Suggested order
- Write
ndi_object_type.txtfromndi_session_dir/ndi_dataset, matching MATLAB'supdateObjectTypeMarker/setObjectTypeMarker. Cheapest, and it is the one failure with a named cause. - Re-run and re-count. If
filesInDotNDIstill disagrees, list a MATLAB-generated.ndiand diff it against Python's rather than guessing at the fifth entry. - Root-cause the two dataset errors, which have no diagnostic yet and may be unrelated to the file listing.
- Add the missing
pathSafeNameandwhatVariesartifact generators, so those four checks stop silently skipping.
The acceptance criterion is Stage 3 passing, which would make the symmetry job green end to end for the first time since June.
Verification of the claims above
- Stage table: job steps on
mainrun 33338462744 vs Port the vhprairieview image DAQ system, and stop swallowing load failures #72 run 33340014507. - Failure list and diagnostics: Stage 3 log of the latter.
- Marker filename:
src/ndi/+ndi/+session/dir.min NDI-matlab,objecttypemarkerfilename(). - Marker absent from Python, and the three-entry
.ndilisting: run locally against this branch. - No MATLAB in the environment where this was written, so nothing MATLAB-side was executed; the MATLAB claims are read from source and from CI logs.
Related
- Port the vhprairieview DAQ system: the last symmetry failure, and untracked until now #71 / Syncrule resurrection: update_syncgraph_in_db re-adds syncrule documents under ids DID has retired VH-Lab/NDI-matlab#898 — the Stage 2 failure whose fix made this reachable.
- Port the vhprairieview image DAQ system, and stop swallowing load failures #72 — the PR that fixes Stage 2.
- Move file storage and retrieval onto DID's file services #70 — moved file storage onto DID's file services, which is why
files/is where it is.
Activity
Create DID's files/ directory up front, completing the .ndi listing
stevevanhooser commentedon Aug 31, 2026
Resolved — Stage 3 is green
The symmetry job passes end to end on #74, all five checks: run 33343247075. Stage 3 has never passed before, because it had never run before.
Two changes did it:
.ndi/ndi_object_type.txt, mirroring MATLAB'sobjecttypemarkerfilename().FileDirinSQLiteDB's constructor, where DID-MATLAB'ssqlitedbconstructor creates it. NDI-python picks it up automatically via the unpinneddid @ …@main.The buildDataset finding
This issue listed two errored tests with "cause not yet established":
dataset.buildDataset/testBuildDatasetArtifacts(pythonArtifacts)dataset.downloadIngested/testDownloadIngestedArtifacts(pythonArtifacts)Both were fixed by the object-type marker alone, before the
files/change landed. They are not a separate defect.The evidence is the intermediate run, 33343247075 attempt 1 — marker present,
files/still missing becausedidhad not yet been updated. That run went from23 passed, 11 failedto26 passed, 8 failed, and the two dataset tests dropped out of the failure summary entirely while the eightfilesInDotNDIfailures remained, their message shifting from(5) and (3)to(5) and (4).So the marker cleared exactly three:
objectTypeMarker, plus these two.On the mechanism, being careful about what is actually established: what is observed is that both went from Errored to passing when the marker was added, and nothing else changed in that run. The plausible reading is that they open the artifact directory as a dataset and MATLAB could not identify a Python-written directory as one — the same root cause
objectTypeMarkerreports directly, which is why one fix cleared all three. I did not read those tests' source to confirm that path, so treat the mechanism as inference and the before/after as fact.That also explains why the marker was worth more than its one named test:
directorytypereturning'session'for a dataset directory is not a cosmetic mismatch, it makes MATLAB mis-handle the directory.Status against this issue's suggested order
ndi_object_type.txt.ndientryfiles/, confirmed against a real MATLAB.ndi, fixed in DID-python#57pathSafeName/whatVariesartifact generatorsWhat is left
Only item 4. Four tests remain
Filtered by assumption, unchanged throughout:fun.pathSafeName/testMatlabPythonSymmetry,fun.pathSafeName/testInputsAgreefun.whatVaries/testMatlabPythonSymmetry,fun.whatVaries/testKnownDivergencesAreStillRealThese are skips, not failures, so the job is green with them outstanding — which is precisely the hazard this issue was filed about in the first place. Four symmetry checks are silently not running because Python's makeArtifacts never produces those two artifacts. Worth keeping this issue open for that, or splitting it out so a green job does not bury it.
Generated by Claude Code
stevevanhooser commentedon Aug 31, 2026
Done. All four items in the suggested order, and the acceptance criterion is met: Stage 3 passes, 38 passed / 0 failed, on
main(2dfa3ff) against NDI-matlabmain(3b865ef).ndi_object_type.txtfilesInDotNDIfiles/, created by VH-Lab/DID-python#57 — not NDI's to createpathSafeName/whatVariesgeneratorsThree corrections to what this issue assumed, worth recording:
The
files/fix did not belong here. A commit on #74's branch briefly created.ndi/filesfromndi_database.__init__. That was the wrong layer: DID-MATLAB'ssqlitedbconstructor creates it and NDI-matlab never touches.ndi/filesexcept to read it. Reverted and fixed upstream in DID-python#57 instead.Item 3 needed no separate work. This issue said the two errored dataset tests (
buildDataset,downloadIngested) had "cause not yet established" and might be unrelated. They were not — writing the marker cleared them along withobjectTypeMarker, so item 1 fixed three of the failures, not one.Item 4 was larger than described. The issue framed it as two missing generators. The functions they exercise were absent from this repository too —
ndi.funhad nopathSafeName/elementDirectoryName, andndi.fun.stimulushad nowhatVaries/whatIsConstant. #75 ports all four, then the battery, then the generators.First contact between the two hand-written batteries then needed reconciliation, which the schema had predicted: two reader bugs (MATLAB's
jsonencodecollapses a one-elementint listto a bare number) and one measurement that refuted a documented prediction —cellValuedConstantParameternever diverged. The last real divergence,allNaNParameter, was fixed in #76 / VH-Lab/NDI-matlab#902, so both allow-lists are now empty.Follow-ups filed rather than left implicit: #77 (a missing artifact still turns a check into a silent pass — this issue's own failure mode, one layer down) and #78 (unported MATLAB functionality).
Generated by Claude Code