spec(ownir): add machine-readable JSON Schema, pinned to code with no new dep#175
Conversation
… new dep OwnIR now has a machine grammar to sit alongside the prose spec (spec/OwnIR.md): spec/ownir.schema.json (JSON Schema draft 2020-12, ownir_version as const:0). It mirrors the contract the Python validator (ownlang/ownir.py::load) enforces — envelope, owned-resource records, flow bodies, DI graph, reactive effects — and is shaped for the P-022 `own-ir` Rust crate to generate serde types from: the flow-op vocabulary is a `oneOf` discriminated on `op`, and the enums (resource kinds, DI lifetimes, param effects) are closed. The schema's trigger has fired: a second language-native type set (the Rust crate in #170) is arriving, so a single source both are generated from stops the two hand-maintained validators from drifting. The core cannot import a jsonschema validator (zero-dependency constraint), so instead of validating documents this binds the schema's *vocabulary* to the code's authoritative sets in tests/test_ownir.py: - resourceKind enum == _KNOWN_RESOURCE_KINDS (the load() routing set) - diLifetime enum == di.LIFETIMES - ownir_version const == OWNIR_VERSION - every flowOp const lowers through _lower_flow without the fail-loud "unknown op" raise; a bogus op the schema omits still raises Schema and validator therefore cannot drift without a red build, no dependency added. Registered in spec/README.md; tech-debt register item 3 updated to shipped. 228/228 bridge checks pass; full suite green.
📝 WalkthroughWalkthroughAdds a JSON Schema ( ChangesOwnIR schema formalization
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 45ac5cc783
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The schema-consistency imports (_KNOWN_RESOURCE_KINDS, DI_LIFETIMES) tripped ruff's import-order check on the PR; merge them into the sorted block.
…inds Three P2 findings from the Codex review on the schema PR: 1. Null resource types. The reference loaders (Python load(), the Rust own-ir parity tests) accept and preserve `"type": null` — load() only rejects a non-null non-string. The schema made `type`/`source_type` string-only, so it (and generated serde types) would reject documents the pipeline accepts. Widen them to ["string","null"] — maps to Option<String>. `source` widened too (load() never constrained it). 2. paramEffect never pinned. The schema advertised a closed paramEffect enum but the drift test jumped straight from diLifetime to flow ops, so it never bound. Extract the effect tuple in load() to a named authority `_PARAM_EFFECTS` and assert schema.paramEffect == it. 3. Flow-op bind was one-directional. The test only proved schema-ops lower; a handled op the schema forgot stayed green. Extract the lowerer's vocabulary to `_FLOW_OPS` (the _lower_flow `else` now distinguishes "declared-but-unhandled" from "unknown vocabulary") and assert schema.flowOp consts == _FLOW_OPS — both directions. The drive-test still lowers every declared op so a phantom set entry fails. Both _FLOW_OPS and _PARAM_EFFECTS now mirror _KNOWN_RESOURCE_KINDS: a named frozenset used by load()/_lower_flow AND bound to the schema by equality, so schema and validator cannot drift either way. 230/230 bridge checks; ruff + mypy --strict + full suite green.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@spec/ownir.schema.json`:
- Around line 85-108: Update the resourceRecord schema to include the missing
fact identifiers event, handler, and lambda alongside the existing
line/released/resource/type/source/source_type fields. Keep them additive and
optional like the other preserved fields so the generated own-ir Rust serde
types round-trip the full subscription/capture facts used in tests. Use
resourceRecord as the anchor in spec/ownir.schema.json so the schema remains the
source of truth for all core identifying fields.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 4e0f50d3-196e-4a1d-81e2-906158633435
📒 Files selected for processing (5)
docs/notes/tech-debt-register.mdownlang/ownir.pyspec/README.mdspec/ownir.schema.jsontests/test_ownir.py
CodeRabbit (Major): the resourceRecord schema omitted the event, handler, and lambda fields that every subscription/timer/capture fact carries — event/handler are core identifying fields (finding messages, rendered output) read as strings via sub.get(), and lambda is the bool flag (ownir.py:2171) marking an un-detachable inline-lambda handler. Without them the schema-generated Rust own-ir serde types would drop the fields and lose round-trip fidelity for real facts, undermining the schema's single-source purpose. Added additive/optional, matching code semantics (event/handler string, lambda bool). 230/230 bridge checks; full suite green.
Что и зачем
Добавляет машинную грамматику OwnIR —
spec/ownir.schema.json(JSON Schema draft 2020-12,ownir_versionкакconst:0) — рядом с прозаической спекойspec/OwnIR.md. Схема зеркалит контракт, который проверяет валидаторownlang/ownir.py::load(), и спроектирована как единый источник, из которого крейтown-ir(P-022, #170) генерирует serde-типы. Ядру нельзя тянутьjsonschema(zero-dependency), поэтому вместо валидации документов тестtests/test_ownir.pyпривязывает словарь схемы к авторитетным множествам в коде — так схема и валидатор не могут разъехаться без красной сборки, без новой зависимости.Тип изменения
Как проверено
python tests/run_tests.py— вся сборка зелёная (ownir: 230/230)ruff check .иmypy(mypy--strictнадownlang) — чистоpython3 -c "import json; json.load(open('spec/ownir.schema.json'))"— схема валидный JSONПривязка схема↔код в тесте:
resourceKind == _KNOWN_RESOURCE_KINDS,diLifetime == di.LIFETIMES,paramEffect == _PARAM_EFFECTS,flowOp consts == _FLOW_OPS(в обе стороны + drive-test лоуэрит каждый op),ownir_version const == OWNIR_VERSION.Связанные issue
Refs #170 (крейт
own-ir— второй набор type-ов, для которого схема станет источником генерации). Closes — none.Чеклист
tests/test_ownir.py)spec/README.md,docs/notes/tech-debt-register.mdп.3 → shipped)spec:,fix:,style:)