299 lines
9.6 KiB
Markdown
299 lines
9.6 KiB
Markdown
<!-- file: deltas/0.0.2/alpha.3.md -->
|
|
<!-- version: 1 -->
|
|
|
|
# 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 :
|
|
|
|
```text
|
|
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 :
|
|
|
|
```text
|
|
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 :
|
|
|
|
```text
|
|
GitRevision
|
|
PathBuf de lecture locale
|
|
```
|
|
|
|
`GitRepository` gagne :
|
|
|
|
```text
|
|
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 :
|
|
|
|
```text
|
|
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 :
|
|
|
|
```text
|
|
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 :
|
|
|
|
```text
|
|
<state-root>/snapshots/<source-key>/<resolved-revision>/
|
|
```
|
|
|
|
Un snapshot absent est créé par :
|
|
|
|
```text
|
|
git --git-dir <mirror> worktree add --detach -- <snapshot-path> <resolved-revision>
|
|
```
|
|
|
|
Un snapshot existant n'est réutilisé qu'après :
|
|
|
|
```text
|
|
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 :
|
|
|
|
```bash
|
|
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`.
|