Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
6835bc3
docs(15-7b1): T0 du développement — partition du registre recomptée (…
guycorbaz Oct 9, 2026
6ddbcd7
feat(15-7b1): seed-demo inscrit installation.demo_seeded puis l'étape…
guycorbaz Oct 9, 2026
c898e83
docs(15-7b1): doc-comments rendus faux par la story — enveloppes pool…
guycorbaz Oct 9, 2026
5902574
docs(15-7b1): manuels et CHANGELOG — le chargement de la démonstratio…
guycorbaz Oct 9, 2026
67523ba
docs(15-7b1): Dev Agent Record — gates réels, mutations, statut revie…
guycorbaz Oct 9, 2026
46c02f6
docs(15-7b1): prompt versionné de la revue de code P1 (Sonnet) (refs …
guycorbaz Oct 9, 2026
3ce0970
fix(15-7b1): revue P1 — garde sous verrou et 400 de seed_demo prouvés…
guycorbaz Oct 9, 2026
eb79e5e
docs(15-7b1): prompt versionné de la revue P2 ciblée (Haiku) (refs #434)
guycorbaz Oct 9, 2026
9064772
docs(15-7b1): clôture — revue de code close (P1 1 MEDIUM → P2 ciblée …
guycorbaz Oct 9, 2026
8429bc9
docs(15-7b1): PDF des manuels régénérés après le rebase sur f8b2accd …
guycorbaz Oct 9, 2026
5e2fe94
docs(15-7b1): clôture sur l'état rebasé (f8b2accd, 15-6b) — gates com…
guycorbaz Oct 9, 2026
62ee504
docs(15-7b1): PDF des manuels régénérés après le rebase sur dc4bc58b …
guycorbaz Oct 9, 2026
b007eaa
docs(15-7b1): clôture sur l'état final (dc4bc58b, 15-12b) — gates com…
guycorbaz Oct 9, 2026
abd72a0
docs(15-7b1): PDF des manuels régénérés après le rebase sur bcded0c8 …
guycorbaz Oct 9, 2026
d9139f9
docs(15-7b1): clôture sur l'état final (bcded0c8, 15-13a) — gates com…
guycorbaz Oct 9, 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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ Le contenu est rédigé en français à destination des **fiduciaires, PME, ind

- **Les exercices se clôturent dans l'ordre : un bilan clos ne change plus en silence ([#543](https://github.com/guycorbaz/kesh/issues/543)).** Le bilan est cumulatif depuis l'origine : toute écriture d'un exercice figure dans le bilan des suivants. Or on pouvait clôturer un exercice en laissant ouvert un exercice antérieur — ou créer un exercice antérieur à un exercice clôturé —, puis écrire dans cet exercice ouvert : le bilan clos changeait sans que rien ne le signale. **La clôture est désormais refusée tant qu'un exercice antérieur est ouvert** : à l'écran, le bouton **Clôturer** est désactivé et son infobulle nomme l'exercice à clôturer d'abord. **La création d'un exercice est refusée** si un exercice postérieur est déjà clôturé. Avec la réouverture, qui allait déjà du plus récent vers l'ancien, aucun exercice ouvert ne peut plus précéder un exercice clôturé **à partir d'une installation saine**. Le refus de modifier ou de supprimer une écriture sous un exercice postérieur clos dit maintenant comment s'en sortir — rouvrir les exercices clôturés **en commençant par le plus récent**, et non celui qu'il nomme, que la réouverture refuserait. ⚠️ Une installation mise à jour ou une sauvegarde restaurée peut porter cet état, hérité d'une version antérieure. **Plus rien ne s'enregistre alors dans l'exercice ouvert concerné** : ni saisie, ni validation, règlement, solde ou dévalidation d'une facture, ni avoir, facture fournisseur, paiement, lot de paiement, soldes de départ ou rapprochement — chacun de ces gestes changerait le bilan clos ; le refus nomme l'exercice clôturé. Une contre-passation — et donc toute annulation, qui en porte une — est datée **du jour** : elle reste possible, et n'est refusée que si l'exercice du jour est lui-même suivi d'un exercice clôturé. **L'écran *Exercices comptables* signale l'état** par un bandeau, visible de tous les rôles, qui dit comment rétablir l'ordre : clôturer l'exercice ouvert le plus ancien si ses comptes sont arrêtés, puis les suivants ; sinon, faire rouvrir les exercices clôturés **en commençant par le plus récent**. L'import accepte toujours une telle sauvegarde. ⚠️ **Limites** : l'écran des soldes de départ et les annulations de règlement ou de rapprochement annoncent le geste possible et le refus ne vient qu'au clic ([#568](https://github.com/guycorbaz/kesh/issues/568)). *(API : `400 LATER_FISCAL_YEAR_CLOSED` sur toute route qui écrit au journal, `details.fiscalYearId` / `fiscalYearName` ; dans `failed[]` de `POST /reconciliation/accept`, sans bloquer le reste du lot. Le message de ce refus couvre désormais la saisie.)*

- **La configuration d'une installation de production s'inscrit au journal d'audit ([#434](https://github.com/guycorbaz/kesh/issues/434)).** Chaque étape de l'assistant — langue, mode d'utilisation, passage en production, type d'organisation, langue comptable, coordonnées, compte bancaire (ou son omission) et finalisation — laisse une entrée *Étape d'installation franchie*, précédée de ce qu'elle a réellement changé : la société créée ou modifiée, le compte bancaire (sans jamais l'IBAN en clair), les réglages de facturation et les taux de TVA effectivement insérés. Le plan comptable livré s'inscrit en **une seule** entrée, *Plan comptable chargé*, qui liste les comptes créés. Quatre actions nouvelles sont libellées dans les quatre langues. Une étape ne laisse plus la société modifiée à moitié : la modification, la progression de l'étape et leur trace sont désormais **une seule transaction**, et l'étape est revérifiée sous verrou — deux demandes simultanées ne chargent plus le plan comptable deux fois. *Le perdant d'une telle course reçoit désormais « étape déjà franchie » au lieu d'un conflit de version.* *La version de la société (`version`, lue par le verrou optimiste de `PUT /company`) n'avance plus lorsqu'une étape ne change rien ; sur une société provisoire dont les coordonnées changent, elle avance désormais de deux.* Le peuplement de démonstration et la remise à zéro restent à tracer (même issue).
- **La configuration d'une installation de production s'inscrit au journal d'audit ([#434](https://github.com/guycorbaz/kesh/issues/434)).** Chaque étape de l'assistant — langue, mode d'utilisation, passage en production, type d'organisation, langue comptable, coordonnées, compte bancaire (ou son omission) et finalisation — laisse une entrée *Étape d'installation franchie*, précédée de ce qu'elle a réellement changé : la société créée ou modifiée, le compte bancaire (sans jamais l'IBAN en clair), les réglages de facturation et les taux de TVA effectivement insérés. Le plan comptable livré s'inscrit en **une seule** entrée, *Plan comptable chargé*, qui liste les comptes créés. Quatre actions nouvelles sont libellées dans les quatre langues. Une étape ne laisse plus la société modifiée à moitié : la modification, la progression de l'étape et leur trace sont désormais **une seule transaction**, et l'étape est revérifiée sous verrou — deux demandes simultanées ne chargent plus le plan comptable deux fois. *Le perdant d'une telle course reçoit désormais « étape déjà franchie » au lieu d'un conflit de version.* *La version de la société (`version`, lue par le verrou optimiste de `PUT /company`) n'avance plus lorsqu'une étape ne change rien ; sur une société provisoire dont les coordonnées changent, elle avance désormais de deux.* Le chargement de la démonstration est tracé lui aussi (entrée suivante) ; la remise à zéro reste à tracer (même issue).
- **Le chargement des données de démonstration s'inscrit au journal d'audit, en une entrée de synthèse ([#434](https://github.com/guycorbaz/kesh/issues/434)).** *Données de démonstration chargées* (type *Installation*), suivie de l'étape franchie, attribuée à son auteur — jeton d'API compris — et dont le détail donne la société, le nombre de comptes créés, l'exercice, le nombre de taux de TVA créés et si les réglages de facturation l'ont été. Elle est écrite dans la même transaction que la levée du drapeau « société provisoire », les réglages de facturation, les taux de TVA et l'étape : si l'une échoue, aucune n'est écrite, et la transaction est rejouée sur interblocage. *Le drapeau provisoire n'est plus levé que sur la société de démonstration, et sa version avance.* ⚠️ Limite connue, suivie par [#538](https://github.com/guycorbaz/kesh/issues/538) : le renommage de la société, le plan comptable et l'exercice sont commités avant cette transaction ; un chargement interrompu les laisse sans entrée, et un nouveau chargement échoue jusqu'à une réinitialisation ; un chargement refusé parce que la configuration de production a franchi l'étape entre-temps les laisse de même, sur l'installation de production. Le manuel utilisateur ne promet plus de contacts, de produits ni d'écritures d'exemple que la démonstration n'a jamais créés, et décrit la sortie de la démonstration par la réinitialisation ([#544](https://github.com/guycorbaz/kesh/issues/544)).

- **Un règlement ne peut plus viser le compte qu'il solde ([#474](https://github.com/guycorbaz/kesh/issues/474)).** Régler une facture client par le compte débiteurs lui-même — en compte interne, ou par un compte bancaire lié à ce compte — écrivait `D 1100 / C 1100` : l'écriture s'équilibrait, le reste dû baissait, la facture pouvait passer « payée », et le grand livre ne bougeait pas. Il en allait de même d'une facture fournisseur réglée par le compte créanciers (`D 2000 / C 2000`), y compris par un lot de paiement, et d'un encaissement par rapprochement quand le compte bancaire était lié au compte débiteurs. Ces règlements sont désormais **refusés sans rien écrire** (`SETTLEMENT_COUNTERPARTY_IS_CLAIM_ACCOUNT`), avec un message qui dit le remède. Les écrans de règlement ne proposent plus ces comptes, ni les comptes bancaires qui y sont liés. Une facture dont le compte créanciers est le compte de banque du lot n'entre plus dans un lot de paiement (elle apparaît parmi les refus, et le fichier pain.001 ne la porte pas) ; si le compte bancaire a été relié depuis la création du lot, la confirmation est refusée et le message dit les deux issues — relier de nouveau le compte bancaire puis confirmer, ou annuler le lot. Les comptes d'écart du même geste sont gardés de même : le compte de différences d'arrondi d'un règlement ou d'un rapprochement, et les comptes de nature, de reste d'arrondi et de TVA due d'un solde du reste ne peuvent pas être le compte débiteurs de la facture (cas d'un compte débiteurs changé de type, puis désigné dans les réglages) — un administrateur doit alors en désigner un autre dans *Paramètres → Facturation*. Les règlements de cette forme déjà enregistrés restent tels quels.

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ d'avant découpage se lit au commit `cabda169`.
| **15-7a1** | `15-7a1-socle-transactions-onboarding.md` | Le **socle** `kesh-db`, sans changement de comportement ni d'audit : variantes `_in_tx` (`accounts`, `bank_accounts`, `company_invoice_settings` — fin du MIRROR —, `vat_rates` ligne à ligne), `companies::clear_stub_in_tx`, `onboarding::lock_state_in_tx` | `refs #434` |
| **15-7a2** | `15-7a2-trace-installation-production.md` | Les **neuf routes de production** (`language`, `mode`, `start-production`, `org-type`, `accounting-language`, `coordinates`, `bank-account`, `skip-bank`, `finalize`) : une transaction par route, `lock_state_at_step`, `installation.step_completed` par un helper unique, entrées de domaine (dont `account.chart_loaded` agrégée et `company_invoice_settings.created`), quatre actions et leurs libellés, registre (94 → 103 tracées), manuel | `refs #434` |
| **15-7b** | `15-7b-trace-demo-et-remise-a-zero.md` | **découpée à la P4** (C-15-7-31) en 15-7b1 (Volet A) + 15-7b2 (Volet B) — corps vidé, pointeurs seuls | — |
| **15-7b1** | `15-7b1-trace-demonstration.md` | **`seed-demo`** : `installation.demo_seeded` puis l'étape dans la dernière transaction du peuplement, acteur threadé, dernière transaction rejouée sur interblocage ; une action, registre (103 → 104), manuel — dont le § *Chemin A* qui décrivait une démonstration inexistante (#544) | `refs #434` ; `closes #544` |
| **15-7b2** | `15-7b2-remise-a-zero.md` | **`reset`** : remise à zéro en **une** transaction rejouée sur interblocage, connexion fermée à la libération, trois gardes sous son verrou, `installation.reset` en dernier ; **identité de la société préservée** ; **une règle et une fonction pour les principaux orphelins** (`reattach_orphan_principals_in_tx` : utilisateurs rattachés, clés d'API actives orphelines **révoquées puis** repointées — C-15-7-45), y compris sur une base déjà sans société (la **cause** de #528) ; vidage **dérivé de la liste canonique**, partition gardée sur le schéma par trois règles (#279) ; une action, registre (104 → 105), manuel — dont la sortie de la démonstration, qui exige `KESH_PRODUCTION_RESET` (C-15-7-48) ; **bootstrap** : une société provisoire seulement sur base sans société (la **cause** de #542) | `closes #434`, `closes #279` ; `refs #528`, `refs #542`, `refs #540`, `refs #538`, `refs #534` |
| **15-7b1** | `15-7b1-trace-demonstration.md` | **`seed-demo`** : `installation.demo_seeded` puis l'étape dans la dernière transaction du peuplement, acteur threadé, dernière transaction rejouée sur interblocage ; une action, registre (104 → 105, recompté au T0 de la 15-7b1), manuel — dont le § *Chemin A* qui décrivait une démonstration inexistante (#544) | `refs #434` ; `closes #544` |
| **15-7b2** | `15-7b2-remise-a-zero.md` | **`reset`** : remise à zéro en **une** transaction rejouée sur interblocage, connexion fermée à la libération, trois gardes sous son verrou, `installation.reset` en dernier ; **identité de la société préservée** ; **une règle et une fonction pour les principaux orphelins** (`reattach_orphan_principals_in_tx` : utilisateurs rattachés, clés d'API actives orphelines **révoquées puis** repointées — C-15-7-45), y compris sur une base déjà sans société (la **cause** de #528) ; vidage **dérivé de la liste canonique**, partition gardée sur le schéma par trois règles (#279) ; une action, registre (105 → 106, recompté au T0 de la 15-7b1), manuel — dont la sortie de la démonstration, qui exige `KESH_PRODUCTION_RESET` (C-15-7-48) ; **bootstrap** : une société provisoire seulement sur base sans société (la **cause** de #542) | `closes #434`, `closes #279` ; `refs #528`, `refs #542`, `refs #540`, `refs #538`, `refs #534` |
| **15-7b3** | `15-7b3-reparation-des-installations-atteintes.md` | **Réparation des installations déjà atteintes par #528 et #542**, née de la P3 de la 15-7b2 (C-15-7-40) : `repair_installation_in_tx`, au **démarrage** (non bloquante en cas d'échec, C-15-7-47) et dans la transaction de **restauration** d'une sauvegarde ; principaux orphelins par la fonction de la 15-7b2 (clés révoquées quel que soit le nombre de sociétés, C-15-7-45) ; sociétés provisoires superflues supprimées au démarrage (C-15-7-46) ; entrée `installation.repaired` ; une action, manuels, `docs/api-external.md`, CHANGELOG | `closes #528`, `closes #542` ; `refs #546` |

⚠️ **L'ordre n'est pas indifférent** : 15-7a1 → 15-7a2 → 15-7b1 → 15-7b2 → 15-7b3, chacune après le merge de la
Expand Down
37 changes: 37 additions & 0 deletions _bmad-output/implementation-artifacts/15-7b1-review-prompt-p1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Prompt — revue de code P1, Story 15-7b1

*Versionné le 2026-10-09. Trois lentilles (Sonnet), contexte frais chacune, en lecture seule (bmad-code-review :
Blind Hunter, Edge Case Hunter, Acceptance Auditor). Rotation D6 : passes complètes Sonnet ↔ Opus ; Haiku en passe ciblée.*

Worktree `/home/gcorbaz/devel/kesh-15-7b1`, branche `story/15-7b1-trace-demonstration`. **Le diff à revoir** : `git -C /home/gcorbaz/devel/kesh-15-7b1 diff 200f5e79..87ababd4` (un seul diff aplati ; le code,
les tests, les manuels, la doc — les fiches `_bmad-output/` sont le contexte, pas l'objet). **Fiche** :
`_bmad-output/implementation-artifacts/15-7b1-trace-demonstration.md` (AC, tâches, Dev Agent Record, Change Log). Issues (par
`gh api repos/guycorbaz/kesh/issues/N`) : #434, #544 (#538 pour le contexte). Registre : `epic-15-choix-autonomes.md`. Règles : `CLAUDE.md`. Choix C-15-7-*, C-15-7b1-1. Code touché : kesh-seed (SeedAttemptError, is_seed_retryable, acteur (user_id, api_key_id), dernière transaction sous retry_with : verrou d'état, clear_stub_in_tx, réglages puis taux, étape, installation.demo_seeded), handler seed-demo (400 sur StepAlreadyCompleted, UPDATE is_stub et lecture de ui_mode retirés), registre 105/5/2, une action et ses 4 libellés, helper create_key_via_http remonté dans tests/common, manuels FR et PDF, CHANGELOG. Axes : la dernière transaction est-elle vraiment atomique et rejouable (rien lu ou écrit hors transaction, booléens relus à chaque tentative) ; ui_mode lu hors verrou (mutation déclarée non couverte : est-ce acceptable ?) ; l'audit for_actor pour une clé d'API ; le refactor du helper de test ne change-t-il le sens d'aucun test d'api_keys_e2e ; la partition du registre recomptée ; la sortie de démonstration au manuel (KESH_PRODUCTION_RESET) ; PDF aplati.

## Lentilles

- **B — Blind Hunter** : le diff seul, sans la fiche. Défauts de correction, régressions, erreurs de concurrence
(verrous, REPEATABLE READ, ordre d'acquisition), erreurs rendues au client, tests qui passeraient à vide (un test qui
ne mord pas sur la mutation qu'il prétend couvrir), code mort, duplication (DRY), doc-comments devenus faux.
- **E — Edge Case Hunter** : chaque branche et chaque borne du code modifié — entrées vides, nulles, multiples, en
doublon, d'une autre société, archivées ; chemins par clé d'API ; lots partiellement en échec ; locales ; et les
**chemins NON modifiés qui devraient l'être** (inventorier les sites non résolus de la même famille par `grep`).
- **A — Acceptance Auditor** : chaque AC de la fiche contre le code ET les tests (un AC sans test qui le prouve est
un finding) ; le Dev Agent Record ne déclare-t-il que ce qui a tourné (chiffres recomptés : `grep -c '#\[sqlx::test\]\|#\[test\]\|#\[tokio::test\]'` aux deux bornes) ;
le **manuel** (`docs/manual/fr/*.tex` **et PDF aplatis** : `pdftotext -nopgbrk f.pdf - | tr '\n' ' ' | tr -s ' '` vers
`target/gate-logs/`, ligatures ff/fi/fl normalisées), `docs/api-external.md`, CHANGELOG, i18n 4 locales.

## Ce que tu rends

Rapport complet dans `target/gate-logs/15-7b1-review-p1-<B|E|A>.md` : findings numérotés, sévérité
(CRITICAL/HIGH/MEDIUM/LOW), `fichier:ligne`, **preuve** (sortie de `grep -nF` pour toute affirmation de présence ou
d'absence ; code cité relu), correction proposée ; ⛔ **axes exercés ET non exercés**. Dernier message : le chemin, le
bilan par sévérité, une ligne par MEDIUM+.

## Interdits

⛔ N'écris aucun fichier hors `target/gate-logs/`. Aucune commande qui écrit dans le dépôt ou dans une base, ni
aucune commande qui compile ou exécute des tests : `scripts/*` (dont `scripts/prepare-release.sh`), `make`,
`latexmk`, `git commit`/`add`/`checkout`/`stash`/`apply`, `sqlx`, `cargo`, `npm`, `npx`,
`gh issue create`/`comment`/`edit`, SQL d'écriture. Autorisés : lecture, `grep`, `sed -n`, `git log`/`show`/`diff`,
`gh api` en lecture, `pdftotext` vers `target/gate-logs/`.
Loading
Loading