feat(spec): x-gts-closed-derivations schema modifier (0.14 draft) - #91
feat(spec): x-gts-closed-derivations schema modifier (0.14 draft)#91AndrejK666 wants to merge 1 commit into
Conversation
An (open) base type may require every derived schema to resolve to a closed content model at its own top level, enforced at registration and in OP#12. Motivated by extensible metadata envelopes: the base stays open and abstract as a derivation anchor, while every derived schema must reject undeclared properties - so a mistyped property fails instance validation instead of being silently accepted. Adds S9.11.4 semantics, keyword/combination tables, S4.4.1 cross-reference; renumbers S9.11.4/5 -> S9.11.5/6. Signed-off-by: Andrej Kuchma <Andrej.Kuchma@constructor.tech>
📝 WalkthroughWalkthroughThe README updates the GTS specification to draft 0.14. It defines ChangesClosed derivations specification
Estimated code review effort: 1 (Trivial) | ~5 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 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.
Actionable comments posted: 4
🤖 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 `@README.md`:
- Line 118: Reorder the release history in README.md so the “0.14 (draft)” entry
appears below “0.13”, preserving the existing entry text and chronological
ordering.
- Line 1759: Update the Evolution note in §4.4 to make the major-version
recommendation conditional: adding a base payload property requires a new MAJOR
version only when it makes the effective accepted-instance set incompatible,
while preserving that optional properties in open models are not necessarily
breaking.
- Around line 1672-1686: Replace broad “every derived schema” wording with
“every directly derived schema” or equivalent immediate-base wording in
README.md lines 1672-1686, including the overview, table, and content-model
guidance; make the same wording correction at README.md line 703. Clarify that
x-gts-closed-derivations applies only when the modified schema is the immediate
base, not to transitive descendants.
- Line 1771: Update the “9.11.6 Registration enforcement” documentation to scope
x-gts-closed-derivations enforcement to schema registration and OP#12 endpoints
(/validate-type-schema and /validate-entity type validation), removing
/validate-instance. Keep each modifier’s enforcement endpoint listed separately.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
| | 0.10 | BREAKING: terminology unified around GTS Type / GTS Instance; rename API fields `schema_id` → `type_id` (also `old_schema_id`/`new_schema_id`/`to_schema_id`/`selected_schema_id_field`); rename API field `is_schema` → `is_type` (type-definition vs instance discriminator); `type_id` MUST be a GTS Type Identifier or `null` — no longer falls back to JSON Schema dialect URL; rename endpoints `/validate-schema` → `/validate-type`, `/schemas` → `/types`; rename OP#12 'Schema vs Schema Validation' → 'Type Derivation Validation'; rename OpenAPI components `ValidateSchemaRequest` → `ValidateTypeRequest`, `SchemaRegister` → `TypeRegister`; rename example directories `examples/**/schemas/` → `examples/**/types/` (file extensions `.schema.json` retained); add Terminology section | | ||
| | 0.11 | Introduce term **GTS Type Schema** as the canonical definition of a GTS Type; remove the standalone `Schema` term from Terminology; rewrite `GTS Type` entry to name the abstract registered entity; rename `GTS Type Registry` → `GTS Registry` (registry now scopes both Type Schemas and well-known Instances). **Conformance tests for reference implementations** also updated: rename API endpoints `/validate-type` → `/validate-type-schema` and `/types` → `/type-schemas`; rename OpenAPI components `TypeRegister` → `TypeSchemaRegister`, `ValidateTypeRequest` → `ValidateTypeSchemaRequest`; rename request field `TypeSchemaRegister.schema` → `TypeSchemaRegister.type_schema`; rename helper `validate_type` → `validate_type_schema`. | | ||
| | 0.12 | BREAKING: reframe GTS Type Schemas as a dialect-agnostic JSON Schema extension; the prior `$defs MUST NOT` and post-Draft-07-keyword restrictions are dropped; derivation compatibility and the finality guard use the chained `$id` alone, `allOf`+`$ref` recommended but not required (ADR-0001). `x-gts-traits-schema` becomes a JSON Schema subschema (object/`true`/`false`); the registry chain-aggregates declarations along the `$id` chain via `allOf` (ADR-0002). Trait completeness is keyed on `x-gts-abstract` and enforced on non-abstract types against the materialized effective traits object (ADR-0003). Trait-value merge follows JSON Merge Patch (RFC 7396); cross-descendant locking moves to standard JSON Schema `const` in `x-gts-traits-schema` (ADR-0004). The four document-level keywords (`x-gts-final`, `x-gts-abstract`, `x-gts-traits-schema`, `x-gts-traits`) MUST appear at the schema top level and are rejected (fail fast) when nested in a subschema (§9.7.1, §9.11). | | ||
| | 0.14 (draft) | Add `x-gts-closed-derivations` schema modifier: an (open) base type may require every derived schema to resolve to a closed content model at its own top level, enforced at registration and in OP#12 (§9.11.4). Motivated by extensible metadata envelopes: open abstract base + mandatory-closed derived schemas keeps payload extension possible while undeclared properties are still rejected at instance validation. | |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Keep the release history chronological.
Move 0.14 (draft) below 0.13. The current order makes the version history ambiguous.
🤖 Prompt for 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.
In `@README.md` at line 118, Reorder the release history in README.md so the “0.14
(draft)” entry appears below “0.13”, preserving the existing entry text and
chronological ordering.
| | **`x-gts-closed-derivations`** | `boolean` | Requires every **derived** schema to resolve to a **closed content model** (§4.4) at its own top level | Open abstract envelope bases (extensible metadata / plugin payloads) | | ||
|
|
||
| **Schema annotation keywords:** Both `x-gts-final` and `x-gts-abstract` have GTS meaning only in JSON Schema documents (documents with `$schema`). In instance documents, fields with these names are ordinary data and have no GTS modifier semantics unless the instance's own JSON Schema assigns constraints to them. | ||
| **Schema annotation keywords:** All three modifiers have GTS meaning only in JSON Schema documents (documents with `$schema`). In instance documents, fields with these names are ordinary data and have no GTS modifier semantics unless the instance's own JSON Schema assigns constraints to them. | ||
|
|
||
| **Allowed values:** The only meaningful value is `true`. If the keyword is absent or set to `false`, it has no effect (the schema behaves normally — both inheritable and instantiable). Implementations MUST reject non-boolean values. | ||
|
|
||
| **Mutual exclusion:** A schema MUST NOT declare both `"x-gts-final": true` and `"x-gts-abstract": true`. This combination is semantically meaningless (a type that can be neither inherited from nor instantiated serves no purpose) and MUST be rejected during schema registration or validation. | ||
| **Mutual exclusion:** A schema MUST NOT declare both `"x-gts-final": true` and `"x-gts-abstract": true`. This combination is semantically meaningless (a type that can be neither inherited from nor instantiated serves no purpose) and MUST be rejected during schema registration or validation. Likewise, a schema MUST NOT declare both `"x-gts-final": true` and `"x-gts-closed-derivations": true` — a final type has no derivations to constrain. `x-gts-abstract` + `x-gts-closed-derivations` is the expected pairing for extensible envelope bases. | ||
|
|
||
| | Modifier combination | Inheritance allowed? | Direct instances allowed? | | ||
| |---|---|---| | ||
| | *(default / neither)* | Yes | Yes | | ||
| | *(default / none)* | Yes | Yes | | ||
| | `x-gts-abstract: true` | Yes | No | | ||
| | `x-gts-final: true` | No | Yes | | ||
| | Both `true` | **INVALID** — MUST be rejected | — | | ||
| | `x-gts-closed-derivations: true` | Yes — derived schemas must be closed | Yes | | ||
| | `x-gts-abstract` + `x-gts-closed-derivations` | Yes — derived schemas must be closed | No | |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Use direct-derivation wording consistently.
The normative rule applies only when the modified type is the immediate base. The overview, table, and content-model guidance say “every derived schema”. Implementers may enforce the rule on grandchildren and reject valid schemas.
README.md#L1672-L1686: replace broad wording with “immediately derived schemas” or “schemas whose immediate base declares the modifier”.README.md#L703-L703: replace “every derived schema” with “every directly derived schema”.
📍 Affects 1 file
README.md#L1672-L1686(this comment)README.md#L703-L703
🤖 Prompt for 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.
In `@README.md` around lines 1672 - 1686, Replace broad “every derived schema”
wording with “every directly derived schema” or equivalent immediate-base
wording in README.md lines 1672-1686, including the overview, table, and
content-model guidance; make the same wording correction at README.md line 703.
Clarify that x-gts-closed-derivations applies only when the modified schema is
the immediate base, not to transitive descendants.
|
|
||
| 5. **No propagation**: Like `x-gts-final`, the modifier applies only to the schema that declares it; a closed derived schema does not implicitly carry it further. | ||
|
|
||
| 6. **Evolution note**: A base declaring this modifier SHOULD keep its own payload level property-free (an *envelope*). In an open content model, adding a base payload property later is not a compatible change (§4.5) — it is a new MAJOR version. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Qualify the compatibility and versioning guidance.
Section §4.4 says that adding an optional property to an open model is not necessarily backward incompatible. A new major version is required only when the effective accepted-instance set becomes incompatible. Replace the absolute wording with conditional guidance.
🤖 Prompt for 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.
In `@README.md` at line 1759, Update the Evolution note in §4.4 to make the
major-version recommendation conditional: adding a base payload property
requires a new MAJOR version only when it makes the effective accepted-instance
set incompatible, while preserving that optional properties in open models are
not necessarily breaking.
| - **Abstract types may declare `x-gts-traits-schema`**: Doing so contributes to the effective trait-schema of descendants; the abstract type itself is not required to provide values. | ||
|
|
||
| #### 9.11.5 Registration enforcement | ||
| #### 9.11.6 Registration enforcement |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 4 'x-gts-closed-derivations|OP#12|OP#6|/validate-type-schema|/validate-instance|/validate-entity' .Repository: GlobalTypeSystem/gts-spec
Length of output: 50384
Scope registration enforcement by endpoint.
The current ?validate=true enforcement list says x-gts-closed-derivations is enforced on /validate-instance. Derivation compatibility belongs to schema registration / OP#12 (/validate-type-schema / /validate-entity type validation); instance validation does not check base-chain derivation. Split the endpoint scope per modifier.
🤖 Prompt for 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.
In `@README.md` at line 1771, Update the “9.11.6 Registration enforcement”
documentation to scope x-gts-closed-derivations enforcement to schema
registration and OP#12 endpoints (/validate-type-schema and /validate-entity
type validation), removing /validate-instance. Keep each modifier’s enforcement
endpoint listed separately.
Summary
Adds a third schema modifier, x-gts-closed-derivations. Declared on a base type (typically an open, abstract envelope), it requires every schema deriving from that base to resolve to a closed content model at its own top level (§4.4: effective additionalProperties: false after $ref/allOf resolution). Enforced at registration (when validation is enabled) and in OP#12 — regardless of how the schema is registered: API, config seeding, or macro-generated.
Motivation
The extensible-envelope pattern (per-tenant metadata, plugin payloads) needs the base open so derived schemas can declare their own payload properties (§3.1). But openness is inherited: if a derived schema is also open, a mistyped property (automation_levl next to a declared automation_level) validates successfully and is silently ignored — defeating server-side validation. §4.4.1 already recommends "closed envelope with designated open containers"; this modifier covers the complementary layout where the base itself is the open derivation anchor, and makes "derived must close its level" a registry-enforced invariant instead of a convention.
Agreed with the account-management/types-registry maintainers as the resolution of the open-envelope discussion (context: derived tenant-metadata schemas could not be registered at all; opening the base was acceptable only if derived schemas are guaranteed closed).
Changes
§9.11 title + intro: three modifiers instead of two.
§9.11.1: keyword table row, combination table (final+closed-derivations → INVALID; abstract+closed-derivations → the expected envelope pairing), mutual-exclusion paragraph.
New §9.11.4 "x-gts-closed-derivations semantics": derivation guard, typical use, why grandchildren need no extra checks (§3.1 blocks additions under a closed parent; re-opening fails §4.1 derivation compatibility — so implementations check only schemas whose immediate base declares the modifier), no propagation, evolution note (base payload stays property-free; a base payload field is a MAJOR bump), top-level placement.
§9.11.4/§9.11.5 renumbered to §9.11.5/§9.11.6; the one cross-reference updated.
§4.4.1: cross-reference from the recommended-pattern discussion.
Version: 0.14 (draft) row + header bump.
Notes for reviewers
The check is deliberately scoped to direct derivations — deeper levels are covered by existing rules (see §9.11.4 item 3), keeping OP#12 cost O(chain).
Conformance tests for OP#12: happy to add to tests/ in this PR or as a follow-up once the wording settles — maintainers' preference?
Reference implementation PR (gts-rust): GlobalTypeSystem/gts-rust#111
Summary by CodeRabbit
x-gts-closed-derivationsmodifier and its effects on schemas, inheritance, validation, registration, and related behaviors.