astp-docs-server 0.1.0__py3-none-any.whl
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.
- astp_docs_server/__init__.py +12 -0
- astp_docs_server/__main__.py +8 -0
- astp_docs_server/atlas_manifest.py +108 -0
- astp_docs_server/corpus/open/CHANGELOG.md +568 -0
- astp_docs_server/corpus/open/CONFORMANCE-BFM.md +430 -0
- astp_docs_server/corpus/open/CONFORMANCE-CONTEXT.md +332 -0
- astp_docs_server/corpus/open/CONFORMANCE-CROSS-EPISODE-LINKING.md +258 -0
- astp_docs_server/corpus/open/CONFORMANCE-LAYER3.md +272 -0
- astp_docs_server/corpus/open/CONFORMANCE-REPRODUCIBILITY.md +219 -0
- astp_docs_server/corpus/open/CONFORMANCE-TRUST.md +639 -0
- astp_docs_server/corpus/open/GLOSSARY.md +661 -0
- astp_docs_server/corpus/open/GOVERNANCE.md +43 -0
- astp_docs_server/corpus/open/IMPLEMENTATION-CONTEXT.md +121 -0
- astp_docs_server/corpus/open/IMPLEMENTATION-PHASE3.md +732 -0
- astp_docs_server/corpus/open/LICENSE.txt +202 -0
- astp_docs_server/corpus/open/NOTICE +60 -0
- astp_docs_server/corpus/open/PATENTS.md +325 -0
- astp_docs_server/corpus/open/PROTOCOL-CONFORMANCE.md +470 -0
- astp_docs_server/corpus/open/RATIFICATION-5.0.0.md +56 -0
- astp_docs_server/corpus/open/RATIFICATION-6.0.0.md +71 -0
- astp_docs_server/corpus/open/RATIFICATION-PATENTS-1.0.0.md +116 -0
- astp_docs_server/corpus/open/RATIFICATION-PROTOCOL-CONFORMANCE-1.0.0.md +145 -0
- astp_docs_server/corpus/open/RATIFICATION-SPEC-6.0.2.md +136 -0
- astp_docs_server/corpus/open/README.md +230 -0
- astp_docs_server/corpus/open/SPEC.md +3220 -0
- astp_docs_server/corpus/open/VERSIONING.md +105 -0
- astp_docs_server/corpus/open/vectors/5.0.0/seal-constructions.json +402 -0
- astp_docs_server/corpus/open/vectors/6.0.0/context-commitment.json +353 -0
- astp_docs_server/corpus/open/vendor_manifest.json +31 -0
- astp_docs_server/mcp_server.py +145 -0
- astp_docs_server/open_corpus.py +235 -0
- astp_docs_server/vendor_manifest.py +124 -0
- astp_docs_server/web/__init__.py +7 -0
- astp_docs_server/web/__main__.py +5 -0
- astp_docs_server/web/answerer.py +307 -0
- astp_docs_server/web/app.py +151 -0
- astp_docs_server-0.1.0.dist-info/METADATA +107 -0
- astp_docs_server-0.1.0.dist-info/RECORD +42 -0
- astp_docs_server-0.1.0.dist-info/WHEEL +4 -0
- astp_docs_server-0.1.0.dist-info/entry_points.txt +3 -0
- astp_docs_server-0.1.0.dist-info/licenses/LICENSE.txt +202 -0
- astp_docs_server-0.1.0.dist-info/licenses/NOTICE +72 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# ASTP — Context-Commitment Conformance Test Vectors
|
|
2
|
+
|
|
3
|
+
**Version:** 1.0.0
|
|
4
|
+
**Status:** Stable — ratified with SPEC 6.0.0 in Episode of Record `80e5a2dd-3d9f-45d0-abfb-6489c8caf1b8` ([`docs/RATIFICATION-6.0.0.md`](./docs/RATIFICATION-6.0.0.md)); the values were generated while 6.0.0 was a draft and none changed at ratification
|
|
5
|
+
**Authors:** Scorched Earth Labs
|
|
6
|
+
**Date:** 2026-09-22
|
|
7
|
+
**Applies To:** SPEC.md 6.0.0 — §4.8 ContextEntryNode, §4.9 Erasure and ErasureTombstone, §5.7 Episode Root version 3, §5.7.3 Context Manifest, §5.8 `spine_algorithm_version` 3, §9.2–§9.3 as extended, G-41, G-42, G-43.
|
|
8
|
+
**Companions:** [CONFORMANCE-REPRODUCIBILITY.md](CONFORMANCE-REPRODUCIBILITY.md) (§5.6–§5.8, `spine_algorithm_version` 0–2), [CONFORMANCE-TRUST.md](CONFORMANCE-TRUST.md) (§16), [CONFORMANCE-LAYER3.md](CONFORMANCE-LAYER3.md) (§21).
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Overview
|
|
13
|
+
|
|
14
|
+
These vectors test the one thing 6.0.0 adds — a sealed commitment to what an Episode's agents were *given* — and the one thing it states: **the seal proves history, not retention.** Every expected value below is pinned in [`vectors/6.0.0/context-commitment.json`](./vectors/6.0.0/context-commitment.json), generated by `vectors/6.0.0/generate.py` and never edited by hand, and is reproduced twice in `tests/conformance/test_context_commitment_v1_vectors.py`: once by the reference package and once by a `hashlib`-only implementation written from the SPEC text that imports nothing from `astp`.
|
|
15
|
+
|
|
16
|
+
The Episode is the one the ratified 5.0.0 vectors seal (`550e8400-e29b-41d4-a716-446655440000`, its seven Segments, five Signals and seven structural members), so the version 2 roots here are the ratified values byte for byte. A conforming implementation MUST pass all vectors marked **REQUIRED**. Format follows [CONFORMANCE-TRUST.md §1](CONFORMANCE-TRUST.md); hash values are lowercase hex and enter every construction as 32 raw bytes under the §5.1.1 field encoding.
|
|
17
|
+
|
|
18
|
+
Reference implementation: `astp/core/context_v1.py`; `astp.core.seal_v2.reproduce_episode_root` dispatches version 3.
|
|
19
|
+
|
|
20
|
+
**The shared inputs.** Seven context entries on the base Episode, provided at one-minute intervals from `2026-01-01T00:01:00.123Z`; identifiers are fixed for reproducibility and MUST be random in practice (§5.2). The salt is fixed for the same reason and MUST be 32 CSPRNG bytes in practice (§5.3).
|
|
21
|
+
|
|
22
|
+
| # | `entry_id` | `entry_type` | `capture_state` | `salted` | `verifiability_at_seal` | `entry_hash` |
|
|
23
|
+
|---|---|---|---|---|---|---|
|
|
24
|
+
| 1 | `…0200` | attachment | captured | false | verifiable | `b08d864e0d6d41321cecbd90483ee1396ece80368f72ca496f772dfd04f85663` |
|
|
25
|
+
| 2 | `…0201` | retrieval | captured | false | attested | `a4dabb6716c72fc11c6e2a3cc2569c67c807c7b4c2aa882fb0dfb7ac4ef3f885` |
|
|
26
|
+
| 3 | `…0202` | retrieval (low-entropy personal data) | captured | **true** | verifiable | `4f45678a1893131e24d4afddd1350fbfcc7ce3f7cb5fe4ec893c76e58ff92704` |
|
|
27
|
+
| 4 | `…0203` | external | captured | false | verifiable | `e88d185230ffbe206d333f59f4156fb7337b5ced90083e9b704727c73dea0397` |
|
|
28
|
+
| 5 | `…0204` | tool_output | captured | false | verifiable | `956432ad9964673fced63541a9e1e6c3bf864ac5452a3d9f393bf60c6b8a5572` |
|
|
29
|
+
| 6 | `…0205` | retrieval | **declared_incomplete** | false | — | `0dbaaff8a22a5d772c49350bb94fc6fa825a635660fb128c2420bdff070d4cc3` |
|
|
30
|
+
| 7 | `…0206` | retrieval, `resolves` #6 | captured | false | verifiable | `eb174452baa2d2eb6ba47329dec7af36150cc07c669cd3fc92c5cb696102a643` |
|
|
31
|
+
|
|
32
|
+
Full field values are in the vector file's `entries` list. The base Episode's version 2 components: `spine_root` `4420e38a22409317822ac14e3d5bc8069e6556c0fc08928290f76d23396daa01`, `signal_manifest_hash` `70dbc8e8f2e87b63e49187979b14ad56ba11219b42be132015c23dcad36acb43`, `structural_manifest_hash` `0a4b777227b87ee0d6c8efd5b2e9a5fc05c02e61d677f2460f868ab06779b537`, `exclusion_hash` `ddea405cc1729ebf63d93b16d723873ad02f9f64af3cc159bf86e5f999b02ce1`, `episode_root_hash` (version 2) `f0511b4d1be172554b9f87ec64d400d24a1409f1742ad72f628bf5ab7b7d33f0`.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 2. Content Commitment (§4.8.3)
|
|
37
|
+
|
|
38
|
+
**CC-001** — Plain Content Commitment
|
|
39
|
+
- **Class:** REQUIRED
|
|
40
|
+
- **Spec Reference:** §4.8.3
|
|
41
|
+
- **Description:** `CONTEXT_CONTENT:v1:` over the bytes as provided, under the BYTES field encoding (tag `01`, u32 length, bytes).
|
|
42
|
+
- **Inputs:**
|
|
43
|
+
```
|
|
44
|
+
content (hex): 255044462d312e370a312030206f626a203c3c202f54797065202f436174616c6f67203e3e20656e646f626a0a2525454f460a
|
|
45
|
+
construction: SHA3-256("CONTEXT_CONTENT:v1:" ‖ BYTES(content))
|
|
46
|
+
```
|
|
47
|
+
- **Expected Output:**
|
|
48
|
+
```
|
|
49
|
+
content_hash: 9fbce78d71635571ef48ac04c99f1f340ac5141749f62bde5a77b425192d0baf
|
|
50
|
+
```
|
|
51
|
+
- **Failure Condition:** Any other value; a hash over the hex text of the content or over an extraction of it.
|
|
52
|
+
|
|
53
|
+
**CC-002** — Salted Content Commitment
|
|
54
|
+
- **Class:** REQUIRED
|
|
55
|
+
- **Spec Reference:** §4.8.3, G-42
|
|
56
|
+
- **Description:** `CONTEXT_CONTENT_SALTED:v1:` over the 32-byte salt and then the bytes; the salt is a separate BYTES field, so the boundary between salt and content cannot be moved.
|
|
57
|
+
- **Inputs:**
|
|
58
|
+
```
|
|
59
|
+
content (utf-8): 1979-03-14
|
|
60
|
+
salt (hex): 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
|
|
61
|
+
construction: SHA3-256("CONTEXT_CONTENT_SALTED:v1:" ‖ BYTES(salt) ‖ BYTES(content))
|
|
62
|
+
```
|
|
63
|
+
- **Expected Output:**
|
|
64
|
+
```
|
|
65
|
+
content_hash (salted): f94cc9f2c956d78e7a1c9c17ac6ae74580da6a8cb8256d923f012afa8b0e501a
|
|
66
|
+
content_hash (plain, for contrast — what G-42 forbids for this content): 4ae9d00037107b8d1ed647f47bf2e4c97311929b4c5d6dd2a57b678fffb5c772
|
|
67
|
+
```
|
|
68
|
+
- **Failure Condition:** Any other value; a salt of any length but 32 accepted; the plain construction used for content classified low-entropy personal data.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 3. Entry Hash (§5.7.3)
|
|
73
|
+
|
|
74
|
+
**CM-002** — Entry Hash Binds Its Claims and Nothing Else
|
|
75
|
+
- **Class:** REQUIRED
|
|
76
|
+
- **Spec Reference:** §5.7.3, §4.8.6
|
|
77
|
+
- **Description:** the preimage is the thirteen fields in the stated order; `source_ref`, `content_ref`, `salt_ref`, `erasure_state` and any implementation classification are outside it. Changing any preimage field changes the hash; changing any side-channel field does not.
|
|
78
|
+
- **Inputs:**
|
|
79
|
+
```
|
|
80
|
+
preimage: entry_id UUID ‖ episode_id UUID ‖ entry_type STRING ‖ provided_to STRING ‖ provided_at TIMESTAMP ‖ provided_before_sequence_index UINT|NULL ‖ capture_state STRING ‖ content_hash HASH|NULL ‖ salted BOOL ‖ verifiability_at_seal STRING|NULL ‖ media_type STRING|NULL ‖ source_version_hash HASH|NULL ‖ resolves_entry_hash HASH|NULL
|
|
81
|
+
entry #1 (attachment): see vectors "entries"[0]
|
|
82
|
+
```
|
|
83
|
+
- **Expected Output:**
|
|
84
|
+
```
|
|
85
|
+
entry_hash: b08d864e0d6d41321cecbd90483ee1396ece80368f72ca496f772dfd04f85663
|
|
86
|
+
unchanged when source_ref, content_ref, salt_ref, erasure_state change
|
|
87
|
+
changed when any preimage field changes (each tested)
|
|
88
|
+
```
|
|
89
|
+
- **Failure Condition:** A side-channel field moving the hash (erasure would then move a sealed preimage); a preimage field not moving it.
|
|
90
|
+
|
|
91
|
+
**CM-002a** — Declared-Incomplete Entry
|
|
92
|
+
- **Class:** REQUIRED
|
|
93
|
+
- **Spec Reference:** §4.8.5, §5.7.3
|
|
94
|
+
- **Description:** NULL `content_hash`, `salted` false, NULL `verifiability_at_seal`, encoded as NULL fields (`00`); a captured entry MUST carry a content hash and a verifiability state.
|
|
95
|
+
- **Inputs:**
|
|
96
|
+
```
|
|
97
|
+
entry #6: capture_state=declared_incomplete, content_hash=NULL, salted=false, verifiability_at_seal=NULL, media_type=NULL
|
|
98
|
+
```
|
|
99
|
+
- **Expected Output:**
|
|
100
|
+
```
|
|
101
|
+
entry_hash: 0dbaaff8a22a5d772c49350bb94fc6fa825a635660fb128c2420bdff070d4cc3
|
|
102
|
+
```
|
|
103
|
+
- **Failure Condition:** A declared-incomplete entry accepted with content, or a captured entry accepted without verifiability.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 4. Context Manifest (§5.7.3)
|
|
108
|
+
|
|
109
|
+
**CM-003** — Manifest Is Order-Independent; Removal and Posture Change It
|
|
110
|
+
- **Class:** REQUIRED
|
|
111
|
+
- **Spec Reference:** §5.7.3
|
|
112
|
+
- **Description:** the tree is the §5.4 version 2 tree over entry hashes sorted ascending bytewise; the manifest hash binds the posture and the count with the tree root.
|
|
113
|
+
- **Inputs:**
|
|
114
|
+
```
|
|
115
|
+
entry hashes: the seven above, in any insertion order
|
|
116
|
+
capture_posture: declared_only
|
|
117
|
+
construction: SHA3-256("CONTEXT_MANIFEST:v1:" ‖ STRING(posture) ‖ UINT(n) ‖ HASH|NULL(context_tree_root))
|
|
118
|
+
```
|
|
119
|
+
- **Expected Output:**
|
|
120
|
+
```
|
|
121
|
+
context_tree_root (sorted leaves): e730a2153f39eb61b27888528000ffdc0b88a94a24f3daf29300126a9d42acc1
|
|
122
|
+
sorted leaf order (entry_id suffixes): 0205, 0202, 0204, 0201, 0200, 0203, 0206
|
|
123
|
+
context_manifest_hash (declared_only, 7): 94e7681209cb0315427622aee9b22abf832e5e35ba653cf7e692faa413e75df7
|
|
124
|
+
same entries, reverse insertion order: 94e7681209cb0315427622aee9b22abf832e5e35ba653cf7e692faa413e75df7
|
|
125
|
+
without entry #2: 54a733a5c6592d150f5374cb1327a44a72e2fd45a67ca20d07bda2a4cb4d5004
|
|
126
|
+
posture all_external instead: 68c1bc568cd1b4967dc8214a450dbb2e8a185841cddd76c5472451dfa70dcf92
|
|
127
|
+
```
|
|
128
|
+
- **Failure Condition:** Insertion order changing the hash; a removed entry or a changed posture leaving it unchanged.
|
|
129
|
+
|
|
130
|
+
**CM-001** — Empty Manifest Is Defined
|
|
131
|
+
- **Class:** REQUIRED
|
|
132
|
+
- **Spec Reference:** §5.7.3, §5.7
|
|
133
|
+
- **Description:** an Episode with zero context entries composes `n = 0` and a NULL root, seals under version 3 and reproduces from stored state.
|
|
134
|
+
- **Inputs:**
|
|
135
|
+
```
|
|
136
|
+
entries: none
|
|
137
|
+
capture_posture: none
|
|
138
|
+
```
|
|
139
|
+
- **Expected Output:**
|
|
140
|
+
```
|
|
141
|
+
context_manifest_hash (none, 0): 66be9e2d4febffe1afb2afb2e388aec945777f4f8b1ef58c1a5a234ea9eedb5d
|
|
142
|
+
context_manifest_hash (declared_only, 0): 0bcf1339549cd0673d1776d198b856dba92987798b0ba9c9838ee1a936076e7d
|
|
143
|
+
episode_root_hash (version 3, posture none): 490fb1f566a5ef75640f54d6d5550bd7706073809902d18348a870f188fd6882
|
|
144
|
+
```
|
|
145
|
+
- **Failure Condition:** A version 3 seal refused for an Episode without entries; a tree root computed for zero leaves; the two postures giving one hash.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 5. Episode Root Version 3 (§5.7, §5.8)
|
|
150
|
+
|
|
151
|
+
**ER3-001** — Six-Field Root Selected by `spine_algorithm_version` 3
|
|
152
|
+
- **Class:** REQUIRED
|
|
153
|
+
- **Spec Reference:** §5.7, §5.8
|
|
154
|
+
- **Description:** the version 2 root's five fields unchanged, then `context_manifest_hash`; the spine root is byte-identical to version 2.
|
|
155
|
+
- **Inputs:**
|
|
156
|
+
```
|
|
157
|
+
episode_id: 550e8400-e29b-41d4-a716-446655440000
|
|
158
|
+
spine_root: 4420e38a22409317822ac14e3d5bc8069e6556c0fc08928290f76d23396daa01
|
|
159
|
+
signal_manifest_hash: 70dbc8e8f2e87b63e49187979b14ad56ba11219b42be132015c23dcad36acb43
|
|
160
|
+
structural_manifest_hash: 0a4b777227b87ee0d6c8efd5b2e9a5fc05c02e61d677f2460f868ab06779b537
|
|
161
|
+
exclusion_hash: ddea405cc1729ebf63d93b16d723873ad02f9f64af3cc159bf86e5f999b02ce1
|
|
162
|
+
context_manifest_hash: 94e7681209cb0315427622aee9b22abf832e5e35ba653cf7e692faa413e75df7
|
|
163
|
+
construction: SHA3-256("EPISODE_ROOT:v3:" ‖ UUID ‖ HASH ‖ HASH ‖ HASH ‖ HASH ‖ HASH)
|
|
164
|
+
```
|
|
165
|
+
- **Expected Output:**
|
|
166
|
+
```
|
|
167
|
+
episode_root_hash: 22675041b1af6243fe8c72f318ca853a6e775073355c718116c9ac0d19fe0e88
|
|
168
|
+
seal record identifiers: spine_algorithm_version 3, ordering_version 2, hash_version 2
|
|
169
|
+
```
|
|
170
|
+
- **Failure Condition:** Any other value; a separate root-version identifier on the record (§5.8: one identifier selects the whole construction).
|
|
171
|
+
|
|
172
|
+
**CM-010** — A Version 2 Seal Is Unchanged by Context Entries
|
|
173
|
+
- **Class:** REQUIRED
|
|
174
|
+
- **Spec Reference:** §5.7, §5.8
|
|
175
|
+
- **Description:** context entries are members of no version 2 root; the same Episode, holding the seven entries, seals under version 2 to the ratified 5.0.0 value.
|
|
176
|
+
- **Inputs:**
|
|
177
|
+
```
|
|
178
|
+
the base Episode with the seven entries present
|
|
179
|
+
spine_algorithm_version: 2
|
|
180
|
+
```
|
|
181
|
+
- **Expected Output:**
|
|
182
|
+
```
|
|
183
|
+
episode_root_hash (version 2): f0511b4d1be172554b9f87ec64d400d24a1409f1742ad72f628bf5ab7b7d33f0 (= vectors/5.0.0 episode_root_v2.hash)
|
|
184
|
+
episode_root_hash (version 3): 22675041b1af6243fe8c72f318ca853a6e775073355c718116c9ac0d19fe0e88 (differs)
|
|
185
|
+
```
|
|
186
|
+
- **Failure Condition:** A version 2 root that changes when entries exist; a version 3 root equal to the version 2 root.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 6. Inclusion Proofs (§9.2)
|
|
191
|
+
|
|
192
|
+
**CM-004** — One Entry Proven Without the Others
|
|
193
|
+
- **Class:** REQUIRED
|
|
194
|
+
- **Spec Reference:** §9.2, §5.7.3
|
|
195
|
+
- **Description:** the §9.2 proof over the context tree; `leaf_index` is the entry's position in the sorted leaf list; the verifier reproduces the tree root, then the manifest hash from posture and count, then the Episode root.
|
|
196
|
+
- **Inputs:**
|
|
197
|
+
```
|
|
198
|
+
entry: #3 (entry_hash 4f45678a1893131e24d4afddd1350fbfcc7ce3f7cb5fe4ec893c76e58ff92704)
|
|
199
|
+
leaf_index: 1 leaf_count: 7
|
|
200
|
+
siblings: ["5c2e34164e93e1de4d62b5b498cb1c6cfb5e456627f26cae21e1ad0140228ae9", "f6d2ee6739f138deff2724d247ae8ceb5e70b112f1b74bbd5d929af5cff06429", "d5c030cda42f4363eac47a200e2055334f4507f42de83ca1fb3b1373c6cc2f08"]
|
|
201
|
+
capture_posture: declared_only entry_count: 7
|
|
202
|
+
```
|
|
203
|
+
- **Expected Output:**
|
|
204
|
+
```
|
|
205
|
+
context_tree_root: e730a2153f39eb61b27888528000ffdc0b88a94a24f3daf29300126a9d42acc1
|
|
206
|
+
context_manifest_hash: 94e7681209cb0315427622aee9b22abf832e5e35ba653cf7e692faa413e75df7
|
|
207
|
+
episode_root_hash: 22675041b1af6243fe8c72f318ca853a6e775073355c718116c9ac0d19fe0e88
|
|
208
|
+
```
|
|
209
|
+
- **Failure Condition:** The proof verifying at any other leaf_index, under any other posture, or for any other count.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 7. Append-Only Repair (§4.8.5)
|
|
214
|
+
|
|
215
|
+
**CM-005** — A Resolving Entry Binds the Resolved Entry's Hash
|
|
216
|
+
- **Class:** REQUIRED
|
|
217
|
+
- **Spec Reference:** §4.8.5, §5.7.3
|
|
218
|
+
- **Description:** entry #7 carries `resolves` = entry #6; its preimage's last field is #6's entry hash; #6 is unchanged.
|
|
219
|
+
- **Inputs:**
|
|
220
|
+
```
|
|
221
|
+
resolved (declared_incomplete) entry_id: …0205
|
|
222
|
+
resolving entry_id: …0206, resolves = …0205
|
|
223
|
+
```
|
|
224
|
+
- **Expected Output:**
|
|
225
|
+
```
|
|
226
|
+
resolved entry_hash: 0dbaaff8a22a5d772c49350bb94fc6fa825a635660fb128c2420bdff070d4cc3
|
|
227
|
+
resolving entry_hash: eb174452baa2d2eb6ba47329dec7af36150cc07c669cd3fc92c5cb696102a643
|
|
228
|
+
```
|
|
229
|
+
- **Failure Condition:** The resolving entry's hash unchanged when the resolved entry's hash changes; a `resolves` naming an entry outside the Episode, a captured entry, or an entry that itself resolves.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## 8. Erasure (§4.9; G-43)
|
|
234
|
+
|
|
235
|
+
**CM-006** — Erasure Is Content-Plane and Witnessed
|
|
236
|
+
- **Class:** REQUIRED
|
|
237
|
+
- **Spec Reference:** §4.9.2, §4.9.3, G-43
|
|
238
|
+
- **Description:** after erasure of entry #3: `content_ref` and `salt_ref` NULL, `erasure_state` tombstoned; the entry hash, the manifest hash and the Episode root are unchanged; a codicil tombstone binds the entry's unchanged hash.
|
|
239
|
+
- **Inputs:**
|
|
240
|
+
```
|
|
241
|
+
entry #3 before: content_ref=blob://ctx/e3, salt_ref=salt://ctx/e3, erasure_state=present
|
|
242
|
+
tombstone: tombstone_id …0400, entry_id …0202, erased_at 2026-01-01T01:00:00.123000Z, erasure_authority GDPR-Art17, erasure_request_id dsr-2026-0142, erased_by privacy-officer
|
|
243
|
+
construction: SHA3-256("ERASURE_TOMBSTONE:v1:" ‖ UUID ‖ UUID ‖ UUID ‖ HASH(entry_hash) ‖ TIMESTAMP ‖ STRING ‖ STRING ‖ STRING)
|
|
244
|
+
```
|
|
245
|
+
- **Expected Output:**
|
|
246
|
+
```
|
|
247
|
+
entry #3 after: content_ref=NULL, salt_ref=NULL, erasure_state=tombstoned
|
|
248
|
+
entry_hash (unchanged): 4f45678a1893131e24d4afddd1350fbfcc7ce3f7cb5fe4ec893c76e58ff92704
|
|
249
|
+
tombstone_hash: 05dac249ff0fcbd8f9022f3e57e173821541b20f0b2af54d1f65d168276ef384
|
|
250
|
+
context_manifest_hash (unchanged): 94e7681209cb0315427622aee9b22abf832e5e35ba653cf7e692faa413e75df7
|
|
251
|
+
episode_root_hash (unchanged): 22675041b1af6243fe8c72f318ca853a6e775073355c718116c9ac0d19fe0e88
|
|
252
|
+
```
|
|
253
|
+
- **Failure Condition:** Any sealed value moving; an erased entry reported as an integrity failure; a tombstone outside the codicil chain; content destroyed without the salt or the reverse.
|
|
254
|
+
|
|
255
|
+
**CM-007** — A Salted Commitment Confirms No Guess Once the Salt Is Gone
|
|
256
|
+
- **Class:** REQUIRED
|
|
257
|
+
- **Spec Reference:** §4.8.3, G-42
|
|
258
|
+
- **Description:** stated as a property, tested by construction: the plain commitment to `1979-03-14` equals a recomputation from the guess; the salted one does not, under no salt and under any wrong salt, across the whole low-entropy space.
|
|
259
|
+
- **Inputs:**
|
|
260
|
+
```
|
|
261
|
+
guess: 1979-03-14 (and every 1979-03-DD)
|
|
262
|
+
plain content_hash: 4ae9d00037107b8d1ed647f47bf2e4c97311929b4c5d6dd2a57b678fffb5c772
|
|
263
|
+
salted content_hash: f94cc9f2c956d78e7a1c9c17ac6ae74580da6a8cb8256d923f012afa8b0e501a
|
|
264
|
+
```
|
|
265
|
+
- **Expected Output:**
|
|
266
|
+
```
|
|
267
|
+
SHA3-256("CONTEXT_CONTENT:v1:" ‖ BYTES(guess)) == plain content_hash (a plain commitment is an oracle)
|
|
268
|
+
SHA3-256("CONTEXT_CONTENT:v1:" ‖ BYTES(guess)) != salted content_hash
|
|
269
|
+
SHA3-256("CONTEXT_CONTENT_SALTED:v1:" ‖ BYTES(any wrong salt) ‖ BYTES(guess)) != salted content_hash
|
|
270
|
+
only the true salt reproduces it — verification of an un-erased salted entry needs that one entry's salt (§4.9.5)
|
|
271
|
+
```
|
|
272
|
+
- **Failure Condition:** A salted commitment reproducible without its salt.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## 9. External Entries (§4.8.4)
|
|
277
|
+
|
|
278
|
+
**CM-008** — An External Entry Verifies Without a Fetch
|
|
279
|
+
- **Class:** REQUIRED
|
|
280
|
+
- **Spec Reference:** §4.8.4, §4.8.6
|
|
281
|
+
- **Description:** the URI and fetch metadata in `source_ref` are provenance outside the preimage; `source_version_hash` is NULL; a verifier MUST NOT re-fetch and treat a difference as a failure.
|
|
282
|
+
- **Inputs:**
|
|
283
|
+
```
|
|
284
|
+
entry #4: entry_type=external, source_ref='https://rates.example/sheet?date=2026-01-01 status=200 etag="7f3a"', source_version_hash=NULL
|
|
285
|
+
source_ref changed to: 'https://rates.example/sheet?date=2026-01-02 status=404'
|
|
286
|
+
```
|
|
287
|
+
- **Expected Output:**
|
|
288
|
+
```
|
|
289
|
+
entry_hash before: e88d185230ffbe206d333f59f4156fb7337b5ced90083e9b704727c73dea0397
|
|
290
|
+
entry_hash after: e88d185230ffbe206d333f59f4156fb7337b5ced90083e9b704727c73dea0397 (unchanged)
|
|
291
|
+
```
|
|
292
|
+
- **Failure Condition:** The entry hash depending on the URI or on the result of a fetch.
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## 10. Governance at the Seal (G-41, G-42)
|
|
297
|
+
|
|
298
|
+
**CM-009** — Safe Only Together
|
|
299
|
+
- **Class:** REQUIRED
|
|
300
|
+
- **Spec Reference:** G-42, CM-009
|
|
301
|
+
- **Description:** an implementation that claims 6.0.0 context commitment and does not implement G-42 is non-conformant. In the reference package the rule is enforced where the seal happens: an entry the implementation classified as low-entropy personal data and committed plain is refused.
|
|
302
|
+
- **Inputs:**
|
|
303
|
+
```
|
|
304
|
+
entry #3 with salted=false and the plain content_hash 4ae9d00037107b8d1ed647f47bf2e4c97311929b4c5d6dd2a57b678fffb5c772, classified low_entropy_personal
|
|
305
|
+
```
|
|
306
|
+
- **Expected Output:**
|
|
307
|
+
```
|
|
308
|
+
seal refused (G-42 violation)
|
|
309
|
+
the same entry with no classification seals — the classifier's quality is the implementation's residual risk (§4.9.5)
|
|
310
|
+
```
|
|
311
|
+
- **Failure Condition:** A ConformanceDeclaration claiming 6.0.0 context commitment from an implementation that commits low-entropy personal data plain.
|
|
312
|
+
|
|
313
|
+
**G41-001** — Posture Required; an Undeclared Gap Blocks the Seal
|
|
314
|
+
- **Class:** REQUIRED
|
|
315
|
+
- **Spec Reference:** G-41, §5.7.3, §4.8.5
|
|
316
|
+
- **Description:** a version 3 seal without a `capture_posture` is refused; an entry whose write did not complete as `captured` or `declared_incomplete` blocks the seal.
|
|
317
|
+
- **Inputs:**
|
|
318
|
+
```
|
|
319
|
+
seal with capture_posture = NULL
|
|
320
|
+
seal over an entry with capture_state = pending
|
|
321
|
+
```
|
|
322
|
+
- **Expected Output:**
|
|
323
|
+
```
|
|
324
|
+
both refused (G-41 violation)
|
|
325
|
+
```
|
|
326
|
+
- **Failure Condition:** A version 3 seal without a posture; a seal over an entry in a non-terminal capture state.
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## 11. Retained Constructions
|
|
331
|
+
|
|
332
|
+
Nothing here changes a value sealed under `spine_algorithm_version` 0, 1 or 2. RP-001 … RP-011 of [CONFORMANCE-REPRODUCIBILITY.md](CONFORMANCE-REPRODUCIBILITY.md) continue to apply unchanged, and CM-010 above is the statement of that for version 2 seals of Episodes that hold context entries.
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# ASTP — Cross-Episode Linking & Grouping Conformance Test Vectors
|
|
2
|
+
|
|
3
|
+
**Version:** 1.1.0
|
|
4
|
+
**Status:** Stable
|
|
5
|
+
**Authors:** Scorched Earth Labs
|
|
6
|
+
**Date:** 2026-09-19
|
|
7
|
+
**Applies To:** SPEC.md §20 (Cross-Episode Linking & Grouping), 5.1.0 (SPEC §20 as of 5.1.0; see the note in §1)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. Overview
|
|
12
|
+
|
|
13
|
+
> **SPEC 5.0.0 / 5.1.0 note.** SPEC §20 →2 now defines `EpisodeLink.content_hash` as `EPISODE_LINK:v2:` — binding each end's Episode root when that end was sealed at link creation, the type, exact strength, every inference signal (`LINK_SIGNAL:v2:`) in order and the threshold, with health, quarantine and `created_by` **out** of the preimage (they are lifecycle and provenance, the audit chain's). The 4.x preimage this document describes, which bound `health_state` and the quarantine fields and so changed whenever a link's health did, is retained in SPEC only as the definition of links already written; the `LINK_INTEGRITY` field snapshot is the bound set. The reference writer (`write_episode_link_sync`) fills `source_episode_root` / `target_episode_root` from the graph and stamps the 5.0.0 form from `astp` 0.5.0; links written before that carry the 4.x form this document describes (`compute_episode_link_content_hash_4x`). `MembershipRecord` and `ConformanceDeclaration` hashes are unchanged. The audit records these operations write are the version 2 audit record of SPEC §8 (`GENESIS` → NULL); `GroupingSystem` reserves only the protocol's own value — `astp_native` from astp 0.6.0, with `ariadne_native` retained as the value carried by records written before it (`group_system` is in the MembershipRecord preimage).
|
|
14
|
+
|
|
15
|
+
This document specifies the conformance test vectors for the **Cross-Episode Linking & Grouping** feature family of ASTP (the AI State Tree Protocol; SPEC §20). A conforming implementation MUST pass all vectors marked **REQUIRED**. Vectors marked **RECOMMENDED** test behaviors that conforming implementations SHOULD support.
|
|
16
|
+
|
|
17
|
+
These are **cross-implementation-consistency** vectors, not hardcoded golden-hash values. A hash vector specifies the canonical byte layout (ordered field set + canonicalization rules) and asserts that **two conforming implementations MUST produce identical bytes for the same input tuple**. This is wire-tier conformance (§20 →12.1): the protocol fixes the preimage, not a specific digest. Where a vector references SPEC §20, it uses the amendment's internal §1–§12 numbering scoped within §20 (cited as `§20 →N`).
|
|
18
|
+
|
|
19
|
+
Cross-Episode Linking & Grouping is organized into the following scopes (the reference deployment's adapter guide, `IMPLEMENTATION-CROSS-EPISODE-LINKING.md`, which lives with that adapter, follows the same order):
|
|
20
|
+
|
|
21
|
+
| Scope | Coverage | Vector Prefix |
|
|
22
|
+
|-------|----------|---------------|
|
|
23
|
+
| Cross-episode link schema + integrity | `EpisodeLink` hash, mutual exclusivity, audit deltas | `CEL-` |
|
|
24
|
+
| Link health & quarantine lifecycle | Health-state FSM, quarantine resolution/escalation | `LH-` |
|
|
25
|
+
| Inference signals & discovery | `Signal` recording, propose/reject audit events | `SG-` |
|
|
26
|
+
| Episode membership | `MembershipRecord` hash + succession chain | `MR-` |
|
|
27
|
+
| Grouping conformance | `ConformanceDeclaration` hash + SemVer versioning | `CD-` |
|
|
28
|
+
|
|
29
|
+
All hex values lowercase. All string fields UTF-8. Datetimes UTC-normalized ISO 8601. Floats canonicalized via Python `repr()` semantics (round-trippable, platform-stable).
|
|
30
|
+
|
|
31
|
+
> **Governance model note.** Unlike the BFM family (SPEC §19, G-19–G-35), Cross-Episode Linking & Grouping has **zero numbered SPEC G-rules**. Its governance is enforced through (a) the `LinkGovernanceError` taxonomy (mutual exclusivity), (b) the Link Health / quarantine FSM (§20 →6, →11.3), (c) the immutable-with-succession chain-integrity checks for `MembershipRecord` / `ConformanceDeclaration`, and (d) the `GroupingGovernanceError` SemVer taxonomy. The governance matrix in §7 reflects THIS structure, not invented G-numbers.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 2. Cross-Episode Link Vectors (§20 →2, →3, →5)
|
|
36
|
+
|
|
37
|
+
### 2.1 Hash Canonicalization
|
|
38
|
+
|
|
39
|
+
**CEL-001** — `EpisodeLink` content hash
|
|
40
|
+
- **Class:** REQUIRED — *4.x form, for links written before astp 0.5.0; the 5.0.0 construction is `EPISODE_LINK:v2:` over the §5.1.1 field encoding (SPEC §20 →2)*
|
|
41
|
+
- **Spec Reference:** §20 →2 (hash preimage note)
|
|
42
|
+
- **Description:** `compute_episode_link_content_hash()` MUST produce identical bytes across implementations given identical inputs. The canonical layout is the ordered field set, serialized as a JSON object with `sort_keys=False` and `separators=(",",":")`, then SHA3-256. Field order (from `_HASH_PREIMAGE_FIELDS`): `link_id`, `source_episode`, `target_episode`, `created_at`, `created_by`, `link_type`, `link_strength`, `is_inferred`, `inference_signals`, `inference_threshold`, `retroactive`, `health_state`, `health_checked_at`, `source_version`, `target_version`, `quarantine_reason`, `quarantined_at`.
|
|
43
|
+
- **Verification Protocol:** Cross-implementation consistency check. Two conforming implementations MUST produce identical `content_hash` bytes for the same input tuple.
|
|
44
|
+
- **Failure Condition:** Divergent bytes indicate a canonicalization error (wrong field order, alphabetical key sort, non-`repr` float encoding, non-UTC datetime, or an unexpectedly included/excluded field).
|
|
45
|
+
|
|
46
|
+
**CEL-002** — Quarantine-resolution field exclusion
|
|
47
|
+
- **Class:** REQUIRED
|
|
48
|
+
- **Spec Reference:** §20 →2 (hash preimage note)
|
|
49
|
+
- **Description:** `quarantine_resolved_at` and `quarantine_resolution` MUST NOT appear in the `EpisodeLink` content-hash preimage. Setting either field on an existing link (on quarantine close) MUST NOT change `content_hash`.
|
|
50
|
+
- **Failure Condition:** A link's `content_hash` changes when only `quarantine_resolved_at` / `quarantine_resolution` are set — the resolution lifecycle is committed by the audit log, not the content hash.
|
|
51
|
+
|
|
52
|
+
**CEL-003** — Health-state field inclusion
|
|
53
|
+
- **Class:** REQUIRED — *4.x form only; under `EPISODE_LINK:v2:` (SPEC §20 →2) `health_state` and `health_checked_at` are OUT of the preimage and re-stamping after a health transition MUST NOT change `content_hash`*
|
|
54
|
+
- **Spec Reference:** §20 →2, §20 →11.2.2 (`LINK_INTEGRITY` field snapshot)
|
|
55
|
+
- **Description:** Mutable health fields `health_state` and `health_checked_at` ARE part of the preimage (drift detection is cryptographically anchored to write-time state). The `LINK_INTEGRITY` proof's `field_snapshot` MUST cover exactly the CEL-001 field set. Re-stamping after a health transition MUST yield a new, deterministic hash.
|
|
56
|
+
- **Verification Protocol:** Recompute over stored canonical fields; MUST equal stored `content_hash`.
|
|
57
|
+
|
|
58
|
+
**CEL-004** — `LinkAcceptedDelta` audit binding
|
|
59
|
+
- **Class:** REQUIRED
|
|
60
|
+
- **Spec Reference:** §20 →5, §20 →11.4
|
|
61
|
+
- **Description:** Asserting a link (`assert_episode_link`) MUST emit a `LINK_ACCEPTED` `AuditRecord` on the **source-episode** chain, carrying forward delta (`link_id`, `source_episode`, `target_episode`, `link_type`, `link_strength`, `is_inferred`, `retroactive`) and reverse delta (`reverse_delete_link_id`). The record's `record_hash` MUST chain off `prior_audit_hash` and recompute deterministically.
|
|
62
|
+
- **Failure Condition:** A link node created with no corresponding `LINK_ACCEPTED` audit record, or an audit record whose recomputed hash diverges from stored.
|
|
63
|
+
|
|
64
|
+
### 2.2 Mutual-Exclusivity Governance (§20 →3)
|
|
65
|
+
|
|
66
|
+
**CEL-005** — Link-type mutual exclusivity
|
|
67
|
+
- **Class:** REQUIRED
|
|
68
|
+
- **Spec Reference:** §20 →3 (Link Type Taxonomy)
|
|
69
|
+
- **Description:** `enforce_link_mutual_exclusivity()` MUST raise `LinkGovernanceError` when a new link type collides with an existing type on the same `(source_episode, target_episode)` pair. The exclusion set is exactly `{CONTINUES_FROM, SUPERSEDES}` and `{CONTINUES_FROM, BRANCHES_FROM}`. `SUPERSEDES` and `BRANCHES_FROM` MUST coexist; all other types compose freely.
|
|
70
|
+
- **Failure Condition:** A `(source, target)` pair carries both `CONTINUES_FROM` and `SUPERSEDES` (or both `CONTINUES_FROM` and `BRANCHES_FROM`), or a valid compatible pair is spuriously rejected.
|
|
71
|
+
|
|
72
|
+
**CEL-006** — Endpoint existence precondition
|
|
73
|
+
- **Class:** REQUIRED
|
|
74
|
+
- **Spec Reference:** §20 →2, IMPLEMENTATION §4.4
|
|
75
|
+
- **Description:** A link assertion whose source or target Episode does not exist MUST be rejected before any node/edge write (no orphan links). The `LINKED_TO {via: link_id}` edge MUST carry the link_id for one-hop edge→node lookup.
|
|
76
|
+
|
|
77
|
+
**CEL-007** — Resumption isolation rule
|
|
78
|
+
- **Class:** RECOMMENDED
|
|
79
|
+
- **Spec Reference:** §20 →3 (Resumption isolation rule)
|
|
80
|
+
- **Description:** On episode resumption the loader MUST follow `CONTINUES_FROM` and `SUPERSEDES` links (spine traversal) and MAY follow `INFORMED_BY` / `SPAWNED_FROM` up to one hop. `REFERENCES` links are non-loading — available for audit but MUST NOT trigger content retrieval on resumption.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 3. Link Health & Quarantine Vectors (§20 →6, →11.3)
|
|
85
|
+
|
|
86
|
+
**LH-001** — Health-state FSM
|
|
87
|
+
- **Class:** REQUIRED
|
|
88
|
+
- **Spec Reference:** §20 →6 (Link Health State Machine)
|
|
89
|
+
- **Description:** The health FSM MUST admit exactly the transitions in §20 →6: `VALID → {STALE, FROZEN, BROKEN, QUARANTINED}`, `STALE → {BROKEN, QUARANTINED}`, `QUARANTINED → {VALID (CONFIRMED), BROKEN (DISSOLVED), ESCALATED (TTL)}`, `BROKEN → QUARANTINED (re-evaluation)`. There is NO automatic `QUARANTINED → BROKEN`; exit requires an explicit `QuarantineResolution`.
|
|
90
|
+
- **Verification Protocol:** Given a state and a transition trigger, the resulting state MUST match the FSM; illegal transitions MUST be rejected, not silently applied.
|
|
91
|
+
- **Failure Condition:** A quarantined link auto-transitions to `BROKEN` without an explicit resolution, or a major-version target advance auto-transitions to `BROKEN` (it MUST route to human review, remaining `VALID`/`STALE`).
|
|
92
|
+
|
|
93
|
+
**LH-002** — Quarantine resolution semantics
|
|
94
|
+
- **Class:** REQUIRED
|
|
95
|
+
- **Spec Reference:** §20 →11.3.1, `QuarantineResolution` enum
|
|
96
|
+
- **Description:** `CONFIRMED` → `health_state = VALID`; `DISSOLVED` → `health_state = BROKEN`; both set `quarantine_resolved_at` + `quarantine_resolution` and emit `LINK_QUARANTINE_RESOLVED`. `ESCALATED` keeps `health_state = QUARANTINED` and emits `QUARANTINE_ESCALATED`. Escalated links MUST NOT auto-resolve — human review is required to reach `CONFIRMED`/`DISSOLVED`.
|
|
97
|
+
|
|
98
|
+
**LH-003** — Per-Episode quarantine queue
|
|
99
|
+
- **Class:** REQUIRED
|
|
100
|
+
- **Spec Reference:** §20 →11.1.4 (ephemeral coordinator, quarantine queue scope)
|
|
101
|
+
- **Description:** The quarantine queue MUST be scoped per Episode and ordered by quarantine deadline. How the coordinator represents it — key names, data structure — is an implementation choice. A single global queue across all Episodes is non-conforming.
|
|
102
|
+
- **Failure Condition:** A single global quarantine queue is used, causing a quarantine event in one Episode to be processed in another's context.
|
|
103
|
+
|
|
104
|
+
**LH-004** — Quarantine escalation event
|
|
105
|
+
- **Class:** REQUIRED
|
|
106
|
+
- **Spec Reference:** §20 →11.3.3 (quarantine escalation)
|
|
107
|
+
- **Description:** On TTL breach a `QUARANTINE_ESCALATED` audit event MUST fire carrying `link_id`, `episode_id`, `quarantined_at`, `ttl_deadline`, `escalated_at`, `escalation_reason ∈ {TTL_EXCEEDED, INTEGRITY_UNRESOLVABLE, HUMAN_REQUIRED}`. The link remains `QUARANTINED`.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 4. Inference Signal & Discovery Vectors (§20 →4, →5, →12.2)
|
|
112
|
+
|
|
113
|
+
**SG-001** — `Signal` recording completeness
|
|
114
|
+
- **Class:** REQUIRED
|
|
115
|
+
- **Spec Reference:** §20 →4 (Inference Signal Specification)
|
|
116
|
+
- **Description:** Every signal contributing to a candidate's composite score MUST be recorded in `inference_signals` with `signal_type ∈ {SEMANTIC_SIMILARITY, PARTICIPANT_OVERLAP, TEMPORAL_PROXIMITY, EXPLICIT_REFERENCE, SHARED_ARTIFACT}`, `signal_weight`, `signal_value`, `computed_at`. Signals are canonicalized into the CEL-001 preimage via `model_dump()` (recursively, in list order). Signal **combination** (weights, composite formula) is behavioral-tier (sovereign); signal **recording** is required.
|
|
117
|
+
- **Failure Condition:** A composite score computed from a signal not present in the recorded `inference_signals` list.
|
|
118
|
+
|
|
119
|
+
**SG-002** — `LINK_PROPOSED` audit-the-decision
|
|
120
|
+
- **Class:** REQUIRED
|
|
121
|
+
- **Spec Reference:** §20 →5, §20 →12.2, §1 (constants)
|
|
122
|
+
- **Description:** `propose_link_candidate()` (score in `[DISCOVERY_THRESHOLD, AUTO_ACCEPT_THRESHOLD)`) MUST emit an append-only `LINK_PROPOSED` audit event carrying `composite_score`, the full `inference_signals` breakdown, and `discovery_threshold_at_creation` + `auto_accept_threshold_at_creation` (the threshold values in effect at proposal time). No `EpisodeLink` node is created. The returned `audit_id` correlates later accept/reject decisions.
|
|
123
|
+
- **Failure Condition:** A proposal that omits the threshold-at-creation values, defeating post-hoc calibration.
|
|
124
|
+
|
|
125
|
+
**SG-003** — `CANDIDATE_REJECTED` sub-threshold recording
|
|
126
|
+
- **Class:** REQUIRED
|
|
127
|
+
- **Spec Reference:** §20 →5 (CANDIDATE_REJECTED note), §1
|
|
128
|
+
- **Description:** `record_candidate_rejection()` (score strictly `< DISCOVERY_THRESHOLD`) MUST emit an append-only `CANDIDATE_REJECTED` audit event with full signals + `discovery_threshold_at_creation`. Not surfaced for human review; exists purely so the calibration loop can analyze sub-threshold patterns.
|
|
129
|
+
|
|
130
|
+
**SG-004** — `LINK_REJECTED` proposal correlation
|
|
131
|
+
- **Class:** REQUIRED
|
|
132
|
+
- **Spec Reference:** §20 →5, `RejectionReason` enum
|
|
133
|
+
- **Description:** `record_link_rejection()` MUST emit `LINK_REJECTED` carrying `proposed_audit_event_id` (the `LINK_PROPOSED` it rejects) and `rejection_reason ∈ {LOW_CONFIDENCE, WRONG_RELATIONSHIP_TYPE, NOT_RELATED, DUPLICATE_OF_EXISTING}`. Rejection is a new forward event (append-only) — it MUST NOT mutate or delete the prior proposal record.
|
|
134
|
+
- **Failure Condition:** A rejection that overwrites the proposal, or omits the `proposed_audit_event_id` linkage.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 5. Episode Membership Vectors (§20 →7, →11.3.2)
|
|
139
|
+
|
|
140
|
+
### 5.1 Hash Canonicalization
|
|
141
|
+
|
|
142
|
+
**MR-001** — `MembershipRecord` content hash
|
|
143
|
+
- **Class:** REQUIRED
|
|
144
|
+
- **Spec Reference:** §20 →7, §20 →10 (forward-pointer exclusion)
|
|
145
|
+
- **Description:** `compute_membership_record_content_hash()` canonicalizes, in order (from `_MEMBERSHIP_HASH_PREIMAGE_FIELDS`): `record_id`, `episode_id`, `group_id`, `group_system`, `asserted_at`, `asserted_by`, `membership_role`, `supersedes_record_id`, `succession_reason`. Same §3-canonicalizer (SHA3-256, `sort_keys=False`) as CEL-001. `membership_role` is INCLUDED: role is content, so a role change requires a new record via succession.
|
|
146
|
+
- **Verification Protocol:** Cross-implementation consistency check. Two conforming implementations MUST produce identical bytes for the same input tuple.
|
|
147
|
+
- **Failure Condition:** `membership_role` omitted from the preimage (would let a role edit go uncommitted), or `superseded_by_record_id` included (would invalidate a sealed record's hash on later succession).
|
|
148
|
+
|
|
149
|
+
**MR-002** — Forward-pointer exclusion
|
|
150
|
+
- **Class:** REQUIRED
|
|
151
|
+
- **Spec Reference:** §20 →10, §20 →11.3.2
|
|
152
|
+
- **Description:** `superseded_by_record_id` MUST NOT appear in the `MembershipRecord` preimage. Setting it (when a later record supersedes this one) MUST NOT change this record's `content_hash`.
|
|
153
|
+
- **Failure Condition:** A prior record's `content_hash` changes when its `superseded_by_record_id` forward pointer is set during succession.
|
|
154
|
+
|
|
155
|
+
### 5.2 Succession Chain
|
|
156
|
+
|
|
157
|
+
**MR-003** — Immutable-with-succession chain integrity
|
|
158
|
+
- **Class:** REQUIRED
|
|
159
|
+
- **Spec Reference:** §20 →7 (Immutability rule), §20 →11.3.2
|
|
160
|
+
- **Description:** `MembershipRecord` is append-only. A successor with `supersedes_record_id` set MUST be rejected unless the prior exists, is not already superseded, and shares the same `episode_id` + `(group_id, group_system)`. On success, `(new)-[:SUPERSEDES]->(prior)` is wired and the prior's `superseded_by_record_id` forward pointer is set. The **active** record for a `(episode_id, group_id, group_system)` tuple is the one with no `superseded_by_record_id`.
|
|
161
|
+
- **Failure Condition:** A prior record superseded twice, a cross-group/cross-episode succession accepted, or a prior record deleted/modified in place.
|
|
162
|
+
|
|
163
|
+
**MR-004** — `MEMBERSHIP_CHAIN` proof
|
|
164
|
+
- **Class:** REQUIRED
|
|
165
|
+
- **Spec Reference:** §20 →11.2.3
|
|
166
|
+
- **Description:** A `MEMBERSHIP_CHAIN` proof MUST re-verify the ordered `content_hash` of each record oldest-first and identify the single active (terminal) record. Any broken link or invalid hash MUST yield `BROKEN_CHAIN` / `INVALID`.
|
|
167
|
+
|
|
168
|
+
**MR-005** — Membership audit events
|
|
169
|
+
- **Class:** REQUIRED
|
|
170
|
+
- **Spec Reference:** §20 →11.4
|
|
171
|
+
- **Description:** `assert_membership_record()` MUST emit `MEMBERSHIP_RECORD_CREATED` unconditionally, and additionally `MEMBERSHIP_RECORD_SUPERSEDED` on any succession — carrying `old_role` + `new_role` so role-change history is queryable from the audit log alone. The `SUPERSEDED` record MUST chain directly off the `CREATED` record's `record_hash` (both describe one operation).
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 6. Grouping Conformance Vectors (§20 →8, Appendix A)
|
|
176
|
+
|
|
177
|
+
### 6.1 Hash Canonicalization
|
|
178
|
+
|
|
179
|
+
**CD-001** — `ConformanceDeclaration` hash
|
|
180
|
+
- **Class:** REQUIRED
|
|
181
|
+
- **Spec Reference:** §20 →8, §20 →10
|
|
182
|
+
- **Description:** `compute_conformance_declaration_hash()` canonicalizes, in order (from `_DECLARATION_HASH_PREIMAGE_FIELDS`): `declaration_id`, `group_id`, `group_system`, `declared_at`, `declared_by`, `declaration_version`, `capabilities`. Same §3-canonicalizer. `capabilities` is a `list[Capability]`; each canonicalizes via `model_dump()` (recursively, in list order — `capability_id` + `description`). `superseded_by` is EXCLUDED (forward pointer, §20 →10).
|
|
183
|
+
- **Verification Protocol:** Cross-implementation consistency check. Two conforming implementations MUST produce identical bytes for the same input tuple.
|
|
184
|
+
- **Failure Condition:** `superseded_by` included, capability ordering not preserved, or field order divergence.
|
|
185
|
+
|
|
186
|
+
### 6.2 SemVer Governance
|
|
187
|
+
|
|
188
|
+
**CD-002** — SemVer format enforcement
|
|
189
|
+
- **Class:** REQUIRED
|
|
190
|
+
- **Spec Reference:** §20 →8
|
|
191
|
+
- **Description:** `enforce_semver_format()` MUST reject any `declaration_version` that is not a strict `major.minor.patch` non-negative triplet (pre-release / build-metadata suffixes rejected), raising `GroupingGovernanceError`.
|
|
192
|
+
|
|
193
|
+
**CD-003** — Version-bump classification
|
|
194
|
+
- **Class:** REQUIRED
|
|
195
|
+
- **Spec Reference:** §20 →8 (version semantics table), Appendix A
|
|
196
|
+
- **Description:** `classify_version_bump(old, new)` MUST require `new > old` strictly (raise otherwise) and return `"major"` (major component changed), `"minor"` (minor changed), or `"patch"`. Level-skips (e.g. 1.0.0 → 3.0.0) are accepted as their highest changed component. Major → breaking; minor/patch → compatible.
|
|
197
|
+
- **Failure Condition:** A non-increasing version accepted, or a bump misclassified against the §20 →8 table.
|
|
198
|
+
|
|
199
|
+
**CD-004** — Bump audit-event selection
|
|
200
|
+
- **Class:** REQUIRED
|
|
201
|
+
- **Spec Reference:** §20 →11.4, §20 →8
|
|
202
|
+
- **Description:** `bump_conformance_declaration()` MUST emit `DECLARATION_SUPERSEDED` for a major bump and `DECLARATION_VERSION_BUMPED` for a minor/patch bump, wire `(old)-[:SUPERSEDED_BY]->(new)`, set the prior's `superseded_by` forward pointer, and anchor the audit event to the synthetic chain key `declaration:{group_system}:{group_id}`. Initial `register_conformance_declaration()` MUST NOT fire an audit event (only bumps do).
|
|
203
|
+
- **Failure Condition:** A major bump emitting `DECLARATION_VERSION_BUMPED` (or vice versa); an initial registration firing a spurious event; declaration events anchored to an episode chain instead of the synthetic key.
|
|
204
|
+
|
|
205
|
+
**CD-005** — Breaking-change reference (Appendix A)
|
|
206
|
+
- **Class:** RECOMMENDED
|
|
207
|
+
- **Spec Reference:** §20 Appendix A
|
|
208
|
+
- **Description:** Implementations SHOULD classify as **major** any change that renames/removes/retypes a field appearing in a `content_hash` preimage, or changes the hash algorithm / canonical serialization; as **minor** any new optional field, new `LinkType`, new `AuditEventType`, or new `LinkHealthState`; as **patch** documentation/threshold/editorial changes.
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## 7. Governance Enforcement Matrix
|
|
213
|
+
|
|
214
|
+
Cross-Episode Linking & Grouping has **no numbered SPEC G-rules**. Governance is enforced via error taxonomies, the health/quarantine FSM, and succession-chain integrity. This matrix maps each enforcement mechanism to its vector(s).
|
|
215
|
+
|
|
216
|
+
| Mechanism | Enforcement surface | Vector(s) |
|
|
217
|
+
|-----------|---------------------|-----------|
|
|
218
|
+
| Link mutual exclusivity | `LinkGovernanceError` (`enforce_link_mutual_exclusivity`) | CEL-005 |
|
|
219
|
+
| Endpoint existence | `ValueError` in `write_episode_link_sync` | CEL-006 |
|
|
220
|
+
| Quarantine-field hash exclusion | `_HASH_PREIMAGE_FIELDS` (§20 →2) | CEL-002 |
|
|
221
|
+
| Link health FSM | Health-state transition rules (§20 →6) | LH-001, LH-002 |
|
|
222
|
+
| Per-Episode quarantine queue | Coordinator queue scope (§20 →11.1.4) | LH-003 |
|
|
223
|
+
| Quarantine escalation | `QUARANTINE_ESCALATED` (§20 →11.3.3) | LH-004 |
|
|
224
|
+
| Signal recording | Audit-the-decision (§20 →4, →12.2) | SG-001, SG-002, SG-003, SG-004 |
|
|
225
|
+
| Membership hash inclusion/exclusion | `_MEMBERSHIP_HASH_PREIMAGE_FIELDS` (§20 →7, →10) | MR-001, MR-002 |
|
|
226
|
+
| Membership succession integrity | Chain checks in `write_membership_record_sync` | MR-003, MR-004, MR-005 |
|
|
227
|
+
| Declaration forward-pointer exclusion | `_DECLARATION_HASH_PREIMAGE_FIELDS` (§20 →8, →10) | CD-001 |
|
|
228
|
+
| SemVer governance | `GroupingGovernanceError` (`enforce_semver_format` / `classify_version_bump`) | CD-002, CD-003, CD-004 |
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## 8. Conformance Levels
|
|
233
|
+
|
|
234
|
+
### Level 1: Protocol Conformance (Wire + State tiers)
|
|
235
|
+
|
|
236
|
+
Implementation passes all **REQUIRED** vectors in sections 2–6 and the governance matrix in section 7. This makes two implementations interoperable — they can exchange `EpisodeLink`, `MembershipRecord`, and `ConformanceDeclaration` structures and verify each other's hashes (wire tier, §20 →12.1), and their audit logs are comparable (state tier). No claim is made about storage layout, embedding model, or scoring algorithm.
|
|
237
|
+
|
|
238
|
+
### Level 2: Full Conformance
|
|
239
|
+
|
|
240
|
+
Level 1 plus all **RECOMMENDED** vectors (CEL-007 resumption isolation, CD-005 breaking-change classification) and the storage-architecture obligations of §20 →11.1 / →11.5 (write-order invariant, active-record index, consistency-window SLA).
|
|
241
|
+
|
|
242
|
+
### Behavioral tier (sovereign — no conformance requirement)
|
|
243
|
+
|
|
244
|
+
Signal-combination algorithm, embedding-model selection, threshold-calibration strategy, and internal indexing are implementation decisions (§20 →12.1). The protocol requires only that the *decision* is recorded (audit-the-decision, §20 →12.2), which is covered by the `SG-` vectors.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## 9. Cross-Reference
|
|
249
|
+
|
|
250
|
+
- **SPEC.md §20** — normative protocol surface (v3.2.1); internal §1–§12 numbering cited as `§20 →N`.
|
|
251
|
+
- **IMPLEMENTATION-CROSS-EPISODE-LINKING.md** — the reference deployment's adapter guide (non-normative; shipped with that adapter, not with the protocol).
|
|
252
|
+
- **CONFORMANCE-BFM.md** — sibling BFM vector set (SPEC §19); shares the cross-implementation-consistency vector format.
|
|
253
|
+
- **`astp/core/hash_canonical.py`** — the shared canonicalizer that every `CEL-`/`MR-`/`CD-` hash vector references.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
*ASTP Cross-Episode Linking & Grouping Conformance Test Vectors are maintained by Scorched Earth Labs.*
|
|
258
|
+
*Vector set version: 1.0.0 | Applies to SPEC.md: v3.2.1 §20*
|