0.0.2-beta.1

This commit is contained in:
2026-09-23 15:26:40 +02:00
parent ead2e879ef
commit 0719955875
8 changed files with 475 additions and 19 deletions

View File

@@ -1 +1 @@
0.0.2-alpha.5
0.0.2-beta.1

154
deltas/0.0.2/beta.1.md Normal file
View File

@@ -0,0 +1,154 @@
<!-- file: deltas/0.0.2/beta.1.md -->
<!-- version: 1 -->
# Delta 0.0.2-beta.1 — réconciliation des profils
## Baseline
Version attendue avant application :
```text
0.0.2-alpha.5
```
Le history `history/0.0.2/alpha.5.md` MUST avoir été appliqué et committé avant ce delta.
Version après application :
```text
0.0.2-beta.1
```
## Objet
Exécuter la réconciliation prévue après matérialisation des trois profils de `0.0.2` :
```text
510 — Rust / Cargo
520 — Java / Maven / Gradle
610 — Android
```
La tranche ne crée aucun nouveau profil technologique.
Elle vérifie et consolide l'ownership normatif, la composition général → langage/build → plateforme, l'absence de contradiction non résolue, la non-duplication des règles générales et la navigation documentaire.
## Résultat de la réconciliation
Aucune famille `700 — frameworks` ou `800 — architecture` n'est nécessaire pour fermer `0.0.2`.
Aucun profil composite n'est créé.
La composition actuellement démontrée reste :
```text
Rust ordinaire
→ GENERAL + 500 + 510
Java/Gradle Android
→ GENERAL + 500 + 520 + 600 + 610
```
Android peut raffiner les contraintes JDK/Gradle dans son scope lorsque la matrice AGP/Gradle/JDK l'exige. Cette spécialisation ne modifie pas le profil Java/Gradle hors Android.
Le profil Android est ajusté pour ne plus présenter l'interdiction générale des secrets comme une règle dont il serait propriétaire : `RULES.md` conserve l'ownership, tandis que `610-ANDROID.md` décrit les artefacts de signing Android qui tombent sous cette règle.
## Audit de navigation monotâche
La réconciliation doit vérifier réellement la navigation locale. PGR ajoute donc :
```text
scripts/audit_markdown_links.py
```
Cet audit est volontairement séparé de `audit_markdown_tables.py`.
Il contrôle uniquement l'existence des cibles de liens Markdown locaux inline. Il ne contrôle pas les anchors, les headers `file/version`, les responsabilités documentaires, les tableaux ou les URLs externes.
`PGR-NAV-001` devient l'owner de ce contrôle automatisé dans la matrice de validation.
`PGR-DOC-001` reste un contrôle de revue pour les headers, chemins et responsabilités documentaires, sans dupliquer la vérification des liens locaux.
## Scope
REPLACE :
```text
VERSION
docs/architecture/003-RULE_PROFILE_MODEL.md
docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
docs/rules/610-ANDROID.md
docs/validation/001-VALIDATION_MATRIX.md
```
ADD :
```text
scripts/audit_markdown_links.py
deltas/0.0.2/beta.1.md
```
DELETE : aucun.
## Validation opérateur
```bash
test "$(cat VERSION)" = "0.0.2-beta.1"
test -f scripts/audit_markdown_links.py
test -f deltas/0.0.2/beta.1.md
grep -F 'Aucune contradiction non résolue de même niveau' docs/architecture/003-RULE_PROFILE_MODEL.md
grep -F 'GENERAL + 500 + 520 + 600 + 610' docs/architecture/003-RULE_PROFILE_MODEL.md
grep -F 'Aucune famille `700` ou `800` n' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F 'L'interdiction générale de versionner ou distribuer des secrets reste possédée par `RULES.md`.' docs/rules/610-ANDROID.md
grep -F '`PGR-NAV-001`' docs/validation/001-VALIDATION_MATRIX.md
grep -F 'audit_markdown_links.py' docs/validation/001-VALIDATION_MATRIX.md
grep -F 'plusieurs audits simples avec une responsabilité identifiable' docs/validation/001-VALIDATION_MATRIX.md
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
git diff --check
git add VERSION docs/architecture/003-RULE_PROFILE_MODEL.md docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md docs/rules/610-ANDROID.md docs/validation/001-VALIDATION_MATRIX.md scripts/audit_markdown_links.py deltas/0.0.2/beta.1.md
git diff --cached --check
git status --short
```
La sortie attendue avant ajout du history est :
```text
M VERSION
A deltas/0.0.2/beta.1.md
M docs/architecture/003-RULE_PROFILE_MODEL.md
M docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
M docs/rules/610-ANDROID.md
M docs/validation/001-VALIDATION_MATRIX.md
A scripts/audit_markdown_links.py
```
## Revue opérateur complémentaire
- confirmer que beta n'introduit aucun profil technologique nouveau ;
- confirmer que `510`, `520` et `610` possèdent toujours des scopes distincts et compréhensibles ;
- confirmer qu'Android raffine Java/Gradle sans faire remonter ses contraintes vers tous les projets Java ;
- confirmer qu'aucun owner `700` ou `800` n'est créé sans contenu nécessaire ;
- confirmer que le nouvel audit reste strictement monotâche et read-only ;
- confirmer que la validation des liens locaux est désormais automatisée sans transformer `PGR-DOC-001` en wrapper multifonction.
## Transition
### PASS
Créer et appliquer séparément `history/0.0.2/beta.1.md`, committer la tranche, puis préparer `0.0.2-rc.1`.
`rc.1` devra geler le scope, préparer l'entrée candidate `0.0.2` du changelog, finaliser le prompt manuel de reprise `0.0.3` et exécuter la gate documentaire complète.
### FAIL
Rester dans `0.0.2-beta.1.fix.M` jusqu'à correction. Aucun nouveau profil majeur ne doit être absorbé dans un fix beta.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/003-RULE_PROFILE_MODEL.md -->
<!-- version: 1 -->
<!-- version: 2 -->
# Modèle de profils de règles PGR
@@ -156,6 +156,46 @@ Les familles `700 — frameworks` et `800 — architecture` restent réservées
Le modèle architectural présent n'oblige pas à créer des fichiers placeholders pour les profils différés.
## Réconciliation des profils matérialisés en `0.0.2`
La première implémentation réelle du modèle comporte trois profils :
```text
510 — Rust / Cargo
520 — Java / Maven / Gradle
610 — Android
```
Leur composition observée confirme que la taxonomie n'a pas besoin d'un profil composite supplémentaire dans `0.0.2`.
Un projet Rust ordinaire peut appliquer :
```text
GENERAL
+ 500
+ 510
```
Un projet Java/Gradle Android peut appliquer :
```text
GENERAL
+ 500
+ 520
+ 600
+ 610
```
La forme condensée de cette composition est `GENERAL + 500 + 520 + 600 + 610`.
Le profil Android raffine localement les contraintes JDK/Gradle lorsque la matrice AGP/Gradle/JDK l'exige ; cette spécialisation ne modifie pas le profil Java/Gradle hors Android.
Aucune contradiction non résolue de même niveau n'a été identifiée entre les profils `510`, `520` et `610`.
La revue beta n'a pas justifié l'activation d'une famille `700 — frameworks` ou `800 — architecture`. Les règles réellement transversales rencontrées restent déjà possédées par `RULES.md`, les familles existantes ou le présent modèle architectural.
La réconciliation a également confirmé qu'une règle générale ne doit pas être recopiée comme si le profil spécifique en devenait propriétaire. Un profil peut rappeler une conséquence spécifique au contexte, mais doit référencer l'owner général lorsque le contrat lui-même n'est pas spécialisé.
## Instanciation future
Les futures skeleton specifications sélectionneront les profils applicables et recopieront leurs règles pertinentes dans la baseline locale du projet créé.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md -->
<!-- version: 3 -->
<!-- version: 4 -->
# Plan 0.0.2 — premiers profils de règles technologiques
@@ -149,6 +149,30 @@ Réconcilier les profils créés, vérifier les scopes/overrides, éliminer les
Aucun nouveau profil technologique majeur ne doit être introduit en beta sans REPLAN.
État observé à l'entrée de beta :
```text
alpha.1 FAIL cadrage initial corrigé par fix.1
alpha.1.fix.1 PASS sizing réduit + premier audit Markdown
alpha.2 PASS modèle de profils et familles 500/600
alpha.3 PASS Rust / Cargo
alpha.4 FAIL incohérence locale entre texte et grep de gate
alpha.4.fix.1 PASS cohérence de gate rétablie
alpha.5 PASS Android
```
Cette synthèse décrit uniquement la trajectoire du plan ; les preuves détaillées restent dans les histories immuables correspondants.
La réconciliation beta confirme comme owners technologiques de `0.0.2` :
```text
510-RUST_CARGO.md
520-JAVA_MAVEN_GRADLE.md
610-ANDROID.md
```
Aucune famille `700` ou `800` n'est activée. Aucun profil différé n'est ramené dans le scope.
### rc.1 — Rule profiles release candidate
Geler le scope, préparer l'entrée candidate `0.0.2` du changelog, finaliser le prompt `0.0.3` et exécuter la gate documentaire complète applicable.
@@ -187,7 +211,7 @@ Un nouveau besoin critique, plusieurs fixes consécutifs ou une évolution qui r
- créer les skeleton specifications complètes réservées à `0.0.4` ;
- créer un générateur ;
- réécrire KSP ou `sasedev-games` ;
- multiplier les audits spécialisés ; `alpha.1.fix.1` introduit uniquement l'audit Markdown monotâche justifié par un défaut réellement observé ;
- multiplier les audits spécialisés ; `0.0.2` ne matérialise que des audits génériques monotâches justifiés par un besoin réel (`tables` puis `liens locaux`), sans audit technologique artificiel ;
- transformer les exemples de technologies en dépendances du dépôt PGR ;
- modifier rétroactivement les deltas/histories `0.0.1` pour refléter des règles apparues après leur émission.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/610-ANDROID.md -->
<!-- version: 1 -->
<!-- version: 2 -->
# Profil Android
@@ -147,9 +147,9 @@ La même politique s'applique aux fichiers locaux analogues tels que `keystore.p
## Signing et secrets
Les secrets de signature ne sont jamais versionnés.
L'interdiction générale de versionner ou distribuer des secrets reste possédée par `RULES.md`. Le profil Android ajoute uniquement les conséquences propres au signing de cette plateforme.
Sont notamment interdits dans Git, les deltas, histories, prompts et documentation :
Dans le scope Android, les éléments suivants sont notamment des secrets ou artefacts privés soumis à cette interdiction :
```text
release keystore

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/001-VALIDATION_MATRIX.md -->
<!-- version: 5 -->
<!-- version: 6 -->
# Matrice de validation PGR
@@ -14,19 +14,23 @@ Les catégories et règles de sélection sont définies dans [`../rules/400-VALI
## Contrôles actifs
| ID | Catégorie | Commande / contrôle | Prérequis | Trigger | Phase | Coût | Acteur |
|--------------------|-----------|------------------------------------------------------------------------------------------|------------------------|---------------------------------|----------------------|--------|-----------------|
|--------------------|-----------|--------------------------------------------------------------------------------------|------------------------|---------------------------------|----------------------|--------|-----------------|
| `PGR-GIT-001` | `CHECK` | `git diff --check` ou `git diff --cached --check` selon l'état de l'index | Git | toute modification suivie | alpha/beta/RC/stable | faible | opérateur |
| `PGR-VERSION-001` | `CHECK` | comparer `VERSION` à la version attendue par le delta courant | fichier `VERSION` | changement de tranche/version | alpha/beta/RC/stable | faible | opérateur |
| `PGR-LAYOUT-001` | `AUDIT` | comparer les fichiers ajoutés/remplacés/supprimés au scope déclaré du delta | scope du delta | changement de structure | alpha/beta/RC/stable | faible | opérateur/revue |
| `PGR-DOC-001` | `AUDIT` | vérifier headers `file/version`, chemins, liens et responsabilités des documents touchés | fichiers documentaires | modification documentaire | alpha/beta/RC/stable | faible | opérateur/revue |
| `PGR-DOC-001` | `AUDIT` | vérifier headers `file/version`, chemins et responsabilités des documents touchés | fichiers documentaires | modification documentaire | alpha/beta/RC/stable | faible | opérateur/revue |
| `PGR-MD-TABLE-001` | `AUDIT` | `python3 -B scripts/audit_markdown_tables.py <paths...>` | Python 3 | table Markdown ajoutée/modifiée | alpha/beta/RC/stable | faible | opérateur/CI |
| `PGR-NAV-001` | `AUDIT` | vérifier que les points d'entrée et liens canoniques ciblent des fichiers existants | index et docs racine | navigation ou réconciliation | beta/RC/stable | faible | opérateur/revue |
| `PGR-NAV-001` | `AUDIT` | `python3 -B scripts/audit_markdown_links.py <paths...>` | Python 3 | navigation ou réconciliation | beta/RC/stable | faible | opérateur/CI |
| `PGR-SCOPE-001` | `AUDIT` | vérifier que les documents vivants pointent vers les propriétaires normatifs actuels | documents vivants | réconciliation de phase | beta/RC/stable | faible | revue |
| `PGR-STATUS-001` | `CHECK` | `git status --short` | Git | avant fermeture d'une tranche | alpha/beta/RC/stable | faible | opérateur |
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` est le premier audit matérialisé dans PGR lui-même. Il reste volontairement monotâche : il contrôle uniquement la structure et l'alignement source des tableaux Markdown, sans vérifier les blank lines, les headers, les liens ou d'autres règles documentaires.
`PGR-MD-TABLE-001` reste volontairement monotâche : il contrôle uniquement la structure et l'alignement source des tableaux Markdown.
`PGR-NAV-001` est automatisé séparément par `audit_markdown_links.py`. Il vérifie uniquement l'existence des cibles de liens Markdown locaux inline, sans contrôler les anchors, les headers, les responsabilités documentaires ou la forme des tableaux.
PGR préfère plusieurs audits simples avec une responsabilité identifiable à un script unique qui agrège des règles indépendantes.
## Politique Eclipse actuelle

103
history/0.0.2/beta.1.md Normal file
View File

@@ -0,0 +1,103 @@
<!-- file: history/0.0.2/beta.1.md -->
<!-- version: 1 -->
# History 0.0.2-beta.1 — réconciliation des profils
## Statut
FAIL
La tranche `0.0.2-beta.1` n'est pas enregistrée `PASS` telle quelle.
Le contenu réconcilié et les deux audits PGR ont produit les résultats attendus, mais une commande obligatoire de la gate possède un quoting Bash invalide.
## Baseline
La tranche précédente `0.0.2-alpha.5` a été enregistrée `PASS`, puis committée et poussée sous le commit observé :
```text
ead2e87
```
Version contrôlée après application de `beta.1` :
```text
0.0.2-beta.1
```
## Contrôles réussis observés
Les contrôles initiaux ont confirmé la version, les fichiers attendus et plusieurs contrats de réconciliation :
```text
Aucune contradiction non résolue de même niveau n'a été identifiée entre les profils `510`, `520` et `610`.
La forme condensée de cette composition est `GENERAL + 500 + 520 + 600 + 610`.
Aucune famille `700` ou `800` n'est activée.
```
Après interruption de la commande défectueuse, les contrôles restants ont été exécutés et ont réussi.
La matrice contient bien `PGR-NAV-001`, la commande `audit_markdown_links.py` et la règle de séparation des audits monotâches.
Résultats observés :
```text
Markdown table audit: clean (2 table(s), 63 file(s))
Markdown link audit: clean (49 local link(s), 63 file(s))
```
`git diff --check` et `git diff --cached --check` n'ont produit aucun diagnostic.
Le scope Git observé avant le présent history est exactement :
```text
M VERSION
A deltas/0.0.2/beta.1.md
M docs/architecture/003-RULE_PROFILE_MODEL.md
M docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
M docs/rules/610-ANDROID.md
M docs/validation/001-VALIDATION_MATRIX.md
A scripts/audit_markdown_links.py
```
## Défaut exact
La gate contient :
```bash
grep -F 'L'interdiction générale de versionner ou distribuer des secrets reste possédée par `RULES.md`.' docs/rules/610-ANDROID.md
```
L'apostrophe de `L'interdiction` ferme prématurément la chaîne Bash délimitée par apostrophes simples.
Le shell passe alors en invite de continuation :
```text
>
```
et la commande a dû être interrompue avec `Ctrl-C`.
Le contenu à vérifier existe bien dans `docs/rules/610-ANDROID.md`. Le défaut appartient uniquement au quoting de la commande de validation.
## Décision
Aucun REPLAN n'est requis.
La correction reste strictement locale :
```text
0.0.2-beta.1.fix.1
```
Le delta `beta.1` livré reste immuable. Le fix remplace uniquement la commande défectueuse par une recherche littérale sans apostrophe ambiguë et rejoue les preuves nécessaires.
## Résultat
`0.0.2-beta.1` est enregistré `FAIL`.
La seule transition autorisée est :
```text
0.0.2-beta.1.fix.1
```

131
scripts/audit_markdown_links.py Executable file
View File

@@ -0,0 +1,131 @@
#!/usr/bin/env python3
# file: scripts/audit_markdown_links.py
# version: 1
"""Validate that local inline Markdown link targets exist."""
from __future__ import annotations
import argparse
import pathlib
import re
import sys
import urllib.parse
_IGNORED_DIRECTORIES = frozenset({".git", ".idea", ".venv", "__pycache__", "dist", "node_modules", "target"})
_INLINE_LINK = re.compile(r"(?<!!)\[[^\]]+\]\(([^)]+)\)")
def _selected_files(raw_paths: list[str]) -> tuple[list[pathlib.Path], list[str]]:
files: list[pathlib.Path] = []
errors: list[str] = []
for raw_path in raw_paths:
path = pathlib.Path(raw_path)
if path.is_dir():
files.extend(
candidate
for candidate in path.rglob("*.md")
if candidate.is_file() and not any(part in _IGNORED_DIRECTORIES for part in candidate.parts)
)
elif path.is_file() and path.suffix.lower() == ".md":
files.append(path)
else:
errors.append(f"Markdown link audit: unsupported or missing path: {path}")
return sorted(set(files)), errors
def _destination(raw_destination: str) -> str:
destination = raw_destination.strip()
if destination.startswith("<"):
closing = destination.find(">")
return destination[1:closing] if closing > 0 else destination
return destination.split(maxsplit=1)[0] if destination else ""
def _local_target(destination: str) -> str | None:
if not destination or destination.startswith("#") or destination.startswith("//"):
return None
parsed = urllib.parse.urlsplit(destination)
if parsed.scheme or parsed.netloc:
return None
target = urllib.parse.unquote(parsed.path)
return target or None
def _audit_file(path: pathlib.Path) -> tuple[int, list[str]]:
errors: list[str] = []
checked = 0
fence: str | None = None
for line_number, line in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1):
stripped = line.lstrip()
if stripped.startswith("```") or stripped.startswith("~~~"):
marker = stripped[:3]
if fence is None:
fence = marker
elif fence == marker:
fence = None
continue
if fence is not None:
continue
for match in _INLINE_LINK.finditer(line):
destination = _destination(match.group(1))
target = _local_target(destination)
if target is None:
continue
checked += 1
if target.startswith("/"):
candidate = pathlib.Path.cwd() / target.lstrip("/")
else:
candidate = path.parent / target
if not candidate.exists():
errors.append(f"{path}:{line_number}: missing local Markdown target: {destination}")
return checked, errors
def main() -> int:
"""Run the read-only local Markdown link audit."""
parser = argparse.ArgumentParser()
parser.add_argument("paths", nargs="+", help="Markdown files or directories to audit")
arguments = parser.parse_args()
files, selection_errors = _selected_files(arguments.paths)
if selection_errors:
for error in selection_errors:
print(error, file=sys.stderr)
return 2
if not files:
print("Markdown link audit: no Markdown files selected", file=sys.stderr)
return 2
link_count = 0
errors: list[str] = []
for path in files:
current_count, current_errors = _audit_file(path)
link_count += current_count
errors.extend(current_errors)
if errors:
for error in errors:
print(error, file=sys.stderr)
print(f"Markdown link audit: {len(errors)} error(s) across {len(files)} file(s)", file=sys.stderr)
return 1
print(f"Markdown link audit: clean ({link_count} local link(s), {len(files)} file(s))")
return 0
if __name__ == "__main__":
raise SystemExit(main())