0.1.0-rc.1
This commit is contained in:
333
deltas/0.1.0/rc.1.md
Normal file
333
deltas/0.1.0/rc.1.md
Normal file
@@ -0,0 +1,333 @@
|
||||
<!-- file: deltas/0.1.0/rc.1.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# 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 :
|
||||
|
||||
```text
|
||||
0.1.0-beta.1
|
||||
```
|
||||
|
||||
Version après application :
|
||||
|
||||
```text
|
||||
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.N` sans zéro de padding et l'identité du premier commit stable `X.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 `007` vers `0.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 :
|
||||
|
||||
```text
|
||||
VERSION
|
||||
CHANGELOG.md
|
||||
docs/plans/006-V0_1_0_REUSABLE_BASELINE_PLAN.md
|
||||
```
|
||||
|
||||
ADD :
|
||||
|
||||
```text
|
||||
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 :
|
||||
|
||||
```bash
|
||||
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 :
|
||||
|
||||
```bash
|
||||
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 :
|
||||
|
||||
```bash
|
||||
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 :
|
||||
|
||||
```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 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 :
|
||||
|
||||
```text
|
||||
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.0` et non ses tranches internes ;
|
||||
- aucune règle/profil/template/skeleton/audit fonctionnel nouveau n'entre dans la RC ;
|
||||
- `ROADMAP.md` conserve `0.1.0` en cours jusqu'à la promotion stable ;
|
||||
- `0.1.1..0.1.7` restent la trajectoire engagée et les domaines non numérotés restent réellement différés ;
|
||||
- le prompt `007` exige bien l'archive taggée `v0.1.0` et le rapport `publish.001` seulement lorsqu'il existe réellement avec statut `PASS` ;
|
||||
- la RC n'est ni le commit stable `0.1.0`, ni le tag `v0.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.
|
||||
Reference in New Issue
Block a user