Onboarding phase 1 : suivis restants des revues #377-#383 (épingles, carte Transactions, messages d’Import, dérives de docs) #384
Labels
No labels
autopilot:pending-human
source:analyste
source:defenseur
source:human
source:medic
status:approved
status:blocked
status:in-progress
status:needs-clarification
status:needs-fix
status:ready
status:review
status:triage
type:bug
type:feature
type:infra
type:refactor
type:schema
type:security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: maximus/Simpl-Resultat#384
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Contexte
Constats non bloquants des sept
/pr-reviewde l'onboarding phase 1 (PRs #377 à #383, mergées le 2026-10-04,667e058). Ce corps est réécrit par/analyzele 2026-10-16, lu surmain065f580. L'ancien corps et la liste de ce qui a changé sont archivés dans le commentaire 24043. Les items réglés depuis (#377, #378, le label de process, le flash d'Import, le câblage de Budget, le compte des hooks de l'arborescence,block.props.refsous React 19) sont retirés.Décisions (Max, 2026-10-16)
showsEmptyState(src/hooks/useTransactions.ts:213) ne regarde plus quetotalInDb === 0.totalInDbvautnulltant que le compte n'est pas chargé, donc rien ne s'affiche avant. Le test « keeps the regular layout while a page is loading, even at 0 » (useTransactions.test.ts:70) est réécrit pour la nouvelle règle.create_sample_import_folderstraduits par des codes : la commande Rust rend des codes stables au lieu de phrases anglaises, et le front les traduit. Un message inconnu reste affiché brut, comme aujourd'hui (t(state.error, { defaultValue: state.error }),ImportPage.tsx:109).Travail à faire
1. Épingles (code correct, propriété non prouvée)
src-tauri/src/commands/fs_commands.rs, module de tests : cas « Exemple Tangerine existe → Exemple Desjardins non créé, rien n'est écrit ». Le test existant (refuses_when_desjardins_folder_exists_and_writes_nothing) ne couvre que le premier dossier de la boucle. Mutation : retirer la boucle de vérification préalable (for (folder_name, _) in &samples { if root.join(folder_name).exists() ... }) doit rougir ce nouveau test.{{M1}}= mois le plus récent ».assert_dates_inaccepte les deux mois sans les distinguer. Asserter qu'une ligne précise du gabarit (la première ligne de données de chaque fichier, ou toute ligne connue pour porter{{M1}}) porte08/2026pourtoday = 2026-09-25. Mutation : échangerm1_tokenetm2_tokendans les deux.replacedoit rougir. Côté vitest,onboarding-samples.test.ts(M1 = "08/2026", l. 53) : même épingle si le test lit une ligne précise ; sinon le noter dans la PR.src/__integration__/onboarding-samples.test.ts:229: corriger le commentaire « the seed is all priority 0 ». C'est faux : COSTCO et WALMART sont à 50, COUCHE-TARD ESSENCE à 10. Le commentaire doit dire pourquoi le tri du mock reste juste.src/pages/TransactionsPage.render.test.tsx: un cas « profil sans transaction » (totalInDb: 0) qui asserte la cartetransactions.empty.*(clé exacte à lire dansTransactionsPage.tsx, l. 119 et suivantes) et l'absence du tableau, sur le modèle deBudgetPage.render.test.tsx(« a profile without transactions »). Mutation :isEmptyProfileforcé àfalsedoit rougir.2. Transactions et Budget
showsEmptyStatede Transactions =state.totalInDb === 0, signature réduite àPick<TransactionsState, "totalInDb">. Réécrire le test de la ligne 70 : à 0 avec une page en chargement, l'état vide est affiché. Vérifier à la lecture qu'après un import,totalInDbest rechargé (canal d'événements de données, ADR 0022), sinon la carte resterait affichée. Si ce n'est pas le cas, le noter dans la PR comme limite, sans corriger.useTransactions.ts:232etuseBudget.ts:431:Promise.allcouple l'échec degetTransactionCount()à celui des autres chargements, si bien qu'un compte en échec vide aussi les catégories et les sources. Passer àPromise.allSettled: chaque résultat réussi est dispatché, le premier échec part enSET_ERROR, et un compte en échec laissetotalInDbànull(mise en page normale, jamais la carte). Test du chargement si le harnais de hook le permet (src/test/hookHarness.ts), sinon une fonction pure extraite qui transforme les résultats en actions.3. Import (#382)
create_sample_import_folders(fs_commands.rs, l. 240 et suivantes) rend des codes stables :sample_folder_exists:<nom>pour « Folder already exists » ;import_folder_missingpour « Folder does not exist » ;invalid_datepour « Invalid date ».Les erreurs d'écriture (
Cannot create folder,Cannot write) gardent leur texte : ce sont des erreurs du système, rares, utiles brutes dans le Journal. Côté front,createSampleFolders(useImportWizard.ts:443) traduit chaque code en cléimport.empty.sampleErrors.*(FR et EN, nom du dossier interpolé) et garde le message brut pour tout autre texte. Le message brut part aussi enlogWarn. Tests Rust des trois codes (adapter leserr.contains(...)existants) et test du mapping côté front (fonction pure).scanFolderInternalattrape son erreur et ne la relance pas, doncSET_SAMPLE_CREATEDpart même après un rescan en échec. Ne poserSET_SAMPLE_CREATEDque si le rescan a réussi :scanFolderInternalrend un booléen, ou une valeur équivalente lisible par l'appelant. Test : rescan en échec →sampleCreatedrestenullet l'erreur est posée.ImportEmptyState:hasFolderetfolderNamesont redondants (folderName !== null⇔hasFolderaux deux sites d'appel,ImportPage.tsx:77-78et153-155). GarderfolderName: string | nullseul et mettre à jour les deux appels et les tests de rendu existants.4. Documentation
docs/architecture.md, section « Commandes Tauri » :generate_handler!(src-tauri/src/lib.rs, 45 commandes au 2026-10-16) ;send_feedback,get_feedback_user_agent,ensure_backup_dir,get_file_size,file_exists) dans la section de leur module ;fetch_pricepar sa description réelle (balance_commands.rs,fetch_price_in, refusLicenseRevoked, voir la section licence l. 464) ;docs/architecture.md: titre « Hooks (25+) » → compte réel (29 au 2026-10-16, fichiers.tshors tests desrc/hooks/).CLAUDE.md, arborescence : « 13 hooks custom » → même compte. Pour éviter un conflit avec #446 (compte des composants dans la même arborescence deCLAUDE.md), recompter au moment du maillon, pas recopier ces chiffres.docs/guide-utilisateur.md:30et la clédocs.*correspondante (FR et EN) : « le seed de mots-clés » → « les mots-clés fournis avec l'application » (EN : « the keywords that come with the app »).Fichiers concernés
src-tauri/src/commands/fs_commands.rs: codes d'erreur, deux épinglessrc/__integration__/onboarding-samples.test.tssrc/hooks/useTransactions.ts,src/hooks/useTransactions.test.ts,src/hooks/useBudget.ts,src/hooks/useBudget.test.tssrc/pages/TransactionsPage.render.test.tsxsrc/hooks/useImportWizard.ts,src/hooks/useImportWizard.test.ts,src/pages/ImportPage.tsx,src/components/import/ImportEmptyState.tsxet ses tests de rendusrc/i18n/locales/fr.json,src/i18n/locales/en.jsondocs/architecture.md,docs/guide-utilisateur.md,CLAUDE.mdCHANGELOG.md,CHANGELOG.fr.mdSurface de test
fs_commands.rs(5 tests du dossier d'exemple),onboarding-samples.test.ts,useTransactions.test.ts(showsEmptyState, l. 39-77),useBudget.test.ts(l. 371-401),TransactionsPage.render.test.tsx,BudgetPage.render.test.tsx,ImportPage.render.test.tsx,useImportWizard.test.ts.Critères d'acceptation
TransactionsPagerougissent sous leur mutation, citée dans la PR.ImportEmptyStaten'a plus quefolderName.architecture.md: compteurs de commandes et de hooks justes, les cinq commandes documentées,fetch_pricedécrite au présent ;CLAUDE.mdà jour ; guide sans « seed ».npm test,cargo testet la CI verts.Hors portée
docs/qa-onboarding.html).Complexité
Medium : volume, une modification Rust bornée, aucune migration.
Plan d'exécution — milestone lot-v018 (planifié le 2026-10-16)
Les sections ci-dessous viennent de la séance
/plan-rundu 2026-10-16 (revue/review-specSécurité, Architecture, Technique comprise). En cas de conflit avec le corps au-dessus, elles priment.Consignes communes
v0.17.2existe (git ls-remote --tags origin v0.17.2). Sinon, arrêt sans rien écrire.main065f580; #369, #419 et #421 les ont déplacés depuis. Repérer chaque site par son contenu (symbole, chaîne), jamais par son numéro.STATE.md: le report dansSTATE.mdse fait au/merge-stack.Depends on
Note : dépendance d'ordre de la pile, pas de dépendance de code.
Décisions prises en planification
/analyzele 2026-10-16 (D1, D2 ci-dessus, décisions de Max). Ajoutée à la milestone par Max le même jour, juste avant #446 : les deux touchentdocs/architecture.mdet l'arborescence deCLAUDE.md. Chacune recompte sur le tip de son maillon.Spec source
spec-plan-lot-v018.md
La pile du parcours guidé (#402 → #407, mergée le 2026-10-08,
mainee17f31) règle trois items de cette liste, cochés dans le corps :hide()pendant unrefresh()en vol : #396 (PR #402) fait primer une action locale sur le snapshot d'un chargement parti avant elle (hiddenSetAtdans le reducer deuseOnboardingChecklist, ADR 0022 §4).onboarding.state.*) dansOnboardingChecklist.status:approvedposé par les workers : le skillautopilotlaisse désormaisstatus:review; le run du 2026-10-08 a laissé ses six issues enstatus:review.En partie seulement, donc non coché : #382. Le flash de la variante « sans dossier » est réglé par
d024f5a(#398, PR #404) : la page attend la lecture du dossier d'import. Restent les bannières succès et erreur qui peuvent coexister si le rescan échoue après l'écriture, et le message de refus Rust affiché en anglais brut. Un micro-flash de la ligne « Aucun dossier configuré » d'ImportFolderConfigest noté comme limite connue dans la liste QA (guided-import-flash).Archive avant réécriture par
/analyze(2026-10-16, lu surmain065f580). Corps rédigé le 2026-10-04, jamais relu contre le code depuis. Entre-temps, les piles du parcours guidé (#396-#401), de la fiabilité des tests (#408, #409, #389, #395) et des retours de la v0.17.1 (#422-#432) ont touché Import, Transactions, Budget etdocs/architecture.md.Ce qui a changé :
d024f5a(#398), déjà noté dans le commentaire 20845.isEmptyProfiledes pages : Budget est maintenant couvert (BudgetPage.render.test.tsx, « a profile without transactions »). Transactions ne l’est pas :TransactionsPage.render.test.tsxne rend jamaistotalInDb: 0.src/__integration__/onboarding-samples.test.ts.docs/architecture.mddit maintenant « (39) » ;generate_handler!en enregistre 45. Cinq ne sont jamais nommées (send_feedback,get_feedback_user_agent,ensure_backup_dir,get_file_size,file_exists).compute_account_returnest documentée, maisfetch_priceest encore décrite « à venir Phase 5 » alors qu’elle est enregistrée.architecture.mddit 29, juste (29 fichiers hors tests). Restent le titre « Hooks (25+) » etCLAUDE.md(« 13 hooks custom »).block.props.ref: le projet est sur React^19.1.0, donc le test est valide ; plus rien à faire tant que React reste en 19.Promise.all(useTransactions.ts:232,useBudget.ts:431), le garde!isLoadingdeshowsEmptyState(useTransactions.ts:213), les bandeaux réussite et erreur qui coexistent (scanFolderInternalattrape son erreur et ne la relance pas,SET_SAMPLE_CREATEDpart quand même), le message Rust brut, la redondancehasFolder/folderName, le jargon du guide (l. 30).Corps du 2026-10-04 (avec les coches du 2026-10-09)
Constats non bloquants des sept
/pr-reviewindépendantes de la vagueplanned-2026-10-03-onboarding-phase1(PRs #377 → #383, mergées ff surmainà667e058le 2026-10-04). Les trois correctifs déjà appliqués en tête de pile (statut BMO sans provenance interne, gardebudgetReadysur la liste compacte, testformatLocalDateépinglé hors UTC) n'y figurent pas.Tests à épingler (code correct, propriété non prouvée)
fs_commands.rs: ajouter le cas discriminant « Exemple Tangerine existe → Exemple Desjardins non créé » (retirer la boucle d'existence laisse les 5 tests verts aujourd'hui){{M1}}= mois le plus récent » (l'inversion des jetons laisse Rust 5/5 et vitest 9/9 verts)onboarding-samples.test.ts:239: le commentaire « the seed is all priority 0 » est faux (COSTCO/WALMART = 50, COUCHE-TARD ESSENCE = 10) ; le tri du mock est justeisEmptyProfile ?) n'est couvert par aucun test (convention du dépôt sans renderer) — à documenter ou couvrir si un renderer arriveUX / robustesse
useOnboardingChecklist.ts:92-113: unhide()pendant unrefresh()en vol peut être annulé par le snapshothiddende ce chargement (sans effet tant que le dashboard ne rafraîchit qu'au montage)OnboardingChecklist: l'état fait/verrouillé n'est pas annoncé aux lecteurs d'écran (icônearia-hidden,line-throughmuet)useTransactions.ts:171-180,useBudget.ts:435-441:Promise.allcouple l'échec degetTransactionCount()à celui des catégories/sources ;allSettledgarderait l'ancien comportement!isLoadingsur Transactions allonge le flash au lieu de l'éviter (mise en page régulière jusqu'à la fin de la première page sur un profil vide) ; incohérent avec Budgetloaded) ; bannières succès et erreur peuvent coexister si le rescan échoue après l'écriture ; message de refus Rust affiché en anglais bruthasFolder/folderNameredondants dansImportEmptyStateDocumentation
docs/architecture.md: « Commandes Tauri (37) » = somme des sections, maisgenerate_handler!en enregistre 43 ; 7 commandes jamais listées (send_feedback,get_feedback_user_agent,ensure_backup_dir,get_file_size,file_exists,compute_account_return,fetch_price) — dérive préexistantehooks/ # 29vs « Hooks (25+) » ; #381 : « le seed de mots-clés » est du jargon dans le guide (chapitre 1)DocsSubsectionslitblock.props.ref, valide seulement sous React 19Process
autopilot/sprint: les workers posentstatus:approvedaprès leur auto-revue, avant toute revue indépendante — laisserstatus:review, réserverapprovedau relecteur (mémoirefeedback_autopilot_self_review_label)Onboarding phase 1 : suivis non bloquants des revues #377-#383to Onboarding phase 1 : suivis restants des revues #377-#383 (épingles, carte Transactions, messages d’Import, dérives de docs)