372 lines
14 KiB
Markdown
372 lines
14 KiB
Markdown
<!-- file: deltas/0.1.0/alpha.5.md -->
|
||
<!-- version: 1 -->
|
||
|
||
# Delta 0.1.0-alpha.5 — baseline Rust/Cargo réutilisable et dry-run
|
||
|
||
## Baseline et version
|
||
|
||
Baseline attendue : commit opérateur de `0.1.0-alpha.4`, réalisé après application de `history/0.1.0/alpha.4.md` avec statut `PASS`.
|
||
|
||
Le hash de ce commit n’est pas anticipé.
|
||
|
||
Version avant application :
|
||
|
||
```text
|
||
0.1.0-alpha.4
|
||
```
|
||
|
||
Version après application :
|
||
|
||
```text
|
||
0.1.0-alpha.5
|
||
```
|
||
|
||
## Objet
|
||
|
||
Prouver que la première baseline Rust/Cargo de PGR est réellement réutilisable dans deux situations distinctes :
|
||
|
||
```text
|
||
NEW nouveau workspace gouverné depuis une baseline vide
|
||
ADOPTION workspace Rust existant conservant ses décisions locales légitimes
|
||
```
|
||
|
||
La tranche réconcilie les skeletons `001` / `002`, les guides des templates Rust/Cargo et la validation. Elle ajoute un contrat durable de dry-run, mais aucun générateur de projet permanent et aucun nouveau profil technologique.
|
||
|
||
Games et KSP ne servent pas de fixtures et ne sont pas modifiés.
|
||
|
||
## Scope
|
||
|
||
REPLACE :
|
||
|
||
```text
|
||
VERSION
|
||
docs/000-README.md
|
||
docs/plans/006-V0_1_0_REUSABLE_BASELINE_PLAN.md
|
||
docs/skeletons/000-README.md
|
||
docs/skeletons/001-PROJECT_GOVERNANCE_FOUNDATION.md
|
||
docs/skeletons/002-RUST_CARGO_WORKSPACE.md
|
||
docs/templates/001-RUST_CARGO_TOOLING.md
|
||
docs/templates/002-CARGO_MANIFESTS.md
|
||
docs/validation/001-VALIDATION_MATRIX.md
|
||
```
|
||
|
||
ADD :
|
||
|
||
```text
|
||
deltas/0.1.0/alpha.5.md
|
||
docs/validation/004-RUST_CARGO_BASELINE_DRY_RUN.md
|
||
```
|
||
|
||
DELETE : aucun.
|
||
|
||
Les templates techniques sous `templates/rust-cargo/`, les scripts d’audit, les profils Java/Android/Tauri, `ROADMAP.md` et `CHANGELOG.md` restent inchangés.
|
||
|
||
## Décisions
|
||
|
||
### Nouveau projet
|
||
|
||
Le chemin d’instanciation reste `001 + 002`. Les cinq templates techniques sont adaptés dans un répertoire temporaire, les placeholders sont résolus et une crate source triviale est créée uniquement pour permettre à Cargo de vérifier la baseline.
|
||
|
||
Le code temporaire du dry-run n’est pas ajouté aux templates PGR.
|
||
|
||
### Projet existant
|
||
|
||
Le chemin d’adoption passe par `230-ADOPTION.md`. Les skeletons et templates servent de checklists de comparaison et ne sont jamais copiés aveuglément.
|
||
|
||
Le dry-run doit inclure plusieurs décisions et prouver qu’un choix local classé `KEEP-LOCAL` ou `DEFER` reste inchangé.
|
||
|
||
### Autorité de la toolchain
|
||
|
||
La syntaxe TOML et les assertions structurelles peuvent être prévalidées avec Python. En revanche, le mode `NEW` complet exige Cargo : une absence de toolchain ne peut pas être convertie en `PASS`.
|
||
|
||
## Validation opérateur
|
||
|
||
Après application du history `PASS`, commit/push de `alpha.4`, puis application du présent delta :
|
||
|
||
```bash
|
||
test "$(cat VERSION)" = '0.1.0-alpha.5'
|
||
git cat-file -e HEAD:history/0.1.0/alpha.4.md
|
||
test -f history/0.1.0/alpha.4.md
|
||
test -f deltas/0.1.0/alpha.5.md
|
||
test -f docs/validation/004-RUST_CARGO_BASELINE_DRY_RUN.md
|
||
test ! -e history/0.1.0/alpha.5.md
|
||
|
||
grep -A2 '^## Statut$' history/0.1.0/alpha.4.md | grep -Fx 'PASS'
|
||
grep -Fx '<!-- version: 21 -->' docs/000-README.md
|
||
grep -Fx '<!-- version: 5 -->' docs/skeletons/000-README.md
|
||
grep -Fx '<!-- version: 4 -->' docs/skeletons/001-PROJECT_GOVERNANCE_FOUNDATION.md
|
||
grep -Fx '<!-- version: 6 -->' docs/skeletons/002-RUST_CARGO_WORKSPACE.md
|
||
grep -Fx '<!-- version: 4 -->' docs/templates/001-RUST_CARGO_TOOLING.md
|
||
grep -Fx '<!-- version: 4 -->' docs/templates/002-CARGO_MANIFESTS.md
|
||
grep -Fx '<!-- version: 13 -->' docs/validation/001-VALIDATION_MATRIX.md
|
||
grep -Fx '<!-- version: 1 -->' docs/validation/004-RUST_CARGO_BASELINE_DRY_RUN.md
|
||
grep -Fx '<!-- version: 7 -->' docs/plans/006-V0_1_0_REUSABLE_BASELINE_PLAN.md
|
||
```
|
||
|
||
Contrôle structurel et prévalidation TOML :
|
||
|
||
```bash
|
||
python3 -B - <<'PYGATE'
|
||
from pathlib import Path
|
||
import re
|
||
import tomllib
|
||
|
||
history = Path("history/0.1.0/alpha.4.md").read_text(encoding="utf-8")
|
||
foundation = Path("docs/skeletons/001-PROJECT_GOVERNANCE_FOUNDATION.md").read_text(encoding="utf-8")
|
||
rust_skeleton = Path("docs/skeletons/002-RUST_CARGO_WORKSPACE.md").read_text(encoding="utf-8")
|
||
tooling = Path("docs/templates/001-RUST_CARGO_TOOLING.md").read_text(encoding="utf-8")
|
||
manifests = Path("docs/templates/002-CARGO_MANIFESTS.md").read_text(encoding="utf-8")
|
||
dryrun = Path("docs/validation/004-RUST_CARGO_BASELINE_DRY_RUN.md").read_text(encoding="utf-8")
|
||
plan = Path("docs/plans/006-V0_1_0_REUSABLE_BASELINE_PLAN.md").read_text(encoding="utf-8")
|
||
roadmap = Path("ROADMAP.md").read_text(encoding="utf-8")
|
||
|
||
assert re.search(r"## Statut\s+PASS\s", history)
|
||
assert "../rules/230-ADOPTION.md" in foundation
|
||
assert "../rules/230-ADOPTION.md" in rust_skeleton
|
||
assert "004-RUST_CARGO_BASELINE_DRY_RUN.md" in rust_skeleton
|
||
assert "KEEP-LOCAL" in tooling
|
||
assert "ADOPT / KEEP-LOCAL / OVERRIDE / DEFER" in manifests
|
||
|
||
for phrase in (
|
||
"NEW nouveau projet",
|
||
"ADOPTION projet existant",
|
||
"cargo metadata --format-version 1 --no-deps",
|
||
"cargo clippy --workspace --all-targets --all-features -- -D warnings",
|
||
"KEEP-LOCAL",
|
||
"DEFER",
|
||
"ne constitue pas un `PASS` de la toolchain",
|
||
):
|
||
assert phrase in dryrun, phrase
|
||
|
||
for path in (
|
||
Path("templates/rust-cargo/Cargo.toml"),
|
||
Path("templates/rust-cargo/clippy.toml"),
|
||
Path("templates/rust-cargo/rustfmt.toml"),
|
||
Path("templates/rust-cargo/.cargo/config.toml"),
|
||
Path("templates/rust-cargo/crates/project-core-lib/Cargo.toml"),
|
||
):
|
||
with path.open("rb") as handle:
|
||
tomllib.load(handle)
|
||
|
||
assert "Statut opérateur : **PASS**." in plan
|
||
assert "Statut opérateur : **à valider**." in plan
|
||
assert "Games et KSP ne sont pas utilisés comme fixtures du dry-run." in plan
|
||
assert "- `( ) 0.1.1`" not in roadmap
|
||
|
||
print("0.1.0 alpha.5 structural/TOML audit: clean (NEW and ADOPTION paths explicit, templates parse, external corpora not required)")
|
||
PYGATE
|
||
```
|
||
|
||
Dry-run `NEW` avec la toolchain officielle :
|
||
|
||
```bash
|
||
python3 -B - <<'PYNEW'
|
||
from pathlib import Path
|
||
import shutil
|
||
import subprocess
|
||
import tempfile
|
||
import tomllib
|
||
|
||
cargo = shutil.which("cargo")
|
||
if cargo is None:
|
||
raise SystemExit("BLOCKED: cargo is required for the alpha.5 NEW dry-run")
|
||
|
||
source = Path("templates/rust-cargo")
|
||
with tempfile.TemporaryDirectory(prefix="pgr-alpha5-new-") as temporary:
|
||
root = Path(temporary)
|
||
(root / ".cargo").mkdir(parents=True)
|
||
(root / "crates/pgr-dryrun-core-lib/src").mkdir(parents=True)
|
||
|
||
shutil.copy2(source / "Cargo.toml", root / "Cargo.toml")
|
||
shutil.copy2(source / "clippy.toml", root / "clippy.toml")
|
||
shutil.copy2(source / "rustfmt.toml", root / "rustfmt.toml")
|
||
shutil.copy2(source / ".cargo/config.toml", root / ".cargo/config.toml")
|
||
shutil.copy2(source / "crates/project-core-lib/Cargo.toml", root / "crates/pgr-dryrun-core-lib/Cargo.toml")
|
||
|
||
workspace = (root / "Cargo.toml").read_text(encoding="utf-8")
|
||
workspace = workspace.replace("crates/project-core-lib", "crates/pgr-dryrun-core-lib")
|
||
workspace = workspace.replace('version = "0.1.0"', 'version = "9.9.9"')
|
||
(root / "Cargo.toml").write_text(workspace, encoding="utf-8")
|
||
|
||
member = (root / "crates/pgr-dryrun-core-lib/Cargo.toml").read_text(encoding="utf-8")
|
||
member = member.replace("project-core-lib", "pgr-dryrun-core-lib")
|
||
(root / "crates/pgr-dryrun-core-lib/Cargo.toml").write_text(member, encoding="utf-8")
|
||
|
||
config = (root / ".cargo/config.toml").read_text(encoding="utf-8")
|
||
config = config.replace("project-name", "pgr-alpha5-new")
|
||
(root / ".cargo/config.toml").write_text(config, encoding="utf-8")
|
||
|
||
(root / "crates/pgr-dryrun-core-lib/src/lib.rs").write_text(
|
||
"//! Minimal source used only by the PGR alpha.5 dry-run.\n\n"
|
||
"/// Returns the dry-run marker.\n"
|
||
"#[must_use]\n"
|
||
"pub const fn dry_run_marker() -> u32 {\n"
|
||
" return 1;\n"
|
||
"}\n",
|
||
encoding="utf-8",
|
||
)
|
||
|
||
for path in (
|
||
root / "Cargo.toml",
|
||
root / "clippy.toml",
|
||
root / "rustfmt.toml",
|
||
root / ".cargo/config.toml",
|
||
root / "crates/pgr-dryrun-core-lib/Cargo.toml",
|
||
):
|
||
with path.open("rb") as handle:
|
||
tomllib.load(handle)
|
||
text = path.read_text(encoding="utf-8")
|
||
assert "project-name" not in text
|
||
assert "project-core-lib" not in text
|
||
|
||
commands = (
|
||
[cargo, "metadata", "--format-version", "1", "--no-deps"],
|
||
[cargo, "fmt", "--all", "--", "--check"],
|
||
[cargo, "check", "--workspace"],
|
||
[cargo, "clippy", "--workspace", "--all-targets", "--all-features", "--", "-D", "warnings"],
|
||
)
|
||
for command in commands:
|
||
subprocess.run(command, cwd=root, check=True)
|
||
|
||
print("0.1.0 alpha.5 NEW dry-run: clean (temporary templates accepted by Cargo/rustfmt/Clippy)")
|
||
PYNEW
|
||
```
|
||
|
||
Dry-run `ADOPTION` non destructif :
|
||
|
||
```bash
|
||
python3 -B - <<'PYADOPT'
|
||
from pathlib import Path
|
||
import hashlib
|
||
import shutil
|
||
import subprocess
|
||
import tempfile
|
||
|
||
cargo = shutil.which("cargo")
|
||
if cargo is None:
|
||
raise SystemExit("BLOCKED: cargo is required for the alpha.5 ADOPTION dry-run")
|
||
|
||
valid_decisions = {"ADOPT", "KEEP-LOCAL", "OVERRIDE", "DEFER"}
|
||
with tempfile.TemporaryDirectory(prefix="pgr-alpha5-adoption-") as temporary:
|
||
root = Path(temporary)
|
||
(root / "crates/legacy-core-lib/src").mkdir(parents=True)
|
||
|
||
(root / "Cargo.toml").write_text(
|
||
'[workspace]\nresolver = "3"\nmembers = ["crates/legacy-core-lib"]\n\n'
|
||
'[workspace.package]\nversion = "2.3.4"\nedition = "2024"\npublish = false\n',
|
||
encoding="utf-8",
|
||
)
|
||
(root / "rustfmt.toml").write_text('edition = "2024"\nmax_width = 120\n', encoding="utf-8")
|
||
(root / "crates/legacy-core-lib/Cargo.toml").write_text(
|
||
'[package]\nname = "legacy-core-lib"\nversion.workspace = true\nedition.workspace = true\npublish.workspace = true\n',
|
||
encoding="utf-8",
|
||
)
|
||
(root / "crates/legacy-core-lib/src/lib.rs").write_text(
|
||
"//! Existing synthetic library.\n\n"
|
||
"/// Returns the existing marker.\n"
|
||
"#[must_use]\n"
|
||
"pub const fn existing_marker() -> u32 {\n"
|
||
" 7\n"
|
||
"}\n",
|
||
encoding="utf-8",
|
||
)
|
||
|
||
protected = (root / "Cargo.toml", root / "rustfmt.toml", root / "crates/legacy-core-lib/Cargo.toml")
|
||
before = {path: hashlib.sha256(path.read_bytes()).hexdigest() for path in protected}
|
||
|
||
decisions = {
|
||
"510-RUST_CARGO": "ADOPT",
|
||
"rustfmt.max_width=120": "KEEP-LOCAL",
|
||
"PGR external artifact configuration": "DEFER",
|
||
"strict crate-root export audit": "DEFER",
|
||
}
|
||
assert set(decisions.values()) <= valid_decisions
|
||
assert "KEEP-LOCAL" in decisions.values()
|
||
assert "DEFER" in decisions.values()
|
||
|
||
for command in (
|
||
[cargo, "metadata", "--format-version", "1", "--no-deps"],
|
||
[cargo, "fmt", "--all", "--", "--check"],
|
||
[cargo, "check", "--workspace"],
|
||
[cargo, "clippy", "--workspace", "--all-targets", "--all-features", "--", "-D", "warnings"],
|
||
):
|
||
subprocess.run(command, cwd=root, check=True)
|
||
|
||
after = {path: hashlib.sha256(path.read_bytes()).hexdigest() for path in protected}
|
||
assert before == after
|
||
assert "max_width = 120" in (root / "rustfmt.toml").read_text(encoding="utf-8")
|
||
assert not (root / ".cargo/config.toml").exists()
|
||
|
||
print("0.1.0 alpha.5 ADOPTION dry-run: clean (local KEEP-LOCAL/DEFER choices preserved, workspace remains valid)")
|
||
PYADOPT
|
||
```
|
||
|
||
Puis rejouer les preuves PGR :
|
||
|
||
```bash
|
||
python3 -B -m unittest discover -s tests -v
|
||
|
||
python3 -B scripts/audit_markdown_headers.py \
|
||
README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts
|
||
python3 -B scripts/audit_markdown_tables.py \
|
||
README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts
|
||
python3 -B scripts/audit_markdown_links.py \
|
||
README.md RULES.md ROADMAP.md CHANGELOG.md docs deltas history prompts
|
||
|
||
git diff --check
|
||
|
||
git add VERSION docs/000-README.md \
|
||
docs/plans/006-V0_1_0_REUSABLE_BASELINE_PLAN.md \
|
||
docs/skeletons/000-README.md \
|
||
docs/skeletons/001-PROJECT_GOVERNANCE_FOUNDATION.md \
|
||
docs/skeletons/002-RUST_CARGO_WORKSPACE.md \
|
||
docs/templates/001-RUST_CARGO_TOOLING.md \
|
||
docs/templates/002-CARGO_MANIFESTS.md \
|
||
docs/validation/001-VALIDATION_MATRIX.md \
|
||
docs/validation/004-RUST_CARGO_BASELINE_DRY_RUN.md \
|
||
deltas/0.1.0/alpha.5.md
|
||
|
||
git diff --cached --check
|
||
git status --short
|
||
```
|
||
|
||
Le scope indexé attendu avant ajout du history de `alpha.5` est exactement :
|
||
|
||
```text
|
||
M VERSION
|
||
A deltas/0.1.0/alpha.5.md
|
||
M docs/000-README.md
|
||
M docs/plans/006-V0_1_0_REUSABLE_BASELINE_PLAN.md
|
||
M docs/skeletons/000-README.md
|
||
M docs/skeletons/001-PROJECT_GOVERNANCE_FOUNDATION.md
|
||
M docs/skeletons/002-RUST_CARGO_WORKSPACE.md
|
||
M docs/templates/001-RUST_CARGO_TOOLING.md
|
||
M docs/templates/002-CARGO_MANIFESTS.md
|
||
M docs/validation/001-VALIDATION_MATRIX.md
|
||
A docs/validation/004-RUST_CARGO_BASELINE_DRY_RUN.md
|
||
```
|
||
|
||
## Revue opérateur complémentaire
|
||
|
||
Confirmer que :
|
||
|
||
- le mode `NEW` n’introduit aucun `src/lib.rs` universel dans PGR ;
|
||
- le mode `ADOPTION` ne remplace pas les fichiers existants classés `KEEP-LOCAL` ou `DEFER` ;
|
||
- les templates techniques eux-mêmes restent inchangés dans cette tranche ;
|
||
- la réussite de la prévalidation Python n’est pas confondue avec la réussite Cargo ;
|
||
- Games et KSP ne sont ni modifiés ni nécessaires à la preuve ;
|
||
- aucun profil Java, Android, Tauri, Web, WASM ou serveur n’est matérialisé ;
|
||
- aucun numéro futur `0.1.x` n’est réservé.
|
||
|
||
## Transition
|
||
|
||
### PASS
|
||
|
||
Produire `history/0.1.0/alpha.5.md`, l’appliquer puis remettre automatiquement les commandes de commit/push.
|
||
|
||
Passer ensuite à `0.1.0-beta.1` pour la réconciliation finale et la revue d’horizon obligatoire avant RC.
|
||
|
||
### FAIL / BLOCKED
|
||
|
||
Consigner le résultat réel dans `history/0.1.0/alpha.5.md`. Un défaut des templates/skeletons reste dans `alpha.5.fix.N` sauf REPLAN. Une toolchain Cargo absente qui empêche les dry-runs requis doit être enregistrée `BLOCKED`, pas transformée en `PASS` par la seule prévalidation Python.
|