0.0.2-alpha.3
This commit is contained in:
298
deltas/0.0.2/alpha.3.md
Normal file
298
deltas/0.0.2/alpha.3.md
Normal file
@@ -0,0 +1,298 @@
|
||||
<!-- 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`.
|
||||
Reference in New Issue
Block a user