Milestone planned-2026-10-10-release-deps merged (PRs #414 to #418,
main 9e8c41b): new position paragraph and decision entry, the oldest
decision (#365) rotated out. Blockers: #419 point 1 before the next tag,
stale mentions of #376, #317, #345, #358 and #320 replaced by their
closure.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
43 KiB
Markdown
92 lines
43 KiB
Markdown
# STATE — Simpl'Résultat
|
||
|
||
> Derniere MAJ : 2026-10-12 (**Milestone `planned-2026-10-10-release-deps` mergée, 4/4 fermée — pile #414 → #418 en avance rapide par l'API, `main` `9e8c41b`.** Node 24 dans `check-frontend`, `audit` et `release` (#376) ; garde `windows-sys 0.61.2` dans `check-rust` et ADR 0023 (#345) ; une clé `latest.json` par paquet Linux, sans clé générique `linux-x86_64`, retirée sur décision de Max (#320) ; lock npm rafraîchi, `npm audit` à 0 (#358, ferme #317) ; PR #418 de suivis des revues. Suivis de la revue de #418 en #419, dont un trou de la garde d'avant le `DELETE` à corriger avant le prochain tag.)
|
||
>
|
||
> Précédente MAJ : 2026-10-10 (**Vérifications manuelles toutes faites sur les releases publiées, complétion confirmée par Max** : suites de licence sur la v0.17.0, parcours de démarrage guidé sur la v0.17.1 (liste `docs/qa-onboarding.html`, Orca puis NVDA), post-merge de #390 (fermée), cycle de mise à jour Windows de la v0.16.0 (Michel) et updater (Free refuse, Base accepte). **Go-live clos** : la-compagnie-maximus#141 fermée le même jour sur décision de Max, avec #363 et la milestone `spec-paiements` (ici 5/5).)
|
||
|
||
## Position actuelle
|
||
|
||
v0.9.1 shippée (2026-05-10). Milestones `spec-refonte-rapports`, `spec-refonte-seed-categories-ipc`, `spec-price-fetching`, `overnight-2026-04-26-bilan` et `overnight-2026-04-27-prices` complétées et fermées. Maximus-api 0.3.0 LIVE en prod (`api.lacompagniemaximus.com`) — pubkey Ed25519 alignée, smoke test Phase B (#161) validé. Backlog actif concentré sur `spec-monetisation` (7/12) : activation en ligne (#53), pipeline Stripe desktop (#50, #52) et maximus-api Stripe webhooks (#135, #136).
|
||
|
||
Audit critique de la page Bilan livré (`docs/audit-bilan-2026-05.md`, revue CPA + UX). Étape 0 — quick wins terminologie « catégorie »→« type », symbole optionnel, date de snapshot déplaçable — mergée (#201, issues #198/#199/#200 fermées). Chantier structurel = Étapes 1-2 de l'audit (séparation véhicule fiscal × classe d'actif via `vehicle_type`, puis détail par titre `balance_securities`+holdings+`book_cost`, bascule agrégé→détaillé, réouverture ADR 0012). **Étape 1 livrée** (sprint 2026-06-01 : PRs #206-#209 mergées, milestone `overnight-2026-06-01-bilan-axe-vehicule` fermée 4/4) — `vehicle_type` nullable = enveloppe fiscale portée par le compte, catégorie = pure classe d'actif (5 classes), migrations additives v12/v13 (v1-v11 intactes), renommage via `custom_label` (fix bug I), axe graphique classe/enveloppe + rendements repliables persistés ; ADR 0014 Accepted, ADR 0012 Rejected. CHANGELOG sous [Unreleased] (pas encore taggé). **Étape 2 livrée** (merge manuel 2026-06-09 : pile de 9 PRs stackées #219-#227 mergées bottom-up, milestone `overnight-2026-06-05-bilan-detail-titres` à 9/10, issues #210-#218 fermées) — détail par titre via `balance_securities` + `balance_snapshot_holdings`, `balance_accounts.kind` ('simple'|'detailed') + `detailed_since`, migrations additives v14/v15/v16 (v1-v13 intactes), conversion des comptes cotés existants en détaillés 1-position (v16), service securities transactionnel, reducer holdings + dispatch `account.kind`, UI multi-titres (SecurityPicker), assistant détailler-un-compte (date pivot), drill-down par titre + gain latent, tests intégration/régression ; ADR 0015 Accepted. **#228 mergé** (PR #229, fix-forward : garde d'abort v16 scopée aux comptes convertibles via `JOIN balance_categories` + `c.asset_type IS NOT NULL` dans les 3 copies — Migration v16 / V16_SQL / V16_CORRUPT — + test régression ; CI vert car #229 ciblait `main`) → milestone `overnight-2026-06-05-bilan-detail-titres` complète **10/10 et fermée**. **v0.10.0 shippée** (2026-06-29 : Étapes 1+2 du bilan, migrations v12→v16) **puis hotfix v0.10.1** (2026-06-30, PR #230, déployé) — corrige un « database is locked » introduit en 0.10.0 (apparaissait après l'abandon d'un snapshot en cours) : tout l'accès DB est désormais sérialisé via `withTransaction` dans `db.ts` (tauri-plugin-sql = pool sqlx multi-connexions sans primitive de transaction JS → `BEGIN`/`COMMIT` en `db.execute` séparés pouvaient strander une transaction d'écriture = verrou zombie), appliqué aux 5 sites transactionnels ; + console de log live-update + API `logInfo/logWarn/logError`. 20 tables / 24 index, 16 migrations (v1→v16).
|
||
|
||
**Milestone `deps-security-2026-07` livrée** (2026-07-01, 4/4 fermée) — 4 vulns de dépendances Defenseur remédiées en 2 PRs (#239 `react-router-dom` 7.18.1 ; #240 `vite` 6.4.3 + `vitest` 4.1.9) ; `npm audit` 5→**0** — le dernier `@babel/core` low remédié le 2026-07-04 (override scopé `@vitejs/plugin-react`→`@babel/core@^7.29.7`, issue #241 / PR #242 mergée). **Ce « 0 » n'a pas tenu** : des advisories publiées depuis l'ont ramené à 3 (#311, 2026-07-27, 2 acceptées sur `react-router`), puis à 8 ; **0 de nouveau au 2026-10-10** par le rafraîchissement du lock de #358 (mergé le 2026-10-12), qui ferme aussi #317. Nouveau milestone `spec-ci-build-optimization` (2/4) ouvert (baseline #231 : cause #2 = `reserveCache timeout` du runner ; #234 connectivité cache VPS, #232 split workflows).
|
||
|
||
**v0.11.0 shippée** (2026-07-05, tag `v0.11.0` → CI release Windows/Linux + JSON updater) — milestone `overnight-2026-07-05-bilan-rapports-ux` complétée **5/5 et fermée** via un run `/autopilot` (5 workers séquentiels, PRs #248-#252 toutes `/pr-review` APPROVE, puis merge local de la pile + réconciliation Forgejo). Contenu : rapport comparable réel-vs-réel **hiérarchique** avec sous-totaux (#247) ; **netting des transferts** ciblé (catégories type `transfer` → SUM signé ~0, autres types inchangés au byte) dans le compare (#243) ; landing Bilan en **tuiles** `HubReportNavCard` + guard empty-state découplé + gestion comptes accessible partout (#244) ; **import CSV de titres** dans un snapshot détaillé (front pur, `autoDetectHoldingColumns`, prix flexible) (#245) ; cible de **migration catégories éditable** sur chaque ligne + type-ahead `CategoryCombobox` feuilles-seulement (#246). Aucune migration DB (v1→v16 inchangées), 20 tables / 24 index, 16 migrations. Point de suivi non bloquant : nets de transfert signés traversent du code UI compare pensé pour des magnitudes positives (mord seulement les transferts déséquilibrés à une jambe).
|
||
|
||
**v0.12.0 shippée** (2026-07-05, tag `v0.12.0` → CI release #311) — recadrage de #243 (montants de transfert inclus dans le comparable) par Max en « analyse de résultat » : deux rapports comparables refondus en états de résultat (income statement). Le compare réel-vs-réel (#253) et le tableau de tendance par catégorie (#256) affichent le **revenu**, un **Résultat avant transferts** (revenus − dépenses) et un **Résultat net** (après transferts), sections ordonnées revenu→dépense→transfert ; les rapports comparables ouvrent par défaut sur le **mois complet précédent** (#253). Modules purs extraits et testés (`compareResults.ts`, `overTimeResults.ts`) ; 2 blocages `/pr-review` corrigés (fuite du revenu dans les top-movers Cartes ; garde StrictMode sur le sync du mois de référence). Livré en 2 issues/PRs stackées #255→#257 (merge local + réconciliation Forgejo, branches supprimées), 701 vitest verts, aucune migration DB (v1→v16 inchangées), 20 tables / 24 index. Backlog ouvert au passage : #258 (db-locked `proposeStarterAccounts`) → fermé le 2026-07-07 (déjà corrigé v0.10.1, pas de nesting) ; #254 (collapse/expand) → livré le 2026-07-07 (PR #261) ; #259 (mapping manuel d'un compte standard sans similaire auto) et #260 (epic « rapports uniformes » — tous les rapports sur le modèle income-statement) ouverts.
|
||
|
||
**v0.15.0 shippée** (2026-09-12, tag `v0.15.0` → CI release run 402, 7 artefacts + `latest.json` vérifiés) — première version où le gating par édition est actif : sans clé, Budget, Ajustements, rapports avancés, profils multiples, Bilan et mises à jour automatiques sont verrouillés (données intactes, ADR 0017). Les deux testeurs (Max, Michel) ont une clé Premium émise avant le tag. `[Unreleased]` vide. Aucune migration DB nouvelle (v1→v17). Étape 10 de `/release` **consignée le 2026-09-13** : cycle réel v0.14.0 → v0.15.0 validé par les deux testeurs, trace rédigée pour le corps de la release Forgejo (invite polkit Linux non consignée, `.rpm` hors test → #320).
|
||
|
||
**v0.16.0 shippée** (2026-10-03, tag `v0.16.0` → CI release run 451, 7 artefacts + `latest.json` vérifiés, registre de l'updater en 0.16.0) — première version vendable de bout en bout : « Obtenir Base » ouvre la page produit (#346), le client de licence parle `/v1` et nomme chaque refus (#270), l'édition ne dépend que de la clé (#347), l'activation envoie un identifiant dérivé (#350), une clé révoquée retombe en Gratuite après un contrôle au démarrage (#365), et `rustls` 0.23.45 (#348). `[Unreleased]` vidé au tag. Aucune migration DB nouvelle (v1→v17). Sur la release publiée : #365 vérifiée et fermée le 2026-10-03, étape 10 de `/release` faite sous Linux le même jour (trace dans le corps de la release) ; étape 10 sous Windows faite par Michel (confirmée le 2026-10-10) ; #350 fermée et #346 vérifiée le 2026-10-04.
|
||
|
||
**Onboarding phase 1 mergée sur `main`** (2026-10-04, `667e058`, publiée dans la v0.17.0) — milestone `planned-2026-10-03-onboarding-phase1` fermée 7/7 (#351-#357, PRs #377-#383, produites par `/autopilot` le 2026-10-03 puis relues une à une par `/pr-review`) : états vides guidés (dashboard, Import, Transactions, Budget), liste de démarrage à 6 cases calculée depuis la base, bouton « Créer un dossier d'exemple », guide « Exporter un CSV depuis votre banque » (Desjardins, Tangerine, RBC, BNC, BMO). Aucune migration DB (v1→v17). Suivis : #384 (non bloquants) et #371 (BMO sur compte réel, saisie de Max).
|
||
|
||
**Suites de licence mergées sur `main`** (2026-10-05, `2cbc886`, publiées dans la v0.17.0) — milestone `planned-2026-10-03-suites-licence` fermée 3/3 (#373, #370, #367 ; PRs #386 → #388, produites par `/autopilot` le 2026-10-04, relues par trois `/pr-review` APPROVE, suivis appliqués en tête de pile) : contrôle d'une clé révoquée dès sa saisie (au plus une fois par 24 h et par clé), « Retirer la clé » dans la carte Licence (place libérée d'abord sur une machine activée, contrôle quotidien arrêté), jeton d'une ancienne licence retiré sur un refus des cours ou à l'ouverture de la liste des machines. Aucune migration DB (v1→v17). Suivi : #389 (huit autres fichiers de tests au faux `t` brut).
|
||
|
||
**v0.17.0 shippée** (2026-10-05, tag `v0.17.0` sur `07255e1` → CI release run 491 en 22 min, 7 artefacts + `latest.json` vérifiés par `verify-release.sh`, endpoint de l'updater en 0.17.0) — onboarding phase 1 et suites de licence. `[Unreleased]` vidé au tag. Aucune migration DB nouvelle (v1→v17). Étape 10 de `/release` non exigée (chaîne de mise à jour inchangée), raison écrite sur la release. Vérifications manuelles des suites de licence faites sur la release publiée (confirmées le 2026-10-10).
|
||
|
||
**Parcours de démarrage guidé mergé sur `main`** (2026-10-08, `ee17f31`, publié dans la v0.17.1) — milestone `planned-2026-10-06-onboarding-parcours-guide` fermée 6/6 (#396-#401, PRs #402 → #407, produites par `/autopilot` le 2026-10-08, relues par six `/pr-review` APPROVE, suivis appliqués en tête de pile) : bandeau « Démarrage n/N · Étape suivante » sur chaque page, cartes d'étape avec mise en évidence du contrôle sur Import, Transactions et Budget, état partagé par un fournisseur et canal d'événements de données (ADR 0022), règle D9 (un profil déjà actif trouve le parcours masqué). Aucune migration DB (v1→v17). Suivis : #408 (`db.ts` hors verrou pendant une transaction) et #409 (harnais de test).
|
||
|
||
**v0.17.1 shippée** (2026-10-08, tag `v0.17.1` sur `e4db715` → CI release run 508, 7 artefacts + `latest.json` vérifiés par `verify-release.sh`, endpoint de l'updater en 0.17.1) — parcours de démarrage guidé et #390 (étape 5 de la liste, rattrapage des migrations des profils secondaires, dossier des bases sous Linux). Numéro de correctif choisi par Max malgré les entrées Added. `[Unreleased]` vidé au tag. Aucune migration DB nouvelle (v1→v17). Étape 10 de `/release` non exigée (chaîne de mise à jour inchangée), raison écrite sur la release. Vérifications manuelles faites sur la release publiée (parcours guidé, #390), complétion confirmée le 2026-10-10.
|
||
|
||
**Chaîne de release et dépendances mergée sur `main`** (2026-10-12, `9e8c41b`, pas encore publiée) — milestone `planned-2026-10-10-release-deps` fermée 4/4 (#376, #345, #320, #358, plus #317 ; PRs #414 → #417 produites par `/autopilot` le 2026-10-10 et relues par quatre `/pr-review` APPROVE, puis PR #418 de suivis des revues, relue à son tour) : Node 24 dans les trois workflows encore en Node 20 ; garde `Verify windows-sys pinning` dans `check-rust` (ADR 0023) ; `latest.json` avec une clé par paquet Linux (`linux-x86_64-deb`, `linux-x86_64-rpm`) et sans clé générique, contrôlé avant le `DELETE` du registre par `scripts/check-latest-json.jq` ; lock npm rafraîchi, `npm audit` à 0. Aucune migration DB (v1→v17). `[Unreleased]` porte un Corrigé (#320) et un Sécurité (#358). Suivi : #419 (point 1 avant le prochain tag).
|
||
|
||
## Decisions recentes
|
||
|
||
- 2026-10-12 : **Milestone `planned-2026-10-10-release-deps` mergée — `/autopilot` (4 PRs stackées en 1 h 50, CI lue dans les journaux à chaque maillon) → quatre `/pr-review` APPROVE → PR #418 de suivis en tête de pile → `/pr-review` APPROVE → merge ff par l'API, chaque enfant reciblé sur `main` (`main` `9e8c41b`, 5 PRs `merged`).**
|
||
- **Décision de Max : clé générique `linux-x86_64` retirée** de `latest.json`. Le worker de #320 puis la revue ont mesuré que ses seuls lecteurs (AppImage v0.4.3 à v0.4.5, binaire hors paquet) ne savaient pas installer le `.deb` qu'elle servait, et que les 64 tags qui embarquent l'updater (plugin 2.10.0) cherchent d'abord la clé de leur paquet : ces lecteurs reçoivent désormais `TargetsNotFound`, rien n'est installé.
|
||
- **Suivis des revues dans une 5ᵉ PR (#418)** plutôt qu'en commits sur #417 : le retrait touche la garde d'avant le `DELETE` du registre, catégorie « garde de destruction » de `/merge-stack`, donc relue avant le merge, et les quatre têtes revues n'ont pas bougé. Le contrôle passe dans `scripts/check-latest-json.jq`, exercé à chaque PR par le test du script (11 → 28 tests, 10 mutations rouges, vert sous jq 1.6) ; `/release` rejoue le garde `windows-sys` juste après l'édition de `Cargo.lock`.
|
||
- **Constats** : la prémisse « pas de Python dans le conteneur » de #345 était fausse (ADR 0023 corrigé) ; le déclencheur de la dérive `windows-sys` n'est pas « `hyper` et ce qu'il tire » (`f4b09b0`, #310) ; react-router 7.18.3 valide les navigations (150 contrôles sur les cibles de l'app, aucun échec) ; `/actions/tasks` ne liste un job qu'une fois pris par le runner, seuls les statuts de commit voient la file.
|
||
- **Restes** : #419, dont le point 1 (sous jq 1.6, le filtre accepte un `latest.json` vide ou à deux documents, inatteignable aujourd'hui) à corriger avant le prochain tag ; vérifications de la prochaine release dans Blockers ; vérification de la navigation dans l'app lancée (Linux, Windows), confirmatoire.
|
||
- Aucune migration DB (v1→v17). (ref #376, #345, #320, #358, #317, PRs #414-#418, #419, ADR 0023)
|
||
- 2026-10-08 : **v0.17.1 taggée et publiée (`e4db715`, run 508 vert), sur demande de Max (« /deploy et nouveau release 17.1 »).** Pré-vol du skill sur le tip `6de73b3` : build, 1904 vitest, `cargo check` sans avertissement, 255 Rust ; `.claude/worktrees/` vide. Diff depuis `v0.17.0` : `Cargo.lock`, `release.yml` et `tauri.conf.json` inchangés, seul ajout au manifeste Rust une dépendance de test (`tauri` avec la feature `test`, #390), rien sur le gating par édition : ni clés testeurs à émettre, ni cycle de mise à jour réel exigé (étape 10), la raison étant écrite dans le corps de la release. Numéro : `[Unreleased]` portait 6 entrées Added, et la convention (v0.16.0, v0.17.0) aurait donné une mineure ; question posée, Max a gardé 0.17.1. 5 manifestes, 2 changelogs et la ligne de `CLAUDE.md`, `Cargo.lock` édité à la main et accepté par `cargo metadata --locked`. Tag annoté poussé seul (jamais `--tags`). Run 508 ; `verify-release.sh` vert (7 artefacts, signatures et URL en 0.17.1) ; l'endpoint de `tauri.conf.json` (registre de paquets) sert la 0.17.1. Les vérifications manuelles (parcours guidé, post-merge de #390) passent après la publication, comme pour la v0.16.0. Aucune migration DB (v1→v17). (ref v0.17.1, #396-#401, #390)
|
||
- 2026-10-08 : **Parcours de démarrage guidé livré de bout en bout — `/autopilot` (6 PRs stackées en 3 h, CI verte à chaque maillon) → six `/pr-review` APPROVE → sept commits en tête de pile → merge ff par l'API (`main` `ee17f31`).**
|
||
- **Revues** : aucun bloquant, un verdict indépendant par PR (commentaires 20659 à 20730) ; `status:approved` posé par les seuls relecteurs, les workers ayant laissé `status:review` (skill corrigé).
|
||
- **Décision de Max : voie A** sur le critère de #398 « pas de « Fait. » pour un import qui n'ajoute rien ». Le relecteur a corrigé le rapport du run : les doublons seuls sont sans effet (leurs transactions sont venues avec un fichier `completed`) ; le vrai cas est l'import sans ligne valide (en-tête seul, format mal détecté), qui cochait l'étape 4 et faisait boucler /transactions et /import. L'étape compte désormais les `imported_files` en `completed` ayant au moins une transaction (`EXISTS` sur `transactions.file_id`, index `idx_transactions_file`), avec une entrée Corrigé : la v0.17.0 a déjà le défaut.
|
||
- **Autres suivis en tête** : D9 lit son drapeau hors transaction, donc plus de `BEGIN`/`COMMIT` à chaque ouverture, pendant lesquels `db.ts` laisse tout passer hors verrou ; `:focus-visible { outline: revert }` sur le contrôle entouré (WCAG 2.4.7) ; carte Budget sans cible sur l'état vide ; épingles (séquence réelle du reducer, phrase selon le filtre, notification de restauration hors verrou, fuseau du test du mois) ; docs et liste QA à 44 cas.
|
||
- **Preuves** : 16 mutations sur ces correctifs, toutes rouges, dont 4 survivantes des revues ; compteur rejoué avec sqlite3 sur le schéma consolidé ; tip en worktree `npm ci` propre (sonde rc=1, build, 1904 vitest) ; CI 507. Les commits ajoutés après la revue, non relus, sont nommés dans le commentaire 20835 de #407.
|
||
- **Merge** : chaque enfant reciblé sur `main` puis mergé en ff épinglé, branches gardées jusqu'au dernier merge puis supprimées, donc 6 PRs `merged`. #384 : trois items cochés (réglés par la pile), #382 en partie.
|
||
- **Acquis** : au `/plan-run`, confronter un critère à la définition du compteur hérité qu'il suppose (celui de l'étape 4 venait de la phase 1).
|
||
- Aucune migration DB (v1→v17). (ref #396-#401, PRs #402-#407, #408, #409, #384)
|
||
- 2026-10-06 : **#390 mergée (PR #394, `main` `5910387`) — l'étape 5 de la liste de démarrage se coche, les profils secondaires rattrapent leurs migrations, et les bases sont cherchées dans le bon dossier sous Linux.**
|
||
- **Constat** : en testant l'onboarding de la v0.17.0, Max a vu que classer une transaction ne cochait pas l'étape 5.
|
||
- **Cause** : depuis la v0.1.0, `updateTransactionCategory` lie un booléen JS. tauri-plugin-sql 2.3.2 le stocke en texte `'true'`, que le compteur `= 1` ne trouve pas.
|
||
- **Deux défauts plus anciens, trouvés en corrigeant** :
|
||
- tauri-plugin-sql ne migre que `simpl_resultat.db`. Un profil secondaire gardait le schéma de sa création ; il existe sept états publiés depuis la v0.3.0.
|
||
- Le plugin range les bases sous `app_config_dir()`. `repair_migrations`, `delete_profile_db` et `compute_account_return` cherchaient sous `app_data_dir()`, dossier différent sous Linux seulement. Supprimer un profil laissait sa base sur le disque, et les rendements du Bilan s'affichaient en tirets.
|
||
- **Décisions de Max** : réparer les drapeaux à l'ouverture de chaque profil plutôt que par une v18 ; inclure le rattrapage dans #390 ; appliquer les suggestions rapides de la revue, puis merger.
|
||
- **Livré** :
|
||
- `toSqlFlag`, à l'écriture et à la restauration d'une sauvegarde ;
|
||
- `prepare_profile_db` : plancher déduit du schéma, copie `VACUUM INTO` avant la première écriture, historique `_sqlx_migrations` au format sqlx, clés étrangères actives avec une seule reprise ciblée, réparation des drapeaux texte, échec ouvert ;
|
||
- l'historique écrit dès la création d'un profil ;
|
||
- `profile_db_path` : dossier `app_config_dir()` et nom de fichier validé ;
|
||
- l'ADR 0021, et les amendements des ADR 0003 et 0005.
|
||
- **Preuves** :
|
||
- les sept états publiés sont rejoués en fixtures ;
|
||
- 22 mutations de l'auteur, toutes rouges ;
|
||
- le plan checker a refusé trois fois (dossier Linux, rejeu de v2, clés étrangères), puis Max a validé la suite ;
|
||
- `/pr-review` APPROVE sur `71147c5` ;
|
||
- les quatre suggestions rapides sont appliquées en tête (`5910387`, des tests seulement, non relu), les quatre autres sont reportées en #395 ;
|
||
- tête éprouvée dans un worktree propre : sonde rc=1, 1520 vitest, 255 Rust, CI 495 et 496.
|
||
- **Suite** : #390 reste ouverte en `status:blocked` jusqu'à la liste post-merge.
|
||
- Aucune migration ajoutée (v1→v17). (ref #390, PR #394, #395, ADR 0021)
|
||
- 2026-10-05 : **v0.17.0 taggée et publiée (`07255e1`, run 491 vert) ; #234 close ; textes de la-compagnie-maximus#184 postés.** Pré-vol du skill sur le tip `8f964e0` : build, 1498 vitest, `cargo check` sans avertissement, 224 Rust ; `.claude/worktrees/` vide. Avant le bump, diff vide depuis `v0.16.0` sur `Cargo.lock`, `Cargo.toml`, `release.yml`, `tauri.conf.json` et `package*.json`, et aucune ligne du diff ne touche le gating par édition : ni clés testeurs à émettre, ni cycle de mise à jour réel exigé (étape 10), la raison étant écrite dans le corps de la release plutôt que tue. Version mineure (fonctionnalités ajoutées) : 5 manifestes, 2 changelogs et la ligne de `CLAUDE.md`, `Cargo.lock` édité à la main et accepté par `cargo metadata --locked`. Tag annoté confirmé par Max, poussé seul (jamais `--tags`). Run 491 en 22 min ; `verify-release.sh` vert (7 artefacts, signatures et URL en 0.17.0) ; l'endpoint de `tauri.conf.json` (registre de paquets) sert aussi la 0.17.0. Le même jour : **#234 fermée** sur sa quatrième preuve (`actcache` à 999 Mo, une seule entrée : celle, isolée, de la PR #375 a été évincée par le ménage par clé), avec la milestone `spec-ci-build-optimization` (4/4) ; la-compagnie-maximus#184 reçoit les deux textes des suites de licence (contrôle à la saisie, retrait de la clé), rattachés aux deux passages de son corps que la v0.17.0 rend faux. Aucune migration DB (v1→v17). (ref v0.17.0, #234, #373, #370, #367, la-compagnie-maximus#184)
|
||
- 2026-10-05 : **Suites de licence livrées — `/autopilot` (2026-10-04, 3 workers séquentiels de 36, 39 et 41 min, CI attendue verte entre deux maillons) → trois `/pr-review` APPROVE → suivis en tête de pile → merge ff par l'API (`main` `2cbc886`).** #373 : contrôle de révocation à la saisie, en arrière-plan, sous un verrou `tauri::async_runtime::Mutex` qui sérialise lecture de l'état → tentative → requête → verdict ; écart accepté : le test de concurrence rougit sans verrou sur le verdict lu par le second contrôle, pas sur le nombre de requêtes (une sonde à deux fils de 200 rondes n'a jamais ouvert la fenêtre). #370 : `remove_license` (clé supprimée d'abord, puis le jeton ; `license.check` gardé ; libération préalable par `deactivate_idempotent` + `note_revocation`, jamais `deactivate_in`, qui supprimerait le jeton avant la clé). #367 : suppression du jeton seulement s'il est « inchangé depuis la requête » (CWE-367), sur un 403 `license_revoked` des cours et à la lecture d'une liste complète sans ligne de ce poste ; garde étendue à la liste par le worker ; lignes de Journal à code fixe. Revues : aucun bloquant ; les 5 mutations survivantes des relecteurs (relais de « déjà révoquée », deux `t` oubliés, `Storage` de `store_license_in`, jeton non UTF-8) et deux autres suggestions (rechargement après un retrait en échec, budget de 6 requêtes) appliquées dans `2cbc886`, prouvées par 2, 18, 4, 1, 10, 1 et 1 tests rouges. Tip validé en worktree `npm ci` propre (sonde rouge rc=1, build, 1498 vitest, 224 cargo), CI 489/490. **Acquis** : appliquer les suggestions de revue en tête de pile garde les têtes revues intactes, donc le merge ff épinglé reste possible maillon par maillon ; un faux `t` qui rend la clé brute rend invisible tout `t` oublié (suite : #389). Aucune migration DB (v1→v17). (ref #373, #370, #367, PRs #386-#388, #389)
|
||
- 2026-10-04 : **#350 fermée sur l'étape 3, sans vérification en production de l'acceptation d'un jeton brut, sur décision de Max.** Le `/warmup` a relevé que la vérification de #365 (clé Base révoquée enregistrée sur le poste Linux le 10-03) avait dû effacer le jeton de la v0.15.0, puisqu'un changement de clé l'efface (#347), alors que l'entrée du 10-03 demandait de faire #350 avant. Un script local en lecture seule (`verif-350.py`, déposé sur le poste de Max : même clé HMAC et même ordre de lecture du `machine-id` que l'app, contrôlé contre le vecteur `THIS_DERIVED` et sur 7 cas synthétiques, n'affiche ni identifiant ni clé) l'a confirmé : clé révoquée enregistrée, aucun jeton. Clé testeur ressaisie puis « Activer » : jeton émis le 2026-10-04, claim dérivé (`64 brut: False dérivé: True`), poste marqué « Cette machine ». La liste ne montre qu'une machine, aucune ligne brute active, donc les étapes 1-2 ne sont plus vérifiables : l'acceptation d'un jeton brut (ADR 0020, D1) reste gardée par `activation_token_from_before_the_derivation_still_matches` et `activation_status_accepts_a_token_from_before_the_derivation`, et un défaut ne toucherait que les installations activées par la v0.15.0 (testeurs), réparable par « Activer ». Dans la même séance, en Gratuite par la clé révoquée, **#346 vérifiée** : « J'ai déjà une clé » ferme le modal sur la carte Licence. Le corps de #370 passe donc sa PR en `Fixes #370`, sans `status:blocked` après la PR. **Leçon** : une vérification manuelle qui change la clé détruit l'état dont dépend une autre ; ordonner les vérifications d'une release par ce qu'elles consomment. Aucune migration DB (v1→v17), pas d'entrée CHANGELOG. (ref #350, #346, #365, #370)
|
||
- 2026-10-04 : **Onboarding phase 1 livrée de bout en bout — `/plan-run` (2026-10-03) → `/autopilot` (7 PRs stackées en 1 h 15) → 7 `/pr-review` → `/merge-stack` ff (`main` `667e058`).** Trois faits d'ancrage avaient réécrit la spec : le seed IPC met 180 mots-clés dans tout profil neuf et le wizard catégorise à l'import (`useImportWizard.ts:1016`), donc la case « première règle » devient « une transaction classée à la main » (`is_manually_categorized = 1`) et les gabarits portent 7 + 4 lignes hors seed ; aucune commande Rust n'écrivait de fichier, d'où `create_sample_import_folders(import_folder, today)` avec `today` venu du webview (`chrono` compilé sans `clock`) ; une seule banque (Tangerine) a une page officielle d'export, chaque bloc du guide porte son statut de vérification. `/review-spec` avait trouvé 2 critiques (le corpus `CsvFixtureName` gelé à 15 par 6 boucles ; `DocsContent` non testable par appel direct) et corrigé une erreur du plan (33/40, pas 35/40, mesuré avec la vraie regex). Run autopilot : pile linéaire honorée malgré un graphe à 3 maillons parallélisables, pour un merge ff sans conflit `fr.json`/`en.json` ; un seul report inter-maillons (réalignement JSON du « Démarrage rapide », #355 → #357). Revues : 3 correctifs en tête de pile — statut BMO sans provenance interne (le corps d'issue avait fui dans l'UI), garde `budgetReady` sur la liste compacte (fenêtre 5/5 → 5/6 au boot), test `formatLocalDate` aveugle sous `TZ=UTC` (mutation `toISOString` vérifiée rouge). Merge : tip éprouvé en worktree `npm ci` propre (sonde rouge rc=1, tsc, 1440 vitest, build, 192 cargo), API ff du bas vers le haut avec recible de chaque enfant sur `main` → 7 PRs `merged`, pas `closed`. **Constat de process** : les workers autopilot posent `status:approved` eux-mêmes après auto-revue, le label ne prouve plus une revue indépendante (mémoire, #384). Max est client BMO, banque sans signature : la validation sur compte réel vit dans #371, la signature d'import BMO est reportée. Aucune migration DB (v1→v17). (ref #351-#357, PRs #377-#383, #384, #371)
|
||
- 2026-10-03 : **#234 mergée (PR #375, `main` `f821492`) — le cache Rust de la CI fonctionne, `check-rust` tombe de 9 min 37 s à 3 min 22 s, et la panne tenait au VPS, pas à l'adresse `cache.host` que visait l'issue.** Diagnostic par la PR #374, fermée sans merge : ufw n'ouvrait l'hôte aux conteneurs que depuis `172.16.0.0/12`, alors que Docker (`daemon.json` de Coolify) alloue ses réseaux, ceux des jobs compris, dans `10.0.0.0/8` ; et le runner, sans fichier de config, tirait le port de son proxy de cache au hasard à chaque démarrage. Correctif appliqué par Max sur le VPS : `runner-config.yml` avec `cache.proxy_port: 28100`, passé en `--config` par un fichier complémentaire systemd, règle ufw de `10.0.0.0/8` vers ce port, ports du cache vérifiés fermés depuis Internet ; consigné avec son retour arrière dans `forgejo-ops.md` (la-compagnie-maximus `66787ea`). **Le design vient d'un constat** : le runner v12.7.0 isole ce qu'écrit un run `pull_request` sous la référence de la PR, et les autres PR ne retombent que sur les entrées non isolées. Décisions de Max : **D1** `Swatinem/rust-cache@v2` sur les PR, avec un run hebdomadaire sur `main` (lundi 06:30 UTC) et `workflow_dispatch` pour seuls écrivains du cache partagé ; **D2** pas de cache npm (`npm ci` prend 9 s). Mesuré : run 459 à froid, sauvegarde d'environ 999 Mo ; run 461 en `full match: true`, `cargo check` en 9,9 s. **`/pr-review` APPROVE**, trois suggestions appliquées dans `f821492` sans nouvelle relecture : le ménage du runner garde une entrée par clé, toutes portées confondues (une PR qui sauvegarde sous la clé partagée l'évince jusqu'au lundi) ; la clé hache aussi les variables `CARGO*`/`RUST*` du job et ignore la version de l'app ; un 404 un lundi après une semaine sans requête est une course connue du runner (forgejo/runner#1741), pas un retour de #234. **Après le merge**, `check-rust` lancé sur `main` par `workflow_dispatch` (run 464) : même clé que l'entrée de la PR, `No cache found.` (isolation prouvée), puis `Cache saved successfully` en portée partagée. **#234 reste ouverte en `status:blocked`** jusqu'à la restauration de cette entrée par la prochaine PR Rust, un premier run planifié vert le lundi 2026-10-05 et la taille de `actcache` relevée par Max ; fermeture à la main ensuite. Suite ouverte : #376 (Node 20 en fin de vie dans `check-frontend` et `audit`). Hors dépôt, `/warmup` doit filtrer les échecs `check-rust` sur l'événement `schedule`, et `forgejo-ops.md` décrire l'isolation des PR et l'éviction par clé. Aucune migration DB (v1→v17), pas d'entrée CHANGELOG (CI seule), pas de release. (ref #234, PR #375, #374, #376)
|
||
- 2026-10-03 : **v0.16.0 taggée et publiée (`56fc612`, run 451 vert) — sur le constat de Max qu'il n'y a pas d'autres utilisateurs que les testeurs, les vérifications manuelles passent après la publication.** Aucune PR ouverte à merger. Pré-vol du skill sur le tip `6625d25` : build, vitest 1348, `cargo check` sans avertissement, 187 Rust ; aucun worktree résiduel ; les deux testeurs ont une clé Premium valide depuis la v0.15.0 et rien ne touche `FEATURE_TIERS`. Version mineure (fonctionnalités ajoutées) : 5 manifestes, 2 changelogs et la ligne de `CLAUDE.md`, `Cargo.lock` édité à la main et accepté par `cargo metadata --locked`. Tag annoté confirmé par Max avant le push, poussé seul (jamais `--tags`). Run 451 en 22 min ; `verify-release.sh` vert ; l'endpoint de `tauri.conf.json` (registre de paquets) sert la 0.16.0, au-delà de la copie attachée à la release que lit le script. **Correction faite en route** : j'avais écrit que les installations Base+ recevraient la mise à jour d'elles-mêmes ; `docs/qa-update-cycle.md` et le code disent l'inverse, aucune vérification automatique, quatre déclencheurs manuels. Personne ne reçoit donc la release sans cliquer « Vérifier les mises à jour ». **Étape 10 due** (`rustls` 0.23.45 est sur le chemin TLS de l'updater) : Linux par Max, enchaînée avec #350 sur le poste activé en v0.15.0 (à faire avant tout changement de clé, qui efface le jeton) ; Windows par Michel. Trace à consigner dans le corps de la release. En parallèle : la-compagnie-maximus#184 (politique de confidentialité) par Max ; #370 ouverte (retrait de la clé, `status:triage`). **Tests de Max le jour même** : mise à jour Linux v0.15.0 → v0.16.0 réussie, trace consignée dans le corps de la release (invite d'authentification apparue, type non noté ; Windows à dérouler par Michel) ; #365 vérifiée avec la clé réellement révoquée et fermée. Anomalie relevée : saisie en cours de session, cette clé gardait l'édition Base jusqu'au clic sur « Activer », comportement livré (contrôle au démarrage seulement) → **#373** propose le contrôle dès la saisie. La vérification de #346, qui demande une édition Gratuite propre, est reportée à #370 (instructions ajoutées à son corps) ; **#372** ouverte (la liste complète des versions repousse le Journal en bas de Paramètres → Systèmes). Aucune migration DB (v1→v17). (ref v0.16.0, #270, #346, #347, #348, #350, #365, #370, #372, #373)
|
||
## Blockers actifs
|
||
|
||
- Aucun blocker externe dur. `spec-monetisation` **fermée 12/12** (2026-07-08) — #50/#52/#53/#135/#136 livrées, ne sont plus des blockers.
|
||
- **Avant le prochain tag : #419, point 1.** Sous jq 1.6, la version du conteneur de release, `scripts/check-latest-json.jq` accepte un `latest.json` vide ou à deux documents : c'est la garde du `DELETE` du registre. Inatteignable aujourd'hui (la génération échoue fermée avant « Publish »), mais à fermer avant de tagger.
|
||
- **Vérifications dues à la prochaine release** (après le tag, étape 9 de `/release`) :
|
||
- `release.yml` sous Node 24 (#376) : `node --version` à `v24.x` dans le journal du run de release, et `verify-release.sh` vert. Le diff touchant `release.yml`, l'étape 10 de `/release` (cycle réel de mise à jour, `docs/qa-update-cycle.md`) s'applique aussi, selon la règle du skill.
|
||
- `latest.json` à trois clés (#320, clé générique `linux-x86_64` retirée le 2026-10-11) : étape « Generate latest.json » du journal lue (un paquet retenu par type), `verify-release.sh` en `VERDICT : OK` sur `linux-x86_64-deb`, `linux-x86_64-rpm` et `windows-x86_64` (extensions, `file:` des signatures). Cycle réel depuis une installation `.rpm` (§3 de `docs/qa-update-cycle.md`) dès qu'une machine Fedora ou openSUSE est disponible, sinon « non déroulé » avec la raison dans la trace de la release.
|
||
- **Le paiement est live : « aucun tag avant le go-live » n'a plus de raison d'être, et la release desktop qu'attendait le go-live est publiée (v0.16.0, 2026-10-03).** Bascule live le 2026-09-29 (Product et Price live à 19 $ CAD, webhook, variables Stripe de production, redeploy `3673d09` de maximus-api, URL `cs_live_` vérifiée), puis achat réel de contrôle le 2026-09-30 : clé sur `/merci` et par courriel, activation dans l'app, remboursement complet et licence révoquée par `charge.refunded`. **Volet serveur clos le 2026-10-03** (derniers commentaires relus le 2026-10-04) : maximus-api#62 fermée, tous critères cochés (maximus-api 0.4.2 en prod, secrets en runtime seul), avec la milestone `spec-paiements` de maximus-api (12/12) ; la-compagnie-maximus#150 (Link dans les textes légaux) livrée et fermée le 2026-10-01. **Go-live clos : la-compagnie-maximus#141** fermée le 2026-10-10 sur décision de Max, l'updater vérifié (Free refuse et invite à acheter, Base accepte ; confirmé le même jour). Restent pour mémoire, sans issue : le Dashboard Stripe (logo, paramètres Checkout, reçus automatiques, alertes d'échec de webhook) et les relevés du commentaire de fermeture. la-compagnie-maximus#184 (politique de confidentialité : données d'activation, contrôle au démarrage) est en `status:review` ; sa PR reste en brouillon jusqu'au déploiement de maximus-api#85 (commentaire du 2026-10-03). Les deux textes des suites de licence (contrôle à la saisie, retrait de la clé) y sont postés depuis le 2026-10-05 (commentaire 19724). **Vérifications manuelles sur la release publiée, toutes faites** : #365 le 2026-10-03, #346 et #350 le 2026-10-04 (voir Décisions). L'étape 10 sous Windows est faite (Michel, confirmée le 2026-10-10).
|
||
- Backlog ouvert : **vague `planned-2026-09-24-paiements` close 3/3** (milestone fermée le 2026-09-30) : #270 (PR #359) et #346 (PR #362) mergées le 2026-09-27, #347 (PR #364, ferme aussi #360) mergée le 2026-09-30 ; volet site **clos** (maximus/la-compagnie-maximus#153, redirection de `/simpl-resultat` en prod). **#365 fermée le 2026-10-03** après sa vérification manuelle. **Milestone `planned-2026-10-03-suites-licence` fermée 3/3 le 2026-10-05** (#373, #370, #367 mergées, voir Décisions ; suivi #389 en `status:triage`). Hors milestone, en `status:ready` : **#369** (réserver le fractionnement de transactions à l'édition Base) et **#372** (la liste complète des versions repousse le Journal en bas de Paramètres → Systèmes). **#350 fermée le 2026-10-04** (étape 3 vérifiée en production, voir Décisions) ; #363 fermée le 2026-10-10 sur décision de Max (ses tests, absorbés par #347, sont livrés dans la v0.16.0) ; réglés côté serveur et site : maximus-api#63 (clés de 100 ans) et maximus-api#70 (réactivation d'une machine désactivée), fermées et contenues dans `3673d09`, le commit déployé à la bascule du 2026-09-29, et la-compagnie-maximus#157, fermée, dont les CGV sont publiées en tronc commun plus annexe Simpl-Résultat (annexe relue en production le 2026-09-30, plus aucune durée de 10 ans) ; côté serveur, `/v1/prices` ne vérifie pas qu'une machine est encore active (une machine désactivée garde les cours jusqu'à l'expiration de son jeton), issue maximus-api à ouvrir ; suites de #350 ouvertes le 2026-10-01 : maximus-api#82 (`status:triage` : identifiants machine bruts déjà stockés, lignes désactivées comprises ; à rehacher avant l'expiration des premiers jetons bruts, sinon une réactivation crée une seconde ligne) et la-compagnie-maximus#184 (`status:review`, voir ci-dessus) ; go-live clos (la-compagnie-maximus#141 fermée le 2026-10-10, maximus-api#62 le 2026-10-03) ; `spec-paiements` fermée ici 5/5 ; onboarding phase 2 (parcours guidé) **mergée** : milestone `planned-2026-10-06-onboarding-parcours-guide` fermée 6/6 le 2026-10-08 (#396 à #401, `ee17f31`), suivis **#408** et **#409** (`status:triage`) ; onboarding phase 1 **livrée** : milestone `planned-2026-10-03-onboarding-phase1` fermée 7/7 le 2026-10-04 (#351 à #357, mergées en avance rapide, `667e058`) ; suivis ouverts : **#384** (`status:ready`, suivis non bloquants des revues) et **#371** (`status:blocked`, hors `/autopilot` : en-têtes CSV BMO à fournir par Max depuis un compte réel, un par type de compte, chèques/épargne et Mastercard, avec des valeurs fictives) ; analyse d'origine dans `docs/analyse-onboarding-2026-09.md`, plan détaillé dans les `spec-*-onboarding-phase1.md` locaux, ignorés par git ; #271 absorbé par #301, livré ; `spec-ci-build-optimization` **fermée 4/4** le 2026-10-05 (#232 livrée le 2026-07-27 ; #234 close le 2026-10-05 avec ses quatre preuves : dispatch run 464, PR #386 run 480, run planifié 488, `actcache` à 999 Mo) ; **#376** fermée le 2026-10-12 (Node 24, PR #414). Le suivi « glob `src-tauri/**` non prouvé » ouvert avec #232 est **levé** : la PR #344 est le cas test isolé attendu (`Cargo.lock` + 2 `.md` seulement) — `check-rust` a bien tourné, `check-frontend` a bien été sauté par sa denylist.
|
||
- Suivis des advisories : **#312, #313 et #315 fermées le 2026-08-15** (PRs #321/#322 mergées). **#314 fermée le 2026-08-15, prémisse infirmée** — elle affirmait « zéro run `schedule` », or `audit.yml` tire tous les jours à 06:00 UTC (**19 runs `schedule` verts** du 07-28 au 08-15, sans trou) ; elle a été écrite le 07-27 vers 23:56Z, ~6 h avant le premier tir programmé possible, et décrivait donc une fenêtre trop courte, pas un scheduler en panne. Ces 19 runs confirment au passage que `.cargo/audit.toml` est bien lu en conteneur **sur `main`** — l'ADR 0018 ne l'avait vérifié que par un `workflow_dispatch` sur une branche. **#343 fermée le 2026-09-04** (PR #344) — RUSTSEC-2026-0258 sur `h2`, la seule vulnérabilité qui rougissait l'audit depuis le 08-19 ; l'audit est de nouveau vert sur `main`, prouvé par `workflow_dispatch` (run 393) et non déduit du run de PR. **#348 fermée le 2026-09-21** (PR #349) — RUSTSEC-2026-0285 sur `rustls`, seule vulnérabilité rougissant l'audit depuis le 09-15 (7 runs, 405→411) ; vert reprouvé par `workflow_dispatch` sur `main` (run 414 : 666 paquets, zéro vulnérabilité, 12 warnings autorisés). Deux advisories en cinq semaines sur le même chemin, celui de la mise à jour automatique. **#317** fermée le 2026-10-12 par la PR #417 (#358). Reste **#319** (déclencheur de retrait pour `rsa`, désormais **seule** entrée de `.cargo/audit.toml` — le garde-fou est passé à 2 vérifications). **#345** fermée le 2026-10-12 (PR #415) : garde `Verify windows-sys pinning` dans `check-rust.yml` et ADR 0023, qui portent la mesure, le coût (3 contre 5 versions compilées pour Windows) et la condition de sortie. Côté npm, **#358** fermée le 2026-10-12 (PR #417) : lock régénéré par `npm@11.21.0` dans les bornes de `package.json`, `npm audit` 8 → 0 au 2026-10-10.
|
||
- **#320** fermée le 2026-10-12 (PR #416, clé générique retirée par la PR #418) : une clé `latest.json` par paquet Linux, à vérifier au prochain tag (puce « Vérifications dues à la prochaine release ») ; le §3 de `docs/qa-update-cycle.md` est devenu la procédure de test rpm.
|
||
- Suivis ouverts du chantier import (milestone fermée) : le refus du format « montant absolu + indicateur D/C » ne scanne que `amountCol ± 1`, donc une colonne D/C placée ailleurs passe encore ; dérives de comptes préexistantes dans `CLAUDE.md` et `docs/architecture.md` (composants, pages, services, `Version actuelle : 0.6.3` vs tag v0.14.0) mesurées et documentées en revue, non corrigées.
|
||
- **Étape 10 de la release v0.15.0 consignée le 2026-09-13** — plus un blocker : cycle réel v0.14.0 → v0.15.0 validé par les deux testeurs ; trace rédigée pour le corps de la release (`PATCH` à appliquer par Max) ; invite d'authentification Linux non consignée ; #320 reste ouverte (`.rpm`). Deux restes : (1) le texte de la carte Compte Maximus (« Le compte est requis uniquement pour les fonctionnalités Premium », hérité de v0.7) contredit v0.15.0 où Premium vient de la clé, et a vraisemblablement conduit un testeur à se connecter pour rien (code de vérification Logto reçu par courriel) — reformulation livrée par #346 (PR #362), avec une réserve notée dans l'ADR 0017 (exacte tant que le chemin abonnement → Premium reste dormant) ; (2) le flux Logto exact (connexion par code, mot de passe oublié ou inscription) reste à lire dans le journal d'audit. Position produit : v0.17.0 (2026-10-05) ; `[Unreleased]` vide.
|