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.
- legion_platform_contracts-0.2.0/.gitignore +26 -0
- legion_platform_contracts-0.2.0/PKG-INFO +136 -0
- legion_platform_contracts-0.2.0/README.md +108 -0
- legion_platform_contracts-0.2.0/contracts/entities/README.md +119 -0
- legion_platform_contracts-0.2.0/contracts/entities/entity-id.schema.json +10 -0
- legion_platform_contracts-0.2.0/contracts/entities/entity-provenance.schema.json +40 -0
- legion_platform_contracts-0.2.0/contracts/entities/entity.schema.json +68 -0
- legion_platform_contracts-0.2.0/contracts/provenance/inference-provenance.md +51 -0
- legion_platform_contracts-0.2.0/contracts/provenance/inference-provenance.schema.json +87 -0
- legion_platform_contracts-0.2.0/contracts/seams/seam-a-harvester-compendium.md +141 -0
- legion_platform_contracts-0.2.0/contracts/seams/seam-a-reference-bundle.schema.json +145 -0
- legion_platform_contracts-0.2.0/contracts/seams/seam-a-reference-type-mapping.json +48 -0
- legion_platform_contracts-0.2.0/contracts/seams/seam-b-association-event.schema.json +246 -0
- legion_platform_contracts-0.2.0/contracts/seams/seam-b-compendium-bodega.md +90 -0
- legion_platform_contracts-0.2.0/contracts/seams/seam-b-identity-op-log.md +119 -0
- legion_platform_contracts-0.2.0/contracts/seams/seam-b-identity-op-log.schema.json +292 -0
- legion_platform_contracts-0.2.0/contracts/seams/seam-b-two-log-consumer.md +78 -0
- legion_platform_contracts-0.2.0/contracts/seams/seam-c-erasure-consumer.md +81 -0
- legion_platform_contracts-0.2.0/contracts/seams/seam-c-erasure-event.schema.json +190 -0
- legion_platform_contracts-0.2.0/contracts/seams/seam-c-erasure-propagation.md +91 -0
- legion_platform_contracts-0.2.0/contracts/storage/storage-adapter-dtos.schema.json +185 -0
- legion_platform_contracts-0.2.0/contracts/storage/storage-adapter-spi.md +181 -0
- legion_platform_contracts-0.2.0/contracts/tck/README.md +176 -0
- legion_platform_contracts-0.2.0/contracts/tokens/dragons-attestation-profile.md +224 -0
- legion_platform_contracts-0.2.0/contracts/tokens/dragons-capability-token-profile.md +91 -0
- legion_platform_contracts-0.2.0/contracts/tokens/dragons-delegation-claim-schema.schema.json +52 -0
- legion_platform_contracts-0.2.0/contracts/tokens/token-issuer-contract.md +89 -0
- legion_platform_contracts-0.2.0/contracts/tokens/token-issuer-dtos.schema.json +70 -0
- legion_platform_contracts-0.2.0/pyproject.toml +142 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/__init__.py +23 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/_generate_models.py +79 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/authz.py +206 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/egress.py +279 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/errors.py +240 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/models.py +229 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/provenance.py +105 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/spi.py +150 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/__init__.py +0 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/_dragons.py +141 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/_resources.py +75 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/association_consumer.py +306 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/conftest.py +98 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/erasure_consumer.py +264 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/erasure_producer.py +205 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/identity_log.py +556 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/reference_adapter.py +257 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/status_resolver.py +159 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_egress.py +296 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_entities.py +442 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_erasure_consumer.py +414 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_goodstanding.py +82 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_query_spec_validation.py +126 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_schemas.py +160 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_seam_a.py +195 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_seam_b.py +577 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_seam_b_identity_log.py +713 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_seam_c.py +468 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_spi_no_backend_type_leak.py +93 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_status_resolver.py +216 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_storage_security.py +158 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_storage_vector.py +168 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_tokens.py +120 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_tokens_audience.py +290 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_tokens_dragons.py +465 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/test_two_log_consumer.py +849 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/two_log_consumer.py +616 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/vectors/PROVENANCE.md +10 -0
- legion_platform_contracts-0.2.0/src/platform_contracts/tck/vectors/authorize.vectors.json +3912 -0
- 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).
|