12 KiB
Delta 0.1.0-rc.1 — gel du scope et gate de release candidate
Baseline et version
Baseline attendue : commit opérateur de 0.1.0-beta.1, réalisé après application de history/0.1.0/beta.1.md avec statut PASS.
Le hash de ce commit n'est pas anticipé.
Version avant application :
0.1.0-beta.1
Version après application :
0.1.0-rc.1
Objet et gel
La RC gèle le scope fonctionnel de 0.1.0 sur :
- la fondation de gouvernance et les skeleton specifications réutilisables ;
- le socle Rust/Cargo, ses cinq templates techniques et les dry-runs
NEW/ADOPTION; - le contrat d'adoption de projets existants
ADOPT / KEEP-LOCAL / OVERRIDE / DEFER; - la convention de clôture stable
rel.Nsans zéro de padding et l'identité du premier commit stableX.Y.Z; - le handoff automatique des commandes opérateur, du commit/push au tag et à la preuve
publish.*; - la revue d'horizon validée et le prompt
007vers0.1.1.
Le changelog reçoit une entrée candidate 0.1.0 orientée utilisateurs. ROADMAP.md, RULES.md, les owners, profils, templates techniques, skeletons et scripts d'audit sont vérifiés mais non modifiés.
Aucun scope Web, Java/Gradle, Android, Tauri, WASM, serveur Rust, Games/KSP ou deployment/operations n'entre fonctionnellement dans cette RC au-delà des décisions de trajectoire déjà validées.
Scope
REPLACE :
VERSION
CHANGELOG.md
docs/plans/006-V0_1_0_REUSABLE_BASELINE_PLAN.md
ADD :
deltas/0.1.0/rc.1.md
DELETE : aucun.
Le history beta.1 est livré séparément et MUST être appliqué/committé avant ce delta.
Gate opérateur de release candidate
Après application du history PASS de beta.1, commit/push de beta.1, puis application du présent delta :
test "$(cat VERSION)" = '0.1.0-rc.1'
git cat-file -e HEAD:history/0.1.0/beta.1.md
test -f history/0.1.0/beta.1.md
test -f deltas/0.1.0/rc.1.md
test -f prompts/007-V0_1_1_START_PROMPT.md
test ! -e history/0.1.0/rc.1.md
grep -A2 '^## Statut$' history/0.1.0/beta.1.md | grep -Fx 'PASS'
grep -Fx '<!-- version: 10 -->' CHANGELOG.md
grep -Fx '## 0.1.0 (candidate)' CHANGELOG.md
grep -Fx '<!-- version: 9 -->' docs/plans/006-V0_1_0_REUSABLE_BASELINE_PLAN.md
grep -Fx '<!-- version: 9 -->' ROADMAP.md
grep -Fx '<!-- version: 1 -->' prompts/007-V0_1_1_START_PROMPT.md
Contrôle d'intégration de la RC :
python3 -B - <<'PYGATE'
from pathlib import Path
import re
expected = {
"alpha.1.md": "PASS",
"alpha.2.md": "FAIL",
"alpha.2.fix.1.md": "PASS",
"alpha.3.md": "FAIL",
"alpha.3.fix.1.md": "PASS",
"alpha.4.md": "PASS",
"alpha.5.md": "PASS",
"beta.1.md": "PASS",
}
histories = {path.name for path in Path("history/0.1.0").glob("*.md")}
assert histories == set(expected), histories
for name, status in expected.items():
text = Path("history/0.1.0", name).read_text(encoding="utf-8")
assert re.search(rf"## Statut\s+{status}\s", text), (name, status)
deltas = {path.name for path in Path("deltas/0.1.0").glob("*.md")}
assert deltas == set(expected) | {"rc.1.md"}, deltas
changelog = Path("CHANGELOG.md").read_text(encoding="utf-8")
assert "## 0.1.0 (candidate)" in changelog
section = changelog.split("## 0.1.0 (candidate)", 1)[1].split("## 0.0.5", 1)[0]
for phrase in (
"première baseline PGR réellement réutilisable",
"ADOPT / KEEP-LOCAL / OVERRIDE / DEFER",
"rel.N",
"publish.*",
"frontend Web",
):
assert phrase in section, phrase
for forbidden in ("alpha.2", "alpha.3", "beta.1", "rc.1"):
assert forbidden not in section, forbidden
workflow = Path("docs/rules/210-WORKFLOW.md").read_text(encoding="utf-8")
for phrase in (
"La famille `rel.N` utilise la représentation sans zéro de padding",
"première de ces tranches qui obtient réellement `PASS` est incluse dans le commit stable `X.Y.Z`",
"Le rapport `publish.*` est produit seulement à partir des artefacts et preuves réellement disponibles après publication.",
"../templates/006-OPERATOR_COMMAND_HANDOFF.md",
):
assert phrase in workflow, phrase
adoption = Path("docs/rules/230-ADOPTION.md").read_text(encoding="utf-8")
for phrase in ("ADOPT", "KEEP-LOCAL", "OVERRIDE", "DEFER", "Préservation de l’historique"):
assert phrase in adoption, phrase
rust_dryrun = Path("docs/validation/004-RUST_CARGO_BASELINE_DRY_RUN.md").read_text(encoding="utf-8")
assert "NEW nouveau projet" in rust_dryrun
assert "ADOPTION projet existant" in rust_dryrun
roadmap = Path("ROADMAP.md").read_text(encoding="utf-8")
for version in ("0.1.1", "0.1.2", "0.1.3", "0.1.4", "0.1.5", "0.1.6", "0.1.7"):
assert f"- `( ) {version}`" in roadmap, version
assert "- `( ) 0.1.8`" not in roadmap
assert "WASM" in roadmap
assert "serveur Web Rust / Actix Web ou alternative" in roadmap
assert "deployment & operations" in roadmap
prompt = Path("prompts/007-V0_1_1_START_PROMPT.md").read_text(encoding="utf-8")
for phrase in (
"archive source téléchargée depuis le tag Gitea `v0.1.0`",
"pgr-0.1.0-publish.001-report.md",
"0.1.1-alpha.1",
"games-v0.3.6.zip",
"TypeScript",
"Vite",
"Sass/CSS",
"Le skeleton Tauri reste `DEFER` pendant cette release.",
):
assert phrase in prompt, phrase
plan = Path("docs/plans/006-V0_1_0_REUSABLE_BASELINE_PLAN.md").read_text(encoding="utf-8")
assert "### beta.1 — réconciliation finale et revue d'horizon\n\nStatut opérateur : **PASS**." in plan
assert "### rc.1 — release candidate\n\nStatut opérateur : **à valider**." in plan
assert "État : **validée `PASS` par la gate opérateur de `beta.1`**." in plan
print("0.1.0 rc.1 integration audit: clean (8 prior histories, frozen reusable baseline, candidate changelog, horizon and prompt 007 verified)")
PYGATE
Rejouer également les deux chemins Rust/Cargo avec la toolchain réelle :
python3 -B - <<'PYRUST'
from pathlib import Path
import hashlib
import shutil
import subprocess
import tempfile
import tomllib
cargo = shutil.which("cargo")
if cargo is None:
raise SystemExit("BLOCKED: cargo is required for the 0.1.0 RC Rust/Cargo release gate")
commands = (
[cargo, "metadata", "--format-version", "1", "--no-deps"],
[cargo, "fmt", "--all", "--", "--check"],
[cargo, "check", "--workspace"],
[cargo, "clippy", "--workspace", "--all-targets", "--all-features", "--", "-D", "warnings"],
)
source = Path("templates/rust-cargo")
with tempfile.TemporaryDirectory(prefix="pgr-rc1-new-") as temporary:
root = Path(temporary)
(root / ".cargo").mkdir(parents=True)
(root / "crates/pgr-rc-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-rc-core-lib/Cargo.toml")
workspace = (root / "Cargo.toml").read_text(encoding="utf-8")
workspace = workspace.replace("crates/project-core-lib", "crates/pgr-rc-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-rc-core-lib/Cargo.toml").read_text(encoding="utf-8")
member = member.replace("project-core-lib", "pgr-rc-core-lib")
(root / "crates/pgr-rc-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-rc1-new")
(root / ".cargo/config.toml").write_text(config, encoding="utf-8")
(root / "crates/pgr-rc-core-lib/src/lib.rs").write_text(
"//! Minimal source used only by the PGR RC dry-run.\n\n"
"/// Returns the RC marker.\n"
"#[must_use]\n"
"pub const fn rc_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-rc-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
for command in commands:
subprocess.run(command, cwd=root, check=True)
with tempfile.TemporaryDirectory(prefix="pgr-rc1-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()) <= {"ADOPT", "KEEP-LOCAL", "OVERRIDE", "DEFER"}
for command in commands:
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")
print("0.1.0 rc.1 Rust/Cargo release dry-runs: clean (NEW and ADOPTION accepted by Cargo/rustfmt/Clippy)")
PYRUST
Puis la suite PGR complète :
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 CHANGELOG.md \
docs/plans/006-V0_1_0_REUSABLE_BASELINE_PLAN.md \
deltas/0.1.0/rc.1.md
git diff --cached --check
git status --short
Le scope attendu avant ajout du history est exactement :
M CHANGELOG.md
M VERSION
A deltas/0.1.0/rc.1.md
M docs/plans/006-V0_1_0_REUSABLE_BASELINE_PLAN.md
Revue opérateur complémentaire
Confirmer que :
- le changelog décrit les capacités de
0.1.0et non ses tranches internes ; - aucune règle/profil/template/skeleton/audit fonctionnel nouveau n'entre dans la RC ;
ROADMAP.mdconserve0.1.0en cours jusqu'à la promotion stable ;0.1.1..0.1.7restent la trajectoire engagée et les domaines non numérotés restent réellement différés ;- le prompt
007exige bien l'archive taggéev0.1.0et le rapportpublish.001seulement lorsqu'il existe réellement avec statutPASS; - la RC n'est ni le commit stable
0.1.0, ni le tagv0.1.0, ni la vérification post-tag.
Transition
PASS
Produire séparément history/0.1.0/rc.1.md, l'appliquer puis committer/pousser 0.1.0-rc.1 avant le delta stable rel.1.
FAIL
Consigner l'échec réel dans history/0.1.0/rc.1.md puis corriger uniquement le scope gelé dans rc.1.fix.1, sauf REPLAN si la candidate révèle un défaut fonctionnel plus large.