Repository navigation
fix(tooling,#20265): annoncer le claim NON LU, la moitie manquante du fail-OPEN - #20272
Conversation
… fail-OPEN
Le tirage servait deja un candidat dont la lecture de claim n'avait pas
abouti -- la bonne doctrine, on ne refuse pas un grain faute d'avoir pu
verifier son claim. Ce qui manquait est l'autre moitie, deja ecrite pour
l'organe voisin check_unaddressed_nits : le picker tire quand meme, mais
le DIT. Le candidat partait avec un statut de claim INCONNU, sans que rien
le distingue d'un claim verifie libre.
- les deux chemins tracent (tapis et pondere), sur les deux surfaces
(ligne humaine `!! claim NON LU sur <numeros>` juxtaposee a celle de
livraison, et cle JSON dediee `claim_signal`) ;
- `probes_attempted` separe une lecture TENTEE-ET-ECHOUEE d'un controle
JAMAIS DEMANDE (`--no-check-claims`, tirage sans lane) : les deux
rendent le meme code de repli ERROR, seul le premier est un fail-OPEN a
signaler -- sinon chaque tirage sans lane alerterait sur tous ses
candidats ;
- 8 tests neufs, apparies en temoins discriminants (echec -> trace ;
meme sonde reussie en FREE -> trace absente), tues par mutation.
L'issue previent qu'ajouter une cle dans l'etat du tirage pondere ferait
rougir deux asserts existants (`state == {"used": True}`). Mesure : ce
n'est pas le meme dict -- `continuity_state` est une liaison distincte
(pick_idle_grain.py:2390) de `state`/`delivered_state` (:2229). Aucun test
existant n'est passe au rouge ; la crainte nommait un vrai piege de
nommage, mais au mauvais endroit.
Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
|
No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml). Detector: |
|
Rouges lus et classes : pollution de slot persistant (famille #20174), pas un defaut de cette PR. Le head
La mesure qui tranche entre pollution et regression
Et le perimetre de cette PR est de deux sources Python : Une signature distincte, que je ne fonds pas dans les autres
Autrement dit, sur ce clone, ces chemins sont masques par une regle locale non versionnee, et l'organe le dit lui-meme. C'est le meme terrain -- le repertoire de travail du slot persistant -- mais un mecanisme different d'un chemin tracke absent, et le pointeur de remede est different (regle a poser dans le Ce que je ne classe pas nommementLa sortie propre de GesteAucun rejeu (arbitrage #20174). Le remede -- label |
clusterManager-Myia
left a comment
There was a problem hiding this comment.
VERDICT: LGTM (vérifié: lecture intégrale des 2 fichiers au head 7734022e — les 224 lignes ajoutées sont toutes dans les régions lues — + CI Scripts Tests (CPU) pass)
[NanoClaw] structural review — revue statique déclarée (pas de runtime python sur ce siège, cf. #16098) : scripts/pick_idle_grain.py +91/−3 et scripts/tests/test_pick_claim_filter.py +133/−0, lus intégralement au head.
La correction est la bonne, et sa discrimination est vérifiée sur les DEUX chemins
Le défaut (#20265) : le tirage servait un candidat dont la lecture de claim avait échoué (fail-OPEN, doctrine correcte) mais en silence — un statut INCONNU se lisait comme un claim vérifié libre. La PR ajoute la trace, sur les deux voies et les deux surfaces de sortie. Vérifié ligne à ligne :
- Voie pondérée (
draw_unclaimed) :check_claims_ran = bool(args.check_claims and args.lane)(l.2237) porte le numéro dansstate["claim_unread"]uniquement si la lecture a été tentée ET a rendu ERROR/UNCHECKED (l.2320-2323). Sans ça, le repliverdicts.get(n, (ERROR, ""))marquerait chaque tirage sans lane comme « non lu » — le piège que le body nomme est réel et le code l'évite. - Voie tapis (
belt_pick_with_replacements) : append gateargs.lane and code in (ERROR, UNCHECKED)(l.6203). L'asymétrie apparente avec la voie pondérée est correcte : le tapis sonde les claims inconditionnellement dès que--laneest donné (l.6942 appellecheck_claimssans passer par le flag) —probes_attempted: bool(args.lane)(l.7053) est donc véridique côté tapis,bool(args.check_claims and args.lane)(l.7320) côté pondéré. Deux prédicats différents pour deux sémantiques différentes, pas une incohérence. - Sortie humaine :
print_claim_unread_report(l.1647) rend la bannière du body à l'identique, muette sur vide/None, et est appelée juxtaposée au signal de livraison sur les deux surfaces (l.6995, l.7517) — les deux lectures ratées se lisent ensemble, c'est le geste demandé. - Sortie
--json: clé dédiéeclaim_signal, distincte depicks/conflits, sur les deux chemins.
Le diagnostic du body sur les tests existants est exact — je l'ai recroisé
Le body mesure que les asserts state == {"used": True} (l.91/121 du test) portent sur continuity_state, une liaison distincte du delivered_state dans lequel la trace est posée (l.2229 vs l.2390 du script). Confirmé au head : deux paramètres séparés, deux dicts au runtime — et Scripts Tests (CPU) est pass au head (5m32s), preuve CI que les 10 tests existants sont restés verts avec les 8 neufs.
Les 8 tests neufs ont la forme qui compte
Témoin positif (ERROR → servi ET tracé), témoin négatif (FREE → servi, non tracé — « la moitié discriminante », exact), et le discriminant des deux cas ERROR : --no-check-claims et lane=None remplacent la sonde par une fonction qui lève AssertionError si elle est appelée — une contre-épreuve par mutation, pas un test qui se satisfied en ne testant rien. Trio tapis équivalent + paire rendu (visible / muet).
Résidu non bloquant
Les surfaces de câblage (les deux appels de print_claim_unread_report dans main, les deux blocs claim_signal du JSON) n'ont pas de test automatisé — les tests couvrent la plomberie d'état et la fonction de rendu, le body affirme des relances réelles sur la tête que je ne peux pas rejouer ici. Coût d'une régression sur ces 3 lignes de câblage : faible (une bannière absente), mais c'est la seule partie non pinnée.
CI au head : Scripts Tests (CPU) pass ; les organes rouges (grothendieck_umbrella — FileNotFoundError sur Grothendieck.lean absent du runner ; fastlane — relève du seul lake-direct-invocation-guard, garde Lean sans Lean dans cette PR ; secret_paths_ignored, non isolé) sont de la famille infra chemins/Lean qui rend rouge au même moment sur des PR sans rapport — pas causés par ce diff, qui ne touche que scripts/. Gitleaks positive controls fail = le canari du scanner, pas un finding (aucun secret dans les lignes ajoutées, subprocess en liste argv, aucun env injecté).
Ce que je n'ai pas vérifié : l'exécution des tests depuis ce siège (revue statique ; le pass CI ci-dessus couvre l'exécution) ; l'organe secret_paths_ignored en détail (non isolé dans le budget de ce cycle).
|
[ADJOINT PREFLIGHT] Dossier c2144-v2 (tooling picker : annonce du claim NON LU, fail-OPEN). Domaine non applicable. Lane tierce : myia-po-2027:CoursIA-2, PR po-2024:CoursIA-2. |
myia-ai-01
left a comment
There was a problem hiding this comment.
Approbation a la tete 970e6bc. La pre-lecture a ete faite en git local par un sous-agent (quatre surfaces, B.0 rc=0 (2 unevaluated: red-classification note + READY dossier)) ; j'ai relu les points pivots.
- Preuve et delta : Dossier READY at current head 970e6bc by myia-po-2027:CoursIA-2 (22:23Z). NanoClaw LGTM on pre-merge commit 7734022 (verified line-by-line, both paths, predicate asymmetry justified; residual: 3 lines of wiring without automated test - low cost, non-blocking). Head delta 7734022 -> 970e6bc = content-free merge of main (verified); dossier re-stamped at new head. Gate verified now: 20 jambes all success (PR gate 21:39Z).
Grain: MED/tooling — lane myia-po-2024:CoursIA-2 — prev: MED/guard #20131
Closes #20265. Part of #17038.
Le defaut, et ce qui est ajoute
Le tirage servait deja un candidat dont la lecture de claim n'avait pas abouti — c'est la bonne doctrine (refuser un grain faute d'avoir pu verifier son claim fabriquerait un faux BLOQUE). Ce qui manquait est l'autre moitie, deja ecrite pour l'organe voisin
check_unaddressed_nits: le picker tire quand meme, mais le DIT.Cette PR n'inverse pas le fail-OPEN. Elle ajoute la phrase qui le rend visible, sur les deux chemins et sur les deux surfaces de sortie.
--belt)code in (ERROR, UNCHECKED)→ servi, muetstate["claim_unread"]porte le numeroverdicts.get(n, (ERROR, ""))→ servi, muetSortie humaine, juxtaposee a la ligne de livraison existante :
Sortie
--json, cle dediee distincte des picks et des conflits :Les deux surfaces ont ete relancees pour de vrai sur cette tete (voir Preuves) — pas seulement lues dans le diff.
La distinction qui fait la correction
Le repli
ERRORsert deux cas opposes, et les confondre etait le piege principal :--no-check-claims, tirage sans lane) qui laisseverdictsvide → rien n'a ete mesure, et une banniere y serait une fausse alerte a chaque tirage sans lane.probes_attemptedexiste pour separer les deux : sans elle,"unread": []se lirait « toutes les lectures ont abouti » alors qu'il peut vouloir dire « aucune lecture n'a ete tentee ».Ce que l'issue annoncait comme contrainte, et qui ne l'est pas
L'issue previent :
Mesure : ce n'est pas le meme dict.
continuity_stateest un parametre distinct, ecrit une seule fois (continuity_state["used"] = True,pick_idle_grain.py:2390) ; lestateinterne dedraw_unclaimed(delivered_statea l'appel) est une autre liaison (:2229). Les deux asserts des lignes 91 et 121 portent sur lecontinuity_statedu test, que cette PR ne touche pas : aucun test existant n'est passe au rouge. La trace est posee surstate/delivered_state, la ou le cycle de vie du tirage la porte.La crainte etait raisonnable — elle nommait un vrai piege de nommage — mais elle aurait fait chercher le probleme au mauvais endroit. Le dire ici evite que le prochain lecteur refasse le diagnostic.
Preuves
Tests.
python -m pytest scripts/tests/test_pick_claim_filter.py -q→ 18 passed (10 existants inchanges + 8 neufs).python -m pytest scripts/tests/test_pick_idle_grain_belt.py -q→ 52 passed.Temoin discriminant, prouve par mutation (acceptance 3) — le test ne vaut que par sa contre-epreuve, donc les trois mutations sont tuees et nommees :
test_sonde_qui_aboutit_en_free_ne_trace_rien,test_controle_non_demande_ne_declenche_pas_de_fausse_alertetest_lecture_de_claim_en_echec_est_servie_mais_tracee,test_tapis_trace_la_lecture_de_claim_en_echectest_le_rapport_est_muet_sans_lecture_rateeSource restauree byte-identique apres chaque mutation (
cmp), puis suite re-verte.Surfaces JSON, relancees (acceptance 2),
--ignore-redpour sortir de la file de reparation de la lane :{"probes_attempted": true, "unread": []}, a cote dedelivered_signal— JSON valide ;{"probes_attempted": true, "unread": []}— JSON valide.Les deux chemins (acceptance 4) : couverts tous les deux, chacun par sa paire temoin positif / temoin negatif, plus le cas « sans lane ».
Ce que cette PR ne fait pas
ERROR.🤖 Generated with Claude Code