22 Commits

Author SHA1 Message Date
1e10feba95 0.0.3 2026-09-24 13:28:35 +02:00
ec3a101d9b 0.0.3-rc.1 2026-09-24 13:22:43 +02:00
47114fa96b 0.0.3-beta.1 2026-09-24 11:34:28 +02:00
dee864e22b 0.0.3-alpha.6 2026-09-24 11:26:50 +02:00
584a0d1586 0.0.3-alpha.5 2026-09-24 10:57:10 +02:00
8ad4987d38 0.0.3-alpha.4 2026-09-24 09:50:33 +02:00
b3230b4da9 0.0.3-alpha.3 2026-09-24 09:21:39 +02:00
a8dd8ae349 0.0.3-alpha.2 2026-09-24 06:51:16 +02:00
883e20e3c5 0.0.3-alpha.1.fix.1 2026-09-23 22:11:26 +02:00
3472fe7094 0.0.3-alpha.1 2026-09-23 17:54:34 +02:00
1b37d2752a 0.0.2 2026-09-23 15:57:03 +02:00
3ba513da16 0.0.2-rc.1.fix.1 2026-09-23 15:53:55 +02:00
8272cfe33d 0.0.2-rc.1 2026-09-23 15:39:55 +02:00
d0ac83569f 0.0.2-beta.1.fix.1 2026-09-23 15:35:09 +02:00
0719955875 0.0.2-beta.1 2026-09-23 15:26:40 +02:00
ead2e879ef 0.0.2-alpha.5 2026-09-23 15:20:18 +02:00
368dedbed9 0.0.2-alpha.4.fix.1 2026-09-23 15:11:14 +02:00
70ff272b79 0.0.2-alpha.4 2026-09-23 15:05:35 +02:00
34ac3a9286 0.0.2-alpha.3 2026-09-23 11:35:41 +02:00
5f9b84c980 0.0.2-alpha.2 2026-09-23 11:19:21 +02:00
1a5dd0908c 0.0.2-alpha.1.fix.1 2026-09-23 10:44:34 +02:00
d3f1e13c84 0.0.2-alpha.1 2026-09-23 10:29:23 +02:00
81 changed files with 7782 additions and 26 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: CHANGELOG.md --> <!-- file: CHANGELOG.md -->
<!-- version: 2 --> <!-- version: 5 -->
# Changelog Project Governance Rules # Changelog Project Governance Rules
@@ -7,6 +7,23 @@ Ce fichier décrit les changements utiles aux utilisateurs ou intégrateurs des
Les tranches `alpha`, `beta`, `rc`, fixes, validations, audits et détails de développement appartiennent aux plans, deltas et historiques. Ils ne sont pas recopiés ici par défaut. Les tranches `alpha`, `beta`, `rc`, fixes, validations, audits et détails de développement appartiennent aux plans, deltas et historiques. Ils ne sont pas recopiés ici par défaut.
## 0.0.3
- fournit cinq fichiers modèles Rust/Cargo : `rustfmt.toml`, `clippy.toml`, `.cargo/config.toml`, un manifest workspace et un manifest de crate membre, avec instructions d'adaptation ;
- explicite l'héritage des métadonnées et lints Cargo, ainsi que les exceptions locales motivées ;
- ajoute deux audits facultatifs et ciblés du style Rust, pour l'espacement des lignes vides et les blocs de constantes racine sans ordre sémantique, sans remplacer Rustfmt ni Clippy ;
- ajoute un audit read-only des headers `file` et `version` des fichiers Markdown gouvernés par PGR ;
- fournit une spécification courte pour rédiger le message manuel de reprise après publication d'une stable.
## 0.0.2
- introduit le modèle de profils PGR avec ownership normatif, applicabilité, composition du général vers le spécifique et overrides bornés ;
- matérialise les familles `500 — languages / ecosystems` et `600 — platforms` sans créer prématurément les familles frameworks ou architecture ;
- ajoute les premiers profils réutilisables `510 — Rust / Cargo`, `520 — Java / Maven / Gradle` et `610 — Android` ;
- formalise notamment les politiques de toolchain/target, dépendances et build, visibilité/API, safety/FFI, structure canonique, compatibilité Android, packaging et niveaux de preuve ;
- ajoute deux audits PGR read-only et monotâches : alignement des tableaux Markdown et existence des cibles de liens Markdown locaux ;
- confirme que Rust/JNI, Web/Vite/WASM, Tauri, C/C++/CMake, PHP/Composer et Python restent différés jusqu'à une release où leur contenu justifie un owner réel.
## 0.0.1 ## 0.0.1
- établit la fondation normative de PGR : force `MUST` / `SHOULD` / `MAY`, hiérarchie des scopes et principe de proportionnalité ; - établit la fondation normative de PGR : force `MUST` / `SHOULD` / `MAY`, hiérarchie des scopes et principe de proportionnalité ;

View File

@@ -1,5 +1,5 @@
<!-- file: README.md --> <!-- file: README.md -->
<!-- version: 3 --> <!-- version: 6 -->
# Project Governance Rules # Project Governance Rules
@@ -13,7 +13,7 @@ Le dépôt officiel est `https://git.sasedev.com/Sasedev/pgr`.
PGR est actuellement en phase de fondation `0.0.x`. PGR est actuellement en phase de fondation `0.0.x`.
La version courante est définie par [`VERSION`](VERSION). La release `0.0.1` établit la gouvernance normative et documentaire de PGR lui-même ; les releases suivantes de la série `0.0.x` introduisent progressivement profils technologiques, templates techniques et spécifications de skeletons. La version courante est définie par [`VERSION`](VERSION). La release `0.0.1` établit la gouvernance normative et documentaire de PGR lui-même. La release `0.0.2` ajoute les premiers profils réutilisables Rust/Cargo, Java/Maven/Gradle et Android, ainsi que deux audits Markdown. La release `0.0.3` fournit les premiers modèles Rust/Cargo, deux audits de style Rust facultatifs, l'audit des headers Markdown et la spécification du message manuel de reprise. La série `0.0.x` se poursuit avec les spécifications de skeletons prévues pour `0.0.4`.
## Entrées principales ## Entrées principales
@@ -25,6 +25,8 @@ La version courante est définie par [`VERSION`](VERSION). La release `0.0.1` é
- [`docs/architecture/001-PROJECT_PROFILE.md`](docs/architecture/001-PROJECT_PROFILE.md) — profil applicable au dépôt PGR ; - [`docs/architecture/001-PROJECT_PROFILE.md`](docs/architecture/001-PROJECT_PROFILE.md) — profil applicable au dépôt PGR ;
- [`docs/architecture/002-GOVERNANCE_ARCHITECTURE.md`](docs/architecture/002-GOVERNANCE_ARCHITECTURE.md) — architecture du référentiel ; - [`docs/architecture/002-GOVERNANCE_ARCHITECTURE.md`](docs/architecture/002-GOVERNANCE_ARCHITECTURE.md) — architecture du référentiel ;
- [`docs/plans/001-V0_0_1_FOUNDATION_PLAN.md`](docs/plans/001-V0_0_1_FOUNDATION_PLAN.md) — plan historique de fondation `0.0.1` ; - [`docs/plans/001-V0_0_1_FOUNDATION_PLAN.md`](docs/plans/001-V0_0_1_FOUNDATION_PLAN.md) — plan historique de fondation `0.0.1` ;
- [`docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md`](docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md) — plan historique des premiers profils `0.0.2` ;
- [`docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md`](docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md) — plan historique des templates et audits `0.0.3` ;
- [`docs/validation/001-VALIDATION_MATRIX.md`](docs/validation/001-VALIDATION_MATRIX.md) — matrice de validation. - [`docs/validation/001-VALIDATION_MATRIX.md`](docs/validation/001-VALIDATION_MATRIX.md) — matrice de validation.
## Langue et nomenclature ## Langue et nomenclature

View File

@@ -1,5 +1,5 @@
<!-- file: ROADMAP.md --> <!-- file: ROADMAP.md -->
<!-- version: 2 --> <!-- version: 4 -->
# Roadmap Project Governance Rules # Roadmap Project Governance Rules
@@ -10,8 +10,8 @@ Statuts : `( )` planifié, `(x)` terminé, `(d)` différé, `(c)` annulé.
## Fondation `0.0.x` ## Fondation `0.0.x`
- `(x) 0.0.1` — fondation normative et documentaire : gouvernance, lifecycle des releases, rôles documentaires, workflow delta/history/handoff et validation proportionnée ; - `(x) 0.0.1` — fondation normative et documentaire : gouvernance, lifecycle des releases, rôles documentaires, workflow delta/history/handoff et validation proportionnée ;
- `( ) 0.0.2` — profils de règles par langage, plateforme, framework et type de projet ; - `(x) 0.0.2` — premiers profils de règles réutilisables : Rust/Cargo, Java/Maven/Gradle et Android, avec modèle de composition et audits Markdown initiaux ;
- `( ) 0.0.3` — templates techniques initiaux et premiers patterns d'audit réutilisables issus de besoins réels ; - `(x) 0.0.3` — templates techniques initiaux et premiers patterns d'audit réutilisables issus de besoins réels ;
- `( ) 0.0.4` — spécifications Markdown de skeletons et règles de composition des profils/templates ; - `( ) 0.0.4` — spécifications Markdown de skeletons et règles de composition des profils/templates ;
- `( ) 0.0.5` — réconciliation réelle de PGR avec `khadhroony-solana-project` et `sasedev-games`. - `( ) 0.0.5` — réconciliation réelle de PGR avec `khadhroony-solana-project` et `sasedev-games`.

View File

@@ -1,5 +1,5 @@
<!-- file: RULES.md --> <!-- file: RULES.md -->
<!-- version: 5 --> <!-- version: 9 -->
# Index normatif Project Governance Rules # Index normatif Project Governance Rules
@@ -72,12 +72,19 @@ Les traductions complètes éventuelles vivent dans des dépôts distincts (`pgr
Les règles détaillées sont structurées progressivement sous [`docs/rules/`](docs/rules/). Les règles détaillées sont structurées progressivement sous [`docs/rules/`](docs/rules/).
Famille actuellement active : Familles actuellement actives :
- [`docs/rules/200-GOVERNANCE.md`](docs/rules/200-GOVERNANCE.md) — versioning, lifecycle des releases, fixes, cadrage, replan et abandon/supersession. - [`docs/rules/200-GOVERNANCE.md`](docs/rules/200-GOVERNANCE.md) — versioning, lifecycle des releases, fixes, cadrage, replan et abandon/supersession.
- [`docs/rules/210-WORKFLOW.md`](docs/rules/210-WORKFLOW.md) — plans, deltas, histories, prompts, handoffs, manifests, commits, baselines et reprise de session. - [`docs/rules/210-WORKFLOW.md`](docs/rules/210-WORKFLOW.md) — plans, deltas, histories, prompts, handoffs, manifests, commits, baselines et reprise de session.
- [`docs/rules/300-DOCUMENTATION.md`](docs/rules/300-DOCUMENTATION.md) — rôles documentaires, taxonomie, révisions internes, documents vivants et conservation historique. - [`docs/rules/300-DOCUMENTATION.md`](docs/rules/300-DOCUMENTATION.md) — rôles documentaires, taxonomie, révisions internes, documents vivants et conservation historique.
- [`docs/rules/400-VALIDATION.md`](docs/rules/400-VALIDATION.md) — sélection proportionnelle des preuves, catégories de validation, tests utiles, doubles de test et autorité opérateur. - [`docs/rules/400-VALIDATION.md`](docs/rules/400-VALIDATION.md) — sélection proportionnelle des preuves, catégories de validation, tests utiles, doubles de test et autorité opérateur.
- [`docs/rules/500-LANGUAGES.md`](docs/rules/500-LANGUAGES.md) — contrat commun des profils langage, écosystème et spécialisations de build associées.
- [`docs/rules/510-RUST_CARGO.md`](docs/rules/510-RUST_CARGO.md) — profil Rust/Cargo : workspace, manifests, dépendances, lints, API, formatage, tests et validation spécialisée.
- [`docs/rules/520-JAVA_MAVEN_GRADLE.md`](docs/rules/520-JAVA_MAVEN_GRADLE.md) — profil Java et spécialisations Maven/Gradle : toolchain LTS, structure, dépendances, tests et validation de build.
- [`docs/rules/600-PLATFORMS.md`](docs/rules/600-PLATFORMS.md) — contrat commun des profils plateforme et de leur compatibilité de target/runtime.
- [`docs/rules/610-ANDROID.md`](docs/rules/610-ANDROID.md) — profil Android : structure, toolchain/SDK, compatibilité, packaging, configuration locale et validation plateforme.
Le modèle de composition et d'ownership des profils est défini dans [`docs/architecture/003-RULE_PROFILE_MODEL.md`](docs/architecture/003-RULE_PROFILE_MODEL.md).
Une famille de règles n'est créée que lorsqu'elle possède un contenu réel ; aucun répertoire vide n'est requis pour anticiper une future technologie. Une famille de règles n'est créée que lorsqu'elle possède un contenu réel ; aucun répertoire vide n'est requis pour anticiper une future technologie.

View File

@@ -1 +1 @@
0.0.1 0.0.3

View File

@@ -0,0 +1,180 @@
<!-- file: deltas/0.0.2/alpha.1.fix.1.md -->
<!-- version: 1 -->
# Delta 0.0.2-alpha.1.fix.1 — correction du cadrage, sizing et audit Markdown
## Baseline
Version attendue avant application :
```text
0.0.2-alpha.1
```
La baseline doit correspondre au commit de `alpha.1` après application de `history/0.0.2/alpha.1.md` en statut `FAIL`.
Version après application :
```text
0.0.2-alpha.1.fix.1
```
## Objet
Corriger exclusivement les défauts identifiés dans le cadrage `alpha.1` avant de commencer `alpha.2` :
- corriger l'alignement source du tableau `Inventaire des profils candidats` ;
- reconnaître la preuve post-tag `publish.001` déjà disponible sans modifier rétroactivement `v0.0.1` ;
- réduire le forecast `0.0.2` à un ensemble de profils compatible avec le sizing d'une session ;
- introduire le premier audit PGR monotâche réellement justifié par un défaut observé ;
- enregistrer cet audit dans la matrice de validation.
Aucune règle technologique détaillée n'est introduite par ce fix.
## Rapport post-tag reconnu
Le rapport externe à la baseline source :
```text
pgr-0.0.1-publish.001-report.md
```
est connu comme preuve post-publication `PASS` de l'archive `pgr-v0.0.1.zip`.
Il ne fait pas partie du tag stable et ne doit pas être copié dans le dépôt rétroactivement.
Le besoin futur d'indiquer automatiquement, dans le handoff/prompt manuel de reprise, si un rapport `publish.*` doit être fourni est conservé comme amélioration de workflow hors scope de `0.0.2`.
## Sizing corrigé
Le forecast actif devient :
```text
alpha.2 Rule profile model
alpha.3 Rust / Cargo
alpha.4 Java / Maven / Gradle
alpha.5 Android
beta.1 Profile reconciliation
rc.1 Rule profiles release candidate
stable 0.0.2
```
Les profils/compositions suivants restent explicitement différés :
```text
Rust + Android / JNI
Web / TypeScript / Vite / WASM / Rust server
Tauri desktop/mobile
C / C++ / CMake
PHP / Composer
Python 3 application/package
```
Leur différé ne vaut ni rejet ni oubli.
## Premier audit PGR matérialisé
Le fichier suivant est ajouté :
```text
scripts/audit_markdown_tables.py
```
Son contrat est volontairement limité :
```text
INPUT
fichiers/répertoires Markdown explicitement fournis
OUTPUT
diagnostics texte
exit code
SIDE EFFECTS
aucun
```
Il vérifie uniquement :
- la reconnaissance des tableaux hors fenced code blocks ;
- le nombre cohérent de colonnes ;
- l'alignement vertical des cellules dans le source ;
- la largeur des séparateurs ;
- le padding conforme à l'alignement Markdown.
Il ne vérifie pas les blank lines, headers `file/version`, liens, orthographe ou responsabilités documentaires. Ces propriétés appartiennent à d'autres contrôles présents ou futurs.
Il utilise uniquement la bibliothèque standard Python et doit être exécuté avec `python3 -B` afin de ne pas créer `__pycache__` ou `.pyc`.
## Scope
REPLACE :
```text
VERSION
docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
docs/validation/001-VALIDATION_MATRIX.md
```
ADD :
```text
scripts/audit_markdown_tables.py
deltas/0.0.2/alpha.1.fix.1.md
```
DELETE : aucun.
Aucun manifest de suppression n'est nécessaire.
## Validation opérateur
```bash
test "$(cat VERSION)" = "0.0.2-alpha.1.fix.1"
test -f scripts/audit_markdown_tables.py
test -f deltas/0.0.2/alpha.1.fix.1.md
grep -F '### Preuve post-tag `publish.001`' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F '### alpha.5 — Android' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F 'Rust + Android / JNI' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F '`PGR-MD-TABLE-001`' 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
git diff --check
git add VERSION docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md docs/validation/001-VALIDATION_MATRIX.md scripts/audit_markdown_tables.py deltas/0.0.2/alpha.1.fix.1.md
git diff --cached --check
git status --short
```
La sortie attendue avant ajout du history du fix est :
```text
M VERSION
A deltas/0.0.2/alpha.1.fix.1.md
M docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
M docs/validation/001-VALIDATION_MATRIX.md
A scripts/audit_markdown_tables.py
```
Revue opérateur complémentaire :
- confirmer que le tableau `Inventaire des profils candidats` est lisible et aligné dans le source ;
- confirmer que le report `publish.001` est traité comme preuve post-tag externe et non comme fichier manquant du tag ;
- confirmer que le scope réduit reste suffisamment représentatif sans chercher à matérialiser les profils différés ;
- confirmer que l'audit Python est read-only et monotâche ;
- confirmer qu'aucune règle technologique de `alpha.2+` n'a été introduite.
## Transition
### PASS
Créer et appliquer séparément `history/0.0.2/alpha.1.fix.1.md`, committer le fix, puis seulement préparer `0.0.2-alpha.2` consacré au modèle de profils.
### FAIL
Rester dans `0.0.2-alpha.1.fix.M`. À partir de `.fix.3`, réexaminer obligatoirement le plan et la nécessité d'un REPLAN conformément aux règles PGR.

171
deltas/0.0.2/alpha.1.md Normal file
View File

@@ -0,0 +1,171 @@
<!-- file: deltas/0.0.2/alpha.1.md -->
<!-- version: 1 -->
# Delta 0.0.2-alpha.1 — audit de baseline et cadrage des profils
## Baseline
Archive source fournie par l'opérateur comme téléchargement du tag stable Gitea :
```text
v0.0.1
```
Cette archive constitue la baseline autoritaire de la tranche. L'absence de `.git` y est normale ; aucun état provenant d'un workspace local ou d'une conversation antérieure n'est utilisé comme état courant s'il n'est pas confirmé par l'archive ou par `prompts/002-V0_0_2_START_PROMPT.md`.
Version attendue avant application :
```text
0.0.1
```
Version après application :
```text
0.0.2-alpha.1
```
## Objet
Exécuter le gate de framing imposé par le prompt `0.0.2` avant toute consolidation technologique :
- vérifier la baseline stable `v0.0.1` ;
- auditer les règles, la gouvernance, la structure documentaire, les deltas/histories et la cohérence générale ;
- confronter le prompt `0.0.2` à l'état réel du dépôt ;
- inventorier les profils technologiques candidats ;
- limiter le scope aux profils utiles à cette première release ;
- dimensionner les tranches suivantes ;
- créer le plan actif `0.0.2`.
Aucune règle technologique détaillée n'est introduite dans `alpha.1`.
## Résultat de l'audit de baseline
La prévalidation de l'archive a constaté :
- archive ZIP lisible, racine unique `pgr/`, sans doublon, traversal ou symlink ;
- `44` fichiers et `13` répertoires ;
- `VERSION` égal à `0.0.1` ;
- absence normale de `.git` ;
- aucun cache/build connu ou secret local distribué ;
- headers `file/version` cohérents sur tous les Markdown ;
- aucun lien Markdown local cassé parmi les liens vérifiés ;
- `12` deltas et `12` histories `0.0.1` appariés exactement ;
- chaîne PASS/FAIL/fix cohérente jusqu'à `rel.001` PASS ;
- plan `0.0.1` clôturé, roadmap/changelog cohérents et prompt `0.0.2` présent ;
- compteurs internes des documents vivants cohérents avec les opérations de deltas observées.
Aucun défaut bloquant n'impose de `0.0.1` correctif avant le démarrage de `0.0.2`.
Une observation non bloquante est conservée dans le plan : le history stable mentionne un contrôle post-tag `publish.001`, mais aucune preuve versionnée correspondante ne peut être déduite de cette archive. `alpha.1` n'invente ni ne reconstruit cette preuve.
## Cadrage retenu
`0.0.2` matérialisera d'abord :
```text
profile model / composition
Rust / Cargo
Java / Maven / Gradle
Android
Rust + Android / JNI
Web / TypeScript / Vite / WASM / Rust server composition
Tauri desktop/mobile
```
Les profils suivants sont examinés mais différés de cette release afin d'éviter une taxonomie exhaustive sans nécessité immédiate :
```text
C / C++ / CMake
PHP / Composer
Python 3 application/package
```
Ils restent des candidats futurs et ne sont pas rejetés.
Les règles cross-cutting ne recevront un propriétaire `800 — architecture` que lorsqu'une règle réellement commune à plusieurs profils n'est pas déjà possédée par un owner général existant.
## Scope
REPLACE :
```text
VERSION
```
ADD :
```text
docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
deltas/0.0.2/alpha.1.md
```
DELETE : aucun.
Aucun manifest de suppression n'est nécessaire.
## Documents volontairement inchangés
Les documents suivants ne sont pas modifiés uniquement pour refléter le passage à `0.0.2-alpha.1` :
```text
README.md
RULES.md
ROADMAP.md
CHANGELOG.md
docs/000-README.md
docs/rules/000-README.md
```
Leur contenu courant reste cohérent : la roadmap annonce déjà `0.0.2`, les règles possèdent déjà le framing `alpha.1` et la hiérarchie général → spécifique, et le changelog ne journalise pas les prereleases internes.
## Validation opérateur
```bash
test "$(cat VERSION)" = "0.0.2-alpha.1"
test -f docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
test -f deltas/0.0.2/alpha.1.md
grep -F 'Plan actif créé pendant `0.0.2-alpha.1`' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F 'Aucun défaut bloquant de gouvernance' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F '### alpha.2 — Rule profile model' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F '### alpha.8 — Tauri desktop/mobile' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F -- '- `( ) 0.0.2`' ROADMAP.md
grep -F 'v0.0.1' prompts/002-V0_0_2_START_PROMPT.md
git diff --check
git add VERSION docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md deltas/0.0.2/alpha.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/alpha.1.md
A docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
```
Revue opérateur complémentaire :
- confirmer que l'archive `v0.0.1` utilisée est bien celle téléchargée depuis le tag Gitea déclaré ;
- confirmer que l'absence de `.git` n'est pas traitée comme une anomalie ;
- vérifier que le plan n'introduit aucune règle technologique comme déjà normative ;
- vérifier que les profils différés ne sont ni oubliés ni artificiellement matérialisés ;
- vérifier que `README.md`, `RULES.md`, `ROADMAP.md`, `CHANGELOG.md` et les historiques `0.0.1` ne sont pas modifiés par cette tranche.
## Transition
### PASS
Créer et appliquer séparément `history/0.0.2/alpha.1.md`, committer `alpha.1`, puis seulement préparer `0.0.2-alpha.2` consacré au modèle documentaire et à la composition des profils.
### FAIL
Rester dans le scope de cadrage avec `0.0.2-alpha.1.fix.1`. Le fix corrige uniquement les défauts du framing/audit/plan ; aucune règle technologique de `alpha.2+` ne doit y être absorbée.

180
deltas/0.0.2/alpha.2.md Normal file
View File

@@ -0,0 +1,180 @@
<!-- file: deltas/0.0.2/alpha.2.md -->
<!-- version: 1 -->
# Delta 0.0.2-alpha.2 — rule profile model
## Baseline
Version attendue avant application :
```text
0.0.2-alpha.1.fix.1
```
Le history `history/0.0.2/alpha.1.fix.1.md` MUST avoir été appliqué et committé avant ce delta.
Version après application :
```text
0.0.2-alpha.2
```
## Objet
Formaliser le modèle de profils PGR avant toute consolidation technologique détaillée.
Cette tranche définit :
- la notion de profil et son propriétaire normatif ;
- l'applicabilité d'un profil à partir de faits réels du projet ;
- la composition du général vers le spécifique ;
- la résolution des overrides et des conflits ;
- la non-duplication des règles héritées ;
- le traitement des spécialisations internes et profils composites ;
- la distinction entre règle décidée et choix encore ouvert ;
- les contrats communs des familles `500 — languages / ecosystems` et `600 — platforms` nécessaires au scope réduit de `0.0.2`.
Aucune règle Rust, Cargo, Java, Maven, Gradle ou Android détaillée n'est encore introduite.
## Modèle retenu
La composition de référence reste :
```text
GENERAL
↓
ecosystem / language
↓
platform
↓
framework
↓
project type / subsystem
↓
project-specific
↓
explicit exception
```
Chaque règle durable possède un seul owner normatif. Les profils spécifiques héritent des règles générales et ne les recopient pas.
Une contradiction volontaire doit être un override explicite, borné et justifié. Deux règles applicables de même niveau qui se contredisent sans relation explicite constituent un défaut à résoudre ; l'ordre des fichiers ne crée aucune priorité.
Les profils composites ne sont créés que si l'intersection de plusieurs profils possède un contrat propre réel. La simple coexistence de deux technologies ne suffit pas.
## Familles activées
`alpha.2` active uniquement les familles nécessaires aux prochaines tranches :
```text
500 — languages / ecosystems
600 — platforms
```
Les familles suivantes restent réservées et non matérialisées :
```text
700 — frameworks
800 — architecture
```
Les règles project-specific continuent d'appartenir au dépôt qui les possède ; PGR ne crée pas de placeholder `900` sans contenu réel.
## Scope
REPLACE :
```text
VERSION
RULES.md
docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
docs/rules/000-README.md
```
ADD :
```text
docs/architecture/003-RULE_PROFILE_MODEL.md
docs/rules/500-LANGUAGES.md
docs/rules/600-PLATFORMS.md
deltas/0.0.2/alpha.2.md
```
DELETE : aucun.
Aucun manifest de suppression n'est nécessaire.
## Validation opérateur
```bash
test "$(cat VERSION)" = "0.0.2-alpha.2"
test -f docs/architecture/003-RULE_PROFILE_MODEL.md
test -f docs/rules/500-LANGUAGES.md
test -f docs/rules/600-PLATFORMS.md
test -f deltas/0.0.2/alpha.2.md
grep -F 'Toute règle durable doit posséder un seul propriétaire normatif canonique.' docs/architecture/003-RULE_PROFILE_MODEL.md
grep -F "L'ordre des fichiers dans un répertoire ne crée jamais une priorité normative." docs/architecture/003-RULE_PROFILE_MODEL.md
grep -F 'PGR ne crée pas automatiquement un profil composite pour chaque combinaison possible.' docs/architecture/003-RULE_PROFILE_MODEL.md
grep -F 'Les profils spécifiques utilisent la plage `510` à `599`.' docs/rules/500-LANGUAGES.md
grep -F 'Une spécialisation de build tool ne devient pas une règle du langage entier.' docs/rules/500-LANGUAGES.md
grep -F 'La modernité de la toolchain de build et la version minimale du runtime ou de la target sont deux décisions distinctes.' docs/rules/600-PLATFORMS.md
grep -F 'Les profils spécifiques utilisent la plage `610` à `699`.' docs/rules/600-PLATFORMS.md
grep -F '500-LANGUAGES.md' RULES.md
grep -F '600-PLATFORMS.md' RULES.md
grep -F '003-RULE_PROFILE_MODEL.md' docs/rules/000-README.md
grep -F 'famille `500 — languages / ecosystems`' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
python3 -B scripts/audit_markdown_tables.py \
README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts
git diff --check
git add VERSION RULES.md \
docs/architecture/003-RULE_PROFILE_MODEL.md \
docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md \
docs/rules/000-README.md \
docs/rules/500-LANGUAGES.md \
docs/rules/600-PLATFORMS.md \
deltas/0.0.2/alpha.2.md
git diff --cached --check
git status --short
```
La sortie attendue avant ajout du history est :
```text
M RULES.md
M VERSION
A deltas/0.0.2/alpha.2.md
A docs/architecture/003-RULE_PROFILE_MODEL.md
M docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
M docs/rules/000-README.md
A docs/rules/500-LANGUAGES.md
A docs/rules/600-PLATFORMS.md
```
Revue opérateur complémentaire :
- confirmer que le modèle permet de déterminer où une règle doit être possédée sans utiliser l'ordre des fichiers comme priorité ;
- confirmer que les spécialisations Maven/Gradle pourront rester locales à Java/build et qu'une contrainte Android ne contaminera pas Java en général ;
- confirmer que les familles `700` et `800` ne sont pas créées prématurément ;
- confirmer qu'aucune règle technologique détaillée prévue pour `alpha.3+` n'a été absorbée dans cette tranche.
## Transition
### PASS
Créer et appliquer séparément `history/0.0.2/alpha.2.md`, committer la tranche, puis préparer `0.0.2-alpha.3` consacré au premier profil réel `Rust / Cargo`.
`alpha.3` reste le point de mesure prévu par le plan : si le coût réel d'un profil complet invalide le sizing, effectuer un REPLAN avant `alpha.4`.
### FAIL
Rester dans `0.0.2-alpha.2.fix.M` tant que le modèle de profil lui-même n'est pas cohérent. Ne pas commencer le profil Rust/Cargo sur un modèle non validé.

166
deltas/0.0.2/alpha.3.md Normal file
View File

@@ -0,0 +1,166 @@
<!-- file: deltas/0.0.2/alpha.3.md -->
<!-- version: 1 -->
# Delta 0.0.2-alpha.3 — premier profil Rust / Cargo
## Baseline
Version attendue avant application :
```text
0.0.2-alpha.2
```
Le history `history/0.0.2/alpha.2.md` MUST avoir été appliqué et committé avant ce delta.
Version après application :
```text
0.0.2-alpha.3
```
## Objet
Matérialiser le premier profil technologique réel de PGR : `Rust / Cargo`.
Cette tranche sert aussi de point de mesure prévu par le plan `0.0.2`. Elle doit consolider uniquement les règles Rust/Cargo suffisamment générales pour être réutilisables, sans recopier les particularités métier ou les micro-conventions propres à KSP ou `sasedev-games`.
## Réconciliation des corpus sources
Les deux corpus historiques de référence convergent notamment sur :
- l'utilisation d'un workspace Cargo structuré ;
- la centralisation des métadonnées/lints et des dépendances réellement partagées ;
- l'activation locale des features selon le besoin de la crate ;
- une politique Rust stricte autour de `unsafe`, `unwrap`, `expect`, retours explicites et Clippy ;
- une façade de crate explicite plutôt qu'une exposition accidentelle des modules internes ;
- `rustfmt.toml` comme propriétaire du formatage ;
- la séparation des tests unitaires et d'intégration ;
- une gate `fmt` / audit applicable / `check` / `clippy`, avec tests ciblés par défaut et tests workspace aux gates larges ;
- l'absence d'exécution opportuniste de `cargo update`, `cargo tree`, `cargo build` ou `cargo clean` sans besoin correspondant.
La consolidation ne promeut pas automatiquement les divergences ou conventions trop spécifiques :
- l'interdiction KSP de tous les imports `use` non-traits n'est pas élevée au profil Rust général ;
- les micro-règles KSP de lignes vides/ordre interne ne remplacent pas `rustfmt` au niveau PGR ;
- aucune dépendance, crate, version de bibliothèque ou règle Solana/games n'est reprise ;
- la politique historique commune d'ignorer `Cargo.lock` n'est pas rendue universelle : le profil exige une politique explicite selon le type de produit ;
- l'exception `unsafe` Android/JNI de games reste un exemple de spécialisation FFI locale et non une permission Rust générale ;
- le chemin externe des artefacts Cargo n'est pas figé avant les futures règles de skeleton/layout.
## Profil créé
Le nouveau propriétaire normatif est :
```text
docs/rules/510-RUST_CARGO.md
```
Il couvre :
- toolchain et édition ;
- workspace et unités de release ;
- manifests, dépendances et features ;
- politique explicite de `Cargo.lock` ;
- lints communs et safety ;
- API, visibilité et rustdoc ;
- contrôle de flux/erreurs du profil strict ;
- `rustfmt.toml` ;
- `.cargo/config.toml` et artefacts générés ;
- organisation des tests ;
- commandes de validation Rust/Cargo ;
- stratégie future d'audits Rust monotâches.
Aucun script Rust supplémentaire n'est créé dans cette tranche. PGR ne possède actuellement aucun workspace Rust réel à auditer ; introduire maintenant une copie simplifiée des auditeurs games/KSP créerait une gate sans sujet réel. Le premier audit PGR déjà matérialisé reste l'audit Markdown monotâche introduit lorsque son besoin a été observé.
## Scope
REPLACE :
```text
VERSION
RULES.md
docs/rules/000-README.md
```
ADD :
```text
docs/rules/510-RUST_CARGO.md
deltas/0.0.2/alpha.3.md
```
DELETE : aucun.
Aucun manifest de suppression n'est nécessaire.
## Validation opérateur
```bash
test "$(cat VERSION)" = "0.0.2-alpha.3"
test -f docs/rules/510-RUST_CARGO.md
test -f deltas/0.0.2/alpha.3.md
grep -F 'PGR MUST NOT imposer un pin exact de toolchain uniquement parce qu' docs/rules/510-RUST_CARGO.md
grep -F 'le fichier PGR `VERSION` reste la version canonique de l' docs/rules/510-RUST_CARGO.md
grep -F 'Une crate membre SHOULD consommer cette dépendance avec `workspace = true`' docs/rules/510-RUST_CARGO.md
grep -F 'PGR ne généralise pas automatiquement la politique de lockfile' docs/rules/510-RUST_CARGO.md
grep -F 'unsafe_code = "forbid"' docs/rules/510-RUST_CARGO.md
grep -F 'PGR ne généralise pas l'"'"'interdiction KSP plus stricte de tous les `use` non-traits' docs/rules/510-RUST_CARGO.md
grep -F 'cargo clippy --workspace --all-targets --all-features -- -D warnings' docs/rules/510-RUST_CARGO.md
grep -F 'PGR SHOULD préférer plusieurs audits monotâches et lisibles' docs/rules/510-RUST_CARGO.md
grep -F '510-RUST_CARGO.md' RULES.md
grep -F '510-RUST_CARGO.md' docs/rules/000-README.md
python3 -B scripts/audit_markdown_tables.py \
README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts
git diff --check
git add VERSION RULES.md \
docs/rules/000-README.md \
docs/rules/510-RUST_CARGO.md \
deltas/0.0.2/alpha.3.md
git diff --cached --check
git status --short
```
La sortie attendue avant ajout du history est :
```text
M RULES.md
M VERSION
A deltas/0.0.2/alpha.3.md
M docs/rules/000-README.md
A docs/rules/510-RUST_CARGO.md
```
Revue opérateur complémentaire :
- confirmer que le profil distingue bien les règles Rust/Cargo générales des conventions strictement KSP ou games ;
- confirmer que la politique de lockfile reste explicitement project-type-specific et n'est pas généralisée uniquement parce que les deux corpus historiques ignoraient `Cargo.lock` ;
- confirmer que les contraintes FFI/plateforme restent des overrides locaux ;
- confirmer qu'aucune version de crate ou de toolchain historique n'a été recopiée comme pin universel ;
- confirmer qu'aucun audit Rust complexe n'a été ajouté avant d'avoir un sujet réel et une propriété mono-responsabilité à contrôler.
## Point de mesure / REPLAN
`alpha.3` est le point de mesure explicite prévu par le plan.
Le profil Rust/Cargo tient dans une tranche documentaire autonome sans nécessiter de famille supplémentaire, de script d'audit complexe ou de sous-profil framework/plateforme. Le forecast `alpha.4 — Java / Maven / Gradle` reste donc raisonnable à ce stade.
Si la validation de cette tranche révèle au contraire une dérive importante du modèle ou plusieurs corrections substantielles, effectuer un REPLAN avant `alpha.4` plutôt que poursuivre mécaniquement.
## Transition
### PASS
Créer et appliquer séparément `history/0.0.2/alpha.3.md`, committer la tranche, puis préparer `0.0.2-alpha.4` consacré à `Java / Maven / Gradle`.
### FAIL
Rester dans `0.0.2-alpha.3.fix.M` tant que le premier profil réel ne respecte pas le modèle `alpha.2`. Un défaut de dimensionnement significatif peut déclencher un REPLAN avant toute tranche Java.

View File

@@ -0,0 +1,106 @@
<!-- file: deltas/0.0.2/alpha.4.fix.1.md -->
<!-- version: 1 -->
# Delta 0.0.2-alpha.4.fix.1 — cohérence de la gate Java
## Baseline
Version attendue avant application :
```text
0.0.2-alpha.4
```
Le history `history/0.0.2/alpha.4.md` MUST avoir été appliqué avant ce correctif.
Version après application :
```text
0.0.2-alpha.4.fix.1
```
## Objet
Corriger uniquement le défaut de cohérence détecté pendant la gate opérateur de `alpha.4`.
Le profil décrivait déjà la structure Java canonique sous forme d'arbre, mais la validation cherchait littéralement :
```text
src/main/
```
sans que cette chaîne existe telle quelle dans le document.
Le correctif ajoute une phrase explicite listant les chemins canoniques déjà impliqués par l'arborescence :
```text
src/main/java/
src/main/resources/
src/test/java/
src/test/resources/
```
Aucune règle Java, Maven ou Gradle nouvelle n'est introduite.
## Scope
REPLACE :
```text
VERSION
docs/rules/520-JAVA_MAVEN_GRADLE.md
```
ADD :
```text
deltas/0.0.2/alpha.4.fix.1.md
```
DELETE : aucun.
## Validation opérateur
```bash
test "$(cat VERSION)" = "0.0.2-alpha.4.fix.1"
test -f docs/rules/520-JAVA_MAVEN_GRADLE.md
test -f deltas/0.0.2/alpha.4.fix.1.md
grep -F 'src/main/java/' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'src/main/resources/' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'src/test/java/' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'src/test/resources/' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'le JDK de développement SHOULD être une version LTS' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'PGR MUST NOT ajouter un Maven Wrapper uniquement par cérémonie.' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'Un Gradle Wrapper SHOULD être versionné lorsqu' docs/rules/520-JAVA_MAVEN_GRADLE.md
python3 -B scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts
git diff --check
git add VERSION docs/rules/520-JAVA_MAVEN_GRADLE.md deltas/0.0.2/alpha.4.fix.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/alpha.4.fix.1.md
M docs/rules/520-JAVA_MAVEN_GRADLE.md
```
## Transition
### PASS
Créer et appliquer séparément `history/0.0.2/alpha.4.fix.1.md`, committer le correctif, puis préparer `0.0.2-alpha.5` consacré au profil Android.
### FAIL
Rester dans `0.0.2-alpha.4.fix.M`. Le correctif MUST rester limité à la cohérence de la tranche Java/Maven/Gradle.

162
deltas/0.0.2/alpha.4.md Normal file
View File

@@ -0,0 +1,162 @@
<!-- file: deltas/0.0.2/alpha.4.md -->
<!-- version: 1 -->
# Delta 0.0.2-alpha.4 — profil Java / Maven / Gradle
## Baseline
Version attendue avant application :
```text
0.0.2-alpha.3
```
Le history `history/0.0.2/alpha.3.md` MUST avoir été appliqué et committé avant ce delta.
Version après application :
```text
0.0.2-alpha.4
```
## Objet
Matérialiser le deuxième profil technologique de PGR : `Java / Maven / Gradle`.
Cette tranche conserve une frontière explicite entre :
```text
Java
→ règles du langage et de l'API
Maven / Gradle
→ spécialisations de build
Android / frameworks futurs
→ contraintes plus spécifiques qui pourront surcharger localement Java ou Gradle
```
Aucune règle Android, AGP, SDK, `minSdk`, `targetSdk`, `versionCode`, APK/AAB ou JNI n'est absorbée dans ce profil.
## Réconciliation retenue
Le profil reprend les principes déjà établis par PGR et les corpus de conception revus pour cette release :
- JDK LTS par défaut, dernière LTS compatible utilisée en priorité ;
- bascule vers une LTS plus ancienne lorsqu'une dépendance ou un outil l'exige ;
- non-LTS uniquement par exception justifiée ;
- séparation entre JDK de build et niveau Java/runtime supporté ;
- structure standard `src/main/java`, `src/main/resources`, `src/test/java`, `src/test/resources` ;
- packages orientés responsabilités et visibilité minimale ;
- imports explicites ;
- interfaces uniquement lorsqu'une vraie frontière existe ;
- pas de Lombok/convenience codegen implicite par défaut, sans interdire les annotations fonctionnelles de frameworks ;
- nullabilité et exceptions explicites ;
- tests unitaires/intégration/environnement séparables ;
- politique Maven centralisée dans le parent/root ;
- `dependencyManagement` / `pluginManagement` utilisés pour la politique commune sans ajouter artificiellement les dépendances aux modules ;
- Maven Wrapper conditionnel selon le besoin de reproductibilité ;
- configuration Gradle commune centralisée ;
- version catalog Gradle uniquement si la complexité le justifie ;
- contrainte Gradle exprimée comme minimum, range, pin exact ou latest compatible selon la vraie matrice ;
- Gradle Wrapper recommandé lorsqu'il apporte une reproductibilité réelle, sans interdire un Gradle système explicitement contraint ;
- un DSL Gradle cohérent par projet, sans transformer Groovy/Kotlin DSL en préférence de langage applicatif ;
- tâches ciblées pendant le développement, gates globales lorsque leur preuve devient utile ;
- `clean` traité comme maintenance ;
- outputs/caches/état local hors Git, avec wrappers comme exception volontaire lorsqu'ils sont retenus.
## Profil créé
Le nouveau propriétaire normatif est :
```text
docs/rules/520-JAVA_MAVEN_GRADLE.md
```
Il complète la famille `500 — languages / ecosystems` et n'introduit pas de nouvelle famille de navigation.
Aucun audit Java/Maven/Gradle n'est ajouté : le dépôt PGR ne contient actuellement aucun projet de ce type sur lequel une telle gate fournirait une preuve réelle.
## Scope
REPLACE :
```text
VERSION
RULES.md
docs/rules/000-README.md
```
ADD :
```text
docs/rules/520-JAVA_MAVEN_GRADLE.md
deltas/0.0.2/alpha.4.md
```
DELETE : aucun.
Aucun manifest de suppression n'est nécessaire.
## Validation opérateur
```bash
test "$(cat VERSION)" = "0.0.2-alpha.4"
test -f docs/rules/520-JAVA_MAVEN_GRADLE.md
test -f deltas/0.0.2/alpha.4.md
grep -F 'le JDK de développement SHOULD être une version LTS' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'JDK utilisé pour construire' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'src/main/' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'Lombok et les outils équivalents de convenience/codegen implicite SHOULD NOT être utilisés par défaut' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'Le fichier PGR `VERSION` reste la version canonique de l' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'PGR MUST NOT ajouter un Maven Wrapper uniquement par cérémonie.' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'minimum seulement' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'Un Gradle Wrapper SHOULD être versionné lorsqu' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'Groovy DSL et Kotlin DSL sont tous deux reconnus.' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'gradle clean` est une opération de maintenance' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F 'Aucune commande Maven/Gradle n' docs/rules/520-JAVA_MAVEN_GRADLE.md
grep -F '520-JAVA_MAVEN_GRADLE.md' RULES.md
grep -F '520-JAVA_MAVEN_GRADLE.md' docs/rules/000-README.md
python3 -B scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts
git diff --check
git add VERSION RULES.md docs/rules/000-README.md docs/rules/520-JAVA_MAVEN_GRADLE.md deltas/0.0.2/alpha.4.md
git diff --cached --check
git status --short
```
La sortie attendue avant ajout du history est :
```text
M RULES.md
M VERSION
A deltas/0.0.2/alpha.4.md
M docs/rules/000-README.md
A docs/rules/520-JAVA_MAVEN_GRADLE.md
```
Revue opérateur complémentaire :
- confirmer que les règles Java restent distinctes des contraintes propres à Maven/Gradle ;
- confirmer que les contraintes Android restent hors de ce profil et pourront surcharger localement Gradle/JDK en `alpha.5` ;
- confirmer que la politique JDK privilégie les LTS sans pin exact arbitraire ;
- confirmer que Lombok/convenience codegen est distingué des annotations fonctionnelles de frameworks ;
- confirmer que Maven Wrapper et Gradle Wrapper sont des choix de reproductibilité justifiés, pas des obligations cérémonielles universelles ;
- confirmer qu'aucune commande Maven/Gradle réelle n'est exigée pour valider cette tranche documentaire dans le dépôt PGR lui-même.
## Transition
### PASS
Créer et appliquer séparément `history/0.0.2/alpha.4.md`, committer la tranche, puis préparer `0.0.2-alpha.5` consacré au profil plateforme Android.
### FAIL
Rester dans `0.0.2-alpha.4.fix.M` tant que les frontières Java/build tool ou les politiques de compatibilité restent incorrectes. Effectuer un REPLAN si la tranche révèle une dérive significative du scope.

142
deltas/0.0.2/alpha.5.md Normal file
View File

@@ -0,0 +1,142 @@
<!-- file: deltas/0.0.2/alpha.5.md -->
<!-- version: 1 -->
# Delta 0.0.2-alpha.5 — profil plateforme Android
## Baseline
Version attendue avant application :
```text
0.0.2-alpha.4.fix.1
```
Le history `history/0.0.2/alpha.4.fix.1.md` MUST avoir été appliqué et committé avant ce delta.
Version après application :
```text
0.0.2-alpha.5
```
## Objet
Matérialiser le premier profil plateforme de PGR :
```text
docs/rules/610-ANDROID.md
```
La tranche consolide les règles Android réutilisables sans absorber les spécialisations Rust/JNI ou Tauri.
## Frontières retenues
Le profil Android possède notamment :
- la structure Android dans un dépôt mono- ou multi-plateforme ;
- Java comme défaut applicatif PGR lorsque rien n'impose un autre langage ;
- la matrice AGP / Gradle / JDK ;
- la séparation `compileSdk` / `targetSdk` / `minSdk` ;
- `VERSION` / `versionName` / `versionCode` ;
- configuration locale, signing et secrets ;
- modules et dépendances Android ;
- ABI lorsqu'un code natif existe, sans définir JNI ;
- niveaux de tests Android et ordre de validation ;
- manifest, permissions et ressources ;
- APK/AAB et packaging de distribution.
Restent hors scope :
```text
Rust / Android / JNI
Tauri desktop
Tauri mobile
Web / WASM
```
Ces compositions ne doivent pas être introduites implicitement dans `610-ANDROID.md`.
## Scope
REPLACE :
```text
VERSION
RULES.md
docs/rules/000-README.md
```
ADD :
```text
docs/rules/610-ANDROID.md
deltas/0.0.2/alpha.5.md
```
DELETE : aucun.
## Validation opérateur
```bash
test "$(cat VERSION)" = "0.0.2-alpha.5"
test -f docs/rules/610-ANDROID.md
test -f deltas/0.0.2/alpha.5.md
grep -F 'Les profils Rust/JNI et Tauri ne sont pas définis ici.' docs/rules/610-ANDROID.md
grep -F 'Dans un dépôt multi-plateforme où une zone Android distincte est nécessaire' docs/rules/610-ANDROID.md
grep -F 'Java est le langage applicatif Android par défaut du profil PGR' docs/rules/610-ANDROID.md
grep -F 'Android Gradle Plugin' docs/rules/610-ANDROID.md
grep -F 'PGR MUST NOT déduire une hausse de `minSdk`' docs/rules/610-ANDROID.md
grep -F '`versionCode` est un compteur Android monotone distinct du SemVer.' docs/rules/610-ANDROID.md
grep -F '`local.properties` est un fichier local Android typique' docs/rules/610-ANDROID.md
grep -F 'Les secrets de signature ne sont jamais versionnés.' docs/rules/610-ANDROID.md
grep -F 'Une ABI annoncée comme supportée doit disposer d' docs/rules/610-ANDROID.md
grep -F 'JVM unit' docs/rules/610-ANDROID.md
grep -F '`AndroidManifest.xml` MUST déclarer uniquement les permissions' docs/rules/610-ANDROID.md
grep -F 'APK debug' docs/rules/610-ANDROID.md
grep -F 'PGR lui-même ne contient actuellement aucun projet Android' docs/rules/610-ANDROID.md
grep -F '610-ANDROID.md' RULES.md
grep -F '610-ANDROID.md' docs/rules/000-README.md
python3 -B scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts
git diff --check
git add VERSION RULES.md docs/rules/000-README.md docs/rules/610-ANDROID.md deltas/0.0.2/alpha.5.md
git diff --cached --check
git status --short
```
La sortie attendue avant ajout du history est :
```text
M RULES.md
M VERSION
A deltas/0.0.2/alpha.5.md
M docs/rules/000-README.md
A docs/rules/610-ANDROID.md
```
Revue opérateur complémentaire :
- confirmer que le profil reste Android général et n'absorbe ni JNI ni Tauri ;
- confirmer que `compileSdk`, `targetSdk` et `minSdk` restent des contrats distincts ;
- confirmer que l'usage d'une toolchain moderne ne relève pas automatiquement `minSdk` ;
- confirmer que `versionCode` reste un compteur Android distinct de SemVer ;
- confirmer que les secrets et configurations locales restent hors Git ;
- confirmer que les niveaux de preuve unit/instrumented/smoke ne sont pas confondus ;
- confirmer qu'aucune validation Android réelle n'est revendiquée pour PGR lui-même en l'absence de projet Android.
## Transition
### PASS
Créer et appliquer séparément `history/0.0.2/alpha.5.md`, committer la tranche, puis passer à `0.0.2-beta.1` pour la réconciliation des profils.
### FAIL
Rester dans `0.0.2-alpha.5.fix.M` jusqu'à correction. Un REPLAN n'est nécessaire que si la correction révèle un élargissement substantiel du scope.

View File

@@ -0,0 +1,91 @@
<!-- file: deltas/0.0.2/beta.1.fix.1.md -->
<!-- version: 1 -->
# Delta 0.0.2-beta.1.fix.1 — correction du quoting de la gate beta
## Baseline
Version attendue avant application :
```text
0.0.2-beta.1
```
Le history `history/0.0.2/beta.1.md` MUST avoir été appliqué et committé avant ce delta.
Version après application :
```text
0.0.2-beta.1.fix.1
```
## Objet
Corriger uniquement la commande Bash invalide observée dans la gate de `beta.1`.
La commande précédente utilisait une chaîne délimitée par apostrophes simples contenant elle-même l'apostrophe de `L'interdiction`, ce qui ouvrait une invite Bash de continuation.
Le document `docs/rules/610-ANDROID.md` est correct et n'est pas modifié.
La vérification est remplacée par une recherche littérale équivalente ne contenant aucune apostrophe conflictuelle :
```bash
grep -F 'reste possédée par `RULES.md`.' docs/rules/610-ANDROID.md
```
Aucune règle, aucun profil et aucun audit n'est ajouté ou modifié par ce fix.
## Scope
REPLACE :
```text
VERSION
```
ADD :
```text
deltas/0.0.2/beta.1.fix.1.md
```
DELETE : aucun.
## Validation opérateur
```bash
test "$(cat VERSION)" = "0.0.2-beta.1.fix.1"
test -f deltas/0.0.2/beta.1.fix.1.md
grep -F 'reste possédée par `RULES.md`.' docs/rules/610-ANDROID.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 deltas/0.0.2/beta.1.fix.1.md
git diff --cached --check
git status --short
```
La sortie attendue avant ajout du history est exactement :
```text
M VERSION
A deltas/0.0.2/beta.1.fix.1.md
```
## Transition
### PASS
Créer et appliquer séparément `history/0.0.2/beta.1.fix.1.md`, committer le fix, puis préparer `0.0.2-rc.1`.
### FAIL
Rester dans `0.0.2-beta.1.fix.M`. Le scope du correctif MUST rester limité à la cohérence de la gate beta.

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.

120
deltas/0.0.2/rc.1.fix.1.md Normal file
View File

@@ -0,0 +1,120 @@
<!-- file: deltas/0.0.2/rc.1.fix.1.md -->
<!-- version: 1 -->
# Delta 0.0.2-rc.1.fix.1 — correction de l'audit inline des headers
## Baseline
Version attendue avant application :
```text
0.0.2-rc.1
```
Le history `history/0.0.2/rc.1.md` MUST avoir été appliqué et committé avant ce delta.
Version après application :
```text
0.0.2-rc.1.fix.1
```
## Objet
Corriger uniquement le script Python inline invalide observé dans la gate de `rc.1`.
La gate précédente matérialisait une chaîne Python sur deux lignes et produisait :
```text
SyntaxError: unterminated string literal
```
Le correctif n'ajoute pas de troisième audit PGR permanent : le scope RC reste gelé sur les audits `tables` et `liens locaux`.
L'audit ponctuel des headers est rejoué avec une forme sans échappement ambigu.
## Scope
REPLACE :
```text
VERSION
```
ADD :
```text
deltas/0.0.2/rc.1.fix.1.md
```
DELETE : aucun.
## Validation opérateur
```bash
test "$(cat VERSION)" = "0.0.2-rc.1.fix.1"
test -f deltas/0.0.2/rc.1.fix.1.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
python3 -B - <<'PY'
from pathlib import Path
import re
roots = [Path(name) for name in ('README.md', 'RULES.md', 'ROADMAP.md', 'CHANGELOG.md')]
for directory in ('docs', 'deltas', 'history', 'prompts'):
roots.extend(Path(directory).rglob('*.md'))
paths = sorted(set(roots))
errors = []
for path in paths:
lines = path.read_text(encoding='utf-8').splitlines()
expected = f'<!-- file: {path.as_posix()} -->'
if len(lines) < 2 or lines[0] != expected:
errors.append(f'{path}: invalid file header')
elif re.fullmatch(r'<!-- version: [1-9][0-9]* -->', lines[1]) is None:
errors.append(f'{path}: invalid version header')
if errors:
for error in errors:
print(error)
raise SystemExit(1)
print(f'Markdown header audit: clean ({len(paths)} file(s))')
PY
git diff --check
git add VERSION deltas/0.0.2/rc.1.fix.1.md
git diff --cached --check
git status --short
```
La sortie attendue avant ajout du history est exactement :
```text
M VERSION
A deltas/0.0.2/rc.1.fix.1.md
```
## Revue opérateur complémentaire
- confirmer que les deux audits PGR existants restent propres ;
- confirmer que l'audit ponctuel des headers s'exécute réellement et annonce un résultat `clean` ;
- confirmer qu'aucun contenu fonctionnel de `rc.1` n'est modifié ;
- confirmer que le scope RC reste gelé.
## Transition
### PASS
Créer et appliquer séparément `history/0.0.2/rc.1.fix.1.md`, committer le fix, puis préparer la tranche stable `0.0.2` selon le workflow de release.
### FAIL
Rester dans `0.0.2-rc.1.fix.M`. À partir de `.fix.3`, appliquer la revue de plan/diagnostic imposée par la gouvernance.

158
deltas/0.0.2/rc.1.md Normal file
View File

@@ -0,0 +1,158 @@
<!-- file: deltas/0.0.2/rc.1.md -->
<!-- version: 1 -->
# Delta 0.0.2-rc.1 — gel des profils et préparation de release
## Baseline
Version attendue avant application :
```text
0.0.2-beta.1.fix.1
```
Le history `history/0.0.2/beta.1.fix.1.md` MUST avoir été appliqué et committé avant ce delta.
Version après application :
```text
0.0.2-rc.1
```
## Objet
Entrer en release candidate après réconciliation beta.
La tranche :
- gèle le scope `0.0.2` ;
- prépare l'entrée candidate stable `0.0.2` du changelog ;
- met à jour le plan avec l'état réellement observé de la beta et le freeze RC ;
- ajoute `prompts/003-V0_0_3_START_PROMPT.md` ;
- inclut dans ce prompt le texte manuel canonique de reprise et la règle de transmission du futur rapport `publish.001` ;
- exécute la gate documentaire complète applicable à PGR.
Aucun nouveau profil technologique, famille de règles ou audit n'est ajouté en RC.
## Scope gelé
Les owners technologiques de la release restent exactement :
```text
510 — Rust / Cargo
520 — Java / Maven / Gradle
610 — Android
```
Les audits PGR ajoutés pendant la release restent exactement :
```text
scripts/audit_markdown_tables.py
scripts/audit_markdown_links.py
```
Les profils différés restent différés.
## Scope
REPLACE :
```text
VERSION
CHANGELOG.md
docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
```
ADD :
```text
prompts/003-V0_0_3_START_PROMPT.md
deltas/0.0.2/rc.1.md
```
DELETE : aucun.
## Validation opérateur
```bash
test "$(cat VERSION)" = "0.0.2-rc.1"
test -f prompts/003-V0_0_3_START_PROMPT.md
test -f deltas/0.0.2/rc.1.md
grep -F '## 0.0.2' CHANGELOG.md
grep -F '510 — Rust / Cargo' CHANGELOG.md
grep -F '520 — Java / Maven / Gradle' CHANGELOG.md
grep -F '610 — Android' CHANGELOG.md
grep -F 'Le scope RC est gelé' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F 'beta.1.fix.1 PASS' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F 'pgr-0.0.2-publish.001-report.md' prompts/003-V0_0_3_START_PROMPT.md
grep -F 'Prompt manuel de nouvelle session' prompts/003-V0_0_3_START_PROMPT.md
grep -F 'Partir de v0.0.2' prompts/003-V0_0_3_START_PROMPT.md
grep -F 'Ce texte doit être présenté spontanément' prompts/003-V0_0_3_START_PROMPT.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
python3 -B - <<'PY'
from pathlib import Path
import re
roots = [Path(name) for name in ('README.md', 'RULES.md', 'ROADMAP.md', 'CHANGELOG.md')]
for directory in ('docs', 'deltas', 'history', 'prompts'):
roots.extend(Path(directory).rglob('*.md'))
errors = []
for path in sorted(set(roots)):
lines = path.read_text(encoding='utf-8').splitlines()
expected = f'<!-- file: {path.as_posix()} -->'
if len(lines) < 2 or lines[0] != expected:
errors.append(f'{path}: invalid file header')
elif re.fullmatch(r'<!-- version: [1-9][0-9]* -->', lines[1]) is None:
errors.append(f'{path}: invalid version header')
if errors:
raise SystemExit('
'.join(errors))
print(f'Markdown header audit: clean ({len(set(roots))} file(s))')
PY
git diff --check
git add VERSION CHANGELOG.md docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md prompts/003-V0_0_3_START_PROMPT.md deltas/0.0.2/rc.1.md
git diff --cached --check
git status --short
```
La sortie attendue avant ajout du history est exactement :
```text
M CHANGELOG.md
M VERSION
A deltas/0.0.2/rc.1.md
M docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
A prompts/003-V0_0_3_START_PROMPT.md
```
## Revue opérateur complémentaire
- confirmer qu'aucun nouveau profil n'est introduit en RC ;
- confirmer que le changelog décrit la release utilement sans recopier la chronologie des fixes ;
- confirmer que le prompt `0.0.3` impose une nouvelle vérification de l'archive taggée plutôt que de faire confiance au report précédent ;
- confirmer que le prompt manuel de nouvelle session est fourni spontanément et précise explicitement le report `publish.001` à joindre après publication ;
- confirmer que `0.0.3` reste centré sur templates initiaux et patterns d'audit, sans absorber les skeleton specifications de `0.0.4`.
## Transition
### PASS
Créer et appliquer séparément `history/0.0.2/rc.1.md`, committer la RC, puis préparer la promotion stable `rel.001`.
### FAIL
Rester dans `0.0.2-rc.1.fix.M` jusqu'à correction. Aucun nouveau scope fonctionnel ne doit être introduit dans un fix RC.

154
deltas/0.0.2/rel.001.md Normal file
View File

@@ -0,0 +1,154 @@
<!-- file: deltas/0.0.2/rel.001.md -->
<!-- version: 1 -->
# Delta 0.0.2 rel.001 — promotion stable
## Baseline
Version attendue avant application :
```text
0.0.2-rc.1.fix.1
```
Le history `history/0.0.2/rc.1.fix.1.md` MUST avoir été appliqué et committé avant ce delta.
Version après application :
```text
0.0.2
```
`rel.001` est l'identifiant opérationnel de cette clôture stable ; il ne fait pas partie de la version SemVer produit.
## Objet
Promouvoir mécaniquement la release candidate validée vers la stable `0.0.2`, finaliser les métadonnées vivantes de la release et préparer le commit/tag stable.
Cette tranche n'introduit aucune nouvelle règle normative, aucun nouveau profil, aucun nouvel audit et aucun nouveau scope fonctionnel.
## Scope
REPLACE :
```text
VERSION
README.md
ROADMAP.md
docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
```
ADD :
```text
deltas/0.0.2/rel.001.md
```
DELETE : aucun.
## Changements
- `VERSION` devient `0.0.2` ;
- `README.md` présente `0.0.2` comme la première release matérialisant des profils technologiques réutilisables et référence son plan historique ;
- `ROADMAP.md` marque `0.0.2` terminé ;
- le plan `0.0.2` est clôturé après `rc.1.fix.1` et rappelle la séparation entre `rel.001` pré-tag et `publish.001` post-tag ;
- `CHANGELOG.md` n'est pas modifié : l'entrée stable `0.0.2` préparée en RC est déjà finalisée ;
- `prompts/003-V0_0_3_START_PROMPT.md` n'est pas modifié : il cible déjà `v0.0.2` et demande explicitement le rapport post-tag lorsqu'il existe.
## Validation opérateur
```bash
test "$(cat VERSION)" = "0.0.2"
grep -F 'La release `0.0.2` ajoute le premier modèle de profils réutilisables' README.md
grep -F 'plan historique des premiers profils `0.0.2`' README.md
grep -F -- '- `(x) 0.0.2`' ROADMAP.md
grep -F 'Plan clôturé par la promotion stable `0.0.2` après validation de `0.0.2-rc.1.fix.1`.' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F 'Le contrôle post-tag `publish.001` reste une preuve séparée' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -Fx '## 0.0.2' CHANGELOG.md
test -f prompts/003-V0_0_3_START_PROMPT.md
grep -F 'v0.0.2' prompts/003-V0_0_3_START_PROMPT.md
grep -F 'pgr-0.0.2-publish.001-report.md' prompts/003-V0_0_3_START_PROMPT.md
for delta in deltas/0.0.2/*.md; do
name="${delta##*/}"
if [ "$name" = 'rel.001.md' ]; then
continue
fi
test -f "history/0.0.2/$name" || {
echo "Missing history for ${delta}" >&2
exit 1
}
done
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 - <<'PY'
from pathlib import Path
import re
roots = [Path(name) for name in ('README.md', 'RULES.md', 'ROADMAP.md', 'CHANGELOG.md')]
for directory in ('docs', 'deltas', 'history', 'prompts'):
roots.extend(Path(directory).rglob('*.md'))
paths = sorted(set(roots))
errors = []
for path in paths:
lines = path.read_text(encoding='utf-8').splitlines()
expected = f'<!-- file: {path.as_posix()} -->'
if len(lines) < 2 or lines[0] != expected:
errors.append(f'{path}: invalid file header')
elif re.fullmatch(r'<!-- version: [1-9][0-9]* -->', lines[1]) is None:
errors.append(f'{path}: invalid version header')
if errors:
for error in errors:
print(error)
raise SystemExit(1)
print(f'Markdown header audit: clean ({len(paths)} file(s))')
PY
git diff --check
git add VERSION README.md ROADMAP.md \
docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md \
deltas/0.0.2/rel.001.md
git diff --cached --check
git status --short
```
La sortie attendue avant ajout du history est exactement :
```text
M README.md
M ROADMAP.md
M VERSION
A deltas/0.0.2/rel.001.md
M docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
```
## Revue opérateur complémentaire
- confirmer que la promotion stable ne contient aucun changement fonctionnel ou normatif nouveau ;
- confirmer que `0.0.2` clôt uniquement les profils `510`, `520` et `610` retenus par le plan ;
- confirmer que les profils différés restent différés ;
- confirmer que le prompt `0.0.3` demande explicitement l'archive taggée et le rapport `publish.001` lorsqu'il existe ;
- confirmer que `CHANGELOG.md` décrit la stable utilement sans recopier les détails de prerelease.
## Transition
### PASS
Créer et appliquer séparément `history/0.0.2/rel.001.md`, committer la stable `0.0.2`, créer le tag `v0.0.2`, pousser commit et tag, puis télécharger l'archive source produite depuis ce tag et exécuter la vérification post-tag `publish.001`.
### FAIL
Ne pas créer le tag. Corriger la promotion stable dans une nouvelle tranche de clôture explicite avant toute publication.

View File

@@ -0,0 +1,122 @@
<!-- file: deltas/0.0.3/alpha.1.fix.1.md -->
<!-- version: 1 -->
# Delta 0.0.3-alpha.1.fix.1 — périmètre Rust/Cargo du plan
## Baseline et version
Baseline : tranche `0.0.3-alpha.1` validée par l'opérateur, avec `history/0.0.3/alpha.1.md` appliqué et committé. Ce fix ne doit pas être appliqué sur un état où le history `alpha.1` n'est pas encore dans le commit de base.
Version avant application :
```text
0.0.3-alpha.1
```
Version après application :
```text
0.0.3-alpha.1.fix.1
```
## Motif et observations
Le delta `alpha.1` a passé sa gate mécanique. La revue du plan ensuite a montré que la tranche Rust prévue autour du seul `rustfmt.toml` n'intégrait pas les réglages Clippy et les deux manifests Cargo communs déjà décrits dans `510-RUST_CARGO.md` et pratiqués dans KSP et Games.
Les archives de référence supplémentaires inspectées sont :
```text
khadhroony-solana-project-v0.3.16.zip SHA-256 db3cc1b3fc3fb07ee864b02e2a7346c673d4cf63b33e8e872aca6c6458856ca0
games-v0.3.5.zip SHA-256 5f5fdee1a271386766d059657d6eaa831acdc263b3e722fed738808335c0a105
```
Les deux projets centralisent lints et métadonnées Cargo, et conservent `rustfmt.toml` ainsi qu'un `clippy.toml`. Les scripts Rust des projets mêlent plusieurs politiques ; le plan corrigé en tire des candidats de propriétés isolées sans les recopier. La seule exception de lints locaux constatée parmi les `45` crates inspectées concerne la frontière Android de Games.
## Scope
REPLACE :
```text
VERSION
docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
```
ADD :
```text
deltas/0.0.3/alpha.1.fix.1.md
```
DELETE : aucun.
Le plan passe de `<!-- version: 1 -->` à `<!-- version: 2 -->` pour sa révision réelle. Les snapshots `deltas/0.0.3/alpha.1.md` et `history/0.0.3/alpha.1.md` restent inchangés. Aucun template, script, règle normative ou manifest de suppression n'est ajouté dans ce fix.
## Contenu corrigé
- le template Rust prévu couvre `rustfmt.toml`, les niveaux de lint Rust/Clippy dans Cargo, les manifests workspace/membre et, seulement si justifié, des paramètres distincts dans `clippy.toml` ;
- le plan compare les deux corpus réels, relève l'héritage explicite des lints et son exception Android bornée, distingue les options communes des seuils ou dépendances propres à un projet ;
- les tranches sont redimensionnées : `alpha.2` formatage/Clippy, `alpha.3` manifests Cargo, `alpha.4` audit de headers Markdown, puis décision conditionnelle sur un template de workflow ;
- les scripts Rust KSP/Games servent de corpus de comparaison pour des audits futurs read-only et monotâches, sans transfert direct de leurs règles locales vers PGR.
## Validation opérateur
Après application sur le commit `alpha.1` :
```bash
test "$(cat VERSION)" = '0.0.3-alpha.1.fix.1'
git cat-file -e HEAD:history/0.0.3/alpha.1.md
test -f deltas/0.0.3/alpha.1.fix.1.md
test -f history/0.0.3/alpha.1.md
test ! -e history/0.0.3/alpha.1.fix.1.md
grep -Fx '<!-- version: 2 -->' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
grep -F 'Les `22` crates KSP héritent des lints workspace' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
grep -F '### alpha.2 — formatage et configuration Clippy' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
grep -F '### alpha.3 — manifests Cargo workspace et crate membre' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
grep -F '### alpha.4 — audit de headers Markdown' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.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
python3 -B - <<'PY'
from pathlib import Path
import re
files = [Path(name) for name in ('README.md', 'RULES.md', 'ROADMAP.md', 'CHANGELOG.md')]
for directory in ('docs', 'deltas', 'history', 'prompts'):
files.extend(Path(directory).rglob('*.md'))
files = sorted(set(files))
for path in files:
lines = path.read_text(encoding='utf-8').splitlines()
assert len(lines) >= 2 and lines[0] == f'<!-- file: {path.as_posix()} -->', path
assert re.fullmatch(r'<!-- version: [1-9][0-9]* -->', lines[1]), path
print(f'Markdown header audit: clean ({len(files)} file(s))')
PY
git diff --check
git add VERSION docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md deltas/0.0.3/alpha.1.fix.1.md
git diff --cached --check
git status --short
```
Avant ajout du history du fix, le scope indexé attendu est :
```text
M VERSION
A deltas/0.0.3/alpha.1.fix.1.md
M docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
```
Revue complémentaire : confirmer que la correction ne copie pas de version de dépendance, de path Cargo ou de seuil Clippy arbitraire ; vérifier que le plan reste une prévision et que `alpha.1` demeure un snapshot historique inchangé.
## Transition
### PASS
Produire et appliquer séparément `history/0.0.3/alpha.1.fix.1.md` avec les résultats réellement observés, puis committer ce fix avant tout delta `alpha.2`.
### FAIL
Consigner le résultat réel dans le history du fix et poursuivre par `alpha.1.fix.2` limité au cadrage, ou engager un REPLAN explicite si le scope Rust doit changer davantage.

101
deltas/0.0.3/alpha.1.md Normal file
View File

@@ -0,0 +1,101 @@
<!-- file: deltas/0.0.3/alpha.1.md -->
<!-- version: 1 -->
# Delta 0.0.3-alpha.1 — audit de baseline et cadrage
## Baseline
Archive fournie `pgr-v0.0.2.zip`, déclarée téléchargée du tag Gitea `v0.0.2`, vérifiée avec SHA-256 :
```text
8dc5c979a4d722b4ef6ec84b6227c8cbfffb3f865f4ea9063c03ecb1e365cdc4
```
Le rapport post-tag externe `pgr-0.0.2-publish.001-report.md` indique `PASS` et le même hash. Il n'est pas ajouté rétroactivement à la stable. Aucun `.git` n'est attendu dans l'archive source.
Version avant application : `0.0.2`.
Version après application : `0.0.3-alpha.1`.
## Objet
Exécuter le cadrage demandé par `prompts/003-V0_0_3_START_PROMPT.md` : audit complet de la stable, vérification des règles et de la chaîne historique, inventaire des sujets utiles, choix d'un scope initial et découpage proportionné dans un plan actif.
Le résultat détaillé de l'audit, ses limites et les décisions de scope sont consignés dans `docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md`. L'archive est cohérente dans les contrôles réalisés ; aucune correction rétroactive de `0.0.2` n'est nécessaire avant cette tranche.
## Scope
REPLACE :
```text
VERSION
```
ADD :
```text
docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
deltas/0.0.3/alpha.1.md
```
DELETE : aucun.
L'archive delta contient exactement les fichiers complets ci-dessus, avec les mêmes chemins relatifs. Aucun manifest de suppression, history, nouveau template ou script d'audit n'appartient à cette tranche.
Les index et les documents historiques restent conformes sans mise à jour cérémonielle : la roadmap annonce déjà `0.0.3`, le changelog conserve les releases stables et les index documentaires pointent vers les collections existantes.
## Validation opérateur
Appliquer l'archive delta à la copie de travail du dépôt fondée sur `v0.0.2`. Depuis sa racine :
```bash
test "$(cat VERSION)" = '0.0.3-alpha.1'
test -f docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
test -f deltas/0.0.3/alpha.1.md
test ! -e history/0.0.3/alpha.1.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
python3 -B - <<'PY'
from pathlib import Path
import re
files = [Path(name) for name in ('README.md', 'RULES.md', 'ROADMAP.md', 'CHANGELOG.md')]
for directory in ('docs', 'deltas', 'history', 'prompts'):
files.extend(Path(directory).rglob('*.md'))
files = sorted(set(files))
for path in files:
lines = path.read_text(encoding='utf-8').splitlines()
assert len(lines) >= 2 and lines[0] == f'<!-- file: {path.as_posix()} -->', path
assert re.fullmatch(r'<!-- version: [1-9][0-9]* -->', lines[1]), path
print(f'Markdown header audit: clean ({len(files)} file(s))')
PY
git diff --check
git add VERSION docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md deltas/0.0.3/alpha.1.md
git diff --cached --check
git status --short
```
Avant d'ajouter le history, le scope attendu des fichiers indexés est :
```text
M VERSION
A docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
A deltas/0.0.3/alpha.1.md
```
L'opérateur confirme également que la baseline provient bien du tag déclaré, que le hash concorde avec la preuve post-tag, que les `24` couples historiques antérieurs sont conservés, que les profils différés ne sont pas matérialisés, et que le plan ne fait pas passer une prévision pour une règle déjà active.
## Transition
### PASS
Rédiger et livrer séparément `history/0.0.3/alpha.1.md` avec les résultats réellement observés ; l'appliquer et committer la tranche. Préparer seulement ensuite `0.0.3-alpha.2`.
### FAIL
Enregistrer le résultat réellement observé dans le history de `alpha.1`, puis corriger le cadrage dans `0.0.3-alpha.1.fix.1` ou produire un REPLAN motivé. Aucune implémentation `alpha.2` ne doit être absorbée dans le fix.

123
deltas/0.0.3/alpha.2.md Normal file
View File

@@ -0,0 +1,123 @@
<!-- file: deltas/0.0.3/alpha.2.md -->
<!-- version: 1 -->
# Delta 0.0.3-alpha.2 — outillage Rust/Cargo partagé
## Baseline et version
Baseline : `0.0.3-alpha.1.fix.1` avec `history/0.0.3/alpha.1.fix.1.md` appliqué et committé. Ce delta MUST NOT être appliqué avant ce commit.
Version avant application :
```text
0.0.3-alpha.1.fix.1
```
Version après application :
```text
0.0.3-alpha.2
```
## Objet
Matérialiser trois configurations Rust/Cargo directement issues des pratiques éprouvées dans KSP et Games, avec des instructions explicites d'adaptation. L'opérateur a précisé après le gate de `alpha.1.fix.1` que la sortie Cargo est généralement déportée vers `../builds/<projet>/target/` et que Rustfmt/Clippy constituent des conventions de départ qu'il réutilise avec des adaptations mineures.
Le `clippy.toml` livré conserve les réglages communs utiles aux deux corpus, sans copier leurs listes d'identifiants propres ni leurs entrées vides. Les niveaux des lints appartiendront aux templates `Cargo.toml` de `alpha.3`, conformément au profil `510`.
## Scope
REPLACE :
```text
VERSION
docs/000-README.md
docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
```
ADD :
```text
templates/rust-cargo/rustfmt.toml
templates/rust-cargo/clippy.toml
templates/rust-cargo/.cargo/config.toml
docs/templates/001-RUST_CARGO_TOOLING.md
deltas/0.0.3/alpha.2.md
```
DELETE : aucun.
Les fichiers complets sont livrés dans l'archive delta. Aucun history `alpha.2`, manifest de suppression, crate PGR ou script d'audit nouveau n'y est inclus.
## Validation opérateur
Depuis la racine du dépôt après application du delta :
```bash
test "$(cat VERSION)" = '0.0.3-alpha.2'
git cat-file -e HEAD:history/0.0.3/alpha.1.fix.1.md
test ! -e history/0.0.3/alpha.2.md
python3 -B - <<'PY'
from pathlib import Path
import tomllib
root = Path('templates/rust-cargo')
rustfmt = tomllib.loads((root / 'rustfmt.toml').read_text(encoding='utf-8'))
clippy = tomllib.loads((root / 'clippy.toml').read_text(encoding='utf-8'))
cargo = tomllib.loads((root / '.cargo/config.toml').read_text(encoding='utf-8'))
assert rustfmt['edition'] == '2024'
assert rustfmt['max_width'] == 160
assert clippy['allow-unwrap-in-tests'] is True
assert clippy['allowed-idents-below-min-chars'] == ['id']
assert cargo['build']['target-dir'] == '../builds/project-name/target'
assert cargo['build']['build-dir'] == cargo['build']['target-dir']
for path in (root / 'rustfmt.toml', root / 'clippy.toml', root / '.cargo/config.toml'):
lines = path.read_text(encoding='utf-8').splitlines()
assert lines[0] == f'# file: {path.as_posix()}', path
assert lines[1] == '# version: 1', path
print('Rust/Cargo template TOML audit: clean (3 file(s))')
PY
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 - <<'PY'
from pathlib import Path
import re
files = [Path(name) for name in ('README.md', 'RULES.md', 'ROADMAP.md', 'CHANGELOG.md')]
for directory in ('docs', 'deltas', 'history', 'prompts'):
files.extend(Path(directory).rglob('*.md'))
files = sorted(set(files))
for path in files:
lines = path.read_text(encoding='utf-8').splitlines()
assert len(lines) >= 2 and lines[0] == f'<!-- file: {path.as_posix()} -->', path
assert re.fullmatch(r'<!-- version: [1-9][0-9]* -->', lines[1]), path
print(f'Markdown header audit: clean ({len(files)} file(s))')
PY
git diff --check
git add VERSION docs/000-README.md docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md \
docs/templates/001-RUST_CARGO_TOOLING.md deltas/0.0.3/alpha.2.md \
templates/rust-cargo/rustfmt.toml templates/rust-cargo/clippy.toml \
templates/rust-cargo/.cargo/config.toml
git diff --cached --check
git status --short
```
Scope attendu avant ajout du history : les trois `REPLACE` et les cinq `ADD` énumérés ci-dessus, sans modification des deltas ou histories précédents.
Revue opérateur : confirmer que la convention de sortie Cargo vers un dossier frère est expliquée avec son chemin relatif réel, que `project-name` est à remplacer avant copie et que les lints de niveau Cargo et les manifests restent bien au scope de `alpha.3`. La gate de cette tranche reste documentaire/TOML : PGR ne contient aucun workspace Rust à compiler.
## Transition
### PASS
Produire séparément `history/0.0.3/alpha.2.md` avec les sorties réellement observées, l'appliquer et committer avant de préparer `alpha.3` consacré aux manifests Cargo.
### FAIL
Enregistrer la défaillance réelle puis corriger ces seuls templates ou instructions dans `alpha.2.fix.1`, sauf besoin de REPLAN justifié.

118
deltas/0.0.3/alpha.3.md Normal file
View File

@@ -0,0 +1,118 @@
<!-- file: deltas/0.0.3/alpha.3.md -->
<!-- version: 1 -->
# Delta 0.0.3-alpha.3 — audits de style Rust ciblés
## Baseline et version
Baseline : `0.0.3-alpha.2`, avec `history/0.0.3/alpha.2.md` appliqué et committé. Ce delta MUST NOT être appliqué tant que ce commit n'existe pas.
Version avant application :
```text
0.0.3-alpha.2
```
Version après application :
```text
0.0.3-alpha.3
```
## Objet et REPLAN
Après la gate PASS de `alpha.2`, l'opérateur a signalé les audits Python de style Rust de KSP et Games et demandé leur découpage en scripts plus petits et monotâches. L'examen de leurs `audit_rust_general_rules.py` montre qu'ils combinent blancs, constantes, ordre de modules, headers, rustdoc et règles de façade. Résultat REPLAN : `SPLIT`. Les deux contrôles de style apportant une preuve autonome passent à `alpha.3` ; les manifests Cargo initialement prévus ici passent à `alpha.4`, l'audit des headers Markdown à `alpha.5` et la décision workflow à `alpha.6`.
Ajouter un contrôle facultatif d'espacement des lignes vides et un contrôle facultatif des blocs de constantes racine, avec un helper lexical commun sans politique autonome. Le profil `510` possède leurs conventions optionnelles, la documentation de validation explicite leur adoption et leurs limites ; la matrice répertorie leur test ciblé. Rustfmt reste propriétaire du tri interne qu'il effectue déjà ; Clippy garde ses lints. Aucun script KSP/Games complet ni gate Rust obligatoire n'est copié dans PGR.
## Scope
REPLACE :
```text
VERSION
docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
docs/rules/510-RUST_CARGO.md
docs/templates/001-RUST_CARGO_TOOLING.md
docs/validation/001-VALIDATION_MATRIX.md
```
ADD :
```text
docs/validation/002-RUST_STYLE_AUDITS.md
scripts/_rust_audit_common.py
scripts/audit_rust_blank_lines.py
scripts/audit_rust_const_blocks.py
tests/test_rust_audits.py
deltas/0.0.3/alpha.3.md
```
DELETE : aucun.
Les fichiers complets figurent dans l'archive delta. Aucun history `alpha.3`, changement rétroactif de delta/history, manifest Cargo, suppression ou modification des corpus de référence n'est inclus.
## Limites et prévalidation
Les audits sont read-only, sélectionnent explicitement des fichiers `.rs` et signalent les violations avec chemin et ligne. La prévalidation hors dépôt PGR a porté sur `300` sources KSP et `59` sources Games : l'audit des blancs est propre sur les deux ; l'audit des constantes est propre sur Games mais affiche `17` signaux KSP lorsqu'il est lancé globalement. Des séquences KSP portent un ordre métier ou de schéma ; l'ordre alphabétique ne leur est pas imposé. La sélection du projet doit donc exclure les fichiers ayant une sémantique d'ordre incompatible. Les scripts ne parsèrent pas intégralement Rust et ne remplacent ni Rustfmt ni Clippy.
Cette prévalidation de corpus n'est pas une validation opérateur de la tranche. Le dépôt PGR ne contient ni crate Rust ni fichiers Rust sujets à un audit produit. Les cas de test Python du delta vérifient les contrats réellement livrés, y compris échecs attendus et statut CLI.
## Validation opérateur
Après application sur le commit `alpha.2` :
```bash
test "$(cat VERSION)" = '0.0.3-alpha.3'
git cat-file -e HEAD:history/0.0.3/alpha.2.md
test -f history/0.0.3/alpha.2.md
test -f deltas/0.0.3/alpha.3.md
test ! -e history/0.0.3/alpha.3.md
grep -Fx '<!-- version: 4 -->' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
grep -F '### alpha.4 — manifests Cargo workspace et crate membre' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
grep -F '### alpha.5 — audit de headers Markdown' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
python3 -B -m unittest discover -s tests -p test_rust_audits.py -v
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 - <<'PY'
from pathlib import Path
import re
files = [Path(name) for name in ('README.md', 'RULES.md', 'ROADMAP.md', 'CHANGELOG.md')]
for directory in ('docs', 'deltas', 'history', 'prompts'):
files.extend(Path(directory).rglob('*.md'))
files = sorted(set(files))
for path in files:
lines = path.read_text(encoding='utf-8').splitlines()
assert len(lines) >= 2 and lines[0] == f'<!-- file: {path.as_posix()} -->', path
assert re.fullmatch(r'<!-- version: [1-9][0-9]* -->', lines[1]), path
print(f'Markdown header audit: clean ({len(files)} file(s))')
PY
git diff --check
git add VERSION docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md \
docs/rules/510-RUST_CARGO.md docs/templates/001-RUST_CARGO_TOOLING.md \
docs/validation/001-VALIDATION_MATRIX.md docs/validation/002-RUST_STYLE_AUDITS.md \
scripts/_rust_audit_common.py scripts/audit_rust_blank_lines.py \
scripts/audit_rust_const_blocks.py tests/test_rust_audits.py \
deltas/0.0.3/alpha.3.md
git diff --cached --check
git status --short
```
Scope attendu avant ajout du history : cinq `REPLACE` et six `ADD` exactement comme ci-dessus. Revue opérateur : vérifier le rôle facultatif des deux scripts, leur dépendance commune, la sélection des fichiers Rust et la priorité de l'ordre sémantique ; confirmer que les manifests Cargo restent prévus en `alpha.4`.
## Transition
### PASS
Produire séparément `history/0.0.3/alpha.3.md` avec les résultats réellement exécutés, l'appliquer et committer cette tranche avant tout delta `alpha.4`.
### FAIL
Consigner le diagnostic dans le history `alpha.3`, puis corriger ce scope dans `alpha.3.fix.1` ou engager un nouveau REPLAN si la séparation des contrôles n'est plus adaptée.

191
deltas/0.0.3/alpha.4.md Normal file
View File

@@ -0,0 +1,191 @@
<!-- file: deltas/0.0.3/alpha.4.md -->
<!-- version: 1 -->
# Delta 0.0.3-alpha.4 — manifests Cargo workspace et membre
## Baseline et version
Baseline : `0.0.3-alpha.3`, avec `history/0.0.3/alpha.3.md` appliqué et committé. Ce delta MUST NOT être appliqué avant ce commit.
Version avant application :
```text
0.0.3-alpha.3
```
Version après application :
```text
0.0.3-alpha.4
```
## Objet
Fournir les deux manifests Cargo prévus dans le plan après son REPLAN `SPLIT` : un workspace virtuel à release commune et une crate bibliothèque membre. Les sections d'héritage, les lints Rust/Clippy communs, la version de release et le périmètre des dépendances doivent être compréhensibles sans figer les identités KSP/Games ni une liste de dépendances tierces.
Le manifest racine reprend les trois lints Rust et les `18` niveaux Clippy effectivement communs aux deux projets. Il déclare un bloc `[workspace.dependencies]` initialement vide. Le membre hérite explicitement des métadonnées présentes et des lints par `[lints] workspace = true`. La documentation distingue l'adaptation ordinaire d'une exception FFI locale, qui ne peut combiner cet héritage avec des lints locaux dans une même crate. La version `0.1.0` et le nom `project-core-lib` sont des exemples à remplacer, pas des valeurs de PGR ou d'un projet tiers.
Le plan vivant reçoit deux corrections factuelles : PGR possède désormais plus de deux utilitaires Python et la famille énumère cinq responsabilités, et non quatre. Ces corrections n'altèrent aucun delta ni history précédent.
## Scope
REPLACE :
```text
VERSION
docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
docs/templates/001-RUST_CARGO_TOOLING.md
```
ADD :
```text
templates/rust-cargo/Cargo.toml
templates/rust-cargo/crates/project-core-lib/Cargo.toml
docs/templates/002-CARGO_MANIFESTS.md
deltas/0.0.3/alpha.4.md
```
DELETE : aucun.
L'archive contient uniquement ces fichiers complets. Aucun fichier source Rust, history `alpha.4`, suppression, dépendance de build de PGR ou version tierce n'est introduit.
## Validation opérateur
Après application sur le commit `alpha.3` :
```bash
test "$(cat VERSION)" = '0.0.3-alpha.4'
git cat-file -e HEAD:history/0.0.3/alpha.3.md
test -f history/0.0.3/alpha.3.md
test ! -e history/0.0.3/alpha.4.md
test -f deltas/0.0.3/alpha.4.md
python3 -B - <<'PY'
from pathlib import Path
import json
import shutil
import subprocess
import tempfile
import tomllib
source = Path('templates/rust-cargo')
root_file = source / 'Cargo.toml'
member_file = source / 'crates/project-core-lib/Cargo.toml'
root = tomllib.loads(root_file.read_text(encoding='utf-8'))
member = tomllib.loads(member_file.read_text(encoding='utf-8'))
assert root['workspace']['resolver'] == '3'
assert root['workspace']['members'] == ['crates/project-core-lib']
assert root['workspace']['package']['version'] == '0.1.0' # Explicit example.
assert root['workspace']['package']['edition'] == '2024'
assert root['workspace']['package']['publish'] is False
assert root['workspace']['dependencies'] == {}
assert root['workspace']['lints']['rust'] == {
'missing_docs': 'warn', 'unreachable_pub': 'deny', 'unsafe_code': 'forbid'
}
clippy = root['workspace']['lints']['clippy']
assert len(clippy) == 18 and clippy['implicit_return'] == 'deny'
assert clippy['needless_return'] == 'allow' and clippy['unwrap_used'] == 'deny'
assert member['package']['name'] == 'project-core-lib'
for field in ('version', 'edition', 'publish'):
assert member['package'][field] == {'workspace': True}, field
assert member['dependencies'] == {} and member['lints'] == {'workspace': True}
for path in (root_file, member_file):
lines = path.read_text(encoding='utf-8').splitlines()
assert lines[:2] == [f'# file: {path.as_posix()}', '# version: 1'], path
print('Cargo manifest TOML audit: clean (2 file(s))')
if shutil.which('cargo') is None:
print('Cargo workspace smoke: toolchain unavailable; TOML audit only')
else:
with tempfile.TemporaryDirectory(prefix='pgr-cargo-manifests-') as folder:
workspace = Path(folder)
crate = workspace / 'crates/project-core-lib'
(crate / 'src').mkdir(parents=True)
shutil.copy2(root_file, workspace / 'Cargo.toml')
shutil.copy2(member_file, crate / 'Cargo.toml')
(crate / 'src/lib.rs').write_text(
'//! Minimal template check.\n\n/// Return one.\n'
'pub fn value() -> u8 {\n return 1;\n}\n', encoding='utf-8'
)
command = ['cargo', 'metadata', '--manifest-path', str(workspace / 'Cargo.toml'),
'--format-version', '1', '--no-deps', '--offline']
result = subprocess.run(command, cwd=workspace, text=True,
capture_output=True, check=True)
package = json.loads(result.stdout)['packages'][0]
assert package['name'] == 'project-core-lib'
assert package['version'] == '0.1.0' and package['edition'] == '2024'
subprocess.run(['cargo', 'check', '--workspace', '--offline'],
cwd=workspace, check=True)
if subprocess.run(['cargo', 'clippy', '--version'], capture_output=True).returncode == 0:
subprocess.run(['cargo', 'clippy', '--workspace', '--all-targets',
'--all-features', '--offline', '--', '-D', 'warnings'],
cwd=workspace, check=True)
# Inherited forbid must reject unsafe code before a local FFI exception.
(crate / 'src/lib.rs').write_text(
'//! Minimal FFI exception check.\n\n/// Return one.\n'
'pub fn value() -> u8 {\n'
' let value: u8 = 1;\n let ptr: *const u8 = &value;\n'
' unsafe { return *ptr; }\n}\n', encoding='utf-8'
)
rejected = subprocess.run(['cargo', 'check', '--workspace', '--offline'],
cwd=workspace, capture_output=True, text=True)
assert rejected.returncode != 0 and 'unsafe' in rejected.stderr
# Cargo must accept a local lint table in place of inheritance.
local = member_file.read_text(encoding='utf-8').replace(
'[lints]\nworkspace = true\n',
'[lints.rust]\nmissing_docs = "warn"\n'
'unreachable_pub = "deny"\nunsafe_code = "allow"\n\n'
'[lints.clippy]\n' + ''.join(
f'{name} = {json.dumps(level)}\n' for name, level in clippy.items()
)
)
assert '[lints.rust]' in local and '[lints]\nworkspace = true' not in local
(crate / 'Cargo.toml').write_text(local, encoding='utf-8')
subprocess.run(['cargo', 'check', '--workspace', '--offline'],
cwd=workspace, check=True)
print('Cargo workspace smoke: clean (inherited and local lints)')
PY
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 - <<'PY'
from pathlib import Path
import re
files = [Path(name) for name in ('README.md', 'RULES.md', 'ROADMAP.md', 'CHANGELOG.md')]
for directory in ('docs', 'deltas', 'history', 'prompts'):
files.extend(Path(directory).rglob('*.md'))
files = sorted(set(files))
for path in files:
lines = path.read_text(encoding='utf-8').splitlines()
assert len(lines) >= 2 and lines[0] == f'<!-- file: {path.as_posix()} -->', path
assert re.fullmatch(r'<!-- version: [1-9][0-9]* -->', lines[1]), path
print(f'Markdown header audit: clean ({len(files)} file(s))')
PY
git diff --check
git add VERSION docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md \
docs/templates/001-RUST_CARGO_TOOLING.md docs/templates/002-CARGO_MANIFESTS.md \
templates/rust-cargo/Cargo.toml templates/rust-cargo/crates/project-core-lib/Cargo.toml \
deltas/0.0.3/alpha.4.md
git diff --cached --check
git status --short
```
Scope attendu avant ajout du history : les trois `REPLACE` et les quatre `ADD` ci-dessus. Revue opérateur : vérifier que le manifest membre hérite seulement des champs racine présents, que les lints Clippy sont ceux des deux corpus et que la version d'exemple ainsi que le nom de crate doivent être remplacés lors d'une adoption réelle. Si Cargo n'est pas disponible dans l'environnement de PGR, le smoke workspace est indiqué comme non exécuté et le parsing TOML reste la preuve locale ; l'adoption dans un projet Rust doit exécuter sa propre gate Cargo.
## Transition
### PASS
Fournir séparément `history/0.0.3/alpha.4.md` avec les sorties réellement observées, l'appliquer et committer la tranche avant le delta `alpha.5` relatif aux headers Markdown.
### FAIL
Consigner le défaut dans le history, puis corriger manifests ou instructions dans `alpha.4.fix.1` sauf besoin justifié d'un nouveau REPLAN.

90
deltas/0.0.3/alpha.5.md Normal file
View File

@@ -0,0 +1,90 @@
<!-- file: deltas/0.0.3/alpha.5.md -->
<!-- version: 1 -->
# Delta 0.0.3-alpha.5 — audit des headers Markdown
## Baseline et version
Baseline : `0.0.3-alpha.4`, avec `history/0.0.3/alpha.4.md` appliqué et committé. Ce delta MUST NOT être appliqué avant ce commit.
Version avant application :
```text
0.0.3-alpha.4
```
Version après application :
```text
0.0.3-alpha.5
```
## Objet
Extraire le contrôle des headers Markdown répété en Python inline dans les gates précédentes. `scripts/audit_markdown_headers.py` vérifie une seule propriété documentaire : les deux premières lignes de chaque fichier choisi doivent déclarer son chemin relatif canonique et une révision interne positive. Le script accepte des chemins explicites depuis la racine du projet, lit sans modifier, produit des erreurs déterministes avec chemin et ligne et distingue violation de sélection invalide.
`docs/rules/300-DOCUMENTATION.md` possède la convention pour le corpus Markdown de PGR. La matrice inscrit l'audit mécanique séparément de la revue des rôles documentaires, de l'audit des tableaux et de celui des liens. Une révision positive ne démontre pas qu'elle a été incrémentée à bon escient : cela reste une décision de revue.
## Scope
REPLACE :
```text
VERSION
docs/rules/300-DOCUMENTATION.md
docs/validation/001-VALIDATION_MATRIX.md
```
ADD :
```text
scripts/audit_markdown_headers.py
tests/test_markdown_headers.py
deltas/0.0.3/alpha.5.md
```
DELETE : aucun.
L'archive livre uniquement ces fichiers complets. Aucun history `alpha.5`, réécriture historique, nouveau profil de langage ou autre audit Markdown n'est inclus.
## Validation opérateur
Après application sur le commit `alpha.4`, depuis la racine du dépôt :
```bash
test "$(cat VERSION)" = '0.0.3-alpha.5'
git cat-file -e HEAD:history/0.0.3/alpha.4.md
test -f history/0.0.3/alpha.4.md
test -f deltas/0.0.3/alpha.5.md
test ! -e history/0.0.3/alpha.5.md
grep -Fx '<!-- version: 2 -->' docs/rules/300-DOCUMENTATION.md
grep -Fx '<!-- version: 8 -->' docs/validation/001-VALIDATION_MATRIX.md
python3 -B -m unittest discover -s tests -p test_markdown_headers.py -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
git diff --check
git add VERSION docs/rules/300-DOCUMENTATION.md \
docs/validation/001-VALIDATION_MATRIX.md scripts/audit_markdown_headers.py \
tests/test_markdown_headers.py deltas/0.0.3/alpha.5.md
git diff --cached --check
git status --short
```
Scope attendu avant ajout du history : trois `REPLACE` et trois `ADD`, sans toucher à un delta ou history antérieur. Vérifier que le nouveau script reste monotâche, traite les headers faux et les chemins absents, et ne remplace ni la revue des documents ni les deux autres audits Markdown.
## Transition
### PASS
Produire séparément `history/0.0.3/alpha.5.md` avec les preuves réellement observées, l'appliquer et committer avant la tranche `alpha.6`, consacrée à la décision conditionnelle sur le template de workflow.
### FAIL
Enregistrer la défaillance et corriger ce scope dans `alpha.5.fix.1`, sauf REPLAN explicitement justifié.

92
deltas/0.0.3/alpha.6.md Normal file
View File

@@ -0,0 +1,92 @@
<!-- file: deltas/0.0.3/alpha.6.md -->
<!-- version: 1 -->
# Delta 0.0.3-alpha.6 — prompt manuel de reprise
## Baseline et version
Baseline : `0.0.3-alpha.5`, avec `history/0.0.3/alpha.5.md` appliqué et committé. Ce delta MUST NOT être appliqué avant ce commit.
Version avant application :
```text
0.0.3-alpha.5
```
Version après application :
```text
0.0.3-alpha.6
```
## Décision et objet
La comparaison des prompts `002` et `003` et des règles `210-WORKFLOW.md` confirme une répétition utile : baseline taggée, version cible, première tranche et consigne d'audit à la reprise. `003` ajoute une preuve de vérification post-tag distincte et une phrase manuelle à remettre à l'opérateur. La décision conditionnelle de la tranche est donc **retenir** une spécification courte dans `docs/templates/003-NEW_SESSION_PROMPT.md`.
Ce document rassemble les champs à renseigner et une forme de message manuel, avec une branche claire lorsque le rapport post-tag manque ou n'est pas `PASS`. Il ne génère rien, ne fige aucun nom de projet ni preuve et ne prépare pas encore le prompt versionné de `0.0.4`. `docs/rules/210-WORKFLOW.md` reste propriétaire de la séquence delta/history/commit et de la publication après tag ; le plan vivant enregistre la décision.
## Scope
REPLACE :
```text
VERSION
docs/rules/210-WORKFLOW.md
docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
```
ADD :
```text
docs/templates/003-NEW_SESSION_PROMPT.md
deltas/0.0.3/alpha.6.md
```
DELETE : aucun.
L'archive contient uniquement ces fichiers complets. Aucun history `alpha.6`, prompt `004`, générateur, modification de prompts historiques ou changement de configuration Rust/Cargo n'est inclus.
## Validation opérateur
Après application sur le commit `alpha.5`, depuis la racine du dépôt :
```bash
test "$(cat VERSION)" = '0.0.3-alpha.6'
git cat-file -e HEAD:history/0.0.3/alpha.5.md
test -f history/0.0.3/alpha.5.md
test -f deltas/0.0.3/alpha.6.md
test -f docs/templates/003-NEW_SESSION_PROMPT.md
test ! -e history/0.0.3/alpha.6.md
test ! -e prompts/004-V0_0_4_START_PROMPT.md
grep -Fx '<!-- version: 3 -->' docs/rules/210-WORKFLOW.md
grep -Fx '<!-- version: 6 -->' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
grep -F '### Retenu : spécification courte du prompt manuel de nouvelle session' \
docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
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
git diff --check
git add VERSION docs/rules/210-WORKFLOW.md \
docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md \
docs/templates/003-NEW_SESSION_PROMPT.md deltas/0.0.3/alpha.6.md
git diff --cached --check
git status --short
```
Scope attendu avant ajout du history : trois `REPLACE` et deux `ADD`. Revue opérateur : confirmer que le message manuel est actionnable sans supposer un rapport `PASS`, que son contrat versionné est distinct, que les prompts `002`/`003` restent historiques et que la préparation de `0.0.4` n'est pas anticipée.
## Transition
### PASS
Produire séparément `history/0.0.3/alpha.6.md` d'après la gate exécutée, l'appliquer et committer avant de passer à `beta.1` pour la réconciliation de release.
### FAIL
Enregistrer le diagnostic puis corriger uniquement cette spécification et ses renvois dans `alpha.6.fix.1`, sauf REPLAN justifié.

115
deltas/0.0.3/beta.1.md Normal file
View File

@@ -0,0 +1,115 @@
<!-- file: deltas/0.0.3/beta.1.md -->
<!-- version: 1 -->
# Delta 0.0.3-beta.1 — réconciliation documentaire
## Baseline et version
Baseline : `0.0.3-alpha.6`, avec `history/0.0.3/alpha.6.md` appliqué et committé. Ce delta MUST NOT être appliqué avant ce commit.
Version avant application :
```text
0.0.3-alpha.6
```
Version après application :
```text
0.0.3-beta.1
```
## Objet et résultat de la revue
Réconcilier la navigation, les propriétaires et les contrôles après les six tranches alpha et le fix documentaire. Les sept deltas `alpha.1` à `alpha.6`, fix inclus, ont chacun un history `PASS` fourni par la gate opérateur ; leur chaîne de versions est continue depuis `0.0.2`. La règle `210` possède le workflow ; la règle `300` possède les headers Markdown ; le profil `510` possède les conventions Rust facultatives. Les documents `docs/templates/` expliquent comment adapter les cinq fichiers Rust/Cargo et le message de reprise, tandis que les scripts restent de petits contrôles de propriétés délimitées.
La revue relève quatre corrections de documents vivants : exposer le plan actif depuis `README.md`, ouvrir la navigation directe depuis `docs/000-README.md` et décrire son template de workflow, actualiser dans le plan l'audit des headers déjà livré, et rendre dans la matrice l'audit des liens applicable à une tranche alpha qui modifie la navigation. La réconciliation n'ajoute aucune famille normative, audit, règle de version universelle, dépendance de build ou prompt `0.0.4`. Les versions et seuils du modèle Cargo restent des exemples ou choix adaptables, et les snapshots antérieurs restent intacts.
## Scope
REPLACE :
```text
VERSION
README.md
docs/000-README.md
docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
docs/validation/001-VALIDATION_MATRIX.md
```
ADD :
```text
deltas/0.0.3/beta.1.md
```
DELETE : aucun.
L'archive contient exactement ces fichiers complets. Le history de `alpha.6` est livré séparément, celui de `beta.1` n'existe pas encore ; `CHANGELOG.md`, les règles, templates techniques, scripts, tests et prompts ne sont pas modifiés.
## Validation opérateur
Après application de `history/0.0.3/alpha.6.md` et son commit, appliquer ce delta puis exécuter à la racine :
```bash
test "$(cat VERSION)" = '0.0.3-beta.1'
git cat-file -e HEAD:history/0.0.3/alpha.6.md
test -f history/0.0.3/alpha.6.md
test -f deltas/0.0.3/beta.1.md
test ! -e history/0.0.3/beta.1.md
test ! -e prompts/004-V0_0_4_START_PROMPT.md
grep -Fx '<!-- version: 5 -->' README.md
grep -Fx '<!-- version: 3 -->' docs/000-README.md
grep -Fx '<!-- version: 7 -->' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
grep -Fx '<!-- version: 9 -->' docs/validation/001-VALIDATION_MATRIX.md
python3 -B -m unittest discover -s tests -p 'test_*.py' -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 - <<'PY'
from pathlib import Path
import re
import tomllib
tranches = ['alpha.1', 'alpha.1.fix.1', 'alpha.2', 'alpha.3',
'alpha.4', 'alpha.5', 'alpha.6']
version = '0.0.2'
for name in tranches:
delta = Path(f'deltas/0.0.3/{name}.md').read_text(encoding='utf-8')
history = Path(f'history/0.0.3/{name}.md').read_text(encoding='utf-8')
assert re.search(r'## Statut\s+PASS\s', history), name
assert f'Version avant application : `{version}`.' in delta or \
f'Version avant application :\n\n```text\n{version}\n```' in delta, name
version = f'0.0.3-{name}'
assert f'Version après application : `{version}`.' in delta or \
f'Version après application :\n\n```text\n{version}\n```' in delta, name
for path in sorted(Path('templates/rust-cargo').rglob('*.toml')):
tomllib.loads(path.read_text(encoding='utf-8'))
print(f'Reconciliation audit: clean ({len(tranches)} PASS histories, 5 TOML files)')
PY
git diff --check
git add VERSION README.md docs/000-README.md \
docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md \
docs/validation/001-VALIDATION_MATRIX.md deltas/0.0.3/beta.1.md
git diff --cached --check
git status --short
```
Scope attendu avant ajout du history : cinq `REPLACE` et un `ADD` exactement comme ci-dessus. Revue opérateur : confirmer que les liens pointent vers les documents propriétaires et que les valeurs du template Cargo restent des exemples adaptables ; les gates alpha déjà observées ne sont pas réinterprétées et la RC n'est pas déclarée acquise par cette prévalidation.
## Transition
### PASS
Produire séparément `history/0.0.3/beta.1.md` avec les résultats réellement observés, l'appliquer et committer `beta.1` avant de préparer `rc.1`.
### FAIL
Enregistrer le diagnostic dans le history de `beta.1`, puis corriger la réconciliation dans `beta.1.fix.1` ou faire un REPLAN explicite si le scope a changé.

117
deltas/0.0.3/rc.1.md Normal file
View File

@@ -0,0 +1,117 @@
<!-- file: deltas/0.0.3/rc.1.md -->
<!-- version: 1 -->
# Delta 0.0.3-rc.1 — gel du scope et préparation de release
## Baseline et version
Baseline : `0.0.3-beta.1`, avec `history/0.0.3/beta.1.md` appliqué et committé. Ce delta MUST NOT être appliqué avant ce commit.
Version avant application :
```text
0.0.3-beta.1
```
Version après application :
```text
0.0.3-rc.1
```
## Objet et gel
La gate de `beta.1` est `PASS`. La RC gèle le scope fonctionnel : cinq modèles Rust/Cargo adaptables, deux audits facultatifs de style Rust, un audit de headers Markdown et une spécification du message manuel de reprise. La candidate `0.0.3` du changelog décrit ces résultats sans détailler les fixes ; le plan enregistre le gel et l'état observé de beta.
Le prompt `004` prépare le cadrage de `0.0.4` consacré aux skeleton specifications Markdown et à la composition des profils/templates. Il demande un audit de la future archive taggée `v0.0.3` et traite son rapport post-tag comme une preuve conditionnelle, jamais acquise en RC. Son message manuel doit être ajusté et remis après la publication et son contrôle réel. Aucun skeleton complet, générateur, règle normative nouvelle, audit nouveau ni projet source modifié n'appartient à `rc.1`.
## Scope
REPLACE :
```text
VERSION
CHANGELOG.md
docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
```
ADD :
```text
prompts/004-V0_0_4_START_PROMPT.md
deltas/0.0.3/rc.1.md
```
DELETE : aucun.
L'archive contient exactement ces fichiers complets. Le history `beta.1` est livré séparément ; le history `rc.1` sera produit après la gate opérateur. Les histories et deltas antérieurs, les règles, modèles techniques, scripts, tests et `ROADMAP.md` restent inchangés.
## Gate opérateur de release candidate
Après application sur le commit `beta.1`, depuis la racine du dépôt :
```bash
test "$(cat VERSION)" = '0.0.3-rc.1'
git cat-file -e HEAD:history/0.0.3/beta.1.md
test -f history/0.0.3/beta.1.md
test -f deltas/0.0.3/rc.1.md
test -f prompts/004-V0_0_4_START_PROMPT.md
test ! -e history/0.0.3/rc.1.md
grep -Fx '<!-- version: 4 -->' CHANGELOG.md
grep -Fx '## 0.0.3 (candidate)' CHANGELOG.md
grep -Fx '<!-- version: 8 -->' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
grep -F 'La gate opérateur de `beta.1` est `PASS`' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
grep -F 'pgr-0.0.3-publish.001-report.md' prompts/004-V0_0_4_START_PROMPT.md
grep -F "Si le rapport manque ou n'est pas PASS" prompts/004-V0_0_4_START_PROMPT.md
python3 -B -m unittest discover -s tests -p 'test_*.py' -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 - <<'PY'
from pathlib import Path
import re
import tomllib
names = ['alpha.1', 'alpha.1.fix.1', 'alpha.2', 'alpha.3',
'alpha.4', 'alpha.5', 'alpha.6', 'beta.1']
version = '0.0.2'
for name in names:
delta = Path(f'deltas/0.0.3/{name}.md').read_text(encoding='utf-8')
history = Path(f'history/0.0.3/{name}.md').read_text(encoding='utf-8')
assert re.search(r'## Statut\s+PASS\s', history), name
assert f'Version avant application : `{version}`.' in delta or \
f'Version avant application :\n\n```text\n{version}\n```' in delta, name
version = f'0.0.3-{name}'
assert f'Version après application : `{version}`.' in delta or \
f'Version après application :\n\n```text\n{version}\n```' in delta, name
assert {p.stem for p in Path('deltas/0.0.3').glob('*.md')} - \
{p.stem for p in Path('history/0.0.3').glob('*.md')} == {'rc.1'}
for path in Path('templates/rust-cargo').rglob('*.toml'):
tomllib.loads(path.read_text(encoding='utf-8'))
print(f'RC integration audit: clean ({len(names)} PASS histories, 5 TOML files)')
PY
git diff --check
git add VERSION CHANGELOG.md docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md \
prompts/004-V0_0_4_START_PROMPT.md deltas/0.0.3/rc.1.md
git diff --cached --check
git status --short
```
Scope attendu avant ajout du history : trois `REPLACE` et deux `ADD`. Revue opérateur : contrôler que le changelog décrit la release et non les tranches, que les exemples Cargo restent adaptables, que `004` concerne exclusivement la future `0.0.4` et que sa preuve post-tag n'est pas présumée. Une gate RC PASS n'est pas un tag ni une vérification de l'archive publiée.
## Transition
### PASS
Produire séparément `history/0.0.3/rc.1.md` d'après la gate observée, l'appliquer puis committer la RC avant la promotion stable `rel.001`.
### FAIL
Consigner les échecs dans le history RC et corriger le scope gelé dans `rc.1.fix.1` ; réviser le plan si un changement fonctionnel plus large s'impose.

116
deltas/0.0.3/rel.001.md Normal file
View File

@@ -0,0 +1,116 @@
<!-- file: deltas/0.0.3/rel.001.md -->
<!-- version: 1 -->
# Delta 0.0.3 rel.001 — promotion stable pré-tag
## Baseline et version
Baseline : `0.0.3-rc.1`, avec `history/0.0.3/rc.1.md` appliqué et committé. Ce delta MUST NOT être appliqué avant ce commit.
Version avant application :
```text
0.0.3-rc.1
```
Version après application :
```text
0.0.3
```
`rel.001` identifie la clôture opérationnelle ; il ne fait pas partie de la version SemVer du produit.
## Objet
Promouvoir la RC validée vers la stable `0.0.3`. La tranche finalise la présentation de la release, marque la roadmap terminée, retire la mention « candidate » du changelog et clôt le plan comme référence historique. Le prompt `004`, les règles, les modèles, les audits et les tests sont ceux validés en RC : aucune fonctionnalité, règle ou preuve post-tag nouvelle n'est introduite.
La validation de cette tranche est **pré-tag**. Ni le tag `v0.0.3` ni une archive téléchargée depuis Gitea ni un rapport `publish.001` ne sont déclarés existants par ce delta. Ils suivent le history PASS, le commit stable et la publication du tag.
## Scope
REPLACE :
```text
VERSION
README.md
ROADMAP.md
CHANGELOG.md
docs/000-README.md
docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
```
ADD :
```text
deltas/0.0.3/rel.001.md
```
DELETE : aucun.
L'archive contient uniquement ces fichiers complets. `history/0.0.3/rc.1.md` arrive séparément ; le history de `rel.001` sera rédigé après sa gate. Le rapport post-tag sera hors de l'archive source taggée.
## Validation opérateur pré-tag
Après application sur le commit `rc.1`, depuis la racine du dépôt :
```bash
test "$(cat VERSION)" = '0.0.3'
git cat-file -e HEAD:history/0.0.3/rc.1.md
test -f history/0.0.3/rc.1.md
test -f deltas/0.0.3/rel.001.md
test -f prompts/004-V0_0_4_START_PROMPT.md
test ! -e history/0.0.3/rel.001.md
grep -Fx '<!-- version: 6 -->' README.md
grep -Fx '<!-- version: 4 -->' ROADMAP.md
grep -Fx '<!-- version: 5 -->' CHANGELOG.md
grep -Fx '<!-- version: 4 -->' docs/000-README.md
grep -Fx '<!-- version: 9 -->' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
grep -F 'La release `0.0.3` fournit les premiers modèles Rust/Cargo' README.md
grep -F 'plan historique des templates et audits `0.0.3`' README.md
grep -F -- '- `(x) 0.0.3`' ROADMAP.md
grep -Fx '## 0.0.3' CHANGELOG.md
grep -F 'La gate opérateur de `rc.1` est `PASS`' docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
grep -F "La vérification de l'archive" docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
python3 -B - <<'PY'
from pathlib import Path
import re
names = ['alpha.1', 'alpha.1.fix.1', 'alpha.2', 'alpha.3',
'alpha.4', 'alpha.5', 'alpha.6', 'beta.1', 'rc.1']
for name in names:
history = Path(f'history/0.0.3/{name}.md')
assert Path(f'deltas/0.0.3/{name}.md').is_file(), name
assert re.search(r'## Statut\s+PASS\s', history.read_text(encoding='utf-8')), name
assert {p.stem for p in Path('deltas/0.0.3').glob('*.md')} - \
{p.stem for p in Path('history/0.0.3').glob('*.md')} == {'rel.001'}
print(f'Stable history audit: clean ({len(names)} PASS histories, rel.001 pending)')
PY
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
git diff --check
git add VERSION README.md ROADMAP.md CHANGELOG.md docs/000-README.md \
docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md deltas/0.0.3/rel.001.md
git diff --cached --check
git status --short
```
Scope attendu avant ajout du history : six `REPLACE` et un `ADD` exactement comme ci-dessus. Revue opérateur : confirmer que le scope RC ne change pas, que la présentation du dépôt, le changelog et la roadmap décrivent la même stable, que le prompt `004` reste conditionnel au rapport post-tag et que les snapshots historiques restent intacts. Les `15` tests et les cinq TOML validés en RC restent des preuves utilisables parce qu'aucun code, script, test ou template n'a changé dans cette promotion.
## Transition
### PASS
Rédiger et livrer séparément `history/0.0.3/rel.001.md` avec le résultat réellement observé ; l'appliquer et committer la stable. Ensuite seulement, créer et publier le tag canonique `v0.0.3`, télécharger son archive source depuis Gitea, vérifier cette archive et conserver séparément la preuve post-tag `publish.001`. Le texte manuel du prompt `004` n'est remis à l'opérateur qu'après vérification de l'archive et d'un rapport post-tag PASS réel.
### FAIL
Consigner le diagnostic dans le history de `rel.001`, ne pas tagger, puis corriger la clôture dans une tranche explicite avant publication.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/000-README.md --> <!-- file: docs/000-README.md -->
<!-- version: 1 --> <!-- version: 4 -->
# Documentation PGR # Documentation PGR
@@ -11,8 +11,16 @@ Ce fichier est l'index d'entrée de la documentation structurée de Project Gove
- [`architecture/`](architecture/) — état architectural courant de PGR et profils applicables ; - [`architecture/`](architecture/) — état architectural courant de PGR et profils applicables ;
- [`plans/`](plans/) — plans vivants des releases en cours, puis références historiques après fermeture ; - [`plans/`](plans/) — plans vivants des releases en cours, puis références historiques après fermeture ;
- [`rules/`](rules/) — règles normatives détaillées, organisées progressivement par scope ; - [`rules/`](rules/) — règles normatives détaillées, organisées progressivement par scope ;
- [`templates/`](templates/) — instructions d'adaptation des templates techniques et spécification du message manuel de reprise ;
- [`validation/`](validation/) — matrices de validation et contrats de preuve. - [`validation/`](validation/) — matrices de validation et contrats de preuve.
D'autres collections telles que `ideas/`, `studies/`, `reference/`, `formats/` ou `templates/` ne sont créées que lorsqu'un premier artefact réel les justifie. D'autres collections telles que `ideas/`, `studies/`, `reference/` ou `formats/` ne sont créées que lorsqu'un premier artefact réel les justifie.
Les répertoires workflow de racine (`deltas/`, `history/`, `handoffs/`, `manifests/`, `prompts/`, `scripts/`) restent séparés de `docs/` parce qu'ils portent le processus de développement et de livraison lui-même. Les templates techniques copiables sous `templates/` restent séparés des instructions documentaires sous `docs/templates/`. Les répertoires workflow de racine (`deltas/`, `history/`, `handoffs/`, `manifests/`, `prompts/`, `scripts/`) restent séparés de `docs/` parce qu'ils portent le processus de développement et de livraison lui-même.
## Points d'entrée de 0.0.3
- [`plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md`](plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md) — périmètre et décisions de la release `0.0.3` ;
- [`templates/001-RUST_CARGO_TOOLING.md`](templates/001-RUST_CARGO_TOOLING.md) et [`templates/002-CARGO_MANIFESTS.md`](templates/002-CARGO_MANIFESTS.md) — adaptation des cinq fichiers Rust/Cargo copiables ;
- [`templates/003-NEW_SESSION_PROMPT.md`](templates/003-NEW_SESSION_PROMPT.md) — spécification du message manuel après une stable publiée ;
- [`validation/001-VALIDATION_MATRIX.md`](validation/001-VALIDATION_MATRIX.md) et [`validation/002-RUST_STYLE_AUDITS.md`](validation/002-RUST_STYLE_AUDITS.md) — gates PGR et limites des audits de style Rust facultatifs.

View File

@@ -0,0 +1,203 @@
<!-- file: docs/architecture/003-RULE_PROFILE_MODEL.md -->
<!-- version: 2 -->
# Modèle de profils de règles PGR
## Rôle
Un profil PGR est un ensemble cohérent de règles réutilisables dont le scope est plus spécifique que les règles générales.
Un profil ne constitue ni un catalogue de dépendances, ni un template technique, ni un skeleton de projet. Il définit uniquement les règles durables réellement propres à un langage, un écosystème, une plateforme, un framework, un type de projet ou un sous-système.
Les règles générales restent héritées implicitement. Elles ne sont pas recopiées dans chaque profil.
## Axes de spécialisation
La composition normative suit l'ordre général :
```text
GENERAL
↓
ecosystem / language
↓
platform
↓
framework
↓
project type / subsystem
↓
project-specific
↓
explicit exception
```
Cet ordre exprime la spécificité des scopes. Il ne signifie pas qu'un projet doit posséder un profil à chaque niveau.
Un projet peut par exemple combiner uniquement :
```text
GENERAL
+ Rust / Cargo
```
ou :
```text
GENERAL
+ Java
+ Gradle
+ Android
```
Une technologie absente du projet ne rend aucun profil correspondant applicable.
## Propriétaire normatif
Toute règle durable doit posséder un seul propriétaire normatif canonique.
Lorsqu'une règle est déjà correctement possédée par un document général, un profil spécifique doit la référencer si nécessaire, mais ne doit pas la recopier sous une formulation équivalente.
Inversement, une contrainte réellement propre à un profil ne doit pas être remontée vers un owner général uniquement pour réduire le nombre de fichiers.
Le propriétaire est choisi selon le scope le plus général dans lequel la règle reste vraie sans exception implicite.
## Applicabilité
Un profil doit rendre son scope explicite : l'utilisateur ou le skeleton futur doit pouvoir déterminer à partir de faits du projet si le profil s'applique.
L'applicabilité doit reposer sur des propriétés concrètes, par exemple :
- langage ou écosystème réellement utilisé ;
- build tool réellement utilisé ;
- plateforme réellement ciblée ;
- framework réellement présent ;
- type de projet ou sous-système réellement concerné.
PGR ne doit pas appliquer un profil uniquement parce qu'il est fréquent, recommandé ailleurs ou présent dans un projet source historique.
## Composition et résolution
La résolution d'un ensemble de profils suit ces étapes :
1. appliquer les règles générales ;
2. ajouter les profils langage/écosystème applicables ;
3. ajouter les profils plateforme applicables ;
4. ajouter les profils framework applicables ;
5. ajouter les profils de type de projet ou sous-système applicables ;
6. appliquer les règles propres au projet ;
7. appliquer les exceptions explicites et bornées.
Une règle plus spécifique peut raffiner, renforcer ou remplacer une règle plus générale dans son scope.
Lorsqu'elle contredit volontairement une règle héritée, le profil spécifique doit identifier l'override, son scope et sa raison. L'ordre des fichiers dans un répertoire ne crée jamais une priorité normative.
Deux règles applicables de même niveau qui se contredisent sans relation explicite ne sont pas départagées arbitrairement : la situation constitue un défaut de conformité ou de modélisation à résoudre.
## Spécialisation interne à une famille
Une famille peut posséder plusieurs niveaux internes lorsque cela réduit la duplication.
Par exemple, un profil de langage peut être complété par un build tool particulier :
```text
Java
↓
Maven
```
ou :
```text
Java
↓
Gradle
```
Cette relation interne ne modifie pas la hiérarchie globale. Une contrainte de plateforme plus spécifique peut encore raffiner le résultat lorsqu'elle s'applique.
Lorsque langage et build tool sont pratiquement indissociables pour le scope visé, PGR peut les documenter dans un même profil si cette fusion évite une séparation artificielle. Le choix du découpage doit suivre les responsabilités réelles, pas une taxonomie rigide.
## Profils composites
PGR ne crée pas automatiquement un profil composite pour chaque combinaison possible.
Un profil composite n'est justifié que lorsque l'intersection de plusieurs profils possède des règles propres qui ne peuvent être correctement possédées par chacun séparément.
Ainsi, la simple coexistence de Rust et Android ne suffit pas à créer un profil `Rust + Android`. Un tel profil devient pertinent seulement lorsqu'un contrat propre à leur interaction, par exemple une frontière FFI/JNI, doit être normé.
## Choix ouverts
Un choix encore indécis n'est pas une règle.
Lorsqu'un profil révèle plusieurs options légitimes sans critère permettant d'en retenir une, PGR doit conserver la question comme décision ouverte, étude ou point de planification approprié plutôt que d'inventer une valeur par défaut arbitraire.
Une contrainte issue d'un framework, d'une plateforme ou d'un outil externe peut devenir une règle spécifique lorsque son caractère obligatoire est établi.
## Non-duplication
Un profil doit contenir uniquement ce qui ajoute une information normative dans son scope.
Il ne doit pas recopier les règles générales relatives notamment à la gouvernance, aux documents, aux secrets, au lifecycle des releases ou à la validation lorsque ces règles s'appliquent déjà sans modification.
Une règle transversale découverte pendant la création de plusieurs profils doit être remontée vers un propriétaire commun uniquement si elle est réellement indépendante de ces profils.
## Croissance documentaire
PGR matérialise uniquement les familles et profils possédant un contenu normatif réel.
Pour `0.0.2`, les familles nécessaires sont :
```text
500 — languages / ecosystems
600 — platforms
```
Les familles `700 — frameworks` et `800 — architecture` restent réservées tant qu'un premier profil réel ne justifie pas leur activation normative.
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éé.
Le projet instancié restera autonome : la composition de profils sert à construire sa baseline initiale, pas à créer une dépendance dynamique vers PGR.

View File

@@ -0,0 +1,243 @@
<!-- file: docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md -->
<!-- version: 6 -->
# Plan 0.0.2 — premiers profils de règles technologiques
## Statut
Plan clôturé par la promotion stable `0.0.2` après validation de `0.0.2-rc.1.fix.1`.
La baseline `v0.0.1` est cohérente pour démarrer `0.0.2`. L'absence de `.git` dans cette archive est normale et n'est pas une anomalie de baseline.
Le présent plan reste prévisionnel. Il peut être révisé lorsqu'un résultat réel invalide son dimensionnement ou son découpage, conformément aux règles de REPLAN.
## Mission
`0.0.2` introduit les premiers profils de règles technologiques réutilisables de PGR sans dupliquer les responsabilités déjà possédées par `RULES.md` et les familles `200`, `300` et `400`.
La release doit démontrer concrètement la composition :
```text
GENERAL
↓
ecosystem / language
↓
platform
↓
framework
↓
project type / subsystem
↓
project-specific / explicit exception
```
Un profil matérialisé doit posséder un contenu normatif réel, un scope explicite et un propriétaire documentaire identifiable. Il ne doit pas devenir un catalogue de dépendances ni répéter les règles générales sous une autre forme.
## Autorité des sources pendant la consolidation
Pour cette release :
- l'archive source issue du tag `v0.0.1` est la baseline autoritaire de l'état PGR ;
- `prompts/002-V0_0_2_START_PROMPT.md` est le contrat opératoire de démarrage de `0.0.2` ;
- les corpus de conception externes ou historiques peuvent servir de matière d'analyse, mais ne constituent pas l'état courant du dépôt ;
- aucune règle, décision, version de fichier ou structure absente de la baseline et du prompt ne doit être supposée déjà acquise ;
- chaque proposition réutilisée doit être requalifiée selon les règles PGR actuelles avant de devenir normative.
## Audit de la baseline `v0.0.1`
L'inspection de l'archive taggée a constaté :
- une racine unique `pgr/` ;
- `44` fichiers et `13` répertoires dans l'archive, sans entrée dupliquée ;
- aucune entrée absolue, traversée `..` ou symlink ;
- aucune arborescence `.git`, conformément au contrat des archives de tag ;
- `VERSION` égal exactement à `0.0.1` ;
- aucun cache/build connu, `__pycache__`, `.pyc`, `node_modules`, `target`, `dist` ou secret local distribué ;
- tous les fichiers Markdown avec headers `file/version` cohérents avec leur emplacement ;
- aucun lien Markdown local cassé parmi les liens vérifiés ;
- `12` deltas `0.0.1` et `12` histories correspondants, sans delta ou history orphelin ;
- une chaîne de résultats cohérente : les `FAIL` de `alpha.1`, `alpha.1.fix.1`, `alpha.4` et `rc.1` restent historiques et sont suivis par leurs corrections validées avant progression ;
- la promotion `rel.001` enregistrée `PASS`, le plan `0.0.1` clôturé et le prompt `0.0.2` présent ;
- les compteurs internes `version:` des documents vivants cohérents avec les opérations `ADD`/`REPLACE` observées dans les deltas `0.0.1`.
Aucun défaut bloquant de gouvernance, de structure documentaire, de pairing delta/history ou de cohérence interne n'a été trouvé.
### Preuve post-tag `publish.001`
Le rapport post-tag `pgr-0.0.1-publish.001-report.md` a été retrouvé dans la bibliothèque de travail après la première revue de `alpha.1`.
Il enregistre `Status: PASS` pour `pgr-v0.0.1.zip` et confirme le SHA-256 déjà observé pour l'archive de baseline :
```text
48bfed6acc50d2c5bdd69db764ae29fe8c5a06b64375943f5d4120c7bb8429ef
```
Cette preuve est volontairement extérieure au tag `v0.0.1` parce qu'elle vérifie un artefact produit après le tag. Elle ne doit ni être injectée rétroactivement dans la stable ni remplacer l'audit d'intake de la session courante.
La revue a également identifié un besoin de maturité futur : un handoff/prompt de reprise doit finir par indiquer explicitement si une preuve post-publication telle que `publish.001` doit être fournie à la session suivante. Ce besoin de workflow reste hors scope fonctionnel de `0.0.2`.
## Inventaire des profils candidats
Le prompt demande d'examiner le corpus suivant. Après revue du sizing initial, `0.0.2-alpha.1.fix.1` réduit volontairement le nombre de profils matérialisés afin de conserver une version terminable et correctement validable dans une session.
| Domaine candidat | Décision `0.0.2` | Propriétaire prévisionnel | Motif |
|------------------------------------------------|------------------|------------------------------------------------|------------------------------------------------------------------------------|
| modèle de profil et composition des scopes | inclure | architecture PGR | nécessaire avant de créer plusieurs profils cohérents |
| Rust / Cargo | inclure | famille `500 — languages / ecosystems` | premier profil langage/écosystème, corpus éprouvé |
| Java / Maven / Gradle | inclure | famille `500 — languages / ecosystems` + build | permet de distinguer langage et build tool avant Android |
| Android | inclure | famille `600 — platforms` | premier exemple de spécialisation plateforme sur des règles de langage/build |
| Rust + Android / JNI | différer | future composition spécialisée | utile mais non nécessaire pour prouver le premier modèle |
| Web / TypeScript / Vite / WASM / serveurs Rust | différer | future composition Web | scope autonome suffisamment large pour une release ultérieure |
| Tauri desktop/mobile | différer | future famille `700 — frameworks` | dépend de profils Rust/Web/plateforme suffisamment stabilisés |
| C / C++ / CMake | différer | future famille `500 — languages / ecosystems` | corpus utile mais non nécessaire au premier lot |
| PHP / Composer | différer | future famille `500 — languages / ecosystems` | ne pas matérialiser un profil uniquement pour remplir la taxonomie |
| Python 3 application/package | différer | future famille `500 — languages / ecosystems` | à introduire lorsqu'un besoin concret le justifie |
| architecture/règles cross-cutting | conditionnel | famille `800 — architecture` ou owner existant | uniquement si plusieurs profils révèlent une règle commune sans propriétaire |
Les domaines différés restent des candidats légitimes. Leur absence de `0.0.2` ne vaut ni rejet ni interdiction future.
Le choix retenu cherche le plus petit ensemble qui exerce réellement plusieurs niveaux de composition : un modèle commun, un profil langage/écosystème, une distinction langage/build et une plateforme. Les compositions FFI, Web et framework restent séparées afin de ne pas transformer la première release de profils en catalogue.
## Règles de consolidation
Chaque tranche technologique doit :
1. repartir des règles générales actuellement applicables ;
2. identifier ce qui est réellement spécifique au profil ;
3. éviter les duplications de gouvernance, documentation et validation générales ;
4. distinguer règle normative, exemple, choix de projet et point encore ouvert ;
5. documenter explicitement les overrides/contraintes spécialisées et leur scope ;
6. préférer les structures canoniques de l'écosystème lorsqu'elles apportent une vraie valeur ;
7. ne pas fixer une version d'outil ou de dépendance sans raison de compatibilité, reproductibilité, support ou sécurité ;
8. ne créer un audit que lorsqu'une propriété stable, objectivement automatisable et réellement utile a été démontrée ;
9. conserver PGR lui-même indépendant des toolchains qu'il documente ;
10. réviser le plan si une tranche devient sensiblement plus large que prévu au lieu d'absorber silencieusement le scope.
## Découpage prévisionnel
### alpha.1 — Baseline audit and profile sizing
Auditer intégralement `v0.0.1`, confronter le prompt à l'état réel, inventorier les profils candidats, fixer les domaines inclus/différés et créer le présent plan.
Aucune règle technologique détaillée n'est consolidée dans cette tranche.
### alpha.2 — Rule profile model
Formaliser le contrat d'un profil PGR : ownership, composition général → spécifique, navigation des familles nécessaires, règles de non-duplication et traitement des choix encore ouverts.
Cette tranche doit créer uniquement les propriétaires documentaires réellement nécessaires à `0.0.2`. Les familles `700` et `800` restent réservées tant qu'aucun contenu réel ne justifie leur matérialisation.
### alpha.3 — Rust / Cargo
Consolider le premier profil langage/écosystème Rust/Cargo, notamment structure de workspace/crates, manifests et toolchain, dépendances/features, API/imports, erreurs/safety, tests et validation spécialisée lorsque ces sujets ne sont pas déjà possédés par une règle générale.
Cette tranche sert aussi de mesure réelle du coût d'un profil. Si elle montre que le modèle documentaire est sensiblement plus lourd que prévu, un REPLAN doit intervenir avant d'enchaîner les autres profils.
### alpha.4 — Java / Maven / Gradle
Consolider le profil Java et ses spécialisations de build Maven/Gradle en maintenant une frontière nette entre règles Java, contraintes de build tool et choix propres à une plateforme ou un framework.
### alpha.5 — Android
Consolider le premier profil plateforme Android : structure canonique, toolchain compatible, SDK/targets, configuration locale/signing, modules, packaging, tests/smokes et règles de compatibilité de target.
Les règles Rust/JNI, Web et Tauri ne doivent pas être absorbées dans ce profil général. Elles restent différées jusqu'à une release où leurs compositions pourront être traitées sans surcharger `0.0.2`.
### beta.1 — Profile reconciliation
Réconcilier les profils créés, vérifier les scopes/overrides, éliminer les répétitions, vérifier la navigation et extraire vers un owner cross-cutting uniquement les règles réellement communes qui ne possèdent pas déjà de propriétaire normatif.
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
beta.1 FAIL quoting Bash invalide dans une commande de gate
beta.1.fix.1 PASS quoting de gate corrigé sans changement de scope
```
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.
Le scope RC est gelé sur les trois profils matérialisés (`510`, `520`, `610`) et les deux audits génériques monotâches (`tables`, `liens locaux`). Aucun nouveau profil, owner de famille ou audit technologique n'est admis sans correction strictement nécessaire ou REPLAN.
Le prompt `0.0.3` doit aussi fournir explicitement le texte manuel de nouvelle session et indiquer le rôle du futur rapport post-tag `publish.001`, afin que cette information ne dépende plus d'une demande ad hoc de l'opérateur.
### stable — 0.0.2
Promouvoir mécaniquement la RC validée, finaliser les métadonnées de release, enregistrer `rel.001`, commit/tag `v0.0.2`, puis vérifier séparément l'archive publiée issue du tag.
## Clôture
La release candidate `rc.1` a été enregistrée `FAIL` à cause d'un audit Python inline invalide dans sa gate. `rc.1.fix.1` a corrigé exclusivement cette commande et a ensuite été validée `PASS`, sans changement du scope fonctionnel ou normatif.
La promotion stable `rel.001` clôt le plan en mettant à jour uniquement les métadonnées vivantes de release et en préparant le tag `v0.0.2`.
Le contrôle post-tag `publish.001` reste une preuve séparée : il doit vérifier l'archive réellement produite depuis le tag et fournir `pgr-0.0.2-publish.001-report.md` à la future session `0.0.3` lorsqu'il est `PASS`.
## Dimensionnement et points de replan
Le premier forecast `alpha.2` à `alpha.8` a été jugé trop large pendant la revue opérateur de `alpha.1`. Le présent plan réduit donc la release avant tout développement technologique lourd.
Après `alpha.1.fix.1`, le chemin prévu est :
```text
alpha.2 modèle de profil
alpha.3 Rust / Cargo
alpha.4 Java / Maven / Gradle
alpha.5 Android
beta.1 réconciliation
rc.1 release candidate
stable 0.0.2
```
Ce découpage reste un forecast, pas une obligation de remplir tous les numéros coûte que coûte.
`alpha.3` est un point de mesure explicite. Si la construction du premier profil montre qu'un profil complet dépasse sensiblement le sizing envisagé, la release doit être REPLANifiée avant `alpha.4` au lieu de conserver mécaniquement le forecast.
Un nouveau besoin critique, plusieurs fixes consécutifs ou une évolution qui rend `0.0.2` non terminable dans la session doivent également déclencher un REPLAN. La qualité de la release prend le dessus sur la volonté de conserver artificiellement le nombre initial de profils.
## Hors périmètre
`0.0.2` ne doit pas :
- produire les templates techniques réservés à `0.0.3` ;
- 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 ; `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.
## Critères de fermeture
`0.0.2` peut atteindre RC lorsque :
- le modèle documentaire des profils est explicite et cohérent avec la hiérarchie PGR ;
- les profils retenus dans le scope possèdent chacun un propriétaire normatif réel ;
- les spécialisations de build et de plateforme retenues ne contaminent pas les règles générales ;
- les choix encore ouverts restent identifiés comme tels ;
- la navigation entre règles générales et profils spécifiques est claire ;
- aucune duplication importante avec les familles `200`, `300` et `400` ne subsiste ;
- les profils différés ne sont pas artificiellement matérialisés ;
- les validations de la release restent documentaires et proportionnées au dépôt PGR lui-même.

View File

@@ -0,0 +1,159 @@
<!-- file: docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md -->
<!-- version: 9 -->
# Plan 0.0.3 — templates initiaux et audits réutilisables
## Statut et sources
Plan de cadrage créé dans `0.0.3-alpha.1` et corrigé dans `0.0.3-alpha.1.fix.1` après sa validation mécanique. `alpha.2` intègre la convention opérateur sur les fichiers d'outillage Rust et matérialise les premiers templates ; sa gate opérateur est PASS. Après cette gate, la demande de décomposer les audits de style Rust KSP/Games modifie le calendrier prévisionnel. Le résultat REPLAN de `alpha.3` est `SPLIT` : deux audits de style ciblés sont traités d'abord, les manifests Cargo puis les headers Markdown suivent dans des tranches distinctes. Les tranches suivantes restent une prévision, non un état validé.
La source autoritaire est l'archive Gitea fournie `pgr-v0.0.2.zip`, issue selon l'opérateur du tag `v0.0.2`. Son SHA-256 vérifié localement est :
```text
8dc5c979a4d722b4ef6ec84b6227c8cbfffb3f865f4ea9063c03ecb1e365cdc4
```
Le rapport séparé `pgr-0.0.2-publish.001-report.md` indique `PASS` et donne le même hash. Il atteste la publication post-tag sans appartenir au tag. L'archive sans `.git` ne peut prouver indépendamment le commit ni l'identité du tag ; ces éléments sont les déclarations et preuves de publication de l'opérateur.
Le contrat de démarrage est `prompts/003-V0_0_3_START_PROMPT.md`. Les règles applicables partent de `RULES.md`, puis des familles `200`, `210`, `300`, `400`, du modèle de profils `003` et des profils `500`/`510`, `520`, `600`/`610` selon leur scope. PGR reste un dépôt documentaire doté d'outils Python ; les toolchains Rust, Java et Android ne deviennent pas des prérequis du dépôt.
Deux corpus de comparaison supplémentaires, fournis après le gate initial de `alpha.1`, ont été inspectés pour ce fix documentaire :
```text
khadhroony-solana-project-v0.3.16.zip SHA-256 db3cc1b3fc3fb07ee864b02e2a7346c673d4cf63b33e8e872aca6c6458856ca0
games-v0.3.5.zip SHA-256 5f5fdee1a271386766d059657d6eaa831acdc263b3e722fed738808335c0a105
```
Ce sont des sources de comparaison pour les décisions de templates et d'audits, non la baseline PGR et non des dépendances de build. Leur présence ne rend pas les conventions locales de KSP ou Games normatives pour tous les projets.
## Audit indépendant de la stable `v0.0.2`
L'inspection de l'archive, sa lecture et la comparaison des fichiers extraits avec les membres ZIP ont établi :
- ZIP lisible, `94` entrées : `78` fichiers et `16` répertoires, une seule racine `pgr/` ; aucun doublon, chemin absolu, traversée `..`, chemin Windows ambigu ou lien symbolique ;
- exactement `78` fichiers extraits ; `VERSION` contient `0.0.2` avec un seul retour final à la ligne ; `.git` absent comme attendu ;
- octets des fichiers distribués décodables en UTF-8, sans NUL, CR, espace de fin de ligne ou retour final manquant ;
- `73` fichiers Markdown dont les deux premières lignes correspondent exactement au chemin relatif `file` et à une révision positive `version` ;
- contrôle local des deux scripts existants : `Markdown table audit: clean (2 table(s), 73 file(s))` et `Markdown link audit: clean (50 local link(s), 73 file(s))` ;
- aucun répertoire de build/cache ou fichier local sensible connu dans les chemins distribués ; seule la préférence Eclipse UTF-8 intentionnellement conservée est présente sous `.settings/`.
La vérification de structure et de gouvernance a constaté :
- `12` deltas et `12` histories appariés exactement dans chacune des séries `0.0.1` et `0.0.2`, y compris `rel.001` ; chaque history possède un statut explicite ;
- les versions `avant`/`après` déclarées dans tous les deltas `0.0.2` forment une chaîne continue de `0.0.1` à `0.0.2` ; les deltas `0.0.1` au format homogène depuis `alpha.1.fix.2` forment également une chaîne continue jusqu'à la stable ;
- dans `0.0.1`, les `FAIL` de `alpha.1`, `alpha.1.fix.1`, `alpha.4` et `rc.1` sont suivis d'une tranche corrective `PASS` ; dans `0.0.2`, même traitement pour `alpha.1`, `alpha.4`, `beta.1` et `rc.1` ; les deux `rel.001` sont `PASS` ;
- `README.md`, `ROADMAP.md` et `CHANGELOG.md` présentent `0.0.2` comme terminé et `0.0.3` comme prévu ; les plans `001` et `002` restent historiques ; le prompt `003` nomme l'archive et la preuve post-tag fournies ;
- séparation cohérente entre objectifs durables, architecture, règles normatives, validation, plans, deltas prospectifs, histories rétrospectifs et changelog stable ; les index pointent vers les familles et profils réellement présents ;
- les profils réellement matérialisés sont `510` Rust/Cargo, `520` Java/Maven/Gradle et `610` Android ; les seuls scripts d'audit PGR sont ceux des tableaux et des liens Markdown locaux. Aucun skeleton, générateur ou profil différé n'est présent.
Aucun écart bloquant n'a été constaté dans ces contrôles. Les scripts Markdown ont chacun une portée volontairement limitée : le contrôle des liens vérifie l'existence des cibles inline locales, pas les ancres ; celui des tableaux vérifie leur structure source. Leur PASS n'atteste donc pas des propriétés hors de leur contrat.
## Comparaison réelle des corpus Rust
KSP `0.3.16` et Games `0.3.5` possèdent chacun un workspace Cargo virtuel avec `resolver = "3"` et centralisent réellement dans `[workspace.package]` `version`, `edition`, `license`, `repository`, `authors` et `publish`. Ils utilisent `[workspace.dependencies]` pour des dépendances tierces, mais avec respectivement `37` et `19` entrées propres à leur projet. Les deux racines déclarent les mêmes trois lints Rust de base (`missing_docs`, `unreachable_pub`, `unsafe_code`) et les mêmes `18` niveaux Clippy ; les éventuels `allow` doivent être revus un par un avant réemploi.
Les `22` crates KSP héritent des lints workspace par `[lints] workspace = true`. Parmi `23` crates Games, `22` utilisent ce même héritage ; l'entrée Android déclare des lints locaux pour ajuster `unsafe_code` à sa frontière FFI. La capacité d'exception locale est donc réelle et doit être expliquée sans rendre l'exception Android générale.
Les deux `rustfmt.toml` ont un contenu technique identique et seulement un numéro de révision de fichier différent. Les deux `clippy.toml` partagent leurs seuils principaux et divergent sur les identifiants courts autorisés et quelques entrées vides. L'opérateur confirme qu'il réutilise ces conventions comme baseline de départ, telles quelles ou avec de petites adaptations. Les deux `.cargo/config.toml` déplacent les artefacts de build vers `../builds/<projet>/target/` ; Games ajoute des flags Web propres à sa cible. La configuration générique de déplacement est donc retenue avec un nom de projet à remplacer.
## Sélection des templates
### Retenu : famille Rust/Cargo minimale
Le besoin concret n'est pas limité à `rustfmt.toml`. La première famille doit couvrir cinq responsabilités distinctes :
1. `rustfmt.toml` : options communes dont la valeur est justifiée ; alignement de `edition` avec le projet destinataire ; ne pas reprendre mécaniquement chaque préférence des deux sources ;
2. configuration Clippy : niveaux de lint Rust/Clippy dans les sections Cargo `[workspace.lints.rust]` et `[workspace.lints.clippy]`, plus `clippy.toml` pour les seuils et réglages conservés dans le profil de départ éprouvé ; chaque projet peut adapter ces choix ;
3. `.cargo/config.toml` : `target-dir` et `build-dir` vers un dossier frère `../builds/<projet>/target/`, après remplacement explicite du nom ; les flags Web et les autres particularités restent locaux ;
4. `Cargo.toml` workspace : sections `[workspace]`, `[workspace.package]`, `[workspace.dependencies]` et `[workspace.lints.*]` avec les responsabilités et champs de décision explicités ; `VERSION` doit correspondre à `workspace.package.version` seulement pour une unité de release commune ;
5. `Cargo.toml` d'une crate membre ordinaire : identité locale, héritage explicite des métadonnées communes et des lints, et dépendances/features limitées aux besoins de la crate. Une adaptation locale des lints doit être documentée comme exception ciblée ; elle ne devient pas un deuxième jeu de valeurs globales.
Ces fichiers ou extraits doivent être copiables et compréhensibles sans figer le nom de projet, la version, les dépendances, le layout de toutes les crates, la publication, la toolchain ni le minimum de plateforme. Lorsqu'un champ obligatoire ne peut pas avoir de valeur générique sûre, des instructions Markdown guident son remplacement avant l'usage ; un fichier TOML présenté comme prêt à l'emploi doit être valide. Les crates bibliothèque et application peuvent partager un tronc commun, leurs différences réelles restant documentées sans créer des dizaines de variantes.
Pour la validation, comparer les templates au profil `510`, parser les configs/manifests avec un parseur TOML et exercer sur un workspace d'essai les héritages et le cas d'une exception locale quand les toolchains sont disponibles. Tester `rustfmt` et Clippy pour les réglages réellement livrés dans un projet Rust concerné ; une compilation de KSP/Games n'est pas une gate de PGR.
### Retenu : spécification courte du prompt manuel de nouvelle session
Les prompts `002` et `003` répètent la transmission de la baseline taggée, de la cible et de la première tranche ; `003` ajoute le rapport post-tag et le texte manuel remis à l'opérateur. Après comparaison, `alpha.6` retient une courte spécification Markdown des champs et de la phrase de reprise. Elle facilite la prochaine clôture sans créer un générateur, un nouveau prompt versionné prématuré ou une copie du plan. Le rapport ne devient un champ rempli que s'il existe et que son résultat est réellement connu.
### Différés
Les fichiers Maven/Gradle complets, wrappers, Android `local.properties` ou signing, règles `.gitignore` universelles et versions de dépendances ne sont pas copiés par anticipation. Games fournit un exemple Android concret, mais sa matrice AGP/Gradle/JDK, son build natif et ses flags Cargo Web restent propres à ce projet. Les wrappers restent soumis aux outils officiels et à la décision du projet ; un `local.properties` entièrement régénéré ne justifie pas d'exemple.
Les spécifications complètes de skeleton restent réservées à `0.0.4` ; Rust/JNI, Web/WASM, Tauri et les autres profils différés n'entrent pas dans cette release par simple proximité technologique.
## Sélection des audits et patterns
Les trois audits Markdown (`headers`, `tables`, `liens locaux`) restent séparés : une propriété chacun, sélection explicite des chemins et lecture seule. L'audit des headers, livré en `alpha.5`, applique le contrat de `docs/rules/300-DOCUMENTATION.md` avec des cas positifs et négatifs ciblés ; il ne juge ni le rôle du document ni la pertinence de l'incrément de sa révision.
La comparaison des scripts Python KSP `0.3.16` et Games `0.3.5` montre que `audit_rust_general_rules.py` (~580 lignes dans chaque corpus) mélange headers et versions Rust, imports, rustdoc, structure des items, blancs, constantes et modules. `audit_rust_export_completeness.py` possède le contrat particulier des façades et réexports ; KSP ajoute `audit_ksp_workspace_rules.py` pour manifests/frontières/tracing, tandis que Games regroupe plusieurs intégrations Web/Android/Gradle dans `audit_distribution_layout.py`. `audit_rust_workspace_rules.py` est un orchestrateur ; il peut rester un lanceur sans devenir propriétaire de ces contrats.
| Propriété | Owner | Suite |
|------------------------------------------|-------------------------|----------------------------------------|
| Ordre interne des `use` et `mod` | Rustfmt | `cargo fmt --all -- --check` |
| Diagnostics du langage et des lints | Rust/Clippy | Outils officiels du projet |
| Espacement des lignes vides | Profil `510` facultatif | `audit_rust_blank_lines.py` |
| Blocs de constantes racine | Profil `510` facultatif | `audit_rust_const_blocks.py` |
| Headers, rustdoc, API, tests, plateforme | Profils locaux | Audits séparés uniquement si justifiés |
Le balayage préalable des vrais sources `crates/**/src/**/*.rs` donne `300` fichiers KSP et `59` Games. Le contrôle des blancs passe les deux corpus. Un tri naïf de toutes les constantes racine trouve `17` signaux dans KSP et zéro dans Games ; plusieurs listes KSP sont ordonnées par contrat de protocole ou de schéma. Cela interdit de déclarer le tri globalement obligatoire ou de corriger ces fichiers sans revue. Les scripts livrés sont des patrons facultatifs : le propriétaire d'un projet choisit le sous-ensemble de sources concerné, applique `cargo fmt` avant ces audits et conserve l'ordre sémantique là où il existe. Un petit helper lexical partagé masque commentaires et littéraux ; il n'est pas un troisième audit ni un parseur Rust exhaustif. Les limites et le mode d'emploi sont dans `docs/validation/002-RUST_STYLE_AUDITS.md`.
Les autres candidats demeurent conditionnels : miroir `VERSION`/`workspace.package.version` si une release unit est partagée, héritage explicite des lints dans les crates et façade publique seulement lorsqu'un projet possède ce contrat. Aucun audit spécialisé de ces domaines ni de layout Android/Web n'est justifié par le dépôt documentaire PGR lui-même.
## Trajectoire prévisionnelle
### alpha.1 — intake et dimensionnement
Enregistrer l'audit de la stable, confronter le prompt au dépôt réel, inventorier les candidats, fixer le scope et produire le présent plan ainsi que le delta. Aucune matérialisation technique importante. Attendre la validation opérateur, le history distinct et le commit avant tout delta suivant.
### alpha.1.fix.1 — correction documentaire du plan
Après le history et le commit de `alpha.1`, documenter la comparaison réelle de KSP/Games, élargir les templates Rust à Cargo et Clippy et redimensionner les tranches. Aucun template ou audit nouveau dans ce fix.
### alpha.2 — outillage Rust/Cargo partagé
Créer les templates `rustfmt.toml`, `clippy.toml` et `.cargo/config.toml` à partir du noyau éprouvé dans KSP et Games. Documenter les responsabilités distinctes : formatage, paramètres Clippy, sortie Cargo hors du dépôt. Le nom du projet, l'édition Rust et les seuils ajustables sont explicités au point de copie ; vérifier syntaxe et chemins relatifs. Les niveaux de lint dans `Cargo.toml` restent à `alpha.4` après le REPLAN, qui les reliera au profil Clippy retenu.
### alpha.3 — audits de style Rust découpés (REPLAN : SPLIT)
Suite à la demande post-gate `alpha.2`, isoler deux contrôles réutilisables des scripts composites KSP/Games : espacement des lignes vides et blocs de constantes racine sans ordre sémantique. Posséder leur convention facultative dans le profil `510`, documenter sélection/limites et exécuter des cas ciblés positifs et négatifs. Vérifier sur les corpus réels que les ordres contractuels ne deviennent pas de faux changements imposés. Les manifests initialement prévus ici passent à `alpha.4` : aucune validation anticipée n'est déduite du PASS de `alpha.2`.
### alpha.4 — manifests Cargo workspace et crate membre
Fournir des modèles minimaux de `Cargo.toml` racine et membre, incluant l'héritage des métadonnées et des lints et une explication des variations de scope. Vérifier les exemples sur un workspace d'essai lorsque la toolchain est disponible, sans recopier les listes de dépendances, versions et chemins de KSP/Games. Si les modèles exigent trop de décisions pour former des fichiers TOML valides, livrer des extraits complets avec procédure de substitution documentée, sans prétendre qu'un placeholder est prêt à compiler.
### alpha.5 — audit de headers Markdown
Extraire le contrôle récurrent en un script read-only monotâche, documenter sa portée dans la matrice et vérifier des cas positifs et négatifs utiles. Ne pas fusionner cet audit avec les deux audits Markdown existants.
### alpha.6 — décision sur le template de workflow
La comparaison des prompts `002` et `003` confirme une répétition utile à factoriser : baseline source, preuve post-tag éventuelle, prompt versionné et gate d'intake. Livrer une spécification courte de rédaction manuelle, détenue par `210-WORKFLOW.md`, sans générateur ni prompt de version suivante avant la clôture stable. Le template reste distinct des configurations Rust/Cargo et ne modifie pas les prompts historiques.
### beta.1 — réconciliation
Vérifier ownership, navigation, séparation règle/template/audit, absence de versions universelles arbitraires et proportion des contrôles. Aucun nouveau domaine majeur sans REPLAN.
La revue préparatoire de cette tranche a constaté que les sept deltas `0.0.3` de `alpha.1` à `alpha.6`, fix inclus, forment une chaîne de versions continue depuis `0.0.2` et possèdent chacun un history `PASS` fondé sur la gate opérateur. Les propriétaires restent distincts : profil `510` pour les conventions Rust facultatives, règles `210` et `300` pour workflow et headers, documents de `docs/templates/` pour l'adaptation, scripts monotâches pour les contrôles. Leurs validations ciblées avaient été acquises dans les tranches précédentes ; `beta.1` a vérifié leur intégration et la navigation sans exiger de nouveau build des projets sources.
Trois écarts documentaires justifiaient le delta : l'index de `docs/` présentait tous ses templates comme techniques alors que le troisième décrit la reprise de session ; le plan désignait toujours les headers Markdown comme candidat après leur livraison ; la matrice réservait l'audit de liens à `beta/RC/stable` alors que les gates `alpha` l'emploient également sur des changements de navigation. L'index racine ne pointait pas vers le plan actif. Ces renvois ont été corrigés dans les documents vivants sans modifier les snapshots ni les choix de version `0.1.0` et d'édition `2024` explicitement présentés comme exemples adaptables dans les manifests et instructions Rust/Cargo.
### rc.1 — gate de release candidate
Geler le scope, préparer le changelog et le prompt de la version suivante si la trajectoire est confirmée ; exécuter la gate documentaire et les vérifications ciblées des scripts réellement ajoutés.
La gate opérateur de `beta.1` est `PASS` : `15` tests ciblés, trois audits Markdown, chaîne des sept histories alpha et cinq TOML vérifiés. Son résultat détaillé appartient à `history/0.0.3/beta.1.md`. À l'entrée de `rc.1`, le scope est gelé sur les cinq fichiers Rust/Cargo avec leurs deux guides techniques, la spécification du message manuel, les deux audits de style Rust facultatifs et l'audit des headers Markdown. Les règles et scripts antérieurs restent en place ; aucun profil technologique nouveau, générateur ou skeleton complet n'entre dans cette release.
La RC a préparé une entrée candidate `0.0.3` dans le changelog et le prompt `004` de `0.0.4`. La gate opérateur de `rc.1` est `PASS` : `15` tests, trois audits Markdown, chaîne des huit histories précédents et cinq TOML vérifiés. Son résultat détaillé appartient à `history/0.0.3/rc.1.md`. La première tranche de `0.0.4` décidera des skeleton specifications réellement justifiées après audit de la stable publiée ; son rapport post-tag reste une preuve ultérieure distincte.
### stable — 0.0.3
Promouvoir la RC validée, produire le history de clôture pré-tag, committer et tagger, puis contrôler séparément l'archive du tag publiée.
Le delta `rel.001` prépare mécaniquement la version stable `0.0.3` : `VERSION`, statut de la roadmap, présentation du dépôt et des index, et conversion de l'entrée candidate du changelog en entrée stable. Ce plan devient une référence historique à la clôture, sans ajout de règle, profil, template ou audit. Le résultat réel de la gate pré-tag appartient à `history/0.0.3/rel.001.md`, fourni après exécution opérateur ; commit et tag `v0.0.3` suivent uniquement un PASS. La vérification de l'archive effectivement publiée depuis le tag constitue ensuite une preuve post-tag séparée, typiquement `publish.001`, et ne doit pas être présumée par le history pré-tag.
## Points de décision et validation
Le résultat `SPLIT` de `alpha.3` répond à la découverte post-gate de contrôles de style Rust utiles mais mêlés dans deux scripts de référence. Le plan doit encore être revu si les manifests Cargo exigent des choix de projet incompatibles avec un modèle minimal, si l'audit de headers ne peut rester fiable et monotâche, si le template de workflow duplique le plan, ou si un autre examen des corpus révèle des contraintes nouvelles. Un REPLAN explicite indique `CONTINUE`, `SPLIT`, `CONTINUE-NEXT-SESSION` ou `ABANDON` ; la durée d'une conversation ne crée pas une nouvelle version.
La validation `alpha.1` a porté sur l'identité de `VERSION`, la portée du delta, les headers et audits Markdown, l'absence de changement historique rétroactif et le contrôle Git du dépôt de l'opérateur. Ses résultats observés sont conservés dans `history/0.0.3/alpha.1.md`. Le fix documentaire décrit ci-dessus possède sa propre gate et son propre history : le PASS de `alpha.1` ne vaut pas validation anticipée de `alpha.1.fix.1`.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/000-README.md --> <!-- file: docs/rules/000-README.md -->
<!-- version: 6 --> <!-- version: 10 -->
# Index des règles PGR # Index des règles PGR
@@ -15,6 +15,13 @@ Les règles générales actuellement nécessaires restent dans `RULES.md`. La fa
- [`210-WORKFLOW.md`](210-WORKFLOW.md) — contrats des artefacts workflow, ordre delta/history/commit, reprise et baselines de release. - [`210-WORKFLOW.md`](210-WORKFLOW.md) — contrats des artefacts workflow, ordre delta/history/commit, reprise et baselines de release.
- [`300-DOCUMENTATION.md`](300-DOCUMENTATION.md) — rôles des documents, taxonomie, révisions internes, documents vivants et snapshots historiques. - [`300-DOCUMENTATION.md`](300-DOCUMENTATION.md) — rôles des documents, taxonomie, révisions internes, documents vivants et snapshots historiques.
- [`400-VALIDATION.md`](400-VALIDATION.md) — matrice de validation, preuves proportionnelles, tests/audits/diagnostics, doubles de test et autorité du gate opérateur. - [`400-VALIDATION.md`](400-VALIDATION.md) — matrice de validation, preuves proportionnelles, tests/audits/diagnostics, doubles de test et autorité du gate opérateur.
- [`500-LANGUAGES.md`](500-LANGUAGES.md) — contrat commun des profils langage/écosystème et de leurs spécialisations de build.
- [`510-RUST_CARGO.md`](510-RUST_CARGO.md) — profil Rust/Cargo et règles réutilisables propres à cet écosystème.
- [`520-JAVA_MAVEN_GRADLE.md`](520-JAVA_MAVEN_GRADLE.md) — profil Java et spécialisations de build Maven/Gradle.
- [`600-PLATFORMS.md`](600-PLATFORMS.md) — contrat commun des profils plateforme.
- [`610-ANDROID.md`](610-ANDROID.md) — profil plateforme Android et règles réutilisables de compatibilité, packaging et validation.
Le modèle transversal d'ownership, d'applicabilité et de composition est décrit dans [`../architecture/003-RULE_PROFILE_MODEL.md`](../architecture/003-RULE_PROFILE_MODEL.md).
## Organisation prévue ## Organisation prévue
@@ -25,7 +32,7 @@ Les autres familles seront créées uniquement lorsqu'elles disposent d'un conte
200 — governance 200 — governance
300 — documentation 300 — documentation
400 — validation 400 — validation
500 — languages 500 — languages / ecosystems
600 — platforms 600 — platforms
700 — frameworks 700 — frameworks
800 — architecture 800 — architecture

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/210-WORKFLOW.md --> <!-- file: docs/rules/210-WORKFLOW.md -->
<!-- version: 2 --> <!-- version: 3 -->
# Workflow artifact rules # Workflow artifact rules
@@ -193,6 +193,8 @@ Le prompt :
Une interruption au milieu d'une version MUST NOT produire artificiellement le prompt de la version suivante. Une interruption au milieu d'une version MUST NOT produire artificiellement le prompt de la version suivante.
Lors d'une nouvelle session ouverte depuis une stable publiée, une courte consigne manuelle MAY identifier l'archive du tag, le rapport post-tag lorsqu'il existe réellement, le prompt versionné à lire et la première gate. [`../templates/003-NEW_SESSION_PROMPT.md`](../templates/003-NEW_SESSION_PROMPT.md) décrit une forme réutilisable ; elle ne remplace ni le prompt versionné ni la preuve de publication.
## Handoff ## Handoff
Un handoff est un snapshot de continuité utilisé lorsqu'un travail doit être repris sans changer artificiellement de version ou de tranche. Un handoff est un snapshot de continuité utilisé lorsqu'un travail doit être repris sans changer artificiellement de version ou de tranche.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/300-DOCUMENTATION.md --> <!-- file: docs/rules/300-DOCUMENTATION.md -->
<!-- version: 1 --> <!-- version: 2 -->
# Documentation rules # Documentation rules
@@ -165,6 +165,8 @@ La syntaxe de commentaire dépend du format. Pour Markdown :
<!-- version: 1 --> <!-- version: 1 -->
``` ```
Dans le dépôt PGR, `README.md`, `RULES.md`, `ROADMAP.md`, `CHANGELOG.md` et les fichiers Markdown gouvernés sous `docs/`, `deltas/`, `history/` et `prompts/` MUST placer ces deux commentaires sur leurs deux premières lignes. Le `file` MUST être le chemin relatif depuis la racine du dépôt et `version` MUST être un entier positif sans zéro initial. `scripts/audit_markdown_headers.py` contrôle mécaniquement ces deux champs pour les chemins explicitement sélectionnés. Ce contrôle ne juge ni le contenu du document, ni si le numéro de révision a réellement été incrémenté lors d'un changement.
`file` identifie le chemin relatif canonique du fichier. `file` identifie le chemin relatif canonique du fichier.
`version` est une révision interne du fichier. Elle est indépendante de `VERSION`, de SemVer produit, des versions de protocole, de schema ou de package. `version` est une révision interne du fichier. Elle est indépendante de `VERSION`, de SemVer produit, des versions de protocole, de schema ou de package.

View File

@@ -0,0 +1,76 @@
<!-- file: docs/rules/500-LANGUAGES.md -->
<!-- version: 1 -->
# Règles de profils langage et écosystème
## Scope
Cette famille définit le contrat commun des profils liés à un langage, son écosystème et, lorsque pertinent, ses build tools ou package managers.
Les règles propres à Rust/Cargo, Java, Maven, Gradle ou à d'autres technologies sont ajoutées dans des documents plus spécifiques uniquement lorsqu'un contenu normatif réel existe.
## Responsabilités de la famille
Un profil langage/écosystème MAY posséder les règles spécifiques concernant notamment :
- l'organisation canonique des sources, packages, modules, crates ou workspaces ;
- les manifests et fichiers de configuration propres à l'écosystème ;
- la toolchain de compilation ou d'exécution lorsqu'elle appartient au langage ;
- les build tools et package managers liés à cet écosystème ;
- les dépendances, features, scopes ou configurations propres au gestionnaire utilisé ;
- le formatter, le linter et les commandes officielles de vérification ;
- les conventions d'API, d'import, d'erreur ou de safety réellement propres au langage ;
- l'organisation des tests lorsque l'écosystème lui donne une structure spécifique ;
- les artefacts générés ou lockfiles lorsque leur traitement dépend réellement de l'écosystème.
Un profil langage/écosystème MUST NOT absorber des règles dont le propriétaire naturel est une plateforme, un framework, un domaine métier ou le projet particulier.
## Héritage
Les profils de cette famille héritent des règles générales PGR et ne doivent pas recopier les contrats déjà possédés par les familles de gouvernance, documentation ou validation.
Une règle générale comme l'interdiction de versionner des secrets reste applicable sans être répétée dans chaque profil langage.
Lorsqu'un langage ou un build tool impose une exception réelle à une règle générale, le profil spécifique doit déclarer l'override et sa justification.
## Langage et build tool
PGR ne force pas un découpage identique pour tous les écosystèmes.
Un langage et son build tool MAY partager un profil lorsque leurs responsabilités sont suffisamment liées et que les séparer ne produirait que des renvois artificiels.
Ils SHOULD être séparés lorsque plusieurs build tools interchangeables possèdent chacun des règles propres significatives.
Dans ce second cas, la composition est explicite :
```text
language profile
↓
build-tool specialization
```
Une spécialisation de build tool ne devient pas une règle du langage entier.
## Versions d'outils et dépendances
Un profil MUST NOT figer une version exacte d'outil ou de dépendance uniquement parce qu'une version apparaît dans un projet source historique.
Une contrainte de version appartient au profil lorsqu'elle répond à une nécessité démontrée de compatibilité, reproductibilité, support, sécurité ou matrice imposée par un outil plus spécifique.
Une contrainte introduite par une plateforme ou un framework reste possédée par ce scope plus spécifique et ne se propage pas au langage entier.
## Validation spécialisée
Un profil langage/écosystème peut ajouter des commandes de formatage, lint, check ou test propres à sa toolchain.
Ces commandes complètent la gouvernance de validation générale ; elles ne redéfinissent ni l'autorité du gate opérateur, ni les statuts de preuve, ni le principe de proportionnalité.
Un audit Python PGR ne doit pas réimplémenter une propriété déjà contrôlée de façon fiable par le compilateur, le formatter, le linter ou le build tool officiel sans besoin distinct démontré.
## Nomenclature documentaire
Le document `500-LANGUAGES.md` possède le contrat commun de la famille.
Les profils spécifiques utilisent la plage `510` à `599`. Leur numéro identifie la navigation documentaire et ne représente ni une priorité normative implicite ni une version technologique.
L'applicabilité et les relations de spécialisation sont déterminées par le contenu du profil conformément à [`../architecture/003-RULE_PROFILE_MODEL.md`](../architecture/003-RULE_PROFILE_MODEL.md), jamais par l'ordre lexical des fichiers.

View File

@@ -0,0 +1,195 @@
<!-- file: docs/rules/510-RUST_CARGO.md -->
<!-- version: 2 -->
# Profil Rust / Cargo
## Scope
Ce profil s'applique aux projets qui utilisent Rust avec Cargo.
Il spécialise [`500-LANGUAGES.md`](500-LANGUAGES.md) pour les responsabilités propres à Rust et Cargo. Il ne possède pas les contraintes particulières d'une plateforme, d'un framework, d'une FFI, d'un protocole ou d'un domaine métier.
Une règle plus spécifique, par exemple Android, WASM, Tauri ou une frontière FFI, MAY raffiner ce profil dans son scope sans modifier la politique Rust générale.
## Toolchain et édition
Un nouveau projet Rust SHOULD utiliser une toolchain stable récente compatible avec ses dépendances et ses cibles. Une toolchain nightly, beta ou autre prerelease nécessite une justification explicite.
PGR MUST NOT imposer un pin exact de toolchain uniquement parce qu'un projet source historique utilisait cette version. Un fichier `rust-toolchain.toml` ou équivalent SHOULD être ajouté uniquement lorsqu'un besoin réel de reproductibilité, de composant ou de compatibilité l'exige.
Lorsqu'un workspace partage une politique d'édition unique, l'édition Rust SHOULD être déclarée une seule fois sous `[workspace.package]` et héritée par les membres. Une évolution d'édition est une décision de compatibilité/toolchain et non une modification opportuniste.
## Workspace et unités de release
Un projet Rust composé de plusieurs packages SHOULD utiliser un workspace Cargo lorsque les packages partagent réellement gouvernance, validation ou dépendances.
Pour un workspace à train de release unique :
- le fichier PGR `VERSION` reste la version canonique de l'unité de release ;
- `[workspace.package].version` MUST refléter cette version lorsque Cargo exige une version de package ;
- les crates membres SHOULD hériter de la version workspace plutôt que recopier la même valeur ;
- les métadonnées réellement communes comme `edition`, `license`, `repository` ou `authors` SHOULD être centralisées puis héritées lorsqu'elles ont le même propriétaire.
Un monorepo contenant plusieurs unités de release indépendantes MUST NOT fabriquer une fausse version Cargo globale uniquement pour appliquer ce modèle. Chaque unité conserve alors son propriétaire de version conformément aux règles générales PGR.
Le répertoire `crates/` est le placement PGR recommandé pour les packages Rust d'un workspace structuré, sauf layout imposé par un framework, une plateforme ou un projet existant.
## Manifests et dépendances Cargo
Dans un workspace, une dépendance tierce réellement partagée par plusieurs crates SHOULD posséder sa contrainte de version canonique sous `[workspace.dependencies]`.
Une crate membre SHOULD consommer cette dépendance avec `workspace = true` et activer localement uniquement les features nécessaires à son propre code. Une feature de plateforme ou de test MUST NOT être activée globalement par commodité lorsqu'un scope plus étroit suffit.
Une dépendance utilisée uniquement par les tests, benchmarks ou exemples SHOULD rester dans la section de dépendances de développement appropriée.
Les contraintes de version SHOULD exprimer l'intention de compatibilité réellement souhaitée. Un pin exact ou une version volontairement ancienne MUST avoir une raison identifiable : compatibilité, reproductibilité, sécurité, bug connu ou matrice imposée par un scope plus spécifique.
`cargo update` MUST NOT être exécuté opportunistement dans une tranche sans rapport avec les dépendances. Une mise à jour de résolution ou de dépendance appartient au scope courant uniquement lorsqu'elle est nécessaire et explicitement vérifiée.
## Politique de `Cargo.lock`
PGR ne généralise pas automatiquement la politique de lockfile d'un projet source à tous les projets Rust.
La décision de versionner ou non `Cargo.lock` MUST être explicite et cohérente avec le type de produit, le mode de publication et le besoin de reproductibilité du projet. Un profil plus spécifique MAY imposer une politique particulière.
Dans tous les cas, un lockfile ne remplace jamais les contraintes de version et décisions de compatibilité appartenant aux manifests et à la documentation normative.
## Lints communs
Un workspace structuré SHOULD déclarer les lints communs au niveau racine et les crates membres SHOULD les hériter plutôt que maintenir plusieurs copies divergentes.
Le profil strict PGR recommandé pour un nouveau workspace Rust comprend au minimum :
```toml
[workspace.lints.rust]
missing_docs = "warn"
unreachable_pub = "deny"
unsafe_code = "forbid"
[workspace.lints.clippy]
unwrap_used = "deny"
expect_used = "deny"
implicit_return = "deny"
question_mark = "deny"
question_mark_used = "deny"
```
Des `allow` nécessaires pour éviter qu'un lint de suggestion contredise intentionnellement le style retenu MAY être déclarés au workspace, mais la liste doit rester minimale et justifiée par une règle réelle.
## Safety et FFI
Le code `unsafe` est interdit par défaut dans un projet suivant le profil strict PGR.
Lorsqu'une FFI ou une plateforme impose réellement une opération `unsafe`, l'exception MUST appartenir au scope le plus étroit possible : crate, module, symbole ou attribut concerné. Elle MUST être documentée et ne doit pas affaiblir silencieusement le reste du workspace.
Une exception FFI locale n'autorise donc pas à remplacer globalement `unsafe_code = "forbid"` par une politique permissive pour toutes les crates.
## API, visibilité et rustdoc
Tout élément `pub` ou `pub(crate)` SHOULD posséder une rustdoc utile au point de déclaration lorsque son contrat dépasse une implémentation triviale locale.
Une crate réutilisable SHOULD exposer son API durable depuis son crate-root par des réexports explicites. Les modules d'implémentation SHOULD rester privés ; `pub mod` ne doit pas être utilisé uniquement pour éviter de concevoir une façade stable.
Un élément partagé à l'échelle de sa propre crate SHOULD être consommable via `crate::Item` après réexport approprié. Les autres crates consomment l'API publique du crate propriétaire plutôt que ses chemins internes.
Les glob imports SHOULD être évités. Un alias de réexport ne doit pas servir à masquer durablement une collision de noms dans l'API ; lorsqu'un nom fait partie du contrat public, le propriétaire SHOULD choisir un nom canonique non ambigu.
PGR ne généralise pas l'interdiction KSP plus stricte de tous les `use` non-traits : cette convention appartient à un profil ou projet plus spécifique tant qu'elle n'est pas nécessaire au contrat Rust général.
## Contrôle de flux et erreurs
Dans le code de production du profil strict PGR :
- `unwrap()` et `expect()` MUST NOT servir à traiter un chemin d'erreur récupérable ;
- `panic!` MUST NOT représenter une erreur métier récupérable ;
- les retours explicites sont la convention par défaut ;
- l'opérateur `?` est désactivé par le profil Clippy strict afin de conserver des chemins d'erreur explicites.
Une règle plus spécifique MAY définir une politique d'erreur différente lorsqu'elle possède une justification architecturale explicite. PGR ne généralise pas l'interdiction d'une bibliothèque d'erreur particulière à partir d'un seul projet source.
## Formatage
`rustfmt.toml` à la racine SHOULD être le propriétaire canonique du formatage Rust d'un workspace.
Le profil PGR issu des corpus actuellement éprouvés utilise notamment :
```toml
edition = "2024"
newline_style = "Unix"
hard_tabs = false
tab_spaces = 4
max_width = 160
reorder_imports = true
reorder_modules = true
use_try_shorthand = false
force_explicit_abi = true
```
L'édition de ce fichier MUST rester cohérente avec l'édition réellement utilisée par le workspace ; l'exemple `2024` décrit la baseline actuelle et ne constitue pas un pin éternel pour les futures éditions Rust.
Après une modification Rust, `cargo fmt --all` applique le formatage canonique puis `cargo fmt --all -- --check` vérifie l'état livré. Une modification produite uniquement par le formatter officiel ne crée pas artificiellement une nouvelle révision documentaire d'un fichier si aucun contenu réel n'a changé.
Le profil de style strict supplémentaire peut être adopté par un projet qui souhaite appliquer les conventions KSP/Games. Dans ce scope choisi, les lignes vides consécutives SHOULD être supprimées, ainsi que les lignes vides à l'intérieur des fonctions/méthodes et des définitions `struct`/`enum`. Ces propriétés ne sont pas entièrement possédées par Rustfmt. L'audit facultatif `scripts/audit_rust_blank_lines.py` contrôle ces deux formes d'espacement sur les seuls fichiers Rust sélectionnés.
Les constantes de module qui constituent un bloc homogène sans ordre sémantique SHOULD être regroupées dans l'ordre `pub`, `pub(crate)`, privé, puis par nom dans chaque visibilité : aucune ligne vide entre constantes d'une même visibilité et exactement une entre niveaux différents. `scripts/audit_rust_const_blocks.py` vérifie cette convention uniquement sur les constantes au niveau racine des fichiers choisis. Son exécution requiert une sélection explicite des fichiers pour lesquels cet ordre est réellement souhaité. Une table de protocole, une séquence de migrations ou tout autre ordre contractuel conserve son ordre propre ; le lecteur ne doit pas réordonner une telle séquence pour faire passer l'audit.
L'ordre des `use`, réexports et déclarations `mod` que Rustfmt sait réordonner dans ses groupes appartient au formatteur ; les modules de test après les modules de production et l'organisation d'une façade relèvent de leur contrat local, avec revue ou audit dédié seulement si celui-ci apporte une preuve fiable. Les règles rustdoc et d'API conservent leurs propriétaires ci-dessus. Les scripts PGR ne prétendent pas parser toutes les macros ou les items Rust : une décision sémantique reste une revue.
## Configuration Cargo et artefacts générés
`.cargo/config.toml` est le propriétaire naturel d'une configuration Cargo partagée par le projet lorsqu'une telle configuration est nécessaire.
Si un projet choisit de placer les artefacts Cargo hors de l'arborescence source, `target-dir` et les autres paramètres correspondants SHOULD être définis dans cette configuration plutôt que répétés dans chaque commande. Le chemin exact reste une décision de projet ou de skeleton et n'est pas figé par ce profil.
Les sorties `target/`, caches et artefacts de compilation MUST rester hors des livraisons source sauf contrat de packaging explicite.
## Tests Rust
Les tests MUST NOT élargir artificiellement la visibilité de l'API de production.
Les tests d'intégration Cargo résident sous `tests/` de la crate concernée et consomment son API publique.
Les tests unitaires restent sous la responsabilité de la crate ou du module testé. Un workspace MAY adopter une arborescence `unit_tests/` séparée et miroir de `src/` lorsqu'elle améliore la lisibilité ; cette convention doit alors être appliquée de manière cohérente sans transformer `tests/` en tests internes.
Une dépendance ou feature exclusivement nécessaire aux tests SHOULD rester dans le scope de développement/test approprié.
## Validation Rust / Cargo
Les catégories, l'autorité du gate et la proportionnalité restent possédées par [`400-VALIDATION.md`](400-VALIDATION.md). Ce profil ajoute seulement les commandes propres à Rust/Cargo.
Lorsqu'un delta modifie du code Rust, un manifeste Cargo, une feature ou une dépendance Rust, la séquence normale SHOULD inclure :
```bash
cargo fmt --all
cargo fmt --all -- --check
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
```
Les audits structurels read-only réellement applicables s'insèrent après le formatage et avant ou autour des contrôles Cargo selon leur responsabilité.
Les tests ciblés constituent la stratégie normale d'une tranche :
```bash
cargo test -p <crate> --all-targets --all-features
```
`cargo test --workspace --all-targets --all-features` est une gate plus large réservée aux changements transverses ou aux phases où une validation globale apporte une preuve supplémentaire réelle.
`cargo build` SHOULD être exécuté lorsqu'un artefact est nécessaire ; il ne doit pas être ajouté systématiquement à `cargo check` sans besoin de build ou packaging.
`cargo tree` et ses variantes SHOULD être utilisés lors d'une modification de dépendances/features ou d'un diagnostic de graphe, pas comme cérémonie de chaque delta.
`cargo clean` est une opération de maintenance et MUST NOT être exécuté automatiquement à chaque tranche.
La validation Cargo finale appartient à l'environnement autoritaire du projet. Une prévalidation par générateur ou CI supplémentaire ne remplace pas le gate opérateur défini par le projet.
## Audits PGR pour Rust
Les audits Rust historiques de projets sources peuvent combiner de nombreuses responsabilités. PGR ne doit pas recopier cette complexité comme point de départ.
Lorsqu'une règle Rust devient objectivement automatisable dans un projet ou skeleton concret, PGR SHOULD préférer plusieurs audits monotâches et lisibles, par exemple un contrôle de manifests/workspace distinct d'un contrôle de headers ou de façade publique.
Un éventuel wrapper d'orchestration MAY appeler plusieurs audits, mais chaque audit propriétaire doit conserver une responsabilité identifiable et rester read-only.
Les deux audits de style disponibles sont documentés dans [`../validation/002-RUST_STYLE_AUDITS.md`](../validation/002-RUST_STYLE_AUDITS.md). Ils restent optionnels et prennent un corpus Rust explicitement sélectionné ; le dépôt PGR lui-même ne contient pas de workspace Rust sur lequel une telle gate fournirait une preuve réelle.

View File

@@ -0,0 +1,316 @@
<!-- file: docs/rules/520-JAVA_MAVEN_GRADLE.md -->
<!-- version: 2 -->
# Profil Java / Maven / Gradle
## Rôle
Ce document possède les règles réutilisables propres au langage Java et à ses deux spécialisations de build principales retenues ici : Maven et Gradle.
Il complète [`500-LANGUAGES.md`](500-LANGUAGES.md). Les règles de gouvernance, documentation et validation restent possédées par leurs familles générales.
Android n'est pas défini ici. Une contrainte AGP, SDK Android, `minSdk`, `targetSdk`, `versionCode`, signing ou packaging APK/AAB appartient au profil plateforme Android et peut surcharger localement les règles Gradle ou JDK de ce document.
## Politique JDK et compatibilité Java
Pour un projet Java général suivant le profil PGR :
- le JDK de développement SHOULD être une version LTS ;
- la dernière LTS compatible disponible dans l'environnement SHOULD être utilisée par défaut ;
- une LTS plus ancienne MAY être sélectionnée lorsqu'un outil, framework, serveur, CI ou environnement d'exécution l'exige ;
- une version Java non-LTS SHOULD NOT être introduite sans besoin technique explicite.
PGR MUST distinguer :
```text
JDK utilisé pour construire
≠
niveau Java du code source
≠
niveau de bytecode/runtime minimal supporté
```
Le niveau Java ciblé MUST être déclaré explicitement par le build lorsqu'il affecte la compatibilité. Il ne doit pas dépendre implicitement du JDK actif sur la machine.
Une hausse de la version Java minimale supportée constitue un changement de compatibilité et MUST être justifiée comme telle.
PGR MUST NOT imposer une version exacte de JDK uniquement parce qu'un corpus historique ou un autre projet utilise cette version.
## Structure source Java
Un module Java classique SHOULD conserver la structure reconnue par l'écosystème :
```text
src/
├── main/
│ ├── java/
│ └── resources/
└── test/
├── java/
└── resources/
```
PGR SHOULD NOT remplacer cette convention par une arborescence propriétaire telle que `sources/`, `java-code/` ou `tests-java/` sans contrainte réelle.
Les chemins canoniques correspondants sont donc notamment `src/main/java/`, `src/main/resources/`, `src/test/java/` et `src/test/resources/`.
Lorsqu'un projet distingue des tests d'intégration, environnementaux ou live, il SHOULD utiliser un source set ou un module explicitement déclaré par le build plutôt que détourner `src/test/`.
## Packages et ownership
Un package Java représente une responsabilité architecturale, pas seulement un dossier.
La racine de package SHOULD être stable et appartenir au projet ou à l'organisation. Les sous-packages SHOULD refléter des responsabilités telles que `config`, `transport`, `store`, `logging` ou `protocol`.
Les packages génériques tels que `misc`, `stuff`, `helpers`, `common` ou `util` SHOULD NOT devenir des dépotoirs. Lorsqu'un élément est partagé, son propriétaire architectural doit d'abord être identifié.
Un package utilitaire petit et cohérent MAY exister lorsque sa responsabilité est claire.
## Nommage des modules
Lorsqu'un dépôt multi-langage ou multi-module utilise déjà une nomenclature de rôles commune, les modules Java SHOULD conserver les mêmes suffixes conceptuels afin de rester lisibles à l'échelle du dépôt.
Exemples usuels :
```text
foo-api
foo-lib
foo-app
foo-cli
foo-server
foo-service
foo-worker
foo-tool
foo-demo
foo-smoke
foo-poc
```
Ce vocabulaire est une convention de rôle et non une obligation de créer artificiellement des modules séparés.
## Imports
Les imports wildcard SHOULD NOT être utilisés :
```java
import foo.*;
import static foo.Bar.*;
```
Les imports explicites sont préférés afin de conserver l'origine des symboles visible.
Les imports statiques SHOULD être évités par défaut dans le code produit lorsqu'une forme qualifiée reste lisible. Une règle de test ou de framework plus spécifique MAY autoriser une convention différente lorsqu'elle est réellement idiomatique et bornée.
## Visibilité et API
La visibilité minimale appropriée est la règle par défaut :
```text
private
→ package-private
→ protected
→ public
```
Une méthode ou un type MUST NOT devenir `public` uniquement pour faciliter un test.
Une interface Java SHOULD exister lorsqu'elle représente une vraie frontière : plusieurs implémentations, contrat consommé indépendamment, adaptation de plateforme, API publique ou autre séparation architecturale réelle.
PGR SHOULD NOT généraliser le pattern `Foo` / `FooImpl` lorsqu'une seule implémentation existe sans frontière utile.
## Annotations et génération implicite
PGR n'interdit pas les annotations en tant que mécanisme Java.
Les annotations fonctionnelles faisant partie du contrat officiel d'un framework ou d'une API sont légitimes, par exemple pour la persistance, la validation, l'injection, le routage ou d'autres mécanismes officiellement documentés.
En revanche, Lombok et les outils équivalents de convenience/codegen implicite SHOULD NOT être utilisés par défaut lorsqu'ils servent principalement à masquer du boilerplate, générer des constructeurs/getters/setters ou modifier implicitement l'API visible dans la source.
Une exception exige une justification explicite et reste attachée au projet ou framework concerné.
## Nullabilité
`null` SHOULD apparaître uniquement lorsqu'il appartient explicitement au contrat.
Une API ne devrait pas laisser le caller deviner si l'absence est possible. Selon le cas, le contrat peut employer :
- `Optional<T>` ;
- une collection vide ;
- une exception appropriée ;
- un type résultat plus explicite ;
- une annotation de nullabilité reconnue par le projet.
PGR MUST NOT imposer `Optional` partout. L'objectif est l'explicitation du contrat, pas une cérémonie syntaxique.
## Exceptions
Java possède un mécanisme natif d'exceptions ; PGR ne recrée pas automatiquement un modèle `Result` autour de toutes les opérations.
La distinction checked/unchecked appartient au contrat de la couche concernée.
Un `catch` SHOULD exister uniquement lorsque la couche sait réellement traiter, traduire ou enrichir l'erreur. Les captures silencieuses de `Exception` ou `Throwable` sont interdites hors mécanisme de frontière explicitement spécialisé.
Lorsqu'une erreur est traduite, sa cause SHOULD être préservée lorsque cette information reste pertinente.
Une couche SHOULD exposer ses propres erreurs de contrat plutôt que propager sans contrôle les détails techniques d'une dépendance interne.
## Tests Java
Les tests comportementaux et structurels gardent des responsabilités distinctes.
Les tests unitaires résident normalement sous `src/test/java/`. Les tests d'intégration, environnementaux ou live SHOULD être séparés par source set, module ou tâche lorsque leur exécution possède des préconditions différentes.
Les tests MUST NOT :
- rendre publique une API uniquement pour l'atteindre ;
- rechercher des chaînes dans les sources pour simuler un audit d'architecture ;
- vérifier une prerelease en codant en dur la version courante ;
- ouvrir `VERSION`, `pom.xml` ou `build.gradle` uniquement pour confirmer leur synchronisation.
Les contraintes structurelles appartiennent au build system, au compilateur, à un linter adapté ou à un audit read-only.
## Maven — ownership du build
Dans un projet Maven multi-module, le POM parent/root SHOULD centraliser ce qui est réellement commun :
- version du projet lorsqu'elle doit être reflétée par Maven ;
- niveau Java cible ;
- `dependencyManagement` ;
- `pluginManagement` ;
- configuration commune de compilation et de tests.
Les modules SHOULD hériter de cette politique lorsque Maven le permet et ne pas recopier les mêmes versions/configurations sans nécessité.
Le fichier PGR `VERSION` reste la version canonique de l'unité de release. Le `pom.xml` racine porte un miroir technique lorsque Maven exige cette valeur. Les enfants SHOULD hériter de la version parent afin d'éviter les modifications mécaniques répétées de nombreux POM.
`dependencyManagement` centralise les contraintes de version communes ; il ne signifie pas qu'une dépendance doit être effectivement ajoutée à tous les modules. Chaque module déclare uniquement ce qu'il utilise.
## Maven Wrapper
Deux politiques sont légitimes :
```text
Maven système
→ environnement contrôlé
→ contrainte de version documentée
Maven Wrapper
→ distribution / CI / onboarding reproductible
→ wrapper versionné
```
PGR MUST NOT ajouter un Maven Wrapper uniquement par cérémonie.
Lorsqu'un wrapper est retenu, ses fichiers requis sont versionnés et constituent une exception explicite à la politique générale qui ignore les outputs générés.
## Validation Maven
Le développement SHOULD privilégier les gates ciblées avant le reactor complet.
Exemple avec wrapper :
```bash
./mvnw -pl <module> -am test
```
Exemple avec Maven système :
```bash
mvn -pl <module> -am test
```
Les gates globales telles que le reactor complet, `verify` ou le packaging de tous les modules SHOULD être réservées aux changements transverses et aux phases où elles fournissent une preuve supplémentaire réelle.
`clean` est une opération de maintenance et MUST NOT précéder automatiquement chaque validation.
## Gradle — ownership du build
Un projet Gradle SHOULD centraliser la configuration commune au niveau root lorsqu'elle est réellement partagée.
Selon le DSL retenu, les propriétaires typiques sont :
```text
settings.gradle / settings.gradle.kts
build.gradle / build.gradle.kts
gradle.properties
```
Les sous-projets SHOULD NOT recopier sans nécessité :
- la compatibilité Java ;
- les repositories ;
- les versions de plugins ;
- les contraintes de dépendances ;
- les configurations de tests communes.
Un version catalog tel que `gradle/libs.versions.toml` MAY être utilisé lorsque la taille du projet le justifie. PGR MUST NOT l'imposer pour un projet qui n'en tire aucun bénéfice réel.
## Gradle Wrapper et version de Gradle
La contrainte Gradle doit refléter la matrice réellement supportée par le projet :
```text
minimum seulement
range min..max
version exacte/pinnée
latest compatible
```
Le projet MUST choisir la forme la moins restrictive qui prouve réellement sa compatibilité.
Un Gradle Wrapper SHOULD être versionné lorsqu'il apporte une reproductibilité utile pour la distribution, la CI ou l'onboarding. Un projet contrôlé MAY utiliser un Gradle système si sa contrainte de compatibilité est explicitement vérifiée.
Une plateforme ou un framework plus spécifique MAY imposer une contrainte plus étroite. Cette contrainte ne se propage jamais implicitement aux autres projets Gradle.
## DSL Gradle
PGR ne transforme pas une préférence de langage applicatif en interdiction du DSL de build.
Groovy DSL et Kotlin DSL sont tous deux reconnus. Un projet SHOULD retenir un DSL canonique et éviter de les mélanger arbitrairement.
Le code applicatif Java reste Java par défaut lorsque rien n'impose Kotlin/Groovy. Les scripts Gradle SHOULD rester aussi déclaratifs et courts que raisonnablement possible.
Une logique de build devenue importante SHOULD être déplacée vers une abstraction ou un plugin clairement possédé plutôt que grossir indéfiniment les scripts root.
## Validation Gradle
Les tâches ciblées sont préférées pendant le développement :
```bash
./gradlew :<module>:test
```
ou, lorsqu'un Gradle système est explicitement retenu :
```bash
gradle :<module>:test
```
Les tâches globales `check`, `build`, `assemble` ou de packaging complet SHOULD être sélectionnées lorsqu'elles correspondent réellement au scope, typiquement lors d'un changement transverse ou dans les phases de stabilisation/release.
`gradle clean` est une opération de maintenance et MUST NOT être utilisé comme précondition automatique à chaque build.
## Outputs, état local et Git
Les sorties de build et caches usuels ne sont pas versionnés :
```text
Maven: target/
Gradle: .gradle/, build/
```
Les métadonnées IDE spécifiques à une machine restent ignorées sauf exception explicitement partagée selon les règles générales du projet.
Les wrappers retenus sont une exception volontaire : ils peuvent être générés par l'outil, mais leurs fichiers nécessaires au bootstrap reproductible sont versionnés.
Les fichiers de configuration locale contenant chemins machine, credentials ou overrides développeur restent hors Git. Un template est ajouté uniquement lorsqu'un utilisateur doit réellement préparer une valeur non régénérée automatiquement.
## Validation et futurs audits PGR
Les catégories et l'autorité du gate restent possédées par [`400-VALIDATION.md`](400-VALIDATION.md).
Ce profil définit des commandes et politiques Java/Maven/Gradle, mais PGR lui-même ne possède actuellement aucun projet Java, Maven ou Gradle à compiler. Aucune commande Maven/Gradle n'est donc ajoutée à la gate documentaire de cette tranche.
De même, aucun audit Java/Maven/Gradle n'est créé uniquement pour matérialiser un outil.
Lorsqu'un skeleton ou projet réel fournira un sujet stable, des audits monotâches MAY vérifier séparément des propriétés objectivement structurelles, par exemple la cohérence `VERSION`/POM, l'héritage d'une politique Maven ou la contrainte Gradle déclarée. Ils resteront read-only et ne lanceront jamais Maven ou Gradle à la place de leurs gates propres.

View File

@@ -0,0 +1,65 @@
<!-- file: docs/rules/600-PLATFORMS.md -->
<!-- version: 1 -->
# Règles de profils plateforme
## Scope
Cette famille définit le contrat commun des profils liés à une plateforme de build, d'exécution ou de distribution telle qu'Android, iOS, Desktop, Web ou une cible embarquée lorsqu'un profil réel le justifie.
Les règles propres à une plateforme sont ajoutées dans des documents plus spécifiques uniquement lorsqu'elles possèdent un contenu normatif réel.
## Responsabilités de la famille
Un profil plateforme MAY posséder les règles spécifiques concernant notamment :
- la structure de projet imposée ou conventionnelle sur cette plateforme ;
- les SDKs, targets, runtimes et niveaux minimums supportés ;
- les contraintes de toolchain réellement imposées par la plateforme ;
- les permissions, manifests, capabilities ou métadonnées de plateforme ;
- le packaging, la signature et les artefacts de distribution ;
- les émulateurs, simulateurs, appareils ou environnements nécessaires aux smokes ;
- les adaptations de lifecycle, input ou services réellement propres à la plateforme ;
- les contraintes de compatibilité utilisateur liées à une version minimale de target/runtime.
Un profil plateforme MUST NOT recopier les règles du langage ou du build tool lorsque celles-ci restent valides sans spécialisation.
## Composition avec les langages et build tools
Une plateforme peut être utilisée avec plusieurs langages ou toolchains. Son profil ne doit donc pas supposer implicitement une combinaison unique lorsque la plateforme elle-même ne l'impose pas.
Lorsqu'une plateforme impose une contrainte plus précise à un langage ou build tool déjà applicable, la règle plateforme peut la raffiner ou la remplacer dans son scope à condition d'identifier clairement la contrainte et sa raison.
Cette contrainte MUST NOT se propager aux projets utilisant le même langage hors de cette plateforme.
## Toolchain de build et compatibilité de target
La modernité de la toolchain de build et la version minimale du runtime ou de la target sont deux décisions distinctes.
L'utilisation d'un SDK, compilateur ou build tool récent ne justifie pas à elle seule l'augmentation de la version minimale supportée par les utilisateurs.
Une hausse d'un minimum de target/runtime constitue un changement de compatibilité et doit être justifiée par une contrainte ou un bénéfice réel du projet.
Inversement, un minimum ancien ne doit pas être conservé artificiellement lorsqu'il empêche une capacité nécessaire, une maintenance raisonnable ou une chaîne de build supportée.
## Packaging, secrets et configuration locale
Les règles de packaging ou de signature spécifiques à une plateforme peuvent appartenir à son profil, mais les secrets eux-mêmes restent soumis aux règles générales PGR et ne sont jamais versionnés.
Une plateforme peut nécessiter des fichiers locaux ou générés particuliers ; leur politique Git doit être documentée dans le profil spécifique seulement lorsqu'elle diffère réellement du contrat général.
## Validation spécialisée
Un profil plateforme peut définir les builds, packages et smokes réellement nécessaires pour prouver le support annoncé.
La présence d'une plateforme dans un projet ne rend pas automatiquement tous ses smokes obligatoires à chaque tranche. La sélection reste proportionnée au scope modifié et aux preuves invalidées.
Les validations nécessitant un appareil, un simulateur, un service externe ou une chaîne de packaging réelle doivent être distinguées des contrôles documentaires ou unitaires qui ne prouvent pas ces comportements.
## Nomenclature documentaire
Le document `600-PLATFORMS.md` possède le contrat commun de la famille.
Les profils spécifiques utilisent la plage `610` à `699`. Leur numéro sert à la navigation et ne détermine pas une priorité normative implicite.
La résolution entre profils suit [`../architecture/003-RULE_PROFILE_MODEL.md`](../architecture/003-RULE_PROFILE_MODEL.md).

316
docs/rules/610-ANDROID.md Normal file
View File

@@ -0,0 +1,316 @@
<!-- file: docs/rules/610-ANDROID.md -->
<!-- version: 2 -->
# Profil Android
## Rôle
Ce document possède les règles réutilisables propres à la plateforme Android.
Il complète [`600-PLATFORMS.md`](600-PLATFORMS.md) et, lorsqu'un projet Android utilise Java/Gradle, [`520-JAVA_MAVEN_GRADLE.md`](520-JAVA_MAVEN_GRADLE.md).
Une contrainte Android plus spécifique MAY raffiner les règles générales Java ou Gradle dans le seul scope Android lorsqu'une matrice AGP/Gradle/JDK, un SDK ou une contrainte de distribution l'impose.
Les profils Rust/JNI et Tauri ne sont pas définis ici. Ils constituent des compositions plus spécialisées et MUST NOT contaminer le profil Android général.
## Structure du projet
Pour un dépôt exclusivement Android, les conventions Android normales restent prioritaires et la racine du dépôt MAY être directement le projet Gradle.
Dans un dépôt multi-plateforme où une zone Android distincte est nécessaire, PGR SHOULD utiliser la racine :
```text
Android/
```
Cette racine est alors un chemin de plateforme stable. Elle ne doit pas être renommée arbitrairement en `android/`, `mobile/` ou autre uniquement par préférence locale.
Une structure multi-plateforme peut par exemple contenir :
```text
project/
├── VERSION
├── crates/
├── Web/
└── Android/
├── settings.gradle
├── build.gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
└── gradle/
```
Les noms et fichiers exacts restent soumis au projet Android réellement utilisé ; PGR ne crée pas de niveau `Android/` artificiel dans un dépôt qui est déjà exclusivement Android.
## Langage applicatif et logique de build
Java est le langage applicatif Android par défaut du profil PGR lorsqu'aucune API, framework ou contrainte réelle n'impose un autre choix.
Kotlin MAY être utilisé lorsqu'une API, un framework ou une intégration l'exige réellement.
Groovy DSL ou Kotlin DSL MAY être utilisés par Gradle comme langage de configuration. Leur présence dans le build ne transforme pas Kotlin ou Groovy en langage applicatif du projet.
Les fichiers Gradle SHOULD rester aussi déclaratifs et courts que raisonnablement possible. Une logique de build importante SHOULD être possédée par une abstraction ou un plugin identifiable plutôt que devenir du code produit caché dans un script Gradle.
Les annotations fonctionnelles Android ou de frameworks restent autorisées lorsqu'elles constituent le mécanisme officiel de l'API concernée.
## Matrice AGP / Gradle / JDK
Un projet Android MUST exprimer une chaîne de build compatible.
La matrice conceptuelle est :
```text
Android Gradle Plugin
↕
Gradle
↕
JDK LTS
```
PGR MUST NOT imposer globalement une version Gradle, AGP ou JDK uniquement parce qu'elle est utilisée par un autre projet Android.
La contrainte applicable peut être :
```text
minimum
range min..max
version exacte / pin
latest compatible
```
Le projet choisit la forme la moins restrictive qui reste réellement compatible avec sa stack.
Le JDK suit le profil Java : dernière LTS compatible par défaut, LTS plus ancienne lorsqu'une contrainte Android ou de framework l'impose, non-LTS uniquement par exception justifiée.
Lorsque le Gradle Wrapper est retenu, ses fichiers requis sont versionnés et sa version doit satisfaire la matrice réelle AGP/Gradle/JDK.
## `compileSdk`, `targetSdk` et `minSdk`
Ces trois valeurs représentent des contrats différents.
`compileSdk` définit l'API Android utilisée pour compiler. Il MAY être récent afin de permettre l'usage des APIs et outils actuels.
`targetSdk` déclare le niveau de comportement Android pour lequel l'application a été adaptée. Il MUST respecter les exigences applicables au canal de distribution réellement visé.
`minSdk` définit la plus ancienne version Android que le produit promet de pouvoir installer et exécuter.
PGR MUST NOT déduire une hausse de `minSdk` d'une hausse de `compileSdk` ou `targetSdk`.
`minSdk` SHOULD rester aussi bas que raisonnablement supportable tant que cela ne compromet pas une capacité nécessaire, une dépendance imposée, la sécurité ou une maintenance raisonnable.
Une hausse de `minSdk` est un changement de compatibilité utilisateur et MUST être explicitement justifiée.
## `VERSION`, `versionName` et `versionCode`
Lorsqu'une application Android appartient au même release train que le projet, le fichier PGR `VERSION` reste la version SemVer canonique de cette unité de release.
`versionName` est un miroir technique de cette version lorsqu'elle doit représenter la même release à l'utilisateur ou au canal de distribution.
`versionCode` est un compteur Android monotone distinct du SemVer.
PGR MUST NOT confondre `versionCode` avec `VERSION` ou `versionName`.
Pour une application publiée, `versionCode` MUST NOT diminuer. Lorsqu'un dépôt publie plusieurs applications indépendantes, chaque application MAY posséder son propre compteur versionné.
Le projet MAY stocker ce compteur dans un fichier explicite tel que :
```text
Android/app/VERSION_CODE
```
si cela correspond à son architecture.
PGR SHOULD NOT imposer une formule dérivant automatiquement `versionCode` du SemVer sans décision explicite du projet.
Un futur audit read-only MAY vérifier séparément :
```text
VERSION ↔ versionName
VERSION_CODE ↔ configuration Android
```
lorsqu'un projet ou skeleton réel fournit des fichiers à contrôler. Cet audit ne doit jamais modifier les versions.
## Configuration locale
`local.properties` est un fichier local Android typique et SHOULD rester hors Git lorsqu'il contient des chemins machine tels que l'emplacement du SDK.
PGR MUST NOT utiliser `local.properties` comme source normative de configuration partagée du projet.
Si l'outil ou l'IDE régénère intégralement ce fichier, aucun fichier exemple n'est nécessaire.
Lorsqu'une propriété locale obligatoire n'est pas automatiquement reproductible, un template MAY être fourni conformément aux règles générales PGR.
La même politique s'applique aux fichiers locaux analogues tels que `keystore.properties`, `user.properties` ou des variantes `*.local.properties` lorsqu'ils contiennent des valeurs propres à la machine ou à l'utilisateur.
## Signing et secrets
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.
Dans le scope Android, les éléments suivants sont notamment des secrets ou artefacts privés soumis à cette interdiction :
```text
release keystore
private signing key
passwords
credentials
service account secret
```
Une configuration versionnée MAY référencer des variables ou propriétés telles que :
```text
RELEASE_KEYSTORE
RELEASE_KEY_ALIAS
```
mais MUST NOT contenir leurs valeurs privées.
Le debug keystore généré automatiquement est local.
Le signing de release ne doit pas être requis pour une validation ordinaire de développement sauf lorsque la tranche valide précisément la distribution ou la signature finale.
## Modules Android
Les modules Android SHOULD être nommés par responsabilité.
Des noms tels que :
```text
app
common
game-reflex
game-snake
```
peuvent être légitimes lorsque ces responsabilités existent réellement.
Des noms opaques tels que `module1`, `module2`, `misc` ou `utils2` SHOULD NOT servir de structure durable.
Un module partagé doit posséder une responsabilité commune réelle ; il ne doit pas devenir un dépôt générique de code sans owner.
## Dépendances Android
Les dépendances Android doivent rester minimales et explicites.
Une dépendance officielle et étroite SHOULD être préférée à un framework beaucoup plus large lorsqu'une petite capability suffit.
À l'inverse, PGR SHOULD NOT réimplémenter une API de plateforme, un protocole standard ou une primitive de sécurité uniquement pour éviter une dépendance officielle appropriée.
Une BOM ou un mécanisme officiel de gestion de versions MAY être utilisé lorsqu'il réduit réellement les incompatibilités. Il ne doit pas entraîner l'ajout automatique de toute une famille de dépendances non utilisées.
La politique d'un lockfile Android/Gradle, lorsqu'un projet en utilise un, doit être décidée selon le besoin réel de cet écosystème et du projet. Elle n'est pas déduite automatiquement d'un autre profil.
## ABI et code natif
Un projet Android purement Java peut ne posséder aucune règle ABI spécifique.
Dès qu'un projet contient du code natif via NDK, C/C++, Rust ou une autre frontière native, les ABI réellement supportées MUST être déclarées explicitement.
Exemples possibles :
```text
arm64-v8a
armeabi-v7a
x86_64
```
PGR ne fixe pas une liste universelle d'ABI.
Une ABI annoncée comme supportée doit disposer d'une preuve adaptée. Une cross-compilation native seule ne prouve pas l'intégration dans l'APK, le lifecycle Android ni l'exécution sur device/AVD.
Les règles JNI elles-mêmes appartiennent à un profil spécialisé et restent hors de ce document.
## Niveaux de tests Android
PGR distingue au moins trois niveaux de preuve Android lorsqu'ils sont applicables :
```text
JVM unit
→ logique ne nécessitant pas le runtime Android
instrumented / integration
→ comportement nécessitant le framework Android
smoke device / AVD
→ application ou package réel dans un environnement Android
```
Un test JVM MUST NOT être enregistré comme preuve d'un comportement réel d'`Activity`, de lifecycle ou de device.
Un test instrumenté ne remplace pas automatiquement un smoke du package final.
Un appareil physique n'est pas obligatoire pour chaque release. Il devient nécessaire lorsqu'une propriété annoncée dépend d'un matériel ou comportement qui ne peut pas être suffisamment prouvé par AVD.
## Ordre de validation Android
Une validation Android ordinaire SHOULD progresser du ciblé vers le plus coûteux :
```text
format applicable
↓
audits read-only applicables
↓
compilation module ciblé
↓
lint Android ciblé
↓
unit tests ciblés
↓
assemble/package lorsque nécessaire
↓
install
↓
smoke
```
Les tests globaux, l'instrumentation large, les bundles de release, les matrices multi-ABI et les smokes multi-device sont sélectionnés lorsque le scope ou la phase de release l'exige réellement.
Les commandes exactes appartiennent à la matrice du projet ou du skeleton qui possède un Android build réel.
`clean` reste une opération de maintenance et ne doit pas précéder automatiquement chaque gate.
## Manifest et ressources
`AndroidManifest.xml` MUST déclarer uniquement les permissions et capabilities réellement nécessaires.
Une permission sensible ne doit pas être ajoutée « au cas où ». Son introduction constitue un changement significatif qui doit être visible dans le delta et, lorsque pertinent, dans la documentation de release.
`src/main/res/` reste la source canonique des ressources Android d'un module standard.
Dans un projet multi-plateforme, des assets réellement partagés MAY vivre dans un owner commun hors d'Android si leur consommation est définie clairement.
PGR SHOULD NOT maintenir manuellement plusieurs copies divergentes du même asset source dans des arborescences de plateforme différentes.
## APK, AAB et artefacts de distribution
PGR distingue les rôles des principaux artefacts :
```text
APK debug
→ développement et smokes ordinaires
APK release
→ validation d'un package release installable lorsque nécessaire
AAB
→ artefact de distribution lorsque le canal cible l'exige
```
La phase de release et le scope modifié déterminent l'artefact nécessaire.
Une alpha documentaire n'a pas besoin d'un package Android réel si aucun projet Android n'est concerné. Une release d'une application Android peut au contraire nécessiter un package ou smoke réel lorsque `versionName`, `versionCode`, signing ou packaging sont modifiés.
La promotion stable ne doit pas provoquer mécaniquement un full rebuild sans preuve invalidée ; elle doit toutefois revalider le packaging ciblé lorsque les métadonnées qui entrent dans l'artefact ont changé.
## Validation et futurs audits PGR
Les catégories générales et l'autorité du gate restent possédées par [`400-VALIDATION.md`](400-VALIDATION.md).
PGR lui-même ne contient actuellement aucun projet Android à compiler, installer ou exécuter. Cette tranche ne prétend donc pas valider AGP, Gradle, SDK, AVD, APK ou AAB réels.
Aucun audit Android spécialisé n'est créé uniquement pour remplir le profil.
Lorsqu'un skeleton ou projet concret fournira les fichiers nécessaires, des audits monotâches MAY vérifier des propriétés structurelles stables telles que la cohérence de version, la présence d'une configuration locale ignorée ou une matrice de compatibilité explicitement déclarée. Ces audits restent read-only et ne remplacent jamais Gradle, Android Lint, l'installation ou les smokes.

View File

@@ -0,0 +1,45 @@
<!-- file: docs/templates/001-RUST_CARGO_TOOLING.md -->
<!-- version: 3 -->
# Templates d'outillage Rust/Cargo
## Rôle et sélection
Ces trois fichiers fournissent une baseline de configuration issue des conventions réellement utilisées dans KSP et Games. Ils s'appliquent à un projet Rust/Cargo qui choisit ce profil d'outillage ; ils ne créent pas une dépendance vers PGR après copie.
- [`rustfmt.toml`](../../templates/rust-cargo/rustfmt.toml) — formatage canonique, avec notamment largeur `160` et édition `2024` dans l'exemple ;
- [`clippy.toml`](../../templates/rust-cargo/clippy.toml) — paramètres de lints (seuils, exceptions de tests, identifiants courts) issus du noyau partagé des deux projets ;
- [`.cargo/config.toml`](../../templates/rust-cargo/.cargo/config.toml) — emplacements des artefacts Cargo hors de la racine source.
Les niveaux `deny`, `allow`, `warn` et `forbid` des lints Rust/Clippy appartiennent au `Cargo.toml` du workspace, selon [`510-RUST_CARGO.md`](../rules/510-RUST_CARGO.md). `clippy.toml` règle des paramètres de lints, pas leur niveau. Les deux modèles Cargo et l'héritage `[lints] workspace = true` sont documentés dans [`002-CARGO_MANIFESTS.md`](002-CARGO_MANIFESTS.md).
## Copier et adapter
Copier ces fichiers aux chemins suivants dans le projet destinataire :
```text
rustfmt.toml
clippy.toml
.cargo/config.toml
```
Adapter le header `# file:` de chacun à son nouveau chemin relatif. Comme il s'agit de nouveaux fichiers locaux, leur révision interne commence à `1` si le projet suit cette convention. Vérifier les choix avant de les utiliser :
1. `rustfmt.toml` : aligner `edition` sur l'édition déclarée dans le manifeste du projet. La largeur et les autres options constituent la convention de départ de KSP/Games et peuvent être ajustées pour le projet ;
2. `clippy.toml` : revoir les seuils au regard des types et API du projet ; adapter `allowed-idents-below-min-chars` à ses abréviations réelles. Les exceptions `allow-*-in-tests` sont une décision explicite du profil retenu ; elles ne relâchent pas les lints de production ;
3. `.cargo/config.toml` : remplacer `project-name` par un identifiant propre au projet pour éviter la collision de deux workspaces sous `../builds/`. Depuis une configuration placée dans `<racine>/.cargo/`, Cargo résout ici les chemins relatifs par rapport à `<racine>/` : la sortie se trouve donc sous le dossier frère `<parent>/builds/<projet>/target/` ;
4. conserver les deux entrées `target-dir` et `build-dir` lorsque cette politique est choisie. Elles ciblent volontairement le même dossier, même si Cargo utilise actuellement `target-dir` comme valeur par défaut de `build-dir` ;
5. ajouter séparément les flags de cible, chemins particuliers ou ajustements Clippy nécessaires à un projet. Les flags Web présents dans Games ne sont pas un défaut de tous les projets Rust.
Le chemin de sortie sous `builds/` est externe au dépôt source ; il ne doit pas être inclus dans les archives du projet. Si l'environnement impose un autre emplacement, ajuster la configuration du projet au lieu de copier un chemin machine depuis KSP ou Games.
## Validation dans un projet Rust
Après adaptation, les contrôles utiles dépendent du code et des manifests effectivement présents :
```bash
cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
```
Vérifier l'emplacement effectif des artefacts sur un build ou un check pertinent. La validation de PGR lui-même peut vérifier la syntaxe TOML et la cohérence des chemins sans demander de compiler un workspace Rust absent de son dépôt.

47
docs/templates/002-CARGO_MANIFESTS.md vendored Normal file
View File

@@ -0,0 +1,47 @@
<!-- file: docs/templates/002-CARGO_MANIFESTS.md -->
<!-- version: 1 -->
# Modèles de manifests Cargo workspace et crate membre
## Rôle des deux fichiers
Le [manifest racine](../../templates/rust-cargo/Cargo.toml) est celui d'un workspace virtuel à une unité de release ; le [manifest membre](../../templates/rust-cargo/crates/project-core-lib/Cargo.toml) montre une crate bibliothèque ordinaire. Les deux fichiers forment un exemple TOML syntaxiquement valide. Après copie dans un nouveau projet, il faut aussi fournir le code source de la crate avant de demander à Cargo de la compiler. Le dépôt PGR ne devient pas lui-même un workspace Cargo.
Ces modèles prolongent les trois configurations de [`001-RUST_CARGO_TOOLING.md`](001-RUST_CARGO_TOOLING.md). Le propriétaire des choix normatifs reste [`510-RUST_CARGO.md`](../rules/510-RUST_CARGO.md). Les chemins `project-core-lib`, le nom du package et la version `0.1.0` sont des **valeurs d'exemple à remplacer** : cette version ne reflète pas `VERSION` de PGR et ne définit pas la version d'un autre projet.
## Adopter le manifest racine
Copier `templates/rust-cargo/Cargo.toml` vers `Cargo.toml` du projet, corriger son header `# file:` et commencer sa propre révision de fichier à `1`. Adapter `members` aux répertoires qui existent effectivement, puis choisir la version canonique de l'unité de release. Lorsque toutes les crates partagent une seule release, aligner `[workspace.package].version` sur le `VERSION` de ce projet ; plusieurs unités de release indépendantes ne doivent pas hériter d'une version fictive commune.
L'édition `2024` et `resolver = "3"` sont cohérents avec l'exemple [`rustfmt.toml`](../../templates/rust-cargo/rustfmt.toml). Pour un workspace virtuel, fixer explicitement le resolver souhaité ; adapter ensemble l'édition, Rustfmt et la toolchain compatible si le projet prend d'autres valeurs. `publish = false` est un défaut prudent pour cet exemple ; définir la politique de publication réelle avant de publier une crate.
`license`, `repository` et `authors` ne sont volontairement pas renseignés avec des identités fictives. Si ces métadonnées ont une valeur vraie et commune, les déclarer dans `[workspace.package]` et les hériter explicitement dans chaque crate concernée, par exemple `license.workspace = true` seulement après avoir déclaré `license` à la racine. Ne pas imposer un auteur, une licence ou une URL propres à KSP/Games.
Le bloc `[workspace.dependencies]` est vide tant qu'aucune dépendance concrète ne sert plusieurs crates. Déclarer à la racine seulement les contraintes et features réellement communes ; les features propres à un membre sont activées sur sa dépendance locale. Cargo ajoute les features demandées au membre à celles déjà sélectionnées au workspace ; éviter d'activer globalement une feature de test ou de plateforme par facilité. Les dépendances de test appartiennent à `[dev-dependencies]` du membre qui les utilise.
Les trois lints Rust et les `18` niveaux Clippy reprennent la politique partagée observée dans KSP et Games. Les `allow` retiennent leurs choix de style explicite, notamment `needless_return` malgré `implicit_return = "deny"`, et évitent qu'un lint de suggestion réécrive systématiquement ce style. Réviser leur pertinence pour le projet avant adoption. Les seuils et réglages supplémentaires appartiennent au [`clippy.toml`](../../templates/rust-cargo/clippy.toml) distinct : ce fichier ne définit aucun niveau de lint.
## Adopter le manifest membre
Copier le membre vers `crates/<nom>/Cargo.toml`, adapter `name`, son chemin dans `members` et le header `# file:`. `version.workspace = true`, `edition.workspace = true` et `publish.workspace = true` rendent visibles les héritages choisis ; ajouter séparément `license.workspace = true`, `repository.workspace = true` ou `authors.workspace = true` si les valeurs existent à la racine et concernent cette crate. `[lints] workspace = true` est requis pour reprendre les niveaux du workspace : leur présence à la racine ne suffit pas à les appliquer automatiquement aux membres.
Le bloc `[dependencies]` vide se remplit selon les besoins de la crate. Pour une dépendance déjà déclarée sous `[workspace.dependencies]`, utiliser localement `nom = { workspace = true }`, avec `features = [...]` au besoin. Pour une dépendance strictement locale, choisir sa contrainte directement dans ce membre ; aucune liste tierce arbitraire n'est copiée par ce modèle.
Une application binaire peut reprendre les mêmes héritages après adaptation du nom, du layout et de sa cible `src/main.rs` ; ne pas fabriquer un deuxième manifest quasi identique. Une crate à version ou politique de publication réellement indépendante doit déclarer ses valeurs locales et ne plus hériter ces champs par automatisme.
## Exception locale de lints
Une frontière FFI peut avoir besoin de `unsafe_code = "allow"` dans une crate particulière, comme l'entrée Android observée dans Games. Cette exception demande justification, portée étroite et validation du code `unsafe` concerné. Cargo ne permet pas de combiner `workspace = true` avec des définitions de lints locaux dans le même manifest membre : retirer l'héritage `[lints]` pour cette crate et déclarer localement `[lints.rust]` ainsi que `[lints.clippy]`, en recopiant les niveaux partagés réellement conservés puis en ajustant seulement l'exception motivée. Les autres membres continuent d'hériter des lints racine.
## Vérification dans le projet destinataire
Après avoir ajouté le code source nécessaire, vérifier d'abord la résolution des manifests et les héritages, puis les contrôles réellement applicables :
```bash
cargo metadata --format-version 1 --no-deps
cargo fmt --all -- --check
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
```
Vérifier séparément le cas d'une crate à lints locaux lorsque le projet comporte réellement une exception. `Cargo.lock` et les artefacts créés par ces commandes suivent la politique du projet et la configuration Cargo de [`001-RUST_CARGO_TOOLING.md`](001-RUST_CARGO_TOOLING.md).

View File

@@ -0,0 +1,29 @@
<!-- file: docs/templates/003-NEW_SESSION_PROMPT.md -->
<!-- version: 1 -->
# Spécification du prompt manuel de nouvelle session
## Usage
Cette spécification sert à préparer un court message de reprise après une stable publiée. Le prompt de démarrage propre à la version suivante reste un fichier `prompts/NNN-VX_Y_Z_START_PROMPT.md` finalisé selon [`210-WORKFLOW.md`](../rules/210-WORKFLOW.md). Le message manuel indique où commencer et quelles preuves fournir ; il ne copie ni ce prompt, ni le plan, ni le history de la release.
La comparaison des prompts PGR `002` et `003` montre une structure récurrente (baseline taggée, cible, première tranche et mission). `003` ajoute le rapport de vérification post-tag et un texte transmis explicitement à l'opérateur. Une forme courte commune réduit les oublis lors de la clôture suivante, sans rendre obligatoires des champs propres à PGR dans les autres projets.
## Champs à renseigner
1. **Baseline** : identifier le tag stable, le nom réel de l'archive source téléchargée depuis ce tag et la forge d'origine. Une archive sans `.git` demande une vérification interne ; elle ne prouve pas à elle seule le commit du tag.
2. **Preuve post-tag** : si un rapport de publication/vérification distinct existe et est réellement `PASS`, indiquer son chemin exact et le joindre. Sinon, signaler explicitement qu'il est absent ou que son état n'est pas `PASS` ; ne jamais fabriquer cette preuve ni la confondre avec le tag.
3. **Contrat de reprise** : indiquer le chemin du prompt `prompts/NNN-VX_Y_Z_START_PROMPT.md` existant dans la baseline, la version cible et la première tranche attendue. Le prompt versionné possède la mission détaillée et le scope de la release.
4. **Intake** : demander la vérification de l'archive, des règles applicables, de la gouvernance, de la structure documentaire et des deltas/histories avant de préparer la première tranche. Adapter la liste aux artefacts effectivement présents et aux risques du projet.
## Forme à remplir et à remettre
Après vérification des chemins et de l'état réel du rapport, écrire **une seule phrase** adaptée au projet. Si le rapport est `PASS` et fourni :
```text
Partir de l'archive <nom exact du ZIP issu du tag vX.Y.Z> et du rapport post-tag <chemin exact du rapport PASS>. Lire et exécuter <chemin du prompt de démarrage dans la baseline>. Vérifier l'archive, les règles, la gouvernance, la structure documentaire, les deltas/histories et la cohérence globale avant de préparer <version cible-alpha.1>.
```
Si le rapport est absent ou non validé, retirer « et du rapport post-tag ... » de la phrase et préciser séparément son état réel à la nouvelle session. Conserver les noms exacts de la forge et des fichiers du projet : la forme `<nom exact du ZIP>` n'est qu'un champ de rédaction.
Rédiger le texte manuel à la clôture après le contrôle de l'archive publiée et le remettre à l'opérateur. Une interruption au milieu d'une prerelease suit le mécanisme de reprise de la tranche courante prévu dans `210-WORKFLOW.md` ; elle ne crée pas artificiellement un nouveau prompt de version.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/001-VALIDATION_MATRIX.md --> <!-- file: docs/validation/001-VALIDATION_MATRIX.md -->
<!-- version: 4 --> <!-- version: 9 -->
# Matrice de validation PGR # Matrice de validation PGR
@@ -13,18 +13,34 @@ 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 chemins, rôles et responsabilités des documents touchés | fichiers documentaires | modification documentaire | alpha/beta/RC/stable | faible | opérateur/revue |
| `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-MD-HEADER-001` | `AUDIT` | `python3 -B scripts/audit_markdown_headers.py <paths...>` | Python 3 | Markdown gouverné modifié | alpha/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-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-STATUS-001` | `CHECK` | `git status --short` | Git | avant fermeture d'une tranche | alpha/beta/RC/stable | faible | opérateur | | `PGR-NAV-001` | `AUDIT` | `python3 -B scripts/audit_markdown_links.py <paths...>` | Python 3 | navigation ou réconciliation | alpha/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. 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-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.
`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.
## Contrôles Rust réutilisables, hors gate du dépôt PGR
[`002-RUST_STYLE_AUDITS.md`](002-RUST_STYLE_AUDITS.md) décrit deux audits facultatifs : `audit_rust_blank_lines.py` contrôle l'espacement des lignes vides, `audit_rust_const_blocks.py` contrôle l'ordre et l'espacement des blocs de constantes au niveau racine. Ils acceptent des chemins Rust sélectionnés et partagent un petit support lexical ; leur validation ciblée dans PGR est `python3 -B -m unittest discover -s tests -p test_rust_audits.py`.
Leur disponibilité ne transforme pas PGR en workspace Rust et ne rend pas automatiquement l'ordre alphabétique applicable à chaque fichier d'un projet. Lors d'une adoption, le projet propriétaire sélectionne ses chemins après `cargo fmt` et applique sa propre gate ; Rustfmt et Clippy conservent les contrôles qu'ils possèdent.
## Politique Eclipse actuelle ## Politique Eclipse actuelle
Les métadonnées Eclipse spécifiques à une machine restent ignorées, notamment `.project`, `.classpath` et les préférences non partagées. Les métadonnées Eclipse spécifiques à une machine restent ignorées, notamment `.project`, `.classpath` et les préférences non partagées.

View File

@@ -0,0 +1,34 @@
<!-- file: docs/validation/002-RUST_STYLE_AUDITS.md -->
<!-- version: 1 -->
# Audits facultatifs de style Rust
## Responsabilité et provenance
Les sources KSP `0.3.16` et Games `0.3.5` possèdent chacune un `audit_rust_general_rules.py` qui mêle plusieurs règles. Le découpage PGR fournit deux contrôles ciblés sans copier l'orchestrateur ni les règles propres aux deux projets. Le contrat de style facultatif est dans [`510-RUST_CARGO.md`](../rules/510-RUST_CARGO.md), et la sélection des preuves dans [`400-VALIDATION.md`](../rules/400-VALIDATION.md).
`scripts/audit_rust_blank_lines.py` contrôle les lignes vides consécutives et les lignes vides dans un corps de fonction/méthode, `struct` ou `enum`. `scripts/audit_rust_const_blocks.py` contrôle l'ordre `pub`, `pub(crate)`, privé, le tri naturel des noms dans chaque visibilité et l'espacement entre constantes consécutives au niveau racine du fichier. `scripts/_rust_audit_common.py` partage la sélection des chemins et le masquage des commentaires/littéraux : il ne définit aucune nouvelle politique.
## Adoption et commandes
Dans un projet Rust qui choisit ces conventions, copier les trois fichiers `scripts/*.py` concernés en gardant le helper à côté des deux audits. Adapter les headers `file` au chemin du projet et maintenir une révision de fichier propre à cette copie.
Choisir explicitement les fichiers concernés par chaque contrat. Après formatage :
```bash
cargo fmt --all -- --check
python3 -B scripts/audit_rust_blank_lines.py crates/example/src
python3 -B scripts/audit_rust_const_blocks.py crates/example/src/constants.rs
```
Une invocation sans chemin est une erreur, de même qu'un chemin absent ou aucun fichier Rust sélectionné. Un répertoire sélectionne récursivement les fichiers `.rs` hors répertoires générés habituels. Les audits ne modifient ni les fichiers inspectés ni l'arborescence de build. Les sorties utilisent le chemin et la ligne ; le code de sortie est `0` si propre, `1` pour violation, `2` pour sélection/lecture impossible.
Ne sélectionner pour l'audit des constantes que les fichiers dont les blocs racine sans sémantique d'ordre doivent effectivement suivre ce contrat. Un tri de table de protocole, des migrations, des champs de wire format ou de toute séquence métier peut casser le programme : sa revue appartient au projet. Ne pas utiliser la sortie du script comme justification pour les réordonner.
## Limites mesurées
La prévalidation des sources réels a porté sur `300` fichiers KSP et `59` Games sous `crates/**/src/`. L'audit des lignes vides n'y détecte aucun écart. L'audit de constantes détecte `17` signaux KSP et aucun Games lorsque tous ces fichiers lui sont soumis ; des fichiers KSP contiennent des séquences ordonnées selon le protocole ou le schéma, ce qui rend une gate globale du tri inappropriée. Ces observations ne sont pas une gate de validation opérateur PGR.
L'analyse lexicale masque littéraux et commentaires courants, y compris commentaires imbriqués et chaînes Rust brutes. Elle n'est pas un parseur Rust : les macros élaborées, syntaxe nouvelle, attributs complexes, items associés dans `impl` et constantes dans modules inline n'entrent pas dans le contrat garanti de l'audit des blocs racine. Les lignes vides à l'intérieur d'un littéral multilignes sont exclues. Les cas qui demandent une interprétation sémantique nécessitent la revue humaine ou les outils Rust du projet.
Rustfmt reste propriétaire de l'ordre qu'il réécrit déjà dans les groupes de `use`/`mod`. Clippy et le compilateur restent responsables de leurs diagnostics. La suite `tests/test_rust_audits.py` vérifie les propriétés ciblées avec des cas propres, des violations et des littéraux/commentaires qui contiennent des accolades.

View File

@@ -0,0 +1,104 @@
<!-- file: history/0.0.2/alpha.1.fix.1.md -->
<!-- version: 1 -->
# History 0.0.2-alpha.1.fix.1 — correction du cadrage, sizing et audit Markdown
## Statut
PASS
Le correctif de cadrage `0.0.2-alpha.1.fix.1` a été validé par l'opérateur. Le sizing réduit, la reconnaissance de la preuve post-tag et le premier audit Markdown monotâche sont cohérents avec l'objectif de `alpha.1`.
## Baseline
La tranche précédente `0.0.2-alpha.1` a été enregistrée `FAIL`, puis committée et poussée sous le commit observé :
```text
d3f1e13
```
Version validée après application du fix :
```text
0.0.2-alpha.1.fix.1
```
## Validation opérateur observée
L'opérateur a confirmé la présence et le contenu attendu des artefacts du fix :
```bash
test "$(cat VERSION)" = "0.0.2-alpha.1.fix.1"
test -f scripts/audit_markdown_tables.py
test -f deltas/0.0.2/alpha.1.fix.1.md
grep -F '### Preuve post-tag `publish.001`' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F '### alpha.5 — Android' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F 'Rust + Android / JNI' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F '`PGR-MD-TABLE-001`' docs/validation/001-VALIDATION_MATRIX.md
```
L'audit Markdown PGR a ensuite été exécuté sur le corpus documentaire courant :
```bash
python3 -B scripts/audit_markdown_tables.py \
README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts
```
Résultat observé :
```text
Markdown table audit: clean (2 table(s), 45 file(s))
```
Les contrôles Git ont également réussi :
```bash
git diff --check
git add VERSION \
docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md \
docs/validation/001-VALIDATION_MATRIX.md \
scripts/audit_markdown_tables.py \
deltas/0.0.2/alpha.1.fix.1.md
git diff --cached --check
git status --short
```
`git diff --check` et `git diff --cached --check` n'ont produit aucun diagnostic.
La sortie finale observée avant ajout du présent history était exactement :
```text
M VERSION
A deltas/0.0.2/alpha.1.fix.1.md
M docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
M docs/validation/001-VALIDATION_MATRIX.md
A scripts/audit_markdown_tables.py
```
## Revue qualitative
Les décisions qualitatives ayant motivé le fix avaient déjà été explicitées par l'opérateur avant son application :
- conserver `publish.001` comme preuve post-tag externe plutôt que l'injecter dans le tag stable ;
- réduire le nombre de profils matérialisés afin de ne pas surcharger la session ;
- différer les profils C/C++/CMake, PHP/Composer, Python et les compositions plus larges au lieu de s'éparpiller ;
- commencer à introduire des audits PGR uniquement lorsque l'occasion révèle une propriété stable et objectivement contrôlable ;
- préférer des audits simples et monotâches aux scripts combinés historiques lorsqu'une responsabilité unique suffit.
Le résultat mécanique du fix est conforme à ces décisions.
## Résultat
`0.0.2-alpha.1.fix.1` est validée `PASS`.
Le cadrage de `0.0.2` est désormais autorisé à progresser vers :
```text
0.0.2-alpha.2
```
Cette tranche suivante est limitée au modèle de profils PGR : ownership, composition général → spécifique, résolution des overrides, non-duplication et activation des seules familles documentaires nécessaires aux profils retenus pour `0.0.2`.

105
history/0.0.2/alpha.1.md Normal file
View File

@@ -0,0 +1,105 @@
<!-- file: history/0.0.2/alpha.1.md -->
<!-- version: 1 -->
# History 0.0.2-alpha.1 — baseline audit and profile sizing
## Statut
FAIL
Les commandes mécaniques prévues par le delta `alpha.1` ont toutes réussi, mais la revue opérateur a identifié des défauts dans le cadrage lui-même. Comme `alpha.1` est précisément la gate d'audit, de sizing et de planification de `0.0.2`, la tranche ne doit pas être déclarée PASS tant que ces défauts ne sont pas corrigés.
## Baseline
Archive source issue du tag stable Gitea :
```text
v0.0.1
```
Version observée après application du delta :
```text
0.0.2-alpha.1
```
L'absence de `.git` dans l'archive de baseline reste normale et n'a pas été traitée comme une anomalie.
## Validation opérateur observée
Les commandes communiquées par l'opérateur ont réussi :
```bash
test "$(cat VERSION)" = "0.0.2-alpha.1"
test -f docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
test -f deltas/0.0.2/alpha.1.md
grep -F 'Plan actif créé pendant `0.0.2-alpha.1`' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F 'Aucun défaut bloquant de gouvernance' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F '### alpha.2 — Rule profile model' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F '### alpha.8 — Tauri desktop/mobile' docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
grep -F -- '- `( ) 0.0.2`' ROADMAP.md
grep -F 'v0.0.1' prompts/002-V0_0_2_START_PROMPT.md
git diff --check
git add VERSION docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md deltas/0.0.2/alpha.1.md
git diff --cached --check
git status --short
```
`git diff --check` et `git diff --cached --check` n'ont produit aucun diagnostic.
La sortie finale observée avant ajout du présent history est exactement :
```text
M VERSION
A deltas/0.0.2/alpha.1.md
A docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
```
## Défauts identifiés par revue
### Tableau Markdown non aligné
Le tableau `Inventaire des profils candidats` est syntaxiquement lisible par Markdown, mais ses colonnes ne sont pas alignées dans le source. Le défaut est visible immédiatement lors d'une revue et n'a pas été détecté par la gate `alpha.1`.
Un audit réutilisé en diagnostic depuis les projets sources confirme le défaut sur les quatre colonnes du tableau.
Ce cas fournit une propriété stable et objectivement automatisable : l'alignement source des tableaux Markdown. Il justifie l'introduction d'un premier audit PGR monotâche et read-only au lieu d'ajouter un contrôle manuel supplémentaire.
### Sizing trop large
Le plan initial conservait, après `alpha.1`, sept tranches technologiques `alpha.2` à `alpha.8` avant réconciliation et RC.
Ce découpage est trop ambitieux pour l'objectif de dimensionnement « une version complète par session », surtout avant d'avoir mesuré le coût réel du premier profil. L'opérateur demande explicitement de privilégier l'exécution correcte du scope retenu plutôt que de matérialiser trop de profils dans `0.0.2`.
Le fix doit donc réduire le scope initial de la release à un ensemble minimal mais représentatif : modèle de profil, Rust/Cargo, Java/Maven/Gradle et Android. Les compositions Rust+Android/JNI, Web/WASM et Tauri restent candidates mais sont différées.
### Preuve post-tag `publish.001` déjà disponible
La revue initiale avait correctement conclu que `publish.001` ne pouvait pas faire partie du tag `v0.0.1`, mais elle n'avait pas retrouvé le rapport post-tag déjà conservé hors du tag.
Le rapport `pgr-0.0.1-publish.001-report.md` existe dans la bibliothèque de travail et indique `Status: PASS` pour l'archive `pgr-v0.0.1.zip`, avec le SHA-256 attendu.
Cette preuve ne doit pas être injectée rétroactivement dans le tag stable. Elle doit simplement être reconnue comme preuve post-publication externe à la baseline source.
La maturité future de PGR devra également permettre aux handoffs/prompts de reprise d'indiquer explicitement si un tel rapport post-publication doit être fourni à la session suivante. Cette amélioration de workflow ne doit toutefois pas élargir `0.0.2`.
## Conséquence
`0.0.2-alpha.1` est enregistré en `FAIL`.
La tranche suivante est `0.0.2-alpha.1.fix.1`, strictement limitée au cadrage de `alpha.1` :
- corriger le tableau Markdown du plan ;
- reconnaître correctement le rapport post-tag `publish.001` déjà disponible sans modifier `v0.0.1` ;
- réduire le nombre de profils matérialisés dans `0.0.2` ;
- introduire un premier audit Markdown monotâche, read-only et sans dépendance externe, parce qu'un défaut réel vient d'en démontrer la nécessité ;
- enregistrer ce nouvel audit dans la matrice de validation.
Aucune règle technologique prévue pour `alpha.2+` ne doit être absorbée dans le fix.

123
history/0.0.2/alpha.2.md Normal file
View File

@@ -0,0 +1,123 @@
<!-- file: history/0.0.2/alpha.2.md -->
<!-- version: 1 -->
# History 0.0.2-alpha.2 — modèle de profils PGR
## Statut
PASS
La tranche `0.0.2-alpha.2` a été validée par l'opérateur. Le modèle d'ownership, d'applicabilité et de composition des profils est en place avant l'introduction du premier profil technologique réel.
## Baseline
La tranche précédente `0.0.2-alpha.1.fix.1` a été enregistrée `PASS`, puis committée et poussée sous le commit observé :
```text
1a5dd09
```
Version validée après application de `alpha.2` :
```text
0.0.2-alpha.2
```
## Validation opérateur observée
L'opérateur a confirmé la version et la présence des nouveaux propriétaires documentaires :
```bash
test "$(cat VERSION)" = "0.0.2-alpha.2"
test -f docs/architecture/003-RULE_PROFILE_MODEL.md
test -f docs/rules/500-LANGUAGES.md
test -f docs/rules/600-PLATFORMS.md
test -f deltas/0.0.2/alpha.2.md
```
Les contrats principaux du modèle ont été vérifiés par recherche littérale :
```text
Toute règle durable doit posséder un seul propriétaire normatif canonique.
L'ordre des fichiers dans un répertoire ne crée jamais une priorité normative.
PGR ne crée pas automatiquement un profil composite pour chaque combinaison possible.
```
Les contrats des familles `500` et `600` ont également été retrouvés, notamment :
```text
Les profils spécifiques utilisent la plage `510` à `599`.
Une spécialisation de build tool ne devient pas une règle du langage entier.
La modernité de la toolchain de build et la version minimale du runtime ou de la target sont deux décisions distinctes.
Les profils spécifiques utilisent la plage `610` à `699`.
```
Les liens depuis `RULES.md`, l'index `docs/rules/000-README.md` et le plan `0.0.2` ont été vérifiés.
L'audit Markdown PGR a ensuite été exécuté :
```bash
python3 -B scripts/audit_markdown_tables.py \
README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts
```
Résultat observé :
```text
Markdown table audit: clean (2 table(s), 50 file(s))
```
Les contrôles Git ont réussi :
```bash
git diff --check
git add VERSION RULES.md \
docs/architecture/003-RULE_PROFILE_MODEL.md \
docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md \
docs/rules/000-README.md \
docs/rules/500-LANGUAGES.md \
docs/rules/600-PLATFORMS.md \
deltas/0.0.2/alpha.2.md
git diff --cached --check
git status --short
```
`git diff --check` et `git diff --cached --check` n'ont produit aucun diagnostic.
La sortie finale observée avant ajout du présent history était exactement :
```text
M RULES.md
M VERSION
A deltas/0.0.2/alpha.2.md
A docs/architecture/003-RULE_PROFILE_MODEL.md
M docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
M docs/rules/000-README.md
A docs/rules/500-LANGUAGES.md
A docs/rules/600-PLATFORMS.md
```
## Revue qualitative
L'état livré respecte les frontières prévues par `alpha.2` :
- l'ownership d'une règle dépend de son scope et non du numéro ou de l'ordre lexical des fichiers ;
- une spécialisation de build tool peut rester plus spécifique que son langage sans contaminer ce dernier ;
- une contrainte plateforme peut surcharger localement un langage/build tool sans devenir une règle générale ;
- les familles `700 — frameworks` et `800 — architecture` restent réservées et ne sont pas matérialisées sans contenu réel ;
- aucune règle Rust, Cargo, Java, Maven, Gradle ou Android détaillée n'a été absorbée prématurément dans le modèle transversal.
## Résultat
`0.0.2-alpha.2` est validée `PASS`.
La tranche suivante autorisée est :
```text
0.0.2-alpha.3
```
Elle est consacrée au premier profil réel `Rust / Cargo` et sert de point de mesure du coût d'un profil complet avant de confirmer ou replanifier les tranches `alpha.4+`.

122
history/0.0.2/alpha.3.md Normal file
View File

@@ -0,0 +1,122 @@
<!-- file: history/0.0.2/alpha.3.md -->
<!-- version: 1 -->
# History 0.0.2-alpha.3 — premier profil Rust / Cargo
## Statut
PASS
La tranche `0.0.2-alpha.3` a été validée par l'opérateur. Le premier profil technologique réel de PGR est en place et le point de mesure prévu par le plan ne révèle pas de dérive nécessitant un REPLAN avant `alpha.4`.
## Baseline
La tranche précédente `0.0.2-alpha.2` a été enregistrée `PASS`, puis committée et poussée sous le commit observé :
```text
5f9b84c
```
Version validée après application de `alpha.3` :
```text
0.0.2-alpha.3
```
## Validation opérateur observée
L'opérateur a confirmé la version et la présence du nouveau profil :
```bash
test "$(cat VERSION)" = "0.0.2-alpha.3"
test -f docs/rules/510-RUST_CARGO.md
test -f deltas/0.0.2/alpha.3.md
```
Les contrats principaux ont été retrouvés par recherche littérale, notamment :
```text
PGR MUST NOT imposer un pin exact de toolchain uniquement parce qu'un projet source historique utilisait cette version.
le fichier PGR `VERSION` reste la version canonique de l'unité de release
Une crate membre SHOULD consommer cette dépendance avec `workspace = true`
PGR ne généralise pas automatiquement la politique de lockfile
unsafe_code = "forbid"
PGR ne généralise pas l'interdiction KSP plus stricte de tous les `use` non-traits
cargo clippy --workspace --all-targets --all-features -- -D warnings
PGR SHOULD préférer plusieurs audits monotâches et lisibles
```
Les liens vers `510-RUST_CARGO.md` ont été retrouvés depuis `RULES.md` et `docs/rules/000-README.md`.
L'audit Markdown PGR a été exécuté :
```bash
python3 -B scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts
```
Résultat observé :
```text
Markdown table audit: clean (2 table(s), 53 file(s))
```
Les contrôles Git ont réussi :
```bash
git diff --check
git add VERSION RULES.md docs/rules/000-README.md docs/rules/510-RUST_CARGO.md deltas/0.0.2/alpha.3.md
git diff --cached --check
git status --short
```
`git diff --check` et `git diff --cached --check` n'ont produit aucun diagnostic.
La sortie finale observée avant ajout du présent history était exactement :
```text
M RULES.md
M VERSION
A deltas/0.0.2/alpha.3.md
M docs/rules/000-README.md
A docs/rules/510-RUST_CARGO.md
```
Les marqueurs `EXEC >>` visibles dans la transcription proviennent du prompt Bash personnalisé de l'opérateur. Ils n'indiquent pas une erreur ou une commande supplémentaire dans la gate.
## Revue qualitative
L'état validé respecte le scope de `alpha.3` :
- les règles Rust/Cargo réutilisables sont séparées des conventions propres à KSP et `sasedev-games` ;
- la politique de `Cargo.lock` reste une décision explicitement liée au type de projet au lieu d'être généralisée depuis les corpus historiques ;
- les exceptions FFI et plateforme restent bornées au scope qui les impose ;
- aucune version de crate, dépendance ou toolchain historique n'est devenue un pin universel ;
- aucun audit Rust complexe n'a été ajouté sans workspace Rust réel ni propriété stable à contrôler ;
- le profil tient dans un propriétaire documentaire unique et cohérent sans matérialiser prématurément de famille supplémentaire.
## Point de mesure
Le point de mesure prévu par le plan est satisfaisant.
La matérialisation d'un profil complet n'a pas nécessité de série de fixes ni de découpage supplémentaire. Le forecast suivant reste raisonnable :
```text
0.0.2-alpha.4 — Java / Maven / Gradle
0.0.2-alpha.5 — Android
```
Un REPLAN reste obligatoire si une tranche ultérieure révèle une dérive significative ; aucune dérive de cette nature n'est observée ici.
## Résultat
`0.0.2-alpha.3` est validée `PASS`.
La tranche suivante autorisée est :
```text
0.0.2-alpha.4
```
Elle est consacrée au profil `Java / Maven / Gradle`, en maintenant une frontière nette entre règles du langage Java, politique de build Maven/Gradle et contraintes de plateforme qui appartiendront notamment au futur profil Android.

View File

@@ -0,0 +1,81 @@
<!-- file: history/0.0.2/alpha.4.fix.1.md -->
<!-- version: 1 -->
# History 0.0.2-alpha.4.fix.1 — cohérence de la gate Java
## Statut
PASS
Le correctif `0.0.2-alpha.4.fix.1` a été validé par l'opérateur. Le défaut de cohérence entre le profil Java/Maven/Gradle et sa gate est corrigé sans modification de scope fonctionnel.
## Baseline
La tranche `0.0.2-alpha.4` a été enregistrée `FAIL`, puis committée et poussée sous le commit observé :
```text
70ff272
```
Version validée après application du correctif :
```text
0.0.2-alpha.4.fix.1
```
## Validation opérateur observée
La version et les fichiers attendus ont été confirmés :
```bash
test "$(cat VERSION)" = "0.0.2-alpha.4.fix.1"
test -f docs/rules/520-JAVA_MAVEN_GRADLE.md
test -f deltas/0.0.2/alpha.4.fix.1.md
```
Les quatre chemins Java canoniques ajoutés par le correctif ont été retrouvés :
```text
src/main/java/
src/main/resources/
src/test/java/
src/test/resources/
```
Les invariants principaux du profil sont toujours présents :
```text
le JDK de développement SHOULD être une version LTS
PGR MUST NOT ajouter un Maven Wrapper uniquement par cérémonie.
Un Gradle Wrapper SHOULD être versionné lorsqu'il apporte une reproductibilité utile
```
L'audit Markdown PGR a réussi :
```text
Markdown table audit: clean (2 table(s), 58 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/alpha.4.fix.1.md
M docs/rules/520-JAVA_MAVEN_GRADLE.md
```
## Résultat
`0.0.2-alpha.4.fix.1` est validée `PASS`.
Le profil Java/Maven/Gradle est clos pour le scope de `0.0.2`.
La tranche suivante autorisée est :
```text
0.0.2-alpha.5
```
Elle est consacrée au premier profil plateforme Android. Les spécialisations Rust/JNI, Tauri et autres compositions restent explicitement hors scope de cette tranche.

119
history/0.0.2/alpha.4.md Normal file
View File

@@ -0,0 +1,119 @@
<!-- file: history/0.0.2/alpha.4.md -->
<!-- version: 1 -->
# History 0.0.2-alpha.4 — profil Java / Maven / Gradle
## Statut
FAIL
La tranche `0.0.2-alpha.4` n'est pas validée `PASS` telle quelle.
Le contenu principal est cohérent et presque toute la gate a réussi, mais une commande obligatoire du delta n'a produit aucun match :
```bash
grep -F 'src/main/' docs/rules/520-JAVA_MAVEN_GRADLE.md
```
La sortie observée est vide. Pour `grep -F`, l'absence de correspondance correspond à un code de retour non nul.
Il s'agit d'un défaut de cohérence entre le texte du profil et la gate de validation, pas d'un défaut de la politique Java/Maven/Gradle elle-même.
## Baseline
Version contrôlée :
```text
0.0.2-alpha.4
```
Le profil attendu et le delta sont présents :
```text
docs/rules/520-JAVA_MAVEN_GRADLE.md
deltas/0.0.2/alpha.4.md
```
## Contrôles réussis observés
Les contrôles suivants ont produit les correspondances attendues :
```text
le JDK de développement SHOULD être une version LTS
JDK utilisé pour construire
Lombok et les outils équivalents de convenience/codegen implicite SHOULD NOT être utilisés par défaut
Le fichier PGR `VERSION` reste la version canonique de l'unité de release
PGR MUST NOT ajouter un Maven Wrapper uniquement par cérémonie.
minimum seulement
Un Gradle Wrapper SHOULD être versionné lorsqu'il apporte une reproductibilité utile
Groovy DSL et Kotlin DSL sont tous deux reconnus.
`gradle clean` est une opération de maintenance
Aucune commande Maven/Gradle n'est donc ajoutée à la gate documentaire de cette tranche.
```
Les références de navigation vers `520-JAVA_MAVEN_GRADLE.md` ont également été trouvées dans :
```text
RULES.md
docs/rules/000-README.md
```
L'audit Markdown a réussi :
```text
Markdown table audit: clean (2 table(s), 56 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 :
```text
M RULES.md
M VERSION
A deltas/0.0.2/alpha.4.md
M docs/rules/000-README.md
A docs/rules/520-JAVA_MAVEN_GRADLE.md
```
## Défaut exact
Le document contient une arborescence structurée :
```text
src/
├── main/
│ ├── java/
│ └── resources/
└── test/
├── java/
└── resources/
```
mais la gate cherche littéralement la chaîne :
```text
src/main/
```
Cette chaîne n'existe pas dans cette représentation arborescente.
La tranche ne peut donc pas être enregistrée `PASS` tant que sa propre gate n'est pas reproductible telle qu'elle est spécifiée.
## Décision
Aucun REPLAN n'est requis.
Le correctif est local et conserve exactement l'objectif de `alpha.4` :
```text
0.0.2-alpha.4.fix.1
```
Il doit seulement rendre explicites dans le profil les chemins Java canoniques déjà décrits conceptuellement, puis rejouer une gate cohérente.
## Résultat
`0.0.2-alpha.4` est enregistré `FAIL`.
La seule transition autorisée est `0.0.2-alpha.4.fix.1`.

104
history/0.0.2/alpha.5.md Normal file
View File

@@ -0,0 +1,104 @@
<!-- file: history/0.0.2/alpha.5.md -->
<!-- version: 1 -->
# History 0.0.2-alpha.5 — profil plateforme Android
## Statut
PASS
La tranche `0.0.2-alpha.5` a été validée par l'opérateur. Le premier profil plateforme Android est matérialisé sans absorber les spécialisations Rust/JNI, Tauri ou Web différées.
## Baseline
La correction précédente `0.0.2-alpha.4.fix.1` a été enregistrée `PASS`, puis committée et poussée sous le commit observé :
```text
368dedb
```
Version validée après application de `alpha.5` :
```text
0.0.2-alpha.5
```
## Validation opérateur observée
La version et les fichiers attendus ont été confirmés :
```bash
test "$(cat VERSION)" = "0.0.2-alpha.5"
test -f docs/rules/610-ANDROID.md
test -f deltas/0.0.2/alpha.5.md
```
Les contrats principaux du profil Android ont été retrouvés, notamment :
```text
Les profils Rust/JNI et Tauri ne sont pas définis ici.
Dans un dépôt multi-plateforme où une zone Android distincte est nécessaire
Java est le langage applicatif Android par défaut du profil PGR
Android Gradle Plugin
PGR MUST NOT déduire une hausse de `minSdk`
`versionCode` est un compteur Android monotone distinct du SemVer.
`local.properties` est un fichier local Android typique
Les secrets de signature ne sont jamais versionnés.
Une ABI annoncée comme supportée doit disposer d'une preuve adaptée.
JVM unit
`AndroidManifest.xml` MUST déclarer uniquement les permissions
APK debug
PGR lui-même ne contient actuellement aucun projet Android
```
La navigation vers `610-ANDROID.md` a été retrouvée depuis `RULES.md` et `docs/rules/000-README.md`.
L'audit Markdown PGR a réussi :
```text
Markdown table audit: clean (2 table(s), 61 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 RULES.md
M VERSION
A deltas/0.0.2/alpha.5.md
M docs/rules/000-README.md
A docs/rules/610-ANDROID.md
```
## Revue qualitative
Le profil validé conserve les frontières prévues :
- Android possède les contraintes de plateforme, SDK, packaging, signing et compatibilité de target ;
- Java/Gradle restent possédés par le profil langage/build et sont seulement raffinés lorsque la plateforme impose une contrainte ;
- `compileSdk`, `targetSdk` et `minSdk` restent trois contrats distincts ;
- une toolchain moderne ne relève pas automatiquement `minSdk` ;
- `versionCode` reste un compteur Android distinct du SemVer ;
- les niveaux `JVM unit`, instrumentation/intégration et smoke device/AVD ne sont pas confondus ;
- aucune validation Android réelle n'est revendiquée pour PGR lui-même en l'absence d'un projet Android à compiler ou exécuter.
## Résultat
`0.0.2-alpha.5` est validée `PASS`.
Les trois profils technologiques retenus pour `0.0.2` sont maintenant matérialisés :
```text
510 — Rust / Cargo
520 — Java / Maven / Gradle
610 — Android
```
La tranche suivante autorisée est :
```text
0.0.2-beta.1
```
Elle est consacrée à leur réconciliation, à la vérification des owners/scopes/overrides et à la navigation. Aucun nouveau profil technologique majeur n'est autorisé en beta sans REPLAN.

View File

@@ -0,0 +1,75 @@
<!-- file: history/0.0.2/beta.1.fix.1.md -->
<!-- version: 1 -->
# History 0.0.2-beta.1.fix.1 — correction du quoting de la gate beta
## Statut
PASS
Le correctif `0.0.2-beta.1.fix.1` a été validé par l'opérateur. La commande de validation défectueuse de `beta.1` est remplacée par une recherche littérale Bash sûre, sans modification des profils ni des audits introduits en beta.
## Baseline
La tranche `0.0.2-beta.1` a été enregistrée `FAIL`, puis committée sous :
```text
0719955
```
Le premier `git push origin master` a été interrompu à l'invite d'authentification, puis le second a réussi et a publié ce commit sur `origin/master`.
Version validée après application du correctif :
```text
0.0.2-beta.1.fix.1
```
## Validation opérateur observée
La version et le delta attendu ont été confirmés :
```bash
test "$(cat VERSION)" = "0.0.2-beta.1.fix.1"
test -f deltas/0.0.2/beta.1.fix.1.md
```
La recherche littérale corrigée a réussi :
```bash
grep -F 'reste possédée par `RULES.md`.' docs/rules/610-ANDROID.md
```
Sortie observée :
```text
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.
```
Les deux audits PGR ont réussi :
```text
Markdown table audit: clean (2 table(s), 65 file(s))
Markdown link audit: clean (49 local link(s), 65 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.fix.1.md
```
## Résultat
`0.0.2-beta.1.fix.1` est validée `PASS`.
La beta est réconciliée et la tranche suivante autorisée est :
```text
0.0.2-rc.1
```
La RC doit geler le scope, préparer l'entrée candidate `0.0.2` du changelog, finaliser le prompt de démarrage `0.0.3` et exécuter la gate documentaire complète sans introduire de nouveau profil technologique.

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

View File

@@ -0,0 +1,75 @@
<!-- file: history/0.0.2/rc.1.fix.1.md -->
<!-- version: 1 -->
# History 0.0.2-rc.1.fix.1 — correction de l'audit inline des headers
## Statut
PASS
Le correctif `0.0.2-rc.1.fix.1` a été validé par l'opérateur. L'audit ponctuel des headers Markdown s'exécute désormais correctement sans élargir le scope de la RC.
## Baseline
La tranche `0.0.2-rc.1` a été enregistrée `FAIL`, puis committée et poussée sous le commit observé :
```text
8272cfe
```
Version validée après application du correctif :
```text
0.0.2-rc.1.fix.1
```
## Validation opérateur observée
La version et le delta de correction ont été confirmés :
```bash
test "$(cat VERSION)" = "0.0.2-rc.1.fix.1"
test -f deltas/0.0.2/rc.1.fix.1.md
```
Les deux audits PGR permanents ont réussi :
```text
Markdown table audit: clean (2 table(s), 70 file(s))
Markdown link audit: clean (49 local link(s), 70 file(s))
```
L'audit ponctuel des headers Markdown s'est exécuté sans erreur et a produit :
```text
Markdown header audit: clean (70 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/rc.1.fix.1.md
```
## Revue qualitative
Le correctif n'a modifié aucune règle, aucun profil, aucun audit permanent, aucun changelog et aucun prompt.
Le scope RC reste gelé sur les trois profils technologiques retenus et les deux audits PGR monotâches `tables` et `liens locaux`.
La correction concerne exclusivement la forme exécutable de la gate RC.
## Résultat
`0.0.2-rc.1.fix.1` est validée `PASS`.
La promotion stable peut maintenant être préparée sous l'identifiant opérationnel :
```text
rel.001
```
La promotion reste une opération pré-tag. Le tag `v0.0.2` ne doit être créé qu'après validation et history `PASS` de `rel.001`.

115
history/0.0.2/rc.1.md Normal file
View File

@@ -0,0 +1,115 @@
<!-- file: history/0.0.2/rc.1.md -->
<!-- version: 1 -->
# History 0.0.2-rc.1 — gel du scope et préparation de clôture
## Statut
FAIL
La tranche `0.0.2-rc.1` n'est pas enregistrée `PASS` telle quelle.
Les contrôles documentaires principaux, les deux audits PGR et les contrôles Git ont réussi, mais l'audit inline des headers Markdown contenu dans la gate possède une chaîne Python invalide et se termine par une `SyntaxError`.
## Baseline
La tranche précédente `0.0.2-beta.1.fix.1` a été enregistrée `PASS`, puis committée et poussée sous le commit observé :
```text
d0ac835
```
Version contrôlée après application de `rc.1` :
```text
0.0.2-rc.1
```
## Contrôles réussis observés
La version, le prompt de reprise et le delta RC ont été confirmés.
Le `CHANGELOG.md` contient l'entrée `0.0.2` et les trois profils attendus :
```text
510 — Rust / Cargo
520 — Java / Maven / Gradle
610 — Android
```
Le plan confirme le gel du scope RC et l'état `PASS` de `beta.1.fix.1`.
Le prompt `prompts/003-V0_0_3_START_PROMPT.md` contient :
```text
pgr-0.0.2-publish.001-report.md
Prompt manuel de nouvelle session
Partir de v0.0.2
Ce texte doit être présenté spontanément
```
Les deux audits PGR ont réussi :
```text
Markdown table audit: clean (2 table(s), 68 file(s))
Markdown link audit: clean (49 local link(s), 68 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 CHANGELOG.md
M VERSION
A deltas/0.0.2/rc.1.md
M docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
A prompts/003-V0_0_3_START_PROMPT.md
```
## Défaut exact
La gate RC contient un audit Python inline destiné à contrôler les deux premiers headers de chaque fichier Markdown.
Lors de son exécution, la séquence destinée à joindre les erreurs avec un saut de ligne a été matérialisée ainsi :
```text
raise SystemExit('
'.join(errors))
```
Python l'interprète comme une chaîne littérale non terminée et produit :
```text
SyntaxError: unterminated string literal
```
Le défaut appartient uniquement au script inline de validation livré dans `deltas/0.0.2/rc.1.md`.
Aucun défaut de header Markdown n'a été démontré par cette exécution, puisque l'audit n'a pas pu s'exécuter jusqu'au contrôle des fichiers.
## Décision
Aucun REPLAN n'est requis.
Le correctif reste strictement limité à la gate RC :
```text
0.0.2-rc.1.fix.1
```
Le delta RC livré reste immuable.
Le fix rejoue l'audit des headers avec une forme Python qui n'utilise aucune séquence d'échappement ambiguë : chaque erreur est imprimée individuellement puis le processus sort avec le code `1`.
Aucune règle, aucun profil, aucun audit PGR permanent et aucun contenu fonctionnel RC n'est ajouté ou modifié.
## Résultat
`0.0.2-rc.1` est enregistré `FAIL`.
La seule transition autorisée est :
```text
0.0.2-rc.1.fix.1
```

116
history/0.0.2/rel.001.md Normal file
View File

@@ -0,0 +1,116 @@
<!-- file: history/0.0.2/rel.001.md -->
<!-- version: 1 -->
# History 0.0.2-rel.001 — promotion stable pré-tag
## Statut
PASS
La tranche `0.0.2-rel.001` a été validée par l'opérateur.
La promotion stable vers `0.0.2` est cohérente avant création du tag. Le contrôle post-tag `publish.001` reste une étape séparée et doit porter sur l'archive réellement produite depuis le tag `v0.0.2`.
## Baseline
La tranche précédente `0.0.2-rc.1.fix.1` a été validée `PASS`, puis committée et poussée sous le commit observé :
```text
3ba513d
```
Version contrôlée après application de `rel.001` :
```text
0.0.2
```
## Validation opérateur observée
La version stable a été confirmée :
```bash
test "$(cat VERSION)" = "0.0.2"
```
Les marqueurs de clôture stable ont été retrouvés :
```text
README.md
→ La release `0.0.2` ajoute le premier modèle de profils réutilisables
README.md
→ plan historique des premiers profils `0.0.2`
ROADMAP.md
→ `(x) 0.0.2`
docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
→ Plan clôturé par la promotion stable `0.0.2` après validation de `0.0.2-rc.1.fix.1`.
docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
→ Le contrôle post-tag `publish.001` reste une preuve séparée
```
Le `CHANGELOG.md` contient exactement l'entrée :
```text
## 0.0.2
```
Le prompt de reprise `prompts/003-V0_0_3_START_PROMPT.md` existe et référence correctement :
```text
v0.0.2
pgr-v0.0.2.zip
pgr-0.0.2-publish.001-report.md
```
## Pairing deltas / histories
La boucle de contrôle a vérifié que chaque delta `deltas/0.0.2/*.md` antérieur à `rel.001.md` possède son history correspondant.
Aucun history manquant n'a été signalé.
## Audits documentaires
Résultats observés :
```text
Markdown table audit: clean (2 table(s), 72 file(s))
Markdown link audit: clean (50 local link(s), 72 file(s))
Markdown header audit: clean (72 file(s))
```
## Contrôles Git
`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 README.md
M ROADMAP.md
M VERSION
A deltas/0.0.2/rel.001.md
M docs/plans/002-V0_0_2_RULE_PROFILES_PLAN.md
```
## Résultat
`0.0.2-rel.001` est validée `PASS`.
L'état est prêt pour :
```text
1. application du présent history ;
2. commit stable `0.0.2` ;
3. push du commit stable ;
4. création du tag `v0.0.2` sur ce commit ;
5. push du tag ;
6. téléchargement de l'archive ZIP produite depuis ce tag ;
7. contrôle post-tag `publish.001` de cette archive réelle ;
8. production de `pgr-0.0.2-publish.001-report.md`.
```
Le tag ne doit pas être considéré publié correctement tant que `publish.001` n'a pas contrôlé l'archive réellement servie par la forge.

View File

@@ -0,0 +1,46 @@
<!-- file: history/0.0.3/alpha.1.fix.1.md -->
<!-- version: 1 -->
# History 0.0.3-alpha.1.fix.1 — correction du plan Rust/Cargo
## Statut
PASS
La gate documentaire du fix a été exécutée par l'opérateur avec succès. La précision apportée ensuite sur `.cargo/config.toml` et sur la valeur des conventions Rustfmt/Clippy des projets constitue un apport au cadrage de `alpha.2`, sans invalider le résultat observé du fix.
## Baseline et version
La présence de `history/0.0.3/alpha.1.md` dans `HEAD` a été vérifiée par l'opérateur avec `git cat-file -e`. La version contrôlée après application est :
```text
0.0.3-alpha.1.fix.1
```
## Validation opérateur observée
Le terminal fourni pour `~/Projects/pgr` le `2026-09-23` affiche la réussite des contrôles de version, de présence du delta et du history précédent, et d'absence du history courant. Les recherches dans le plan retrouvent sa révision `2`, les `22` crates KSP héritant des lints et les titres des tranches `alpha.2`, `alpha.3` et `alpha.4`.
Les trois audits ont produit :
```text
Markdown table audit: clean (2 table(s), 77 file(s))
Markdown link audit: clean (50 local link(s), 77 file(s))
Markdown header audit: clean (77 file(s))
```
`git diff --check` et `git diff --cached --check` n'ont émis aucun diagnostic. Après ajout des fichiers du delta, le scope observé est :
```text
M VERSION
A deltas/0.0.3/alpha.1.fix.1.md
M docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
```
Le collage du terminal intercale une portion du futur script de contrôle près de la sortie de l'audit de liens, mais la commande Python, son résultat et les contrôles Git apparaissent ensuite séparément. Aucun résultat d'échec n'est présent dans les sorties fournies.
## Décision et transition
`alpha.1.fix.1` est validé `PASS`. Appliquer ce history et committer le fix avant toute application du delta `alpha.2`.
La clarification métier post-gate fixe une convention de départ pour `alpha.2` : `rustfmt.toml` et `clippy.toml` dérivent des configurations éprouvées des deux projets, avec adaptations mineures selon le projet, et `.cargo/config.toml` déplace ordinairement `target-dir` et `build-dir` vers `../builds/<nom-du-projet>/target/`. `alpha.2` peut adapter le plan vivant et livrer ces templates sans réécrire rétrospectivement le delta ou le présent history. Aucun commit de `alpha.1.fix.1` ni résultat de `alpha.2` n'est prétendu observé ici.

55
history/0.0.3/alpha.1.md Normal file
View File

@@ -0,0 +1,55 @@
<!-- file: history/0.0.3/alpha.1.md -->
<!-- version: 1 -->
# History 0.0.3-alpha.1 — cadrage initial
## Statut
PASS
Les contrôles mécaniques demandés par le delta `alpha.1` ont été exécutés par l'opérateur et ont réussi. La revue complémentaire, après ce gate, demande d'élargir le plan des templates Rust à Cargo et Clippy en examinant les archives de référence KSP et Games. Cette précision documentaire sera une tranche `.fix.1` distincte, après application du présent history et commit de `alpha.1`.
## Baseline et version
Baseline déclarée : archive issue du tag `v0.0.2`, accompagnée du rapport `pgr-0.0.2-publish.001-report.md` contrôlé pendant le cadrage. Version validée après application de `alpha.1` :
```text
0.0.3-alpha.1
```
## Validation opérateur observée
L'opérateur a fourni les sorties du `2026-09-23` à `16:41:08`–`16:41:09` depuis `~/Projects/pgr`. Les quatre contrôles de version, présence du plan et du delta, et absence du history courant ont terminé sans erreur :
```text
test "$(cat VERSION)" = '0.0.3-alpha.1'
test -f docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
test -f deltas/0.0.3/alpha.1.md
test ! -e history/0.0.3/alpha.1.md
```
Audits documentaires observés :
```text
Markdown table audit: clean (2 table(s), 75 file(s))
Markdown link audit: clean (50 local link(s), 75 file(s))
Markdown header audit: clean (75 file(s))
```
Les commandes `git diff --check` et `git diff --cached --check` n'ont émis aucun diagnostic. Après `git add` des trois chemins du delta, `git status --short` a affiché :
```text
M VERSION
A deltas/0.0.3/alpha.1.md
A docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
```
La copie fournie du terminal contient un fragment de collage `ck` après le heredoc Python ; les commandes Git et leur sortie apparaissent ensuite séparément et sans erreur. Ce fragment ne modifie pas les trois résultats d'audit ni le scope Git observé.
## Revue post-gate et décision
La revue du plan après réussite mécanique a relevé une lacune de dimensionnement : le profil PGR `510` et les deux projets de référence justifient d'examiner `Cargo.toml` racine, `Cargo.toml` de crate membre et les deux niveaux de configuration Clippy en plus de `rustfmt.toml`.
Les archives de référence ont été fournies après l'exécution de la gate initiale. Leur étude et la correction du plan constituent le scope documentaire de `alpha.1.fix.1` ; elles ne sont pas présentées rétroactivement comme des preuves exécutées par l'opérateur pendant `alpha.1`.
Appliquer le présent history puis committer `alpha.1` avant d'appliquer le delta `alpha.1.fix.1`. Aucun commit, push ou gate de fix n'est déclaré observé ici.

55
history/0.0.3/alpha.2.md Normal file
View File

@@ -0,0 +1,55 @@
<!-- file: history/0.0.3/alpha.2.md -->
<!-- version: 1 -->
# History 0.0.3-alpha.2 — outillage Rust/Cargo partagé
## Statut
PASS
La gate documentaire et TOML de `alpha.2` a été exécutée par l'opérateur avec succès. Une demande ultérieure complète le cadrage des audits Rust à partir des scripts KSP et Games ; elle concerne les tranches suivantes et ne modifie pas rétroactivement le résultat des templates de cette tranche.
## Baseline et version
La présence de `history/0.0.3/alpha.1.fix.1.md` dans `HEAD` a été vérifiée par `git cat-file -e`. Version contrôlée après application :
```text
0.0.3-alpha.2
```
## Validation opérateur observée
Les commandes fournies depuis `~/Projects/pgr` le `2026-09-23` à `22:29:19` confirment la version, la baseline committée et l'absence du history courant. Le contrôle TOML de `rustfmt.toml`, `clippy.toml` et `.cargo/config.toml` affiche :
```text
Rust/Cargo template TOML audit: clean (3 file(s))
```
Les audits documentaires affichent :
```text
Markdown table audit: clean (2 table(s), 80 file(s))
Markdown link audit: clean (55 local link(s), 80 file(s))
Markdown header audit: clean (80 file(s))
```
`git diff --check` et `git diff --cached --check` n'ont émis aucun diagnostic. Après `git add`, le scope observé est :
```text
M VERSION
A deltas/0.0.3/alpha.2.md
M docs/000-README.md
M docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
A docs/templates/001-RUST_CARGO_TOOLING.md
A templates/rust-cargo/.cargo/config.toml
A templates/rust-cargo/clippy.toml
A templates/rust-cargo/rustfmt.toml
```
Le collage du terminal intercale quelques lignes de la commande `git add` dans la zone de sortie des audits ; chaque commande et son résultat apparaissent ensuite séparément. Aucune erreur n'est signalée par les sorties fournies.
## Suite
Le travail approuvé après ce gate demande de comparer les contrôles de format Rust des scripts KSP et Games, de les répartir par propriété monotâche lorsqu'ils doivent être réutilisés, et de distinguer ce que Rustfmt/Clippy possèdent déjà de ce qui exige un audit dédié. Cette revue n'a pas été exécutée par l'opérateur pendant le gate `alpha.2` et ne constitue pas sa preuve PASS.
Appliquer le présent history et committer `alpha.2` avant tout nouveau delta. Aucun commit ou gate ultérieur n'est déclaré observé ici.

48
history/0.0.3/alpha.3.md Normal file
View File

@@ -0,0 +1,48 @@
<!-- file: history/0.0.3/alpha.3.md -->
<!-- version: 1 -->
# History 0.0.3-alpha.3 — audits de style Rust ciblés
## Statut
PASS
L'opérateur a exécuté la gate prescrite pour `alpha.3` dans son dépôt le `2026-09-24`. Les neuf tests des audits Rust et les contrôles documentaires passent. Ce history constate les preuves fournies pour cette tranche, sans préjuger de la validation des manifests Cargo de `alpha.4`.
## Baseline et version
`git cat-file -e HEAD:history/0.0.3/alpha.2.md` a confirmé la présence dans `HEAD` du history de la tranche précédente. L'opérateur a vérifié `VERSION = 0.0.3-alpha.3`, la présence du delta courant, celle du history précédent et l'absence de `history/0.0.3/alpha.3.md` avant sa livraison.
## Validation opérateur observée
Les recherches sur le plan ont confirmé sa révision `4`, la tranche Cargo prévue en `alpha.4` et l'audit des headers Markdown prévu en `alpha.5`.
La commande `python3 -B -m unittest discover -s tests -p test_rust_audits.py -v` a exécuté `9` cas, tous `ok` ; le résultat final est `OK`. Les contrôles documentaires ont affiché :
```text
Markdown table audit: clean (3 table(s), 83 file(s))
Markdown link audit: clean (59 local link(s), 83 file(s))
Markdown header audit: clean (83 file(s))
```
`git diff --check` et `git diff --cached --check` n'ont affiché aucun diagnostic. Après `git add`, le scope indexé fourni est :
```text
M VERSION
A deltas/0.0.3/alpha.3.md
M docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
M docs/rules/510-RUST_CARGO.md
M docs/templates/001-RUST_CARGO_TOOLING.md
M docs/validation/001-VALIDATION_MATRIX.md
A docs/validation/002-RUST_STYLE_AUDITS.md
A scripts/_rust_audit_common.py
A scripts/audit_rust_blank_lines.py
A scripts/audit_rust_const_blocks.py
A tests/test_rust_audits.py
```
Le collage du terminal intercale le début de la commande de contrôle des headers avant la sortie des tests. Les neuf résultats des tests, les sorties des audits et les commandes Git apparaissent ensuite dans la transcription, sans échec signalé.
## Transition
Appliquer ce history et committer la tranche `alpha.3` avant d'appliquer le delta `alpha.4`. Le commit lui-même n'est pas observé dans la preuve fournie. La suite conforme au plan est la livraison des deux templates `Cargo.toml` et de leur documentation d'adaptation, avec sa propre gate opérateur.

54
history/0.0.3/alpha.4.md Normal file
View File

@@ -0,0 +1,54 @@
<!-- file: history/0.0.3/alpha.4.md -->
<!-- version: 1 -->
# History 0.0.3-alpha.4 — manifests Cargo workspace et membre
## Statut
PASS
L'opérateur a exécuté le `2026-09-24` la gate de `alpha.4` avec Cargo disponible. Les deux manifests sont valides ; la vérification en workspace temporaire couvre l'héritage des lints, une erreur `unsafe` attendue sous `forbid`, puis la réussite avec une exception locale déclarée dans la crate.
## Baseline et version
`git cat-file -e HEAD:history/0.0.3/alpha.3.md` a confirmé la présence du history précédent dans `HEAD`. La version après application est `0.0.3-alpha.4`, le delta et le history `alpha.3` sont présents, et `history/0.0.3/alpha.4.md` était absent lors du contrôle.
## Validation opérateur observée
Le contrôle TOML a affiché :
```text
Cargo manifest TOML audit: clean (2 file(s))
```
Le smoke a effectué `cargo metadata` sur un workspace d'essai, puis `cargo check --workspace --offline` et `cargo clippy --workspace --all-targets --all-features --offline -- -D warnings` sur une crate minimale. Après insertion d'un bloc `unsafe`, le test attendu d'interdiction a été satisfait ; `cargo check` est redevenu propre après remplacement de l'héritage par les lints locaux ciblés. Résultat affiché :
```text
Cargo workspace smoke: clean (inherited and local lints)
```
Les audits documentaires affichent :
```text
Markdown table audit: clean (3 table(s), 86 file(s))
Markdown link audit: clean (67 local link(s), 86 file(s))
Markdown header audit: clean (86 file(s))
```
`git diff --check` et `git diff --cached --check` n'ont pas affiché de diagnostic. Après `git add`, l'état indexé fourni contient exactement :
```text
M VERSION
A deltas/0.0.3/alpha.4.md
M docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
M docs/templates/001-RUST_CARGO_TOOLING.md
A docs/templates/002-CARGO_MANIFESTS.md
A templates/rust-cargo/Cargo.toml
A templates/rust-cargo/crates/project-core-lib/Cargo.toml
```
Le terminal intercale certains fragments de la commande de validation dans les sorties du smoke ; les résultats Cargo et les résultats finaux des audits restent identifiables. Aucun échec n'est signalé dans la transcription fournie.
## Transition
Appliquer le présent history et committer la tranche `alpha.4` avant d'appliquer un delta `alpha.5`. La présence de ce futur commit n'est pas déduite des commandes fournies. La tranche suivante concerne le contrôle monotâche des headers Markdown déjà effectué manuellement dans les gates précédentes.

41
history/0.0.3/alpha.5.md Normal file
View File

@@ -0,0 +1,41 @@
<!-- file: history/0.0.3/alpha.5.md -->
<!-- version: 1 -->
# History 0.0.3-alpha.5 — audit des headers Markdown
## Statut
PASS
La gate de `alpha.5` exécutée par l'opérateur le `2026-09-24` a validé le script monotâche des headers Markdown, ses cas positifs et négatifs, et les audits documentaires de PGR.
## Baseline et version
L'opérateur a confirmé `VERSION = 0.0.3-alpha.5`, la présence dans `HEAD` de `history/0.0.3/alpha.4.md` par `git cat-file -e`, l'existence du delta `alpha.5` et l'absence du history courant avant sa livraison. Les révisions internes attendues de `docs/rules/300-DOCUMENTATION.md` et de la matrice sont respectivement `2` et `8`.
## Validation opérateur observée
`python3 -B -m unittest discover -s tests -p test_markdown_headers.py -v` a exécuté `6` tests, tous `ok`, avec résultat final `OK`. Les audits ont affiché :
```text
Markdown header audit: clean (88 file(s))
Markdown table audit: clean (3 table(s), 88 file(s))
Markdown link audit: clean (67 local link(s), 88 file(s))
```
`git diff --check` et `git diff --cached --check` n'ont affiché aucun diagnostic. Après ajout des fichiers du delta, le statut indexé transmis est exactement :
```text
M VERSION
A deltas/0.0.3/alpha.5.md
M docs/rules/300-DOCUMENTATION.md
M docs/validation/001-VALIDATION_MATRIX.md
A scripts/audit_markdown_headers.py
A tests/test_markdown_headers.py
```
Le collage du terminal intercale un fragment d'une commande `git status --short` dans la sortie d'un test. Les six cas, le résumé `OK` et les résultats finaux des trois audits restent lisibles ; aucun échec n'est signalé.
## Transition
Appliquer ce history puis committer `alpha.5` avant le delta `alpha.6`. Le commit futur n'est pas attesté par la transcription fournie. La suite prévue consiste à décider, après comparaison des prompts existants, si une courte spécification de prompt manuel améliore réellement la clôture stable.

40
history/0.0.3/alpha.6.md Normal file
View File

@@ -0,0 +1,40 @@
<!-- file: history/0.0.3/alpha.6.md -->
<!-- version: 1 -->
# History 0.0.3-alpha.6 — prompt manuel de reprise
## Statut
PASS
La gate de `alpha.6` exécutée par l'opérateur le `2026-09-24` valide la spécification courte du prompt manuel de nouvelle session et les renvois documentaires associés.
## Baseline et version
L'opérateur a confirmé `VERSION = 0.0.3-alpha.6`, la présence dans `HEAD` de `history/0.0.3/alpha.5.md` par `git cat-file -e`, la présence de ce history dans le répertoire de travail, du delta `alpha.6` et du template `003`, ainsi que l'absence du history courant et de `prompts/004-V0_0_4_START_PROMPT.md` avant cette livraison. Les révisions internes du workflow et du plan sont respectivement `3` et `6` ; la décision de retenir une spécification manuelle figure bien dans le plan.
## Validation opérateur observée
Les trois audits ont affiché :
```text
Markdown header audit: clean (91 file(s))
Markdown table audit: clean (3 table(s), 91 file(s))
Markdown link audit: clean (69 local link(s), 91 file(s))
```
`git diff --check` et `git diff --cached --check` n'ont affiché aucun diagnostic. Après ajout des fichiers du delta, le statut indexé transmis est exactement :
```text
M VERSION
A deltas/0.0.3/alpha.6.md
M docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
M docs/rules/210-WORKFLOW.md
A docs/templates/003-NEW_SESSION_PROMPT.md
```
Le collage du terminal intercale un fragment de la commande `git add` dans la sortie de l'audit des liens ; son résultat final `clean` et les autres contrôles restent lisibles. Aucun échec n'est signalé.
## Transition
Appliquer ce history puis committer `alpha.6` avant le delta `beta.1`. Le commit futur n'est pas attesté par la transcription fournie. La suite prévue est la réconciliation des responsabilités, de la navigation, des templates et des audits avant la RC.

47
history/0.0.3/beta.1.md Normal file
View File

@@ -0,0 +1,47 @@
<!-- file: history/0.0.3/beta.1.md -->
<!-- version: 1 -->
# History 0.0.3-beta.1 — réconciliation documentaire
## Statut
PASS
La gate `beta.1` exécutée par l'opérateur le `2026-09-24` confirme la navigation des documents vivants, la chaîne des tranches alpha et les validations d'intégration prévues pour la réconciliation.
## Baseline et version
L'opérateur a confirmé `VERSION = 0.0.3-beta.1`, la présence dans `HEAD` de `history/0.0.3/alpha.6.md` par `git cat-file -e`, la présence de ce history et du delta `beta.1`, ainsi que l'absence du history courant et du prompt `004` avant cette livraison. Les révisions attendues sont `5` pour `README.md`, `3` pour l'index documentaire, `7` pour le plan et `9` pour la matrice.
## Validation opérateur observée
`python3 -B -m unittest discover -s tests -p 'test_*.py' -v` a exécuté `15` tests, tous `ok`, avec résultat final `OK`. Les audits documentaires ont affiché :
```text
Markdown header audit: clean (93 file(s))
Markdown table audit: clean (3 table(s), 93 file(s))
Markdown link audit: clean (76 local link(s), 93 file(s))
```
La vérification de la chaîne et des modèles TOML a affiché :
```text
Reconciliation audit: clean (7 PASS histories, 5 TOML files)
```
`git diff --check` et `git diff --cached --check` n'ont affiché aucun diagnostic. Après ajout des fichiers du delta, le statut indexé transmis est exactement :
```text
M README.md
M VERSION
A deltas/0.0.3/beta.1.md
M docs/000-README.md
M docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
M docs/validation/001-VALIDATION_MATRIX.md
```
Le collage du terminal intercale des fragments de commandes et de sorties des tests ; leurs résumés `OK`, les résultats finaux des audits et le statut Git restent lisibles. Aucun échec n'est signalé.
## Transition
Appliquer ce history et committer `beta.1` avant le delta `rc.1`. Le commit futur n'est pas attesté par la transcription fournie. La RC préparera l'entrée candidate du changelog et le prompt de `0.0.4`, puis exécutera sa propre gate ; le présent PASS ne valide pas cette RC par anticipation.

41
history/0.0.3/rc.1.md Normal file
View File

@@ -0,0 +1,41 @@
<!-- file: history/0.0.3/rc.1.md -->
<!-- version: 1 -->
# History 0.0.3-rc.1 — gel du scope et préparation de release
## Statut
PASS
La gate de release candidate `rc.1` exécutée par l'opérateur le `2026-09-24` confirme le gel du périmètre, l'entrée candidate du changelog, le prompt `004` et l'intégration documentaire.
## Baseline et version
L'opérateur a confirmé `VERSION = 0.0.3-rc.1`, la présence dans `HEAD` de `history/0.0.3/beta.1.md` par `git cat-file -e`, la présence de ce history, du delta RC et du prompt `004`, ainsi que l'absence du history RC avant cette livraison. Les révisions internes attendues sont `4` pour `CHANGELOG.md` et `8` pour le plan. Le changelog porte l'intitulé `0.0.3 (candidate)` ; le prompt prévoit le rapport post-tag seulement si son résultat réel est PASS.
## Validation opérateur observée
`python3 -B -m unittest discover -s tests -p 'test_*.py' -v` a exécuté `15` tests, tous `ok`, et s'est terminé par `OK`. Les audits ont affiché :
```text
Markdown header audit: clean (96 file(s))
Markdown table audit: clean (3 table(s), 96 file(s))
Markdown link audit: clean (79 local link(s), 96 file(s))
RC integration audit: clean (8 PASS histories, 5 TOML files)
```
`git diff --check` et `git diff --cached --check` n'ont affiché aucun diagnostic. Le statut indexé observé après ajout des fichiers du delta est :
```text
M CHANGELOG.md
M VERSION
A deltas/0.0.3/rc.1.md
M docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
A prompts/004-V0_0_4_START_PROMPT.md
```
Le collage du terminal intercale des fragments de commandes et la sortie des tests ; les résumés `OK`, les résultats finaux des audits et le statut Git restent lisibles. Aucun échec n'est signalé.
## Transition
Appliquer ce history puis committer `rc.1` avant le delta stable `rel.001`. Le commit futur n'est pas attesté par la transcription fournie. Ce PASS n'atteste ni la promotion stable, ni le tag `v0.0.3`, ni le contrôle de l'archive publiée après le tag.

50
history/0.0.3/rel.001.md Normal file
View File

@@ -0,0 +1,50 @@
<!-- file: history/0.0.3/rel.001.md -->
<!-- version: 1 -->
# History 0.0.3 rel.001 — clôture stable pré-tag
## Statut
PASS
La gate stable pré-tag `rel.001` exécutée par l'opérateur le `2026-09-24` valide la promotion documentaire de `0.0.3`. Ce résultat porte sur l'état du dépôt avant le commit et le tag stables ; il ne valide pas l'archive téléchargée ensuite depuis Gitea.
## Baseline et version
L'opérateur a confirmé `VERSION = 0.0.3`, la présence dans `HEAD` de `history/0.0.3/rc.1.md` par `git cat-file -e`, la présence de ce history, du delta stable et du prompt `004`, ainsi que l'absence du présent history avant sa livraison. Les révisions attendues sont `6` pour `README.md`, `4` pour `ROADMAP.md`, `5` pour `CHANGELOG.md`, `4` pour l'index `docs/` et `9` pour le plan.
La présentation de la release dans `README.md`, le statut `(x)` de `0.0.3` dans la roadmap, l'entrée `## 0.0.3` du changelog, le statut historique du plan et la séparation du contrôle post-tag ont été vérifiés par les commandes de la gate.
## Validation opérateur observée
La vérification des deltas et histories antérieurs a affiché :
```text
Stable history audit: clean (9 PASS histories, rel.001 pending)
```
Les trois audits Markdown ont affiché :
```text
Markdown header audit: clean (98 file(s))
Markdown table audit: clean (3 table(s), 98 file(s))
Markdown link audit: clean (79 local link(s), 98 file(s))
```
`git diff --check` et `git diff --cached --check` n'ont affiché aucun diagnostic. Après ajout des fichiers du delta, le statut indexé transmis est :
```text
M CHANGELOG.md
M README.md
M ROADMAP.md
M VERSION
A deltas/0.0.3/rel.001.md
M docs/000-README.md
M docs/plans/003-V0_0_3_TEMPLATES_AUDITS_PLAN.md
```
Le collage du terminal intercale un fragment de commande dans la sortie de l'audit des tableaux ; son résultat final `clean` et les autres résultats restent lisibles. Les tests et la syntaxe des modèles TOML validés en RC n'ont pas été rejoués dans cette gate documentaire ; aucun code, script, test ni modèle technique ne change pendant `rel.001`.
## Transition
Appliquer ce history puis committer la stable. Ensuite seulement, créer et publier le tag `v0.0.3`, télécharger l'archive source associée depuis Gitea et exécuter une vérification post-tag séparée. Le commit stable, le tag, la publication et le résultat de cette vérification ne sont pas attestés par la transcription reçue ; aucun statut `publish.001` ne peut encore être consigné.

View File

@@ -0,0 +1,146 @@
<!-- file: prompts/003-V0_0_3_START_PROMPT.md -->
<!-- version: 1 -->
# Prompt de démarrage 0.0.3 — templates initiaux et audits réutilisables
## Base et cible
Dépôt canonique :
```text
https://git.sasedev.com/Sasedev/pgr
```
Baseline attendue au démarrage effectif de `0.0.3` : archive source issue du tag stable :
```text
v0.0.2
```
L'archive taggée Gitea est la baseline autoritaire du dépôt. Elle peut légitimement ne pas contenir `.git`.
Version cible :
```text
0.0.3
```
Première tranche attendue :
```text
0.0.3-alpha.1
```
## Entrées de reprise à fournir
La nouvelle session doit recevoir au minimum :
```text
pgr-v0.0.2.zip
```
après téléchargement depuis le tag Gitea `v0.0.2`.
Après la publication stable, la session de clôture doit également produire une preuve post-tag séparée, normalement :
```text
pgr-0.0.2-publish.001-report.md
```
Si ce rapport existe et que `publish.001` est `PASS`, il SHOULD être fourni à la nouvelle session avec l'archive taggée. Il complète la preuve d'intake mais ne remplace jamais l'audit de l'archive par la nouvelle session et ne fait pas partie du tag stable.
Si le rapport n'a pas été produit ou n'est pas disponible, la nouvelle session doit l'indiquer explicitement au lieu d'en supposer l'existence.
## Prompt manuel de nouvelle session
Après `publish.001 PASS`, le texte manuel canonique à utiliser pour ouvrir la session `0.0.3` est :
```text
Partir de v0.0.2 (téléchargé via le lien ZIP de la version taggée sur Gitea) et du rapport post-tag pgr-0.0.2-publish.001-report.md, lire et exécuter prompts/003-V0_0_3_START_PROMPT.md, faire une vérification complète de l'archive et surtout des règles, de la gouvernance, de la structure documentaire, des deltas/histories et de la cohérence globale avant de démarrer 0.0.3-alpha.1.
```
Ce texte doit être présenté spontanément à l'opérateur pendant la clôture stable de `0.0.2`; il ne doit pas dépendre d'une demande supplémentaire.
## Mission
`0.0.3` doit introduire les premiers templates techniques réutilisables et les premiers patterns d'audit issus de besoins réellement démontrés par les profils `0.0.2` et par les projets de référence.
La release ne doit pas chercher à construire un catalogue exhaustif. `alpha.1` MUST commencer par auditer intégralement la stable `v0.0.2`, vérifier les profils et audits réellement présents, inventorier les templates/patterns qui apportent une valeur immédiate et découper la version en tranches proportionnées avant de matérialiser massivement des fichiers.
## Acquis de `0.0.2`
La baseline stable attendue doit notamment contenir :
```text
docs/architecture/003-RULE_PROFILE_MODEL.md
docs/rules/500-LANGUAGES.md
docs/rules/510-RUST_CARGO.md
docs/rules/520-JAVA_MAVEN_GRADLE.md
docs/rules/600-PLATFORMS.md
docs/rules/610-ANDROID.md
scripts/audit_markdown_tables.py
scripts/audit_markdown_links.py
```
Les profils matérialisés sont volontairement limités à Rust/Cargo, Java/Maven/Gradle et Android. Les autres domaines restent différés et ne deviennent pas automatiquement le scope de `0.0.3`.
## Principes pour les templates
Un template `0.0.3` doit :
- répondre à un besoin concret et répété ;
- avoir un owner et un scope clairs ;
- respecter les structures canoniques de l'écosystème ;
- rester minimal et paramétrable plutôt que copier un projet complet ;
- ne pas figer des versions arbitraires de toolchain ou de dépendances ;
- ne pas introduire un générateur tant que la spécification Markdown du template suffit ;
- rester distinct d'une skeleton specification complète, réservée à `0.0.4`.
Les templates de workflow, notamment la forme du prompt manuel de nouvelle session et la transmission explicite d'une preuve `publish.001`, MAY être examinés en `0.0.3` s'ils peuvent être factorisés sans créer un générateur prématuré.
## Principes pour les audits
Les audits PGR restent read-only, déterministes et monotâches autant que raisonnablement possible.
Le point de départ est le besoin réellement éprouvé :
```text
tables Markdown
liens Markdown locaux
```
Les audits plus complexes de KSP ou `sasedev-games` sont des corpus de comparaison. `0.0.3` doit les décomposer par propriété stable au lieu de copier leurs scripts combinés tels quels.
Un audit spécialisé n'est matérialisé que lorsqu'il possède :
- une propriété objectivement contrôlable ;
- un owner documentaire ;
- un sujet réel dans un template, skeleton ou projet ;
- une valeur distincte d'un compilateur, linter ou build tool officiel.
## Hors périmètre attendu
Sauf REPLAN justifié, `0.0.3` ne doit pas encore :
- créer les skeleton specifications complètes prévues pour `0.0.4` ;
- créer un générateur PGR ;
- réécrire KSP ou `sasedev-games` ;
- matérialiser tous les profils technologiques différés ;
- transformer des exemples de configuration en versions obligatoires universelles ;
- regrouper plusieurs contrôles indépendants dans un audit monolithique uniquement pour réduire le nombre de scripts.
## Règles de travail
Le cycle PGR reste :
```text
delta N
→ validation opérateur
→ history N
→ commit N
→ delta N+1
```
Le delta suivant MUST NOT être appliqué avant le commit de la tranche courante.
Une interruption de session ne crée pas une nouvelle version. Reprendre depuis la dernière tranche réellement committée et son history ; produire un handoff uniquement lorsqu'il apporte une valeur réelle.

View File

@@ -0,0 +1,44 @@
<!-- file: prompts/004-V0_0_4_START_PROMPT.md -->
<!-- version: 1 -->
# Prompt de démarrage 0.0.4 — spécifications de skeletons
## Baseline et cible
Dépôt canonique : `https://git.sasedev.com/Sasedev/pgr`.
La baseline attendue au démarrage effectif de `0.0.4` est l'archive source téléchargée depuis le tag Gitea `v0.0.3`, dont le nom attendu est `pgr-v0.0.3.zip`. Une archive source peut légitimement ne pas contenir `.git` ; vérifier son contenu et ses artefacts de gouvernance sans lui attribuer une preuve Git qu'elle ne peut contenir.
Version cible : `0.0.4`. Première tranche attendue : `0.0.4-alpha.1`.
Si un rapport séparé `pgr-0.0.3-publish.001-report.md` a effectivement été produit et conclut `PASS`, le fournir avec l'archive. S'il est absent ou non validé, le signaler explicitement ; ne jamais présumer la publication ou un résultat PASS. Ce rapport ne fait pas partie du tag et ne remplace pas l'audit de la nouvelle session.
## Reprise manuelle après publication
Après vérification réelle de l'archive du tag et du rapport post-tag PASS, remettre spontanément à l'opérateur un message de reprise adapté selon [`docs/templates/003-NEW_SESSION_PROMPT.md`](../docs/templates/003-NEW_SESSION_PROMPT.md). Si les noms attendus ci-dessus sont confirmés et le rapport est PASS, le texte est :
```text
Partir de l'archive pgr-v0.0.3.zip téléchargée depuis le tag Gitea v0.0.3 et du rapport post-tag pgr-0.0.3-publish.001-report.md. Lire et exécuter prompts/004-V0_0_4_START_PROMPT.md. Vérifier l'archive, les règles, la gouvernance, la structure documentaire, les deltas/histories et la cohérence globale avant de préparer 0.0.4-alpha.1.
```
Si le rapport manque ou n'est pas PASS, supprimer sa mention de la phrase et transmettre son état réel séparément. Adapter les noms à ceux des fichiers effectivement téléchargés. Ce texte ne doit être remis qu'après clôture stable et vérification post-tag, jamais comme attestation anticipée au stade RC.
## Mission
Définir les premières skeleton specifications Markdown réutilisables et les règles pratiques de composition des profils, templates et choix propres au projet. Un skeleton décrit une procédure de sélection, les fichiers et profils applicables, les décisions à prendre et une validation proportionnée ; il ne génère pas automatiquement un projet et ne fixe pas son architecture pour toujours.
`alpha.1` MUST vérifier entièrement la stable `v0.0.3`, en particulier les règles `200` à `610`, les cinq modèles Rust/Cargo, les trois audits Markdown, les deux audits de style Rust facultatifs, la chaîne de deltas/histories et les limites annoncées. Elle doit établir quels skeletons répondent déjà à un besoin concret et lesquels exigent encore des templates ou des décisions préalables. Planifier ensuite les tranches proportionnées de `0.0.4` avant toute matérialisation importante.
## Principes de conception
- Conserver un propriétaire normatif unique par règle et une copie autonome des règles/configurations pertinentes dans chaque projet instancié.
- Respecter la séparation : règles applicables sous `docs/rules/`, fichiers techniques copiables sous `templates/`, mode d'adaptation sous `docs/templates/`, spécifications de skeletons Markdown et audits read-only pour les propriétés réellement contrôlables.
- Sélectionner seulement les profils et templates justifiés par le type de projet ; documenter explicitement le nom, la version, les cibles, les dépendances et les exceptions qui dépendent du destinataire.
- Ne pas déclarer universelles les valeurs `0.1.0`, `2024`, les seuils Clippy ou les chemins d'exemple des templates Rust/Cargo.
- Préserver les décisions d'ordre sémantique des constantes : l'audit correspondant n'est pas une gate globale de tout workspace Rust.
- Différer les skeletons Java/Android, Web, JNI, Tauri et autres familles dont les pièces nécessaires ou les propriétaires manquent encore ; un nouveau domaine demande un cadrage justifié.
- Garder les audits ciblés et non redondants avec les outils officiels ; les tests prouvent des comportements utiles, sans quota arbitraire de couverture.
## Workflow
Suivre `RULES.md`, [`docs/rules/210-WORKFLOW.md`](../docs/rules/210-WORKFLOW.md) et [`docs/rules/400-VALIDATION.md`](../docs/rules/400-VALIDATION.md). La séquence reste delta → gate opérateur → history constaté → application du history → commit → delta suivant. Un changement de session ne crée pas une version nouvelle. Un rapport de publication post-tag est séparé de la validation pré-tag.

View File

@@ -0,0 +1,144 @@
# file: scripts/_rust_audit_common.py
# version: 1
"""Small shared lexical and file-selection helpers for read-only Rust audits."""
from __future__ import annotations
import pathlib
_IGNORED = frozenset({".git", ".venv", "__pycache__", "target", "builds"})
def selected_files(raw_paths: list[str]) -> tuple[list[pathlib.Path], list[str]]:
"""Select explicit Rust files and directories, without following generated trees."""
files: set[pathlib.Path] = set()
errors: list[str] = []
for raw in raw_paths:
path = pathlib.Path(raw)
if path.is_dir():
files.update(
candidate
for candidate in path.rglob("*.rs")
if candidate.is_file() and not (set(candidate.parts) & _IGNORED)
)
elif path.is_file() and path.suffix == ".rs":
files.add(path)
else:
errors.append(f"unsupported or missing Rust path: {path}")
return sorted(files), errors
def mask_source(text: str) -> tuple[str, set[int]]:
"""Mask comments and literals, preserving offsets and structural punctuation.
Return line numbers whose first character is inside a multiline literal, so
an empty line in a raw string cannot be mistaken for an empty code line.
This is a lexical helper, not a full Rust parser or a compiler substitute.
"""
output = list(text)
protected: set[int] = set()
index = 0
line = 1
state = "code"
block_depth = 0
raw_hashes = 0
while index < len(text):
char = text[index]
nxt = text[index + 1] if index + 1 < len(text) else ""
if char == "\n":
line += 1
if state in {"string", "raw_string"}:
protected.add(line)
if state == "line_comment":
state = "code"
index += 1
continue
if state == "code":
if char == "/" and nxt in {"/", "*"}:
output[index:index + 2] = [" ", " "]
state = "line_comment" if nxt == "/" else "block_comment"
block_depth = 1 if nxt == "*" else 0
index += 2
continue
if char == '"':
output[index] = " "
state = "string"
index += 1
continue
if char == "'":
# Lifetimes have no nearby closing quote; char literals do.
probe = index + 1
escaped = False
found = False
while probe < min(len(text), index + 8) and text[probe] != "\n":
if text[probe] == "'" and not escaped:
found = True
break
escaped = text[probe] == "\\" and not escaped
probe += 1
if found:
output[index] = " "
state = "char"
index += 1
continue
# Also covers r#"..."#, br#"..."# and cr#"..."#.
if char == "r" and (index == 0 or text[index - 1] not in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"):
probe = index + 1
while probe < len(text) and text[probe] == "#":
probe += 1
if probe < len(text) and text[probe] == '"':
output[index:probe + 1] = [" "] * (probe + 1 - index)
raw_hashes = probe - index - 1
state = "raw_string"
index = probe + 1
continue
index += 1
continue
if state == "line_comment":
output[index] = " "
elif state == "block_comment":
output[index] = " "
if char == "/" and nxt == "*":
output[index + 1] = " "
block_depth += 1
index += 2
continue
if char == "*" and nxt == "/":
output[index + 1] = " "
block_depth -= 1
if block_depth == 0:
state = "code"
index += 2
continue
elif state in {"string", "char"}:
output[index] = " "
if char == "\\" and index + 1 < len(text):
if text[index + 1] != "\n":
output[index + 1] = " "
index += 2
continue
if char == ('"' if state == "string" else "'"):
state = "code"
elif state == "raw_string":
output[index] = " "
if char == '"' and text.startswith("#" * raw_hashes, index + 1):
output[index + 1:index + 1 + raw_hashes] = [" "] * raw_hashes
index += 1 + raw_hashes
state = "code"
continue
index += 1
return "".join(output), protected
def line_depths(masked: str) -> list[int]:
"""Return brace depth at the start of each line, excluding literals."""
depths: list[int] = []
depth = 0
for line in masked.splitlines():
depths.append(depth)
depth = max(0, depth + line.count("{") - line.count("}"))
return depths

View File

@@ -0,0 +1,96 @@
#!/usr/bin/env python3
# file: scripts/audit_markdown_headers.py
# version: 1
"""Validate path and positive revision in selected Markdown file headers."""
from __future__ import annotations
import argparse
import pathlib
import re
import sys
_IGNORED_DIRECTORIES = frozenset({".git", ".idea", ".venv", "__pycache__", "dist", "node_modules", "target"})
_VERSION = re.compile(r"<!-- version: [1-9][0-9]* -->")
def _selected_files(raw_paths: list[str], root: pathlib.Path) -> tuple[list[pathlib.Path], list[str]]:
files: set[pathlib.Path] = set()
errors: list[str] = []
for raw_path in raw_paths:
path = pathlib.Path(raw_path)
if path.is_dir() or path.is_file():
if not path.resolve().is_relative_to(root):
errors.append(f"Markdown header audit: path outside project root: {path}")
continue
if path.is_dir():
candidates = (
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":
candidates = iter((path,))
else:
errors.append(f"Markdown header audit: unsupported or missing path: {path}")
continue
for candidate in candidates:
canonical = candidate.resolve()
if not canonical.is_relative_to(root):
errors.append(f"Markdown header audit: path outside project root: {candidate}")
else:
files.add(canonical)
return sorted(files), errors
def _audit_file(path: pathlib.Path, root: pathlib.Path) -> list[str]:
relative = path.relative_to(root).as_posix()
lines = path.read_text(encoding="utf-8").splitlines()
errors: list[str] = []
expected_file = f"<!-- file: {relative} -->"
if not lines or lines[0] != expected_file:
errors.append(f"{relative}:1: expected `{expected_file}`")
if len(lines) < 2 or _VERSION.fullmatch(lines[1]) is None:
errors.append(f"{relative}:2: expected positive `<!-- version: N -->`")
return errors
def main() -> int:
"""Run the read-only Markdown header audit from the project root."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("paths", nargs="+", help="Markdown files or directories to audit")
args = parser.parse_args()
root = pathlib.Path.cwd().resolve()
files, selection_errors = _selected_files(args.paths, root)
if selection_errors or not files:
for error in selection_errors or ["Markdown header audit: no Markdown files selected"]:
print(error, file=sys.stderr)
return 2
errors: list[str] = []
for path in files:
try:
errors.extend(_audit_file(path, root))
except (OSError, UnicodeError) as error:
print(f"Markdown header audit: cannot read {path}: {error}", file=sys.stderr)
return 2
for error in errors:
print(error, file=sys.stderr)
if errors:
print(f"Markdown header audit: {len(errors)} error(s) across {len(files)} file(s)", file=sys.stderr)
return 1
print(f"Markdown header audit: clean ({len(files)} file(s))")
return 0
if __name__ == "__main__":
raise SystemExit(main())

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())

View File

@@ -0,0 +1,205 @@
#!/usr/bin/env python3
# file: scripts/audit_markdown_tables.py
# version: 1
"""Validate source formatting of Markdown tables in explicitly selected paths."""
from __future__ import annotations
import argparse
import pathlib
import re
import sys
_SEPARATOR = re.compile(r"^:?-{3,}:?$")
_IGNORED_DIRECTORIES = frozenset({".git", ".idea", ".venv", "__pycache__", "dist", "node_modules", "target"})
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 table audit: unsupported or missing path: {path}")
return sorted(set(files)), errors
def _is_row(line: str) -> bool:
return line.startswith("|") and line.endswith("|")
def _cells(line: str) -> list[str]:
return line.split("|")[1:-1]
def _separator_marker(cell: str) -> str | None:
marker = cell.strip()
return marker if _SEPARATOR.fullmatch(marker) is not None else None
def _is_separator_row(line: str) -> bool:
if not _is_row(line):
return False
cells = _cells(line)
return bool(cells) and all(_separator_marker(cell) is not None for cell in cells)
def _alignment(marker: str) -> str:
if marker.startswith(":") and marker.endswith(":"):
return "center"
if marker.endswith(":"):
return "right"
return "left"
def _padding(cell: str) -> tuple[int, int]:
return len(cell) - len(cell.lstrip(" ")), len(cell) - len(cell.rstrip(" "))
def _validate_table(path: pathlib.Path, start_line: int, rows: list[str]) -> list[str]:
errors: list[str] = []
if any("\\|" in row for row in rows):
errors.append(f"{path}:{start_line}: escaped pipe is forbidden inside a table cell")
parsed = [_cells(row) for row in rows]
column_count = len(parsed[0])
for offset, row in enumerate(parsed):
if len(row) != column_count:
errors.append(f"{path}:{start_line + offset}: table row has {len(row)} columns; expected {column_count}")
return errors
for column in range(column_count):
raw_cells = [row[column] for row in parsed]
widths = [len(cell) for cell in raw_cells]
expected_width = widths[0]
if any(width != expected_width for width in widths):
errors.append(f"{path}:{start_line}: column {column + 1} is not vertically aligned; raw widths are {widths}")
continue
marker = _separator_marker(raw_cells[1])
if marker is None:
errors.append(f"{path}:{start_line + 1}: separator for column {column + 1} is malformed")
continue
content_cells = [cell for index, cell in enumerate(raw_cells) if index != 1]
longest_content = max(len(cell.strip()) for cell in content_cells)
required_width = max(longest_content + 2, 3 + marker.count(":"))
if expected_width != required_width:
errors.append(
f"{path}:{start_line}: column {column + 1} width is {expected_width}; expected {required_width}"
)
continue
alignment = _alignment(marker)
for cell in content_cells:
content_width = len(cell.strip())
left, right = _padding(cell)
expected_padding = expected_width - content_width
if content_width + left + right != len(cell) or left < 1 or right < 1:
errors.append(f"{path}:{start_line}: column {column + 1} must use spaces only for outer padding")
break
if alignment == "left" and (left != 1 or right != expected_padding - 1):
errors.append(f"{path}:{start_line}: column {column + 1} must be source-aligned to the left")
break
if alignment == "right" and (right != 1 or left != expected_padding - 1):
errors.append(f"{path}:{start_line}: column {column + 1} must be source-aligned to the right")
break
if alignment == "center" and abs(left - right) > 1:
errors.append(f"{path}:{start_line}: column {column + 1} must be source-aligned to the center")
break
if len(raw_cells[1]) != expected_width or _SEPARATOR.fullmatch(raw_cells[1]) is None:
errors.append(f"{path}:{start_line + 1}: separator for column {column + 1} must fill the column width")
return errors
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
index = 0
while index < len(lines):
stripped = lines[index].lstrip()
if stripped.startswith("```") or stripped.startswith("~~~"):
marker = stripped[:3]
if fence is None:
fence = marker
elif fence == marker:
fence = None
index += 1
continue
if fence is not None:
index += 1
continue
if index + 1 < len(lines) and _is_row(lines[index]) and _is_separator_row(lines[index + 1]):
start = index
rows = [lines[index], lines[index + 1]]
index += 2
while index < len(lines) and _is_row(lines[index]):
rows.append(lines[index])
index += 1
tables += 1
errors.extend(_validate_table(path, start + 1, rows))
continue
index += 1
return tables, errors
def main() -> int:
"""Run the read-only Markdown table 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 table audit: no Markdown files selected", file=sys.stderr)
return 2
table_count = 0
errors: list[str] = []
for path in files:
current_count, current_errors = _audit_file(path)
table_count += current_count
errors.extend(current_errors)
if errors:
for error in errors:
print(error, file=sys.stderr)
print(f"Markdown table audit: {len(errors)} error(s) across {len(files)} file(s)", file=sys.stderr)
return 1
print(f"Markdown table audit: clean ({table_count} table(s), {len(files)} file(s))")
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,83 @@
#!/usr/bin/env python3
# file: scripts/audit_rust_blank_lines.py
# version: 1
"""Audit blank-line spacing in explicitly selected Rust sources."""
from __future__ import annotations
import argparse
import pathlib
import re
import sys
from _rust_audit_common import line_depths, mask_source, selected_files
_BODY = re.compile(r"^\s*(?:(?:pub(?:\([^)]*\))?|async|const|unsafe|extern|default)\s+)*(fn|struct|enum)\b")
def audit_file(path: pathlib.Path) -> list[str]:
"""Check successive empty lines and empty function/struct/enum body lines."""
text = path.read_text(encoding="utf-8")
lines = text.splitlines()
masked, protected = mask_source(text)
masked_lines = masked.splitlines()
depths = line_depths(masked)
errors: list[str] = []
previous_blank = False
pending: tuple[str, int] | None = None
active: tuple[str, int] | None = None
for number, (original, code, depth) in enumerate(zip(lines, masked_lines, depths, strict=True), 1):
blank = not original.strip() and number not in protected
if blank and previous_blank:
errors.append(f"{path}:{number}: consecutive blank Rust source lines")
previous_blank = blank
if active is not None and depth <= active[1]:
active = None
if active is not None and blank:
errors.append(f"{path}:{number}: blank line inside {active[0]} body")
if active is None and pending is None:
match = _BODY.match(code)
if match is not None:
pending = (match.group(1), depth)
if pending is not None:
if "{" in code:
active = pending
pending = None
elif ";" in code:
pending = None
return errors
def main() -> int:
"""Run the read-only spacing audit on explicitly selected Rust files."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("paths", nargs="+", help="Rust files or directories to inspect")
args = parser.parse_args()
files, errors = selected_files(args.paths)
if errors or not files:
for error in errors or ["no Rust files selected"]:
print(f"Rust blank-line audit: {error}", file=sys.stderr)
return 2
for path in files:
try:
errors.extend(audit_file(path))
except (OSError, UnicodeError) as error:
print(f"Rust blank-line audit: cannot read {path}: {error}", file=sys.stderr)
return 2
for error in errors:
print(error, file=sys.stderr)
if errors:
print(f"Rust blank-line audit: {len(errors)} error(s) across {len(files)} file(s)", file=sys.stderr)
return 1
print(f"Rust blank-line audit: clean ({len(files)} file(s))")
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,109 @@
#!/usr/bin/env python3
# file: scripts/audit_rust_const_blocks.py
# version: 1
"""Audit top-level Rust const blocks for visibility, names and spacing."""
from __future__ import annotations
import argparse
import pathlib
import re
import sys
from _rust_audit_common import line_depths, mask_source, selected_files
_CONST = re.compile(r"^\s*(?:(pub|pub\(crate\))\s+)?const\s+([A-Za-z_][A-Za-z0-9_]*)\s*:")
def _natural_key(value: str) -> tuple[tuple[int, object], ...]:
parts = re.findall(r"[A-Za-z_]+|[0-9]+", value)
return tuple((1, int(part)) if part.isdigit() else (0, part) for part in parts)
def _end_of_const(lines: list[str], start: int) -> int:
"""Find the terminating semicolon outside brackets and initializer braces."""
brackets: list[str] = []
closing = {"}": "{", ")": "(", "]": "["}
for index in range(start, len(lines)):
for char in lines[index]:
if char in "{([":
brackets.append(char)
elif char in "})]" and brackets and brackets[-1] == closing[char]:
brackets.pop()
elif char == ";" and not brackets:
return index
return start
def audit_file(path: pathlib.Path) -> list[str]:
"""Compare adjacent top-level const declarations in homogeneous blocks."""
text = path.read_text(encoding="utf-8")
lines = text.splitlines()
masked, _ = mask_source(text)
code_lines = masked.splitlines()
depths = line_depths(masked)
errors: list[str] = []
previous: tuple[int, int, int, str] | None = None # end, line, visibility rank, name
index = 0
while index < len(lines):
code = code_lines[index]
if depths[index] != 0:
index += 1
continue
match = _CONST.match(code)
if match is not None:
visibility, name = match.groups()
rank = {"pub": 0, "pub(crate)": 1, None: 2}[visibility]
if previous is not None:
end, _, last_rank, last_name = previous
if rank < last_rank:
errors.append(f"{path}:{index + 1}: const visibility must be pub, pub(crate), private")
if rank == last_rank and _natural_key(name) < _natural_key(last_name):
errors.append(f"{path}:{index + 1}: const names out of alphabetical order: {last_name}, {name}")
between = lines[end + 1:index]
if all(not candidate.strip() for candidate in between):
expected = 0 if rank == last_rank else 1
if len(between) != expected:
errors.append(f"{path}:{index + 1}: expected {expected} blank line(s) between const declarations")
end = _end_of_const(code_lines, index)
previous = (end, index + 1, rank, name)
index = end + 1
continue
# Comments, attributes and whitespace attach to the surrounding block.
if code.strip() and not lines[index].lstrip().startswith(("//", "/*", "*", "#[")):
previous = None
index += 1
return errors
def main() -> int:
"""Run the read-only top-level const-block audit."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("paths", nargs="+", help="Rust files or directories to inspect")
args = parser.parse_args()
files, errors = selected_files(args.paths)
if errors or not files:
for error in errors or ["no Rust files selected"]:
print(f"Rust const-block audit: {error}", file=sys.stderr)
return 2
for path in files:
try:
errors.extend(audit_file(path))
except (OSError, UnicodeError) as error:
print(f"Rust const-block audit: cannot read {path}: {error}", file=sys.stderr)
return 2
for error in errors:
print(error, file=sys.stderr)
if errors:
print(f"Rust const-block audit: {len(errors)} error(s) across {len(files)} file(s)", file=sys.stderr)
return 1
print(f"Rust const-block audit: clean ({len(files)} file(s))")
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,7 @@
# file: templates/rust-cargo/.cargo/config.toml
# version: 1
# Replace project-name with a unique name before using this configuration.
[build]
target-dir = "../builds/project-name/target"
build-dir = "../builds/project-name/target"

View File

@@ -0,0 +1,41 @@
# file: templates/rust-cargo/Cargo.toml
# version: 1
[workspace]
resolver = "3"
members = ["crates/project-core-lib"]
[workspace.package]
# Replace this example with the release-unit version before adopting this template.
version = "0.1.0"
edition = "2024"
publish = false
# Add license, repository, and authors only with the project's real values.
[workspace.dependencies]
# Add dependencies actually shared by multiple crates, with reviewed versions.
[workspace.lints.rust]
missing_docs = "warn"
unreachable_pub = "deny"
unsafe_code = "forbid"
[workspace.lints.clippy]
unwrap_used = "deny"
expect_used = "deny"
implicit_return = "deny"
needless_return = "allow"
useless_vec = "deny"
question_mark = "deny"
question_mark_used = "deny"
needless_match = "allow"
manual_ok_err = "allow"
manual_unwrap_or = "allow"
manual_map = "allow"
match_like_matches_macro = "allow"
single_match = "allow"
manual_unwrap_or_default = "allow"
manual_find = "allow"
explicit_counter_loop = "allow"
get_first = "allow"
implicit_saturating_sub = "allow"

View File

@@ -0,0 +1,23 @@
# file: templates/rust-cargo/clippy.toml
# version: 1
# Baseline shared by the KSP and Games projects; adapt thresholds per project.
too-many-arguments-threshold = 16
type-complexity-threshold = 250
single-char-binding-names-threshold = 3
trivial-copy-size-limit = 16
pass-by-value-size-limit = 256
stack-size-threshold = 512000
vec-box-size-threshold = 4096
max-fn-params-bools = 2
max-include-file-size = 1048576
cognitive-complexity-threshold = 25
too-large-for-stack = 2048
enum-variant-size-threshold = 200
large-error-threshold = 128
avoid-breaking-exported-api = true
allow-unwrap-in-tests = true
allow-expect-in-tests = true
allow-useless-vec-in-tests = true
disallowed-names = ["foo", "bar", "baz", "tmp"]
allowed-idents-below-min-chars = ["id"]

View File

@@ -0,0 +1,14 @@
# file: templates/rust-cargo/crates/project-core-lib/Cargo.toml
# version: 1
[package]
name = "project-core-lib"
version.workspace = true
edition.workspace = true
publish.workspace = true
[dependencies]
# Inherit only the workspace dependencies this crate actually uses.
[lints]
workspace = true

View File

@@ -0,0 +1,23 @@
# file: templates/rust-cargo/rustfmt.toml
# version: 1
edition = "2024"
newline_style = "Unix"
use_small_heuristics = "Default"
hard_tabs = false
tab_spaces = 4
max_width = 160
chain_width = 140
fn_call_width = 140
attr_fn_like_width = 140
struct_lit_width = 100
struct_variant_width = 100
array_width = 140
single_line_if_else_max_width = 120
single_line_let_else_max_width = 120
reorder_imports = true
reorder_modules = true
match_block_trailing_comma = true
use_field_init_shorthand = true
use_try_shorthand = false
force_explicit_abi = true

View File

@@ -0,0 +1,76 @@
# file: tests/test_markdown_headers.py
# version: 1
"""Exercise the Markdown header audit's real file and CLI contracts."""
from __future__ import annotations
import pathlib
import subprocess
import sys
import tempfile
import unittest
_SCRIPT = pathlib.Path(__file__).resolve().parents[1] / "scripts/audit_markdown_headers.py"
class MarkdownHeaderAuditTests(unittest.TestCase):
def setUp(self) -> None:
temporary = tempfile.TemporaryDirectory(prefix="pgr-headers-")
self.addCleanup(temporary.cleanup)
self.root = pathlib.Path(temporary.name)
def source(self, name: str, contents: str) -> pathlib.Path:
path = self.root / name
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(contents, encoding="utf-8")
return path
def run_audit(self, *paths: str) -> subprocess.CompletedProcess[str]:
return subprocess.run(
[sys.executable, "-B", str(_SCRIPT), *paths],
cwd=self.root, capture_output=True, text=True, check=False,
)
def test_valid_root_and_nested_files_are_deduplicated(self) -> None:
self.source("README.md", "<!-- file: README.md -->\n<!-- version: 1 -->\n")
self.source("docs/page.md", "<!-- file: docs/page.md -->\n<!-- version: 27 -->\n")
result = self.run_audit("README.md", "docs", "docs/page.md")
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn("clean (2 file(s))", result.stdout)
def test_wrong_path_and_nonpositive_revision_report_both_lines(self) -> None:
self.source("docs/page.md", "<!-- file: docs/other.md -->\n<!-- version: 0 -->\n")
result = self.run_audit("docs/page.md")
self.assertEqual(result.returncode, 1)
self.assertIn("docs/page.md:1:", result.stderr)
self.assertIn("docs/page.md:2:", result.stderr)
self.assertIn("2 error(s)", result.stderr)
def test_leading_zero_revision_is_rejected(self) -> None:
self.source("README.md", "<!-- file: README.md -->\n<!-- version: 01 -->\n")
result = self.run_audit("README.md")
self.assertEqual(result.returncode, 1)
self.assertIn("README.md:2:", result.stderr)
def test_missing_path_is_a_selection_error(self) -> None:
result = self.run_audit("missing.md")
self.assertEqual(result.returncode, 2)
self.assertIn("unsupported or missing path", result.stderr)
def test_empty_directory_is_a_selection_error(self) -> None:
(self.root / "docs").mkdir()
result = self.run_audit("docs")
self.assertEqual(result.returncode, 2)
self.assertIn("no Markdown files selected", result.stderr)
def test_generated_directory_is_skipped(self) -> None:
self.source("docs/visible.md", "<!-- file: docs/visible.md -->\n<!-- version: 1 -->\n")
self.source("docs/target/skip.md", "incorrect\n")
result = self.run_audit("docs")
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn("clean (1 file(s))", result.stdout)
if __name__ == "__main__":
unittest.main()

137
tests/test_rust_audits.py Normal file
View File

@@ -0,0 +1,137 @@
# file: tests/test_rust_audits.py
# version: 1
"""Targeted contracts for the two optional Rust style audits."""
from __future__ import annotations
import pathlib
import subprocess
import sys
import tempfile
import unittest
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1] / "scripts"))
from audit_rust_blank_lines import audit_file as audit_blanks # noqa: E402
from audit_rust_const_blocks import audit_file as audit_consts # noqa: E402
from _rust_audit_common import selected_files # noqa: E402
class RustAuditTests(unittest.TestCase):
def setUp(self) -> None:
self.temporary = tempfile.TemporaryDirectory()
self.addCleanup(self.temporary.cleanup)
self.root = pathlib.Path(self.temporary.name)
def source(self, text: str) -> pathlib.Path:
path = self.root / "source.rs"
path.write_text(text, encoding="utf-8")
return path
def test_clean_body_and_const_visibility_groups(self) -> None:
path = self.source("""pub const ALPHA: u8 = 1;
pub const BETA: u8 = 2;
pub(crate) const GAMMA: u8 = 3;
const OMEGA: u8 = 4;
fn sample() {
let value = r#"{\n\n}"#;
println!("{value}");
}
""")
self.assertEqual(audit_blanks(path), [])
self.assertEqual(audit_consts(path), [])
def test_blank_body_and_repeated_blank_lines(self) -> None:
path = self.source("""fn sample() {
let value = 1;
println!("{value}");
}
""")
issues = audit_blanks(path)
self.assertTrue(any("consecutive" in issue for issue in issues))
self.assertTrue(any("inside fn body" in issue for issue in issues))
def test_blank_string_and_nested_comment_braces_are_ignored(self) -> None:
path = self.source('''fn sample() {
let data = r#"{
}"#;
/* outer { /* inner } */ outer } */
println!("{data}");
}
''')
self.assertEqual(audit_blanks(path), [])
def test_struct_body_and_tuple_struct(self) -> None:
path = self.source("""struct Payload {
x: u8,
y: u8,
}
struct Pair(u8, u8);
""")
self.assertEqual(len(audit_blanks(path)), 1)
self.assertIn("struct body", audit_blanks(path)[0])
def test_const_order_and_multiline_initializer(self) -> None:
path = self.source("""const BETA: [u8; 2] = [
1,
2,
];
const ALPHA: u8 = 1;
pub const GAMMA: u8 = 3;
""")
issues = audit_consts(path)
self.assertTrue(any("alphabetical" in issue for issue in issues))
self.assertTrue(any("visibility" in issue for issue in issues))
def test_const_spacing(self) -> None:
path = self.source("""pub const ALPHA: u8 = 1;
pub const BETA: u8 = 2;
pub(crate) const GAMMA: u8 = 3;
""")
issues = audit_consts(path)
self.assertEqual(sum("blank line(s)" in issue for issue in issues), 2)
def test_const_function_does_not_join_const_block(self) -> None:
path = self.source("""const ZETA: u8 = 1;
const fn compute() -> u8 {
1
}
const ALPHA: u8 = 2;
""")
self.assertEqual(audit_consts(path), [])
def test_scope_and_missing_path(self) -> None:
self.source("fn sample() {}\n")
selected, errors = selected_files([str(self.root), str(self.root / "absent.rs")])
self.assertEqual(len(selected), 1)
self.assertEqual(len(errors), 1)
def test_cli_status_for_success_violation_and_invalid_selection(self) -> None:
path = self.source("const ALPHA: u8 = 1;\nconst BETA: u8 = 2;\n")
script = pathlib.Path(__file__).resolve().parents[1] / "scripts" / "audit_rust_const_blocks.py"
def run(subject: pathlib.Path) -> subprocess.CompletedProcess[str]:
return subprocess.run([sys.executable, "-B", str(script), str(subject)], capture_output=True, text=True, check=False)
self.assertEqual(run(path).returncode, 0)
path.write_text("const BETA: u8 = 1;\nconst ALPHA: u8 = 2;\n", encoding="utf-8")
self.assertEqual(run(path).returncode, 1)
self.assertEqual(run(self.root / "missing.rs").returncode, 2)
if __name__ == "__main__":
unittest.main()