feat: add experimental data entities as mirrors of the computational ones - #428
Open
timurbazhirov wants to merge 6 commits into
Open
feat: add experimental data entities as mirrors of the computational ones#428timurbazhirov wants to merge 6 commits into
timurbazhirov wants to merge 6 commits into
Conversation
…ones
ESSE describes simulation: a material is characterized by properties produced
by a model through a workflow inside a job. Experimental work has the same
shape and different nouns, so this adds four root entities, each built as the
mirror of the computational one it corresponds to rather than as a separate
vocabulary:
material -> sample a specimen; no basis/lattice required,
nominal structure via _material
software/application -> instrument vendor, model, serial, firmware, with
probes and sources as components
job -> measurement instrument instead of compute, sample
instead of material
workflow -> process stages instead of subworkflows, steps
instead of units, reusing the unit
sequencing mixin unchanged
Properties deliberately do not fork. A measured value is an ordinary
property/holder: same data union, same exabyteId, same repetition. Only
source.info widens, from the exabyte job reference to a union over exabyte,
measurement and process. The measurement reference is shaped like the job
reference -- measurementId where a job has jobId, channel where it has unitId
-- so a consumer that already reads job provenance needs no new code path.
Supporting pieces the four entities compose:
- core/abstract/multidimensional_array and core/reusable/array_data, for
microscopy rasters and spectroscopy grids. core/abstract/3d_grid is a
k-point mesh descriptor rather than a data grid, which is why this is new
- core/reusable/file_reference, for binary instrument output referenced
rather than embedded; system/file_source requires the content as text
- core/reusable/quantity/*, environment and identifier
- system/activity, the status, timing and operator mixin shared by
measurement and process so their vocabularies cannot drift apart
- techniques_category, narrowing the same CateCom tiers that categorize
models and methods
- film_thickness, surface_roughness and hysteresis_loop properties
Examples are built from real records rather than invented: an HTEM
combinatorial library and one of its positions, an Asylum Research DART
piezoresponse scan and switching spectroscopy, and a sputter-and-anneal run
from the National Laboratory of the Rockies lab system.
Two shapes were corrected by validating a real record against the schemas
instead of by inspection. Operators were reusing the bibliographic author
schema, which requires a surname; a lab record identifies an operator by
whatever the instrument logged, often a single username, so activity.operators
is now a name and an optional affiliation. And vendor and model are no longer
required on an instrument: identity comes from the name the entity mixin
supplies, and a lab record often knows a chamber only by the short name its
operators use.
Additive throughout: unit families are extended, never redefined; the holder
gains union branches without changing its required list; no existing $id moves.
Design and dataset survey: plan/upcoming/2026-09-02-experimental-data-*.md
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017pSxTJQwszq7y7n4SKRQRS
Both were found by parsing an actual laboratory deposition record and validating the result against these schemas, rather than by inspection. Operators reused core/reference/literature/name, which requires a surname because a citation needs one. A laboratory record identifies an operator by whatever the instrument logged, which is often a single username with no surname to give. system/activity.operators is now a name and an optional affiliation, plus a reference to a platform account for operators who have one. vendor and model were required on an instrument. A lab record frequently knows a chamber only by the short name its operators use, such as pdac_com5, with the vendor and model recorded elsewhere or not at all. Identity comes from the name the entity mixin already supplies, so neither field is required now; both remain documented as the useful things to record when known. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017pSxTJQwszq7y7n4SKRQRS
Each of these was confirmed against the resolved schemas with a probe record before and after. - Technique unions on process, stage and instrument use anyOf, not oneOf. A record classified only to tier1 satisfies both branches and oneOf rejected it as ambiguous, so a run whose technique was not yet classified below tier1 could not be stored at all. - The stage composes system/activity instead of re-declaring status and timing by hand, which was exactly the drift the mixin was introduced to prevent. - A sample's _parent is a system/_sample reference, as measurement._sample and process._inputSamples already were; a parent pointing at a Material is now rejected, so the join key is as strict on the sample side as on the measurement side. - The technique subtype vocabularies were defined but referenced by nothing, leaving subtype a free string. They are now referenced from each branch, so a misspelt subtype fails validation. Tying subtype to type is left to the per-narrowing leaf files a later phase adds, as models_category does. - The step keeps the workflow-unit status vocabulary, and its description now says why: a step is a unit, and run-level states such as cancelled belong to the stage and process, which carry the activity vocabulary. - Descriptions of parameters on measurement and stage no longer claim a catalogue directory that does not exist yet. - docs/03 said the holder sits on one provenance reference; it is a union of three now. The map comment and legend say what the experiment family actually colours: the components and vocabulary, not the root hexagons, which take the root-entity colour like every root. - The measurements context document gains a dated addendum with the new baseline, as the graph test's own comment requires. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017pSxTJQwszq7y7n4SKRQRS
…e corpus Four assertions the existing suites did not make: - a property holder whose source is a measurement validates, and the job-sourced example still does -- the regression test for the source.info union, which is the one existing schema this change widens - a measurement source without a measurement id is rejected, so the union cannot quietly accept an empty provenance - every schema the experimental-data change added carries a description, because those become the pydantic docstrings and the map's detail panel - no example carries an inline array over the budget stated on array_data, so nobody commits a real 256x256 image into examples.py by accident Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017pSxTJQwszq7y7n4SKRQRS
… probe block Nothing narrows measurement.parameters until a catalogue entry binds a technique to its block, so the example's parameters were never validated against measurement/parameters/scanning_probe_microscopy. This asserts it explicitly, which also gives that schema its first consumer. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017pSxTJQwszq7y7n4SKRQRS
The pre-commit hook writes datamodel-codegen output to dist/py, which is gitignored, while the committed models live under src/py/mat3ra/esse/models as a real directory rather than the link pyproject.toml anticipates. This copies the hook's output over the committed tree, generated with the datamodel-code-generator 0.28.5 that pyproject pins, so untouched modules keep the headers they have. What changed and why, so the churn can be skipped in review: - 50 new modules for the sample, instrument, measurement, process, techniques_category, core and property schemas this branch adds. Every one of them imports; the field descriptions become their docstrings. - 9 modules change in substance: property/holder (the source.info union and the three new data variants), properties_directory/enum_options (the three new property names), and seven property modules whose pressure, force or frequency unit enums gained the experimental units. - 152 modules differ only in the numeric suffixes the generator appends to de-duplicated class names. The counter is global across the run, so adding schemas renumbers every module generated after them. - 54 modules are removed because their schemas no longer exist, and 4 stale duplicates go where the generator now places the module under a package (software/application, material/metadata, workflow/unit/context/item). 14 modules were also behind their schemas on dev (job, workflow and the unit execution schemas). That drift predates this branch; a clean regeneration cannot carry it, and it is spelled out here so it is reviewed knowingly. - materials_category/defective_structures/three_dimensional/__init__.py stays the empty file it has been since 69ac2e8, because the generator does not emit it and it was added by hand. Verified by importing every module file: 670 of 700 import. The 30 that do not are the versioned apse directories, whose dotted names are not importable as packages, and the title-derived Reusable_schema_for_energy_value modules; both fail identically on the base commit and are left for the generator configuration to fix separately. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017pSxTJQwszq7y7n4SKRQRS
timurbazhirov
pushed a commit
to mat3ra/parsers
that referenced
this pull request
Sep 2, 2026
…the process schema
The released package returns None for get_schema_by_id("process"), which the
validation test then handed to jsonschema and failed on a TypeError. The schema
arrives with mat3ra/esse#428; until a release carrying it is the floor in
pyproject.toml, the test is skipped with that reason, so the parser tests run
everywhere while the cross-repository check keeps its teeth wherever the schema
exists. Verified both ways: 3 passed, 1 skipped against mat3ra-esse
2026.8.31.post0, which is what CI installs; 4 passed against an editable install
of the ESSE branch.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017pSxTJQwszq7y7n4SKRQRS
timurbazhirov
pushed a commit
that referenced
this pull request
Sep 2, 2026
…VP is The review's change request (l) asked how dist/py codegen output reaches the committed models before anything was built. Answer, established while landing #428: the hook's output is copied verbatim over src/py/mat3ra/esse/models with the pinned generator, and the committed tree is nothing but that output. The overview now also points at the MVP PR and its parser round trip so the plan says where the work actually is. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017pSxTJQwszq7y7n4SKRQRS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
A minimal, working implementation of experimental data support: four root entities, the pieces they compose, and examples built from real instrument and lab-system records. It is deliberately the smallest thing that stands on its own. The concepts are outlined and each is exercised by a record that actually validates.
Design and dataset survey are in
plan/upcoming/2026-09-02-experimental-data-*.md(onclaude/experimental-data-support-s3bf63).The idea: mirror, don't fork
Experimental work has the same shape as simulation and different nouns. Each new entity is built as the mirror of the computational one it corresponds to, composing the same mixins and keeping the fields that transfer.
materialsamplebasis/latticebecome an optional_materialreference, because a specimen may have no known structuresoftware/applicationinstrumentversionbecomesfirmware,buildbecomesserialNumberjobmeasurementcomputebecomesinstrument,_materialbecomes_sampleworkflowprocesssubworkflowsbecomestages,unitsbecomestepsProperties do not fork. A measured film thickness is an ordinary
property/holder: samedataunion, sameexabyteId, samerepetition. Onlysource.infowidens, from the exabyte job reference to a union over exabyte, measurement and process. The measurement reference is shaped like the job reference (measurementIdwhere a job hasjobId,channelwhere it hasunitId), so a consumer that already reads job provenance needs no new code path.What is in the diff
sample(+ layer, position, library),instrument(+ component, and theinstrument_propertymixin mirroringjob/compute_property),measurement(+ data channel, scanning probe parameters),process(+ stage, step, and the target/precursor/gas source union).core/abstract/multidimensional_arrayandcore/reusable/array_datafor rasters and grids (core/abstract/3d_gridis a k-point mesh descriptor, not a data grid);core/reusable/file_referencefor binary instrument output, whichsystem/file_sourcecannot hold because it requires text;quantity/*,environment,identifier;system/activity, the status and timing mixin shared by measurement and process.techniques_category, narrowing the same CateCom tiers that categorize models and methods.film_thickness,surface_roughness,hysteresis_loop, registered the usual five-touch way.ENTITY_DOMAINSgains the four nouns so the layer taxonomy stays total; the ontology map gains an experiment colour family; a concept page joins the docs.datamodel-code-generator==0.28.5thatpyproject.tomlpins and synced intosrc/py/mat3ra/esse/models/(details below).Why it composes what it composes
process/stepreusesworkflow/unit/mixins/baseunchanged, so a process is walked with the samehead/next/flowchartIdmechanics as a workflow: a deposition recipe and a calculation are the same kind of object to a traversal.system/activityexists so measurement and process cannot grow two different status vocabularies.instrument/instrument_propertymirrorsjob/compute_propertyso "has an instrument" is defined once.Examples are real records
Not invented: an HTEM combinatorial library (6705) and one of its 44 positions, an Asylum Research Jupiter DART piezoresponse scan and switching spectroscopy with their actual scan parameters, and a sputter-and-anneal run from the NLR lab system.
Two shapes corrected by real data
Both were found by validating a real record against the schemas, not by inspection:
activity.operatorswas reusing the bibliographic author schema, which requires a surname. A lab record identifies an operator by whatever the instrument logged, often a single username, so it is now a name and an optional affiliation.vendorandmodelare no longer required on an instrument. Identity comes from thenamethe entity mixin supplies, and a lab record often knows a chamber only by the short name its operators use (pdac_com5).Tightened after a review pass
Each of these was confirmed with a probe record against the resolved schemas before and after (commit 1104d14):
anyOf, notoneOf. A record classified only to tier1 satisfied both branches andoneOfrejected it as ambiguous, so a run not yet classified below tier1 could not be stored at all.system/activityinstead of re-declaring status and timing by hand, which was exactly the drift the mixin exists to prevent._parentis asystem/_samplereference, asmeasurement._samplealready was; a parent pointing at a Material is now rejected.subtypea free string. They are now referenced from each branch, so a misspelt subtype fails validation.cancelledbelong to the stage and process, which carry the activity vocabulary.And the guard tests the existing suites did not make, in
tests/js/experimentalSchemas.tests.ts(commits e06e451, 9b24c75):array_data;parametersvalidate againstmeasurement/parameters/scanning_probe_microscopy, which nothing narrowed until now.How the models were synced
The pre-commit hook writes
datamodel-codegenoutput todist/py, which is gitignored, while the committed models live undersrc/py/mat3ra/esse/models/as a real directory rather than the linkpyproject.tomlanticipates. Commit caec728 copies the hook's output over the committed tree, generated with the pinned 0.28.5 so untouched modules keep their headers. To make the 270-file diff reviewable, this is what it contains, measured against a regeneration on the base commit:property/holder(source union and three data variants),properties_directory/enum_options, and seven property modules whose pressure, force or frequency unit enums gained the new unitsUnits197becomesUnits221); safe to skipImporting every module file: 670 of 700 succeed. The 30 that do not are the versioned
apsedirectories, whose dotted names are not importable, and the title-derivedReusable_schema_for_energy_value…modules; both fail identically on dev and are a generator-configuration question, not this PR's.Verification
Example coverage rises from 209/564 (37%) to 254/610 (42%). Pinned graph counts in
tests/js/entityGraph.tests.tsare updated from the lint output, not by hand.The round trip is exercised end to end in a companion PR on
mat3ra/parsers, which parses a real NLR deposition record into aprocessconfig and validates it against the schema added here.Two things reviewers should decide
devon its own if that is preferred.requiredfrominstrument_propertiesand reshapingactivity.operatorsare the two places this PR touches judgement rather than adding files.Not in this PR
Vendor file formats under
apse/(Nanonis, Asylum, HTEM exports), technique catalogue entries beyond the parameter block, and the HTEM crosswalk. Those are phases 4 and 5 of the plan and want real files inspected first.🤖 Generated with Claude Code
https://claude.ai/code/session_017pSxTJQwszq7y7n4SKRQRS
Generated by Claude Code