docs: architecture, ADR 0019, user guide and changelog for the import format #342
No reviewers
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#342
Loading…
Reference in a new issue
No description provided.
Delete branch "issue-332-docs-adr-changelog"
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?
Link 10 of 10 — the last one — of the import-format stack. Based on
issue-331-sref-import-sources, not onmain. Review the top commit only.Resolves #332
Links 1-9 wrote no changelog and no documentation on purpose (
spec-plan-import-csv-format.md: a per-PR entry would conflict at every level of a ten-deep linear pile). This link owes all of it. The nine PR bodies were read to write the entries, rather than the issue bodies — several links revised their own issue's framing along the way.ADR 0019 — the import format is a persisted value, never re-inferred
The chantier's three failure paths were independent, which is the point of giving them one ADR rather than three fixes:
signConvention: "negative_expense"outright (#324).DELETE FROM import_sourceson restore, replaced by a synthetic "Data Import" source (#331).The ADR records why the completeness guarantee comes from the codec and its test, not from a composed type:
ImportSource.has_headerisbooleanandImportConfigTemplate.has_headeris anumber, so a shared shape is structurally impossible.FORMAT_FIELD_PAIRStypedRecord<keyof ImportFormat, keyof ImportFormatRow>fails to build on an unlisted field; the test fails on a field listed but not wired. It also records the decision thattemplate_idis a provenance label, never re-read as format — deriving the format from it would hand the format back to a mutable carrier, which is the thing being removed.Status Accepted. The
Spec:line points at the two root spec files — both already tracked (force-added inb30c9fa, the base of this stack), verified withgit ls-filesbefore writing the line, so the dead-Spec:-line precedent from ADR 0016 / #295 does not repeat here. Nogit add -fwas needed.Counts — measured against the tree, not derived by arithmetic
v1→v16)Migration { version: 17 }+V17_SQL)src/components/import/src/utils/architecture.mdThe tables/indexes line is the one worth flagging: v17 is an
ALTER TABLEonly, so it adds neither. The counts were re-measured onconsolidated_schema.sqlrather than assumed to have moved with the migration, and the reason they did not is now written intoCLAUDE.mdso the next reader does not re-derive it.CLAUDE.md's tree also saidlib.rs # ... 7 migrations inline— not named in the issue, but it is the same fact as the migration count 60 lines below, so leaving it would have made the file contradict itself inside this very edit. Corrected.ADR 0018 was missing from
architecture.md's ADR table (the file exists, the row did not). Added alongside 0019.Deliberately not fixed — the rest of the count drift in
CLAUDE.mdMeasured while verifying: 120 components (documented 53), 27 hooks (13), 20 pages (11), 24 services (14), 6 Tauri command modules / 36 commands (3 / 17). All stale, none of it caused by this chantier. Rewriting that tree is a separate change and would bury the import edits in noise, so only the two numbers this chantier actually moved were touched. Flagged here so the measurement is not lost.
Changelog
Grouped by user-visible outcome, not one bullet per issue — a user reads "my amounts import correctly now", not nine internal refactors. #326 (fixtures) and #323 (migration) have no user-visible behaviour at all and get no bullet of their own; their numbers ride on the entries whose behaviour they enable, so nothing becomes untraceable. Added / Changed / Fixed; no Security section (no advisory here).
Parity between the two files was verified mechanically, not by eye: same sections, same bullet counts, and the same issue references in the same order, section by section — 5 Added / 2 Changed / 7 Fixed / 2 Security on both sides. The
public/copies sync viasyncChangelogs()invite.config.ts(they are gitignored; the build regenerated them and the new French text is present).Guide and
docs.*docs/guide-utilisateur.md§4 anddocs.import.*in both locales carry the same 9 features / 8 steps / 9 tips — the in-app guide renders from the JSON, the markdown is its printable twin, and divergence between them is the failure mode. Locale files were edited through a JSON round-trip proven byte-identical on the untouched files first, so the diff is 26 lines in each and nothing was reformatted.Two things a user needs to find in the guide rather than only in a toast: the
absolute_indicatorrefusal (the one case where the app now stops instead of importing) and the repair path (delete the faulty import, then replay — re-importing on top doubles the rows).Verification
npm test— 1176 passed (60 files), unchanged from link 9's baseline. Docs-only PR: it adds no test and must move none.npm run build— tsc + vite clean.cd src-tauri && cargo check— clean. No Rust touched, no DB migration (v1→v17 as link 2 left it).Generated autonomously by /autopilot run of 2026-08-13
Revue adversariale — PR #342 (maillon 10/10, documentation)
Verdict : APPROVE
Résumé
PR docs-only conforme : 8 fichiers, aucun fichier source ni test touché (les deux locales le sont, mais c'est le contrat — le guide in-app se rend depuis
docs.*). J'ai re-mesuré chaque compteur revendiqué contre l'arbre plutôt que de relire la table du corps de PR, résolu chaque lien de l'ADR, comparé les deux CHANGELOG mécaniquement, et sondé une vingtaine d'affirmations techniques contre le code du stack. Aucune n'est fausse. Rien de bloquant.Ce que j'ai re-mesuré moi-même
v1→v17)Migration { version: n }, v17 dernièresrc/components/import/src/utils/CREATE TABLE+ 24CREATE INDEXdansconsolidated_schema.sqlLe point le plus facile à rater est le bon : v17 ne contient que quatre
ALTER TABLE+ unUPDATE, donc laisser 20/24 est exact, et la justification écrite enCLAUDE.md:104est vérifiable par un lecteur futur au lieu d'être à re-dériver. La correction du « 7 migrations inline » de l'arbre (CLAUDE.md:84) supprime une contradiction interne réelle avec la ligne 60 lignes plus bas.FilePreviewModal.tsxsupprimé,FormatDriftPanel.tsx+RepairPathNotice.tsxajoutés → 13 − 1 + 2 = 14.lib.rs(le diffmain..HEADn'ajoute que v17 et des constantes de test).Liens de l'ADR
spec-decisions-import-csv-format.mdetspec-plan-import-csv-format.mdsont bien dansgit ls-treede la branche malgré.gitignore:71-72→ les deux liensSpec:résolvent, le précédent ADR 0016 / #295 ne se répète pas. Les trois autres liens de l'ADR (0003, 0004, 0017) existent, ainsi que les deux lignes ajoutées à la table des ADR dearchitecture.md(0018, 0019) ; la date 2026-07-27 portée à la ligne 0018 est celle de son propre en-tête.Parité CHANGELOG et i18n
#327+#328 | #329 | #330 | #331 | #259puis#323+#324+#328 | #297-#301puis#327 | #325 | #325 | #325 | #327 | #325+#327 | #331puis#310 | #311. Ordre Keep a Changelog respecté (Fixed avant Security).en.jsonetfr.jsonest vide (structures strictement identiques), 9 features / 8 steps / 9 tips dans chaque locale, etguide-utilisateur.md§4 porte 9/8/9 aussi. Le mode d'échec connu (divergence des compteurs entre le JSON et son jumeau imprimable) n'est pas présent.Fidélité de la prose au code (sondage)
mapRowcalcule biencrédit − débitsur magnitudes et n'échoue que si les deux colonnes sont illisibles — la doc dit « dans les deux colonnes », pas plus ;parseFrenchAmountest ancré (100,00 CAD→ NaN,(50,00)et50,00-→ −50) et oui, la doc énonce que ce cas produit désormais une ligne en erreur, dans les deux CHANGELOG et dansarchitecture.md; séparateur décimal arbitré par colonne ; garde!existing(useImportWizard.ts:503-508) ;file-previewest sur l'unique chemin avant (le seulSET_STEP → duplicate-checkpart decheckDuplicates, donc « traversée à chaque import » est exact, pas rhétorique) ; config écrite àexecuteImportseul ;flipSignFormatéchange les indices endebit_credit; sélecteur de convention masqué et non réinitialisé (SourceConfigPanel.tsx:358) ;header_signature= tableau JSON de libellés normalisés ;MIN_SIGNATURE_LABELS = 4,MIN_HEADER_ROLE_MATCHES = 2,CONFIDENCE_THRESHOLD = 0.9,SREF_FORMAT_VERSION = 2; modèles restaurés avant les sources, upsert par nom, remaptemplate_id, whitelistAMOUNT_MODES/SIGN_CONVENTIONS,withTransaction; 15 fixtures CSV, exactement celles énumérées ;VALUE_HEADER_KEYWORDScontient bienmontant(la raison invoquée pour séparerheaderDictionary.tsest réelle) ; « éditer le modèle n'altère aucune source liée » est un vrai test d'intégration.Le récit des trois voies de perte tient : la voie 1 de l'ADR correspond au code de
mainmot pour mot (amountMode: mapping.debitAmount !== undefined ? "debit_credit" : "single"puissignConvention: "negative_expense",useImportWizard.ts:321-323), la voie 2 est câblée dansbankSignatures.ts+FormatDriftPanel, la voie 3 dansdataExportService.ts.Blocages
Aucun.
Suggestions (aucune bloquante)
CHANGELOG.md:15/CHANGELOG.fr.md:15— classement de l'entrée #323/#324. C'est le correctif racine du chantier (une source réglée en dépenses positives revenait au défaut au 2e import → dépenses importées en revenus) et il est sousChanged/Modifié. Le bullet est mixte — nouveau modèle de persistance, sélecteur masqué, écriture différée — donc le choix se défend, mais le lecteur des notes de version qui cherche « mon bug de signes est-il réglé ? » ouvreFixeden premier. Option : scinder, la moitié « re-déduisait le mode / remettait silencieusement la convention sur négatif » sousFixed, le reste sousChanged.CHANGELOG.md:16/CHANGELOG.fr.md:16— une ligne vide a été insérée entre les deux bullets deChanged/Modifié, seule section où c'est le cas. Markdown en fait une liste loose (chaque item enveloppé dans un<p>), donc un rendu différent des autres sections sur/changelog. À retirer.docs/guide-utilisateur.md:493etdocs.settings.features— §11 énonce encore « Export des données (transactions, catégories, ou les deux) ». Depuis #331 l'enveloppe emporte aussi les sources et les modèles. L'information existe en §4 (astuce, ligne 133), mais l'utilisateur qui veut savoir ce que contient sa sauvegarde lit §11.docs/guide-utilisateur.md:124-137— le rejet d'un montant à suffixe est un changement visible pour l'utilisateur : une ligne qui passait sans bruit (à 10 000,00) échoue désormais. C'est dans les deux CHANGELOG et dansarchitecture.md, pas dans le guide, alors que le refusD/Cy est (ligne 130). Une astuce de plus suffirait.docs/architecture.md:29(58 composants → 127 hors tests),:44(14 pages → 25 fichiers),:45(14 services → 24 hors tests, alors que sa propre table en liste 17) ;CLAUDE.md:41,54,55,56,65; etCLAUDE.md:14« Version actuelle : 0.6.3 » alors que le dernier tag est v0.14.0. Rien de tout cela n'est causé par ce chantier et le corps de PR le mesure et le déclare — c'est le bon réflexe. Ouvrir une issue de suivi pour que la mesure ne se perde pas.mapRow: en mode débit/crédit, une cellule illisible d'un côté et un0,00lisible de l'autre donnent0 − 0 = 0, donc une transaction à 0,00 écrite en silence — le cas même que la doc décrit comme fermé, mais elle le décrit correctement (« illisible dans les deux colonnes »). C'est un angle mort résiduel de #325, pas un défaut de documentation.Non vérifiable sans muter l'arbre : l'ADR affirme que retirer
sign_conventiondeformatToRow« fait tomber 14 tests ». Le fichier porte 83 tests et le double mécanisme (FORMAT_FIELD_PAIRStypéRecord<keyof ImportFormat, …>+ test de comparaison des clés) est bien en place ; seul le chiffre exact reste sur parole.Mergée dans
mainen fast-forward avec le reste de la pile (tip37b832e).Forgejo ne détecte pas un merge local comme merged — la PR est donc fermée à la main, et l'issue liée s'est fermée automatiquement via son
Resolves #N.Tip cumulé validé avant push : 1181 vitest, 111 tests Rust, build tsc + vite. La CI ne tourne pas sur push
main, cette validation locale était donc le seul filet.Pull request closed