0.0.5-alpha.3.fix.1

This commit is contained in:
2026-09-24 23:40:02 +02:00
parent 1b1a7092e5
commit a954d7f90a
7 changed files with 405 additions and 12 deletions

View File

@@ -1 +1 @@
0.0.5-alpha.3
0.0.5-alpha.3.fix.1

View File

@@ -0,0 +1,164 @@
<!-- file: deltas/0.0.5/alpha.3.fix.1.md -->
<!-- version: 1 -->
# 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 '<!-- version: 2 -->' docs/templates/004-FILE_FAMILY_CONTRACTS.md
grep -Fx '<!-- version: 10 -->' 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.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/templates/004-FILE_FAMILY_CONTRACTS.md -->
<!-- version: 1 -->
<!-- version: 2 -->
# 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 |
|---------------------|------------------|----------------------------|
| `<path-or-pattern>` | `<rôle durable>` | `<quand/comment modifier>` |
```
@@ -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/`.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/001-VALIDATION_MATRIX.md -->
<!-- version: 9 -->
<!-- version: 10 -->
# 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.

View File

@@ -0,0 +1,128 @@
<!-- file: history/0.0.5/alpha.3.fix.1.md -->
<!-- version: 1 -->
# 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.

View File

@@ -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

View File

@@ -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"
"| `<path-or-pattern>` | `<rôle durable>` | `<quand/comment modifier>` |\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()