[Bug — medium] Après nettoyage des clones, un ancien edit rend le prochain audit impossible #89

Closed
opened 2026-09-17 12:09:32 +00:00 by hermes · 0 comments
Member

Ticket de revue indépendante, pour évaluation ultérieure uniquement. Mathieu n’a demandé ni implémentation, ni déclenchement de boucle, ni PR. Aucun correctif apporté.

Référence : branche main, commit 30b53a270c3e28024a74762fc94c5ddb6f541f38 ; branche distante relue juste avant publication. Le contrôle de fraîcheur du paquet 0.1.0.r23.gee99222 passe : ses entrées de code sont identiques à celles examinées.

Défaut et impact

Gravité : medium. Une recette éditée puis approuvée laisse un commit local comme référence SQLite. Quand le clone est supprimé (nettoyage du répertoire temporaire, notamment après redémarrage), un nouveau clone amont ne contient plus ce commit. Le paquet reste bloqué en préparation d’audit ; réessayer ne recrée pas l’objet Git disparu.

Reproduction exécutée sur deux dépôts Git temporaires inertes : créer un amont ; cloner ; modifier PKGBUILD comme texte ; appeler le vrai snapshotEditedWorktree ; persister cette identité avec advanceBaselines ; supprimer uniquement le clone local ; recloner l’amont ; appeler buildAuditBundle avec la référence relue de SQLite. Aucun PKGBUILD exécuté et aucune vraie installation simulée comme preuve de succès.

Observé : build recipe diff: git diff --no-ext-diff <commit-local> --: exit status 128: fatal: bad object <commit-local>.

Attendu : rester capable d’auditer la recette actuelle ; expliciter que le différentiel historique est indisponible, sans prétendre qu’elle est inchangée, sans perdre silencieusement l’historique et sans contourner l’approbation.

Cause et emplacements

Piste minimale et acceptation

Traiter explicitement une référence absente : proposer/produire un audit complet avec avertissement sur l’absence de comparaison, plutôt qu’exiger une conservation permanente de tous les clones. C’est une dégradation du contexte différentiel, jamais un contournement d’audit. Ne pas masquer une autre erreur Git ni classer la recette unchanged.

Tests : scénario d’édition puis perte du clone ci-dessus ; référence distante disparue ; référence encore disponible conservant le diff ; erreur Git non liée à un objet absent restant visible ; nouvel audit valide et approbation requis ; ancienne référence non avancée après annulation/échec ; identité finale toujours contrôlée.

Déduplication : #36/#37 ont corrigé le contexte d’une recette inchangée, #74/#75 le menu de reprise et les liens ; aucun ne traite l’objet historique disparu. Blocage limité aux références absentes, pas à toute mise à jour. Mathieu : évaluer cette récupération minimale avant d’en autoriser l’implémentation.

Reproduction automatisée isolée

Le test ci-dessous réutilise les helpers existants de internal/app. Il a été exécuté avec un overlay Go, sans modifier le checkout : go test -overlay /chemin/overlay.json ./internal/app -run TestReviewProbeEditedBaselineSurvivesCloneCleanup -v -count=1. L’overlay associe le chemin absolu internal/app/review_probe_test.go du checkout au fichier temporaire contenant ce test. Ce test exprime le comportement attendu et échoue actuellement. Aucun vrai Paru/Pacman, fournisseur LLM ou contenu de paquet n’est exécuté.

Test Go reproductible
package app
import ("os"; "path/filepath"; "testing")
func TestReviewProbeEditedBaselineSurvivesCloneCleanup(t *testing.T){
 dir:=t.TempDir(); upstream:=createRecipeRepo(t,dir,"hello","pkgname=hello\npkgver=1\n")
 local:=filepath.Join(dir,"local"); gitRun(t,dir,"clone",upstream,local)
 if err:=os.WriteFile(filepath.Join(local,"PKGBUILD"),[]byte("pkgname=hello\npkgver=1\npkgrel=2\n"),0644);err!=nil{t.Fatal(err)}
 if err:=snapshotEditedWorktree(local,map[string]bool{});err!=nil{t.Fatal(err)}
 id,_,err:=readRecipeIdentity("hello",local);if err!=nil{t.Fatal(err)}
 store,err:=openState(filepath.Join(dir,"state.sqlite3"));if err!=nil{t.Fatal(err)};defer store.Close()
 if err:=store.advanceBaselines([]recipeIdentity{id});err!=nil{t.Fatal(err)}
 if err:=os.RemoveAll(local);err!=nil{t.Fatal(err)}
 gitRun(t,dir,"clone",upstream,local)
 baseline,err:=store.baseline("hello");if err!=nil{t.Fatal(err)}
 bundle,err:=buildAuditBundle("hello",local,baseline);t.Logf("after clone cleanup: mode=%q err=%v",bundle.Mode,err)
 if err!=nil{t.Error("valid current recipe cannot be audited after loss of local-only baseline commit")}
}

Ticket de revue indépendante, **pour évaluation ultérieure uniquement**. Mathieu n’a demandé ni implémentation, ni déclenchement de boucle, ni PR. Aucun correctif apporté. Référence : branche `main`, commit `30b53a270c3e28024a74762fc94c5ddb6f541f38` ; branche distante relue juste avant publication. Le contrôle de fraîcheur du paquet `0.1.0.r23.gee99222` passe : ses entrées de code sont identiques à celles examinées. ## Défaut et impact **Gravité : medium.** Une recette éditée puis approuvée laisse un commit local comme référence SQLite. Quand le clone est supprimé (nettoyage du répertoire temporaire, notamment après redémarrage), un nouveau clone amont ne contient plus ce commit. Le paquet reste bloqué en préparation d’audit ; réessayer ne recrée pas l’objet Git disparu. Reproduction exécutée sur deux dépôts Git temporaires inertes : créer un amont ; cloner ; modifier `PKGBUILD` comme texte ; appeler le vrai `snapshotEditedWorktree` ; persister cette identité avec `advanceBaselines` ; supprimer uniquement le clone local ; recloner l’amont ; appeler `buildAuditBundle` avec la référence relue de SQLite. Aucun PKGBUILD exécuté et aucune vraie installation simulée comme preuve de succès. Observé : `build recipe diff: git diff --no-ext-diff <commit-local> --: exit status 128: fatal: bad object <commit-local>`. Attendu : rester capable d’auditer la recette actuelle ; expliciter que le différentiel historique est indisponible, sans prétendre qu’elle est inchangée, sans perdre silencieusement l’historique et sans contourner l’approbation. ## Cause et emplacements - [Clones par défaut dans le répertoire temporaire, run.go:114–127](https://git.2027a.net/2027a/auroscope/src/commit/30b53a270c3e28024a74762fc94c5ddb6f541f38/internal/app/run.go#L114-L127) alors que SQLite est persistant. - [Commit local d’édition, recipe.go:229–257](https://git.2027a.net/2027a/auroscope/src/commit/30b53a270c3e28024a74762fc94c5ddb6f541f38/internal/app/recipe.go#L229-L257). - [Diff obligatoire vers l’ancien commit, recipe.go:68–82](https://git.2027a.net/2027a/auroscope/src/commit/30b53a270c3e28024a74762fc94c5ddb6f541f38/internal/app/recipe.go#L68-L82), sans traitement de sa disparition. - [Avancement après succès Paru, review.go:162–164](https://git.2027a.net/2027a/auroscope/src/commit/30b53a270c3e28024a74762fc94c5ddb6f541f38/internal/app/review.go#L162-L164). ## Piste minimale et acceptation Traiter explicitement une référence absente : proposer/produire un audit complet avec avertissement sur l’absence de comparaison, plutôt qu’exiger une conservation permanente de tous les clones. C’est une dégradation du contexte différentiel, **jamais** un contournement d’audit. Ne pas masquer une autre erreur Git ni classer la recette `unchanged`. Tests : scénario d’édition puis perte du clone ci-dessus ; référence distante disparue ; référence encore disponible conservant le diff ; erreur Git non liée à un objet absent restant visible ; nouvel audit valide et approbation requis ; ancienne référence non avancée après annulation/échec ; identité finale toujours contrôlée. Déduplication : #36/#37 ont corrigé le contexte d’une recette inchangée, #74/#75 le menu de reprise et les liens ; aucun ne traite l’objet historique disparu. Blocage limité aux références absentes, pas à toute mise à jour. Mathieu : évaluer cette récupération minimale avant d’en autoriser l’implémentation. ## Reproduction automatisée isolée Le test ci-dessous réutilise les helpers existants de `internal/app`. Il a été exécuté avec un overlay Go, sans modifier le checkout : `go test -overlay /chemin/overlay.json ./internal/app -run TestReviewProbeEditedBaselineSurvivesCloneCleanup -v -count=1`. L’overlay associe le chemin absolu `internal/app/review_probe_test.go` du checkout au fichier temporaire contenant ce test. Ce test exprime le comportement attendu et **échoue actuellement**. Aucun vrai Paru/Pacman, fournisseur LLM ou contenu de paquet n’est exécuté. <details><summary>Test Go reproductible</summary> ```go package app import ("os"; "path/filepath"; "testing") func TestReviewProbeEditedBaselineSurvivesCloneCleanup(t *testing.T){ dir:=t.TempDir(); upstream:=createRecipeRepo(t,dir,"hello","pkgname=hello\npkgver=1\n") local:=filepath.Join(dir,"local"); gitRun(t,dir,"clone",upstream,local) if err:=os.WriteFile(filepath.Join(local,"PKGBUILD"),[]byte("pkgname=hello\npkgver=1\npkgrel=2\n"),0644);err!=nil{t.Fatal(err)} if err:=snapshotEditedWorktree(local,map[string]bool{});err!=nil{t.Fatal(err)} id,_,err:=readRecipeIdentity("hello",local);if err!=nil{t.Fatal(err)} store,err:=openState(filepath.Join(dir,"state.sqlite3"));if err!=nil{t.Fatal(err)};defer store.Close() if err:=store.advanceBaselines([]recipeIdentity{id});err!=nil{t.Fatal(err)} if err:=os.RemoveAll(local);err!=nil{t.Fatal(err)} gitRun(t,dir,"clone",upstream,local) baseline,err:=store.baseline("hello");if err!=nil{t.Fatal(err)} bundle,err:=buildAuditBundle("hello",local,baseline);t.Logf("after clone cleanup: mode=%q err=%v",bundle.Mode,err) if err!=nil{t.Error("valid current recipe cannot be audited after loss of local-only baseline commit")} } ``` </details>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
2027a/auroscope#89
No description provided.