Files
system_update/docs/design/tache2/90-questions-investigation.md
T
gilles 0fbca06d3d docs: roadmap tâches 1.9-8 (briefs, gates de validation, designs tâche 2) + plans d'implémentation
Cartographie complète (liste_taches/coherence_taches), briefs tacheN + gates
validation_tacheN, design tâche 2 (docs/design/tache2/), specs/plans jalon 1-2
et tâche 1.9/2 (Phase 1, Phase 2, SJ-0→3). Validations consignées (1.9 , 2-8 🟡).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 19:50:25 +02:00

8.4 KiB

90 — Les 8 questions d'investigation (§3) tranchées

Chaque question : MVP recommandé / alternatives / risques. Décisions autonomes argumentées, cohérentes avec l'existant et tache1.9.md.


Q1 — JSON-in-shell vs parsing-in-TS

MVP recommandé : hybride à dominante parsing-TS. On conserve la convention actuelle (marqueurs ===SU:XXX=== + parsing dans server/services/). On enrichit avec des données semi-structurées produites par le shell uniquement quand le format est déjà stable et documenté : dpkg-query -W -f='${binary:Package}\t${Version}\t${Architecture}\n' (TSV), docker compose ps/images --format json, docker image inspect --format '...'. Pas de construction de gros JSON imbriqué à la main dans le shell.

  • Pourquoi : (a) cohérence avec le jalon 1 (déjà en prod, parsing TS testé) ; (b) testabilité — les fixtures de sortie shell + tests TS sont faciles à maintenir ; (c) robustesse multi-OS — éviter le JSON bricolé en Bash (échappement fragile, comme on le voit dans nas-ops avec la concaténation manuelle de chaînes JSON) ; (d) on tire parti des formats JSON natifs et documentés de Docker sans les réinventer.
  • Alternatives : (1) tout-JSON-in-shell façon nas-ops — rejeté (échappement fragile, dur à tester, risque de casser sur des noms/versions exotiques) ; (2) tout-parsing-TS sur sortie brute uniquement — rejeté pour Docker où --format json est plus sûr que parser du texte libre.
  • Risques : double convention (TSV/clé=valeur + sections) à documenter clairement ; mitigé par un parseur central par section. Format docker ... --format json varie selon version de Compose — pin de la commande + fallback texte.

Q2 — Structure des profils OS

MVP recommandé : un fichier de template complet par profil, dans un dossier par OS, avec fallback base (templates/<osFamily>/<action>.sh.tpl → sinon templates/apt/<action>.sh.tpl). Résolution par convention de chemin (cf. 60-profils-os-machine.md §2).

  • Pourquoi : lisibilité et audit Git (un script = un fichier complet, testable isolément) ; n'invalide pas Debian/Ubuntu (pas de dossier dédié ⇒ fallback apt/, comportement jalon 1 intact).
  • Alternatives : (1) héritage par fragments/partials Mustache (DRY) — plus complexe à auditer, reporté ; (2) une matrice de variables dans un seul template géant avec {{#proxmox}}… — rejeté (templates illisibles, logique métier noyée dans le rendu).
  • Risques : duplication partielle entre profils. Accepté au MVP (peu de profils) ; refactor en partials possible plus tard si la duplication devient coûteuse.

Q3 — Structure des profils machine

MVP recommandé : choix manuel à l'ajout (os_family + machine_kind) + action machine_probe non destructive proposant des corrections (jamais appliquées sans validation). Sources : /etc/os-release, uname -m/dpkg --print-architecture, systemd-detect-virt, présence /etc/pve, /proc/cpuinfo (RPi), lspci (GPU), ip addr (interface).

  • Pourquoi : la détection auto seule est fragile (conteneurs imbriqués, distros dérivées, VM mal taguées). Le couple « défaut manuel + sonde de correction » est robuste et garde l'opérateur maître.
  • Alternatives : (1) détection 100 % auto — rejetée (cas limites) ; (2) manuel sans sonde — perte de confort et risque d'erreur de profil.
  • Risques : utilisateur choisit mal le profil ⇒ machine_probe le signale ; correction nécessite validation. Persisté dans machines + machine_hardware.

Q4 — Capture avant/après (diff réel)

MVP recommandé : snapshot dpkg complet avant ET après chaque action APT réelle via dpkg-query -W -f='${binary:Package}\t${Version}\t${Architecture}\n', diff calculé côté backend (clé package+arch). L'exit code APT ne suffit jamais.

  • Pourquoi : dpkg-query reflète l'état réel installé (pas l'intention APT). Détecte les écarts entre simulation et réalité (paquet annoncé non installé, held back effectif).
  • Alternatives : (1) parser uniquement la sortie apt-get (Setting up …) — moins fiable, dépend du locale et du verbeux ; (2) historique /var/log/dpkg.log — parsing daté fragile. Les deux gardés comme signaux secondaires, pas comme source de vérité.
  • Risques : sur de très gros parcs de paquets, deux dpkg-query ajoutent quelques secondes — négligeable. Diff côté TS = testable par fixtures.

Q5 — Contrats JSON (extensions exactes)

MVP recommandé : extensions additives détaillées dans 40-contrats-json.md — unions élargies (OsFamily, AptProxyMode, ActionType, MachineKind), blocs optionnels docker/errors/reboot/postInstall + champs additifs sur apt, schemaVersion?. Types TS fournis. Un payload jalon 1 reste valide.

  • Pourquoi : rétro-compatibilité stricte exigée par le gate (§3 de la validation). Champs optionnels + unions additives = zéro rupture.
  • Alternatives : versionner par type séparé (UpdateSnapshotV2) — rejeté (duplication, migration lourde) au profit de schemaVersion sur un type unique.
  • Risques : un type unique grossit ; mitigé par découpe en sous-interfaces (AptSnapshotDetail, DockerSnapshot, etc.).

Q6 — Idempotence & opérations longues

MVP recommandé : différencier selon la durée et le risque.

  • Refresh/analyse, scan, inspect : synchrones et courts (comme le jalon 1).

  • Actions applicatives longues (full-upgrade, docker apply) : généraliser l'exécution détachée nohup + fichier exit-code sur la machine (survit à une coupure SSH), comme prévu au jalon 1 et inspiré de linux-update-dashboard. Le backend peut relire l'état/exit-code à la reconnexion plutôt que tout relancer.

  • Reboot : mécanisme dédié reboot_verified (boot_id avant/après + reconnexion + délai adaptatif).

  • Idempotence : les détections sont rejouables sans effet de bord applicatif ; pull-check écrit dans le cache images mais ne démarre rien (rejouable). machine_locks évite la concurrence destructive.

  • Alternatives : (1) tout synchrone — rejeté (un upgrade long meurt avec la session SSH) ; (2) file de jobs persistante dès le MVP — utile mais relève de la tâche 5 ; ici on pose le mécanisme nohup+exit-code et on renvoie l'orchestration job à la tâche 5.

  • Risques : suivi de progression d'une opération détachée = tailing du fichier de sortie distant + WebSocket ; à câbler proprement en implémentation (réutilise outputHub).

Q7 — Sécurité Docker prune / scripts custom

MVP recommandé : barrière de validation côté webapp (action_requests) pour toute action destructive + nettoyage déterministe des secrets dans les erreurs. docker_prune_images -a, docker_compose_down, docker_compose_apply, suppressions APT, reboot, identity_network ⇒ confirmation explicite. Hermes propose, ne déclenche jamais. Credentials registry/sudo/tokens jamais lus ni renvoyés (cf. 70-securite.md).

  • Pourquoi : respecte CLAUDE.md (actions destructives validées, aucun secret vers LLM). La barrière unique (action_requests) centralise l'autorisation côté API.
  • Alternatives : validation par template (flag requiresConfirmation dans le manifeste) — complémentaire, pas suffisant seul ; la décision d'autorisation reste côté API/route.
  • Risques : un script custom pourrait logger un secret ⇒ règle « pas de secret dans le corps du script » + filtre de nettoyage des lignes avant UI/MCP + revue Git des templates.

Q8 — Surface MCP

MVP recommandé : conserver la surface v1 (8 outils), sans nouvelle primitive d'exécution SSH. Les nouvelles capacités (Docker, post-install, APT détaillé) passent par run_action(actionType, params) filtré côté route, pas par de nouveaux outils. preview_template masque les secrets. run_action sur action destructive non validée renvoie un action_request en attente. Audit via mcp_audit_log.

  • Pourquoi : surface petite = agents fiables et auditables ; le MCP reste une façade sans logique SSH ni secret.
  • Alternatives : exposer un outil par action (docker_apply, apt_upgrade…) — rejeté (explosion de surface, duplication d'autorisation).
  • Risques : run_action générique doit valider strictement actionType/params côté API (liste blanche) ; sinon risque d'action non prévue. Mitigé par la table d'autorisation et action_requests.