Add did2 v2 scaffold: document and schema cache classes#120
Merged
Conversation
…ep 1
Begins step 1 of docs/v2/PLAN.md: introduce the parallel-namespace
+did2 package that holds V_gamma documents in their flat JSON shape
(no V_alpha base.* / document_class.* nesting).
Added:
- src/did/+did2/document.m: V_gamma document object. Settled API
surface (fromJSON/fromStruct/blank, get/set/iterate, toJSON,
className/classVersion, validate). Dot-path get/set is
implemented; [*] array iteration is exposed via iterate().
Construct-from-blank and validate delegate to the schema cache.
- src/did/+did2/+schema/cache.m: V_gamma schema cache class.
Singleton bootstrap, schema-path resolution (DID_SCHEMA_PATH env
override or sibling did-schema checkout), getClass, and
superclass traversal are implemented; fieldsFor, queryablePaths,
buildBlankDocument, and validateDocument are stubs that throw
did2:notImplemented and will be filled in next.
- src/did/+did2/Contents.m: package overview.
- tests/+did2/testDocumentScaffold.m: function-based unit tests for
the scaffolded surface (construction, dot-path get/set, iterate,
JSON round-trip, error IDs).
- docs/v2/PLAN.md: progress log entry documenting what landed and
what comes next; +did2 chosen as the provisional namespace,
logged in §1.
Note: per AGENTS.md these files have not been executed in MATLAB.
They are intended for human review and test in a licensed MATLAB
environment.
V2 is the long-lived development line for the +did2 / V_gamma rewrite (docs/v2/PLAN.md). Self-tests should gate the V2 branch the same way they gate main. Symmetry tests are intentionally left on main only — the V_gamma document layout is not yet wired up to the symmetry fixtures.
Spelling check is cheap and prose-heavy V2 docs (docs/v2/PLAN.md and similar) benefit from it. Pair with the test-code update so any push or PR against V2 gets the same gates as main, minus the symmetry tests.
Lets us manually fire the self-test workflow from the Actions UI against any branch. Note: the "Run workflow" button only appears once this file is on the default branch (main); until V2 merges to main, the trigger is defined but not surfaced in the UI.
Same caveat as test-code: the manual "Run workflow" button only shows in the Actions UI once this file lands on the default branch (main).
The floating @v1 tag was moved upstream on 2026-05-01/02 to a commit whose workflow calls codecheckToolbox with more arguments than the installed matbox MATLAB toolbox accepts, producing: Error using codecheckToolbox Too many input arguments. Main's last green test-code run was on 2026-03-31, before that retag. Pin to 4132d36 (Nov 2025), which is the workflow-file revision main was using when it last passed. Comment explains the pin so we can unpin once matbox-actions is fixed upstream.
The reusable workflow ehennestad/matbox-actions/.../test-code-workflow.yml
was retagged on 2026-05-01/02 to call codecheckToolbox with arguments
that the installed matbox MATLAB toolbox rejects ("Too many input
arguments"). Pinning to an older SHA of the reusable workflow did not
help, suggesting the new call shape lives in the older revision too.
NDI-matlab's run-tests.yml uses the individual matbox-actions
(install-matbox + check-code) at @v1 directly and is currently green.
Model test-code.yml on that pattern:
- actions/checkout@v4
- matlab-actions/setup-matlab@v2 (R2021b)
- ehennestad/matbox-actions/install-matbox@v1
- matbox.installRequirements(...) for mksqlite + vhlab-toolbox-matlab
- ehennestad/matbox-actions/check-code@v1
- TestSuite.fromFolder("tests", "IncludingSubfolders", true)
Removed:
- The reusable-workflow `uses:` (replaced by explicit steps).
- The CODECOV_TOKEN secret pass-through (no coverage XML produced
yet; add back with a matbox.testToolbox-style entry point later).
The +did2 tests at tests/+did2/testDocumentScaffold.m are picked up
automatically by fromFolder with IncludingSubfolders.
ehennestad/matbox-actions/check-code@v1 fails on fresh runners with "codecheckToolbox: Too many input arguments" — the action passes more arguments than the installed matbox MATLAB toolbox accepts. The same action passes for NDI-matlab because that repo's setup-matlab cache holds an older matbox image, kept warm by daily CI runs. Ours is cold and pulls the current matbox, exposing the mismatch. Drop check-code from test-code.yml so the self-test suite can run. Static analysis can be re-added once matbox-actions is fixed upstream, or via MATLAB's built-in codeAnalyzer.
Matches NDI-matlab's run-tests.yml, which currently passes daily on release: latest. R2021b is from 2021 and predates many matbox changes; current matbox may rely on features (e.g. arguments-block extensions) that R2021b mis-parses, which could itself be the source of the "Too many input arguments" surfacing through codecheckToolbox. Even if not the root cause, aligning with NDI's known-green release removes one variable.
The codecheckToolbox "Too many input arguments" failure was driven by the R2021b pin; matbox's current check-code uses MATLAB features beyond R2021b. With release: latest, NDI-matlab runs the same check-code@v1 successfully every day. Re-add the step so we get the static-analysis gate alongside the test run. Test run keeps `if: always()` so a check-code failure doesn't mask test results.
Mirrors NDI-matlab's run-tests.yml step order. The previous order ran matbox.installRequirements() before check-code, and check-code failed there with "codecheckToolbox: Too many input arguments" even on release: latest. NDI does not call installRequirements at all and its check-code@v1 step passes daily, so the suspicion is that installRequirements modifies the MATLAB environment in a way that mis-aligns check-code's call to codecheckToolbox. installRequirements is moved after check-code (still required for the tests, which use mksqlite). Both later steps gain `if: always()` so a check-code failure does not skip them.
The bare tools/tasks/codecheckToolbox.m wrapper was being picked up by
addpath(genpath('./tools')) inside ehennestad/matbox-actions/check-code@v1,
which shadowed the real matbox.tasks.codecheckToolbox. check-code calls
codecheckToolbox with multiple arguments; our zero-arg wrapper rejected
them with "Too many input arguments", breaking CI.
Move the wrapper into the +didtools package so it's invoked as
didtools.codecheckToolbox and never collides with the matbox symbol.
The old tools/tasks/codecheckToolbox.m is removed in the next commit.
Replaced by tools/+didtools/codecheckToolbox.m in the previous commit. The bare wrapper at tools/tasks/codecheckToolbox.m shadowed matbox.tasks.codecheckToolbox once tools/ was on the MATLAB path and broke ehennestad/matbox-actions/check-code@v1 with "Too many input arguments". Removing it lets check-code resolve to matbox's version.
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
Hermetic V_gamma schema fixtures under tests/+did2/fixtures/V_gamma/ so the +did2 self-tests can run without a sibling did-schema checkout or network access. base.json root V_gamma class (upstream copy) CURIE_lookups_meta.json trimmed CURIE registry (subset of upstream) demoA.json V_gamma translation of v1's demoA (base + char value) demoB.json multi-level inheritance (demoB -> demoA -> base) demoC.json three _depends_on entries (V_gamma translation of v1 demoC) demoFile.json two _file attachments (V_gamma translation of v1 demoFile) README.md origins and refresh procedure Schemas themselves did not change between the flat-fields and class-scoped versions of V_gamma — only the document-instance wire shape did — so these fixtures are stable across that change.
Fills in the cache to the level step 1 of docs/v2/PLAN.md needs,
against V_gamma's class-scoped property-block document layout
(V_gamma_SPEC.md "JSON Format: Document Instances").
Implemented:
- classChain(className): root-first chain including the class itself.
- ownFields(className): the _fields list the class declares directly.
- fieldsFor(className): merged inherited fields tagged with the
declaring class (struct array of {declaringClass, fieldDef}).
- buildBlankDocument(className): V_gamma class-scoped doc with
x_classname / x_class_version / x_superclasses / x_depends_on at
the top level, plus one property block per class in the chain
(empty {} for zero-field classes). base.id auto-minted via
did.ido.unique_id(); base.datestamp set to current UTC ISO-8601.
- validateDocument(docOrStruct): walks the class chain, validates
each class's own _fields against its property block. Type-shape
check runs before _mustBe* flags so a wrong type is reported as
did2:validation:typeMismatch rather than did2:validation:notScalar.
New error IDs: missingClassBlock, badClassBlock; reuses
emptyField, notScalar, typeMismatch, maxLength, minLength,
minimum, maximum, enum, nanValue, missingClassName.
queryablePaths remains a stub — it belongs to steps 3 and 4 once
the storage layer lands, and will return class-qualified dot-paths
(e.g., 'daqsystem.sample_rate.hertz').
The MATLAB-side storage convention (x_<name> instead of _<name> for
the four leading-underscore JSON keys) is documented in PLAN.md §4.1
and mirrored by did2.document.toJSON's regex rewrite on serialise.
Aligns did2.document with V_gamma's class-scoped property-block
document layout (V_gamma_SPEC.md "JSON Format: Document Instances").
- className() / classVersion() now read from x_classname /
x_class_version (MATLAB-legal renames of the leading-underscore
JSON keys; mirrors what jsondecode produces).
- toJSON() post-processes the jsonencode output with a regex that
rewrites `"x_<name>":` keys back to `"_<name>":` so the wire form
matches the spec. fromJSON relies on jsondecode's default
behaviour to read it back.
- Class metadata accessors no longer assume a `_class.name` nested
path; they read flat top-level fields.
- Header doc updated to describe the V_gamma layout, the x_<name>
convention, and the round-trip path.
dot-path get/set, iterate, fromJSON/fromStruct/blank, and the
(className, valueStruct) constructor are unchanged in shape — they
operate on whatever struct the document carries.
Function-based unit tests for did2.schema.cache (plus end-to-end
through did2.document) against the in-repo fixture set
tests/+did2/fixtures/V_gamma/. Covers:
- schema-path plumbing, getClass, missing-class error, CURIE
registry presence
- superclass chains: base (root), demoA (one parent), demoB
(two-level)
- classChain root-first ordering
- ownFields counts (base=4, demoA=1)
- fieldsFor declaring-class tagging across the chain
- buildBlankDocument top-level metadata (x_classname,
x_class_version, x_superclasses ancestor entries, empty
x_depends_on)
- buildBlankDocument class-scoped blocks: base, the concrete
class, all chain blocks present; demoB has both demoA.value
and demoB.value_b at distinct paths
- buildBlankDocument base block: minted id (length 33),
current-UTC datestamp starting with "20" and ending in "Z"
- validateDocument: empty session_id throws emptyField, passes
after filling; max-length boundary (300 fails, 256 passes);
typeMismatch on numeric-where-char; missingClassName on
structs without x_classname; missingClassBlock when a chain
block is removed
- End-to-end through did2.document: blank() / className() /
classVersion() / get('base.id') / validate() round-trip
- toJSON rewrite: serialised form contains "_classname", not
"x_classname"; fromJSON re-parse preserves the class block.
setupOnce points the cache at the fixture via setSchemaPath;
teardownOnce resets the singleton.
Updates the living plan to the V_gamma "JSON Format: Document Instances" wire shape (upstream did-schema commit 137f583, which restored class-scoped property blocks) and logs the step-1 close. Changes: - Decision #8 in §1 is rewritten to describe class-scoped property blocks keyed by `_classname` verbatim (instead of the earlier "flat MATLAB struct" placeholder). Notes that MATLAB cannot have leading-underscore struct fields, hence the x_<name> internal convention and toJSON regex rewrite. - §4.1 "In-memory document shape" is replaced. Documents the V_gamma class-scoped layout, the universal top-level keys (`_classname`/`x_classname`, etc.), per-class property blocks including empty `{}` for zero-field classes, and the `(declaring_class, _name)` field-identity rule. Compares V_alpha → V_gamma at the document level for converter (§7) reference. - §12 progress log gains a 2026-05-12 entry covering: the SPEC update we drove upstream; the cache methods now implemented (classChain, ownFields, fieldsFor, buildBlankDocument, validateDocument); the document.m changes (className / classVersion read x_<name>, toJSON post-processes the encoded text); the hermetic V_gamma fixture set under tests/+did2/fixtures/V_gamma/; and the new testSchemaCache.m coverage. Step 1 is recorded as complete; queryablePaths and detailed named-composite/`_depends_on`-value validation are noted as deferred to follow-up.
GitHub Advanced Security / Code Analyzer flagged `numel(parts) == 1` in did2.document.assignNested as a length comparison that should be isscalar(parts) for clarity and performance. Cell array isscalar returns true iff the cell has exactly one element, so the substitution is equivalent.
V_gamma_SPEC.md restored the V_alpha-style top-level `document_class`
header with sub-keys `class_name`, `class_version`, `superclasses`
(no leading underscore). Schemas and document instances now both
carry that header; only `_depends_on` stays as a top-level
underscore-prefixed key.
Fixtures updated to match the new shape:
- base.json: document_class header with empty superclasses
- demoA.json: document_class.superclasses [{class_name: "base"}]
- demoB.json: document_class.superclasses [{class_name: "demoA"}]
- demoC.json: document_class header + three top-level _depends_on
declarations
- demoFile.json: document_class header + two top-level _file
declarations
Inside `_fields`, field definitions are unchanged (still _name,
type, _blank_value, _default_value, _mustBe*, _queryable,
_ontology, _documentation, _constraints).
Inside `document_class.superclasses[i]` in a schema file, the keys
are `class_name` + `_schema` (the schema-file path token). In a
document instance the same array uses `class_name` + `class_version`
instead — that distinction is enforced by the cache and the
buildBlankDocument output.
V_gamma_SPEC.md was amended (upstream did-schema commit 94091d8) to
re-introduce the V_alpha-style `document_class` header in both schema
files and document instances, with sub-keys `class_name`,
`class_version`, `superclasses` (no underscore prefixes).
`_depends_on` stays at the top level.
cache.m changes:
- superclasses(className) now walks `document_class.superclasses`
(was top-level `_superclasses`).
- buildBlankDocument emits the new shape:
doc.document_class.class_name / class_version / superclasses
doc.x_depends_on (empty)
doc.<class_name> for each class in the chain
Each superclass entry is `{class_name, class_version}` (the
document-instance form). The `_schema` path token used in schema
files is dropped — document instances pin by version, not by path.
- validateDocument reads `doc.document_class.class_name` and throws
did2:validation:missingClassName if absent.
Header comment updated to describe the new wire shape. The internal
`x_depends_on` / `x_name` convention for the remaining
underscore-prefixed keys is preserved; everything inside
`document_class` is plain (no x_ rename needed since none of those
keys start with an underscore).
V_gamma re-introduced the V_alpha-style `document_class` header in
both schema files and document instances. did2.document is updated
to match:
- className() now reads `documentProperties.document_class.class_name`
(was `x_classname`).
- classVersion() now reads
`documentProperties.document_class.class_version`
(was `x_class_version`).
- Header doc explains the new wire shape and notes that
`document_class` + its sub-keys (`class_name`, `class_version`,
`superclasses`) and the class-block keys are plain MATLAB
identifiers, while only `_depends_on` (top-level) and `_name`
(inside its entries) need the `x_<name>` rename.
The `toJSON` regex rewrite is unchanged — it correctly rewrites
`"x_depends_on":` and `"x_name":` on encode and leaves
`document_class` / `class_name` / `class_version` / `superclasses`
verbatim because they never carried the `x_` prefix.
V_gamma_SPEC.md was further updated (upstream did-schema commit
77c6363) to drop every leading underscore on NDI-extension keys, in
both schema files and document instances. Schema files now use:
document_class { class_name, class_version, superclasses }
maturity_level
depends_on
file
directory
fields[i]: name, type, blank_value, default_value,
mustBeNonEmpty, mustBeScalar, mustNotHaveNaN,
queryable, ontology { node, name }, documentation,
constraints
depends_on[i]: name, mustBeNonEmpty, documentation,
must_refer_to_document_class, multiple?
file[i] / directory[i]: name, documentation
superclasses[i] (schema file): class_name, schema
superclasses[i] (document): class_name, class_version
All NDI-reserved key names live in ndi_reserved_keys.json upstream;
schema authors must not reuse them.
Fixtures (base, demoA, demoB, demoC, demoFile) rewritten to the
plain-key shape. Inheritance, fields, dependency declarations, file
records all preserved structurally — only the key names changed.
V_gamma now uses plain keys everywhere (no leading underscores on
NDI-extension keys per upstream did-schema commit 77c6363). cache.m
follows suit:
- Drops the `extractField` helper that probed for `_<name>` /
`x_<name>` jsondecode-rename variants. Every key now resolves
via direct `isfield`/`s.X` access.
- superclasses() reads `s.document_class.superclasses[i].class_name`
(no x_ rename anywhere).
- ownFields() reads `s.fields` (was `_fields` / `x_fields`).
- buildBlankDocument emits:
doc.document_class.{class_name, class_version, superclasses}
doc.depends_on (empty struct array of {name, value})
doc.<class_name> for each class in the chain
No more `x_depends_on` or `x_name` MATLAB-side.
- buildBlockForClass / buildBlankStructure read field-definition
keys directly (name, type, blank_value, fields).
- validateField reads mustBeNonEmpty / mustBeScalar /
mustNotHaveNaN / constraints / type / name directly.
Same error IDs and validation semantics as before. The in-memory
shape now matches the JSON shape one-to-one — `jsondecode(jsonencode(s))`
is the identity for any well-formed V_gamma document.
V_gamma's "drop underscore prefixes" pass removed every leading
underscore on NDI-extension keys, so the in-memory MATLAB struct now
matches the JSON shape one-to-one. did2.document follows suit:
- toJSON is now a bare jsonencode call. The
rewriteXUnderscoreKeys regex helper is removed — there are no
"x_<name>" keys left to translate.
- Header doc updated to describe the simpler representation
(jsonencode/jsondecode round-trip without any rewrite pass).
- className() / classVersion() continue to read
documentProperties.document_class.class_name /
documentProperties.document_class.class_version unchanged.
dot-path get/set, iterate, fromJSON/fromStruct/blank, and the
(className, valueStruct) constructor are unchanged.
V_gamma dropped all leading underscores on NDI-extension keys, so the
in-memory document is the JSON shape verbatim. Tests updated:
- Assertions on the document_class header read
doc.document_class.class_name / class_version / superclasses(i).class_name
(was doc.x_classname / x_class_version / x_superclasses(i).x_classname).
- depends_on assertion: isfield(doc, 'depends_on') (was 'x_depends_on').
- Validation tests unchanged — same error IDs and semantics.
- toJSON test now confirms the wire form uses "document_class" and
"class_name":"demoA" rather than the previous "_classname":"demoA"
/ "x_classname" pattern. Also re-parses and verifies the class
blocks survive a JSON round-trip.
22 tests; same coverage as before, just adapted to the new shape.
V_gamma went through two back-to-back SPEC revisions on 2026-05-12: restore class-scoped property blocks (did-schema 137f583), then drop the leading-underscore convention on every NDI-extension key (did-schema 77c6363). Net result: the in-memory MATLAB struct is the JSON shape verbatim — no x_<name> aliasing or toJSON rewrite pass. Changes: - Decision #8 in §1 updated to describe the new layout (document_class header + class-scoped blocks + plain keys everywhere) and to record the two-step SPEC history. - §4.1 "In-memory document shape" rewritten. The whole section is now a few short paragraphs plus a four-row table — the MATLAB representation is plain, no encoding/aliasing remarks needed. The V_alpha → V_gamma comparison table is updated to show that the converter (§7) is now a thin per-document data migration (V_alpha's class-scoped layout maps to V_gamma almost verbatim once `property_list_name` and `definition`/`validation` sub-keys are dropped). - §12 progress log gains a 2026-05-12 entry covering both SPEC revisions and the resulting +did2 changes (cache, document, fixtures, tests). - Stray `_queryable` / `_ontology` references in §§3.2, 5, 7 were corrected to the plain names.
Upstream did-schema (commit b54c940) moved `maturity_level` from a top-level key into the `document_class` header alongside `class_name`, `class_version`, `superclasses`. Fixtures updated to match: all five fixture schemas (base, demoA, demoB, demoC, demoFile) now carry `maturity_level: "work_in_progress"` as the fourth sub-key of `document_class`. No +did2 code reads `maturity_level` today, so cache.m / document.m are unchanged. Tests are unchanged (no assertions on `maturity_level`).
…slots
Mirrors the legacy +did test layout exactly:
tests/+did/+test/+fixture/ → tests/+did2/+test/+fixture/ (placeholder)
tests/+did/+test/+helper/ → tests/+did2/+test/+helper/ (placeholder)
tests/+did/+unittest/+abstract/ → tests/+did2/+unittest/+abstract/ (placeholder)
tests/+did/+unittest/*.m → tests/+did2/+unittest/*.m (real tests)
tests_symmetry/+did/+symmetry/+makeArtifacts/ (placeholder)
tests_symmetry/+did/+symmetry/+readArtifacts/ (placeholder)
Adds:
tests/+did2/+unittest/testDocumentScaffold.m
Function-based tests for did2.document's surface API.
Same content as the previous tests/+did2/testDocumentScaffold.m;
docstring updated to advertise the new runtests path:
runtests('did2.unittest.testDocumentScaffold')
tests/+did2/+unittest/testSchemaCache.m
Function-based cache + end-to-end tests (22 tests).
`setupOnce` recomputes the fixture path: two fileparts up from
mfilename's directory now (was one), since this file moved down
one package level.
Empty placeholders (.gitkeep with a one-line comment explaining the
legacy slot they reserve) under:
tests/+did2/+unittest/+abstract/
tests/+did2/+test/+fixture/
tests/+did2/+test/+helper/
tests_symmetry/+did2/+symmetry/+makeArtifacts/
tests_symmetry/+did2/+symmetry/+readArtifacts/
The fixture data directory tests/+did2/fixtures/V_gamma/ stays put —
it's a non-package sibling holding static JSON, not a MATLAB package.
The old test-file locations (tests/+did2/testDocumentScaffold.m and
tests/+did2/testSchemaCache.m) are removed in follow-up commits. CI
discovery via TestSuite.fromPackage will land in a separate
test-code.yml update so the runner finds the relocated tests under
did2.unittest.
Relocated in the previous commit to tests/+did2/+unittest/testDocumentScaffold.m
to mirror the legacy +did/+unittest/ layout exactly. Invoke via
runtests('did2.unittest.testDocumentScaffold') going forward.
Relocated in the prior batch commit to
tests/+did2/+unittest/testSchemaCache.m, with the fixture-path
helper updated to walk one extra fileparts level so it still
resolves to tests/+did2/fixtures/V_gamma/. Invoke via
runtests('did2.unittest.testSchemaCache').
did2 self-tests moved into the tests/+did2/+unittest/ MATLAB package
to mirror the legacy +did/+unittest/ layout. TestSuite.fromFolder does
not recurse into +package directories, so switch to
TestSuite.fromPackage("did2.unittest", "IncludingSubpackages", true)
— same pattern test-symmetry.yml already uses for did.symmetry.*.
The IncludingSubpackages flag also picks up future +abstract base
classes when they land under tests/+did2/+unittest/+abstract/.
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.
Summary
Implements the initial scaffold for DID v2 development (step 1 of PLAN.md §9), introducing the
+did2namespace with core document handling and schema infrastructure. This establishes the API surface and basic functionality for working with V_gamma documents directly, without translation to the legacy V_alpha nesting structure.Key Changes
src/did/+did2/document.m— New V_gamma document class providing:(className, valueStruct)tuplesget()/set()for nested field access with automatic intermediate struct creationiterate()for array-of-structure traversal (supporting[*]semantics)toJSON()/toStruct()serialization and round-trip supportclassName()/classVersion()convenience accessorsvalidate()method delegating to schema cachefromJSON(),fromStruct(),blank()src/did/+did2/+schema/cache.m— Schema cache singleton providing:DID_SCHEMA_PATHor siblingdid-schema/schemas/V_gammacheckout)getClass()for schema lookup with cachingsuperclasses()traversal with cycle detectionfieldsFor,queryablePaths,buildBlankDocument,validateDocument) that throwdid2:notImplementedfor iterative completionCURIE_lookups_meta.jsonsrc/did/+did2/Contents.m— Package overview documenting namespace conventions and planned subpackagestests/+did2/testDocumentScaffold.m— Function-based unit tests covering:Workflow updates — Extended CI/CD to include the
V2branch alongsidemainImplementation Details
get/set) is fully implemented; array iteration via[*]is handled separately throughiterate()to maintain the scalar/array distinctiondid2:document:*,did2:schema:*,did2:notImplemented) to surface incomplete pieces loudly+did2for the scaffold phase, with final naming deferred until v2 reachesmain(PLAN.md §10)https://claude.ai/code/session_013i5twd1zXsZyFXRjb4hbwL