Skip to content

coordination(gpu-reservation): le spool ne rejoint jamais le dashboard -- 43 observations en attente, et check_pending rend un verdict perime #22456

Open

Description

@jsboige

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

  1. Un organe poste le spool : soit debt_ledger.py gagne un flush/publish qui 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 --status rend pending=0 après passage, et une observation non postée bloque le lancement au lieu d'être silencieusement ignorée.
  2. Le drainage est idempotent : rejouer ne duplique pas une observation (l'observation_id de l'enveloppe est la clé).
  3. started_at est en UTC réel : l'organe qui construit l'enveloppe n'écrit jamais une heure naïve. Test qui échoue sur datetime.now() sans timezone.
  4. La garde ne rend plus un verdict périmé sans le dire : check_pending doit distinguer « aucune réservation » de « je n'ai pas pu lire les réservations » — un pending>0 dans le spool est précisément le second cas, et il doit être nommé dans le verdict.
  5. Drainage effectif des 43 observations existantes, une fois, avec preuve (before/after de spool --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

  1. jsboige commented on Oct 25, 2026

    @jsboige
    OwnerAuthor

    [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_at heure locale etiquetee UTC) sont dans le perimetre. Je prends les 5 criteres d'acceptation dans l'ordre, avec la preuve before/after de spool --status exigee au critere 5.

  2. jsboige commented on Oct 25, 2026

    @jsboige
    OwnerAuthor

    [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, --emit du manifeste, --mark-posted pour archiver ce qui a ete poste. Le content de 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_pending rend desormais UNPOSTED (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.
    • D2 : append resout les sentinelles now / now+60m / now-2h depuis utcnow(). L'ecart d'une heure venait d'un appelant qui formatit sa propre horloge — une heure locale suivie de Z est bien formee, donc indetectable en aval. Une garde AST refuse tout datetime.now() sans timezone dans l'organe.

    Mesures : 136 tests passent (124 avant, 12 nouveaux) ; egalite octet a octet entre le content du manifeste et la ligne du spool ; check_pending rend UNPOSTED sur un spool non vide.

    Critere 5 en cours, pas conclu : le drainage des 44 observations est un geste d'exploitation (44 append MCP), lance a l'instant. La mesure before est pending=44, oldest 2026-10-08T11:27:53Z ; le after et les ids archives seront postes ici et sur la PR des que la pose est terminee. Je ne declare pas pending=0 avant 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.

  3. added a commit that references this issue on Oct 25, 2026
  4. jsboige commented on Oct 25, 2026

    @jsboige
    OwnerAuthor

    Critere 5 ferme — spool draine a pending=0, et un trou trouve en drainant

    Le 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) :

    AVANT :  gpu-reservation:   pending=3   oldest_observed_at=2026-10-25T14:58:09Z
    APRES :  gpu-reservation:   pending=0   oldest_observed_at=-
             issue-debt:        pending=0   oldest_observed_at=-
    

    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 held du smoke 14B (obs-52f5013e56c9d4e6, 2026-10-25T14:58:09Z → 16:30Z) n'avait jamais recu de released. Le smoke s'est termine a rc=0 a ~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 held dont l'expected_end est passe sans released est indiscernable, pour le fold, d'une reservation encore tenue.

    L'enveloppe manquante a ete creee par debt_ledger.py append (donc observation_id calcule, pas estampille a la main — la lecon du rejet du 22/10) avec des horodatages UTC explicites :

    obs-d5ed6e46038b4a3a  released  myia-ai-01#gpu2  14:58:09Z -> 15:31:00Z
    

    Publication

    Les 4 enveloppes sont postees sur CoursIA-gpu-reservation-ledger dans l'ordre chronologique de leur observed_at (le fold doit voir held avant released, et le held 8B apres le released du smoke) :

    # Observation Etat Fenetre
    1 obs-52f5013e56c9d4e6 held 14:58:09Z → 16:30:00Z
    2 obs-d5ed6e46038b4a3a released fin du smoke 14B
    3 obs-66ee167d1c359bb4 released onset #17719, 11:14:45Z → 15:51:30Z
    4 obs-0a5c2a2ec41ee17f held chaine 8B #15293, 15:53:23Z → 2026-10-26T07:00:00Z

    Preuve de publication : les 4 appends ont rendu success, et le messageCount du 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 dans posted/, 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 flush de #22491 reste la piece necessaire : il fait le transport et son --mark-posted archive ce qui est parti. Ce drainage manuel est une execution unique du critere 5, pas un remplacement de l'organe.

  5. added a commit that references this issue on Oct 25, 2026
  6. added
    candidate-deliveredReferenced by a merged PR with no post-merge activity -- candidate for close triage (#10466)
    on Oct 26, 2026
  7. jsboige commented on Oct 26, 2026

    @jsboige
    OwnerAuthor

    [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 MCP roo-state-manager disponible, 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).

  8. jsboige commented on Oct 26, 2026

    @jsboige
    OwnerAuthor

    [CLOSURE PREFLIGHT]
    schema: 1
    lane: myia-po-2028:CoursIA-3
    issue: 22456
    verdict: KEEP
    acceptance:

    Lecture G.9 de l'issue #22456 et de ses 4 commentaires (claim myia-ai-01:CoursIA-2 du 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 sur main a la tete de main aujourd'hui, relu fichier par fichier.

    Les cinq criteres de l'issue sont livres et mesures. Le flush existe en dry-run par defaut, avec --emit du manifeste et --mark-posted pour 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. Le started_at est ecrit en UTC reel : parse_utc_timestamp refuse un estampille sans offset et un offset non-UTC, et une garde AST interdit dans tout l'organe l'appel datetime.now() sans timezone -- c'est la cause mesuree de l'ecart d'une heure du constat. check_pending rend UNPOSTED avant 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.

    1. Le reliquat que la lane elle-meme signale le 2026-10-26T16:56:18Z 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 MCP roo-state-manager disponible, 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.
    2. La lane porteuse a reclame l'issue le 2026-10-26T16:56:18Z avec un CLAIM-AMEND qui elargit le perimetre a un grain distinct (rendre l'activite GPU lisible par git, pour que la source de verite ne depende pas d'un transport de messagerie). L'issue n'est donc pas un reliquat inerte : c'est le porte-a-terrain d'un grain en cours. Fermer une issue sur laquelle une lane travaille activement arreterait ce travail.

    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 par myia-po-2028:CoursIA-3, et open-prs: 0 a ete releve sur les PRs vives au moment de l'emission.

  9. jsboige commented on Oct 26, 2026

    @jsboige
    OwnerAuthor

    [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.

    • PR Feat(coordination,#22456): le ledger GPU se publie par git et la garde porte la reservation #22755 (Feat(coordination,#22456)), tete 626d5ff1fad1aacd5c450e1cdbde163cfa920cb9, branche feature/22456-git-ledger. Push verifie : git ls-remote origin refs/heads/feature/22456-git-ledger rend le meme sha que la tete locale.
    • F1 — l'etat se publie et se lit par git : debt_ledger.py publish --git ecrit les observations en attente dans un fichier JSONL par machine sur une branche dediee (ops/gpu-ledger), en ajout seul, observation_id calcule par l'outil ; check_pending --source auto|git|local lit 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.
    • F2 — la garde porte la reservation : run_guarded.py gagne --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 si HOLD ou source indisponible), ecriture du held avant le lancement, refus de lancer si la publication echoue (« une reservation invisible de la flotte n'est pas une reservation »), et released au teardown (arret garde et sortie normale), dont l'echec est signale.
    • Invariants enforces : observation d'une autre machine refusee avant commit (GIT_PUBLISH_FOREIGN_MACHINE) ; commit publie verifie par git diff-tree --root (GIT_PUBLISH_SCOPE, le sha nomme) ; push refuse deux fois -> l'echec nomme les observation_id retenus, dit published=false, et le spool les conserve.
    • Verification refaite par la lane : 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.

  10. added 2 commits that reference this issue on Oct 26, 2026
  11. jsboige commented on Oct 26, 2026

    @jsboige
    OwnerAuthor

    [CLOSURE PREFLIGHT]
    schema: 1
    lane: myia-po-2028:CoursIA-3
    issue: 22456
    verdict: KEEP
    acceptance:

    • Un organe poste le spool, en dry-run par defaut, et une observation non postee bloque le lancement -> scripts/coordination/debt_ledger.py:2995-3002 (sous-commande flush, dry-run par defaut, --emit du manifeste) et :2720-2736 (verdict UNPOSTED rendu avant toute lecture du snapshot, avec le nombre et la plus ancienne observation en attente, rc=1), livre par PR Feat(coordination,#22456): flush du spool, verdict UNPOSTED, horodatage UTC par l'organe #22491 (MERGED le 2026-10-25)
    • Le drainage est idempotent, cle observation_id, et tout-ou-rien -> scripts/coordination/debt_ledger.py:2998 et :3004 (--mark-posted, archivage idempotent) et scripts/tests/test_debt_ledger.py:1943 (test_flush_mark_posted_is_idempotent) et :1962 (un id inconnu refuse le lot entier sans deplacer), livre par PR Feat(coordination,#22456): flush du spool, verdict UNPOSTED, horodatage UTC par l'organe #22491 (MERGED le 2026-10-25)
    • started_at est en UTC reel et l organe refuse une horloge naive -> scripts/coordination/debt_ledger.py:417 (parse_utc_timestamp refuse un estampille sans offset UTC) et :439-442 (un offset non-UTC est refuse aussi) et scripts/tests/test_debt_ledger.py:2114 (test_append_refuses_a_naive_started_at) et :2122 (test_module_never_reads_a_naive_clock, garde AST sur datetime.now() sans timezone), livre par PR Feat(coordination,#22456): flush du spool, verdict UNPOSTED, horodatage UTC par l'organe #22491 (MERGED le 2026-10-25)
    • check_pending distingue l absence de reservation de l etat illisible et nomme le pending -> scripts/coordination/debt_ledger.py:2669 (verdict UNPOSTED en tete des six verdicts) et :2720-2736 (lecture du snapshot refusee tant que le spool n est pas vide) et scripts/tests/test_debt_ledger.py:2061 (test_check_pending_reports_unposted_instead_of_released), livre par PR Feat(coordination,#22456): flush du spool, verdict UNPOSTED, horodatage UTC par l'organe #22491 (MERGED le 2026-10-25)
    • Le drainage effectif est prouve par un avant/apres -> commentaire de la lane porteuse du 2026-10-25T16:03:40Z sur cette issue : AVANT gpu-reservation pending=3 oldest_observed_at=2026-10-25T14:58:09Z, APRES pending=0 ; les 43 observations du constat initial avaient deja ete drainees entre-temps
    • Le reliquat structurel nomme par la lane porteuse, publishing par git et appelant dans la garde -> NON SATISFAIT a la source : sur origin/main, scripts/coordination/debt_ledger.py (3080 lignes) porte 0 occurrence de --source et 0 occurrence de publish --git, et scripts/ci/run_guarded.py (554 lignes) porte 0 occurrence de --gpu-entity et 0 de --gpu-holder ; la source primaire de l etat de reservation reste donc le dashboard, avec check_pending qui lit l etat reduit local, et la livraison est dans une branche non encore mergee, absente de origin/main
      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-2 du 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 le DELIVERED de 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), branche feature/22456-git-ledger). La PR est OPEN, merged: false, mergeable_state: blocked, tete 2d1e5be1aa903805e441acfc37c44742327bdc38, 5 fichiers / +2363 / -55. A noter : la tete que le commentaire DELIVERED nomme (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 de main d'aujourd'hui.

    • scripts/coordination/debt_ledger.py (3080 lignes) : la sous-commande flush existe (l.2995-3002) avec le dry-run par defaut, --emit du manifeste et --mark-posted (l.2998, l.3004) ; le verdict UNPOSTED est 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_timestamp est 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_idempotent l.1943, test_check_pending_reports_unposted_instead_of_released l.2061, test_append_refuses_a_naive_started_at l.2114, test_module_never_reads_a_naive_clock l.2122 (garde AST sur datetime.now() sans timezone) — la cause mesuree de l'ecart d'une heure du constat.
    • Le drainage effectif est prouve par la mesure avant/apres de la lane porteuse (2026-10-25T16:03:40Z) : 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 pas check_pending, qui lit l'etat reduit local » — n'est pas resolu sur main : sur origin/main, debt_ledger.py ne porte ni --source ni publish --git, et scripts/ci/run_guarded.py (554 lignes) ne porte ni --gpu-entity ni --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 fichier docs/coordination/gpu-reservation.md fait 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 par myia-po-2028:CoursIA-3, et open-prs: 0 a ete releve sur les PRs vives par l organe du gate au moment de l'emission.

  12. added 9 commits that reference this issue on Oct 26, 2026
  13. myia-ai-01 commented on Oct 27, 2026

    @myia-ai-01
    Collaborator

    [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éfaut main, avec un README seul). La branche ops/gpu-ledger y 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) :

    1. Feat(coordination,#22456): le ledger GPU se publie par git et la garde porte la reservation #22755 : rien ne change dans son code, puisque la cible est un paramètre (--remote côté organe, --gpu-ledger-remote côté garde). Seul le défaut doit désigner le dépôt privé et non origin, 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 vers jsboige/CoursIA.
    2. La déclaration d'autorité (docs/coordination/gpu-reservation.md, ligne 25 sur main) devient une PR distincte, désormais signée. Elle nomme jsboige/coursia-gpu-ledger, branche ops/gpu-ledger, comme référence, et le dashboard comme copie.
    3. L'accès des sièges : chaque machine lit et pousse sous le compte jsboige. Le premier publish --git --emit d'un siège mesure que le push atterrit (ls-remote relu), sans le supposer.

    Cette issue reste ouverte jusqu'à ce que les points 1 et 2 soient sur main.

  14. removed
    candidate-deliveredReferenced by a merged PR with no post-merge activity -- candidate for close triage (#10466)
    on Oct 27, 2026
  15. added 2 commits that reference this issue on Oct 27, 2026
  16. jsboige commented on Oct 27, 2026

    @jsboige
    OwnerAuthor

    [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 --emit d'un siège mesure que le push atterrit, ls-remote relu ») est faite depuis ce siège, sur la tête 3929007918b54a84ebdbf4712dc06d1cdf8431b4.

    Ce qui a atterri — la branche ops/gpu-ledger est née dans le dépôt privé jsboige/coursia-gpu-ledger, sans parent, comme le décrit l'arbitrage :

    $ python scripts/coordination/debt_ledger.py publish --git --machine myia-ai-01 --emit
    ERROR UNKNOWN_OBSERVATION: no pending or posted envelope for: obs-3b1f724182010686, obs-64ecdf1376e6fbae, obs-6a9cfd926fd29daf
    $ git ls-remote gpu-ledger refs/heads/ops/gpu-ledger
    1049c3adb957968da57f6b7b1d3af7c2acf619cd	refs/heads/ops/gpu-ledger
    $ git show refs/remotes/gpu-ledger/ops/gpu-ledger:gpu-reservation/myia-ai-01.jsonl | wc -l
    51
    

    La mesure dit deux choses, pas une :

    1. la publication a réussi — 51 observations de ce siège sont sur la branche, le sha est relu après la poussée, et le gate relit désormais la branche et non un cache :
    $ python scripts/coordination/debt_ledger.py check_pending --entity myia-ai-01#gpu2 --my-lane myia-ai-01:CoursIA-2 --json
    {"verdict": "RELEASED", ..., "source": "git"}
    

    source: "git" est le point qui compte : l'état de la flotte est lu dans la référence ;

    1. la commande a rendu un échec — parce que le drain local est tout ou rien (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 de archive_posted est 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

    • Feat(coordination,#22456): le ledger GPU se publie par git et la garde porte la reservation #22755 (feature/22456-git-ledger, tête 3929007918b54a84ebdbf4712dc06d1cdf8431b4) — le moyen. Seul le défaut de cible change (de origin, 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 (--remote côté organe, --gpu-ledger-remote cô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) et GIT_LEDGER_FORBIDDEN_TARGET (cible = dépôt de travail public). Le gate rend UNREADABLE sur 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(coordination,#22456): la reference du registre GPU est le depot prive dedie #22943 (docs/22456-gpu-ledger-authority, tête 46d95277c2a) — la déclaration d'autorité, PR distincte et signée : la référence est le dépôt privé jsboige/coursia-gpu-ledger (branche ops/gpu-ledger), le dashboard n'en est plus qu'une copie.

    Un prérequis de siège, à porter par la flotte

    Le remote gpu-ledger est une configuration locale de chaque clone qui publie ou lit le registre :

    git remote add gpu-ledger https://github.com/jsboige/coursia-gpu-ledger.git
    

    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 gh du siège — jamais par un jeton dans une URL git.

    See #22456

  17. added a commit that references this issue on Oct 27, 2026
  18. added a commit that references this issue on Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions