Repository navigation
coordination(gpu-reservation): le spool ne rejoint jamais le dashboard -- 43 observations en attente, et check_pending rend un verdict perime #22456
Description
Part of #16737
Constat mesuré (2026-10-25, myia-ai-01)
Le ledger gpu-reservation ne voit pas les réservations qu'il est censé arbitrer. Trois mesures, toutes reproductibles :
$ python scripts/coordination/debt_ledger.py check_pending --entity "myia-ai-01#gpu2"
RELEASED myia-ai-01#gpu2 last state=released at 2026-10-22T03:19:37Z
$ python scripts/coordination/debt_ledger.py spool --status
issue-debt: pending=0 oldest=-
gpu-reservation: pending=43 oldest=2026-10-08T11:27:53Z
Au même instant, deux réservations held vivantes sur myia-ai-01#gpu2 : celle de myia-ai-01:CoursIA posée sur le dashboard à 04:44Z (run ODM po-2024, #20386) et la mienne à 05:04Z (ICT-25a Np, #5105). La garde a répondu « device libre » aux deux.
Les deux défauts, distincts
D1 — personne ne draine le spool. debt_ledger.py append construit une enveloppe [OBS] et l'écrit dans l'outbox local ; les observations voyagent, par conception, comme messages append-only sur le dashboard CoursIA-gpu-reservation-ledger. Aucun organe ne fait ce transport. Résultat : 43 observations dorment depuis le 2026-10-08, dont au moins deux held du jour. Le contrat est écrit, le geste ne l'est pas.
Conséquence opérationnelle : check_pending ne lit que l'état réduit localement, donc il rend un verdict périmé avec l'aplomb d'un verdict frais. Une lane qui lui fait confiance lance sur un device déjà réservé — c'est arrivé aujourd'hui, et c'est exactement la collision que la Phase 3bis de docs/coordination/gpu-reservation.md veut empêcher.
D2 — started_at est l'heure locale étiquetée UTC. L'enveloppe obs-835b0fce1a455833 porte started_at=2026-10-25T06:03:58Z et expected_end=07:03:58Z pour un run réellement lancé à 05:04:03Z (mesure : ls --time-style=full-iso du log du run). Une heure d'écart, systématique, dans un ledger dont la fonction est de dire qui tient quoi et jusqu'à quand. Toute planification qui s'appuie dessus est décalée d'une heure.
Critères d'acceptation
- Un organe poste le spool : soit
debt_ledger.pygagne unflush/publishqui pousse les enveloppes en attente sur le dashboard dédié, soit un script de coordination le fait, avec un--dry-run. Le critère de sortie est mesurable :spool --statusrendpending=0après passage, et une observation non postée bloque le lancement au lieu d'être silencieusement ignorée. - Le drainage est idempotent : rejouer ne duplique pas une observation (l'
observation_idde l'enveloppe est la clé). started_atest en UTC réel : l'organe qui construit l'enveloppe n'écrit jamais une heure naïve. Test qui échoue surdatetime.now()sans timezone.- La garde ne rend plus un verdict périmé sans le dire :
check_pendingdoit distinguer « aucune réservation » de « je n'ai pas pu lire les réservations » — unpending>0dans le spool est précisément le second cas, et il doit être nommé dans le verdict. - Drainage effectif des 43 observations existantes, une fois, avec preuve (
before/afterdespool --status).
Ce que j'ai fait de mon côté, sans attendre
À partir de maintenant, avant chaque lancement GPU : lecture de la dernière observation du dashboard en plus de check_pending, et held posté à la main au lieu de rester dans le spool. C'est un contournement de lane, pas un correctif — il ne protège aucune autre lane.
Mesure de départ à conserver
| Date | Observation |
|---|---|
| 2026-10-25 | pending=43, plus ancienne 2026-10-08 ; check_pending = RELEASED 2026-10-22 alors que deux held vivants |
| 2026-10-25 | 1 h d'écart entre started_at de l'enveloppe et l'heure réelle du log |
Activity
jsboige commentedon Oct 25, 2026
[CLAIMED] lane myia-ai-01:CoursIA-2 -- paths: scripts/coordination/debt_ledger.py, scripts/tests/test_debt_ledger.py
Les deux defauts D1 (drainage du spool) et D2 (
started_atheure locale etiquetee UTC) sont dans le perimetre. Je prends les 5 criteres d'acceptation dans l'ordre, avec la preuvebefore/afterdespool --statusexigee au critere 5.jsboige commentedon Oct 25, 2026
[DELIVERED] lane myia-ai-01:CoursIA-2 -- PR #22491
Les deux defauts sont traites, avec les criteres 1 a 4 mesures :
flush(nouveau) : dry-run par defaut,--emitdu manifeste,--mark-postedpour archiver ce qui a ete poste. Lecontentde chaque appel est l'octet du fichier de spool. Archivage idempotent (cle =observation_id) et tout-ou-rien : un id inconnu refuse le lot plutot que d'en archiver la moitie.check_pendingrend desormaisUNPOSTED(rc=1) avant de lire le snapshot : un spool non vide est un ledger illisible, pas un device libre. C'est la distinction demandee au critere 4.appendresout les sentinellesnow/now+60m/now-2hdepuisutcnow(). L'ecart d'une heure venait d'un appelant qui formatit sa propre horloge — une heure locale suivie deZest bien formee, donc indetectable en aval. Une garde AST refuse toutdatetime.now()sans timezone dans l'organe.Mesures : 136 tests passent (124 avant, 12 nouveaux) ; egalite octet a octet entre le
contentdu manifeste et la ligne du spool ;check_pendingrendUNPOSTEDsur un spool non vide.Critere 5 en cours, pas conclu : le drainage des 44 observations est un geste d'exploitation (44
appendMCP), lance a l'instant. La mesurebeforeestpending=44, oldest 2026-10-08T11:27:53Z; leafteret les ids archives seront postes ici et sur la PR des que la pose est terminee. Je ne declare paspending=0avant de l'avoir mesure.Note d'exploitation a surveiller pendant ce drainage : le canal est a 81,5 % de son plafond (41,7 Ko / 51,2 Ko) et a deja condense une fois le 2026-10-23 ; l'arrivee de 44 messages declenchera une nouvelle condensation, qui archive les plus anciens messages vivants. Le fold lit les archives, donc rien n'est perdu, mais c'est un effet de bord a verifier au
after— il fait partie de la mesure, pas d'une reserve.Fix(coordination,#22456): le drainage archive par l'id que le manifes…
jsboige commentedon Oct 25, 2026
Critere 5 ferme — spool draine a
pending=0, et un trou trouve en drainantLe drainage n'avait pas ete fait au moment de la livraison de #22491 (les criteres 1 a 4 l'etaient). Il l'est.
Mesure avant/apres (
python scripts/coordination/debt_ledger.py spool --status) :Les 43 observations annoncees dans le constat d'origine avaient deja ete drainees entre-temps ; les 3 restantes etaient les transitions GPU 2 du jour, toutes de cette lane.
Le trou trouve en drainant
En lisant les 3 enveloppes avant de les publier, une quatrieme manquait a l'appel : le
helddu smoke 14B (obs-52f5013e56c9d4e6,2026-10-25T14:58:09Z→16:30Z) n'avait jamais recu dereleased. Le smoke s'est termine arc=0a ~15:31Z, le bras a ete retire sur mesure, et le GPU est repasse a la chaine 8B a 15:53Z — mais aucune ligne ne le disait.C'est exactement le mode de panne que cette issue nomme : une reservation vivante sur un device libre bloque a tort. Une enveloppe
helddont l'expected_endest passe sansreleasedest indiscernable, pour le fold, d'une reservation encore tenue.L'enveloppe manquante a ete creee par
debt_ledger.py append(doncobservation_idcalcule, pas estampille a la main — la lecon du rejet du 22/10) avec des horodatages UTC explicites :Publication
Les 4 enveloppes sont postees sur
CoursIA-gpu-reservation-ledgerdans l'ordre chronologique de leurobserved_at(le fold doit voirheldavantreleased, et leheld8B apres lereleaseddu smoke) :obs-52f5013e56c9d4e6heldobs-d5ed6e46038b4a3areleasedobs-66ee167d1c359bb4releasedobs-0a5c2a2ec41ee17fheldPreuve de publication : les 4 appends ont rendu
success, et lemessageCountdu dashboard est passe de 18 → 19 → 20 → 21 (valeur rendue par chaque appel, donc 17 avant le premier). Je n'ai pas mesure le nombre d'enveloppes[OBS]distinctes que le fold retient apres coup — la publication est mesuree, la reduction ne l'est pas. Le spool local est archive dansposted/, pas supprime : les enveloppes restent lisibles.Ce que ce drainage ne repare PAS, et c'est le fond de D1
Publier sur le dashboard ne rafraichit pas
check_pending: celui-ci lit l'etat reduit localement, pas le dashboard. Tant que rien ne fait le chemin inverse (dashboard → reduce local), la garde continuera de rendre un verdict perime avec l'aplomb d'un verdict frais, meme apres un drainage parfait.C'est pourquoi le
flushde #22491 reste la piece necessaire : il fait le transport et son--mark-postedarchive ce qui est parti. Ce drainage manuel est une execution unique du critere 5, pas un remplacement de l'organe.Feat(coordination,#22456): flush du spool, verdict UNPOSTED, horodata…
jsboige commentedon Oct 26, 2026
[CLAIMED-AMEND] lane myia-ai-01:CoursIA-2 -- paths: scripts/coordination/debt_ledger.py, scripts/tests/test_debt_ledger.py, docs/coordination/gpu-reservation.md
Suite de #22491 (PR mergee) : le point structurel que j'ai ecrit dans le commentaire de cloture tient toujours -- publier sur le dashboard ne rafraichit pas
check_pending, qui lit l'etat reduit local. La lecture du dashboard suppose en outre un MCProo-state-managerdisponible, ce qui n'est pas le cas en ce moment (CONNECTION_CLOSED sur la session).Grain : rendre l'activite GPU de la flotte lisible par git, pour que la source de verite ne depende pas d'un transport de messagerie. Deux fonctions : publication de la file locale dans un etat versionne par machine, et lecture de cet etat par
check_pending. Le chemin de publication existant (flush-> dashboard) reste intact et devient un miroir, pas la source.Le perimetre s'elargit d'un chemin :
docs/coordination/gpu-reservation.md(le protocole doit decrire la nouvelle source, et le document annonce a tort que le picker consulte le gate -- ecart doc/code mesure).jsboige commentedon Oct 26, 2026
[CLOSURE PREFLIGHT]
schema: 1
lane: myia-po-2028:CoursIA-3
issue: 22456
verdict: KEEP
acceptance:
residue: followup coordination(gpu-reservation): le document dit que le picker verifie le gate, le code ne le fait pas #22747
open-prs: 0
comments-reviewed: 4
[/CLOSURE PREFLIGHT]
Lecture G.9 de l'issue #22456 et de ses 4 commentaires (claim
myia-ai-01:CoursIA-2du 2026-10-25T11:29:05Z, livraison du 2026-10-25T11:35:45Z, fermeture du critere 5 le 2026-10-25T16:03:40Z, et un CLAIM-AMEND de la meme lane le 2026-10-26T16:56:18Z). Ce qui est verifie ici n'est pas le compte de la livraison : c'est l'artefact surmaina la tete demainaujourd'hui, relu fichier par fichier.Les cinq criteres de l'issue sont livres et mesures. Le
flushexiste en dry-run par defaut, avec--emitdu manifeste et--mark-postedpour archiver ; l'archivage est idempotent (cle =observation_id) et tout-ou-rien, avec un test qui verifie qu'un id inconnu refuse le lot sans rien deplacer. Lestarted_atest ecrit en UTC reel :parse_utc_timestamprefuse un estampille sans offset et un offset non-UTC, et une garde AST interdit dans tout l'organe l'appeldatetime.now()sans timezone -- c'est la cause mesuree de l'ecart d'une heure du constat.check_pendingrendUNPOSTEDavant de lire le snapshot, avec le nombre et l'anciennete de la plus ancienne observation en attente : un spool non vide ne peut plus se lire comme "device libre". Le drainage effectif est prouve par la mesure avant/apres du 2026-10-25T16:03:40Z.Pourquoi KEEP malgre cela. Deux raisons, l'une structurelle et l'une d'activite de la lane porteuse.
check_pending, qui lit l'etat reduit local ; la lecture du dashboard suppose en outre un MCProo-state-managerdisponible, ce qui n'est pas le cas sur la session mesuree au moment de la lecture (CONNECTION_CLOSED). Ce reliquat est l'ecart doc/code que l'issue de suivi coordination(gpu-reservation): le document dit que le picker verifie le gate, le code ne le fait pas #22747 (ouverte le 2026-10-26T17:03:14Z,Part of #16737) porte : le protocole affirme que le picker consulte le gate, le code ne le fait pas.Le dossier ne ferme donc rien : il atteste que les criteres 1 a 5 sont livres et que l'issue doit rester ouverte jusqu'a la resolution du reliquat structurel.
Aucun risque d'auto-attestation : la PR #22491 est portee par
myia-ai-01:CoursIA-2, le dossier est emis parmyia-po-2028:CoursIA-3, etopen-prs: 0a ete releve sur les PRs vives au moment de l'emission.jsboige commentedon Oct 26, 2026
[DELIVERED] lane myia-ai-01:CoursIA-2 -- PR #22755
Le point structurel que cette issue nomme (« publier sur le dashboard ne rafraichit pas
check_pending») a maintenant un transport independant du canal de messagerie et, surtout, un appelant : la publication n'est plus un geste manuel.Feat(coordination,#22456)), tete626d5ff1fad1aacd5c450e1cdbde163cfa920cb9, branchefeature/22456-git-ledger. Push verifie :git ls-remote origin refs/heads/feature/22456-git-ledgerrend le meme sha que la tete locale.debt_ledger.py publish --gitecrit les observations en attente dans un fichier JSONL par machine sur une branche dediee (ops/gpu-ledger), en ajout seul,observation_idcalcule par l'outil ;check_pending --source auto|git|locallit la branche par defaut et dit quand il retombe sur le cache local (un retour silencieux serait le defaut qu'on corrige). Le snapshot local redevient un cache, jamais une autorite ; le dashboard reste un miroir.run_guarded.pygagne--gpu-entity/--gpu-holder/--gpu-workload/--gpu-expected-end/--gpu-issue. Sans--gpu-entity, son comportement est strictement inchange. Avec : consultation du gate a l'admission (refus siHOLDou source indisponible), ecriture duheldavant le lancement, refus de lancer si la publication echoue (« une reservation invisible de la flotte n'est pas une reservation »), etreleasedau teardown (arret garde et sortie normale), dont l'echec est signale.GIT_PUBLISH_FOREIGN_MACHINE) ; commit publie verifie pargit diff-tree --root(GIT_PUBLISH_SCOPE, le sha nomme) ; push refuse deux fois -> l'echec nomme lesobservation_idretenus, ditpublished=false, et le spool les conserve.python -m pytest scripts/tests/test_debt_ledger.py scripts/tests/test_run_guarded.py -q-> 174 passed in 42,31 s (un seul run), sur le worktree et la tete exacts.Ce qui n'est pas de la lane : la PR change une autorite (la source primaire de l'etat de reservation passe du dashboard a la branche) et publie un etat vivant (« qui tient quel device, pour quel run, quand ») — les deux points sont soumis a sign-off user avant merge (CLAUDE.md §A), et la branche de publication par defaut vit sur un depot public : le choix de la cible et la classe de donnees sont des arbitrages, pas des mesures. Le merge revient au coordinateur ; la cloture de cette issue aussi.
Cette issue n'est donc pas close par la lane : la livraison est la PR #22755, la decision de gouvernance reste a prendre.
Fix(coordination,#22456): les six defauts de la revue adversariale su…
Docs(coordination,#22456): la borne par defaut du hold est dans la no…
jsboige commentedon Oct 26, 2026
[CLOSURE PREFLIGHT]
schema: 1
lane: myia-po-2028:CoursIA-3
issue: 22456
verdict: KEEP
acceptance:
residue: followup coordination(gpu-reservation): le document dit que le picker verifie le gate, le code ne le fait pas #22747
open-prs: 0
comments-reviewed: 6
[/CLOSURE PREFLIGHT]
Lecture G.9 de l'issue #22456 et de ses 6 commentaires (claim
myia-ai-01:CoursIA-2du 2026-10-25T11:29:05Z, livraison du 2026-10-25T11:35:45Z, fermeture du critere 5 le 2026-10-25T16:03:40Z, CLAIM-AMEND du 2026-10-26T16:56:18Z, mon dossier[CLOSURE PREFLIGHT]KEEP du 2026-10-26T17:33:49Z, puis le[DELIVERED]de la lane porteuse du 2026-10-26T17:47:46Z). Ce dossier re-stamp le precedent : la regle de selection du gate prend le dernier bloc, et leDELIVEREDde 17:47 est passe apres mon bloc de 17:33 — c'est lui qui compte aujourd'hui.Ce qui a change depuis mon bloc de 17:33. La lane porteuse a livre le reliquat structurel que je nommais dans la meme PR #22755 (
Feat(coordination,#22456), branchefeature/22456-git-ledger). La PR estOPEN,merged: false,mergeable_state: blocked, tete2d1e5be1aa903805e441acfc37c44742327bdc38, 5 fichiers / +2363 / -55. A noter : la tete que le commentaireDELIVEREDnomme (626d5ff1fad1aacd5c450e1cdbde163cfa920cb9) n'est plus la tete de la branche — la branche a bouge apres le commentaire. Le merge reste au coordinateur, et la lane dit elle-meme que le merge et la cloture lui reviennent.Ce que j'ai reverifie sur
origin/main, a la tete demaind'aujourd'hui.scripts/coordination/debt_ledger.py(3080 lignes) : la sous-commandeflushexiste (l.2995-3002) avec le dry-run par defaut,--emitdu manifeste et--mark-posted(l.2998, l.3004) ; le verdictUNPOSTEDest rendu avant toute lecture du snapshot (l.2720-2736, avec le nombre et l'anciennete de la plus ancienne observation en attente, rc=1) ;parse_utc_timestampest defini l.417 et refuse un offset non-UTC l.439-442.scripts/tests/test_debt_ledger.py(2140 lignes) :test_flush_mark_posted_is_idempotentl.1943,test_check_pending_reports_unposted_instead_of_releasedl.2061,test_append_refuses_a_naive_started_atl.2114,test_module_never_reads_a_naive_clockl.2122 (garde AST surdatetime.now()sans timezone) — la cause mesuree de l'ecart d'une heure du constat.pending=3->pending=0, les 43 observations du constat initial ayant deja ete drainees entre-temps.Les cinq criteres de l'issue sont donc livres et mesures sur
main. Ils sont au nombre de cinq dans le body ; mon bloc en compte six parce que j'ai ajoute le reliquat que la lane elle-meme signale.Pourquoi ce dossier est KEEP et non CLOSE. Le reliquat structurel que la lane nomme dans son
DELIVERED— « publier sur le dashboard ne rafraichit pascheck_pending, qui lit l'etat reduit local » — n'est pas resolu surmain: surorigin/main,debt_ledger.pyne porte ni--sourcenipublish --git, etscripts/ci/run_guarded.py(554 lignes) ne porte ni--gpu-entityni--gpu-holder. La source primaire de l'etat de reservation reste donc le dashboard, et la garde ne porte toujours pas la reservation elle-meme. La livraison existe, elle est mesuree par la lane (174 tests verts sur la tete exacte), mais elle vit dans une branche non mergee.S'y ajoute un point de gouvernance que la lane pose elle-meme et que je ne peux pas ignorer : la PR deplace une autorite (la source primaire passe du dashboard a une branche) et publie un etat vivant (« qui tient quel device, pour quel run, quand ») ; les deux sont soumis a sign-off user avant merge, et la branche de publication par defaut vit sur un depot public — le choix de la cible et la classe de donnees sont des arbitrages, pas des mesures. Ce dossier atteste, il ne tranche pas.
Residue.
followup #22747— ouverte le 2026-10-26T17:03:14Z,Part of #16737, titre « le document dit que le picker verifie le gate, le code ne le fait pas » : verifie ouverte a l'instant de l'emission. C'est l'ecart doc/code que la lane a elargi a son CLAIM-AMEND (le fichierdocs/coordination/gpu-reservation.mdfait partie de son perimetre).Aucun risque d'auto-attestation : la PR #22491 et la PR #22755 sont portees par
myia-ai-01:CoursIA-2, le dossier est emis parmyia-po-2028:CoursIA-3, etopen-prs: 0a ete releve sur les PRs vives par l organe du gate au moment de l'emission.Docs(coordination,#22456): le transport git est une capacite, la decl…
Fix(coordination,#22456): un verdict de gate doit etre documente, et …
Fix(coordination,#22456): le test des codes de sortie voyait une cle …
fix(coordination,#22456): les fixtures check_pending nomment leur sou…
fix(coordination,#22456): le gate GPU ne rend plus OK_TO_RUN sans lan…
fix(coordination,#22456): un fetch en echec ne laisse plus un ref per…
fix(coordination,#22456): deux publieurs d'un meme fichier ne s'effac…
docs(coordination,#22456): le transport decrit la garde de lane, le f…
test(coordination,#22456): le temoin du finding 2 rougit sur BOTH_SUR…
myia-ai-01 commentedon Oct 27, 2026
[DECISION] lane myia-ai-01:CoursIA — arbitrage du mainteneur rendu le 2026-10-27 vers 10:35Z : option (a). La référence du registre des réservations GPU devient un dépôt git privé et dédié, sous le compte
jsboige. Le dashboard RooSync n'en est plus que la copie.Le dépôt existe depuis 10:4xZ :
jsboige/coursia-gpu-ledger(privé, branche par défautmain, avec un README seul). La brancheops/gpu-ledgery naîtra à la première publication, sans parent, comme le décrit #22755.Ce qui suit, confié à la lane
myia-ai-01:CoursIA-2(DM du même cycle) :--remotecôté organe,--gpu-ledger-remotecôté garde). Seul le défaut doit désigner le dépôt privé et nonorigin, qui est public. Que ce soit dans cette PR ou dans une PR qui la suit, c'est au choix de la lane, mais jamais de publication versjsboige/CoursIA.docs/coordination/gpu-reservation.md, ligne 25 surmain) devient une PR distincte, désormais signée. Elle nommejsboige/coursia-gpu-ledger, brancheops/gpu-ledger, comme référence, et le dashboard comme copie.jsboige. Le premierpublish --git --emitd'un siège mesure que le push atterrit (ls-remoterelu), sans le supposer.Cette issue reste ouverte jusqu'à ce que les points 1 et 2 soient sur
main.Fix(coordination,#22456): la reference du registre GPU est le depot p…
Fix(coordination,#22456): une publication reussie ne se dit plus en e…
jsboige commentedon Oct 27, 2026
[DELIVERED] lane myia-ai-01:CoursIA-2 — point 3 de l'arbitrage : la première publication réelle, mesurée
Les trois points de l'arbitrage sont livrés. La mesure demandée au point 3 (« le premier
publish --git --emitd'un siège mesure que le push atterrit,ls-remoterelu ») est faite depuis ce siège, sur la tête3929007918b54a84ebdbf4712dc06d1cdf8431b4.Ce qui a atterri — la branche
ops/gpu-ledgerest née dans le dépôt privéjsboige/coursia-gpu-ledger, sans parent, comme le décrit l'arbitrage :La mesure dit deux choses, pas une :
source: "git"est le point qui compte : l'état de la flotte est lu dans la référence ;archive_posted) et que 3 de ces observations ne se résolvaient plus dans le spool au moment de l'archivage. Rien n'était perdu pour la flotte (elles sont sur la branche), mais l'opérateur ne pouvait pas savoir si la publication était passée : une erreur qui dit « rien n'a été publié » alors que tout est publié — le pire des deux.Le correctif (commit
3929007918b) ferme ce second point : quand la poussée a atterri et que le commit vérifié porte toutes les observations publiées, un drain incomplet ne fait plus échouer la commande — le résidu est nommé (drain_missing), le reste est archivé. L'invariant tout ou rien dearchive_postedest conservé : c'est l'appelant, qui sait que la branche porte l'état, qui tolère un résidu. Deux tests nouveaux couvrent ce chemin.Les deux PR
feature/22456-git-ledger, tête3929007918b54a84ebdbf4712dc06d1cdf8431b4) — le moyen. Seul le défaut de cible change (deorigin, le remote du dépôt de travail public, àgpu-ledger, qui désigne le dépôt privé) ; la cible reste un paramètre (--remotecôté organe,--gpu-ledger-remotecôté garde). Deux gardes fail-CLOSED l'encadrent, dans le code :GIT_LEDGER_REMOTE_UNKNOWN(remote non configuré sur le siège — le refus porte le geste exact) etGIT_LEDGER_FORBIDDEN_TARGET(cible = dépôt de travail public). Le gate rendUNREADABLEsur une cible inutilisable, sans se replier sur le cache local. Tests :pytest scripts/tests/test_debt_ledger.py scripts/tests/test_run_guarded.py -q→ 199 passed ; sélection élargie (-k "pick or belt or debt_ledger or run_guarded") → 957 passed, 1 skipped.docs/22456-gpu-ledger-authority, tête46d95277c2a) — la déclaration d'autorité, PR distincte et signée : la référence est le dépôt privéjsboige/coursia-gpu-ledger(brancheops/gpu-ledger), le dashboard n'en est plus qu'une copie.Un prérequis de siège, à porter par la flotte
Le remote
gpu-ledgerest une configuration locale de chaque clone qui publie ou lit le registre :L'organe ne le crée pas de lui-même (écrire dans un dépôt partagé ne doit pas dépendre d'un effet de bord d'une commande de lecture ou de test) : tant qu'il n'est pas configuré, il refuse en nommant le geste. L'authentification passe par le helper
ghdu siège — jamais par un jeton dans une URL git.See #22456Docs(coordination,#22456): la reference est l'autorite, le dashboard …
Fix(tooling,#22747): le picker consulte le gate GPU avant de proposer…