Files
IdeA/.ideai/tickets/303/carnet.md

24 KiB
Raw Blame History

issueRef, version, updatedBy, updatedAt
issueRef version updatedBy updatedAt
#303 6
kind agent_id
agent a6c6ea12-bfc6-4bdc-8031-324102dfa34d
1789021152339

Carnet #303 - Restaurer les projets ouverts au redémarrage

Demande

  • Date: 2026-09-10.
  • À la fermeture puis relance d'IdeA, les projets qui étaient ouverts doivent être réouverts automatiquement.
  • L'ordre des projets ouverts doit être conservé.
  • Après livraison et QA, rebuild AppImage demandé par l'utilisateur.

Contraintes produit initiales

  • Comportement plug-and-play et silencieux par défaut.
  • Reprise automatique cohérente avec la priorité projet: persistance et reprise.
  • Ne pas bloquer le démarrage si un projet n'existe plus ou n'est plus accessible.
  • Éviter une UI verbeuse sauf si UX décide qu'un état discret est nécessaire.

Cadrage UX

  • Comportement par défaut, sans préférence UI pour cette première version.
  • À chaque lancement, restaurer automatiquement les projets ouverts lors de la dernière fermeture normale.
  • Reprendre strictement l'ordre visible au moment de la fermeture, sans tri par nom, activité ou date.
  • Les projets accessibles conservent leur position relative.
  • Projet supprimé/inaccessible: poursuivre le démarrage et ouvrir les autres projets. Conserver temporairement son emplacement dans l'état mémorisé pour ne pas casser l'ordre si l'indisponibilité est passagère.
  • Retour utilisateur: silencieux si tout est restauré. En cas d'échec uniquement, notification non bloquante:
    • 1 projet n’a pas pu être rouvert ou {n} projets n’ont pas pu être rouverts.
    • actions: Voir les détails, Réessayer.
    • détail par projet: nom, chemin, cause compréhensible, action Retirer de la reprise.
  • Fermer explicitement un projet pendant l'utilisation le retire de la prochaine reprise.

Critères UX QA

  • Après relance, tous les projets précédemment ouverts réapparaissent dans le même ordre.
  • Aucun message ni mouvement visuel parasite quand la reprise réussit.
  • Fermer explicitement un projet empêche sa réouverture au lancement suivant.
  • Un projet manquant/inaccessible/volume indisponible ne bloque ni IdeA ni les autres restaurations.
  • L'échec est signalé une seule fois par lancement, pluriel correct et actions fonctionnelles.
  • Réessayer restaure le projet à sa position mémorisée s'il redevient accessible.
  • Retirer de la reprise empêche les avertissements aux lancements suivants.
  • Premier lancement sans état mémorisé: comportement actuel inchangé.

Cadrage Architect

Source de vérité:

  • Créer une persistance machine-locale backend-owned sous l'app-data IdeA: <app_data_dir>/open-projects.json.
  • Distincte du registre projects.json, qui liste les projets connus mais pas l'état d'ouverture.
  • workspace.json ne doit pas être recyclé pour #303: il modélise des layouts/tabs historiques et n'est pas alimenté par useProjects.

Contrat recommandé:

{
  "version": 1,
  "entries": [
    {
      "projectId": "...",
      "name": "UnitySoundTool",
      "root": "/path/to/project",
      "position": 0,
      "lastFailure": null
    }
  ],
  "updatedAt": 1789017507046
}

Événements/commandes:

  • Ouverture explicite réussie: ajouter si absent, en fin de liste, ou laisser à sa position si c'était un tombstone/inaccessible restauré.
  • Création de projet réussie: même comportement qu'ouverture.
  • Fermeture explicite d'un projet: retirer l'entrée de open-projects.json.
  • Réordonnancement futur: prévoir save_open_project_restore_order(orderedProjectIds) même si l'UI ne sait pas encore réordonner.
  • Ne pas dépendre seulement du shutdown: côté Rust, l'ordre de open_project_ids() via HashMap n'est pas fiable.

Contrats backend:

  • Use cases: ReadOpenProjectRestoreState, SaveOpenProjectRestoreOrder, RecordProjectOpenedForRestore, RecordProjectClosedForRestore, RestoreOpenProjects, RetryOpenProjectRestore, RemoveProjectFromRestore.
  • Port dédié: OpenProjectRestoreStore { load() -> OpenProjectRestoreState, save(state) }.
  • DTO RestoreOpenProjectsOutputDto { opened: ProjectDto[], failures: RestoreOpenProjectFailureDto[] }.
  • Failure DTO: projectId, name, root, position, code: "notFound" | "inaccessible" | "store" | "invalid", message.
  • Requests: RemoveOpenProjectRestoreEntryRequestDto { projectId }, RetryOpenProjectRestoreRequestDto { projectId?: string }.

Stratégie inaccessible:

  • Pendant RestoreOpenProjects, charger les entrées dans l'ordre, résoudre via projects.json, prévalider le root avec FileSystem, puis appeler la même logique d'ouverture que open_project_for_adapter.
  • Projet absent du registre: failure notFound, entrée conservée temporairement.
  • Root manquant/non lisible: failure inaccessible, entrée conservée à sa position.
  • Projet restauré: mêmes side effects que l'ouverture normale: layouts/live-state/background tasks, watcher, MCP server, run-dir repair.
  • Réessayer: relancer la restauration sur les entrées en échec, réinsérer les succès à leur position mémorisée.
  • Retirer de la reprise: supprimer l'entrée persistée et empêcher les warnings futurs.

Contrats frontend:

  • ProjectGateway gagne restoreOpenProjects, retryOpenProjectRestore, removeProjectFromRestore, optionnellement saveOpenProjectRestoreOrder.
  • useProjects initialise: listProjects(), restoreOpenProjects(), remplir openTabs avec opened dans l'ordre retourné, notifier seulement si failures.length > 0.
  • Notification: Voir les détails, Réessayer, Retirer de la reprise.

Fichiers probables:

  • Backend: crates/domain/src/ports.rs, crates/domain/src/project_restore.rs ou équivalent, crates/application/src/project/restore.rs, crates/application/src/project/open.rs, crates/application/src/project/close.rs, crates/infrastructure/src/store/open_project_restore.rs, crates/app-tauri/src/commands.rs, crates/backend/src/lib.rs, crates/web-server/src/lib.rs.
  • Frontend: frontend/src/ports/index.ts, frontend/src/adapters/project.ts, frontend/src/adapters/http/requestResponseGateways.ts, frontend/src/features/projects/useProjects.ts, frontend/src/features/projects/ProjectsView.tsx.

Répartition:

  • DevBackend: modèle, store, use cases, commandes Tauri/HTTP, side effects d'ouverture réutilisables, tests Rust.
  • DevFrontend: init silencieuse, remplissage openTabs, notification échec, détails/retry/remove, tests React/adapters.

Critères QA techniques:

  • Premier lancement sans open-projects.json: aucun onglet restauré, aucune notification.
  • Ouvrir A puis B, quitter, relancer: onglets A/B dans cet ordre.
  • Fermer B explicitement, quitter, relancer: seul A revient.
  • Root de B temporairement inaccessible: A revient, B reste mémorisé à sa position, notification unique.
  • Après restauration du root, Réessayer ouvre B à sa position mémorisée.
  • Retirer de la reprise supprime B du fichier et du warning futur.
  • Watchers/MCP servers sont armés pour les projets restaurés.
  • Tests Tauri + HTTP si le gateway web expose les mêmes commandes.
  • Après validation: rebuild AppImage demandé.

Cycle

  • UX: fait.
  • Architect: fait.
  • Git: branche locale.
  • DevBackend/DevFrontend selon cadrage.
  • QA: tests réels + AppImage rebuild.

Implémentation DevBackend — 2026-09-10

Livré

  • Ajout du modèle versionné OpenProjectRestoreState et du port dédié OpenProjectRestoreStore.
  • Ajout du store filesystem <app_data_dir>/open-projects.json; un fichier absent retourne un état vide sans créer de fichier au premier restore.
  • Ajout des sept use cases cadrés: lecture, record opened/closed, sauvegarde d'ordre, restore, retry et remove.
  • Sérialisation des mutations par un mutex applicatif partagé afin d'éviter les lost updates entre commandes concurrentes.
  • Conservation des tombstones à leur position avec lastFailure; codes stables notFound, inaccessible, store, invalid.
  • Prévalidation d'un root par metadata puis listing du répertoire: une entrée invalide n'interrompt pas les autres restaurations.
  • Centralisation de l'activation dans BackendCore::activate_project: reconciliation layouts, live-state, background tasks, watcher/orchestrator + serveur MCP, puis réparation des run dirs Claude.
  • Ouverture Tauri et HTTP, restore et retry utilisent cette même activation. La création enregistre aussi le projet puis l'active. La fermeture explicite retire l'entrée après succès du use case de fermeture.
  • Exposition Tauri et HTTP des commandes read_open_project_restore_state, restore_open_projects, retry_open_project_restore, remove_project_from_restore, save_open_project_restore_order.
  • Aucun fichier frontend modifié.

Contrat frontend final

  • restore_open_projects sans requête -> { opened: ProjectDto[], failures: RestoreOpenProjectFailureDto[] }.
  • retry_open_project_restore avec { projectId?: string } (requête omissible côté HTTP) -> même output.
  • remove_project_from_restore avec { projectId: string } -> OpenProjectRestoreStateDto.
  • save_open_project_restore_order avec { orderedProjectIds: string[] } -> OpenProjectRestoreStateDto; les IDs omis restent après les IDs fournis dans leur ordre antérieur, doublons/IDs inconnus refusés.
  • read_open_project_restore_state sans requête -> { version, entries, updatedAt }; chaque entrée expose { projectId, name, root, position, lastFailure } et lastFailure vaut explicitement null sans échec.
  • Une failure expose { projectId, name, root, position, code, message } avec code parmi notFound | inaccessible | store | invalid.
  • DevFrontend doit encore appeler restore_open_projects à l'initialisation, reconstruire openTabs dans l'ordre de opened, insérer un retry réussi à la position mémorisée, et porter notification/détails/actions UX.

Fichiers modifiés

  • crates/domain/src/project_restore.rs
  • crates/domain/src/lib.rs
  • crates/domain/src/ports.rs
  • crates/application/src/project/restore.rs
  • crates/application/src/project/mod.rs
  • crates/application/src/lib.rs
  • crates/infrastructure/src/store/open_project_restore.rs
  • crates/infrastructure/src/store/mod.rs
  • crates/infrastructure/src/lib.rs
  • crates/backend/src/dto.rs
  • crates/backend/src/lib.rs
  • crates/app-tauri/src/commands.rs
  • crates/app-tauri/src/lib.rs
  • crates/web-server/src/lib.rs

Tests ajoutés

  • Backend composition: absence initiale, ordre A/B et réordonnancement, fermeture explicite, root inaccessible non bloquant, retry ciblé, entrée absente du registre (notFound), remove et armement du watcher pour les succès.
  • HTTP: ouverture enregistrée, restore et remove, avec formes DTO identiques au transport Tauri.

Commandes exécutées

  • cargo fmt --all
  • cargo check -p application -p infrastructure — vert.
  • cargo check -p backend -p app-tauri -p web-server — vert.
  • cargo test -p backend open_project_restore_tests -- --nocapture — vert, 1 test.
  • cargo test -p web-server authorized_open_project_restore_commands_share_the_tauri_contract -- --nocapture — vert, 1 test.
  • cargo test -p domain -p application -p infrastructure -p backend — partiellement vert: application atteint 180 unit tests verts puis 2 échecs hors périmètre dans tests/layout_usecases.rs (plugin package introuvable); backend 93 passés / 7 ignorés; domain vert; infrastructure 377 passés / 1 échec de timing existant sur la cancellation de process.
  • cargo test -p infrastructure session::process::tests::run_turn_cancellable_kills_current_child_without_waiting_for_natural_exit -- --nocapture — échec isolé après 10 s, hors fichiers #303.
  • cargo test -p domain --quiet — vert, 311 tests.
  • cargo test -p backend open_project_restore_tests --quiet — vert, 1 test ciblé.
  • cargo test -p web-server authorized_open_project_restore_commands_share_the_tauri_contract --quiet — vert, 1 test ciblé.
  • git diff --check — vert.

Gaps / reprise

  • DevFrontend requis pour l'intégration au démarrage et les surfaces d'échec UX.
  • QA doit revalider les deux échecs application liés aux fixtures plugin et le test infrastructure temporel dans son environnement; aucun ne touche les fichiers ou chemins #303.
  • Aucun arbitrage Architect supplémentaire identifié dans le lot backend.
  • Pas de commit effectué.

Implémentation DevFrontend — 2026-09-10

Livré

  • Ajout des DTO frontend de reprise et extension de ProjectGateway avec les cinq commandes backend (restore, retry, remove, save order, read state).
  • Adapters Tauri et HTTP alignés sur les noms de commandes et enveloppes request du backend.
  • Initialisation de useProjects par lecture du registre et restauration automatique; les succès reconstruisent les onglets dans l'ordre renvoyé, sans notification quand il n'y a aucun échec.
  • Protection contre une ouverture explicite concurrente à l'initialisation: les onglets déjà ouverts sont conservés et ajoutés après l'ordre restauré, sans doublon.
  • Notification non bloquante unique au lancement avec singulier/pluriel exact, fermeture, Voir les détails et Réessayer.
  • Détail accessible par projet avec nom, chemin, cause française dérivée du code stable, et Retirer de la reprise.
  • Un retry réussi est réinséré à la position mémorisée de l'échec; les échecs restants sont réconciliés sans recréer la notification après fermeture volontaire.
  • La fermeture explicite attend désormais le succès de closeProject avant de retirer l'onglet localement: un échec de persistance conserve donc l'onglet et affiche l'erreur existante.
  • Mock gateway enrichi avec l'état de reprise et des helpers de scénario; fixture structurelle des services plugin mise à niveau.
  • saveOpenProjectRestoreOrder est exposé mais non appelé: l'UI actuelle ne permet aucun réordonnancement manuel des onglets, conformément au périmètre.

Fichiers frontend modifiés

  • frontend/src/domain/index.ts
  • frontend/src/ports/index.ts
  • frontend/src/adapters/project.ts
  • frontend/src/adapters/project.test.ts
  • frontend/src/adapters/http/requestResponseGateways.ts
  • frontend/src/adapters/http/httpInvoker.test.ts
  • frontend/src/adapters/mock/index.ts
  • frontend/src/features/projects/useProjects.ts
  • frontend/src/features/projects/ProjectsView.tsx
  • frontend/src/features/projects/projects.test.tsx
  • frontend/src/plugins/runtime/services.test.ts

Tests ajoutés / couverts

  • Mapping exact des cinq commandes sur transports Tauri et HTTP.
  • Restauration silencieuse et ordre mémorisé.
  • Notification singulier/pluriel présente une seule fois.
  • Détail nom/chemin/cause compréhensible.
  • Retry d'un projet redevenu accessible et réinsertion entre ses voisins.
  • Retrait d'un tombstone de la reprise future.
  • Fermeture explicite persistée et conservation de l'onglet si le backend refuse la fermeture.

Commandes exécutées

  • cd frontend && npm run typecheck — vert.
  • cd frontend && npm run build — vert (515 modules transformés; avertissement Vite existant sur la taille du chunk principal).
  • cd frontend && npm test -- src/adapters/project.test.ts src/adapters/http/httpInvoker.test.ts src/features/projects/projects.test.tsx — vert, 3 fichiers / 37 tests.
  • cd frontend && git diff --check — vert.
  • cd frontend && npm test — non vert hors tests ciblés: 1234 tests passent, 32 échouent dans 6 fichiers; la sortie inclut notamment des scénarios web WebAgentCell, WebDesktopWorkspace, WebTicketsSprints sans rapport avec #303.
  • cd frontend && npm test -- src/features/projects/ProjectsView.ls7.test.tsx — 6 tests passent, 3 tests échouent sur l'attente du bouton open conversation conversation-open-me; ces scénarios LS7 à menu flottant sont sensibles au timing et ne touchent pas les assertions de reprise #303.

Gaps / reprise QA

  • QA doit rejouer la suite complète dans son environnement et qualifier les 32 échecs non ciblés; aucune erreur de typage ni échec dans les 37 tests du lot #303.
  • Le rebuild AppImage reste une étape post-validation QA/Git et n'a pas été réalisé dans ce lot frontend.
  • Aucun commit effectué.

Validation QA — 2026-09-10

Verdict: VERT pour le périmètre #303, avec réserves hors périmètre maintenues ci-dessous.

Inspection:

  • Carnet complet lu.
  • Diff inspecté sur modèle/port/store backend, use cases, composition BackendCore, commandes Tauri, route HTTP, adapters Tauri/HTTP frontend, mock gateway, useProjects et ProjectsView.
  • Les contrats Tauri et HTTP exposent les cinq commandes attendues:
    • restore_open_projects
    • retry_open_project_restore
    • remove_project_from_restore
    • save_open_project_restore_order
    • read_open_project_restore_state
  • Le frontend lance listProjects() et restoreOpenProjects() à l'initialisation, reconstruit openTabs selon l'ordre opened, reste silencieux sans échec, affiche une notification unique en cas d'échec, expose détails/retry/remove et conserve un onglet si closeProject échoue.
  • Les side effects backend sont centralisés dans BackendCore::activate_project: reconciliation layouts/live-state/background tasks, watcher orchestrateur, serveur MCP via ensure_orchestrator_watch -> ensure_mcp_server, puis réparation des run dirs Claude.
  • Couverture QA ajoutée: le test backend #303 vérifie maintenant explicitement que les projets restaurés/retry ont aussi une entrée dans mcp_servers, en plus de l'ouverture visible dérivée des watchers.

Commandes exécutées et résultats verts:

  • cargo test -p backend open_project_restore_tests -- --nocapture
    • OK: 1 passed; couvre absence initiale sans fichier, ordre, fermeture explicite, root inaccessible non bloquant, retry ciblé, notFound, remove, watcher et serveur MCP.
  • cargo test -p web-server authorized_open_project_restore_commands_share_the_tauri_contract -- --nocapture
    • OK: 1 passed; contrat HTTP aligné sur commandes Tauri.
  • npm test -- src/adapters/project.test.ts src/adapters/http/httpInvoker.test.ts src/features/projects/projects.test.tsx
    • OK: 3 files / 37 tests passed; couvre mappings Tauri/HTTP et comportement frontend #303.
  • cargo fmt --all -- --check
    • OK.
  • cargo check -p application -p infrastructure
    • OK.
  • cargo check -p backend -p app-tauri -p web-server
    • OK.
  • cargo check -p backend
    • OK après ajout de l'assertion QA MCP.
  • npm run typecheck
    • OK.
  • npm run build
    • OK; avertissement Vite existant de chunk > 500 kB.
  • cargo test -p domain --quiet
    • OK: 311 unit tests + suites associées vertes.
  • cargo test -p backend --quiet
    • OK: 93 passed, 7 ignored.
  • git diff --check
    • OK.

Suites larges rouges hors périmètre:

  • cargo test -p application -p infrastructure -p backend
    • ROUGE avant d'atteindre infrastructure/backend à cause de application/tests/layout_usecases.rs.
    • Échecs reproduits:
      • create_layout_plugin_validates_active_runtime_contribution_and_persists_root
      • mutate_set_plugin_layout_state_persists_opaque_state
    • Cause observée: panic sur Err NotFound("plugin package").
    • Qualification QA: hors périmètre #303; fichiers/tests de layouts plugin, pas de lien avec restore/open projects.
  • cargo test -p infrastructure session::process::tests::run_turn_cancellable_kills_current_child_without_waiting_for_natural_exit -- --nocapture
    • ROUGE: panic après 10 s, cancel should not wait for the child process natural exit.
    • Qualification QA: hors périmètre #303; test temporel process cancellation déjà signalé, pas de lien avec restore/open projects.
  • npm test
    • ROUGE: 120 files passed, 6 failed; 1234 tests passed, 32 failed.
    • Fichiers en échec:
      • src/features/projects/ProjectsView.ls7.test.tsx — 3 tests LS7 conversation viewer.
      • src/features/web/WebAgentCell.test.tsx — 1 test mobile custom CLI launch failure.
      • src/features/web/WebApp.test.tsx — 3 tests pairing/session routing.
      • src/features/web/WebDesktopWorkspace.test.tsx — 1 test docking web desktop layout.
      • src/features/web/WebMenus.test.tsx — 8 tests menu/shell web #90.
      • src/features/web/tickets/WebTicketsSprints.test.tsx — 16 tests tickets/sprints web #86.
    • Qualification QA: hors périmètre #303; les 37 tests ciblés #303 sont verts et les fichiers rouges concernent web shell/LS7/tickets, pas la reprise des projets desktop.

Réserves:

  • Je n'ai pas validé un cycle UI AppImage réel fermeture/relance; la validation est automatisée backend/frontend et transport.
  • Les rouges hors périmètre ci-dessus doivent rester suivis séparément; ils ne bloquent pas le symptôme #303.

Conclusion:

  • Premier lancement sans état: restore vide sans création de fichier et sans notification.
  • Restauration A/B dans l'ordre mémorisé: couverte.
  • Fermeture explicite: retire de la prochaine reprise, et l'UI ne retire l'onglet qu'après succès backend.
  • Projet inaccessible/notFound: non bloquant, tombstone conservé avec notification/détails.
  • Retry: réouvre et réinsère selon position mémorisée.
  • Remove: supprime l'entrée de reprise future.
  • Watcher et serveur MCP: activés pour les succès restore/retry via le chemin partagé activate_project, avec assertion backend dédiée.
  • Aucun finding bloquant #303.

Topologie Git — 2026-09-10

QA reconfirmée par Git avant commit (exécution réelle):

  • rustup run stable cargo fmt --all -- --check — OK.
  • git diff --check — OK.
  • cargo test -p backend open_project_restore_tests — 1/1.
  • cargo test -p web-server authorized_open_project_restore_commands_share_the_tauri_contract — 1/1.
  • cargo test -p domain --quiet — 311 unit tests + suites vertes.
  • cargo check -p application -p infrastructure -p backend -p app-tauri -p web-server — OK.
  • Frontend: npm run typecheck OK, npm test ciblé 3 fichiers/37 tests OK, npm run build OK.
  • Suites larges rouges hors périmètre (layout_usecases fixtures plugin, timing infrastructure, 32 échecs web shell/LS7/tickets) non rejouées par Git: qualifiées hors #303 par QA, à suivre séparément.

Commit de la feature (28 fichiers, bookkeeping exclu):

  • Branche: feature/303-restore-open-projects-order.
  • Commit: 8df80ae — feat(domain,application,infrastructure,backend,app-tauri,web-server,frontend): restaurer les projets ouverts au redémarrage dans l'ordre mémorisé — #303.
  • Inclus: 15 fichiers crates (dont nouveaux crates/domain/src/project_restore.rs, crates/application/src/project/restore.rs, crates/infrastructure/src/store/open_project_restore.rs) + 13 fichiers frontend/src (adapters, ports, domain, useProjects, ProjectsView, tests, mock).
  • Exclus (hors périmètre, restés en worktree): .ideai/tickets/296/*, .ideai/tickets/299-303/*, counter.json, index.json, .ideai/attachments/, scripts/.

Merge local:

  • develop ← merge --no-ff de feature/303-restore-open-projects-order → commit bd1c55d.
  • develop n'avait pas divergé depuis la création de la branche (fast-path, contenu identique à 8df80ae).
  • Branche feature/303-restore-open-projects-order conservée.
  • Aucune action distante (aucun push; develop reste en avance locale sur origin/develop).

Restants après merge:

  • Rebuild AppImage demandé par l'utilisateur: commit dédié --allow-empty + tag annoté, incrément y sur develop → v0.45.0.
  • Validation live fermeture/relance depuis l'app installée (ordre des onglets, notification échec, retry/remove).
  • Suivi séparé des rouges hors périmètre (layout_usecases, timing cancellation process, web shell/LS7/tickets).

Rebuild AppImage — 2026-09-10

Rebuild exécuté par Main depuis develop @ bd1c55d (incluant le merge #303):

  • Commandes: npm --prefix frontend run build OK, puis depuis crates/app-tauri: mkdir -p /tmp/idea-cargo-home && CARGO_HOME=/tmp/idea-cargo-home APPIMAGE_EXTRACT_AND_RUN=1 NO_STRIP=1 ../../frontend/node_modules/.bin/tauri build --bundles appimage OK.
  • Artefact: target/release/bundle/appimage/IdeA_0.3.0_amd64.AppImage, 119843320 octets, sha256 e57cc136f17d887798d09468f2858b1b025cd2386abdc4d517ccb49f464df5b5 (vérifié par Git).

Traçabilité Git:

  • Commit dédié --allow-empty (l'artefact vit sous target/ gitignoré): 5b07596 sur develop — chore(appimage): rebuild AppImage develop — commit dédié v0.45.0 #303.
  • Tag annoté v0.45.0 posé sur 5b07596 (convention respectée: y incrémenté pour un rebuild committé sur develop, v0.44.0 -> v0.45.0).
  • Bookkeeping carnet/index/counter et fichiers hors périmètre exclus, restés en worktree. Aucun push.

Restant après rebuild:

  • Validation live fermeture/relance depuis l'app installée v0.45.0: onglets restaurés dans l'ordre, silence si tout réussit, notification unique en cas d'échec avec Réessayer/Retirer de la reprise fonctionnels.