SOF-8026: extract schema reference graph (graph.json) and lint the corpus - #416
Open
timurbazhirov wants to merge 1 commit into
Open
SOF-8026: extract schema reference graph (graph.json) and lint the corpus#416timurbazhirov wants to merge 1 commit into
timurbazhirov wants to merge 1 commit into
Conversation
Adds a build-time extraction of the schema reference graph into a single graph.json asset, plus a lint over the corpus derived from it. Shared foundation for the Entity Map and the concept docs; the lint has standalone value on its own. - src/js/scripts/buildEntityGraph.ts: walks schema/ sources (never the resolved dist copies, which merge allOf and inline $refs) and classifies every $ref by its innermost enclosing keyword: allOf extends, properties/items contains, oneOf/anyOf variant. - schema/system/entity_graph.json: the ESSE schema graph.json validates against, so the asset describing the schemas is itself described by one. - build_entity_graph.ts: CLI, emitting to --output and exiting non-zero on lint failures. - Lint rules L1-L10: unresolvable $refs, $id convention, total layer classification, edge-kind classification, JSON-pointer existence, manifest schemaId resolution and cycles all fail; isolated-node growth and example coverage warn. - Runs on every pull request via npm test, not only at deploy. The layer taxonomy is total by contract: an unclassifiable path fails the lint, so a new top-level directory forces a deliberate decision. The former 123-schema 'other' bucket resolves into 106 entity-components and 17 application-parsing schemas. Corrects the recorded baseline: the planning walker counted same-document $refs as edges. There are 917 cross-schema edges (372 extends, 375 contains, 170 variant) plus 20 same-document refs, and 144 edges carry a JSON pointer. The regenerated pydantic models include unrelated class-numbering churn in five files: datamodel-codegen numbers generated classes globally, so adding a schema shifts them. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014ANArWM4ehvsXKNzQpQgx1
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.
Ticket: SOF-8026 · Epic: SOF-8025
Plan:
plan/review/2026-08-16-entity-graph-foundation.mdChained onto #415 — review that first; this PR's diff is against
epic/SOF-8025.Extracts the schema reference graph into a single
graph.jsonasset and derives a lint over the corpus from it. Shared foundation for the Entity Map and the concept docs — but the lint stands on its own, and already catches a class of breakage nothing checked before.What it does
src/js/scripts/buildEntityGraph.tswalks the source schemas (never the resolved copies underdist, which mergeallOfand inline$refs — exactly the structure being recorded) and classifies every$refby its innermost enclosing keyword:allOfitemextendsproperties.<name>oritemscontains(labelled with the property name)oneOf/anyOfvariantThe enclosing property name travels with the reference regardless of kind, so the 42-way union under
property/holder'sdatafield is recorded as variants ofdatarather than as unlabelled edges.Lint rules
Failures exit non-zero; warnings are reported. Runs on every pull request via
npm test, not only at deploy.$refresolves to a schema$idmatches thesetSchemaIdspath convention$refclassifies to an edge kindmanifest/properties.yamlschemaIdresolvesgraph.jsonvalidates against its own ESSE schemaL5 and L6 cover breakage that was previously silent: a manifest entry pointing at a schema that does not exist, or a
$reffragment that does not resolve, would have gone unnoticed.Verified by deliberately breaking each on a scratch branch:
The layer taxonomy is total
An unclassifiable path is a failure, so adding a top-level directory forces a deliberate decision rather than silently landing in a catch-all. The planning pass had left a 123-schema
otherbucket; it resolves exactly as predicted — 106 entity-components (keyed byownerEntity) and 17 application-parsing schemas.Correction to the recorded baseline
The planning walker counted same-document
$refs (#/…) as edges. They are not edges between schemas. The real figures:The difference is exactly those 20 refs.
plan/context/…-schema-graph-measurements.mdrecords the correction;tests/js/entityGraph.tests.tspins the numbers so they cannot drift silently.Notes for the reviewer
publishedPathis not always the source path.properties_directory/non-scalar/…publishes asnon_scalar, because the id round-trip turns dashes into underscores. Both paths are carried on each node — the GitHub link needs one, the Explorer link the other. For the same reasonschemaIdToPublishedPathhas no pure inverse; the module exportsbuildPublishedPathIndex(nodes)and the round-trip is tested over every node.meta.generatedAtwas dropped in favour of determinism — output is byte-identical across runs, so diffs of the published asset are reviewable.metainstead carries counts worth having.datamodel-codegennumbers generated classes globally (Units277→Units276), so adding any schema shifts them. No behaviour change.graph.jsonis 503 KB, larger than the plan's 150 KB estimate — still one fetch, still comfortably client-side.Testing
tests/js/entityGraph.tests.ts— 15 cases: lint-clean assertion, node/edge/layer baselines, edge-kind partition, same-document refs never becoming self-edges, known relationships (materialextendsnamed-defaultable;modelcontainsmethod; theproperty/holderunion), manifest flags, published-path round-trip, degree consistency, byte-identical determinism, self-schema validation, and pointer/classification unit tests.🤖 Generated with Claude Code
Generated by Claude Code