# FPM 0.2 — Interoperability Checklist A second implementation built only from sections 00–06, the JSON Schemas, and the test vectors MUST satisfy every item below. Items are numbered for citation in conformance reports. "MUST/MUST NOT" per RFC 2119. The conformance suite (`tools/conformance`) exercises the items marked ✦ mechanically; the rest are verified by review. ## ENC — Encoding & canonicalization - **ENC-1** ✦ All operations are UTF-8 JSON within the canonical subset: the only numbers are exact integers in `[-(2^53-1), 2^53-1]`. - **ENC-2** ✦ Canonical serialization: no insignificant whitespace; object members sorted by UTF-16 code units; arrays preserve order. - **ENC-3** ✦ String escaping exactly as §2 of the worked examples (shortest form; lowercase `\u00xx` for unescaped controls; raw UTF-8 otherwise). - **ENC-4** ✦ Duplicate object keys anywhere in an operation are rejected (`ERR_NOT_CANONICAL`), never last-wins. - **ENC-5** ✦ Received operations are verified to be in canonical form by byte round-trip; non-canonical bytes are rejected (`ERR_NOT_CANONICAL`). - **ENC-6** ✦ Integer tokens are checked lexically: `1.0`, `1e3`, `-0`, `01` are rejected even if the host JSON parser accepts them. - **ENC-7** ✦ Canonical envelope size is limited to 65 536 bytes; larger operations are rejected (`ERR_TOO_LARGE`). Evidence content beyond the inline limit is stored out of band by hash. ## ID — Identifiers & crypto - **ID-1** ✦ Key ids are `ed25519:` + b64u(32-byte public key), exactly 43 b64u chars, no padding. - **ID-2** ✦ Hashes are `sha256:` + 64 lowercase hex chars. No other hash or key algorithms exist in fpm/0.2. - **ID-3** ✦ Signatures are pure Ed25519 (RFC 8032) over the canonical pre-signature envelope bytes, encoded as 86 b64u chars. - **ID-4** ✦ `op_id = "sha256:" + hex(sha256(canonical bytes of the SIGNED envelope))`. Implementations MUST NOT derive op_id from pre-signature bytes. - **ID-5** ✦ Signature verification uses the `author` key; an op whose signature does not verify is rejected (`ERR_BAD_SIG`) and MUST NOT be merged or forwarded. ## ENV — Envelope - **ENV-1** ✦ Envelope validates against `envelope.schema.json`, including body dispatch by `type`; unknown top-level fields other than `ext` are rejected. - **ENV-2** ✦ `seq == 0 ⇔ prev == null`; otherwise `prev` is the op_id of the same author's previous op and `seq` increments by exactly 1. - **ENV-3** ✦ `heads`, when present, reference only ops from OTHER authors' logs; a head referencing the author's own log is rejected (`ERR_BAD_HEADS`). - **ENV-4** ✦ `ts` is never used as ordering or validity authority; it is display/audit metadata only. - **ENV-5** ✦ `ext` content is preserved byte-for-byte through store, merge, and forward (it is signed), and never alters standard semantics. ## OP — Per-operation semantics - **OP-EI-1** ✦ `evidence-ingest`: `content_inline` permitted only when `content_size ≤ 4096`. - **OP-EI-2** ✦ Raw evidence bytes are content-addressed by `content_hash`; nodes serve raw content only to principals holding provenance-bearing capability over a claim derived from it — never via claim-scope grants alone. - **OP-EI-3** ✦ When `content_inline` is present: `sha256(decode(content_inline)) == content_hash` and decoded length `== content_size`, else reject (`ERR_CONTENT_MISMATCH`). - **OP-CA-1** ✦ `claim-assert.basis` is non-empty and duplicate-free. - **OP-CA-2** ✦ Every basis op_id resolves, in the merged set, to an `evidence-ingest` or `claim-assert`; unresolved → the op is held PENDING (not rejected) until dependencies arrive; resolving to a wrong type → reject (`ERR_BAD_REF`). - **OP-CA-3** ✦ A basis entry that resolves to a refuted (DEAD) op is rejected (`ERR_DEAD_BASIS`). - **OP-CA-4** ✦ `method.kind == "model"` requires `inference` referencing a resolvable `inference-call`. - **OP-CO-1** ✦ `correction.target` resolves to a `claim-assert`; any other type → reject (`ERR_BAD_REF`). - **OP-CO-2** ✦ Multiple corrections of one claim: the winner is selected by the deterministic merge order of section 03 (causal order via `prev`/`heads`; concurrent ties broken by op_id lexicographic order); all corrections remain in the log. - **OP-CO-3** ✦ Claims whose basis (transitively) includes a corrected claim are STALE: retained, not served, eligible for re-derivation. - **OP-RF-1** ✦ `refutation.target` resolves to a `claim-assert` or `evidence-ingest`; refutation of a refutation/grant/etc. → reject (`ERR_BAD_REF`). - **OP-RF-2** ✦ A refuted op is DEAD: never served, never exported under any capability, never valid as future basis; downstream claims become STALE. - **OP-IC-1** ✦ `inference-call.inputs` resolve like basis entries (PENDING if unknown, reject on wrong type). - **OP-IC-2** ✦ Prompts/outputs are referenced by hash only; their raw bytes follow the evidence-content access rule (OP-EI-2). ## LOG / MRG — Log structure & multi-node merge - **LOG-1** ✦ One log per author key; logs are append-only; implementations MUST refuse to overwrite or delete merged ops. - **LOG-2** ✦ Two distinct signed ops with the same `(author, seq)` constitute equivocation: both are retained as evidence, the author's log is frozen at the fork point, and ops after it are not interpreted (`ERR_LOG_FORK`). - **MRG-1** ✦ Merge of multiple logs is a set union keyed by op_id; merging is idempotent, commutative, and associative. - **MRG-2** ✦ Interpretation order is the topological order over (a) intra-log `prev` edges and (b) cross-log `heads` edges; concurrent ops are ordered by op_id lexicographically. Every implementation MUST produce the identical total order for the same op set. - **MRG-3** ✦ Receiving an op whose `prev`/`heads` are unknown holds it PENDING; PENDING ops are not interpreted, served, or counted as basis, but MAY be forwarded. - **MRG-4** ✦ Re-receiving a known op_id is a no-op. ## CAP — Capabilities - **CAP-1** ✦ A claim is servable to a grantee iff: some merged, valid grant names that grantee; the claim's predicate/subject/confidence match the grant's effective scope; and the claim is LIVE (not stale, dead, or pending). - **CAP-2** ✦ Grants never expose raw evidence content; with `include_provenance: true` the grantee receives the derivation skeleton (op_ids, methods, confidences) only. - **CAP-3** ✦ `expires_at` is enforced at serve time against the server's clock; expired grants authorize nothing. - **CAP-4** ✦ A grant with `parent` is valid only if the parent resolves to a `permission-grant`, names the child's author as grantee, and has `delegable: true`. - **CAP-5** ✦ A delegated grant's effective scope is the intersection with every ancestor's effective scope. - **CAP-6** ✦ A delegated grant whose declared scope is not a subset of its parent's effective scope is rejected at merge (`ERR_CAP_ESCALATION`). - **CAP-7** ✦ A revocation is valid only if its author authored the target grant or an ancestor of it; otherwise reject (`ERR_NOT_AUTHORIZED`). - **CAP-8** ✦ Revocation invalidates the target grant and all its descendants from the moment the revocation is merged, on every node that merges it. - **CAP-9** ✦ Nodes MUST propagate revocations with at least the priority of any other op type during sync. ## VER / ERR — Versioning & errors - **VER-1** ✦ Ops tagged with a well-formed but unsupported protocol version are DEFERRED: stored, forwarded, never interpreted, never an error. - **VER-2** ✦ Deferred ops referenced by supported ops keep the referencing ops PENDING (they neither resolve nor break references). - **ERR-1** ✦ Rejection reasons use the error codes of section 05 (`ERR_NOT_CANONICAL`, `ERR_SCHEMA`, `ERR_BAD_SIG`, `ERR_BAD_OPID`, `ERR_LOG_FORK`, `ERR_BAD_REF`, `ERR_DEAD_BASIS`, `ERR_BAD_HEADS`, `ERR_CONTENT_MISMATCH`, `ERR_CAP_ESCALATION`, `ERR_NOT_AUTHORIZED`, `ERR_TOO_LARGE`). - **ERR-2** ✦ Rejected ops are not merged, not forwarded, and never silently repaired. ## VEC — Conformance - **VEC-1** ✦ The implementation reproduces, byte-for-byte, the canonical bytes, signatures, and op_ids of every `valid/` vector when re-creating those ops from the fixed seeds and inputs. - **VEC-2** ✦ The implementation accepts every `valid/` vector, rejects every `invalid/` vector with the expected error code, and defers every `defer/` vector. - **VEC-3** ✦ Vector verification covers the full pipeline order of worked-examples §8 (byte check → schema → version gate → signature → op_id → chain → semantics); short-circuiting in a different order that yields different error codes is non-conforming. - **VEC-4** A conformance report lists each checklist item with pass/fail and, for ✦ items, the vector ids exercising it.