Files
2026-09-29 17:59:08 +02:00

11 KiB

Delta 0.0.3-rc.1 — release candidate

Base requise

État 0.0.3-beta.1 committé et poussé après application du history :

history/0.0.3/beta.1.md = PASS

La version devient :

0.0.3-rc.1

Objet

Geler le scope de 0.0.3 et exécuter sa gate complète de release candidate.

Aucune nouvelle fonctionnalité, dépendance, crate, route, comportement Git, décision PostgreSQL/Web ou modification de l'horizon produit n'est introduite.

Scope

La RC remplace uniquement :

VERSION
Cargo.toml
README.md
docs/plans/003-V0_0_3_GIT_WRITE_PLAN.md
docs/validation/001-VALIDATION_MATRIX.md

et ajoute :

deltas/0.0.3/rc.1.md

Aucun fichier n'est supprimé. crates/, Web/, CHANGELOG.md, ROADMAP.md, docs/architecture/, docs/studies/, docs/rules/ et prompts/ sont gelés.

Histories attendus avant RC

La gate doit retrouver exactement les huit histories antérieurs suivants :

alpha.1             PARTIAL
alpha.1.fix.1       PARTIAL
alpha.1.fix.2       PASS
alpha.2             PASS
alpha.3             FAIL
alpha.3.fix.1       PASS
alpha.4             PASS
beta.1              PASS

Pendant la gate, rc.1.md doit être le seul delta 0.0.3 sans history correspondant.

Présentation candidate

La RC conserve :

CHANGELOG.md  -> ## 0.0.3 (candidate)
ROADMAP.md    -> 0.0.3 encore engagée + horizon 0.0.4..0.0.10
prompt 004    -> handoff 0.0.4 présent, sans commit/SHA futur inventé

La présentation stable appartient à rel.1, pas à la RC.

Gate opérateur

Exécuter directement dans le shell interactif. Ne pas activer set -e, set -u ou set -o pipefail globalement.

test "$(cat VERSION)" = '0.0.3-rc.1'
grep -F 'version = "0.0.3-rc.1"' Cargo.toml
grep -A2 '^## Statut$' history/0.0.3/beta.1.md | grep -Fx 'PASS'

git diff --check

python3 -B scripts/audit_markdown_headers.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts deltas history
python3 -B scripts/audit_markdown_links.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts deltas history
python3 -B scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts deltas history

cargo fmt --all
cargo fmt --all -- --check

python3 -B scripts/audit_rust_test_layout.py crates
python3 -B scripts/audit_rust_blank_lines.py crates
python3 -B scripts/audit_rust_item_spacing.py crates
python3 -B scripts/audit_rust_module_order.py crates
python3 -B scripts/audit_rust_trait_import_blocks.py crates
python3 -B scripts/audit_rust_reexport_blocks.py crates
python3 -B scripts/audit_rust_crate_root_facades.py crates
python3 -B scripts/audit_rust_export_completeness.py --root . --summary-only

cargo metadata --format-version 1 --no-deps > /tmp/sasedev-knowledge-0.0.3-rc.1-metadata.json
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p knowledge-git-lib --test git_read_path
cargo test -p knowledge-git-lib --test git_write_candidate
cargo test -p knowledge-git-lib --test git_write_push
cargo test --workspace --all-targets --all-features

(cd Web/knowledge-template-lab && npm ci)
(cd Web/knowledge-template-lab && npm run typecheck)
(cd Web/knowledge-template-lab && npm run build)

python3 -c 'import json; from pathlib import Path; p=Path("../builds/sasedev-knowledge/web/template-lab/.vite/manifest.json"); m=json.loads(p.read_text(encoding="utf-8")); e=m["src/main.ts"]; assert e.get("file"); assert e.get("css"); print("Knowledge 0.0.3-rc.1 Vite manifest audit: clean")'

Contrôles d'intégrité courts

grep -A2 '^## Statut$' history/0.0.3/alpha.1.md | grep -Fx 'PARTIAL'
grep -A2 '^## Statut$' history/0.0.3/alpha.1.fix.1.md | grep -Fx 'PARTIAL'
grep -A2 '^## Statut$' history/0.0.3/alpha.1.fix.2.md | grep -Fx 'PASS'
grep -A2 '^## Statut$' history/0.0.3/alpha.2.md | grep -Fx 'PASS'
grep -A2 '^## Statut$' history/0.0.3/alpha.3.md | grep -Fx 'FAIL'
grep -A2 '^## Statut$' history/0.0.3/alpha.3.fix.1.md | grep -Fx 'PASS'
grep -A2 '^## Statut$' history/0.0.3/alpha.4.md | grep -Fx 'PASS'
grep -A2 '^## Statut$' history/0.0.3/beta.1.md | grep -Fx 'PASS'

test "$(find history/0.0.3 -maxdepth 1 -type f -name '*.md' | wc -l)" -eq 8
test "$(find deltas/0.0.3 -maxdepth 1 -type f -name '*.md' | wc -l)" -eq 9

test ! -e history/0.0.3/rc.1.md

grep -F '## 0.0.3 (candidate)' CHANGELOG.md
grep -F -- '- `( ) 0.0.3` — écriture Git contrôlée et push gardé' ROADMAP.md
grep -F -- '- `(h) 0.0.4` — fondation PostgreSQL partagée' ROADMAP.md
grep -F -- '- `(h) 0.0.10` — gestion, proposition, revue et publication' ROADMAP.md

test -f prompts/004-V0_0_4_START_PROMPT.md
! grep -Eq '[0-9a-f]{40}|[0-9a-f]{64}' prompts/004-V0_0_4_START_PROMPT.md

test ! -e crates/knowledge-store-postgres-lib
test ! -e crates/knowledge-forge-gitea-lib
test ! -e migrations

Vérifier le workspace Cargo sans bloc multi-lignes :

python3 -c 'import json; from pathlib import Path; m=json.loads(Path("/tmp/sasedev-knowledge-0.0.3-rc.1-metadata.json").read_text()); expected={"knowledge-app-lib","knowledge-domain-lib","knowledge-git-api","knowledge-git-lib","knowledge-sync-api","knowledge-web-lib","knowledge-pgr-server","knowledge-howtos-server","knowledge-snippets-server"}; assert {p["name"] for p in m["packages"]} == expected; assert len(m["workspace_members"]) == 9; print("Knowledge 0.0.3-rc.1 workspace audit: clean")'

Vérifier l'hygiène texte :

python3 -c 'from pathlib import Path; roots=[Path("README.md"),Path("RULES.md"),Path("ROADMAP.md"),Path("CHANGELOG.md"),Path("docs"),Path("prompts"),Path("deltas"),Path("history")]; paths=[p for r in roots for p in ([r] if r.is_file() else r.rglob("*")) if p.is_file()]; bad=[str(p) for p in paths if (lambda b: b"\r" in b or not b.endswith(b"\n") or b.endswith(b"\n\n") or any(line != line.rstrip(" \t") for line in b.decode("utf-8").splitlines()))(p.read_bytes())]; print(f"Knowledge 0.0.3-rc.1 text hygiene: clean ({len(paths)} file(s))") if not bad else (_ for _ in ()).throw(AssertionError(bad))'

Smokes HTTP de production

Construire les trois launchers :

cargo build -p knowledge-pgr-server -p knowledge-howtos-server -p knowledge-snippets-server

Préparer le chemin du manifest et la liste des assets :

export KNOWLEDGE_RC_MANIFEST="$(realpath ../builds/sasedev-knowledge/web/template-lab/.vite/manifest.json)"
python3 -c 'import json,os; m=json.load(open(os.environ["KNOWLEDGE_RC_MANIFEST"],encoding="utf-8")); e=m["src/main.ts"]; print("/"+e["file"].lstrip("/")); print(*["/"+x.lstrip("/") for x in e.get("css",[])],sep="\n")' > /tmp/sasedev-knowledge-0.0.3-rc.1-assets.txt
cat /tmp/sasedev-knowledge-0.0.3-rc.1-assets.txt

PGR

env -u KNOWLEDGE_VITE_DEV_ORIGIN KNOWLEDGE_VITE_MANIFEST_PATH="$KNOWLEDGE_RC_MANIFEST" KNOWLEDGE_PGR_BIND_ADDRESS=127.0.0.1:18181 ../builds/sasedev-knowledge/target/debug/knowledge-pgr-server > /tmp/knowledge-pgr-rc.1.log 2>&1 & echo $! > /tmp/knowledge-pgr-rc.1.pid
sleep 1
python3 -c 'import urllib.request; r=urllib.request.urlopen("http://127.0.0.1:18181/healthz",timeout=2); assert r.status==200 and r.read().decode()=="ok"; print("pgr healthz PASS")'
python3 -c 'import urllib.request; r=urllib.request.urlopen("http://127.0.0.1:18181/",timeout=2); assert r.status==200; open("/tmp/knowledge-pgr-rc.1.html","wb").write(r.read())'
while IFS= read -r asset; do grep -F "$asset" /tmp/knowledge-pgr-rc.1.html >/dev/null && python3 -c 'import sys,urllib.request; r=urllib.request.urlopen("http://127.0.0.1:18181"+sys.argv[1],timeout=2); assert r.status==200' "$asset" || exit 1; done < /tmp/sasedev-knowledge-0.0.3-rc.1-assets.txt
kill "$(cat /tmp/knowledge-pgr-rc.1.pid)"
wait "$(cat /tmp/knowledge-pgr-rc.1.pid)" 2>/dev/null || true
echo 'knowledge-pgr-server smoke PASS'

HOWTOs

env -u KNOWLEDGE_VITE_DEV_ORIGIN KNOWLEDGE_VITE_MANIFEST_PATH="$KNOWLEDGE_RC_MANIFEST" KNOWLEDGE_HOWTOS_BIND_ADDRESS=127.0.0.1:18182 ../builds/sasedev-knowledge/target/debug/knowledge-howtos-server > /tmp/knowledge-howtos-rc.1.log 2>&1 & echo $! > /tmp/knowledge-howtos-rc.1.pid
sleep 1
python3 -c 'import urllib.request; r=urllib.request.urlopen("http://127.0.0.1:18182/healthz",timeout=2); assert r.status==200 and r.read().decode()=="ok"; print("howtos healthz PASS")'
python3 -c 'import urllib.request; r=urllib.request.urlopen("http://127.0.0.1:18182/",timeout=2); assert r.status==200; open("/tmp/knowledge-howtos-rc.1.html","wb").write(r.read())'
while IFS= read -r asset; do grep -F "$asset" /tmp/knowledge-howtos-rc.1.html >/dev/null && python3 -c 'import sys,urllib.request; r=urllib.request.urlopen("http://127.0.0.1:18182"+sys.argv[1],timeout=2); assert r.status==200' "$asset" || exit 1; done < /tmp/sasedev-knowledge-0.0.3-rc.1-assets.txt
kill "$(cat /tmp/knowledge-howtos-rc.1.pid)"
wait "$(cat /tmp/knowledge-howtos-rc.1.pid)" 2>/dev/null || true
echo 'knowledge-howtos-server smoke PASS'

Snippets

env -u KNOWLEDGE_VITE_DEV_ORIGIN KNOWLEDGE_VITE_MANIFEST_PATH="$KNOWLEDGE_RC_MANIFEST" KNOWLEDGE_SNIPPETS_BIND_ADDRESS=127.0.0.1:18183 ../builds/sasedev-knowledge/target/debug/knowledge-snippets-server > /tmp/knowledge-snippets-rc.1.log 2>&1 & echo $! > /tmp/knowledge-snippets-rc.1.pid
sleep 1
python3 -c 'import urllib.request; r=urllib.request.urlopen("http://127.0.0.1:18183/healthz",timeout=2); assert r.status==200 and r.read().decode()=="ok"; print("snippets healthz PASS")'
python3 -c 'import urllib.request; r=urllib.request.urlopen("http://127.0.0.1:18183/",timeout=2); assert r.status==200; open("/tmp/knowledge-snippets-rc.1.html","wb").write(r.read())'
while IFS= read -r asset; do grep -F "$asset" /tmp/knowledge-snippets-rc.1.html >/dev/null && python3 -c 'import sys,urllib.request; r=urllib.request.urlopen("http://127.0.0.1:18183"+sys.argv[1],timeout=2); assert r.status==200' "$asset" || exit 1; done < /tmp/sasedev-knowledge-0.0.3-rc.1-assets.txt
kill "$(cat /tmp/knowledge-snippets-rc.1.pid)"
wait "$(cat /tmp/knowledge-snippets-rc.1.pid)" 2>/dev/null || true
echo 'knowledge-snippets-server smoke PASS'

Scope gelé et staging

test -z "$(git diff --name-only -- crates Web CHANGELOG.md ROADMAP.md docs/architecture docs/studies docs/rules prompts)"

test -f Cargo.lock
git check-ignore -q Cargo.lock

if git ls-files --error-unmatch Cargo.lock >/dev/null 2>&1; then
    echo 'Cargo.lock must remain untracked for Knowledge' >&2
    exit 1
fi

test -f Web/knowledge-template-lab/package-lock.json

git add -A
git diff --cached --check
git status --short

Le staging final attendu avant history est limité à :

M  Cargo.toml
M  README.md
M  VERSION
A  deltas/0.0.3/rc.1.md
M  docs/plans/003-V0_0_3_GIT_WRITE_PLAN.md
M  docs/validation/001-VALIDATION_MATRIX.md

Transition

PASS

Produire history/0.0.3/rc.1.md, l'appliquer, commit/push 0.0.3-rc.1, puis préparer 0.0.3-rel.1 comme promotion mécanique stable pré-tag.

FAIL

Produire le history avec le résultat exact puis une tranche rc.1.fix.1 strictement bornée à la régression observée. Ne pas promouvoir la stable tant que la RC n'est pas PASS.