Skip to content

Native OO-LD validator driven by the specification rule catalogue - #114

Open
LukasOro wants to merge 37 commits into
mainfrom
feat/validator-migration
Open

Native OO-LD validator driven by the specification rule catalogue#114
LukasOro wants to merge 37 commits into
mainfrom
feat/validator-migration

Conversation

@LukasOro

@LukasOro LukasOro commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

What

A native Python validation subsystem under src/oold/validation/, replacing use of the reference harness oold-schema/scripts/validate.mjs as a subprocess.

  • 39 checks across 11 families: schema.*, lint.*, context.*, roundtrip.*, generate.*, instance.*, variants, compliance.*, coverage.*, meta.*, and 22 rule.* checks
  • CLI: oold validate (a single file is classified as schema or instance from its $schema), oold validate-instance, oold compliance, oold meta, oold rules, oold checks
  • MCP server exposing the same validation entry points
  • 4 tracked meta-schema versions vendored byte-exact: 0.7.0, 0.8.0, 1.0.0-rc.1, 1.0.0-rc.2

Rationale

  • No Node.js dependency, and no subprocess boundary to marshal results across
  • Resolves @context chains that leave the schema's own directory, which the reference harness cannot do: its loader only maps its own directory
  • One code base validates against several meta-schema versions in a single run

Severity comes from the specification, never from this code

Each rule.* check reports a problem; whether that is a failure or a warning is read from the rule's level in oold-rules.json, the catalogue of numbered normative statements.

  • A rule absent from the selected version's catalogue, or deprecated there, is skipped with a message saying so, rather than checked anyway
  • Versions predating the catalogue skip the whole rule.* family
  • Checks judge the resolved context, not the literal @context, so a schema whose terms arrive through a remote context is not reported as violating them

Meta-schema vendoring

src/oold/validation/meta/<version>/ holds verbatim copies from oold-schema release tags, with a sha256 per file recorded in index.json. Nothing is fetched at runtime for a tracked version, so a released version cannot change meaning between runs. Unreleased upstream state is reachable with --meta remote.

  • Files are stored LF and marked -text in .gitattributes; a CRLF copy hashes differently, passing on Windows and failing on Linux
  • v1.0.0-rc.2 is the first release to ship the catalogue and the first to split the dialect meta-schema into a wrapper plus the base it $refs, so it declares its own file set
  • The fixture slice in tests/data/oold/ is refreshed from the same tag it records in fixtures.tag, so fixtures and meta-schemas never come from different releases

Coupling to oold-schema

The two repositories release on separate schedules, so neither pipeline waits on the other.

  • coverage.rules warns when a catalogued rule has no check, rather than failing, so a specification that has moved ahead cannot break this build
  • Currently 15 of 40 machine-checkable rules have no check: 4 predate OO-LD/oold-schema#124 and 11 arrived with the rules that release added
  • OO-LD/oold-schema#133 has merged, reclassifying OOLD-CMP-a05a as not machine-checkable; it reaches this repository at the next release, since tracked catalogues come from tags

Verification

  • 550 tests pass; make check, make validate and make docs-test exit 0
  • Parity tests assert this port reaches the same verdicts as the reference harness on the same fixtures, including check labels and triple counts: 6/6 with OOLD_SCHEMA_DIR set
  • Each deliberately broken fixture in tests/data/oold/broken/ is mapped to the check it must trip, so the checks are proven to fire rather than only to pass on valid input

Follow-ups

The review raised work deliberately not done here, filed as eleven issues. The order they have to
land in is tracked in #129: three pairs carry a hard
dependency where the reverse order leaves the second one unverifiable.

Nothing there blocks this PR. None of the eleven has a branch or a PR open, and every review
thread and top-level comment here has a reply.

LukasOro added 29 commits July 31, 2026 12:04
- Ports scripts/validate.mjs, pattern_lint.mjs and schema_to_frame.mjs into src/oold/validation/
- Backs the library API, an `oold validate` CLI (aliased `oold-validate`), and an MCP server
- Covers meta-schema, $ref composition, @context lint, RDF round-trip, remote-context and oneOf/anyOf checks, plus the compliance-suite and vocabulary-coverage cross-checks
- Meta-schemas are versioned under src/oold/validation/meta/, seeded from tag v0.7.0
- Parity is checked in tests/test_validation/test_parity_live.py against 98 pinned ajv-format outcomes
- Vendors v0.8.0 into the meta-schema version history; `latest` now resolves to it, 0.7.0 stays
- Refreshes the fixture slice from the same tag
- Excludes vendored meta-schemas and fixtures from pre-commit's pretty-format-json and whitespace fixers, which broke their recorded sha256 checksums
- Adds .gitattributes marking vendored files -text to stop core.autocrlf rewriting line endings
- Splits test_selection_expands_and_deduplicates into three tests pinning selector order, `all` version order, and explicit order
- MetaBundle loads the optional oold-rules.json, exposing rule(), has_rules and checkable_rules()
- Check gains a `rule` field, surfaced in the CLI (--verbose), the JSON report and MCP payloads
- CHECK_RULES maps checks to rules centrally in _Run.add, covering the four checks that enforce a single identifiable requirement
- New `oold rules list|explain` commands (--area, --unchecked) and a list_oold_rules MCP tool
- New coverage.rules check reports checkable rules with no check; it only ever warns
- MUST-level: rule.id (OOLD-VER-001), rule.id-fragment (OOLD-CMP-005), rule.range-ref (OOLD-EXT-005), rule.instance-type (OOLD-INS-002), rule.free-text-iri (OOLD-INS-009), rule.closed-object (OOLD-INS-005)
- SHOULD-level: rule.version (OOLD-VER-002), rule.id-alias (OOLD-INS-007), rule.dialect (OOLD-EXT-002), rule.processing-mode (OOLD-EXT-001)
- Checks are declared in a registry and export their own check-id-to-rule mapping
- Checks judge the resolved context rather than the schema's literal @context
- Takes coverage.rules from 21 of 25 checkable rules unchecked to 11
- Vendors meta-schema 1.0.0-rc.1, the first version to ship oold-rules.json
- Severity now comes from the catalogue; the FAIL/WARN column is removed from the check registry
- A rule absent from the selected version, or marked deprecated, is skipped with the reason given
- Fixes _version_key so pre-releases sort before their release (1.0.0-rc.1 before 1.0.0)
- Fixtures refreshed from the v1.0.0-rc.1 tag
- Seven hand-authored fixtures were CRLF while every fixture copied from an oold-schema tag is LF
- `.gitattributes` marks the fixture directory -text, so mixed endings looked deliberate
- Whitespace only; each file re-parsed and compared to its previous value after conversion
- tests/data/oold/README.md refreshed by copying from upstream to avoid a line-ending diff
- Linked from oold-schema's `make check` whenever the catalogue gains a rule
- Covers `applies_to`, severity coming from the catalogue rather than the check, and judging the resolved context instead of the literal @context
- Documents that verdicts are pinned by parity with the reference harness
- Documents that severity is read from the specification catalogue, not decided by a check
- Documents that vendored meta-schemas are checksummed bytes no formatter or line-ending conversion may touch
- AGENTS.md stays ignored
- Rule ids answer which requirement was violated and are permanent; check ids answer which check found it and follow the implementation
- Replaces an earlier "frozen inventory" proposal that hand-synced a second file of ids
- Verified against what the validator actually emits, and holds function references rather than path strings
- Kept out of docs/, since an unlisted page there is still built and published
- Deletes RULE_CHECKS, RULE_CHECK_MAP and CHECK_RULES in favor of one registry
- CheckInfo absorbs RuleCheck by gaining an optional `run` predicate
- rule_checks.py folds into check_registry.py
- Drops the emitting site from `oold checks explain`
- Gating is by presence in the vendored catalogue; a new rule's check needs no backward-compatibility code
- Four phase checks carry a rule id but were not gated by anything
- New `requires_rule` flag extends catalogue gating to any check, defaulting to off
- `since` cannot serve this purpose: all 34 rules carry since=1.0.0-rc.1, when the catalogue was minted
- A fourth drift test pins the promise
- `requires_rule` is insufficient for a legacy check whose rule is later superseded
- Replaced with `predates_catalog`, which asks what a pre-catalogue version cannot answer
- A rewording changes nothing, a data-driven change (0.8.0's no-coercion rule) is free, only bespoke detection needs a new predicate
- Marginal cost of a changed rule is one registry line
- Lists the full set of check ids; the previous registry missed six ids the validator actually emits
- Fixes the verification command: grepping `rule_checks` also matched `run_rule_checks()`
- Records the `compliance.<kind>` decision as a single normalised `compliance.*` family entry
- Notes `lint.iri-format` has never been observed to fire; drift test 2 should fail on it
- RuleCheck, RULE_CHECKS, RULE_CHECK_MAP and CHECK_RULES collapse into `CheckInfo`
- rule_checks.py folds into check_registry.py
- Purely structural: verdicts, messages and report shape unchanged, confirmed byte-for-byte and by the parity suite
- cli.py, mcp_server.py and two test modules move to importing from the registry
- Every emittable id now has a registry entry, including rule.checks, meta.self-check, compliance.suite and a single compliance.* family entry
- `predates_catalog` decides check behaviour against versions that ship no rule catalogue
- Adds the missing lint.iri-format fixture so the check is actually exercised
- Fixes drift test 4, which previously counted a gated SKIP as a run
- Verdicts unchanged on all three tracked versions, confirmed by diff and the parity suite
- Leaf.schema.json now requires `name`, defined only by the remote Thing context via ../Thing.schema.json
- Leaf's own inline context defines just `nickname`, so a literal-@context check would misreport `name` as undefined
- No new test needed; test_a_context_chain_leaving_the_directory_resolves already asserts the whole report passes
- Pre-existing drift, not introduced here: the line was exactly 120 characters, which failed `make check` on a clean checkout
- MetaBundle.self_check now validates the catalogue against the new oold-rules.schema.json, vendored alongside it
- A truncated or malformed catalogue previously looked like a version stating fewer rules, with checks skipping silently
- Loading stays lenient; the loss is now reported via meta.self-check instead of failing validation
- Fixture slice provenance moves from README prose into index.json; `fixtures.tag` is compared against the newest tracked version by a test
- Re-vendors rc.1's catalogue, which gained only the $schema line upstream
- meta/README.md now lists all five files to copy, including the catalogue and its schema added in 1.0.0-rc.1
- CONTRIBUTING.md now documents `predates_catalog` and its default
- Clarifies that a new rule.* check needs no broken-fixture test but does need a corpus schema that exercises its predicate
- Fixture README no longer states the slice's tag, now recorded in index.json
- Rule ids move to a minted hex suffix (e.g. OOLD-RT-002 -> OOLD-RT-08f2); all 14 registry-cited ids remapped
- `checkable` renamed to `machine_checkable` throughout, including checkable_rules() and the CLI label
- Four new checks: rule.uuid (OOLD-VER-edb9), rule.multilang-default (OOLD-EXT-dd76), rule.base-alignment (OOLD-CMP-53bf), rule.scoped-context (OOLD-CMP-5266)
- rule.scoped-context only flags an embed arriving by $ref to another document, not a self-reference
- Verdicts unchanged; parity holds at 6/6
- rule.instance-type and rule.closed-object previously passed without ever running, found via line coverage over a full corpus run
- New fixtures make each fail exactly the check it targets; closed_object also trips roundtrip.generated
- base_uri_misaligned is registered in the fixture table alongside them, having been added earlier without being listed
- rule.id-alias is left with a known gap: no fixture yet exercises its non-violating path
- Declaring any markdown_extensions replaces Zensical's default set rather than extending it, silently dropping fifteen defaults
- Admonitions in docs/how-to/backends.md, codegen.md, object-graph-mapping.md and rdf-export.md rendered as literal text
- zensical.toml now restates all 22 defaults of the installed 0.0.45
- scripts/check_markdown_extensions.py compares that restatement against the installed Zensical and fails on drift; wired into `make check`, a pre-commit hook, and docs CI
- pymdownx.smartsymbols stays enabled here, unlike oold-schema, since its trigger sequences only appear inside Mermaid fences
- rule.multilang-shape (OOLD-EXT-ef09), rule.dialect-version (OOLD-EXT-af50), rule.context-array-order (OOLD-CMP-e4a3), rule.versioned-id (OOLD-VER-534a)
- rule.context-array-order and rule.versioned-id read the literal @context and the rule's summary respectively, both documented exceptions
- Three fixtures added so rule.versioned-id is actually reached, not just guarded
- Not implemented: OOLD-CMP-a05a, OOLD-INS-9416, OOLD-RT-d376, OOLD-CMP-f3c7, each with a reason recorded in the code
- Verdicts unchanged; parity holds at 6/6
- Refreshes meta/1.0.0-rc.1/oold-rules.json from oold-schema: 40 rules to 43
- Adds OOLD-VER-befc, OOLD-VER-4261 and OOLD-EXT-1f92, split out of lead-in lists upstream
- `oold rules list --unchecked` goes from 7 to 10
- rules_source now records feat/rule-list-scope (oold-schema PR #124, unmerged)
- rule.versioned-id's docstring corrected: it is now explicitly the umbrella over OOLD-VER-befc and OOLD-VER-4261
- rules_source now records the pull request number alongside the repository, branch and pre-merge commit
- A rebased branch orphans a recorded commit; the entry it replaces pointed at exactly such an orphan on feat/rule-catalog-rc1
- Adds a `merged` slot to fill in once #124 lands
- oold-schema splits the dialect meta-schema into a wrapper plus oold-meta-schema-base.json
- `files` in meta/index.json is now per-source via `meta_files(source)`, so only the remote bundle carries the new base file
- Restores parity, which had been failing 4 of 6 because the wrapper's $ref could not resolve
- declared_keywords() now collects x-oold-* across every document in the bundle, restoring all 26 keywords and picking up x-oold-sssom
- Two meta_store tests updated to serve the four-file remote list
- rule.context-reflects-refs (OOLD-CMP-b926) and rule.branch-context-conflict (OOLD-CMP-1d7e); unenforced count 10 to 8
- Both read the authored @context rather than the resolved view, the same exception rule.context-array-order already takes
- rule.branch-context-conflict is narrowed via `entries`, distinguishing an authored override (dict) from a reflected conflict (string)
- OOLD-INS-1df7 deliberately not implemented; it duplicates what rule.free-text-iri already checks
- Both checks produce zero findings on the corpus and needed a broken fixture each to be reached
- rule.narrow-only enforces OOLD-CMP-f3c7; unenforced count 8 to 7
- CheckInfo gains `run_resolved`, letting a check receive the dereferenced schema instead of the authored one
- Ten comparable keywords are checked per member: numeric bounds, length/item/property bounds, multipleOf, enum, const, type, uniqueItems, additionalProperties
- `pattern` and `required` are deliberately excluded, with reasons recorded in the code
- Zero findings across the corpus; parity holds at 6/6
- Vendor 1.0.0-rc.2 as its own entry; rc.1 keeps its pre-release copy
- Declare its own four-file set: the dialect split into wrapper plus base
- Close rc.1's rules_source.merged; refresh fixture slice and fixtures.tag
- Unchecked rules 7 -> 15 of 40: 4 carried over, 11 newly released
- Fix a UI cross-reference test that asserted on an undefined keyword
@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Release preview

Merging this PR would release v0.17.0 (current: v0.16.3).

Changelog preview (truncated)
## v0.17.0 (2026-08-20)

### Bug Fixes

- **cli**: Keep the missing-extra guard on oold-validate
  ([`b4e23ac`](https://github.com/OO-LD/oold-python/commit/b4e23ac96a9bf50b61a6a84300c713025af75e96))

- **docs**: Restate and guard Zensical's default Markdown extensions
  ([`ebc3907`](https://github.com/OO-LD/oold-python/commit/ebc3907cae24a685b78edcd856ca514331148a95))

- **validation**: Count x-oold-context synonyms as mapped terms
  ([`7875b51`](https://github.com/OO-LD/oold-python/commit/7875b51b1e71f5b0fe1565009eef07eab2d8cfff))

- **validation**: Report the keyword coverage.vocab leaves out
  ([`c5d9324`](https://github.com/OO-LD/oold-python/commit/c5d93248b0a13363f58f9beb816121f229d6e9e9))

### Chores

- Ignore the local graphify-out directory
  ([`ef375d3`](https://github.com/OO-LD/oold-python/commit/ef375d379edcb81cb65f627cf5e72fd09b4ec967))

- License fix
  ([`daa8d8c`](https://github.com/OO-LD/oold-python/commit/daa8d8cfa325a3745c851c845b9fae7b5e51a0cc))

- **validation**: Vendor the 43-rule catalogue
  ([`cbcf95a`](https://github.com/OO-LD/oold-python/commit/cbcf95a3042c41078c7b670de4ce77b21db36a31))

### Code Style

- Apply ruff-format to the check-registry drift test
  ([`ca11109`](https://github.com/OO-LD/oold-python/commit/ca1110907aa194b32458cfb90599c4b8a51609b5))

- **tests**: Store the hand-written fixtures with LF line endings
  ([`8c965d6`](https://github.com/OO-LD/oold-python/commit/8c965d6cd3aea4963e709fc05e304e789aa73995))

### Continuous Integration

- **release**: Add whats-changed notes with changelog link for zenodo
  ([`147d70f`](https://github.com/OO-LD/oold-python/commit/147d70fbf1c5da070f3cb9055fbe96e831fe8eaa))

- **release**: Update on title and authors
  ([`996c4de`](https://github.com/OO-LD/oold-python/commit/996c4dee6b4f07b6ec994e87cb341155a12e955c))

### Documentation

- Add CLAUDE.md with the conventions agents keep getting wrong
  ([`4fdda5e`](https://github.com/OO-LD/oold-python/commit/4fdda5e796089c4950437918d212c802b4e2e8b4))

- Explain how to turn a specification rule into a check
  ([`988bc38`](https://github.com/OO-LD/oold-python/commit/988bc38de68724a027268721fad8818786bd5184))

- Fix the vendoring procedure and say what a new check owes
  ([`92524af`](https://github.com/OO-LD/oold-python/commit/92524af7fd721819d8d0874757d23dcfbdc6ba92))

- Move documentation out of source dirs and drop meta-talk
  ([`fc4de8c`](https://github.com/OO-LD/oold-python/commit/fc4de8c944bb4dcb238645b25cc45fb968b29d28))

- **spec**: Collapse the check mappings into one registry structure
  ([`264d71e`](https://github.com/OO-LD/oold-python/commit/264d71e300095719cdfe52c86726fb5bb64888e1))

- **spec**: Correct the version gate, and cost out a changed rule
  ([`08b9945`](https://github.com/OO-LD/oold-python/commit/08b9945ea338c3a261eb08d28e82b2d2b7a062ea))

- **spec**: Design a check registry and an `oold checks` command
  ([`26ceba9`](https://github.com/OO-LD/oold-python/commit/26ceba9c63a9170baaa376c63b039ebfa666a100))

- **spec**: Pin where compatibility for a new rule's check lives
  ([`3ba00a6`](https://github.com/OO-LD/oold-python/commit/3ba00a6ddff0aa3c739f6739ae7b76b1b11ffda2))

- **spec**: State which ids the registry covers, and fix the grep guard
  ([`3b497b5`](https://github.com/OO-LD/oold-python/commit/3b497b586ed1e8b13699263b492a27e1acdb1141))

- **validation**: Record catalogue's source so a rebase cannot orphan it
  ([`5bcd043`](https://github.com/OO-LD/oold-python/commit/5bcd043721226b48280e7980890264df9cdc623b))

### Features

- **validation**: Accept raw JSON in every MCP document tool
  ([`18a952c`](https://github.com/OO-LD/oold-python/commit/18a952c0d9994410d6b3a63e4da7c7bc3ab79762))

Preview via python-semantic-release and conventional commits.

@simontaurus

simontaurus commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Correctness:

  • cli.py:246-251 vs mcp_server.py:292-296 - the area and unchecked filters are applied in opposite orders, so the two front ends already return different results for area + unchecked together. Pull select_rules / select_checks / check_summary into check_registry.py and leave both with formatting only. enforced_by = {v: k for k, v in rule_map().items()} is written three times (cli.py:260, cli.py:295, mcp_server.py:291).
  • meta_store.py - _read_rules distinguishes absent from corrupt; _read_rules_schema ten lines below returns None for both. _catalog_problems then returns [], so a corrupt rules schema disables catalogue validation with nothing reported.

Duplication:

  • roundtrip.py:193-208, instance_checks.py:108-125, compliance.py:310-319 - same to_rdf → count → from_rdf → frame-or-compact sequence three times; "application/n-quads" 9 times. Extract project_and_restore(...).
  • pipeline.py:353-379 _check_variant is a compressed copy of _check_schema_jsonld (266-324).
  • resolve.dereference_and_bound() (resolve.py:498) has no caller; pipeline.py:83-87 and mcp_server.py:197-201 open-code it. Use it or delete it.

Naming and dead code:

  • DEFAULT_MAX_DEPTH is 6 in resolve.py:47 and 40 in context_resolution.py:39, same package. Rename both.
  • Seven to_dict() methods have no caller in src/. Check.line() (report.py:70-73) duplicates the live renderer at cli.py:89-93 and has drifted - width 24 vs 22.
  • RoundtripResult.ok defaults True, InstanceRoundtripResult.ok defaults False; nothing reads either.
  • "https://oo-ld.test/" is both loader.DEFAULT_HOST and compliance.RDF_BASE; SCHEMA_SUFFIX is defined in pipeline.py and context_graph.py; two UUID regexes (check_registry.py:55, formats.py:79-82).

Error handling:

  • ~12 except Exception around this package's own code. roundtrip.py:199-208 wraps embedded_properties() and schema_to_frame(), so a bug in frame.py is reported as a roundtrip.generated FAIL against the user's schema. Narrow to jsonld.JsonLdError / SchemaResolutionError.
  • mcp_server.py:231-234 parses inline JSON with no try and assumes a dict at 249, against a docstring promising errors come back as data.
  • predicates.py:113-121 maps a pyld exception and an unmapped property both to DROPPED. PredicateResult.errors exists for this and is never written, though result.ok reads it.

Length - C901 is in ruff's ignore list, so nothing flags these: compliance._run_tests 126 lines, pipeline._check_schema 92, pipeline._check_schema_jsonld 91, Resolver.dereference 84.

oold-validate is bound straight to cli:validate in pyproject.toml, bypassing the ImportErrorINSTALL_HINT guard that oold has, so without the validation extra it prints a traceback.

- Merge both source-tree READMEs into docs/maintaining-meta-schemas.md
- Make docs/contributing.md canonical; CONTRIBUTING.md and CLAUDE.md are pointers
- Fold specs/2026-08-04-check-registry-design.md into docs/architecture.md
- Drop "reference harness" and validate.mjs framing from 18 modules
- Correct context_resolution.py: an OO-LD schema is a valid remote context
- Parse catalogue entries through a Rule model; a missing or renamed field
  is now rejected at load instead of downgrading every MUST to a warning
- Guard Rule's required fields against the vendored oold-rules.schema.json
- MetaBundle becomes a BaseModel; CheckInfo stays a frozen dataclass
- Type all 9 MCP tool results so clients get a schema, not dict[str, Any]
- Record the boundary/internal convention in docs/architecture.md
- Promote a schema's x-oold-context terms into the resolved context, so a
  property mapped only there is no longer reported dropped or lost
- Never select among several synonyms; profile selection is OOLD-EXT-8f62
- Add x_oold_context/ fixture directory and a test proving both checks pass
- Correct three wrong claims: reference refetching, root JSON-LD keywords,
  and the ajv rationale in formats.py
- Guard VOCAB_PREFIXES against an untracked x- prefix
- validate_oold_instance and check_context_mapping now take a path or raw JSON,
  matching the two tools that already did
- An inline instance and schema materialise into one directory, so the
  instance's $schema reference to its sibling still resolves
- check_context_mapping reads a local context file rather than using the path
  as a literal context value; a non-file string is still used as an IRI
- Lead the install docs with uv, keeping pip as the alternative
- Pin the reference-harness comparison to a v1.0.0-rc.2 permalink
@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.0018s → 0.0018s (-0.3%)
  ➖ test_sqlite_document_store: 0.0019s → 0.0019s (+0.5%)
  ➖ test_local_sparql_store: 0.0423s → 0.0445s (+5.3%)
  ➖ test_oneof_subschema: 0.0654s → 0.0650s (-0.6%)
  ➖ test_enum_docstrings: 0.0573s → 0.0554s (-3.3%)
  ➖ test_subclass_inheritance: 0.0598s → 0.0590s (-1.2%)
  ➖ test_class_hierarchy: 0.0566s → 0.0564s (-0.3%)
  ➖ test_core[v1]: 0.0415s → 0.0434s (+4.4%)
  ➖ test_core[v2]: 0.0488s → 0.0480s (-1.5%)
  ➖ test_schema_generation[v1]: 0.0017s → 0.0017s (-1.2%)
  ➖ test_schema_generation[v2]: 0.0030s → 0.0029s (-2.9%)
  ➖ test_simple_json: 0.0007s → 0.0008s (+11.4%)
  ➖ test_complex_graph: 0.0017s → 0.0017s (-2.2%)

============================================================
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

- 1.0.0-rc.1 declares x-sssom, outside VOCAB_PREFIXES, so it was dropped from
  the count while the report still claimed all keywords covered
- Record exemptions with their reason in VOCAB_EXEMPT and name them in the
  message: "26 covered, 1 exempt: x-sssom (renamed to x-oold-sssom ...)"
- Versions with nothing exempt keep reading "all N keywords covered"
- Guard both directions: an untracked prefix must be named or fail, and a
  stale exemption no version declares must fail
@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.0017s → 0.0017s (+0.1%)
  ➖ test_sqlite_document_store: 0.0019s → 0.0019s (+1.5%)
  ➖ test_local_sparql_store: 0.0397s → 0.0403s (+1.4%)
  ➖ test_oneof_subschema: 0.0595s → 0.0634s (+6.6%)
  ➖ test_enum_docstrings: 0.0498s → 0.0524s (+5.3%)
  ➖ test_subclass_inheritance: 0.0543s → 0.0553s (+1.8%)
  ➖ test_class_hierarchy: 0.0516s → 0.0530s (+2.7%)
  ➖ test_core[v1]: 0.0383s → 0.0404s (+5.5%)
  ➖ test_core[v2]: 0.0445s → 0.0468s (+5.2%)
  ➖ test_schema_generation[v1]: 0.0017s → 0.0017s (+1.5%)
  ➖ test_schema_generation[v2]: 0.0029s → 0.0028s (-1.1%)
  ➖ test_simple_json: 0.0007s → 0.0007s (-1.3%)
  ➖ test_complex_graph: 0.0017s → 0.0017s (+0.2%)

============================================================
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

- oold validate <file> now dispatches on content: a meta-schema or a JSON
  Schema dialect means schema, any other $schema means instance
- --as-schema and --as-instance skip detection; a file with no $schema is
  refused naming both, rather than being validated as the wrong kind
- validate-instance is unchanged and stays the explicit form
- Say in Check's docstring how check ids relate to rule ids
- Replace the stale OOLD-RT-002 example, whose spec link no longer resolves
@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.0017s → 0.0017s (-0.1%)
  ➖ test_sqlite_document_store: 0.0019s → 0.0019s (+0.3%)
  ➖ test_local_sparql_store: 0.0406s → 0.0416s (+2.5%)
  ➖ test_oneof_subschema: 0.0621s → 0.0628s (+1.1%)
  ➖ test_enum_docstrings: 0.0523s → 0.0524s (+0.2%)
  ➖ test_subclass_inheritance: 0.0557s → 0.0555s (-0.4%)
  ➖ test_class_hierarchy: 0.0526s → 0.0524s (-0.5%)
  ➖ test_core[v1]: 0.0396s → 0.0401s (+1.4%)
  ➖ test_core[v2]: 0.0463s → 0.0464s (+0.3%)
  ➖ test_schema_generation[v1]: 0.0017s → 0.0017s (-1.9%)
  ➖ test_schema_generation[v2]: 0.0029s → 0.0029s (-0.4%)
  ➖ test_simple_json: 0.0007s → 0.0007s (-2.1%)
  ➖ test_complex_graph: 0.0017s → 0.0017s (-1.1%)

============================================================
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

@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.0016s → 0.0016s (+0.3%)
  ➖ test_sqlite_document_store: 0.0017s → 0.0017s (-0.4%)
  ➖ test_local_sparql_store: 0.0367s → 0.0377s (+2.9%)
  ➖ test_oneof_subschema: 0.0558s → 0.0568s (+1.8%)
  ➖ test_enum_docstrings: 0.0487s → 0.0480s (-1.5%)
  ➖ test_subclass_inheritance: 0.0513s → 0.0513s (+0.0%)
  ➖ test_class_hierarchy: 0.0485s → 0.0483s (-0.3%)
  ➖ test_core[v1]: 0.0365s → 0.0362s (-0.9%)
  ➖ test_core[v2]: 0.0411s → 0.0415s (+1.1%)
  ➖ test_schema_generation[v1]: 0.0015s → 0.0015s (-1.6%)
  ➖ test_schema_generation[v2]: 0.0026s → 0.0026s (-0.8%)
  ➖ test_simple_json: 0.0006s → 0.0006s (-0.3%)
  ➖ test_complex_graph: 0.0015s → 0.0015s (-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

- oold-validate was bound at oold.validation.cli:validate, so an install
  without the validation extra printed a traceback instead of the hint
- Bind it through a guarded oold.cli:validate_main, as oold already is
- Assert both console scripts route through oold.cli, read from the
  installed metadata so the check covers what is actually shipped
- Lead the install hint with uv, matching the docs
@LukasOro

Copy link
Copy Markdown
Contributor Author

Your two top-level comments went unanswered while the inline threads were being worked through - they are not review threads, so they fell outside the list I was tracking. Answering both now, and filing the parts that had no issue.

#114 (comment)

All three are in #125.

  • parity continue-on-error - open decision, gate it or say in the docs that it is measured and not gated
  • offline defaults to False - open. Your framing of it is the one recorded: the vendored meta-schemas are hermetic on purpose and context resolution then is not
  • _MUST_LEVELS - partly done. Rule now rejects a missing level (5feef83), so a renamed or dropped field no longer downgrades every MUST to a warning. The value case is still open: level: str accepts anything and an unrecognised value still becomes WARN. fix(spec): admit NOT RECOMMENDED as a rule level oold-schema#136 has since merged, so the vocabulary is explicit upstream and can be constrained here once rc.3 is vendored

#114 (comment)

Correctness - both in #125: the area/unchecked filter-order divergence with the select_rules / select_checks / check_summary extraction and the triplicated enforced_by, and _read_rules_schema collapsing absent and corrupt.

Duplication, naming and dead code, length - newly filed as #126. Every item re-verified at b4e23ac rather than carried over, and the line numbers there are current. dereference_and_bound() still has no caller, DEFAULT_MAX_DEPTH is still 6 against 40, "application/n-quads" is written 9 times, and C901 is still in ruff's ignore list over five functions of 84 to 126 lines.

Error handling - newly filed as #127. 12 except Exception across 8 modules. The predicates.py case is worse than it looks: the pyld-failure path and the genuinely-unmapped path both return DROPPED and differ only in the detail string, and PredicateResult.errors is serialised and read in the ok computation but never written, so it cannot affect anything. That matters for #120, where the unmapped case becomes a warning and a processor error has to stay a failure.

oold-validate bypassing the INSTALL_HINT guard - fixed in b4e23ac. It is bound through oold.cli:validate_main now, with the same ImportError guard oold has, and a test reads the installed entry-point metadata so a future rebinding cannot skip it again. The hint also leads with uv now, matching the docs change you asked for.

One more, from a thread rather than from you

On #114 (comment) I wrote that a true-remote fixture was "a separate piece of work" and then did not file it. Now #128: the corpus has 25 same-directory and 6 cross-directory references and zero HTTP ones, so context.remote never actually goes remote, and Resolver's fetch and cache layer has no fixture covering it - which is the layer #119 would move onto referencing.

Follow-up index

Issue Subject
#118 pyld for the context walker
#119 referencing for resolve.py
#120 context.predicates citing a rule about prefixes
#121 jsonschema[format-nongpl]
#122 MCP bundle input
#123 oold meta vendor
#124 line and column positions
#125 the five findings from your first comment plus correctness
#126 duplication, dead code, length
#127 broad exception handling
#128 no true-remote fixture

Your comments on 118, 119, 120, 121 and 122 from yesterday are read; replies belong on those issues rather than here and are still to come. The process_context finding on 118 settles that one against my earlier reading, and 120 now has an agreed resolution waiting on OO-LD/oold-schema#137.

Every inline thread on this PR has a reply, CI is green, and nothing else is outstanding on the branch, so this is ready for another look.

@github-actions

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

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

⚠️  Performance Regressions:
  ❌ test_class_hierarchy: 0.0509s → 0.0714s (+40.4%, ratio: 1.40x)

➖ Unchanged (within threshold):
  ➖ test_simple_dict_document_store: 0.0017s → 0.0017s (+1.5%)
  ➖ test_sqlite_document_store: 0.0019s → 0.0019s (-0.6%)
  ➖ test_local_sparql_store: 0.0388s → 0.0396s (+2.0%)
  ➖ test_oneof_subschema: 0.0599s → 0.0610s (+1.9%)
  ➖ test_enum_docstrings: 0.0500s → 0.0500s (+0.0%)
  ➖ test_subclass_inheritance: 0.0544s → 0.0535s (-1.5%)
  ➖ test_core[v1]: 0.0377s → 0.0384s (+1.9%)
  ➖ test_core[v2]: 0.0434s → 0.0440s (+1.5%)
  ➖ test_schema_generation[v1]: 0.0017s → 0.0017s (+1.5%)
  ➖ test_schema_generation[v2]: 0.0029s → 0.0028s (-1.3%)
  ➖ test_simple_json: 0.0007s → 0.0007s (-0.4%)
  ➖ test_complex_graph: 0.0016s → 0.0016s (+0.4%)

============================================================
Summary: 1 regressions, 0 improvements, 12 unchanged
============================================================

⚠️  Regressions detected but not failing build (informational only)

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

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