Files
sasedev-knowledge/deltas/0.0.3/alpha.3.md
2026-09-29 11:39:02 +02:00

257 lines
10 KiB
Markdown

<!-- file: deltas/0.0.3/alpha.3.md -->
<!-- version: 1 -->
# Delta 0.0.3-alpha.3 — worktree d'écriture et commit candidat
## Baseline requise
Partir de `0.0.3-alpha.2` après application, commit et push de son history `PASS`.
La version devient :
```text
0.0.3-alpha.3
```
## Objet
Implémenter dans `knowledge-git-lib` la création locale réelle d'une révision candidate à partir d'une base Git explicite, sans mettre encore à jour de branche distante.
La tranche :
- ajoute un worktree d'écriture temporaire et déterministe sous la racine d'état du backend ;
- réutilise le mirror contrôlé du `SourceId` et exige une `GitRevision` de base sûre ;
- applique exactement les mutations `Write` / `Delete` demandées ;
- refuse toute cible ou tout parent filesystem qui est un symlink ;
- stage uniquement les chemins demandés puis vérifie que l'index contient exactement cet ensemble ;
- neutralise la configuration Git système/globale ambiante pertinente et conserve `core.hooksPath` sous contrôle ;
- crée le commit avec auteur et committer explicitement issus de `GitCommitIdentity`, `--no-verify` et `--no-gpg-sign` ;
- vérifie que le candidat a exactement la base demandée comme premier parent ;
- retient l'objet candidat sous `refs/knowledge/candidates/<revision>` avant suppression du worktree ;
- retire le worktree possédé après succès et tente une suppression forcée après une erreur survenue dans ce worktree ;
- refuse un worktree `candidate` préexistant au lieu de le supprimer silencieusement ;
- ajoute des tests d'intégration Git réels pour le candidat et l'échappement par symlink.
`alpha.3` ne met à jour aucun remote et n'implémente pas encore `GitRepositoryWriter` sur `GitBackend`, car ce trait exige également `push_candidate`. L'implémentation complète du trait et le compare-and-exchange distant restent réservés à `alpha.4`.
## Scope des fichiers
REPLACE :
```text
VERSION
Cargo.toml
README.md
crates/knowledge-git-lib/src/backend.rs
crates/knowledge-git-lib/src/error.rs
crates/knowledge-git-lib/src/lib.rs
crates/knowledge-git-lib/unit_tests/backend.rs
docs/architecture/002-KNOWLEDGE_ARCHITECTURE.md
docs/plans/003-V0_0_3_GIT_WRITE_PLAN.md
docs/validation/001-VALIDATION_MATRIX.md
```
ADD :
```text
crates/knowledge-git-lib/src/write.rs
crates/knowledge-git-lib/tests/git_write_candidate.rs
deltas/0.0.3/alpha.3.md
```
DELETE : aucun.
`knowledge-git-api`, `knowledge-app-lib`, `Web/`, `CHANGELOG.md` et `ROADMAP.md` ne sont pas modifiés.
Aucun history `alpha.3` n'est inclus dans ce delta.
## Contrat backend matérialisé
Le chemin local devient :
```text
GitRevision de base
-> mirror contrôlé
-> write-worktrees/<source-key>/candidate
-> mutations confinées
-> git add limité aux chemins demandés
-> commit avec identité explicite
-> vérification HEAD / HEAD^1
-> refs/knowledge/candidates/<revision>
-> suppression du worktree temporaire
-> GitRevision candidate
```
La racine d'état contrôlée contient désormais également :
```text
empty-global.gitconfig
write-worktrees/
```
`empty-global.gitconfig` neutralise la configuration utilisateur globale pour les commandes possédées par le backend ; `GIT_CONFIG_NOSYSTEM=1` neutralise la configuration système. La configuration repository nécessaire au mirror reste disponible, tandis que `core.hooksPath` est forcé vers `hooks-disabled`.
## Confinement filesystem
`GitMutationPath` fournit déjà le confinement lexical. `alpha.3` ajoute le contrôle physique : avant toute écriture ou suppression, chaque composant existant du chemin sous le worktree est inspecté avec `symlink_metadata`.
Un symlink rencontré produit `UnsafeMutationTarget`. Une suppression d'une cible absente produit `MutationTargetMissing`. Les erreurs filesystem restent récupérables et ne contiennent pas le chemin ou le contenu sensible dans leur texte public.
Un worktree préexistant à l'emplacement contrôlé produit `WriteWorktreeExists`. Il n'est pas supprimé automatiquement.
## Candidate et nettoyage
Une candidate n'est valide que si :
- les chemins réellement stagés correspondent exactement aux mutations demandées ;
- le commit est créé avec l'identité explicite de la requête ;
- `HEAD` est une révision Git sûre ;
- `HEAD^1` est exactement la base demandée ;
- une référence interne `refs/knowledge/candidates/<revision>` conserve l'objet avant retrait du worktree.
Le retrait normal n'utilise pas `--force`. Si une erreur survient après création du worktree possédé par l'opération, le backend utilise `worktree remove --force` pour retirer uniquement cet état temporaire connu. Un échec de nettoyage devient `WriteCleanupFailed` afin qu'un état inattendu ne soit pas masqué.
## Gate opérateur
Exécuter depuis la racine du dépôt après application du delta :
```bash
test "$(cat VERSION)" = '0.0.3-alpha.3'
grep -F 'version = "0.0.3-alpha.3"' Cargo.toml
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-alpha.3-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 --workspace --all-targets --all-features
python3 - <<'PYGATE'
from pathlib import Path
history = Path('history/0.0.3/alpha.2.md').read_text(encoding='utf-8')
assert '\nPASS\n' in history
write = Path('crates/knowledge-git-lib/src/write.rs').read_text(encoding='utf-8')
backend = Path('crates/knowledge-git-lib/src/backend.rs').read_text(encoding='utf-8')
errors = Path('crates/knowledge-git-lib/src/error.rs').read_text(encoding='utf-8')
api = Path('crates/knowledge-git-api/src/write.rs').read_text(encoding='utf-8')
plan = Path('docs/plans/003-V0_0_3_GIT_WRITE_PLAN.md').read_text(encoding='utf-8')
changelog = Path('CHANGELOG.md').read_text(encoding='utf-8')
for required in (
'pub fn create_candidate(',
'symlink_metadata',
'CandidateMutationMismatch',
'GIT_AUTHOR_NAME',
'GIT_COMMITTER_NAME',
'--no-verify',
'--no-gpg-sign',
'HEAD^1',
'refs/knowledge/candidates/',
'RemoveWriteWorktree',
):
assert required in write, required
assert 'GIT_CONFIG_GLOBAL' in backend
assert 'GIT_CONFIG_NOSYSTEM' in backend
assert 'core.hooksPath' in backend
assert 'write_worktrees_path' in backend
assert 'empty_global_config_path' in backend
for required_error in (
'WriteWorktreeExists',
'UnsafeMutationTarget',
'MutationTargetMissing',
'MutationFilesystemFailed',
'CandidateMutationMismatch',
'InvalidCandidate',
'WriteCleanupFailed',
):
assert required_error in errors, required_error
assert 'trait GitRepositoryWriter' in api
assert 'fn create_candidate(' in api
assert 'fn push_candidate(' in api
assert 'impl knowledge_git_api::GitRepositoryWriter for crate::GitBackend' not in write
assert 'GitPushRequest' not in write
assert 'push_candidate' not in write
assert '`alpha.2` a ensuite matérialisé le contrat d\'écriture provider-neutral et sa gate opérateur est `PASS`' in plan
assert '## 0.0.3' not in changelog
assert not Path('history/0.0.3/alpha.3.md').exists()
assert not Path('crates/knowledge-forge-gitea-lib').exists()
assert not Path('crates/knowledge-store-postgres-lib').exists()
assert not Path('migrations').exists()
print('Knowledge 0.0.3-alpha.3 candidate-worktree audit: clean')
PYGATE
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
assert not data.endswith(b'\n\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 0.0.3-alpha.3 text hygiene: clean ({len(paths)} file(s))')
PYTEXT
test -z "$(git diff --name-only -- crates/knowledge-git-api crates/knowledge-app-lib Web CHANGELOG.md ROADMAP.md)"
test ! -e history/0.0.3/alpha.3.md
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
```
La gate ne rejoue pas npm/Vite/HTTP : aucun fichier `Web/`, launcher ou contrat runtime Web n'est modifié.
## Transition
### PASS
Produire `history/0.0.3/alpha.3.md`, l'appliquer, commit/push `0.0.3-alpha.3`, puis préparer `0.0.3-alpha.4` pour l'observation distante, le compare-and-exchange et le push gardé avec conflits explicites.
### FAIL / PARTIAL / BLOCKED
Conserver le résultat réel dans son history avant toute correction. Une correction bornée utilise `alpha.3.fix.N` ; une remise en cause du cycle de vie des worktrees, de la frontière provider-neutral ou de la stratégie process Git exige un `REPLAN` explicite.