Files
sasedev-knowledge/deltas/0.0.2/alpha.3.md
2026-09-28 19:23:12 +02:00

9.6 KiB

Delta 0.0.2-alpha.3 — refresh, résolution et snapshot Git réels

Base requise

Partir de 0.0.2-alpha.2.fix.2 après application, validation, history PASS, commit et push :

deltas/0.0.2/alpha.2.md                présent et historique
deltas/0.0.2/alpha.2.fix.1.md          présent et historique
deltas/0.0.2/alpha.2.fix.2.md          présent et historique
history/0.0.2/alpha.2.md               FAIL
history/0.0.2/alpha.2.fix.1.md         FAIL
history/0.0.2/alpha.2.fix.2.md         PASS

Les deltas et histories antérieurs ne doivent pas être réécrits.

La version devient :

0.0.2-alpha.3

Scope

Cette tranche complète la matérialisation Git de lecture déjà prévue par le plan :

  • faire implémenter réellement knowledge-git-api::GitRepository par knowledge-git-lib ;
  • enregistrer explicitement les configurations physiques des sources dans GitBackend sans les faire remonter dans le domaine ou l'API provider-neutral ;
  • ajouter au contrat uniquement GitSnapshot et prepare_snapshot, maintenant nécessaires ;
  • initialiser ou rafraîchir le mirror avec pruning ;
  • résoudre une référence opaque vers un commit réel ;
  • matérialiser un worktree détaché adressé par la révision résolue ;
  • valider un snapshot existant avant réutilisation ;
  • prouver le chemin avec de vrais repositories Git temporaires locaux.

Cette tranche ne matérialise pas encore le cas d'usage Changed / Unchanged d'alpha.4.

Changements apportés

Contrat provider-neutral

knowledge-git-api ajoute GitSnapshot, contenant uniquement :

GitRevision
PathBuf de lecture locale

GitRepository gagne :

prepare_snapshot(source_id, revision)

Aucune API de forge, notion de remote, commande Git ou configuration physique n'entre dans le contrat.

Backend configuré

GitBackend conserve sa configuration globale puis enregistre explicitement des GitSourceConfig par SourceId.

Un doublon est refusé par une erreur récupérable. Une opération provider-neutral sur une source inconnue échoue également sans exposer son URL ou son chemin.

Refresh

Le refresh :

  1. vérifie que la source logique possède une configuration physique enregistrée ;
  2. initialise le mirror s'il n'existe pas encore ;
  3. exécute ensuite :
git --git-dir <mirror> remote update --prune

Aucune API de forge n'est nécessaire.

Résolution

La résolution exige un mirror existant et utilise :

git --git-dir <mirror> rev-parse --verify --end-of-options <reference>^{commit}

La sortie produite par le backend doit être non vide et hexadécimale avant de devenir GitRevision. Aucune longueur SHA particulière n'est figée.

Snapshot

Le chemin de snapshot reste :

<state-root>/snapshots/<source-key>/<resolved-revision>/

Un snapshot absent est créé par :

git --git-dir <mirror> worktree add --detach -- <snapshot-path> <resolved-revision>

Un snapshot existant n'est réutilisé qu'après :

git -C <snapshot> rev-parse --verify HEAD
git -C <snapshot> status --porcelain=v1 --untracked-files=all

Le HEAD doit correspondre exactement à la révision demandée et le statut doit être vide. Une divergence ou un snapshot sale est rejeté sans suppression automatique.

Tests réels

crates/knowledge-git-lib/tests/git_read_path.rs crée un repository Git local temporaire réel et vérifie notamment :

  • initialisation du mirror via la voie refresh ;
  • résolution de refs/heads/main ;
  • création puis réutilisation idempotente d'un snapshot ;
  • ajout d'un second commit source, refresh et nouvelle révision ;
  • snapshot distinct pour la nouvelle révision ;
  • rejet d'une référence inexistante ;
  • rejet d'un snapshot existant rendu sale.

Ces tests exercent la frontière knowledge_git_api::GitRepository et le client Git réel. Les mocks existants restent uniquement des tests unitaires des arguments/processus.

Hors scope confirmé

La tranche n'ajoute pas :

  • knowledge-app-lib ;
  • scheduler ;
  • persistance de dernière révision ;
  • PostgreSQL ou migrations ;
  • adapter Gitea/GitHub/GitLab ;
  • webhook ;
  • status/diff public, branch, commit, merge, rebase ou push ;
  • dépendance Git Rust secondaire ;
  • changement sous Web/ ;
  • changement de rendu ou de route HTTP.

Gate opérateur

Exécuter depuis la racine du workspace après application du delta :

test "$(cat VERSION)" = '0.0.2-alpha.3'
grep -F 'version = "0.0.2-alpha.3"' Cargo.toml
grep -A2 '^## Statut$' history/0.0.2/alpha.2.fix.2.md | grep -Fx 'PASS'

git diff --check

python3 - <<'PY'
from pathlib import Path
import tomllib

root = tomllib.loads(Path("Cargo.toml").read_text(encoding="utf-8"))
manifest = tomllib.loads(Path("crates/knowledge-git-lib/Cargo.toml").read_text(encoding="utf-8"))
assert len(root["workspace"]["members"]) == 8
assert set(manifest["dependencies"]) == {"knowledge-domain-lib", "knowledge-git-api"}

api = Path("crates/knowledge-git-api/src/lib.rs").read_text(encoding="utf-8")
backend = Path("crates/knowledge-git-lib/src/backend.rs").read_text(encoding="utf-8")
error = Path("crates/knowledge-git-lib/src/error.rs").read_text(encoding="utf-8")
integration = Path("crates/knowledge-git-lib/tests/git_read_path.rs").read_text(encoding="utf-8")

for phrase in (
    "pub struct GitSnapshot",
    "fn prepare_snapshot(",
):
    assert phrase in api, phrase

for phrase in (
    "impl knowledge_git_api::GitRepository for crate::GitBackend",
    "pub fn register_source(",
    'std::ffi::OsString::from("remote")',
    'std::ffi::OsString::from("update")',
    'std::ffi::OsString::from("--prune")',
    'std::ffi::OsString::from("rev-parse")',
    'std::ffi::OsString::from("--verify")',
    'std::ffi::OsString::from("--end-of-options")',
    'std::ffi::OsString::from("worktree")',
    'std::ffi::OsString::from("add")',
    'std::ffi::OsString::from("--detach")',
    'std::ffi::OsString::from("status")',
    'std::ffi::OsString::from("--porcelain=v1")',
    'std::ffi::OsString::from("--untracked-files=all")',
):
    assert phrase in backend, phrase

for phrase in (
    "DuplicateSource",
    "SourceNotConfigured",
    "MirrorMissing",
    "InvalidRevision",
    "InvalidSnapshot",
    "RefreshMirror",
    "ResolveRevision",
    "CreateSnapshot",
    "InspectSnapshot",
):
    assert phrase in error, phrase

for phrase in (
    "real_local_repository_refreshes_resolves_and_materializes_revision_snapshots",
    "invalid_reference_and_dirty_existing_snapshot_are_rejected",
    "knowledge_git_api::GitRepository::refresh",
    "knowledge_git_api::GitRepository::resolve_revision",
    "knowledge_git_api::GitRepository::prepare_snapshot",
):
    assert phrase in integration, phrase

for forbidden in (
    'Command::new("sh")',
    'Command::new("bash")',
    'Command::new("cmd")',
    'Command::new("powershell")',
    "knowledge-app-lib",
    "knowledge-forge-gitea-lib",
    "knowledge-store-postgres-lib",
):
    assert forbidden not in backend + error, forbidden

print("Knowledge 0.0.2-alpha.3 structural audit: clean")
PY

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_export_completeness.py --root . --summary-only

git --version
cargo fmt --all -- --check
cargo metadata --format-version 1 --no-deps > /tmp/sasedev-knowledge-0.0.2-alpha.3-metadata.json
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p knowledge-git-api --all-targets --all-features
cargo test -p knowledge-git-lib --all-targets --all-features
cargo test -p knowledge-git-lib --test git_read_path
cargo test --workspace --all-targets --all-features

python3 - <<'PY'
import json
from pathlib import Path

metadata = json.loads(Path("/tmp/sasedev-knowledge-0.0.2-alpha.3-metadata.json").read_text(encoding="utf-8"))
packages = {package["name"] for package in metadata["packages"]}
expected = {
    "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 packages == expected, packages
assert len(metadata["workspace_members"]) == 8, metadata["workspace_members"]
print("Knowledge 0.0.2-alpha.3 Cargo metadata audit: clean")
PY

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 -- Web)"
test -z "$(git diff --name-only -- crates/knowledge-sync-api)"
test ! -e crates/knowledge-app-lib
test ! -e crates/knowledge-forge-gitea-lib
test ! -e crates/knowledge-store-postgres-lib
test ! -e history/0.0.2/alpha.3.md

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

Résultat attendu

La tranche est PASS uniquement si :

  • le formatage, la compilation et Clippy strict sont propres ;
  • le test knowledge-git-api passe ;
  • les tests unitaires de knowledge-git-lib passent ;
  • les deux tests Git réels de git_read_path passent ;
  • les tests workspace passent ;
  • aucun changement hors scope n'est observé ;
  • aucun history alpha.3 n'est créé avant réception des résultats opérateur.

Un FAIL, PARTIAL ou BLOCKED doit être historisé avant tout fix. Un PASS autorise uniquement 0.0.2-alpha.4.