You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(spec): adopt shallow last-wins merge for x-gts-traits and add ADR-0004
- Replace immutable-once-set rule in README §9.7 with shallow descendant-last-wins merge along the $id chain.
- Lean on standard JSON Schema 'const' in x-gts-traits-schema as the publisher's lock mechanism; no GTS-specific immutability rule.
- Refresh worked example to show natural override plus const-based lock.
- Add ADR-0004 documenting drivers, alternatives (no-merge, immutable-once-set, RFC 7396, per-property keyword), decision, and conformance expectations.
Signed-off-by: Aviator 5 <ai.agent.tor@gmail.com>
Copy file name to clipboardExpand all lines: README.md
+10-8Lines changed: 10 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1506,23 +1506,25 @@ Given an inheritance chain `S₀ → S₁ → … → Sₙ`:
1506
1506
-**Immutable defaults:**`default` values declared in an ancestor's `x-gts-traits-schema` MUST NOT be changed by a descendant's `x-gts-traits-schema`. If a descendant redeclares a trait property with a different `default`, schema validation MUST fail.
1507
1507
1508
1508
-**Trait value merge**
1509
-
- The registry MUST build an *effective traits object* by collecting all `x-gts-traits` objects encountered in the chain (left-to-right).
1510
-
-**Immutable-once-set:** Once a trait key is assigned a concrete value by a schema in the chain, **no descendant may override it**. If a descendant's `x-gts-traits` provides a different value for a key already set by an ancestor, schema validation MUST fail. Providing the **same** value is permitted (idempotent).
1511
-
- Defaults declared in the effective trait schema SHOULD be used as normal JSON Schema defaults to produce a complete effective traits object.
1509
+
- The registry MUST build an *effective traits object* by walking the type's `$id` chain root → leaf and applying each layer's `x-gts-traits` via shallow object assignment: for any top-level key declared at multiple layers, the value from the layer closer to the type wins (descendant-last-wins). Object-valued traits are replaced wholesale; nested fields of an ancestor's object trait are not preserved when a descendant declares the same top-level key. Authors who want per-field composability SHOULD model traits as separate top-level properties rather than as nested objects.
1510
+
- Defaults declared in the effective trait-schema SHOULD be applied (per ADR-0003 materialization) for top-level keys not present in the chain-merged object.
1511
+
- A publisher who wants a trait value to be **locked** across all descendants of a base type SHOULD declare `"const": <value>` for that property in `x-gts-traits-schema`. A descendant attempting to override the value will fail the standard JSON Schema validation that runs against the effective trait-schema (per the Completeness check below). No GTS-specific "immutability" rule is required — `const` is the mechanism.
1512
+
- A descendant MAY redeclare a trait value with the same value the ancestor already declared (idempotent restatement).
1513
+
- See [`adr/0004-x-gts-traits-merge-strategy.md`](adr/0004-x-gts-traits-merge-strategy.md) for the rationale.
1512
1514
1513
1515
-**Validation**
1514
1516
-**Completeness check** (registration-time): For types whose `x-gts-abstract` is not `true`, the registry MUST verify that the *materialized* effective traits object validates against the effective trait-schema using standard JSON Schema validation. "Materialized" means: defaults declared in the effective trait-schema for properties not present in the chain-merged effective traits object are substituted in before validation. If validation fails — in particular, if a `required` property of the effective trait-schema has no chain-assigned value and no default — registration MUST fail. For types with `x-gts-abstract: true`, this completeness check is skipped; descendants are expected to close any unresolved required traits. See [`adr/0003-x-gts-traits-completeness.md`](adr/0003-x-gts-traits-completeness.md) for the rationale.
1515
1517
- If the effective trait schema cannot be satisfied (e.g., contradictory constraints introduced across the chain), schema validation MUST fail.
1516
-
- If a descendant attempts to override a trait value already set by an ancestor with a different value, schema validation MUST fail.
1517
1518
1518
-
**Example — immutable trait override (failure):**
1519
+
**Example — descendant override and `const` lock:**
1519
1520
1520
1521
Consider a 3-level chain: `base → audit_event → most_derived_event`.
1521
1522
1522
-
-`audit_event` sets `x-gts-traits.topicRef` to `gts.x.core.events.topic.v1~x.core._.audit.v1`
1523
-
-`most_derived_event` attempts to set `x-gts-traits.topicRef` to `gts.x.core.events.topic.v1~x.core._.notification.v1`
1523
+
-`base.x-gts-traits-schema.properties.indexed.const = true` — the publisher locks `indexed`.
Validation of `most_derived_event` MUST fail because `topicRef`was already set by `audit_event` and the new value differs.
1527
+
Effective traits for `most_derived_event`: `{ "indexed": <chain-derived true>, "topicRef": ".../notification.v1" }`. The override of `topicRef`is permitted (last-wins). If `most_derived_event` also tried to set `"indexed": false`, registration would fail — not because of a GTS-specific immutability rule, but because the materialized effective traits object would not satisfy the `const: true` constraint declared on `indexed` in the effective trait-schema.
1526
1528
1527
1529
These rules are intentionally aligned with existing JSON Schema composition semantics and GTS schema chaining practices.
0 commit comments