From 06310ff44da1a777a244a4384edf1d99bea3b212 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 14 Jul 2026 06:25:14 +0000 Subject: [PATCH 1/2] docs: document baseline resilience and update exit codes The catalog-versioning guide covered `fce catalog diff` but said nothing about how `fce catalog update` behaves when the existing baseline is imperfect. Document the resilience contract that ships with the commands: a corrupt or unreadable baseline is regenerated with a warning, while a baseline written by a newer schema is refused (upgrade the tool) rather than silently downgraded. Add the cancellation exit code (130) to the `catalog diff` table and spell out `catalog update`'s exit codes, in both the English and French guides. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01J12ghrzM1xiAKw4LETJDqr --- doc/CatalogVersioning.en.md | 12 +++++++++++- doc/CatalogVersioning.fr.md | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/doc/CatalogVersioning.en.md b/doc/CatalogVersioning.en.md index 300c7b7..6297efb 100644 --- a/doc/CatalogVersioning.en.md +++ b/doc/CatalogVersioning.en.md @@ -41,7 +41,8 @@ The command extracts the current catalog, compares it against the baseline, and | --- | --- | | `0` | No change at or above the `--fail-on` threshold. | | `2` | The contract drifted: at least one change reaches the threshold. | -| `1` | Execution error (missing baseline, failed extraction, …). | +| `1` | Execution error — a missing baseline, a failed extraction, or a baseline written by a newer schema (see below). | +| `130` | Cancelled before completing (Ctrl+C). | `--fail-on` selects the policy: `breaking` (default), `any` (any change at all fails, including additions), or `none` (report only). `--report` selects the output: `text` (default), `markdown` (ready to post as a pull-request comment) or `json` (for tooling). @@ -68,6 +69,15 @@ fce catalog update --solution MyApp.sln The command summarizes what it absorbs (`1 breaking, 2 compatible and 0 documentation change(s) accepted`), and the pull request then shows the baseline diff — a removed code appears as a removed line. The accident becomes impossible; the deliberate change becomes visible and reviewable. This is the same discipline as a public-API baseline file, applied to the error catalog. +## 🛡️ Baseline resilience & schema versioning + +The baseline is a checked-in file, so over a project's life it can be corrupted by a bad merge or produced by a different version of the tool. `fce catalog update` handles each case deliberately rather than silently: + +* **A corrupt or unreadable baseline is regenerated, never fatal.** Updating is exactly how a baseline is (re)built, so an existing file that cannot be parsed is rewritten from the current catalog with a warning — a broken baseline never blocks you. +* **A baseline written by a _newer_ schema is refused, never downgraded.** Every snapshot carries a `schema` version. If a teammate committed a baseline with a newer tool, an older tool will not overwrite it with an older schema — that would silently drop information — so it stops with an error telling you to upgrade. `fce catalog diff` refuses it the same way. Upgrading the tool, or aligning versions across the team, resolves it. + +So `fce catalog update` exits `0` when the baseline is created, already up to date, or refreshed (including a self-healed one); `1` on an execution error or a newer-schema baseline; and `130` if cancelled. + ## ⚙️ Snapshots without a baseline Two more ways to produce and compare snapshots: diff --git a/doc/CatalogVersioning.fr.md b/doc/CatalogVersioning.fr.md index fbb8484..b9f7bdb 100644 --- a/doc/CatalogVersioning.fr.md +++ b/doc/CatalogVersioning.fr.md @@ -41,7 +41,8 @@ La commande extrait le catalogue courant, le compare à la baseline et écrit un | --- | --- | | `0` | Aucun changement au niveau du seuil `--fail-on` ou au-dessus. | | `2` | Le contrat a dérivé : au moins un changement atteint le seuil. | -| `1` | Erreur d'exécution (baseline manquante, extraction en échec, …). | +| `1` | Erreur d'exécution — baseline manquante, extraction en échec, ou baseline écrite par un schéma plus récent (voir plus bas). | +| `130` | Interrompu avant la fin (Ctrl+C). | `--fail-on` choisit la politique : `breaking` (défaut), `any` (tout changement fait échouer, y compris les ajouts) ou `none` (rapport seul). `--report` choisit la sortie : `text` (défaut), `markdown` (prêt à poster en commentaire de pull request) ou `json` (pour l'outillage). @@ -68,6 +69,15 @@ fce catalog update --solution MyApp.sln La commande résume ce qu'elle absorbe (`1 breaking, 2 compatible and 0 documentation change(s) accepted`), et la pull request montre alors le diff de la baseline — un code supprimé apparaît comme une ligne supprimée. L'accident devient impossible ; le changement délibéré devient visible et relisible. C'est la même discipline qu'un fichier de baseline d'API publique, appliquée au catalogue d'erreurs. +## 🛡️ Résilience de la baseline & versionnage du schéma + +La baseline est un fichier versionné : au fil de la vie d'un projet, elle peut être corrompue par un merge malheureux ou produite par une version différente de l'outil. `fce catalog update` traite chaque cas de façon délibérée plutôt que silencieuse : + +* **Une baseline corrompue ou illisible est régénérée, jamais fatale.** Mettre à jour, c'est précisément la façon de (re)construire une baseline : un fichier existant impossible à parser est réécrit à partir du catalogue courant, avec un avertissement — une baseline cassée ne vous bloque jamais. +* **Une baseline écrite par un schéma _plus récent_ est refusée, jamais rétrogradée.** Chaque snapshot porte une version de `schema`. Si un collègue a commité une baseline avec un outil plus récent, un outil plus ancien ne l'écrasera pas avec un schéma plus ancien — cela supprimerait silencieusement de l'information — : il s'arrête avec une erreur vous invitant à mettre à jour. `fce catalog diff` la refuse de la même manière. Mettre à jour l'outil, ou aligner les versions dans l'équipe, résout le problème. + +Ainsi `fce catalog update` sort `0` quand la baseline est créée, déjà à jour ou rafraîchie (y compris auto-réparée) ; `1` sur une erreur d'exécution ou une baseline de schéma trop récent ; et `130` en cas d'interruption. + ## ⚙️ Des snapshots sans baseline Deux autres façons de produire et comparer des snapshots : From 1e4e7e6c3f4b7bba5922ad14ad710593e08ada90 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 14 Jul 2026 06:34:00 +0000 Subject: [PATCH 2/2] docs: add copy-paste CI/CD examples to the catalog guide Each base example showed only the bare `fce` command, leaving the reader to guess who runs it and when. Keep the plain command as the minimal illustration, then add a near-copy-paste CI/CD block beside it: seed the baseline automatically on first run (create + commit only when missing), and accept an intentional contract change from CI via a labelled pull request that regenerates and commits the baseline onto its branch. Added to both the English and French guides, with the same commands. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01J12ghrzM1xiAKw4LETJDqr --- doc/CatalogVersioning.en.md | 56 +++++++++++++++++++++++++++++++++++++ doc/CatalogVersioning.fr.md | 56 +++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/doc/CatalogVersioning.en.md b/doc/CatalogVersioning.en.md index 6297efb..ee150f6 100644 --- a/doc/CatalogVersioning.en.md +++ b/doc/CatalogVersioning.en.md @@ -29,6 +29,24 @@ fce catalog update --solution MyApp.sln This extracts the catalog, projects it into its snapshot, and writes `errors-baseline.json` (override with `--baseline`, or set `baseline` in `fce.json`). **Commit this file**: it is the accepted contract, and every change to it goes through code review like any other contract change. +**In CI/CD**, seed it automatically the first time so no one has to remember to bootstrap it — create and commit the file only when it is missing. This belongs on a push to your default branch, and needs a token that can push: + +```yaml +# Runs on push to main; needs: permissions: { contents: write }. +- name: Seed the error-catalog baseline if missing + run: | + if [ ! -f errors-baseline.json ]; then + fce catalog update --solution MyApp.sln + git add errors-baseline.json + git -c user.name='github-actions[bot]' \ + -c user.email='41898282+github-actions[bot]@users.noreply.github.com' \ + commit -m 'chore: seed the error-catalog baseline' + git push + fi +``` + +Prefer a one-time local bootstrap (run `fce catalog update` and commit) if you would rather keep CI read-only — only `catalog diff` truly needs to run on every pull request. + ## 🔍 Detect drift in CI ```bash @@ -69,6 +87,44 @@ fce catalog update --solution MyApp.sln The command summarizes what it absorbs (`1 breaking, 2 compatible and 0 documentation change(s) accepted`), and the pull request then shows the baseline diff — a removed code appears as a removed line. The accident becomes impossible; the deliberate change becomes visible and reviewable. This is the same discipline as a public-API baseline file, applied to the error catalog. +**In CI/CD**, make accepting a change one action instead of a manual local step: on a pull request labelled `accept-contract-change`, regenerate the baseline and commit it back onto the PR branch, so the change lands as an explicit, reviewable diff (works for same-repository branches; from a fork, run `fce catalog update` locally and push): + +```yaml +# .github/workflows/error-catalog-accept.yml +on: + pull_request: + types: [labeled] + +jobs: + accept: + if: github.event.label.name == 'accept-contract-change' + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + - uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + # Make fce available on the runner (see the full example below). + - name: Regenerate and commit the baseline + run: | + fce catalog update --solution MyApp.sln + git add errors-baseline.json + if git diff --cached --quiet; then + echo 'Baseline already up to date — nothing to accept.' + else + git -c user.name='github-actions[bot]' \ + -c user.email='41898282+github-actions[bot]@users.noreply.github.com' \ + commit -m 'chore: accept error-catalog contract change' + git push + fi +``` + +For a purely local flow, the same two lines behind a `make accept-errors` target work just as well. + ## 🛡️ Baseline resilience & schema versioning The baseline is a checked-in file, so over a project's life it can be corrupted by a bad merge or produced by a different version of the tool. `fce catalog update` handles each case deliberately rather than silently: diff --git a/doc/CatalogVersioning.fr.md b/doc/CatalogVersioning.fr.md index b9f7bdb..391625f 100644 --- a/doc/CatalogVersioning.fr.md +++ b/doc/CatalogVersioning.fr.md @@ -29,6 +29,24 @@ fce catalog update --solution MyApp.sln Cette commande extrait le catalogue, le projette en snapshot et écrit `errors-baseline.json` (modifiable avec `--baseline`, ou via `baseline` dans `fce.json`). **Commitez ce fichier** : c'est le contrat accepté, et chaque modification passe en revue de code comme n'importe quel autre changement de contrat. +**En CI/CD**, initialisez-la automatiquement au premier passage pour que personne n'ait à y penser — créez et commitez le fichier uniquement s'il est absent. Cela relève d'un push sur votre branche par défaut et nécessite un jeton capable de pousser : + +```yaml +# Se déclenche sur push vers main ; nécessite : permissions: { contents: write }. +- name: Seed the error-catalog baseline if missing + run: | + if [ ! -f errors-baseline.json ]; then + fce catalog update --solution MyApp.sln + git add errors-baseline.json + git -c user.name='github-actions[bot]' \ + -c user.email='41898282+github-actions[bot]@users.noreply.github.com' \ + commit -m 'chore: seed the error-catalog baseline' + git push + fi +``` + +Préférez une initialisation locale unique (lancez `fce catalog update` puis commitez) si vous voulez garder la CI en lecture seule — seul `catalog diff` a vraiment besoin de s'exécuter à chaque pull request. + ## 🔍 Détecter la dérive en CI ```bash @@ -69,6 +87,44 @@ fce catalog update --solution MyApp.sln La commande résume ce qu'elle absorbe (`1 breaking, 2 compatible and 0 documentation change(s) accepted`), et la pull request montre alors le diff de la baseline — un code supprimé apparaît comme une ligne supprimée. L'accident devient impossible ; le changement délibéré devient visible et relisible. C'est la même discipline qu'un fichier de baseline d'API publique, appliquée au catalogue d'erreurs. +**En CI/CD**, faites de l'acceptation une action unique plutôt qu'une étape locale manuelle : sur une pull request portant le label `accept-contract-change`, régénérez la baseline et recommitez-la sur la branche de la PR, pour que le changement apparaisse comme un diff explicite et relisible (fonctionne pour les branches du même dépôt ; depuis un fork, lancez `fce catalog update` en local et poussez) : + +```yaml +# .github/workflows/error-catalog-accept.yml +on: + pull_request: + types: [labeled] + +jobs: + accept: + if: github.event.label.name == 'accept-contract-change' + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + - uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + # Rendez fce disponible sur le runner (voir l'exemple complet plus bas). + - name: Regenerate and commit the baseline + run: | + fce catalog update --solution MyApp.sln + git add errors-baseline.json + if git diff --cached --quiet; then + echo 'Baseline already up to date — nothing to accept.' + else + git -c user.name='github-actions[bot]' \ + -c user.email='41898282+github-actions[bot]@users.noreply.github.com' \ + commit -m 'chore: accept error-catalog contract change' + git push + fi +``` + +Pour un flux purement local, les deux mêmes lignes derrière une cible `make accept-errors` font tout aussi bien l'affaire. + ## 🛡️ Résilience de la baseline & versionnage du schéma La baseline est un fichier versionné : au fil de la vie d'un projet, elle peut être corrompue par un merge malheureux ou produite par une version différente de l'outil. `fce catalog update` traite chaque cas de façon délibérée plutôt que silencieuse :