diff --git a/src/application/seance.js b/src/application/seance.js index 5c05e80..b975483 100644 --- a/src/application/seance.js +++ b/src/application/seance.js @@ -416,6 +416,19 @@ export function creerSeance({ } } + // La charge restituée, ses compteurs d'identifiants portés au plus grand + // de leur valeur restituée et de leur valeur courante : un retour rend le + // contenu d'un instant, jamais un identifiant déjà donné (§ 8.9) — une + // génération après un défaire numérote au-delà des propositions défaites, + // et le retenu d'un fil abandonné garde la proposition qu'il désignait. + function avecCompteursCourants(charge, courante) { + const prochainsIds = {}; + for (const cle of ['participant', 'table', 'proposition']) { + prochainsIds[cle] = Math.max(charge.prochainsIds[cle], courante.prochainsIds[cle]); + } + return { ...charge, prochainsIds }; + } + // Un retour, sans son suivi : défaire vise le prédécesseur de l'instant // courant sur le fil, refaire le sommet de sa pile, revenir l'instant // donné ; l'entrée porte la charge restituée, son sens et sa cible. @@ -431,7 +444,7 @@ export function creerSeance({ if (cibleRefaire === null) throw new ErreurSeance('RIEN_A_REFAIRE'); cible = cibleRefaire; } - const charge = restituer(ouvert, cible); + const charge = avecCompteursCourants(restituer(ouvert, cible), ouvert.charge); if (serialiserCharge(charge) === serialiserCharge(ouvert.charge)) throw new ErreurSeance('SANS_EFFET', { sens }); const instant = sens === 'defaire' ? courant : libelleDeRevision(ouvert.journal, cible); const entree = { charge, libelle: libelleDuRetour(sens, instant), avertissements: [] }; diff --git a/src/application/seance.test.js b/src/application/seance.test.js index 7a789dd..691fc52 100644 --- a/src/application/seance.test.js +++ b/src/application/seance.test.js @@ -641,8 +641,17 @@ describe('séance : revenir, défaire, refaire (§ 8.3)', () => { [7, 'revenir', 2, 'Retour à « Ajouté Ancolie »'], ], ); - assert.deepEqual(etatDe(fs).charge, reconstruire(journal, 2)); - assert.deepEqual(reconstruire(journal, 7), reconstruire(journal, 2)); + // L'instant 2 revient avec son contenu, et ses compteurs restent où trois + // ajouts les ont portés : aucun identifiant donné ne se redonne (§ 8.9). + const instant2 = reconstruire(journal, 2); + const attendu = { ...instant2, prochainsIds: { ...instant2.prochainsIds, participant: 4 } }; + assert.deepEqual(etatDe(fs).charge, attendu); + assert.deepEqual(reconstruire(journal, 7), attendu); + await seance.executer('ajouterParticipant', { champs: { nom: 'Digitale' } }); + assert.deepEqual( + seance.charge.participants.map(({ id, nom }) => [id, nom]), + [[1, 'Ancolie'], [4, 'Digitale']], + ); }); test("refaire n'existe qu'après des retours, tant qu'aucun geste ne les suit", async () => {