0.0.2-beta.1
This commit is contained in:
154
deltas/0.0.2/beta.1.md
Normal file
154
deltas/0.0.2/beta.1.md
Normal 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.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/architecture/003-RULE_PROFILE_MODEL.md -->
|
<!-- file: docs/architecture/003-RULE_PROFILE_MODEL.md -->
|
||||||
<!-- version: 1 -->
|
<!-- version: 2 -->
|
||||||
|
|
||||||
# Modèle de profils de règles PGR
|
# 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.
|
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
|
## Instanciation future
|
||||||
|
|
||||||
Les futures skeleton specifications sélectionneront les profils applicables et recopieront leurs règles pertinentes dans la baseline locale du projet créé.
|
Les futures skeleton specifications sélectionneront les profils applicables et recopieront leurs règles pertinentes dans la baseline locale du projet créé.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md -->
|
<!-- 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
|
# 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.
|
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
|
### 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.
|
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 les skeleton specifications complètes réservées à `0.0.4` ;
|
||||||
- créer un générateur ;
|
- créer un générateur ;
|
||||||
- réécrire KSP ou `sasedev-games` ;
|
- 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 ;
|
- 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.
|
- modifier rétroactivement les deltas/histories `0.0.1` pour refléter des règles apparues après leur émission.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/rules/610-ANDROID.md -->
|
<!-- file: docs/rules/610-ANDROID.md -->
|
||||||
<!-- version: 1 -->
|
<!-- version: 2 -->
|
||||||
|
|
||||||
# Profil Android
|
# Profil Android
|
||||||
|
|
||||||
@@ -147,9 +147,9 @@ La même politique s'applique aux fichiers locaux analogues tels que `keystore.p
|
|||||||
|
|
||||||
## Signing et secrets
|
## 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
|
```text
|
||||||
release keystore
|
release keystore
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/validation/001-VALIDATION_MATRIX.md -->
|
<!-- file: docs/validation/001-VALIDATION_MATRIX.md -->
|
||||||
<!-- version: 5 -->
|
<!-- version: 6 -->
|
||||||
|
|
||||||
# Matrice de validation PGR
|
# Matrice de validation PGR
|
||||||
|
|
||||||
@@ -13,20 +13,24 @@ Les catégories et règles de sélection sont définies dans [`../rules/400-VALI
|
|||||||
|
|
||||||
## Contrôles actifs
|
## Contrôles actifs
|
||||||
|
|
||||||
| ID | Catégorie | Commande / contrôle | Prérequis | Trigger | Phase | Coût | Acteur |
|
| 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-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-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-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-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-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 |
|
| `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.
|
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
|
## Politique Eclipse actuelle
|
||||||
|
|
||||||
|
|||||||
103
history/0.0.2/beta.1.md
Normal file
103
history/0.0.2/beta.1.md
Normal 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
131
scripts/audit_markdown_links.py
Executable 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())
|
||||||
Reference in New Issue
Block a user