257 lines
10 KiB
Markdown
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.
|