From a954d7f90addd095407079be1ac690e78234c14d Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Thu, 24 Sep 2026 23:40:02 +0200 Subject: [PATCH] 0.0.5-alpha.3.fix.1 --- VERSION | 2 +- deltas/0.0.5/alpha.3.fix.1.md | 164 ++++++++++++++++++++ docs/templates/004-FILE_FAMILY_CONTRACTS.md | 14 +- docs/validation/001-VALIDATION_MATRIX.md | 4 +- history/0.0.5/alpha.3.fix.1.md | 128 +++++++++++++++ scripts/audit_markdown_tables.py | 15 +- tests/test_markdown_tables.py | 90 +++++++++++ 7 files changed, 405 insertions(+), 12 deletions(-) create mode 100644 deltas/0.0.5/alpha.3.fix.1.md create mode 100644 history/0.0.5/alpha.3.fix.1.md create mode 100644 tests/test_markdown_tables.py diff --git a/VERSION b/VERSION index df731ef..a825135 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.5-alpha.3 +0.0.5-alpha.3.fix.1 diff --git a/deltas/0.0.5/alpha.3.fix.1.md b/deltas/0.0.5/alpha.3.fix.1.md new file mode 100644 index 0000000..4fde09b --- /dev/null +++ b/deltas/0.0.5/alpha.3.fix.1.md @@ -0,0 +1,164 @@ + + + +# Delta 0.0.5-alpha.3.fix.1 — couverture des tables dans les exemples Markdown fenced + +## Baseline et version + +Baseline attendue : commit opérateur de `0.0.5-alpha.3`, réalisé après application de `history/0.0.5/alpha.3.md` avec statut `FAIL`. + +Le hash de ce commit n'est pas anticipé. + +Version avant application : + +```text +0.0.5-alpha.3 +``` + +Version après application : + +```text +0.0.5-alpha.3.fix.1 +``` + +## Objet + +Corriger le faux négatif découvert pendant la gate opérateur de `alpha.3` : `audit_markdown_tables.py` ignorait toutes les tables placées dans des blocs fenced, y compris les exemples explicitement `markdown` du template `004-FILE_FAMILY_CONTRACTS.md`. + +Le fix étend uniquement le contrat de l'audit de tables. Il ne transforme pas l'audit en analyseur général des blocs de code et n'introduit aucun contenu de la tranche Rust `alpha.4`. + +## Scope + +REPLACE : + +```text +VERSION +scripts/audit_markdown_tables.py +docs/templates/004-FILE_FAMILY_CONTRACTS.md +docs/validation/001-VALIDATION_MATRIX.md +``` + +ADD : + +```text +tests/test_markdown_tables.py +deltas/0.0.5/alpha.3.fix.1.md +``` + +DELETE : aucun. + +Le history `history/0.0.5/alpha.3.md` appartient au commit baseline du FAIL et n'est pas inclus dans l'archive du fix. + +## Correction + +`scripts/audit_markdown_tables.py` passe en révision interne `2`. + +L'audit continue de contrôler les tables Markdown ordinaires. Dans un bloc fenced : + +- une fence explicitement `markdown` est auditée ; +- une fence explicitement `md` est auditée ; +- une fence d'un autre langage ou sans langage reste ignorée. + +Cette frontière évite les faux positifs sur les sorties terminal, extraits de code ou tableaux ASCII qui utilisent éventuellement des pipes sans être du Markdown à gouverner. + +`tests/test_markdown_tables.py` verrouille quatre cas : + +1. table ordinaire et table fenced Markdown valides toutes deux comptées ; +2. table mal alignée dans une fence `markdown` rejetée ; +3. alias `md` audité ; +4. fence non Markdown conservée hors scope. + +`docs/templates/004-FILE_FAMILY_CONTRACTS.md` passe en révision `2` et réaligne les deux tables fenced révélées par le nouvel audit. + +`docs/validation/001-VALIDATION_MATRIX.md` passe en révision `10` et explicite la frontière de `PGR-MD-TABLE-001`. + +## Validation opérateur + +Après application du history `FAIL`, commit de `alpha.3`, puis application du présent delta : + +```bash +test "$(cat VERSION)" = '0.0.5-alpha.3.fix.1' +test -f history/0.0.5/alpha.3.md +test -f deltas/0.0.5/alpha.3.md +test -f deltas/0.0.5/alpha.3.fix.1.md +test -f tests/test_markdown_tables.py +test ! -e history/0.0.5/alpha.3.fix.1.md + +grep -A2 '^## Statut$' history/0.0.5/alpha.3.md | grep -Fx 'FAIL' +grep -Fx '# version: 2' scripts/audit_markdown_tables.py +grep -Fx '' docs/templates/004-FILE_FAMILY_CONTRACTS.md +grep -Fx '' docs/validation/001-VALIDATION_MATRIX.md +grep -Fx '# version: 1' tests/test_markdown_tables.py + +python3 -B -m unittest discover -s tests -p 'test_markdown_tables.py' -v +python3 -B -m unittest discover -s tests -v + +python3 -B scripts/audit_markdown_headers.py \ + README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts +python3 -B scripts/audit_markdown_tables.py \ + README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts +python3 -B scripts/audit_markdown_links.py \ + README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts + +python3 -B scripts/audit_markdown_tables.py docs/templates/004-FILE_FAMILY_CONTRACTS.md + +python3 -B - <<'PY' +from pathlib import Path +import re + +history = Path('history/0.0.5/alpha.3.md').read_text(encoding='utf-8') +assert re.search(r'## Statut\s+FAIL\s', history) + +script = Path('scripts/audit_markdown_tables.py').read_text(encoding='utf-8') +assert '_MARKDOWN_FENCE_LANGUAGES = frozenset({"markdown", "md"})' in script +assert 'audit_fenced_markdown' in script + +template = Path('docs/templates/004-FILE_FAMILY_CONTRACTS.md').read_text(encoding='utf-8') +assert template.count('```markdown') == 2 + +matrix = Path('docs/validation/001-VALIDATION_MATRIX.md').read_text(encoding='utf-8') +assert 'fences explicitement `markdown` ou `md`' in matrix +assert 'sorties terminal' in matrix + +print('0.0.5 alpha.3.fix.1 fenced Markdown table audit: clean (regression covered, two template examples governed)') +PY + +git diff --check + +git add VERSION scripts/audit_markdown_tables.py tests/test_markdown_tables.py \ + docs/templates/004-FILE_FAMILY_CONTRACTS.md \ + docs/validation/001-VALIDATION_MATRIX.md \ + deltas/0.0.5/alpha.3.fix.1.md + +git diff --cached --check +git status --short +``` + +La sortie Git attendue avant ajout du history du fix est exactement : + +```text +M VERSION +A deltas/0.0.5/alpha.3.fix.1.md +M docs/templates/004-FILE_FAMILY_CONTRACTS.md +M docs/validation/001-VALIDATION_MATRIX.md +M scripts/audit_markdown_tables.py +A tests/test_markdown_tables.py +``` + +Le contrôle ciblé du template doit désormais compter ses deux exemples : + +```text +Markdown table audit: clean (2 table(s), 1 file(s)) +``` + +La suite Python doit compter `19` tests si aucun autre test n'est ajouté localement avant exécution. + +## Transition + +### PASS + +Créer et appliquer séparément `history/0.0.5/alpha.3.fix.1.md`, committer et pousser le fix, puis reprendre le plan `0.0.5` à `alpha.4`. + +### FAIL + +Rester dans `0.0.5-alpha.3.fix.M`. Le scope MUST rester limité au contrat de `PGR-MD-TABLE-001` et aux tables révélées par ce contrôle tant qu'aucun défaut plus large ne justifie un REPLAN. diff --git a/docs/templates/004-FILE_FAMILY_CONTRACTS.md b/docs/templates/004-FILE_FAMILY_CONTRACTS.md index 7827af1..1c49f02 100644 --- a/docs/templates/004-FILE_FAMILY_CONTRACTS.md +++ b/docs/templates/004-FILE_FAMILY_CONTRACTS.md @@ -1,5 +1,5 @@ - + # Pattern — contrats locaux de fichiers ou familles @@ -43,8 +43,8 @@ validation or synchronization requirement Une table Markdown convient aux registres structurés : ```markdown -| Fichier ou famille | Responsabilité | Règle de modification | -|--------------------|----------------|------------------------| +| Fichier ou famille | Responsabilité | Règle de modification | +|---------------------|------------------|----------------------------| | `` | `` | `` | ``` @@ -65,10 +65,10 @@ Le registre SHOULD évoluer lorsqu'une responsabilité ou règle de modification ## Exemple abstrait ```markdown -| Fichier ou famille | Responsabilité | Règle de modification | -|--------------------|----------------|------------------------| -| `config/*.example` | Décrire les exemples versionnés de configuration locale. | Mettre à jour lorsqu'une option utilisateur versionnée est ajoutée ou retirée ; ne jamais y placer de secret réel. | -| `generated/**` | Contenir les sorties reconstruisibles produites par la toolchain choisie. | Ne pas modifier manuellement ; régénérer depuis la source de vérité documentée. | +| Fichier ou famille | Responsabilité | Règle de modification | +|--------------------|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------| +| `config/*.example` | Décrire les exemples versionnés de configuration locale. | Mettre à jour lorsqu'une option utilisateur versionnée est ajoutée ou retirée ; ne jamais y placer de secret réel. | +| `generated/**` | Contenir les sorties reconstruisibles produites par la toolchain choisie. | Ne pas modifier manuellement ; régénérer depuis la source de vérité documentée. | ``` Cet exemple illustre la forme uniquement. Il ne crée aucune règle universelle sur les chemins `config/` ou `generated/`. diff --git a/docs/validation/001-VALIDATION_MATRIX.md b/docs/validation/001-VALIDATION_MATRIX.md index fabf479..86bfd58 100644 --- a/docs/validation/001-VALIDATION_MATRIX.md +++ b/docs/validation/001-VALIDATION_MATRIX.md @@ -1,5 +1,5 @@ - + # Matrice de validation PGR @@ -27,7 +27,7 @@ Les catégories et règles de sélection sont définies dans [`../rules/400-VALI Un contrôle manuel peut rester dans la matrice lorsqu'aucun audit automatisé fiable n'existe encore. PGR SHOULD automatiser uniquement les propriétés stables et objectivement contrôlables. -`PGR-MD-TABLE-001` reste volontairement monotâche : il contrôle uniquement la structure et l'alignement source des tableaux Markdown. +`PGR-MD-TABLE-001` reste volontairement monotâche : il contrôle uniquement la structure et l'alignement source des tableaux Markdown. Il couvre les tableaux Markdown ordinaires ainsi que les exemples placés dans des fences explicitement `markdown` ou `md`. Les autres blocs fenced restent ignorés afin de ne pas interpréter comme Markdown des sorties terminal, extraits de code ou tableaux ASCII d'un autre langage. `PGR-MD-HEADER-001` contrôle seulement les deux premières lignes des fichiers Markdown sélectionnés : chemin relatif depuis la racine et révision interne positive. La revue `PGR-DOC-001` reste responsable du rôle documentaire et de la pertinence réelle d'un incrément de révision. diff --git a/history/0.0.5/alpha.3.fix.1.md b/history/0.0.5/alpha.3.fix.1.md new file mode 100644 index 0000000..9b1ce6e --- /dev/null +++ b/history/0.0.5/alpha.3.fix.1.md @@ -0,0 +1,128 @@ + + + +# History 0.0.5-alpha.3.fix.1 — couverture des tables dans les exemples Markdown fenced + +## Statut + +PASS + +La gate opérateur de `0.0.5-alpha.3.fix.1` exécutée le `2026-09-24` valide la correction de `PGR-MD-TABLE-001`. Le faux négatif constaté pendant `alpha.3` est couvert par des tests de régression, les deux tables fenced du template `004` sont désormais gouvernées par l'audit et les contrôles documentaires/Git sont propres. + +## Baseline et version + +La tranche part du commit opérateur de `0.0.5-alpha.3`, enregistré après application du history `FAIL`. La sortie Git fournie identifie ce commit sous la forme abrégée : + +```text +1b1a709 0.0.5-alpha.3 +``` + +Le push vers `origin/master` a réussi avant l'application de `alpha.3.fix.1`. + +La version contrôlée après application du fix est : + +```text +0.0.5-alpha.3.fix.1 +``` + +Les artefacts suivants sont présents pendant la gate : + +```text +history/0.0.5/alpha.3.md + +deltas/0.0.5/alpha.3.md +deltas/0.0.5/alpha.3.fix.1.md +tests/test_markdown_tables.py +``` + +`history/0.0.5/alpha.3.fix.1.md` est absent pendant la gate, conformément au workflow. + +## Validation opérateur observée + +Les contrôles de statut et de révision ont réussi : + +```text +history/0.0.5/alpha.3.md FAIL +scripts/audit_markdown_tables.py version 2 +docs/templates/004-FILE_FAMILY_CONTRACTS.md version 2 +docs/validation/001-VALIDATION_MATRIX.md version 10 +tests/test_markdown_tables.py version 1 +``` + +La suite ciblée du nouvel audit a exécuté `4` tests, tous réussis : + +```text +Ran 4 tests in 0.093s + +OK +``` + +Les cas couverts vérifient : + +- le comptage conjoint d'une table ordinaire et d'une table fenced Markdown ; +- le rejet d'une table mal alignée dans une fence `markdown` ; +- l'audit de l'alias `md` ; +- le maintien hors scope des fences non Markdown. + +La suite Python globale a exécuté `19` tests, tous réussis : + +```text +Ran 19 tests in 0.311s + +OK +``` + +Les trois audits documentaires affichent : + +```text +Markdown header audit: clean (134 file(s)) +Markdown table audit: clean (6 table(s), 134 file(s)) +Markdown link audit: clean (127 local link(s), 134 file(s)) +``` + +Le contrôle ciblé du template affiche désormais : + +```text +Markdown table audit: clean (2 table(s), 1 file(s)) +``` + +Le contrôle structurel spécifique affiche : + +```text +0.0.5 alpha.3.fix.1 fenced Markdown table audit: clean (regression covered, two template examples governed) +``` + +Il confirme notamment que l'audit reconnaît uniquement les fences explicites `markdown` ou `md`, que les deux exemples du template sont présents et que la matrice de validation documente l'exclusion volontaire des sorties terminal/non-Markdown. + +`git diff --check` et `git diff --cached --check` n'ont produit aucun diagnostic. + +Le scope Git observé avant ajout du présent history est exactement : + +```text +M VERSION +A deltas/0.0.5/alpha.3.fix.1.md +M docs/templates/004-FILE_FAMILY_CONTRACTS.md +M docs/validation/001-VALIDATION_MATRIX.md +M scripts/audit_markdown_tables.py +A tests/test_markdown_tables.py +``` + +## Résultat + +Le défaut de `alpha.3` est corrigé sans élargir l'audit à des blocs de code qui ne sont pas explicitement du Markdown. `PGR-MD-TABLE-001` couvre maintenant les tables normales ainsi que les exemples fenced Markdown, tout en continuant d'ignorer les fences d'autres langages. + +Aucun nouveau fix de `alpha.3` n'est requis. + +Après la gate, une revue distincte du plan et des historiques de conception PGR a révélé un besoin de gouvernance plus large : le contrat des plans n'assigne pas encore explicitement les responsabilités de clôture/transition et PGR ne définit pas encore de revue d'horizon de roadmap. Ce besoin ne remet pas en cause le présent fix ; il justifie un REPLAN dans la tranche normale suivante. + +## Transition + +Appliquer le présent history puis committer et pousser `0.0.5-alpha.3.fix.1`. + +La tranche suivante devient : + +```text +0.0.5-alpha.4 +``` + +avec rôle `REPLAN`. Elle doit traiter uniquement le lifecycle inter-release, le contrat de clôture/transition des plans, la revue d'horizon et les optimisations workflow directement liées. Les anciens travaux prévus à partir de `alpha.4` sont décalés sans être abandonnés. diff --git a/scripts/audit_markdown_tables.py b/scripts/audit_markdown_tables.py index 378583a..4054225 100644 --- a/scripts/audit_markdown_tables.py +++ b/scripts/audit_markdown_tables.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # file: scripts/audit_markdown_tables.py -# version: 1 +# version: 2 """Validate source formatting of Markdown tables in explicitly selected paths.""" @@ -13,6 +13,7 @@ import sys _SEPARATOR = re.compile(r"^:?-{3,}:?$") _IGNORED_DIRECTORIES = frozenset({".git", ".idea", ".venv", "__pycache__", "dist", "node_modules", "target"}) +_MARKDOWN_FENCE_LANGUAGES = frozenset({"markdown", "md"}) def _selected_files(raw_paths: list[str]) -> tuple[list[pathlib.Path], list[str]]: @@ -130,11 +131,19 @@ def _validate_table(path: pathlib.Path, start_line: int, rows: list[str]) -> lis return errors +def _fence_language(stripped: str) -> str | None: + info = stripped[3:].strip() + if not info: + return None + return info.split(None, 1)[0].lower() + + def _audit_file(path: pathlib.Path) -> tuple[int, list[str]]: lines = path.read_text(encoding="utf-8").splitlines() errors: list[str] = [] tables = 0 fence: str | None = None + audit_fenced_markdown = False index = 0 while index < len(lines): @@ -143,12 +152,14 @@ def _audit_file(path: pathlib.Path) -> tuple[int, list[str]]: marker = stripped[:3] if fence is None: fence = marker + audit_fenced_markdown = _fence_language(stripped) in _MARKDOWN_FENCE_LANGUAGES elif fence == marker: fence = None + audit_fenced_markdown = False index += 1 continue - if fence is not None: + if fence is not None and not audit_fenced_markdown: index += 1 continue diff --git a/tests/test_markdown_tables.py b/tests/test_markdown_tables.py new file mode 100644 index 0000000..e24319c --- /dev/null +++ b/tests/test_markdown_tables.py @@ -0,0 +1,90 @@ +# file: tests/test_markdown_tables.py +# version: 1 + +"""Exercise Markdown table detection, including explicit Markdown examples.""" + +from __future__ import annotations + +import pathlib +import subprocess +import sys +import tempfile +import unittest + +_SCRIPT = pathlib.Path(__file__).resolve().parents[1] / "scripts/audit_markdown_tables.py" + + +class MarkdownTableAuditTests(unittest.TestCase): + def setUp(self) -> None: + temporary = tempfile.TemporaryDirectory(prefix="pgr-tables-") + self.addCleanup(temporary.cleanup) + self.root = pathlib.Path(temporary.name) + + def source(self, contents: str) -> pathlib.Path: + path = self.root / "sample.md" + path.write_text(contents, encoding="utf-8") + return path + + def run_audit(self) -> subprocess.CompletedProcess[str]: + return subprocess.run( + [sys.executable, "-B", str(_SCRIPT), "sample.md"], + cwd=self.root, capture_output=True, text=True, check=False, + ) + + def test_regular_and_fenced_markdown_tables_are_counted(self) -> None: + self.source( + "| A | BB |\n" + "|---|----|\n" + "| x | y |\n" + "\n" + "```markdown\n" + "| C | DD |\n" + "|---|----|\n" + "| z | q |\n" + "```\n" + ) + result = self.run_audit() + self.assertEqual(result.returncode, 0, result.stderr) + self.assertIn("clean (2 table(s), 1 file(s))", result.stdout) + + def test_misaligned_table_inside_markdown_fence_is_rejected(self) -> None: + self.source( + "```markdown\n" + "| Fichier ou famille | Responsabilité | Règle de modification |\n" + "|--------------------|----------------|------------------------|\n" + "| `` | `` | `` |\n" + "```\n" + ) + result = self.run_audit() + self.assertEqual(result.returncode, 1) + self.assertIn("sample.md:2: column 1 is not vertically aligned", result.stderr) + self.assertIn("column 2 is not vertically aligned", result.stderr) + self.assertIn("column 3 is not vertically aligned", result.stderr) + + def test_md_fence_is_audited(self) -> None: + self.source( + "```md\n" + "| A | BB |\n" + "|---|----|\n" + "| x | y |\n" + "```\n" + ) + result = self.run_audit() + self.assertEqual(result.returncode, 0, result.stderr) + self.assertIn("clean (1 table(s), 1 file(s))", result.stdout) + + def test_non_markdown_fence_remains_ignored(self) -> None: + self.source( + "```text\n" + "| Fichier ou famille | Responsabilité |\n" + "|--------------------|----------------|\n" + "| x | y |\n" + "```\n" + ) + result = self.run_audit() + self.assertEqual(result.returncode, 0, result.stderr) + self.assertIn("clean (0 table(s), 1 file(s))", result.stdout) + + +if __name__ == "__main__": + unittest.main()