Skip to content

fix(frame): reverse IRI grouping, $ref embeds and default type anchors - #179

Merged
simontaurus merged 3 commits into
mainfrom
fix/schema-to-frame-reverse-and-refs
Nov 15, 2026
Merged

simontaurus merged 3 commits into
mainfrom
fix/schema-to-frame-reverse-and-refs

Conversation

@simontaurus

@simontaurus simontaurus commented Nov 15, 2026 •

Copy link
Copy Markdown
Contributor

Three defects in schema_to_frame, one commit and one regression test each.

  • #175 is_embed counts a $ref, and reference_properties drops anything embedded_properties claims. Reference subframes are written first, embedded ones second, so a property both signals claim keeps {} instead of being overwritten with {"@embed": "@never"} and losing its nested keys. A $ref is the only trace of an embed before dereferencing, while the "@type": "@id" OO-LD requires on such a term makes it look reference-valued at the same time.
  • #176 Reverse-mapped properties move from their term name to @reverse, keyed by the reverse IRI as the term writes it (new helper reverse_predicates). Two terms on one reverse IRI expanded to two subframes under that IRI, which pyld rejects with invalid frame. This changes the derived frame for every reverse term, not only colliding ones; for a single term both forms frame to the same document, checked on the Organization/worksFor shape. Derived frames carry no sub-properties, so the expanded-IRI constraint recorded in the issue does not arise.
  • #177 instance_rdf_types falls back to properties.type.default where x-oold-instance-rdf-type is absent, read before the allOf walk because a schema's own spelling is nearer than an inherited one. Without that anchor the first backwards edge degenerates the framed result to @graph.

#175 is a 2.x regression, from #164 and #155 interacting rather than from either alone, and an open range such as oold[validation]>=0.20 resolves to it today. #176 and #177 are present on 0.18.1 and 0.19.0 as well.

Tests 800 passed / 10 skipped / 1 xfailed before, 804 / 10 / 1 after; each new test was confirmed to fail on the unfixed code. make check and make validate pass.

is_embed now counts a $ref, and the reference subframes are written
before the embedded ones, so a property both signals claim keeps the
empty subframe that preserves its nested keys.

Fixes #175
Reverse-mapped properties are written under @reverse and keyed by their
reverse IRI, so two terms naming the same relation no longer expand to
two subframes under it, which a processor rejects as an invalid frame.

Fixes #176
instance_rdf_types falls back to properties.type.default where
x-oold-instance-rdf-type is absent, so a schema using that spelling
still frames to its root instead of degenerating to @graph.

Fixes #177
@github-actions

Copy link
Copy Markdown
Contributor

Release preview

Merging this PR would release v2.3.1 (current: v2.3.0).

Changelog preview (truncated)
## v2.3.1 (2026-11-15)

### Bug Fixes

- **frame**: Anchor the frame on a type pinned as a default
  ([`fa22022`](https://github.com/OO-LD/oold-python/commit/fa220221e48feb83c26879748c317457d2484012))

- **frame**: Keep a $ref-valued embed out of the reference list
  ([`a7ac1d1`](https://github.com/OO-LD/oold-python/commit/a7ac1d1d153719258fb299c3f706a58238bbe9c4))

- **frame**: One reverse subframe per IRI, not per term
  ([`74a3adf`](https://github.com/OO-LD/oold-python/commit/74a3adf44fb647aa544c7432c0e5fd78f44949c1))

### Documentation

- **controller**: Name controller members for what they do
  ([`648018f`](https://github.com/OO-LD/oold-python/commit/648018fc480934b5b5185c6d0702860392e90c25))

Preview via python-semantic-release and conventional commits.

@github-actions

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

Click to see benchmark comparison
📊 Benchmark Comparison (threshold: 1.3x)
============================================================

➖ Unchanged (within threshold):
  ➖ test_simple_dict_document_store: 0.0014s → 0.0014s (+0.5%)
  ➖ test_sqlite_document_store: 0.0015s → 0.0015s (-0.3%)
  ➖ test_local_sparql_store: 0.0281s → 0.0286s (+1.8%)
  ➖ test_oneof_subschema: 0.0523s → 0.0473s (-9.6%)
  ➖ test_enum_docstrings: 0.0399s → 0.0506s (+26.8%)
  ➖ test_subclass_inheritance: 0.0437s → 0.0469s (+7.5%)
  ➖ test_class_hierarchy: 0.0391s → 0.0413s (+5.5%)
  ➖ test_core[v1]: 0.0284s → 0.0266s (-6.4%)
  ➖ test_core[v2]: 0.0340s → 0.0366s (+7.8%)
  ➖ test_schema_generation[v1]: 0.0012s → 0.0012s (+1.9%)
  ➖ test_schema_generation[v2]: 0.0027s → 0.0027s (-0.7%)
  ➖ test_simple_json: 0.0004s → 0.0004s (-2.1%)
  ➖ test_complex_graph: 0.0011s → 0.0011s (-0.8%)

============================================================
Summary: 0 regressions, 0 improvements, 13 unchanged
============================================================

✅ No significant performance regressions

Threshold: 1.3x (30% slower triggers a regression warning)

Note: Benchmarks are informational only and won't fail the build.

💡 Tip: Download the benchmark-results artifact for detailed JSON data

@codecov

codecov Bot commented Nov 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.18919% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/oold/validation/frame.py 89.1% 2 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

@simontaurus
simontaurus merged commit 9b69eb1 into main Nov 15, 2026
21 checks passed
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.

1 participant