Claim Schema
The JSON Schema for claims in elench.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.invalid/elench/claim/v0.1.json",
"title": "elench claim predicate (v0.1, DRAFT)",
"description": "Carried as the `predicate` of an in-toto Statement inside a DSSE envelope. The envelope supplies signer identity; this schema supplies producer identity, which is a different thing (R2). Status is NOT stored here — it is computed by folding the claim log. A `falsification` record is itself a claim with kind=falsification referencing a target.",
"type": "object",
"required": ["id", "kind", "assertion", "origin", "anchor", "timestamp"],
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"pattern": "^cl_[0-9a-f]{64}$",
"description": "Content address of the claim at creation. Stable across status changes (R1). Never reassigned."
},
"kind": {
"enum": ["assertion", "falsification", "verification", "supersession", "residue-acceptance"],
"description": "falsification/verification/supersession MUST carry `target`. residue-acceptance is the R5 human signature over named unevaluated claims."
},
"target": {
"type": "array",
"items": { "type": "string", "pattern": "^cl_[0-9a-f]{64}$" },
"description": "Claims this record acts upon. Required unless kind=assertion."
},
"assertion": {
"type": "object",
"required": ["form"],
"additionalProperties": false,
"properties": {
"form": {
"enum": ["predicate", "annotation"],
"description": "predicate: machine-checkable, can gate. annotation: prose, searchable, CANNOT gate. Policies MUST NOT read annotations. The BC1 ratio is measured over this field."
},
"expression": {
"type": "object",
"required": ["language", "source"],
"properties": {
"language": { "type": "string", "description": "elench-predicate-v1. See ADR-0004." },
"source": { "type": "string" },
"digest": { "type": "string" }
},
"description": "REQUIRED when form=predicate. A predicate without an executable expression is an annotation wearing a costume; validators MUST reject."
},
"text": {
"type": "string",
"maxLength": 2000,
"description": "Human-readable. Never load-bearing."
}
}
},
"origin": {
"type": "object",
"required": ["kind", "producer"],
"additionalProperties": false,
"properties": {
"kind": {
"enum": ["harness-observed", "agent-asserted", "human-asserted"],
"description": "R2. harness-observed may ONLY be emitted by the harness. See AGENTS.md. Policies may and generally should discriminate on this."
},
"producer": {
"type": "object",
"required": ["id"],
"properties": {
"id": { "type": "string", "description": "Harness build id, model id + version, or human key id." },
"sessionId": { "type": "string" },
"hermeticity": {
"enum": ["none", "container", "vm", "hermetic-derivation"],
"description": "BC3. Self-reported and therefore only as good as the producer. Present so policy can require a floor, not because it is trusted."
}
}
}
}
},
"anchor": {
"$comment": "RESOLVED (E1). The anchor object uses strategy=multi by default — all three strategies (path-range, symbol, content-digest) recorded simultaneously, resolved by agreement, with 'degraded' reported when they disagree. See experiments/E1-anchor-survival-result.md.",
"type": "object",
"required": ["tree", "strategy"],
"properties": {
"tree": { "type": "string", "description": "elench tree OID (content address of the tree state in the store, ADR-0001). Not a git commit OID." },
"strategy": { "enum": ["path-range", "symbol", "content-digest", "multi"], "default": "multi" },
"path": { "type": "string" },
"range": { "type": "array", "items": { "type": "integer" }, "minItems": 2, "maxItems": 2 },
"symbol": { "type": "string", "description": "Language-server qualified name." },
"contentDigest": { "type": "string", "description": "Digest of the anchored span, normalised." }
}
},
"timestamp": {
"type": "integer",
"description": "Unix epoch seconds. Set by the producer at emission time. Used by ADR-0007 for deterministic git commit synthesis — NOT the wall clock at projection time. Two parties projecting the same claim get the same commit timestamp."
},
"evidence": {
"type": "array",
"description": "Empty for agent-asserted claims by default; that emptiness is the signal, not a gap to fill. A human-asserted claim with no evidence is authority without evidence, which is a legitimate and distinguishable state.",
"items": {
"type": "object",
"required": ["kind"],
"properties": {
"kind": { "enum": ["process-exit", "test-report", "artifact-digest", "external-attestation"] },
"digest": { "type": "string" },
"exitCode": { "type": "integer" },
"uri": { "type": "string" }
}
}
},
"dependsOn": {
"type": "array",
"items": { "type": "string", "pattern": "^cl_[0-9a-f]{64}$" },
"description": "Premises. The transitive closure over this field IS the blast radius when something upstream is falsified. This field is the reason the project exists; if it is left empty in practice, revocation cannot propagate and the whole design collapses to per-claim status flags."
}
},
"allOf": [
{
"if": { "properties": { "kind": { "const": "assertion" } } },
"then": { "properties": { "target": { "maxItems": 0 } } }
},
{
"if": { "properties": { "kind": { "not": { "const": "assertion" } } } },
"then": { "required": ["target"] }
},
{
"if": { "properties": { "kind": { "const": "residue-acceptance" } } },
"then": { "properties": { "target": { "minItems": 1 } } }
}
]
}