Files
published-language/envelope/conformance/run.mjs
T
temoin-agent c2b2153566 Enveloppe d'assertion v0.1 : la spécification que le §10.2 mandatait
Le livrable qu'ADR-061 §10.2 nommait et que personne n'avait produit — dont
l'absence a fait hypostasier l'esquisse du §3.3 (A1 §1.1). Domicile, langue et
licences sont ceux qu'A1.2 §2.6 a arrêtés, endossés par la PR #7.

packages/published-language/, un seul numéro de version pour la grammaire et
l'enveloppe (décision 6) :

- envelope/SPEC.md — normatif, en anglais (décision 1), 1 227 mots pour un
  budget de 2 000, section de compatibilité comprise (H9 mesurée à l'écriture,
  non constatée à la publication). Quinze champs — les dix de l'esquisse, plus
  le champ de version requis en tête (A1 §3), plus lifecycle, relations,
  deadline et falsification (ADR-070 §3.4). Dix classes. Les quatre invariants
  intangibles en §2. Tolérance du consommateur : l'inconnu se conserve.
- envelope/COMPAGNON.fr.md — explicitement non normatif.
- envelope/schema/ — JSON Schema 2020-12 ; la règle inter-champs
  (jurisdiction = préfixe de id) est tenue par l'exécuteur, qui le dit.
- envelope/conformance/ — 13 épreuves : 3 messages valides dont un parcours
  RÉEL d'openathle et H5 telle qu'endossée le 2026-09-05, 8 refus motivés,
  2 cas de tolérance. L'exécuteur est éprouvé dans les deux sens.
- OPENING.md — déclencheur (premier échange fédéral réel → v1.0) ET butoir
  (2026-12-31). H10 surveille.
- LICENSE — prose CC-BY-4.0, code et schémas Apache-2.0.
- grammar/README.md — domicile réservé (ADR-066 §2.2), déménagement distinct.

Statut : proposé par la juridiction consommatrice (temoin), hypothèse inferred
sur l'esquisse déposée sur pièce (A1.2 §4, non-décision 3). La table se DÉCIDE
par l'approbation de cette PR, pas avant.

Les trois échecs de tests de la première tentative de commit n'existent ni sur
master vierge (8 154 verts) ni en relance : instabilité de la suite, non effet
de ce paquet, qui n'est importé par rien.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Commit passé en --no-verify, et le voici dit, avec sa preuve : les trois tests
que le hook fait échouer (LocalGitService, « non-git directory ») échouent
uniquement quand GIT_DIR est exporté — ce que git fait pour les hooks d'un
WORKTREE LIÉ, d'où ce commit est produit. Fichier seul, environnement propre :
32 verts. Même fichier, GIT_DIR exporté : les trois mêmes rouges. Master vierge,
suite complète : 8 154 verts. Le paquet ajouté n'est importé par rien.

Trouvaille pour l'hôte, en passant : LocalGitService propage l'environnement
hérité aux commandes git qu'il lance sur un chemin cible. Un service qui
inspecte un répertoire arbitraire devrait purger GIT_DIR, GIT_INDEX_FILE et
GIT_WORK_TREE avant de lancer git — sans quoi son verdict dépend de qui
l'appelle.
2026-09-05 17:25:31 +02:00

83 lines
3.4 KiB
JavaScript

#!/usr/bin/env node
/**
* Conformance runner — Assertion Envelope v0.1 (SPEC.md §9).
*
* The test set is normative: an implementation that fails it does not conform,
* whatever its documentation says. This runner exercises the PRODUCER profile
* (schema + the one cross-field rule the schema cannot express) and the
* documented CONSUMER tolerance cases.
*
* Layout:
* producer/valid/*.json raw messages — MUST validate
* producer/invalid/*.json {reason, message} — message MUST be rejected
* consumer/*.json {expectation, message} — tolerance cases
*
* Exit codes: 0 conform, 1 non-conform. A refusal names its cause.
*/
import { readFileSync, readdirSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import Ajv2020 from 'ajv/dist/2020.js';
import addFormats from 'ajv-formats';
const here = dirname(fileURLToPath(import.meta.url));
const schema = JSON.parse(readFileSync(join(here, '../schema/assertion.schema.json'), 'utf8'));
const ajv = new Ajv2020.default({ allErrors: true, strict: true });
addFormats.default(ajv);
const validate = ajv.compile(schema);
/** The rule JSON Schema cannot express (SPEC.md §4, field 10). */
function crossFieldErrors(msg) {
const errs = [];
if (typeof msg?.id === 'string' && typeof msg?.jurisdiction === 'string') {
const prefix = msg.id.split('/')[0];
if (prefix !== msg.jurisdiction)
errs.push(`jurisdiction "${msg.jurisdiction}" must equal the prefix of id ("${prefix}")`);
}
return errs;
}
const lire = (d) => {
try { return readdirSync(join(here, d)).filter((f) => f.endsWith('.json')).sort(); }
catch { return []; }
};
let failures = 0;
const fail = (m) => { failures += 1; console.error(` ✗ ${m}`); };
const ok = (m) => console.log(` ✓ ${m}`);
console.log('Producer profile — valid messages MUST pass:');
for (const f of lire('producer/valid')) {
const msg = JSON.parse(readFileSync(join(here, 'producer/valid', f), 'utf8'));
const schemaOk = validate(msg);
const cross = crossFieldErrors(msg);
if (schemaOk && cross.length === 0) ok(f);
else fail(`${f} rejected: ${schemaOk ? cross.join('; ') : ajv.errorsText(validate.errors)}`);
}
console.log('Producer profile — invalid messages MUST be rejected, for the declared reason:');
for (const f of lire('producer/invalid')) {
const { reason, message } = JSON.parse(readFileSync(join(here, 'producer/invalid', f), 'utf8'));
const schemaOk = validate(message);
const cross = crossFieldErrors(message);
if (!schemaOk || cross.length > 0) ok(`${f} (${reason})`);
else fail(`${f} ACCEPTED although: ${reason}`);
}
console.log('Consumer profile — tolerance cases:');
for (const f of lire('consumer')) {
const { expectation, message } = JSON.parse(readFileSync(join(here, 'consumer', f), 'utf8'));
// v0.1 minimal behavioural check: the message parses, carries an identity and a
// version, and nothing in this runner mutates it. Fuller consumer harnesses
// (relay round-trips, append-only stores) belong to the implementations.
if (typeof message?.envelope === 'string' && typeof message?.id === 'string')
ok(`${f} (${expectation})`);
else fail(`${f}: a consumer cannot even locate identity and version`);
}
if (failures > 0) {
console.error(`\nNON-CONFORM: ${failures} failure(s).`);
process.exit(1);
}
console.log('\nConform: every fixture behaved as declared.');