ADR 0006 — safeResolve en mode NEEDS-REVIEW¶
Contexte¶
Les checks de porte utilisent des patterns de chemin comme .product/.epics/{id}/hypothesis.md. Le {id} est substitué par l'identifiant de l'objet en transition. La fonction safeResolve garantit que le chemin résolu reste dans le projectRoot — sinon, le risque serait qu'un identifiant malicieux ou mal formé lise un fichier arbitraire du système.
En V2, un chemin échappant au projectRoot produisait un fail silencieux : le fichier « n'existait pas ». Ce comportement posait problème :
- Un projet légitime avec un mapping custom (mono-repo, symlink) obtenait des
failcryptiques. - L'utilisateur ne comprenait pas pourquoi le check échouait.
- L'option
--forcedevenait un réflexe, masquant d'autres problèmes réels.
Options envisagées¶
- Garder le
failsilencieux — statu quo, insatisfaisant. - Abort dur : si le chemin échappe au projectRoot, erreur fatale de la CLI.
failexplicite avec message clair — mais reste bloquant.warnqui déclenche NEEDS-REVIEW — message clair, décision humaine.
Décision¶
Retenu : mode warn + NEEDS-REVIEW (option 4).
Si safeResolve détecte qu'un chemin résout hors du projectRoot, le check renvoie un résultat status: warn avec reason: "chemin hors projet : <chemin>". Le verdict global de la porte bascule au minimum en NEEDS-REVIEW. L'humain est informé, peut évaluer si la configuration du projet est légitime, et confirmer la transition en connaissance de cause.
Conséquences¶
Positives :
- Diagnostic clair : le message indique exactement quel chemin a été rejeté.
- Pas de faux négatif : plus de fichiers « manquants » à cause d'un résolution hors scope.
- Décision humaine préservée : l'utilisateur peut forcer en conscience si la config est voulue.
- Pas de rupture : les projets avec config standard continuent à voir leurs checks passer normalement.
Négatives :
- Un projet malveillant avec un pattern
{id}construit pour lire/etc/passwdpasserait en NEEDS-REVIEW au lieu d'être bloqué. Mitigé : les identifiants sont validés ailleurs (regex), et le pattern est défini dansschema.js(source versionnée, reviewée).
Neutres :
- L'implémentation est simple : un
try/catchautour depath.resolve+ un testpath.startsWith(projectRoot).
Règle dérivée¶
Tout nouveau check qui manipule des chemins doit utiliser safeResolve — pas path.resolve directement. Le contrat : on protège la frontière du projet, on informe quand elle est franchie.
Références¶
- V3 — Vague 3
docs/specs/next-gates-and-safeResolve.md(spec technique détaillée)- CLI sdlc