Verser les quatre séances en attente, du 3 au 7 août - #3
Merged
Conversation
`ingestion.yml` ne commite pas — un runner ne sait pas signer — et l'archive s'était arrêtée au 31 juillet pendant que les artefacts s'empilaient. C'est le retard qui obligeait à cliquer « Actualiser » pour voir le cours du jour. Quatre séances, et non trois : celle du 7 août est arrivée pendant le versement. 188 lignes, 47 sociétés cotant chacun des quatre jours. VERSÉ PAR `versement.yml`, PAS PAR L'ARTEFACT. Le stockage d'artefacts est injoignable depuis cet environnement — le CONNECT échoue au proxy, ce que cette action prévoit explicitement. Le runner a donc réémis l'incrément dans son journal, compressé et empreinté, et l'empreinte a été vérifiée avant écriture : sha256 7223a8765dc5571e, 189 lignes. Le versement se vérifie au lieu de se supposer. Le garde-fou du workflow a servi une fois de plus : 38 lignes de 2015-2017 ont été ÉCARTÉES car antérieures à l'archive versée. Ce sont les séances fantômes retirées le 29 juillet, que l'artefact du 28 porte encore ; les verser les aurait ressuscitées sans que rien ne le dise. Contrôles avant écriture : en-têtes identiques, aucune clé (date, ticker) déjà présente, aucune ligne antérieure à la dernière séance, tri préservé. Le diff est un ajout pur — 188 insertions, zéro suppression. Contrôles après : les 188 variations tiennent dans la limite réglementaire de ±7,5 %, deux exactement au plafond, aucune clôture nulle. `brvm veille` répond « L'archive avance ». 248 tests passent. CE QUI N'EST PAS VERSÉ, ET POURQUOI. Le référentiel accompagnait l'incrément dans le journal, mais sa ligne base64 est arrivée corrompue — gzip rejette le flux, alors que l'incrément cinq fois plus long est passé intact. Deux transcriptions indépendantes donnent le même résultat : ce n'est pas une erreur de lecture. `data/referentiel.csv` reste donc au 31 juillet pour `derniere_vue`. C'est une trace de provenance, lue nulle part ailleurs que dans `db.py` — aucun calcul n'en dépend. La déduire des cours aurait été possible, les 47 sociétés cotant chaque jour, mais cela aurait raté un renommage ou un reclassement sectoriel publié entre-temps : précisément ce que `fusionner_referentiel` existe pour signaler. Mieux vaut une date en retard qu'un reclassement effacé en silence. Le prochain versement dont le journal se relit entier la corrigera. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mu7CkW6727S9ZyRbiYyRk9
L'archive n'avançait pas toute seule : `ingestion.yml` déposait un artefact, et quelqu'un devait penser à le verser. Personne n'y a pensé pendant cinq séances, et c'est ce retard qui obligeait à cliquer « Actualiser » pour voir le cours du jour. `versement.yml` tourne désormais chaque jour ouvré à 16 h 45 UTC, trois quarts d'heure après la collecte, et écrit lui-même. POURQUOI UNE CLÉ POUR UN ROBOT. Le projet refusait qu'un runner commite parce qu'il ne sait pas signer, et qu'un historique à moitié vérifiable ne vaut guère mieux qu'un historique nu. L'objection portait sur la SIGNATURE, pas sur l'écriture : une clé propre au robot, déposée en secret de dépôt, la lève. Chaque versement reste « Verified », et l'auteur — « versement automatique » — dit qui a agi. La contrepartie, dite franchement dans le README plutôt que passée sous silence : une signature ne prouve plus qu'une personne tenait sa clé, seulement que le commit vient de ce dépôt. La distinction reste lisible, elle change de nature. Une autre voie a été essayée avant celle-ci et écartée sur mesure : un commit créé par l'API GitHub revient `unsigned`. Testé, pas supposé. LES MÊMES CONTRÔLES QU'À LA MAIN, PARCE QUE PERSONNE NE REGARDERA. En-têtes identiques, aucune ligne déjà présente, aucune séance antérieure à l'archive, tri préservé, et la limite de ±7,5 % par séance — un cours qui la franchit n'est pas une forte séance mais une lecture fausse ou une réduction du nominal, et dans les deux cas un humain doit voir. Un seul contrôle qui tombe annule le versement. Dix cas vérifiés en dehors du runner, dont les subtils : +7,5 % pile est accepté puisque c'est légal, deux séances consécutives sous la limite le sont aussi puisque le contrôle est par séance et non cumulé, et une clôture vide — valeur non cotée ce jour-là — ne déclenche rien. LE JOURNAL DEVIENT LE FILET. Il ne s'écrit plus que si rien n'a été poussé : secret absent, contrôle en échec, poussée refusée trois fois. C'est exactement ce qui a servi à rattraper les séances du 3 au 7 août quand le stockage d'artefacts était injoignable, et cette voie reste ouverte. Trois défauts corrigés avant d'être laissés en place : le référentiel était DÉPLACÉ vers data/, ce qui privait le filet de la moitié de ce qu'il doit émettre — il est copié ; le message de commit passait par la ligne de commande, où un accent grave dans un nom de société aurait été interprété par le shell — il passe par un fichier ; et la poussée n'était pas retentée si `main` avait bougé pendant le téléchargement des artefacts. L'installation de la clé demande quatre gestes, documentés dans le README. Sans eux le workflow ne pousse rien et retombe sur le journal : la donnée n'est jamais perdue, seulement l'automatisme. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mu7CkW6727S9ZyRbiYyRk9
DEUX CORRECTIONS, ET LA PREMIÈRE EST CELLE D'UNE ERREUR QUE JE VENAIS D'INTRODUIRE. Le versement automatique refusait d'écrire quand une variation franchit ±7,5 %. C'était en contradiction directe avec ce que le projet a mesuré et écrit dans `qualite.limites` : sur l'archive, ce contrôle lève 356 alertes dont l'immense majorité est légitime. Au détachement, le prix de référence est ajusté du dividende et une baisse de 9 à 13 % y est régulière ; la limite relie deux séances CONSÉCUTIVES et non deux blocs séparés d'un mois ; une division du nominal la franchit par construction. Pire : la saison des détachements va de mai à août. Le robot aurait donc refusé de verser dès sa première semaine de service, sur des données correctes — exactement le « contrôle qui crie sur des données correctes » que le projet refuse, parce qu'on apprend à l'ignorer et que le jour où il a raison personne ne l'écoute. Les dépassements sont désormais NOTÉS dans le journal, jamais opposés. `pics_isoles` serait la bonne signature, sans ambiguïté ; elle demande la séance SUIVANTE et ne s'applique donc pas à une séance fraîche. Le refus se limite à ce qui est certain : en-têtes, doublons, antériorité, tri, et clôture nulle ou négative — celle-là ne connaît pas d'exception. Un seuil de complétude a été envisagé puis écarté sur mesure : l'archive contient des séances à une seule valeur, héritées du rapatriement, et le seuil aurait crié dessus. LE SECOND ANGLE MORT DE LA VEILLE. `brvm veille` regardait la dernière séance et concluait « L'archive avance » — ce qui était vrai, et à côté de la question. Le 6 août 2026, l'ingestion a été annulée à mi-course : le 5 et le 7 sont en archive, le 6 n'y est pas, et rien ne l'a dit. Un retard finit par se combler ; un trou, jamais. La commande liste maintenant les jours ouvrés sans séance entre la première et la dernière : 22 sur onze ans et demi. Le message dit franchement que les fériés de la BRVM en font partie — leur calendrier n'est pas en base — plutôt que de taire un trou en croyant l'expliquer. Bornée à l'intervalle couvert : au-delà de la dernière séance c'est du retard, que l'autre moitié de la commande mesure déjà, et les compter deux fois ferait dire à la veille qu'une archive à jour d'hier est trouée. Douze cas de contrôle vérifiés hors du runner, dont les quatre qui changent de verdict : détachement à −9 % et division du nominal à −50 % sont désormais ACCEPTÉS, clôture nulle et négative refusées. Quatre tests pour la détection de trous, dont les négatifs qui comptent le plus : un week-end n'est pas un trou, du retard non plus. 252 tests passent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mu7CkW6727S9ZyRbiYyRk9
Le versement ne retenait que les séances POSTÉRIEURES à l'archive. Ce garde-fou empêche de ressusciter les 38 lignes fantômes retirées le 29 juillet — il a servi dès le premier passage — mais il refusait du même geste toute reprise de trou : une séance manquée est antérieure par définition. Le 6 août 2026 était donc irrattrapable par cette voie. CE QUI SÉPARE LES DEUX CAS SE LIT DANS L'ARCHIVE ELLE-MÊME, et il a fallu le vérifier avant de le croire. Une ligne retirée l'a été d'une date qui existe toujours : le 09/02/2015 garde 22 lignes, le 25/12/2017 en garde 30, le 04/01/2016 en garde 23. Un trou, lui, est une date ENTIÈREMENT absente — le 06/08/2026 en compte zéro. La règle tient en une phrase : on verse ce qui est postérieur, et ce qui comble une date dont l'archive ne sait rien ; jamais une ligne qu'elle a écartée d'une date qu'elle connaît. DEUX SOURCES D'ARTEFACTS. Le versement relit désormais aussi les exécutions de `rapatriement.yml`, qui dépose le même `archive-<run_id>`. C'est ce qui rend un trou rattrapable sans intervention : `brvm rapatrier` relit la période, et le versement suivant la reprend. Le référentiel, lui, ne se prend QUE de l'ingestion : le rapatriement lit un historique valeur par valeur et ne rafraîchit pas la liste des cotées. Retenir le sien ferait reculer `derniere_vue` pour tout le monde. UNE GARANTIE CHANGE DE NATURE. « L'incrément s'ajoute en queue » cesse d'être vraie dès qu'on insère au milieu. Ce qui doit rester vrai, et qui est désormais vérifié : la fusion est triée, elle ne perd aucune ligne de l'archive, et elle en compte exactement autant qu'avant plus l'incrément — donc elle n'en invente ni n'en écrase. Treize cas vérifiés hors du runner, dont les deux qui décident : une date entièrement absente se comble, une ligne antérieure sur une date présente reste refusée. Le harnais a été réécrit plutôt que rapiécé — un premier remplacement en gros avait réécrit les fixtures elles-mêmes et fait rougir huit cas pour rien. 252 tests passent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mu7CkW6727S9ZyRbiYyRk9
`secrets` n'existe pas dans un `if` d'étape. GitHub ne rejette pas l'étape : il refuse le FICHIER, et le workflow ne démarre jamais. Tel que commité, le versement automatique n'aurait pas tourné une seule fois — le défaut est apparu au premier lancement réel, pas à la relecture ni au contrôle YAML, qui tous deux le trouvaient valide. La présence de la clé se lit désormais dans l'`env` du job, où le contexte est autorisé, et voyage ensuite comme une variable ordinaire. Le booléen y arrive en chaîne : c'est « true » qu'on compare. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mu7CkW6727S9ZyRbiYyRk9
La séance manquait depuis que l'ingestion du 6 août a été annulée à mi-course. 47 valeurs, insérées entre le 5 et le 7 — première écriture au MILIEU de l'archive, et non en queue. RÉCUPÉRÉE DE BOUT EN BOUT PAR LA CHAÎNE ELLE-MÊME, ce qui la teste autant qu'elle la répare : `rapatriement.yml` a relu la séance chez la source et déposé son artefact ; `versement.yml`, lancé depuis la branche, l'a reconnue comme un trou — date entièrement absente — et l'a versée dans son espace de travail ; faute de clé, il a sauté la poussée et émis l'incrément dans le journal, exactement comme le filet doit le faire. Empreinte vérifiée avant écriture : sha256 2153ca4fef8e5ab2, 48 lignes. Les mêmes contrôles qu'à la main : en-têtes identiques, aucune ligne déjà présente, aucune ligne antérieure sur une séance connue, clôtures positives, fusion triée sans perte ni doublon. Les 47 variations tiennent dans la limite du marché — de −6,42 % à +7,50 % — et `brvm veille` ne compte plus que 21 trous au lieu de 22, tous antérieurs à 2026 et vraisemblablement des fériés. Le rapatriement renseigne `haut` et `bas`, que l'ingestion laisse vides : l'API d'historique les publie, la page de cote non. Une séance rapatriée est donc un peu plus riche que ses voisines, jamais plus pauvre. 252 tests passent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mu7CkW6727S9ZyRbiYyRk9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
L'archive s'était arrêtée au 31 juillet pendant que les artefacts s'empilaient —
c'est ce retard qui obligeait à cliquer « Actualiser » pour voir le cours du jour.
Quatre séances, et non trois : celle du 7 août est arrivée pendant le
versement. 188 lignes, 47 sociétés cotant chacun des quatre jours.
Versé par
versement.yml, pas par l'artefactLe stockage d'artefacts est injoignable depuis cet environnement — le CONNECT
échoue au proxy, ce que cette action prévoit explicitement. Le runner a donc
réémis l'incrément dans son journal, compressé et empreinté, et l'empreinte a
été vérifiée avant écriture :
sha256 7223a8765dc5571e, 189 lignes. Leversement se vérifie au lieu de se supposer.
Le garde-fou du workflow a servi une fois de plus : 38 lignes de 2015-2017 ont
été écartées car antérieures à l'archive versée. Ce sont les séances fantômes
retirées le 29 juillet, que l'artefact du 28 porte encore ; les verser les aurait
ressuscitées sans que rien ne le dise.
Contrôles
Avant écriture : en-têtes identiques, aucune clé
(date, ticker)déjà présente,aucune ligne antérieure à la dernière séance, tri préservé. Le diff est un ajout
pur — 188 insertions, zéro suppression.
Après écriture :
exactement au plafond, aucune clôture nulle ;
brvm veillerépond « L'archive avance » ;brvm importercharge les 113 101 lignes sans erreur ;Ce qui n'est PAS versé, et pourquoi
Le référentiel accompagnait l'incrément dans le journal, mais sa ligne base64
est arrivée corrompue — gzip rejette le flux, alors que l'incrément cinq fois
plus long est passé intact. Deux transcriptions indépendantes donnent le même
résultat : ce n'est pas une erreur de lecture de ma part.
data/referentiel.csvreste donc au 31 juillet pourderniere_vue. C'est unetrace de provenance, lue nulle part ailleurs que dans
db.py— aucun calcul n'endépend.
La déduire des cours aurait été possible, les 47 sociétés cotant chaque jour,
mais cela aurait raté un renommage ou un reclassement sectoriel publié entre
le 31 juillet et le 7 août : précisément ce que
fusionner_referentielexistepour signaler. Mieux vaut une date en retard qu'un reclassement effacé en
silence. Le prochain versement dont le journal se relit entier la corrigera.
Generated by Claude Code