legion-platform-contracts 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. legion_platform_contracts-0.2.0/.gitignore +26 -0
  2. legion_platform_contracts-0.2.0/PKG-INFO +136 -0
  3. legion_platform_contracts-0.2.0/README.md +108 -0
  4. legion_platform_contracts-0.2.0/contracts/entities/README.md +119 -0
  5. legion_platform_contracts-0.2.0/contracts/entities/entity-id.schema.json +10 -0
  6. legion_platform_contracts-0.2.0/contracts/entities/entity-provenance.schema.json +40 -0
  7. legion_platform_contracts-0.2.0/contracts/entities/entity.schema.json +68 -0
  8. legion_platform_contracts-0.2.0/contracts/provenance/inference-provenance.md +51 -0
  9. legion_platform_contracts-0.2.0/contracts/provenance/inference-provenance.schema.json +87 -0
  10. legion_platform_contracts-0.2.0/contracts/seams/seam-a-harvester-compendium.md +141 -0
  11. legion_platform_contracts-0.2.0/contracts/seams/seam-a-reference-bundle.schema.json +145 -0
  12. legion_platform_contracts-0.2.0/contracts/seams/seam-a-reference-type-mapping.json +48 -0
  13. legion_platform_contracts-0.2.0/contracts/seams/seam-b-association-event.schema.json +246 -0
  14. legion_platform_contracts-0.2.0/contracts/seams/seam-b-compendium-bodega.md +90 -0
  15. legion_platform_contracts-0.2.0/contracts/seams/seam-b-identity-op-log.md +119 -0
  16. legion_platform_contracts-0.2.0/contracts/seams/seam-b-identity-op-log.schema.json +292 -0
  17. legion_platform_contracts-0.2.0/contracts/seams/seam-b-two-log-consumer.md +78 -0
  18. legion_platform_contracts-0.2.0/contracts/seams/seam-c-erasure-consumer.md +81 -0
  19. legion_platform_contracts-0.2.0/contracts/seams/seam-c-erasure-event.schema.json +190 -0
  20. legion_platform_contracts-0.2.0/contracts/seams/seam-c-erasure-propagation.md +91 -0
  21. legion_platform_contracts-0.2.0/contracts/storage/storage-adapter-dtos.schema.json +185 -0
  22. legion_platform_contracts-0.2.0/contracts/storage/storage-adapter-spi.md +181 -0
  23. legion_platform_contracts-0.2.0/contracts/tck/README.md +176 -0
  24. legion_platform_contracts-0.2.0/contracts/tokens/dragons-attestation-profile.md +224 -0
  25. legion_platform_contracts-0.2.0/contracts/tokens/dragons-capability-token-profile.md +91 -0
  26. legion_platform_contracts-0.2.0/contracts/tokens/dragons-delegation-claim-schema.schema.json +52 -0
  27. legion_platform_contracts-0.2.0/contracts/tokens/token-issuer-contract.md +89 -0
  28. legion_platform_contracts-0.2.0/contracts/tokens/token-issuer-dtos.schema.json +70 -0
  29. legion_platform_contracts-0.2.0/pyproject.toml +142 -0
  30. legion_platform_contracts-0.2.0/src/platform_contracts/__init__.py +23 -0
  31. legion_platform_contracts-0.2.0/src/platform_contracts/_generate_models.py +79 -0
  32. legion_platform_contracts-0.2.0/src/platform_contracts/authz.py +206 -0
  33. legion_platform_contracts-0.2.0/src/platform_contracts/egress.py +279 -0
  34. legion_platform_contracts-0.2.0/src/platform_contracts/errors.py +240 -0
  35. legion_platform_contracts-0.2.0/src/platform_contracts/models.py +229 -0
  36. legion_platform_contracts-0.2.0/src/platform_contracts/provenance.py +105 -0
  37. legion_platform_contracts-0.2.0/src/platform_contracts/spi.py +150 -0
  38. legion_platform_contracts-0.2.0/src/platform_contracts/tck/__init__.py +0 -0
  39. legion_platform_contracts-0.2.0/src/platform_contracts/tck/_dragons.py +141 -0
  40. legion_platform_contracts-0.2.0/src/platform_contracts/tck/_resources.py +75 -0
  41. legion_platform_contracts-0.2.0/src/platform_contracts/tck/association_consumer.py +306 -0
  42. legion_platform_contracts-0.2.0/src/platform_contracts/tck/conftest.py +98 -0
  43. legion_platform_contracts-0.2.0/src/platform_contracts/tck/erasure_consumer.py +264 -0
  44. legion_platform_contracts-0.2.0/src/platform_contracts/tck/erasure_producer.py +205 -0
  45. legion_platform_contracts-0.2.0/src/platform_contracts/tck/identity_log.py +556 -0
  46. legion_platform_contracts-0.2.0/src/platform_contracts/tck/reference_adapter.py +257 -0
  47. legion_platform_contracts-0.2.0/src/platform_contracts/tck/status_resolver.py +159 -0
  48. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_egress.py +296 -0
  49. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_entities.py +442 -0
  50. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_erasure_consumer.py +414 -0
  51. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_goodstanding.py +82 -0
  52. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_query_spec_validation.py +126 -0
  53. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_schemas.py +160 -0
  54. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_seam_a.py +195 -0
  55. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_seam_b.py +577 -0
  56. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_seam_b_identity_log.py +713 -0
  57. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_seam_c.py +468 -0
  58. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_spi_no_backend_type_leak.py +93 -0
  59. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_status_resolver.py +216 -0
  60. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_storage_security.py +158 -0
  61. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_storage_vector.py +168 -0
  62. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_tokens.py +120 -0
  63. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_tokens_audience.py +290 -0
  64. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_tokens_dragons.py +465 -0
  65. legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_two_log_consumer.py +849 -0
  66. legion_platform_contracts-0.2.0/src/platform_contracts/tck/two_log_consumer.py +616 -0
  67. legion_platform_contracts-0.2.0/src/platform_contracts/tck/vectors/PROVENANCE.md +10 -0
  68. legion_platform_contracts-0.2.0/src/platform_contracts/tck/vectors/authorize.vectors.json +3912 -0
  69. legion_platform_contracts-0.2.0/src/platform_contracts/tck/vectors/goodstanding.vectors.json +971 -0
@@ -0,0 +1,26 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ .venv/
5
+ venv/
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .mypy_cache/
9
+ .ruff_cache/
10
+
11
+ # Env / secrets
12
+ .env
13
+ *.local
14
+
15
+ # OS / editor
16
+ .DS_Store
17
+ *.swp
18
+
19
+ # Generated binding provenance artifact (regenerate via src/platform_contracts/_generate_models.py).
20
+ # The curated, committed binding is src/platform_contracts/models.py; this raw generator output carries
21
+ # a non-deterministic timestamp header, so it stays out of version control (ADR-0018 §3: schema is
22
+ # authoritative, bindings are generated-from).
23
+ src/platform_contracts/_generated_models.py
24
+
25
+ # build artifacts (the published index artifact carries the canonical bytes)
26
+ dist/
@@ -0,0 +1,136 @@
1
+ Metadata-Version: 2.5
2
+ Name: legion-platform-contracts
3
+ Version: 0.2.0
4
+ Summary: Legion platform authoritative shared cross-component contracts (schemas, storage SPI, token profile, TCK). Decided by farm-to-table ADR-0015; wire format pinned by ADR-0018.
5
+ Project-URL: Homepage, https://github.com/legion-os-dragons/farm-to-table-platform-contracts
6
+ Project-URL: Source, https://github.com/legion-os-dragons/farm-to-table-platform-contracts
7
+ Project-URL: Changelog, https://github.com/legion-os-dragons/farm-to-table-platform-contracts/blob/main/CHANGELOG.md
8
+ Author: Legion platform
9
+ License: proprietary
10
+ Keywords: conformance,contracts,json-schema,storage-spi,tck
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Software Development :: Quality Assurance
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.11
19
+ Requires-Dist: pydantic>=2.6
20
+ Provides-Extra: codegen
21
+ Requires-Dist: datamodel-code-generator>=0.25; extra == 'codegen'
22
+ Provides-Extra: dragons
23
+ Requires-Dist: legion-foundation==0.1.1; extra == 'dragons'
24
+ Provides-Extra: tck
25
+ Requires-Dist: jsonschema>=4.20; extra == 'tck'
26
+ Requires-Dist: pytest>=8.0; extra == 'tck'
27
+ Description-Content-Type: text/markdown
28
+
29
+ # platform-contracts
30
+
31
+ **`platform-contracts`** is the Legion platform's **authoritative, design-tree-owned home for the
32
+ shared cross-component contracts** — the artifacts that bind *across* two or more of the platform's
33
+ repositories and are therefore owned by no single component. It holds the **inter-component seam
34
+ schemas** (Seams A, B, C), the **Bodega↔Spire storage-adapter SPI**, the **platform capability-token
35
+ (dragons) capability-token profile + issuer contract**, and the **conformance TCK spec** every consumer's adapter must
36
+ pass.
37
+
38
+ This package was decided by **`farm-to-table` ADR-0015** (*"Cross-repo coordination — the
39
+ platform-contracts package and the amendment return-seam"*, Accepted 2026-06-29). It is the resolution
40
+ of ADR-0012 §3's open question — where the shared storage-adapter SPI + TCK should live — in favor of a
41
+ dedicated, neutral, versioned package that both consumers pin.
42
+
43
+ It was stood up on **2026-06-30** from the Legion platform design tree (`../farm-to-table`).
44
+
45
+ ## The one thing to understand first: this repo is design-tree-owned, not downstream-owned
46
+
47
+ This is the load-bearing distinction, and it differs from the Bodega / Spire / Kitchen build-repo
48
+ seeds (which say *"you author your own build ADRs here"*). Here:
49
+
50
+ - **The contract SHAPES are authoritative in this repo.** `contracts/` holds the platform-owned,
51
+ versioned truth for each seam schema, the storage SPI, the token profile, and the TCK. Consumers
52
+ read these; they do not fork them.
53
+ - **Contract CHANGES do not originate here.** They come from **`../farm-to-table` ADRs**. A
54
+ downstream repo that discovers, at build time, that a contract must change **proposes** the change
55
+ via the **amendment return-seam** (ADR-0015 §2): it drops a `contract-amendment-proposal` into the
56
+ design tree's `bionic/inbox/`. The design tree disposes — authoring a council-gated amending ADR, or
57
+ declining with a recorded rationale. **No downstream repo ever edits a contract in this repo
58
+ directly.** See `inbox/README.md` (this repo's copy of the return-seam target) and `VERSIONING.md`.
59
+ - **The per-repo IMPLEMENTATIONS live in the consuming repos, not here.** Bodega and Spire each
60
+ implement the storage-adapter SPI behind the port; the Harvester implements the Seam A producer;
61
+ the Compendium implements the Seam B/C producer; Bodega implements the Seam B/C consumer. This repo
62
+ is the **contract + the conformance TCK**, never the implementations (ADR-0015 §1; ADR-0013 §2).
63
+
64
+ If you want to *change* a contract, you are in the wrong repo — go to `../farm-to-table` and file
65
+ an amendment proposal. If you want to *conform to* or *read* a contract, you are in the right place.
66
+
67
+ ## What this package homes (ADR-0015 §1, ADR-0016, ADR-0017)
68
+
69
+ ```
70
+ contracts/
71
+ seams/
72
+ seam-a-harvester-compendium.md # Harvester → Compendium reference contract (ADR-0016 §2 Seam A)
73
+ seam-b-compendium-bodega.md # Compendium → Bodega association-event stream (ADR-0032)
74
+ seam-c-erasure-propagation.md # erasure propagation (ADR-0017 Seam C)
75
+ storage/
76
+ storage-adapter-spi.md # the Bodega↔Spire storage-adapter SPI (ADR-0012 §3, ADR-0015 §1)
77
+ tokens/
78
+ dragons-capability-token-profile.md # the platform dragons capability-token profile (ADR-0021; dev-draft per ADR-0023)
79
+ token-issuer-contract.md # the platform capability-token issuer contract (ADR-0015 §1, ADR-0012 §3)
80
+ tck/
81
+ README.md # the conformance TCK spec (ADR-0012 §2/§3, ADR-0015 §3, ADR-0016, ADR-0017)
82
+ ```
83
+
84
+ Everything in `contracts/` is **versioned as one artifact** on the package's semver line
85
+ (`VERSIONING.md`) and derived from the ADRs copied into `seed/adrs/` for provenance.
86
+
87
+ ## Semver + version-pinning + the return-seam, in one paragraph
88
+
89
+ `platform-contracts` is **semver-versioned** (starting at `0.1.0` — see `CHANGELOG.md`). Every consumer
90
+ repo **version-pins** it (an exact pin, opted into per release — ADR-0015 §1). The TCK version **travels
91
+ with the contract version — one artifact, one version** (ADR-0012 §3; ADR-0015 acceptance criterion 5),
92
+ so pinning a `platform-contracts` version pins both the contract shapes and the conformance tests
93
+ against them. A consumer that needs a contract to change does **not** edit it here — it files a
94
+ `contract-amendment-proposal` back to the design tree (the **amendment return-seam**, ADR-0015 §2); the
95
+ design tree authors the amending ADR (council-gated) and cuts a new `platform-contracts` release, which
96
+ the consumer then re-pins. Full mechanics: `VERSIONING.md`.
97
+
98
+ ## How a consumer pins and conforms (the consumer's-eye view)
99
+
100
+ 1. **Pin a version** of `platform-contracts` (exact, per `VERSIONING.md`).
101
+ 2. **Implement your side** of each relevant contract in your own repo, behind the port — no backend
102
+ type leaks through the SPI (ADR-0012 §1; ADR-0009 §1).
103
+ 3. **Wire the shared TCK as a CI gate** (`contracts/tck/README.md`) — Bodega and Spire both run the
104
+ *same* storage TCK; Seam B/C consumers run the ordering/idempotency/equivalence-class tests.
105
+ 4. **To change the contract:** file a `contract-amendment-proposal` to `../farm-to-table/bionic/inbox/`
106
+ (never edit `contracts/` here). Re-pin when the amending release ships.
107
+
108
+ ## Where to start
109
+
110
+ 1. **`AGENTS.md`** — orientation for anyone (human or agent) turning these specs into a real versioned
111
+ package: the design-tree-owned nuance, the invariants, the recommended stack, and the build cycle.
112
+ **Read first.**
113
+ 2. **`VERSIONING.md`** — the semver policy, breaking-vs-additive rules, the amendment return-seam
114
+ mechanics, and how consumers pin.
115
+ 3. **`contracts/`** — the authoritative contract specs themselves.
116
+ 4. **`seed/adrs/`** — provenance copies of the founding binding ADRs (the source of truth
117
+ lives in `../farm-to-table/bionic/adrs/`; these are provenance copies).
118
+
119
+ ## The wire format is pinned
120
+
121
+ `farm-to-table` **ADR-0018** (Accepted 2026-06-30) pins the canonical wire format to **JSON Schema
122
+ (draft 2020-12)**: the schema wins on any data-shape disagreement; behavior (cross-field rules,
123
+ refusal predicates) lives in the executable TCK. The specs in `contracts/` pair each prose contract
124
+ with its `.schema.json`; new surfaces follow the same pattern (see `AGENTS.md` §build cycle).
125
+
126
+ ## Layout
127
+
128
+ ```
129
+ README.md What it is, why (ADR-0015), the discipline, how consumers pin
130
+ AGENTS.md Orientation + the design-tree-owned nuance + invariants + stack + build cycle + open decisions
131
+ VERSIONING.md Semver policy + amendment return-seam mechanics + consumer pinning
132
+ CHANGELOG.md Starts at 0.1.0 (initial contract set)
133
+ contracts/ The authoritative, versioned contract artifacts (seams, storage SPI, tokens, TCK)
134
+ seed/adrs/ Provenance copies of the founding binding ADRs (source of truth is ../farm-to-table/bionic)
135
+ inbox/ The return-seam target: downstream contract-amendment-proposals land here
136
+ ```
@@ -0,0 +1,108 @@
1
+ # platform-contracts
2
+
3
+ **`platform-contracts`** is the Legion platform's **authoritative, design-tree-owned home for the
4
+ shared cross-component contracts** — the artifacts that bind *across* two or more of the platform's
5
+ repositories and are therefore owned by no single component. It holds the **inter-component seam
6
+ schemas** (Seams A, B, C), the **Bodega↔Spire storage-adapter SPI**, the **platform capability-token
7
+ (dragons) capability-token profile + issuer contract**, and the **conformance TCK spec** every consumer's adapter must
8
+ pass.
9
+
10
+ This package was decided by **`farm-to-table` ADR-0015** (*"Cross-repo coordination — the
11
+ platform-contracts package and the amendment return-seam"*, Accepted 2026-06-29). It is the resolution
12
+ of ADR-0012 §3's open question — where the shared storage-adapter SPI + TCK should live — in favor of a
13
+ dedicated, neutral, versioned package that both consumers pin.
14
+
15
+ It was stood up on **2026-06-30** from the Legion platform design tree (`../farm-to-table`).
16
+
17
+ ## The one thing to understand first: this repo is design-tree-owned, not downstream-owned
18
+
19
+ This is the load-bearing distinction, and it differs from the Bodega / Spire / Kitchen build-repo
20
+ seeds (which say *"you author your own build ADRs here"*). Here:
21
+
22
+ - **The contract SHAPES are authoritative in this repo.** `contracts/` holds the platform-owned,
23
+ versioned truth for each seam schema, the storage SPI, the token profile, and the TCK. Consumers
24
+ read these; they do not fork them.
25
+ - **Contract CHANGES do not originate here.** They come from **`../farm-to-table` ADRs**. A
26
+ downstream repo that discovers, at build time, that a contract must change **proposes** the change
27
+ via the **amendment return-seam** (ADR-0015 §2): it drops a `contract-amendment-proposal` into the
28
+ design tree's `bionic/inbox/`. The design tree disposes — authoring a council-gated amending ADR, or
29
+ declining with a recorded rationale. **No downstream repo ever edits a contract in this repo
30
+ directly.** See `inbox/README.md` (this repo's copy of the return-seam target) and `VERSIONING.md`.
31
+ - **The per-repo IMPLEMENTATIONS live in the consuming repos, not here.** Bodega and Spire each
32
+ implement the storage-adapter SPI behind the port; the Harvester implements the Seam A producer;
33
+ the Compendium implements the Seam B/C producer; Bodega implements the Seam B/C consumer. This repo
34
+ is the **contract + the conformance TCK**, never the implementations (ADR-0015 §1; ADR-0013 §2).
35
+
36
+ If you want to *change* a contract, you are in the wrong repo — go to `../farm-to-table` and file
37
+ an amendment proposal. If you want to *conform to* or *read* a contract, you are in the right place.
38
+
39
+ ## What this package homes (ADR-0015 §1, ADR-0016, ADR-0017)
40
+
41
+ ```
42
+ contracts/
43
+ seams/
44
+ seam-a-harvester-compendium.md # Harvester → Compendium reference contract (ADR-0016 §2 Seam A)
45
+ seam-b-compendium-bodega.md # Compendium → Bodega association-event stream (ADR-0032)
46
+ seam-c-erasure-propagation.md # erasure propagation (ADR-0017 Seam C)
47
+ storage/
48
+ storage-adapter-spi.md # the Bodega↔Spire storage-adapter SPI (ADR-0012 §3, ADR-0015 §1)
49
+ tokens/
50
+ dragons-capability-token-profile.md # the platform dragons capability-token profile (ADR-0021; dev-draft per ADR-0023)
51
+ token-issuer-contract.md # the platform capability-token issuer contract (ADR-0015 §1, ADR-0012 §3)
52
+ tck/
53
+ README.md # the conformance TCK spec (ADR-0012 §2/§3, ADR-0015 §3, ADR-0016, ADR-0017)
54
+ ```
55
+
56
+ Everything in `contracts/` is **versioned as one artifact** on the package's semver line
57
+ (`VERSIONING.md`) and derived from the ADRs copied into `seed/adrs/` for provenance.
58
+
59
+ ## Semver + version-pinning + the return-seam, in one paragraph
60
+
61
+ `platform-contracts` is **semver-versioned** (starting at `0.1.0` — see `CHANGELOG.md`). Every consumer
62
+ repo **version-pins** it (an exact pin, opted into per release — ADR-0015 §1). The TCK version **travels
63
+ with the contract version — one artifact, one version** (ADR-0012 §3; ADR-0015 acceptance criterion 5),
64
+ so pinning a `platform-contracts` version pins both the contract shapes and the conformance tests
65
+ against them. A consumer that needs a contract to change does **not** edit it here — it files a
66
+ `contract-amendment-proposal` back to the design tree (the **amendment return-seam**, ADR-0015 §2); the
67
+ design tree authors the amending ADR (council-gated) and cuts a new `platform-contracts` release, which
68
+ the consumer then re-pins. Full mechanics: `VERSIONING.md`.
69
+
70
+ ## How a consumer pins and conforms (the consumer's-eye view)
71
+
72
+ 1. **Pin a version** of `platform-contracts` (exact, per `VERSIONING.md`).
73
+ 2. **Implement your side** of each relevant contract in your own repo, behind the port — no backend
74
+ type leaks through the SPI (ADR-0012 §1; ADR-0009 §1).
75
+ 3. **Wire the shared TCK as a CI gate** (`contracts/tck/README.md`) — Bodega and Spire both run the
76
+ *same* storage TCK; Seam B/C consumers run the ordering/idempotency/equivalence-class tests.
77
+ 4. **To change the contract:** file a `contract-amendment-proposal` to `../farm-to-table/bionic/inbox/`
78
+ (never edit `contracts/` here). Re-pin when the amending release ships.
79
+
80
+ ## Where to start
81
+
82
+ 1. **`AGENTS.md`** — orientation for anyone (human or agent) turning these specs into a real versioned
83
+ package: the design-tree-owned nuance, the invariants, the recommended stack, and the build cycle.
84
+ **Read first.**
85
+ 2. **`VERSIONING.md`** — the semver policy, breaking-vs-additive rules, the amendment return-seam
86
+ mechanics, and how consumers pin.
87
+ 3. **`contracts/`** — the authoritative contract specs themselves.
88
+ 4. **`seed/adrs/`** — provenance copies of the founding binding ADRs (the source of truth
89
+ lives in `../farm-to-table/bionic/adrs/`; these are provenance copies).
90
+
91
+ ## The wire format is pinned
92
+
93
+ `farm-to-table` **ADR-0018** (Accepted 2026-06-30) pins the canonical wire format to **JSON Schema
94
+ (draft 2020-12)**: the schema wins on any data-shape disagreement; behavior (cross-field rules,
95
+ refusal predicates) lives in the executable TCK. The specs in `contracts/` pair each prose contract
96
+ with its `.schema.json`; new surfaces follow the same pattern (see `AGENTS.md` §build cycle).
97
+
98
+ ## Layout
99
+
100
+ ```
101
+ README.md What it is, why (ADR-0015), the discipline, how consumers pin
102
+ AGENTS.md Orientation + the design-tree-owned nuance + invariants + stack + build cycle + open decisions
103
+ VERSIONING.md Semver policy + amendment return-seam mechanics + consumer pinning
104
+ CHANGELOG.md Starts at 0.1.0 (initial contract set)
105
+ contracts/ The authoritative, versioned contract artifacts (seams, storage SPI, tokens, TCK)
106
+ seed/adrs/ Provenance copies of the founding binding ADRs (source of truth is ../farm-to-table/bionic)
107
+ inbox/ The return-seam target: downstream contract-amendment-proposals land here
108
+ ```
@@ -0,0 +1,119 @@
1
+ # Canonical entity schemas (ADR-0030)
2
+
3
+ - **Contract version:** tracks the `platform-contracts` git ref (ADR-0023 §2); the package-version pin
4
+ returns at phase exit.
5
+ - **Source ADRs:** `farm-to-table` **ADR-0030** (*Canonical entity DTO schemas*, Accepted 2026-07-22 —
6
+ the foundational convergence cut; amends ADR-0016's prose boundary), **ADR-0031** (*Golden-record
7
+ derivation model — occurrence-derived, not event-injected*, Accepted 2026-07-22; amends ADR-0030),
8
+ **ADR-0018** (the canonical wire format these are emitted in), **ADR-0015 §2** (the amendment
9
+ return-seam any change rides).
10
+ - **Cut:** A1 (2026-08-02), the first Phase A realization cut; `entity.schema.json` + its legs landed in
11
+ the A1 completion pass (2026-08-04).
12
+
13
+ ## What's here
14
+
15
+ | Artifact | Pins | Source |
16
+ |---|---|---|
17
+ | `entity-id.schema.json` | The canonical **`EntityId`**: opaque string, `pattern: ^ent_[A-Za-z0-9_-]+$`, `maxLength: 64`. **Contractual:** pattern + length. **Not contractual:** the mint method. Only Compendium mints (ADR-0016). | ADR-0030 §1 |
18
+ | `entity.schema.json` | The canonical **entity DTO** — **seam payloads ONLY**: `{ scope{account_id, project_id}, entity_id (referenced `EntityId`), cluster_state?, resolution_confidence? }`, `additionalProperties: false`. Carries identity + resolver-owned **entity/cluster-level** metadata and **no attribute values**. | ADR-0030 §2 + ADR-0031 §2 (SB-0/SB-6) |
19
+ | `entity-provenance.schema.json` | **`provenance`-of-the-assertion**: `{ source, extractor_id?, extractor_version? }` — `source` required enum; extractor pair required iff `source == "extraction"`, forbidden otherwise; `additionalProperties: true` (additive-safe). | ADR-0030 §3 (SB-8) |
20
+
21
+ ### What the entity DTO deliberately does NOT carry
22
+
23
+ - **No attribute values** (ADR-0031 §2). Gold is **occurrence-derived**: the store composes
24
+ golden-record attribute content from the occurrences it has ingested; a resolution event never
25
+ injects values. `additionalProperties: false` closes the door at the schema layer; the **fail-closed
26
+ hard reject** of a non-empty value injection is behavioral (ADR-0018 §2 — schema pins shapes, the TCK
27
+ pins behavior). Attribute **survivorship** across occurrences is Bodega's (ADR-0013, per ADR-0031
28
+ §2a) — this contract carries the association, never its resolution.
29
+ - **No evidence associations.** Those ride the Seam B association event
30
+ (`../seams/seam-b-association-event.schema.json`, ADR-0032). The **stream mechanics** — delta shape,
31
+ snapshot/reconcile, merge/split transfer, the pending-ref bound, the `ref` namespace — are ADR-0031
32
+ §2b's forward-scoped deliverables (landed in A2/A3): **cited here, not re-opened.**
33
+ - **No provenance envelope.** `provenance` (ADR-0030 §3) is provenance-of-the-**assertion** — a
34
+ property of the *event* that asserts, not of the entity identity, so it rides the assert body.
35
+ `InferenceProvenance` is **prohibited outright** (ADR-0025 AC-2: gold-spine content envelopes only —
36
+ never a Seam A/B/C payload, never an SPI DTO).
37
+ - **Resolver-owned metadata is allowed, at the entity/cluster scope only** (ADR-0031 §2): overall
38
+ `resolution_confidence` + `cluster_state`. The bound is **influence, not authorship** — a consumer
39
+ may weight survivorship by confidence, but the metadata door is never a soft path to authoring a
40
+ value. **Edge**-scoped metadata (per-`(entity_id, ref)` match rationale) rides the association
41
+ event's `AddedRef`, not this DTO.
42
+
43
+ ## The boundary principle (ADR-0030 §2 — read this before adding a schema)
44
+
45
+ A shape is platform-canonical **iff it crosses a platform seam** (judged on real exposure — public API,
46
+ persisted interchange artifact, event payload, shared TCK fixture — not repo ownership). Canonical
47
+ here: `EntityId`, the `provenance` sub-shape, and (in `contracts/seams/`) the lineage-event bodies.
48
+ **Repo-internal, deliberately NOT schematized:** golden-record storage layouts, derivation substrates,
49
+ projections, resolve-output shapes — per ADR-0030 §2/AC-3, the sweep's "no golden-record/projection/
50
+ resolve-output schema" is **correct and intended**, with one escape hatch: if any such shape is ever
51
+ exposed across a component boundary, it becomes a seam contract and is schematized **then** (via the
52
+ ADR-0015 return-seam), never by accretion.
53
+
54
+ ## What this fixes (the sweep items closed)
55
+
56
+ The signed-off convergence sweep (`BRIEF-seam-bc-entity-convergence-sweep`, ADR-0026 §2) found four
57
+ items this directory discharges:
58
+
59
+ - **SB-0 / B0 — no canonical entity DTO existed (ADR-0030 §2):** only the Seam B lineage event was
60
+ schematized, so entity shapes drifted freely across repos. `entity.schema.json` is now the canonical
61
+ seam-crossing entity shape. The same finding's *other* half is closed by **naming shapes out**: the
62
+ golden-record / projection / resolve-output shapes are **repo-internal, correct and intended, not a
63
+ gap to fill** (ADR-0030 §2/AC-3 — Option B rejected). See the boundary principle above.
64
+ - **SB-3 / B1 — the id live break (ADR-0030 §1):** Compendium mints `ent_<uuid4hex>`; Bodega typed
65
+ `entity_id` as `uuid.UUID` and could not ingest a real id. The contract is now: validate against the
66
+ pattern at the boundary, **never parse structure**. (Bodega's migration — drop the cast and any
67
+ UUID-typed persisted key columns — rides the design tree's B1 pack.)
68
+ - **SB-6 / SB-7 — the derivation inversion (ADR-0031 §2):** the two sides of Seam B held *opposite*
69
+ handling of the same field — the schema/Compendium read `attributes` as values **Bodega folds in**,
70
+ while Bodega (ADR-0005 D5, as built) **rejects** injected values and composes gold from ingested
71
+ occurrences. Settled on the principled side: **occurrence-derived**. `attributes` is redefined →
72
+ `evidence_refs` (associations, not values), and a non-empty value injection is a **fail-closed hard
73
+ reject** — ADR-0031 §2 disambiguates D5's "ignored"-vs-"rejected" prose to a hard reject, which **may
74
+ require a Bodega code change**; Bodega's current behavior is **not** ratified as conformant here, its
75
+ conformance is its own cycle's finding. The DTO's contribution is structural: it admits no
76
+ attribute-shaped field at all.
77
+ - **SB-8 — provenance unschematized (ADR-0030 §3):** `entity_assert.provenance` was `type: object` with
78
+ no pinned shape; Compendium's actual carrier (`extractor_id`, `extractor_version`) is now typed and
79
+ conditionally scoped (required iff `source == "extraction"`, forbidden otherwise).
80
+
81
+ And the enforcement that keeps them closed:
82
+
83
+ - **Anti-drift (ADR-0030 AC-7):** seam schemas `$ref` the canonical `EntityId`, never re-declare
84
+ `type: string` inline — enforced mechanically by the lint in
85
+ `src/platform_contracts/tck/test_entities.py`, which is proven to *fire* on inline re-declarations in
86
+ every position one could hide (top-level, nested, inside `allOf`/`anyOf`/`oneOf`, inside an array's
87
+ `items`). The legacy exemption allowlist is **empty** and shrink-only (all seam re-cuts landed:
88
+ A2 association, A3 identity-op log, A4 Seam C).
89
+
90
+ ### What is deferred (scope discipline)
91
+
92
+ - **Provenance-of-derivation-inputs is not on the wire at all.** Per ADR-0031 the event carries ID-only
93
+ pointers; occurrence-granularity inputs (span / offset / source-document) live in Bodega's ingested
94
+ occurrence substrate, which the store already holds.
95
+ - **Stream mechanics** stay with the Seam B wire-shape/TCK work (ADR-0031 §2b, realized in A2/A3) —
96
+ cited, not re-opened here.
97
+ - **`InferenceProvenance`** is prohibited on every shape in this directory (ADR-0025 AC-2: gold-spine
98
+ content envelopes only — enforced by the `$ref`-scoping lint in `test_egress.py`).
99
+
100
+ ## TCK
101
+
102
+ `src/platform_contracts/tck/test_entities.py` (`pytest -m entities`):
103
+
104
+ - **`EntityId`** — round-trip opacity (an `ent_`-prefixed non-UUID-parseable value round-trips; a
105
+ well-formed **bare UUID fails** — the Bodega bug class), pattern/length boundaries, non-string
106
+ rejection, and **mint-method agnosticism** (structurally unrelated suffixes all validate and the
107
+ schema declares no structure-pinning keyword — pinning the mint would collapse
108
+ validate-at-boundary into parse-structure).
109
+ - **The entity DTO** — identity-only acceptance, full-tenancy requirement, id validation *through* the
110
+ canonical `$ref` (resolved offline), the **value-injection bar** (`attributes` / `name` /
111
+ `golden_record` / `canonical_values` / `evidence_refs` all inadmissible), and the two provenance
112
+ prohibitions (`inference_provenance`, and assertion `provenance` — an event property, not an entity
113
+ one).
114
+ - **The §2 boundary tripwire** — no `entity-resolve-output` / `entity-projection` / `golden-record`
115
+ schema is shipped. Retiring that leg requires the ADR-0015 return-seam (the "becomes canonical if
116
+ exposed" hatch), not a local edit.
117
+ - **Provenance** — the conditional-requirement matrix + additive-openness.
118
+ - **AC-7** — the schema-reference lint plus its has-teeth fixture and the empty-allowlist freeze
119
+ tripwire.
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://legion.platform/contracts/entities/entity-id.schema.json",
4
+ "title": "EntityId — the canonical opaque platform entity identifier",
5
+ "$comment": "platform-contracts; canonical wire format JSON Schema draft 2020-12 (ADR-0018 §1). Source: farm-to-table ADR-0030 §1 (canonical entity-identity schema, Accepted 2026-07-22), amending ADR-0016's prose. Distributed by git ref during the pre-first-release iteration phase (ADR-0023 §2). CONTRACTUAL: the pattern (the ent_ prefix + the bounded character class) and the length bound — entity_id is a join key / PK across >=2 stores, so bounding it is free pre-prod. NOT CONTRACTUAL: the generation method (currently Compendium's uuid4().hex) — Compendium may change how it mints the suffix as long as the result still matches the pattern (ADR-0030 §1). MINT AUTHORITY (ADR-0016, unchanged): only Compendium mints an entity_id; external identifiers (LEI/CUSIP/...) are evidence, never the key. OPACITY (ADR-0030 §1): every consumer treats the value as an opaque string — never UUID-typed, never structurally interpreted; boundary pattern-validation is permitted (validate-at-boundary != parse-structure). REFERENCE RULE (ADR-0030 AC-7): Seam B and Seam C schemas $ref this type rather than re-declaring 'type: string' inline — enforced by the anti-drift lint in the TCK (test_entities.py).",
6
+ "type": "string",
7
+ "pattern": "^ent_[A-Za-z0-9_-]+$",
8
+ "maxLength": 64,
9
+ "description": "Opaque platform entity id. Validate against the pattern at the seam boundary; never parse or depend on the suffix structure. Examples: 'ent_surv_001', 'ent_9f3ab2c1d4e5f60718293a4b5c6d7e8f' (a uuid4 hex suffix — opaque, NOT UUID-typed)."
10
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://legion.platform/contracts/entities/entity-provenance.schema.json",
4
+ "title": "EntityAssertionProvenance — provenance-of-the-assertion (source-discriminated)",
5
+ "$comment": "platform-contracts; canonical wire format JSON Schema draft 2020-12 (ADR-0018 §1). Source: farm-to-table ADR-0030 §3 (SB-8; Accepted 2026-07-22). Distributed by git ref (ADR-0023 §2). Pins provenance-OF-THE-ASSERTION (who/what produced this entity_assert event): 'source' is REQUIRED and enum-discriminated; the extractor pair is REQUIRED iff source == 'extraction' and FORBIDDEN otherwise (additive-safe: merge/split/curation/backfill/migration origins carry no extractor id, so no assert is forced to fabricate one). additionalProperties is TRUE (additive-open) per ADR-0030 §3. SCOPE BOUNDARY: provenance-of-the-derivation-inputs (occurrence-granularity refs — span / offset / source-document) is NOT here and NOT on the wire — per ADR-0031 the event carries ID-only pointers and those occurrence-granularity inputs live in Bodega's ingested occurrence substrate; the two are orthogonal (event origin vs. the evidence a consumer folds in). PROHIBITED here: InferenceProvenance (ADR-0025 AC-2 — $ref'd by the gold-spine content envelopes ONLY; never on Seam A/B/C event payloads or SPI DTOs).",
6
+ "type": "object",
7
+ "required": ["source"],
8
+ "additionalProperties": true,
9
+ "properties": {
10
+ "source": {
11
+ "enum": ["extraction", "merge", "split", "curation", "backfill", "migration"],
12
+ "description": "Origin of the assertion. Covers the merge/split and human/tooling origins that have no extractor identity."
13
+ },
14
+ "extractor_id": {
15
+ "type": "string",
16
+ "description": "Extractor identity — REQUIRED iff source == 'extraction'; FORBIDDEN otherwise."
17
+ },
18
+ "extractor_version": {
19
+ "type": "string",
20
+ "description": "Extractor version — REQUIRED iff source == 'extraction'; FORBIDDEN otherwise."
21
+ }
22
+ },
23
+ "allOf": [
24
+ {
25
+ "if": {
26
+ "properties": { "source": { "const": "extraction" } },
27
+ "required": ["source"]
28
+ },
29
+ "then": { "required": ["extractor_id", "extractor_version"] },
30
+ "else": {
31
+ "not": {
32
+ "anyOf": [
33
+ { "required": ["extractor_id"] },
34
+ { "required": ["extractor_version"] }
35
+ ]
36
+ }
37
+ }
38
+ }
39
+ ]
40
+ }
@@ -0,0 +1,68 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://legion.platform/contracts/entities/entity.schema.json",
4
+ "title": "Entity — the canonical entity DTO (seam payloads ONLY)",
5
+ "$comment": "platform-contracts; canonical wire format JSON Schema draft 2020-12 (ADR-0018 §1). Source: farm-to-table ADR-0030 §2 (the entity-shape boundary, Accepted 2026-07-22; amends ADR-0016's prose) + ADR-0031 §2 (the occurrence-derived derivation model + the value-vs-metadata bar, Accepted 2026-07-22). Distributed by git ref during the pre-first-release iteration phase (ADR-0023 §2). Cut A1 (2026-08-02). SCOPE — SEAM PAYLOADS ONLY: a shape is platform-canonical iff it crosses a platform seam, judged on real exposure (public API / persisted interchange artifact / event payload / shared TCK fixture), never on repo ownership (ADR-0030 §2). This DTO is the seam-crossing entity: tenancy + the referenced canonical EntityId + resolver-owned entity/cluster-level metadata. NOT CANONICAL, deliberately NOT schematized here (ADR-0030 §2/AC-3 — the sweep's B0 is 'correct and intended, not a gap to fill'; schematizing them is Option B, REJECTED): Bodega's golden-record storage layout and its segment/occurrence derivation substrate, Compendium's entity_projection / redirect-graph internals, and Compendium's EntityResolveResult / resolve-output. TRIGGER (the narrow escape hatch): if any such repo-internal shape is ever exposed across a component boundary it BECOMES a seam contract and is schematized THEN, via the ADR-0015 §2 amendment return-seam — never by accretion here. NO ATTRIBUTE VALUES (ADR-0031 §2): gold is OCCURRENCE-DERIVED — the store composes golden-record attribute content from the occurrences it has ingested; a resolution event never injects attribute values. Anything Bodega would store as a golden-record ATTRIBUTE is a value and is barred; the schema layer closes the door with additionalProperties:false, and the fail-closed HARD REJECT of a non-empty value injection is behavioral (ADR-0018 §2 — schema pins shapes, the TCK pins behavior; ADR-0031 §2 disambiguates ADR-0005 D5's 'ignored' to a hard reject, which may require a Bodega code change — Bodega's conformance is its own cycle's finding, not ratified here). Attribute SURVIVORSHIP across occurrences is Bodega's (platform ADR-0013, per ADR-0031 §2a) — this contract carries the association, never its resolution. Evidence associations themselves ride the Seam B association event (contracts/seams/seam-b-association-event.schema.json, ADR-0032), not this DTO; the stream mechanics (delta shape, snapshot, merge/split transfer, pending bound, ref namespace) are ADR-0031 §2b's forward-scoped deliverables, cited here and NOT re-opened. RESOLVER-OWNED METADATA IS ALLOWED AT THE ENTITY/CLUSTER SCOPE (ADR-0031 §2): overall resolution confidence + cluster lifecycle state are legitimately the resolver's and are not attribute content — bound: metadata is influence, not authorship. EDGE-scoped metadata (per (entity_id, ref) match rationale) rides the association event's AddedRef, not this DTO. PROVENANCE: provenance-of-the-ASSERTION (ADR-0030 §3, entities/entity-provenance.schema.json) is a property of the EVENT that asserts, not of the entity identity — it rides the assert body, never this DTO. PROHIBITED: InferenceProvenance (ADR-0025 AC-2 — $ref'd by the gold-spine content envelopes ONLY, never a Seam A/B/C payload and never an SPI DTO; adding it FAILS the criterion) — mechanically enforced by the $ref-scoping lint in test_egress.py. REFERENCE RULE (ADR-0030 AC-7): entity_id $refs the canonical EntityId and is never re-declared as 'type: string' inline — enforced by the anti-drift lint in test_entities.py.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "scope",
10
+ "entity_id"
11
+ ],
12
+ "properties": {
13
+ "scope": {
14
+ "type": "object",
15
+ "additionalProperties": false,
16
+ "required": [
17
+ "account_id",
18
+ "project_id"
19
+ ],
20
+ "properties": {
21
+ "account_id": {
22
+ "type": "string",
23
+ "minLength": 1
24
+ },
25
+ "project_id": {
26
+ "type": "string",
27
+ "minLength": 1
28
+ }
29
+ },
30
+ "description": "Nested tenancy — (account_id, project_id) scopes every artifact; tenancy IS identity and cross-tenant access is deny-by-default with existence-leak discipline (404, not 403) per ADR-0001. Matches the Seam A / Seam B / Seam C envelopes."
31
+ },
32
+ "entity_id": {
33
+ "$ref": "entity-id.schema.json"
34
+ },
35
+ "cluster_state": {
36
+ "enum": [
37
+ "active",
38
+ "merged",
39
+ "split"
40
+ ],
41
+ "description": "Resolver-owned entity/cluster-level metadata: the cluster's lifecycle state (ADR-0031 §2). Optional. Not attribute content. Where this DTO is composed into an event, the state is fixed as of that event's cut (ADR-0032 AC-1)."
42
+ },
43
+ "resolution_confidence": {
44
+ "type": "number",
45
+ "minimum": 0.0,
46
+ "maximum": 1.0,
47
+ "description": "Resolver-owned entity/cluster-level metadata: overall confidence in the resolution of this cluster (ADR-0031 §2). Optional. Influence, not authorship — a consumer MAY weight survivorship by it (survivorship precedence is Bodega's, ADR-0013 / ADR-0031 §2a), but it is never a path to authoring an attribute value."
48
+ }
49
+ },
50
+ "examples": [
51
+ {
52
+ "scope": {
53
+ "account_id": "acct_7f21",
54
+ "project_id": "proj_ledger"
55
+ },
56
+ "entity_id": "ent_9f3ab2c1d4e5f60718293a4b5c6d7e8f"
57
+ },
58
+ {
59
+ "scope": {
60
+ "account_id": "acct_7f21",
61
+ "project_id": "proj_ledger"
62
+ },
63
+ "entity_id": "ent_surv_001",
64
+ "cluster_state": "merged",
65
+ "resolution_confidence": 0.94
66
+ }
67
+ ]
68
+ }
@@ -0,0 +1,51 @@
1
+ # Inference-tier stamp + egress invariant — prose companion
2
+
3
+ Contract tracking: git-ref iteration phase (farm-to-table **ADR-0023 §2**); not version-pinned.
4
+ Authority: **ADR-0025** (the platform egress invariant). Schema wins on data-shape disagreement
5
+ (ADR-0018 §1); this prose is the human companion to the two layers.
6
+
7
+ ## Two layers (ADR-0018)
8
+
9
+ - **Layer (a) — data shape:** `contracts/provenance/inference-provenance.schema.json`, bound in Python
10
+ by `platform_contracts.provenance.InferenceProvenance`. The shared inference-tier stamp sub-object,
11
+ `$ref`'d by the **content-bearing gold-spine envelopes ONLY** — the Harvester clause-(A) gold-record
12
+ envelope and Bodega's stored-object envelope. **NOT** the Seam A/B/C event payloads, and **NOT**
13
+ the storage-adapter SPI DTOs. Spire's M3 pins **reserve / carry** the field (a stamped envelope is
14
+ not rejected) and implement no tier branching.
15
+ - **Layer (b) — behavior:** `platform_contracts.egress` — the fail-closed **egress refusal predicate**
16
+ (`evaluate_egress`), its named `EgressViolation` taxonomy (`platform_contracts.errors`), and the
17
+ machine-checkable registries. This is the one shared **choke-point** every controlled-content
18
+ inference call site constructs its egress through (ADR-0025 §5).
19
+
20
+ ## The invariant (ADR-0025 §1)
21
+
22
+ Any inference over controlled content MUST run on controlled infrastructure UNLESS the specific egress
23
+ is permitted by the refusal predicate; every content-bearing gold-spine artifact carries a verifiable
24
+ inference-tier stamp. Data flows forward; the stamp is forward-carried and immutable.
25
+
26
+ ## The refusal predicate (ADR-0025 §3) — PERMIT iff NO code fires; ambiguity ⇒ REFUSE
27
+
28
+ `MissingTierStamp` · `UnboundDerivedPayload` · `LocalTierEgress` · `LicenseFloorViolation` ·
29
+ `ModelHashUnpinned` · `MaskedEgressUnapproved` · `MissingEgressAttestation` · `UncarvedContentEgress`
30
+ (the default-refuse over **all** controlled-derived off-infra content — not only raw bodies).
31
+ Genesis extraction is the one deliberate `MissingTierStamp` exemption (it produces the stamp).
32
+
33
+ ## Ports (model/state-dependent; shapes pinned here, implementations downstream, ADR-0013 §2)
34
+
35
+ `CouncilPayloadSchema`, `PiiScreen` (the whole-payload local screen; recall-floor CI-gated),
36
+ `OptInStore`. Reference implementations live in the TCK (`tck/test_egress.py`). The concrete
37
+ PII-screen model, per-tenant opt-in store, masking-profile store, attestation sink, and the guarded
38
+ egress proxy are Compendium / Harvester / infra build details.
39
+
40
+ ## Council carve-out (ADR-0025 §6a) — decided; NOT live until its acceptance dependencies land
41
+
42
+ Bounded, default-off, per-tenant opt-in egress of **non-person** reference names past the whole-payload
43
+ PII screen, to a **vendor-control-registry**-admitted provider, per-call attested. Person-identifying
44
+ egress is forbidden-by-default and routed to ADR-0017 §4. Going-live is gated on a pinned stratified
45
+ benchmark + a per-activation DPIA-lite (see the ADR §6a / follow-on).
46
+
47
+ ## Conformance
48
+
49
+ TCK §5 (`tck/test_egress.py`, `pytest -m egress`) drives every refusal code, the genesis exemption, the
50
+ default-refuse, and the council / redacted-frontier PERMIT branches. Consumers wire the same leg as a CI
51
+ gate with their own ports and MUST keep it green (ADR-0025 §5 / ADR-0015 AC#1).