0.0.2-beta.1.fix.1

This commit is contained in:
2026-09-29 06:24:50 +02:00
parent 5cee2a65b0
commit 4b51098911
7 changed files with 476 additions and 9 deletions

View File

@@ -1,5 +1,5 @@
# file: Cargo.toml
# version: 26
# version: 27
[workspace]
resolver = "3"
@@ -16,7 +16,7 @@ members = [
]
[workspace.package]
version = "0.0.2-beta.1"
version = "0.0.2-beta.1.fix.1"
edition = "2024"
publish = false
repository = "https://git.sasedev.com/Sasedev/sasedev-knowledge"

View File

@@ -1 +1 @@
0.0.2-beta.1
0.0.2-beta.1.fix.1

View File

@@ -0,0 +1,270 @@
<!-- file: deltas/0.0.2/beta.1.fix.1.md -->
<!-- version: 1 -->
# Delta 0.0.2-beta.1.fix.1 — clôture de la stabilisation runtime
## Base requise
État `0.0.2-beta.1` committé et poussé après application du history :
```text
history/0.0.2/beta.1.md = PARTIAL
```
La version devient :
```text
0.0.2-beta.1.fix.1
```
## Cause
`beta.1` acquiert la réconciliation, la revue d'horizon, les audits Markdown/Rust, Cargo/Clippy/tests, la baseline Web et le manifest Vite. La gate générée n'exécute toutefois pas les trois smokes HTTP requis par le plan pendant la stabilisation.
Cette omission appartient au contrat de validation livré, pas à une défaillance de l'opérateur. Le history `beta.1` reste donc `PARTIAL`.
## Objet du fix
Le fix n'introduit aucune fonctionnalité. Il :
- rend explicite chez `400-VALIDATION` qu'un smoke de stabilisation exigé par le plan ne peut pas être omis au motif qu'il n'existe aucun diff runtime ;
- documente `beta.1 = PARTIAL` dans le plan et la matrice ;
- rejoue la gate beta complète ;
- ajoute les trois smokes HTTP production manquants avant d'autoriser la RC.
## Scope
Fichiers remplacés :
```text
VERSION
Cargo.toml
docs/rules/400-VALIDATION.md
docs/plans/002-V0_0_2_GIT_SYNC_PLAN.md
docs/validation/001-VALIDATION_MATRIX.md
```
Fichier ajouté :
```text
deltas/0.0.2/beta.1.fix.1.md
```
Aucun fichier sous `crates/` ou `Web/` n'est remplacé. Aucun package, dépendance, contrat métier, comportement Git ou prochaine release n'est ajouté.
## Gate opérateur
```bash
set -euo pipefail
test "$(cat VERSION)" = '0.0.2-beta.1.fix.1'
grep -F 'version = "0.0.2-beta.1.fix.1"' Cargo.toml
grep -A2 '^## Statut$' history/0.0.2/beta.1.md | grep -Fx 'PARTIAL'
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.2-beta.1.fix.1-metadata.json
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-targets --all-features
(
cd Web/knowledge-template-lab
npm ci
npm run typecheck
npm run build
)
python3 - <<'PYGATE'
import json
from pathlib import Path
metadata = json.loads(Path('/tmp/sasedev-knowledge-0.0.2-beta.1.fix.1-metadata.json').read_text(encoding='utf-8'))
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 {package['name'] for package in metadata['packages']} == expected
assert len(metadata['workspace_members']) == 9
manifest_path = Path('../builds/sasedev-knowledge/web/template-lab/.vite/manifest.json')
assert manifest_path.is_file(), manifest_path
manifest = json.loads(manifest_path.read_text(encoding='utf-8'))
assert 'src/main.ts' in manifest, manifest.keys()
study = Path('docs/studies/005-V0_0_2_GIT_SYNC_RECONCILIATION.md').read_text(encoding='utf-8')
assert 'Aucun prompt `0.0.3` n'est créé' in study
roadmap = Path('ROADMAP.md').read_text(encoding='utf-8')
assert '0.0.3' not in roadmap
assert not Path('prompts/003-V0_0_3_START_PROMPT.md').exists()
assert not Path('history/0.0.2/beta.1.fix.1.md').exists()
rule400 = Path('docs/rules/400-VALIDATION.md').read_text(encoding='utf-8')
assert 'Lorsqu'un plan exige un smoke de stabilisation, cette preuve est obligatoire' in rule400
print('Knowledge 0.0.2-beta.1.fix.1 stabilization audit: clean')
PYGATE
python3 - <<'PYSMOKE'
import json
import os
from pathlib import Path
import signal
import subprocess
import time
import urllib.request
root = Path.cwd()
build_root = (root / "../builds/sasedev-knowledge").resolve()
manifest_path = build_root / "web/template-lab/.vite/manifest.json"
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
entry = manifest["src/main.ts"]
asset_paths = ["/" + entry["file"].lstrip("/")]
asset_paths.extend("/" + value.lstrip("/") for value in entry.get("css", []))
subprocess.run([
"cargo", "build",
"-p", "knowledge-pgr-server",
"-p", "knowledge-howtos-server",
"-p", "knowledge-snippets-server",
], check=True)
servers = (
("knowledge-pgr-server", "KNOWLEDGE_PGR_BIND_ADDRESS", 18181),
("knowledge-howtos-server", "KNOWLEDGE_HOWTOS_BIND_ADDRESS", 18182),
("knowledge-snippets-server", "KNOWLEDGE_SNIPPETS_BIND_ADDRESS", 18183),
)
for binary_name, bind_variable, port in servers:
binary = build_root / "target/debug" / binary_name
assert binary.is_file(), binary
env = os.environ.copy()
env.pop("KNOWLEDGE_VITE_DEV_ORIGIN", None)
env["KNOWLEDGE_VITE_MANIFEST_PATH"] = str(manifest_path)
env[bind_variable] = f"127.0.0.1:{port}"
process = subprocess.Popen(
[str(binary)],
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
start_new_session=True,
text=True,
)
try:
health_url = f"http://127.0.0.1:{port}/healthz"
for attempt in range(50):
try:
with urllib.request.urlopen(health_url, timeout=1) as response:
body = response.read().decode("utf-8")
assert response.status == 200
assert body == "ok"
break
except Exception:
if process.poll() is not None:
stdout, stderr = process.communicate()
raise AssertionError((binary_name, process.returncode, stdout, stderr))
if attempt == 49:
raise
time.sleep(0.1)
with urllib.request.urlopen(f"http://127.0.0.1:{port}/", timeout=2) as response:
html = response.read().decode("utf-8")
assert response.status == 200
for asset_path in asset_paths:
assert asset_path in html, (binary_name, asset_path)
with urllib.request.urlopen(f"http://127.0.0.1:{port}{asset_path}", timeout=2) as response:
assert response.status == 200, (binary_name, asset_path, response.status)
print(f"{binary_name} smoke PASS")
finally:
if process.poll() is None:
os.killpg(process.pid, signal.SIGTERM)
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
os.killpg(process.pid, signal.SIGKILL)
process.wait(timeout=5)
print("Knowledge 0.0.2-beta.1.fix.1 HTTP smoke: clean")
PYSMOKE
python3 - <<'PYTEXT'
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 = []
for root in roots:
if root.is_file():
paths.append(root)
elif root.is_dir():
paths.extend(path for path in root.rglob('*') if path.is_file())
for path in paths:
data = path.read_bytes()
assert b'\r' not in data, path
assert data.endswith(b'\n'), path
text = data.decode('utf-8')
for number, line in enumerate(text.splitlines(), start=1):
assert line == line.rstrip(' \t'), (path, number)
print(f'Knowledge beta.1.fix.1 text hygiene: clean ({len(paths)} file(s))')
PYTEXT
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 -z "$(git diff --name-only -- crates Web)"
test ! -e crates/knowledge-forge-gitea-lib
test ! -e crates/knowledge-store-postgres-lib
git add -A
git diff --cached --check
git status --short
```
## Résultat attendu
Le `PASS` doit notamment afficher :
```text
Knowledge 0.0.2-beta.1.fix.1 stabilization audit: clean
knowledge-pgr-server smoke PASS
knowledge-howtos-server smoke PASS
knowledge-snippets-server smoke PASS
Knowledge 0.0.2-beta.1.fix.1 HTTP smoke: clean
```
Les warnings npm/Sass déjà observés restent non bloquants si les commandes terminent avec succès.
## Transition
`PASS` autorise uniquement :
```text
0.0.2-rc.1
```
Le history `beta.1.fix.1` est produit seulement après réception de la gate opérateur complète.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/002-V0_0_2_GIT_SYNC_PLAN.md -->
<!-- version: 11 -->
<!-- version: 12 -->
# Plan 0.0.2 — Git générique et synchronisation de lecture
@@ -28,7 +28,7 @@ PGR publish report pgr-0.1.3-publish.001-report.md = PASS
Le passage de PGR `v0.1.1` à `v0.1.3` est traité comme adoption d'un projet existant via `230-ADOPTION`. Les artefacts historiques de `0.0.1` ne sont pas réécrits. `v0.1.3` constitue une provenance d'adoption, pas une dépendance normative vivante : les futurs démarrages Knowledge doivent partir des règles locales et ne consultent PGR que lorsqu'une nouvelle adoption est explicitement engagée.
`0.0.2-alpha.1` est `FAIL` pour défaut de structure du présent plan malgré des contrôles techniques propres. `alpha.1.fix.1` a corrigé uniquement ce cadrage documentaire et sa gate opérateur est `PASS`. `alpha.2` a été fermée par `alpha.2.fix.2` `PASS`. `alpha.3` a été fermée par `alpha.3.fix.1` `PASS`. `alpha.4` a été fermée par `alpha.4.fix.1` `PASS`, terminant l'adoption PGR comme migration ponctuelle. `alpha.5` est `PASS` et ferme le scope fonctionnel alpha avec `knowledge-app-lib` et le cas d'usage partagé `Changed` / `Unchanged`. `beta.1` est la tranche courante de réconciliation et revue d'horizon.
`0.0.2-alpha.1` est `FAIL` pour défaut de structure du présent plan malgré des contrôles techniques propres. `alpha.1.fix.1` a corrigé uniquement ce cadrage documentaire et sa gate opérateur est `PASS`. `alpha.2` a été fermée par `alpha.2.fix.2` `PASS`. `alpha.3` a été fermée par `alpha.3.fix.1` `PASS`. `alpha.4` a été fermée par `alpha.4.fix.1` `PASS`, terminant l'adoption PGR comme migration ponctuelle. `alpha.5` est `PASS` et ferme le scope fonctionnel alpha avec `knowledge-app-lib` et le cas d'usage partagé `Changed` / `Unchanged`. `beta.1` est `PARTIAL` : la réconciliation, les audits Rust/Git et la baseline Web passent, mais la gate générée a omis les smokes HTTP requis pendant la stabilisation. `beta.1.fix.1` est la tranche courante et rejoue la stabilisation complète sans changement fonctionnel.
## Mission
@@ -234,7 +234,11 @@ La gate Rust applique désormais explicitement `cargo fmt --all`, puis `cargo fm
### beta.1 — réconciliation et revue d'horizon
Tranche courante de stabilisation. Elle n'ajoute aucune grande fonctionnalité.
Statut opérateur : **PARTIAL**.
La tranche n'ajoute aucune grande fonctionnalité. La réconciliation documentaire, les audits Rust/Git, la baseline Web, le manifest Vite et la revue d'horizon passent. La gate générée a toutefois omis les trois smokes HTTP alors que la stratégie de validation du présent plan les exige pendant la stabilisation.
`beta.1.fix.1` corrige uniquement ce contrat de validation, rend explicite chez l'owner local `400-VALIDATION` qu'un smoke de stabilisation planifié reste obligatoire même sans diff runtime, puis rejoue la gate complète avec les trois launchers. Aucun code produit, contrat métier, package ou scope fonctionnel n'est modifié.
La réconciliation doit :
@@ -309,7 +313,7 @@ Un REPLAN modifie le présent plan de manière explicite ; il ne doit pas être
## Revue d'horizon
État courant : **réalisée dans `0.0.2-beta.1` et soumise à validation opérateur**.
État courant : **réalisée dans `0.0.2-beta.1`; contenu acquis, clôture beta en attente du smoke `beta.1.fix.1`**.
Résultat : aucune version postérieure à `0.0.2` n'est réservée. Les domaines futurs restent non numérotés parce qu'aucune mission suivante ne possède encore un scope et un ordre suffisamment décidés.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/400-VALIDATION.md -->
<!-- version: 2 -->
<!-- version: 3 -->
# Validation locale Knowledge
@@ -99,6 +99,8 @@ Les audits Markdown ou autres contrôles documentaires peuvent être exécutés
Pour une tranche Web, les preuves npm/typecheck/build sont ajoutées lorsque `Web/` ou son contrat d'intégration est touché. Une tranche documentaire ou Rust sans diff Web ne rejoue pas automatiquement le frontend.
Une phase de stabilisation globale explicitement prévue par le plan (`beta`, `rc` ou clôture stable) peut imposer une preuve de non-régression runtime même sans diff direct sous `Web/` ou dans les launchers. Lorsqu'un plan exige un smoke de stabilisation, cette preuve est obligatoire et ne peut pas être omise au motif que le code runtime n'a pas changé dans la tranche.
## Régression et dette externe
Un warning provenant d'une dépendance tierce n'est pas automatiquement un `FAIL` si la gate locale ne le traite pas comme tel et si l'outil termine avec succès. Il doit toutefois être reclassé si une mise à jour de toolchain le transforme en rupture réelle ou si la release cible exige zéro warning sur cette frontière.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/001-VALIDATION_MATRIX.md -->
<!-- version: 28 -->
<!-- version: 29 -->
# Matrice de validation Knowledge
@@ -759,3 +759,24 @@ La réconciliation beta doit prouver :
- hygiène texte et `git diff --cached --check` propres.
Un `PASS` de `beta.1` autorise uniquement `0.0.2-rc.1`. Aucun prompt de release suivante n'est créé tant que la revue d'horizon ne l'a pas engagée.
## Gate de `0.0.2-beta.1.fix.1`
Le fix de clôture beta doit prouver :
- `VERSION = 0.0.2-beta.1.fix.1` et version workspace identique ;
- history `history/0.0.2/beta.1.md` présent avec statut `PARTIAL` et committé avant application ;
- aucun nouveau package Cargo, package npm, contrat runtime ou comportement Git ;
- aucun diff sous `crates/` ou `Web/` avant le formatage ;
- revue d'horizon et étude `005` inchangées dans leur conclusion : aucune release après `0.0.2` engagée ;
- `cargo fmt --all` puis `cargo fmt --all -- --check` exécutés avant tout audit Rust ;
- audits Markdown et Rust locaux propres ;
- `cargo metadata`, `cargo check --workspace`, Clippy strict et tests workspace propres ;
- baseline Web `npm ci`, `npm run typecheck` et `npm run build` propre ;
- manifest Vite généré parsable avec l'entrée stable `src/main.ts` ;
- smoke HTTP de `knowledge-pgr-server`, `knowledge-howtos-server` et `knowledge-snippets-server` `PASS`, vérifiant `/healthz`, `/`, les références du manifest et le service effectif des assets générés ;
- `Cargo.lock` présent localement, ignoré et non suivi ;
- hygiène texte et `git diff --cached --check` propres.
Le `PASS` de `beta.1.fix.1` ferme la stabilisation beta et autorise uniquement `0.0.2-rc.1`. Un résultat incomplet ou en échec produit son history réel et interdit la RC.

View File

@@ -0,0 +1,170 @@
<!-- file: history/0.0.2/beta.1.fix.1.md -->
<!-- version: 1 -->
# History 0.0.2-beta.1.fix.1 — clôture de stabilisation runtime
## Statut
FAIL
La gate opérateur de `0.0.2-beta.1.fix.1` exécutée le `2026-09-29` acquiert les preuves Rust, Cargo, tests, Web et les trois smokes HTTP requis, mais deux commandes requises échouent dans la gate elle-même : l'audit Python de stabilisation contient une chaîne mal quotée et `git diff --cached --check` détecte une ligne vide supplémentaire en fin de `docs/validation/001-VALIDATION_MATRIX.md`.
Conformément à `400-VALIDATION`, une commande requise en échec conserve le statut `FAIL` même si les preuves runtime exécutées ensuite passent.
## Baseline opérateur
L'opérateur indique que la matérialisation de `beta.1` a été réalisée correctement avant application de `beta.1.fix.1`. Le rendu terminal du commit/push n'est plus disponible à la suite de la fermeture de la fenêtre GNOME Terminal après activation de `set -euo pipefail`.
L'état observé au démarrage de la gate confirme néanmoins :
```text
VERSION 0.0.2-beta.1.fix.1
Cargo workspace version 0.0.2-beta.1.fix.1
history/0.0.2/beta.1.md PARTIAL
```
## Contrôles documentaires et formatage
Les audits suivants passent :
```text
Markdown header audit clean (89 file(s))
Markdown link audit clean (72 local link(s), 89 file(s))
Markdown table audit clean (4 table(s), 89 file(s))
cargo fmt --all PASS
cargo fmt --all -- --check PASS
```
Le premier `git diff --check` de la gate signale toutefois :
```text
docs/validation/001-VALIDATION_MATRIX.md:782: new blank line at EOF.
```
## Audits Rust
Après formatage, les audits Rust passent :
```text
Rust test-layout audit clean (9 crate(s))
Rust blank-line audit clean (32 file(s))
Rust item-spacing audit clean (32 file(s))
Rust module-order audit clean (32 file(s))
Rust trait-import-block audit clean (32 file(s))
Rust re-export-block audit clean (32 file(s))
Rust crate-root facade audit clean (6 crate root(s))
Rust export completeness audit 0 candidate(s) across 9 package(s)
```
## Cargo, Clippy et tests
Les neuf packages passent :
```text
cargo metadata --format-version 1 --no-deps PASS
cargo check --workspace PASS
cargo clippy --workspace --all-targets --all-features
-- -D warnings PASS
cargo test --workspace --all-targets --all-features PASS
```
Résultats observés :
```text
knowledge-app-lib 3 PASS
knowledge-domain-lib 3 PASS
knowledge-git-api 1 PASS
knowledge-git-lib 8 unit PASS + 2 integration PASS
knowledge-sync-api 1 PASS
knowledge-web-lib 4 PASS
launchers 0 test chacun
```
Les tests d'intégration Git réels restent propres.
## Baseline Web
Les commandes suivantes passent :
```text
npm ci
npm run typecheck
npm run build
```
Vite transforme `63` modules et produit le manifest attendu. Les warnings Sass issus de Bootstrap et l'avertissement npm sur le script d'installation de `@parcel/watcher@2.6.0` restent non bloquants.
## Échec de l'audit de stabilisation
Le bloc `PYGATE` échoue avec :
```text
SyntaxError: unterminated string literal
```
La cause est la chaîne Python suivante, délimitée par des apostrophes tout en contenant `n'est` :
```text
assert 'Aucun prompt `0.0.3` n'est créé' in study
```
Cet échec appartient à la gate livrée, pas au produit.
## Smokes HTTP
Malgré l'échec précédent, les trois smokes HTTP sont exécutés et passent :
```text
knowledge-pgr-server smoke PASS
knowledge-howtos-server smoke PASS
knowledge-snippets-server smoke PASS
Knowledge 0.0.2-beta.1.fix.1 HTTP smoke: clean
```
Ils prouvent `/healthz`, `/`, la présence des assets du manifest dans le HTML et leur service HTTP effectif.
## Hygiène texte et EOF
Le script d'hygiène texte affiche :
```text
Knowledge beta.1.fix.1 text hygiene: clean (89 file(s))
```
mais son contrat est insuffisant : il vérifie seulement qu'un fichier se termine par `\n`, pas qu'il se termine par exactement un seul `\n`. Il laisse donc passer un suffixe `\n\n`.
Après staging, `git diff --cached --check` échoue de nouveau sur la même ligne vide supplémentaire à EOF dans `001-VALIDATION_MATRIX.md`.
## Frontières
Les contrôles suivants passent :
```text
Cargo.lock présent localement PASS
Cargo.lock ignoré PASS
Cargo.lock non suivi PASS
aucun diff sous crates/ ou Web/ PASS
aucune crate forge Gitea PASS
aucun store PostgreSQL PASS
```
Le `git status --short` final montre uniquement les fichiers attendus de la tranche après correction de la faute de frappe opérateur `it status --short`.
## Décision
`0.0.2-beta.1.fix.1` est `FAIL`.
Les preuves runtime manquantes de `beta.1` sont désormais acquises, mais la stabilisation beta ne peut pas être fermée tant que la gate elle-même n'est pas propre.
La transition autorisée est :
```text
appliquer ce history
-> git add / diff --cached --check / status
-> commit exact "0.0.2-beta.1.fix.1"
-> push origin master
-> vérifier le workspace propre
-> appliquer seulement ensuite 0.0.2-beta.1.fix.2
```
`beta.1.fix.2` doit rester documentaire/gate-only : corriger le quoting Python, normaliser les EOF à exactement un LF, rendre cette propriété vérifiable et ne pas réintroduire `set -euo pipefail` dans une gate destinée au shell interactif.