Skip to content

Commit 9cca9ee

Browse files
authored
Merge pull request #77 from aviator5/adr-derivation-form
ADRs: types derivation & x-gts-traits-schema & x-gts-traits changes
2 parents c01f956 + a25de85 commit 9cca9ee

13 files changed

Lines changed: 4929 additions & 357 deletions

README.md

Lines changed: 82 additions & 60 deletions
Large diffs are not rendered by default.

adr/0001-derivation-form.md

Lines changed: 255 additions & 0 deletions
Large diffs are not rendered by default.

adr/0002-x-gts-traits-schema.md

Lines changed: 288 additions & 0 deletions
Large diffs are not rendered by default.

adr/0003-x-gts-traits-completeness.md

Lines changed: 294 additions & 0 deletions
Large diffs are not rendered by default.

adr/0004-x-gts-traits-merge-strategy.md

Lines changed: 525 additions & 0 deletions
Large diffs are not rendered by default.

examples/events/types/gts.x.core.events.type.v1~x.commerce.orders.order_placed.v1.0~.schema.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@
88
{
99
"type": "object",
1010
"required": ["type", "payload", "subjectType"],
11-
"x-gts-traits": {
12-
"topicRef": "gts.x.core.events.topic.v1~x.commerce._.orders.v1",
13-
"retention": "P90D"
14-
},
1511
"properties": {
1612
"type": {
1713
"const": "gts.x.core.events.type.v1~x.commerce.orders.order_placed.v1.0~",
@@ -33,5 +29,9 @@
3329
}
3430
}
3531
}
36-
]
32+
],
33+
"x-gts-traits": {
34+
"topicRef": "gts.x.core.events.topic.v1~x.commerce._.orders.v1",
35+
"retention": "P90D"
36+
}
3737
}

examples/events/types/gts.x.core.events.type.v1~x.commerce.orders.order_placed.v1.1~.schema.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@
88
{
99
"type": "object",
1010
"required": ["type", "payload", "subjectType"],
11-
"x-gts-traits": {
12-
"topicRef": "gts.x.core.events.topic.v1~x.commerce._.orders.v1",
13-
"retention": "P90D"
14-
},
1511
"properties": {
1612
"type": {
1713
"const": "gts.x.core.events.type.v1~x.commerce.orders.order_placed.v1.1~",
@@ -34,5 +30,9 @@
3430
}
3531
}
3632
}
37-
]
33+
],
34+
"x-gts-traits": {
35+
"topicRef": "gts.x.core.events.topic.v1~x.commerce._.orders.v1",
36+
"retention": "P90D"
37+
}
3838
}

examples/events/types/gts.x.core.events.type.v1~x.core.idp.contact_created.v1~.schema.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@
99
{
1010
"type": "object",
1111
"required": ["type", "payload", "subjectType"],
12-
"x-gts-traits": {
13-
"topicRef": "gts.x.core.events.topic.v1~x.core.idp.contacts.v1",
14-
"retention": "P365D"
15-
},
1612
"properties": {
1713
"type": {
1814
"const": "gts.x.core.events.type.v1~x.core.idp.contact_created.v1.0~",
@@ -35,5 +31,9 @@
3531
}
3632
}
3733
}
38-
]
34+
],
35+
"x-gts-traits": {
36+
"topicRef": "gts.x.core.events.topic.v1~x.core.idp.contacts.v1",
37+
"retention": "P365D"
38+
}
3939
}

tests/helpers/http_run_helpers.py

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
def register(gts_id, schema_body, label="register schema"):
1111
"""Register a schema via POST /entities."""
1212
body = {
13+
**schema_body,
1314
"$$id": gts_id,
1415
"$$schema": "http://json-schema.org/draft-07/schema#",
15-
**schema_body,
1616
}
1717
return Step(
1818
RunRequest(label)
@@ -28,7 +28,23 @@ def register_derived(gts_id, base_ref, overlay, label="register derived", top_le
2828
2929
top_level: optional dict of extra keys to add at schema top level
3030
(e.g. {"x-gts-final": True}) — these MUST NOT go inside allOf.
31+
32+
The document-level GTS keywords x-gts-traits / x-gts-traits-schema MUST
33+
appear at the schema top level, not nested inside an allOf entry
34+
(GTS spec §9.12). If a caller places them in the `overlay`, they are
35+
transparently hoisted to the top level so existing trait tests express
36+
the spec-correct placement without restating every call site.
3137
"""
38+
overlay = dict(overlay)
39+
trait_kws = ("x-gts-traits", "x-gts-traits-schema")
40+
hoisted = {kw: overlay.pop(kw) for kw in trait_kws if kw in overlay}
41+
if top_level:
42+
clobbered = [kw for kw in trait_kws if kw in top_level]
43+
if clobbered:
44+
raise ValueError(
45+
"top_level must not contain trait keywords "
46+
f"{clobbered}; pass them in `overlay` so they are hoisted"
47+
)
3248
body = {
3349
"$$id": gts_id,
3450
"$$schema": "http://json-schema.org/draft-07/schema#",
@@ -38,6 +54,7 @@ def register_derived(gts_id, base_ref, overlay, label="register derived", top_le
3854
overlay,
3955
],
4056
}
57+
body.update(hoisted)
4158
if top_level:
4259
body.update(top_level)
4360
return Step(
@@ -49,6 +66,58 @@ def register_derived(gts_id, base_ref, overlay, label="register derived", top_le
4966
)
5067

5168

69+
def register_derived_redeclared(
70+
gts_id, base_ref, body, label="register derived (no allOf)", top_level=None
71+
):
72+
"""Register a derived schema without allOf — caller restates parent fields directly.
73+
74+
Per ADR-0001 (GTS as a JSON Schema extension, dialect-agnostic; not a formal
75+
JSON Schema Dialect), derivation is established by the chained $id alone;
76+
the body MAY use any syntactically valid JSON Schema form.
77+
`base_ref` is accepted for parity with register_derived() and documents intent.
78+
79+
`body` is the entire schema body (caller is responsible for restating any
80+
parent fields that need to participate in OP#12 compatibility). The helper
81+
only injects $id and $schema; no allOf wrapping is added.
82+
top_level: optional dict merged into body at the top level.
83+
"""
84+
full = {
85+
**body,
86+
"$$id": gts_id,
87+
"$$schema": "http://json-schema.org/draft-07/schema#",
88+
}
89+
if top_level:
90+
full.update(top_level)
91+
return Step(
92+
RunRequest(label)
93+
.post("/entities")
94+
.with_json(full)
95+
.validate()
96+
.assert_equal("status_code", 200)
97+
)
98+
99+
100+
def register_abstract(gts_id, schema_body, label="register abstract"):
101+
"""Register a schema marked x-gts-abstract: true.
102+
103+
Per ADR-0003, abstract types skip the trait-completeness check at
104+
/validate-type-schema time.
105+
"""
106+
body = {
107+
**schema_body,
108+
"$$id": gts_id,
109+
"$$schema": "http://json-schema.org/draft-07/schema#",
110+
"x-gts-abstract": True,
111+
}
112+
return Step(
113+
RunRequest(label)
114+
.post("/entities")
115+
.with_json(body)
116+
.validate()
117+
.assert_equal("status_code", 200)
118+
)
119+
120+
52121
def register_instance(instance_body, label="register instance"):
53122
"""Register an instance via POST /entities."""
54123
return Step(

0 commit comments

Comments
 (0)