Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
11cf3c9
docs(25-4-c): story créée — le résiduel au rapprochement (refs #420)
guycorbaz Sep 27, 2026
1db610a
docs(25-4-c): arbitrages Q1–Q3 retenus par défaut, rebase sur la b2 (…
guycorbaz Sep 29, 2026
36f9ce3
docs(25-4-c): validation P1 — 3 HIGH, 2 MED, 1 LOW remédiés (refs #42…
guycorbaz Sep 29, 2026
4ba1d29
docs(25-4-c): validation P2 — 0 finding sans preuve, 2 MED repris par…
guycorbaz Sep 29, 2026
73ea2b0
docs(25-4-c): références de lignes du verrou recontrôlées (refs #420)
guycorbaz Sep 29, 2026
de2057a
docs(25-4-c): validation P3 consignée — 1 CRIT / 3 HIGH, découpage et…
guycorbaz Sep 29, 2026
5d74361
docs(25-4-c): découpée — verrou en 25-4-c2 (#480), arrondi en 25-4-c3…
guycorbaz Sep 29, 2026
08646df
docs(25-4-c): validation P4 — 1 MED, 1 LOW remédiés (refs #420)
guycorbaz Sep 29, 2026
7aa56d2
docs(25-4-c): validation P5 ciblée — close, 0 > LOW (refs #420)
guycorbaz Sep 29, 2026
63a6d6a
fix(25-4-c): le rapprochement reconnaît le solde d'une facture réglée…
guycorbaz Sep 30, 2026
8d33460
fix(25-4-c): revue de code P1 — CHANGELOG replacé, traductions univoq…
guycorbaz Sep 30, 2026
4c36ac9
docs(25-4-c): revue de code P2 — close, 0 > LOW ; story done (refs #420)
guycorbaz Sep 30, 2026
b90d0d2
docs(25-4-c2): story créée — l'invariant de version au règlement, et …
guycorbaz Sep 30, 2026
cc79287
docs(25-4-c2): validation P1 — 1 HIGH, 2 MED, 2 LOW remédiés (refs #480)
guycorbaz Sep 30, 2026
6810cd9
docs(25-4-c2): validation P2 — close, 0 > LOW (refs #480)
guycorbaz Sep 30, 2026
177135f
fix(25-4-c2): un règlement partiel marque la facture, et l'acceptatio…
guycorbaz Sep 30, 2026
b3a740a
fix(25-4-c2): revue de code P1 — gardes rows_affected, RELEASE SAVEPO…
guycorbaz Sep 30, 2026
3de67e6
docs(25-4-c2): revue de code P2 ciblée — close, 0 > LOW ; story done …
guycorbaz Sep 30, 2026
de7a340
merge main (#483 squashé, arbre identique à 4c36ac99) dans 25-4-c2
guycorbaz Sep 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ Le contenu est rédigé en français à destination des **fiduciaires, PME, ind

- **Le rapprochement bancaire ne reconnaissait pas le virement qui soldait une facture déjà réglée en partie ([#420](https://github.com/guycorbaz/kesh/issues/420)).** Une facture de 1 000.— TTC réglée de 400.— n'était même pas proposée pour un virement de 600.— — exactement ce que le client devait encore —, parce que la recherche comparait le montant d'origine : il fallait rapprocher à la main un paiement parfaitement identifiable. Le rapprochement cherche et note désormais les factures sur leur **reste dû** ; la proposition affiche ce reste, suivi du total d'origine (« 600, reste dû sur 1000 ») quand la facture est déjà réglée en partie. *(API : le champ `invoiceAmount` des propositions porte désormais le reste dû — identique au TTC tant que rien n'est réglé — et le nouveau champ `invoiceTotalTtc` le total d'origine, seulement quand les deux diffèrent.)* Le manuel décrit enfin le score tel qu'il est calculé — il annonçait un score gradué, un critère de date et des seuils de confiance qui n'existent pas.

- **Un rapprochement et un règlement manuel enregistrés au même moment pouvaient régler deux fois la même facture ([#480](https://github.com/guycorbaz/kesh/issues/480)).** Un règlement manuel **partiel** ne marquait pas la facture comme modifiée : une acceptation de rapprochement en cours, qui avait lu le reste dû juste avant, l'encaissait une seconde fois — une facture de 1 000.— finissait réglée 1 400.—, et le compte clients devenait créditeur sans que rien ne le signale. Chaque règlement marque désormais la facture, et l'acceptation qui arrive trop tard est refusée sans rien écrire (« la facture a changé ») : il suffit de relire les propositions. Un interblocage entre deux opérations simultanées, qui rendait une erreur interne, est maintenant rejoué par le serveur.

### Changed

- **Le bouton *Créer un avoir* s'affiche aussi sur une facture payée**, et c'est voulu. Il était masqué sur une facture payée mais pas sur une facture réglée en partie : l'écran ne couvrait que la moitié de la règle. Il reste désormais visible, et Kesh explique le refus dans le dialogue — comme le bouton *Dévalider*.
Expand Down
52 changes: 52 additions & 0 deletions _bmad-output/implementation-artifacts/25-4-c2-review-prompt-p1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Prompts — revue de code P1, Story 25-4-c2 (le verrou à l'acceptation)

*Versionné le 2026-09-30. Trois lentilles en parallèle, **Sonnet**, contexte frais. Diff : le commit
d'implémentation, `git diff 6810cd97 177135f2 -- . ':(exclude)_bmad-output'`, écrit dans
`/tmp/claude-1000/-home-gcorbaz-devel-kesh/379e6f94-8029-42cb-9720-fa27c2fb204c/scratchpad/25-4-c2-p1.diff`.*

## Commun aux trois lentilles

**Rendu** : findings avec sévérité (CRITICAL/HIGH/MEDIUM/LOW), endroit exact (`fichier:ligne`),
**preuve** (code lu cité, commande et sortie), correction proposée. ⛔ **La liste des axes réellement
exercés ET de ceux qui ne l'ont pas été** — un rapport sans elle ne compte pas.

**Interdits** : n'écrire aucun fichier du dépôt ; aucune commande qui écrit dans le dépôt ou dans une
base — `scripts/prepare-release.sh`, `scripts/regen-test-schema.sh`, `scripts/install-hooks.sh`,
`scripts/test-fast.sh`, `scripts/mem-guard.sh`, `make`, `latexmk`, tout `git commit`/`push`/`add`/
`stash`/`reset`/`rebase`/`checkout`/`switch`/`worktree`, `sqlx migrate`, `cargo test`/`nextest`,
`npm run`, `npx playwright`, `gh issue create`/`comment`/`edit`. Autorisés : lecture, `grep`,
`git log`/`show`/`diff`, `gh issue view`, `pdftotext` vers le scratchpad, `cargo check`.

## Lentille 1 — Blind Hunter (`bmad-review-adversarial-general`)

Reçoit **le diff seul**, aucun contexte projet. Revue adversariale générale.

## Lentille 2 — Edge Case Hunter (`bmad-review-edge-case-hunter`)

Diff **et** lecture du dépôt (MariaDB 10.11, REPEATABLE READ, `innodb_snapshot_isolation` OFF).
- `accept_batch` : chaque chemin où la transaction peut être annulée sous le lot — l'erreur remonte-t-elle
toujours en `TransactionAborted` ou en 1213 direct ? Et `RELEASE SAVEPOINT` après une proposition
réussie, `SAVEPOINT` suivant, `commit` ? Un 1205 (attente dépassée) est-il pris à tort pour un
interblocage ?
- `post_accept` / `accept_once` : le rejeu est-il sûr — effets hors transaction (audit, e-mails,
fichiers, métriques), `GET_LOCK` relâché puis repris, corps réutilisé ? Les validations et le
pré-vol faits une seule fois restent-ils valables à la tentative suivante ?
- `settle_invoice` : l'`UPDATE` inconditionnel (`paid_at` à `NULL` sur un partiel) peut-il effacer un
`paid_at` légitime ? `rows_affected` non vérifié — une facture non `validated` ?
- Les tests de course : montages réellement déterministes ? `LOCK TABLES` sur une connexion du pool
rendue au pool verrouillée si le test panique avant `UNLOCK TABLES` ? Le test d'interblocage : la
victime est-elle garantie ? Un test qui passerait à vide ?
- Inventaire : tout autre écrivain du reste dû ou du statut d'une facture validée qui n'incrémente pas
`version` (`grep -rn "UPDATE invoices\|invoice_settlements\|credit_note" crates/*/src`).

## Lentille 3 — Acceptance Auditor

Diff, fiche `_bmad-output/implementation-artifacts/25-4-c2-verrou-acceptation.md`, lecture du dépôt.
Chaque AC (1 à 7) contre le code ; « Ce qu'il ne faut pas faire » (aucun `FOR UPDATE`, pas d'élargissement
de `is_deadlock_error`, pas de classement par le texte, pas de `sleep`, pas de changement d'isolation) ;
le Dev Agent Record (affirme-t-il seulement ce qui a tourné ? décomptes recomptés depuis la source ?
la dérogation au montage de l'AC 5 est-elle justifiée ?). ⛔ **Le manuel** :
`docs/manual/fr/user-manual.tex` (règlement manuel, réconciliation) et `docs/api-external.md` —
l'entrée *Accepter des propositions de rapprochement* dit-elle vrai sur le code (codes, statuts,
champs) ? PDF aplati : `pdftotext docs/manual/fr/user-manual.pdf - | tr '\n' ' ' | tr -s ' '`. Le
CHANGELOG dit-il vrai ?
42 changes: 42 additions & 0 deletions _bmad-output/implementation-artifacts/25-4-c2-review-prompt-p2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Prompt — revue de code P2 ciblée, Story 25-4-c2 (le verrou à l'acceptation)

*Versionné le 2026-09-30. **Passe ciblée** (CLAUDE.md § « La passe ciblée ») : une lentille (Haiku 4.5),
contexte frais, braquée sur la remédiation P1 seule — `git show b3a740a8`, écrit dans
`/tmp/claude-1000/-home-gcorbaz-devel-kesh/379e6f94-8029-42cb-9720-fa27c2fb204c/scratchpad/25-4-c2-p2.diff`.
Dépôt `/home/gcorbaz/devel/kesh`, lecture seule. Fiche : `_bmad-output/implementation-artifacts/25-4-c2-verrou-acceptation.md`.*

## Axes — tous obligatoires

1. **Les gardes `rows_affected() != 1`** (`crates/kesh-db/src/repositories/invoice_settlements_write.rs`,
dans `settle_invoice` et `cancel_settlement_in_tx`) : lis les deux fonctions en entier dans le fichier
courant. Un chemin **légitime** peut-il rendre 0 ligne et désormais échouer à tort (facture `cancelled`
par un avoir, facture dont le règlement s'annule après avoir été créditée, `WHERE` sans garde de
statut dans l'annulation) ? Qui appelle `cancel_settlement_in_tx` (`grep -rn "cancel_settlement_in_tx" crates/`),
et chacun garantit-il la ligne ? Comment `DbError::Invariant` est-il rendu au client
(`crates/kesh-api/src/errors.rs`) ?
2. **`RELEASE SAVEPOINT`** dans `accept_batch` (`crates/kesh-api/src/routes/reconciliation.rs`) : la
nouvelle branche est-elle correcte ; l'erreur d'origine est-elle préservée ?
3. **`transaction_aborted_outside_accept`** : les trois sites l'appellent-ils, et `drop(tx_outer)` est-il
toujours fait **avant** ?
4. **Le test** : la connexion détachée (`.detach()`) — `&mut verrou` sur un `MySqlConnection`, les deux
requêtes passent-elles bien par elle ? Une connexion détachée non fermée explicitement bloque-t-elle
quoi que ce soit en fin de test ?
5. **`docs/api-external.md`** : la phrase ajoutée est-elle exacte sur le code (`500 INTERNAL_ERROR`,
« rien n'a été écrit ») ?

## Ce que tu rends

- **Findings** : sévérité, endroit exact, **preuve** : la commande exécutée **et sa sortie copiée**, ou
l'extrait de code lu avec son numéro de ligne dans le fichier courant. Pour toute affirmation qu'un
élément est absent, le `grep -rnF` qui le prouve. Un finding sans preuve ne sera pas retenu ; un
« 0 finding » sans preuve non plus.
- ⛔ **La liste des axes réellement exercés ET de ceux qui ne l'ont pas été.**

## Interdits

⛔ N'écris aucun fichier du dépôt ; aucune commande qui écrit dans le dépôt ou dans une base —
`scripts/prepare-release.sh`, `scripts/regen-test-schema.sh`, `scripts/install-hooks.sh`,
`scripts/test-fast.sh`, `scripts/mem-guard.sh`, `make`, `latexmk`, tout `git commit`/`push`/`add`/
`stash`/`reset`/`rebase`/`checkout`/`switch`/`worktree`, `sqlx migrate`, `cargo test`/`nextest`,
`npm run`, `npx playwright`, `gh issue create`/`comment`/`edit`. Autorisés : lecture, `grep`,
`git log`/`show`/`diff`, `gh issue view`, `cargo check`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Prompt — validation P1, Story 25-4-c2 (le verrou à l'acceptation)

*Versionné le 2026-09-30. **Une lentille** (Sonnet), contexte frais.*

Dépôt `/home/gcorbaz/devel/kesh`, branche `story/25-4-c2-verrou-acceptation` (empilée sur la 25-4-c,
PR #483). Fiche à valider : `_bmad-output/implementation-artifacts/25-4-c2-verrou-acceptation.md`.
Source des faits : `25-4-c-residuel-au-rapprochement.md` (Change Log, validation P3, findings F1–F3).
Issue : `gh issue view 480`. Règles : `CLAUDE.md`. Checklist : `.claude/skills/bmad-create-story/checklist.md`.

Le choix par défaut (rejeu inclus) est **retenu** : ne pas le contester, en contester la mise en œuvre.

## Axes — tous obligatoires

1. **Chaque référence `fichier:ligne`** existe et dit ce que la fiche affirme.
2. **L'inventaire des écrivains** — pars du symptôme, pas de la liste : tout ce qui change le reste dû
d'une facture client, c'est-à-dire `invoice_settlements`, les lignes de facture (`invoice_lines`),
les avoirs (`credit_notes`, `credit_note_lines`), le statut (`invoices.status`).
`grep -rn "invoice_settlements\|invoice_lines\|credit_note" crates/*/src --include=*.rs | grep -iE "insert|delete|update"`.
Chacun incrémente-t-il `invoices.version` dans la même transaction ? Un écrivain oublié qui
n'incrémente pas est au moins HIGH : il rouvre la course.
3. **Le raisonnement d'isolation** : sous REPEATABLE READ (MariaDB 10.11, `innodb_snapshot_isolation`
OFF), le verrou optimiste `UPDATE … WHERE version = ?` ferme-t-il réellement la course n° 1 une
fois l'invariant posé ? Cherche un contre-exemple : un ordre d'événements où l'acceptation lit un
reste périmé et où son `UPDATE` réussit quand même. Et `due_after` / `fully_settled`, calculés sur
l'instantané après l'insertion du règlement : peuvent-ils poser `paid_at` à tort quand le contrôle
de version a réussi ?
4. **Le rejeu (AC 4)** : l'affirmation « le 1213 remonte en 1305 au `ROLLBACK TO SAVEPOINT` » est-elle
exacte sur MariaDB 10.11 (lis la doc de MariaDB si tu peux ; sinon dis-le) ? Les autres chemins du
lot (`accept_one_split`, `accept_one_rule`) sont-ils touchés par la même reconnaissance ? Rejouer
un lot entier est-il sûr (effets hors transaction : audit, e-mails, fichiers) ? Le verrou
`GET_LOCK` est-il bien relâché puis repris entre deux tentatives ?
5. **Faisabilité des tests (AC 5)** : le montage proposé (verrou `fiscal_years` tenu par le test,
règlement concurrent daté dans un autre exercice) fonctionne-t-il vraiment ? L'acceptation
atteint-elle `find_open_covering_date` **après** la garde de trop-perçu ? Un règlement manuel
dans un autre exercice est-il permis par `settle_invoice` (date ≥ date de facture, exercice ouvert) ?
Un interblocage déterministe est-il montable ? Mutations tuables ?
6. **Effets de bord de l'invariant** : qui lit `invoices.version` d'une facture validée (frontend,
API, clés d'API, tests) et casserait si un règlement partiel l'incrémente ? La réponse de
`POST /invoices/{id}/settlements` porte-t-elle la facture relue après validation ?
7. **Le manuel et les textes** : `docs/manual/fr/user-manual.tex` (règlement manuel, réconciliation)
et `docs/api-external.md` — que promettent-ils sur la concurrence ou sur `version` ? PDF aplati
(`pdftotext docs/manual/fr/user-manual.pdf - | tr '\n' ' ' | tr -s ' '` vers
`/tmp/claude-1000/-home-gcorbaz-devel-kesh/379e6f94-8029-42cb-9720-fa27c2fb204c/scratchpad/`).
8. **Périmètre et cohérence** : AC ↔ tâches, modules recomptés ; la story laisse-t-elle un état pire
qu'aujourd'hui sur un point quelconque ?

## Ce que tu rends

- **Findings** : sévérité (CRITICAL/HIGH/MEDIUM/LOW), endroit exact, **preuve** (commande exécutée et
sa sortie, ou code lu cité), correction proposée.
- ⛔ **La liste des axes réellement exercés ET de ceux qui ne l'ont pas été.** Un rapport sans elle
ne compte pas.

## Interdits

⛔ N'écris aucun fichier du dépôt ; aucune commande qui écrit dans le dépôt ou dans une base —
`scripts/prepare-release.sh`, `scripts/regen-test-schema.sh`, `scripts/install-hooks.sh`,
`scripts/test-fast.sh`, `scripts/mem-guard.sh`, `make`, `latexmk`, tout `git commit`/`push`/`add`/
`stash`/`reset`/`rebase`/`checkout`/`switch`/`worktree`, `sqlx migrate`, `cargo test`/`nextest`,
`npm run`, `npx playwright`, `gh issue create`/`comment`/`edit`, toute requête d'écriture sur MariaDB.
Autorisés : lecture, `grep`, `git log`/`show`/`diff`, `gh issue view`, `pdftotext` vers le
scratchpad, `cargo check`, requêtes `SELECT`/`SHOW` en lecture seule.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Prompt — validation P2, Story 25-4-c2 (le verrou à l'acceptation)

*Versionné le 2026-09-30. **Une lentille** (Haiku 4.5), contexte frais.*

Dépôt `/home/gcorbaz/devel/kesh`, branche `story/25-4-c2-verrou-acceptation`. Fiche :
`_bmad-output/implementation-artifacts/25-4-c2-verrou-acceptation.md` — **lis le fichier dans son état
actuel**. Ce que la P1 a changé : `git show cc792871 -- _bmad-output/implementation-artifacts/25-4-c2-verrou-acceptation.md`
(contexte seulement ; les numéros de ligne font foi dans les fichiers courants, jamais dans le diff).
Règles : `CLAUDE.md`.

## Axes — tous obligatoires

1. **La remédiation P1** :
- AC 4 : une erreur typée dédiée posée par `accept_batch` quand `ROLLBACK TO SAVEPOINT` échoue —
est-ce réalisable dans `crates/kesh-reconciliation/src/errors.rs` (`ReconciliationError`) et le
`match` de la route (`crates/kesh-api/src/routes/reconciliation.rs`, autour de `lock_result`) ?
Ce `match` est-il exhaustif, et la nouvelle variante y aurait-elle un bras ? Le prédicat de
`retry_with` voit-il un `AppError` ou un `ReconciliationError` ? `with_account_lock`
(`crates/kesh-reconciliation/src/mutex.rs:66`) relâche-t-il `GET_LOCK` quand la closure échoue ?
- Les deux inventaires : `credit_notes.rs:283` et `:586`, `invoices.rs:1453` et `:1577` — lis-les.
Existe-t-il un autre écrivain du statut d'une facture validée ou de son avoir
(`grep -rn "UPDATE invoices SET" crates/*/src`) qui n'incrémente pas `version` ?
- AC 7 : la section `docs/api-external.md:287` et suivantes.
2. **Le contre-exemple** : cherche un ordre d'événements où, l'invariant posé, l'acceptation écrit un
règlement fondé sur un reste périmé **et** réussit son `UPDATE invoices … version = ?`.
3. **Cohérence interne** : AC ↔ tâches, « Ce qu'il ne faut pas faire », Change Log.

## Ce que tu rends

- **Findings** : sévérité, endroit exact, **preuve** : la commande exécutée **et sa sortie copiée**, ou
l'extrait de code lu avec son numéro de ligne. Pour toute affirmation qu'un élément est **absent**, le
`grep -rnF` qui le prouve et sa sortie. Un finding sans preuve ne sera pas retenu ; un « 0 finding »
sans preuve non plus.
- ⛔ **La liste des axes réellement exercés ET de ceux qui ne l'ont pas été.**

## Interdits

⛔ N'écris aucun fichier du dépôt ; aucune commande qui écrit dans le dépôt ou dans une base —
`scripts/prepare-release.sh`, `scripts/regen-test-schema.sh`, `scripts/install-hooks.sh`,
`scripts/test-fast.sh`, `scripts/mem-guard.sh`, `make`, `latexmk`, tout `git commit`/`push`/`add`/
`stash`/`reset`/`rebase`/`checkout`/`switch`/`worktree`, `sqlx migrate`, `cargo test`/`nextest`,
`npm run`, `npx playwright`, `gh issue create`/`comment`/`edit`. Autorisés : lecture, `grep`,
`git log`/`show`/`diff`, `gh issue view`, `cargo check`.
Loading
Loading