From f3d7383748fddab37065ce8a0c429139db70bda0 Mon Sep 17 00:00:00 2001 From: temoin-agent Date: Mon, 21 Sep 2026 13:53:04 +0200 Subject: [PATCH] =?UTF-8?q?SPEC=20v1.2=20:=20la=20mesure=20nomme=20ce=20qu?= =?UTF-8?q?'elle=20a=20examin=C3=A9=20(relations.confirms)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le sens est la décision entière : c'est la MESURE qui déclare ce qu'elle confirme, jamais l'assertion confirmée qui pointe en retour. Trois raisons suffisantes chacune : l'assertion confirmée existe déjà et ne se réécrit pas ; l'instrument sait ce qu'il a mesuré — le lien est inféré, jamais saisi ; et l'auteur d'une confirmation est la machine, non l'agent dont l'affirmation est confirmée. Le runner refuse confirms sur autre chose qu'une mesure de provenance measured. Mineur et ignorable : un consommateur qui ignore la clé la préserve. Co-Authored-By: Claude Fable 5.1 --- envelope/SPEC.md | 23 +++++++++++++++++-- .../invalid/confirms-on-non-measure.json | 20 ++++++++++++++++ .../producer/valid/measure-confirms.json | 17 ++++++++++++++ envelope/conformance/run.mjs | 5 ++++ envelope/schema/assertion.schema.json | 11 ++++++--- package.json | 2 +- 6 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 envelope/conformance/producer/invalid/confirms-on-non-measure.json create mode 100644 envelope/conformance/producer/valid/measure-confirms.json diff --git a/envelope/SPEC.md b/envelope/SPEC.md index 9a1de38..9ef5f6e 100644 --- a/envelope/SPEC.md +++ b/envelope/SPEC.md @@ -1,4 +1,4 @@ -# Assertion Envelope — Specification v1.1 +# Assertion Envelope — Specification v1.2 **Status**: stable. Declared v1.0 upon the first real federated exchange between two distinct jurisdictions — openathle → Prismagram, endorsed @@ -89,7 +89,7 @@ fields (§7). | 10 | `jurisdiction` | string | REQUIRED. MUST equal the prefix of `id`. Lowercase ASCII, no separators | | 11 | `at` | string | REQUIRED. RFC 3339 timestamp of the asserted state | | 12 | `lifecycle` | string | REQUIRED. One of `proposed`, `endorsed`, `superseded`, `rejected`, `under_revision` | -| 13 | `relations` | object | REQUIRED, MAY be empty. Keys among `amends`, `supersedes`, `depends_on`, `satellite_of`; values are lists of prefixed ids | +| 13 | `relations` | object | REQUIRED, MAY be empty. Keys among `amends`, `supersedes`, `depends_on`, `satellite_of`, `confirms` (v1.2); values are lists of prefixed ids | | 14 | `deadline` | string or null | REQUIRED. RFC 3339. When a falsifiable statement expires into a verdict | | 15 | `falsification` | string or null | REQUIRED. What observation would make this assertion false. A hypothesis without one is not a hypothesis | @@ -112,6 +112,22 @@ named, versioned and dated. It is OPTIONAL because a consumer that never exposes a derived value never owes one; it is not optional for those who do (§9). +### 4.2 `confirms` — the measure names what it examined (v1.2) + +A `measure` assertion MAY carry `relations.confirms`: the prefixed ids of the +assertions it examined. The direction is deliberate and it is the whole point: +**the measure declares what it confirms; the confirmed assertion is never +edited to point back.** Three reasons, each sufficient. The confirmed +assertion already exists and is append-only. The instrument already knows what +it measured — the link is inferred, never typed. And the author of a +confirmation is the machine that measured, not the agent whose claim is being +confirmed: a producer MUST NOT emit `confirms` on anything but a `measure` of +provenance `measured`. + +A consumer MAY derive, from `confirms`, which assertions have been examined +and when — and MAY treat an assertion that no measure has ever confirmed +differently from one that has. That reading is consumer-local (§4.1). + ## 5. Classes `invariant`, `step_realized`, `transition`, `traversal`, `stressor`, @@ -151,6 +167,9 @@ a standard field is a contract change under §8. governs it (§9). Additive and ignorable: a v1.0 consumer that meets the field preserves it and moves on, exactly as §8 requires of any unknown field. No existing field, class, provenance or rule changed. +- **v1.2 adds the relation kind `confirms`** (§4.2), carried by measures only. + Additive and ignorable: a consumer that does not know the kind preserves it + as any unknown key of `relations` and moves on. - At most **two published versions per year**. Deprecation is announced in this file at least one version before removal. - Consumers MUST accept any message whose `envelope` shares their MAJOR and diff --git a/envelope/conformance/producer/invalid/confirms-on-non-measure.json b/envelope/conformance/producer/invalid/confirms-on-non-measure.json new file mode 100644 index 0000000..2ea3995 --- /dev/null +++ b/envelope/conformance/producer/invalid/confirms-on-non-measure.json @@ -0,0 +1,20 @@ +{ + "reason": "confirms is the measure's word about what it examined; an agent claiming its own assertion is confirmed is self-attestation with a pointer (SPEC §4.2).", + "message": { + "envelope": "1.2", + "id": "temoin/EVI-999", + "class": "step_realized", + "subject": "x", + "statement": "y", + "evidence": [], + "provenance": "agent:claude-code", + "confidence": 0.4, + "endorsement": null, + "jurisdiction": "temoin", + "at": "2026-09-21T08:00:00Z", + "lifecycle": "proposed", + "relations": { "confirms": ["openathle/MES-INV-011-2"] }, + "deadline": null, + "falsification": null + } +} diff --git a/envelope/conformance/producer/valid/measure-confirms.json b/envelope/conformance/producer/valid/measure-confirms.json new file mode 100644 index 0000000..7512071 --- /dev/null +++ b/envelope/conformance/producer/valid/measure-confirms.json @@ -0,0 +1,17 @@ +{ + "envelope": "1.2", + "id": "openathle/MES-INV-011-2", + "class": "measure", + "subject": "INV-011", + "statement": "INV-011 : vérifié à son étage (domaine) et au-dessus — défense en profondeur.", + "evidence": [{ "kind": "epreuve:domaine", "ref": "quarkus-backoffice/src/test/java/org/openathle/LicenceConfig/Domain/ValueObject/RegistryClubRefTest.java:1" }], + "provenance": "measured", + "confidence": 1.0, + "endorsement": null, + "jurisdiction": "openathle", + "at": "2026-09-10T12:12:20.466Z", + "lifecycle": "proposed", + "relations": { "confirms": ["openathle/INV-011"] }, + "deadline": null, + "falsification": null +} diff --git a/envelope/conformance/run.mjs b/envelope/conformance/run.mjs index 62dacc0..a91e524 100644 --- a/envelope/conformance/run.mjs +++ b/envelope/conformance/run.mjs @@ -34,6 +34,11 @@ function crossFieldErrors(msg) { if (prefix !== msg.jurisdiction) errs.push(`jurisdiction "${msg.jurisdiction}" must equal the prefix of id ("${prefix}")`); } + // §4.2 (v1.2) : la mesure nomme ce qu'elle a examiné — et elle seule. + if (Array.isArray(msg?.relations?.confirms) && msg.relations.confirms.length > 0) { + if (msg.class !== 'measure' || msg.provenance !== 'measured') + errs.push(`relations.confirms is carried by a measure of provenance measured only (got class "${msg.class}", provenance "${msg.provenance}")`); + } return errs; } diff --git a/envelope/schema/assertion.schema.json b/envelope/schema/assertion.schema.json index d6f0481..77aae48 100644 --- a/envelope/schema/assertion.schema.json +++ b/envelope/schema/assertion.schema.json @@ -1,7 +1,7 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://prismagram.com/published-language/envelope/1.0/assertion.schema.json", - "title": "Assertion Envelope v1.1", + "title": "Assertion Envelope v1.2", "description": "Producer contract for envelope v1.1 messages (SPEC.md §4). One cross-field rule cannot be expressed here and is enforced by the conformance runner: `jurisdiction` MUST equal the prefix of `id`.", "type": "object", "required": [ @@ -26,9 +26,10 @@ "enum": [ "0.1", "1.0", - "1.1" + "1.1", + "1.2" ], - "description": "Version of the contract. v1.0 is substantively identical to v0.1 (SPEC §8): both values validate. v1.1 adds the optional declared reading (§4.1). A message that does not declare its version is not versioned (A1 §3)." + "description": "Version of the contract. v1.0 is substantively identical to v0.1 (SPEC §8): both values validate. v1.1 adds the optional declared reading (§4.1); v1.2 adds the relation kind `confirms` (§4.2). A message that does not declare its version is not versioned (A1 §3)." }, "id": { "type": "string", @@ -154,6 +155,10 @@ }, "satellite_of": { "$ref": "#/$defs/idList" + }, + "confirms": { + "$ref": "#/$defs/idList", + "description": "v1.2, §4.2. Carried by a `measure` of provenance `measured` only: the ids it examined. The measure points at what it confirms; the confirmed assertion is never edited to point back." } }, "additionalProperties": false diff --git a/package.json b/package.json index 60c01fb..07eee47 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "published-language", - "version": "1.1.0", + "version": "1.2.0", "private": true, "type": "module", "description": "Contrat d'échange inter-juridictions : grammaire source (grammar/) et enveloppe d'assertion (envelope/), sous un seul numéro de version (ADR-061/A1.2 §2.6, décision 6). Public, développé ici par pull request endossée (temoin/DEC-014).", -- 2.54.0