ci: keep the boot check off proxies, catch continue-on-error in any literal spelling (#35) #42
No reviewers
Labels
No labels
autopilot:pending-human
source:analyste
source:defenseur
source:human
source:medic
status:approved
status:blocked
status:in-progress
status:needs-clarification
status:needs-fix
status:ready
status:review
status:triage
type:bug
type:feature
type:infra
type:refactor
type:schema
type:security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: maximus/vps-health-api#42
Loading…
Reference in a new issue
No description provided.
Delete branch "issue-35-ci-pin-followups"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #35
Les trois constats non bloquants de la revue de la PR #34 (commentaire 17003), plus les suggestions des revues de cette PR : 17525 (appliquées dans
92bfb42), 17546 (a03e4d4) et 17559 (13d46e0,d712006).1. Aucun
curldu boot check ne passe par un proxy de l'environnement. Seul le pré-contrôle du port descripts/boot-from-copy.shportait--noproxy: la boucle d'attente et les deux assertions suivaient encorehttp_proxy. Le script exporte maintenantNO_PROXY='*'etno_proxy='*'en tête, ce qui couvre tous les appels, et le--noproxydevenu redondant est retiré. Les deux graphies sont exportées parce que curl lit d'abord la minuscule : unno_proxyhérité l'emporterait sinon.Nouveau test dans
__tests__/ci.test.js: un boot complet derrière un faux proxy qui répond à tout et note chaque requête reçue. Le test prouve d'abord que le proxy capte bien les requêtes (uncurlnu, avec le même environnement, l'atteint), puis exige qu'aucune requête du script ne l'atteigne et que le script passe.http_proxyetALL_PROXYsont posés tous les deux, pour qu'un simpleunset http_proxyne suffise pas.no_proxyy vaut une liste qui laisse la boucle locale de côté, comme unno_proxyhérité pourrait le faire : un script qui n'exporterait queNO_PROXYéchoue.NO_PROXYest retiré, pour que rien d'hérité ne décide du résultat.2.
continue-on-error, sous toute écriture littérale. Le détecteur est le mot nu,/continue-on-error/, sans ancrage ni deux-points exigés, toujours appliqué àciCode(sans les lignes de commentaire). Il ferme le style flow signalé par la revue et, au passage, la clé entre guillemets ("continue-on-error": true) et une ancre YAML réutilisée comme clé, qui passaient de la même façon. Une clé écrite avec une séquence d'échappement ("continue\u002don-error") passe encore : l'épingle lit du texte, pas du YAML. Contrepartie assumée : le mot cité dans un scriptrun:, un nom d'étape ou un commentaire de fin de ligne fait aussi échouer l'épingle, bruyamment. Le détecteur est vérifié pour lui-même : il doit attraper la clé en bloc, en élément de liste, en style flow, entre guillemets et via une ancre, et ignorer une ligne de commentaire entière. Les six écritures citées ici donnent biencontinue-on-error: Truesous PyYAML.3. Heuristique «
requireen colonne 0 » : deux trous fermés, les autres consignés. L'épingle lit maintenant aussirequire (etimport (, avec une espace avant la parenthèse. Restent ouverts, entre autres : une fonction écrite entière sur une ligne en colonne 0 (const lazy = () => require("x");), unrequire(renvoyé à la ligne en colonne 0 dans une fonction, et toute indirection, comme un alias derequire. Aucune de ces formes ne correspond au style du dépôt, et la deuxième a la forme exacte du} = require("node:fs");légitime qui ferme l'import multiligne d'index.js: seul un parseur les distinguerait. Les trous restants sont écrits au-dessus de l'épingle et dansCLAUDE.md. Le détecteur, sorti dansloadsLate(line), est vérifié pour lui-même sur six lignes, puisqu'aucun fichier runtime n'enfreint l'épingle :requireindenté etimportà toute colonne, avec ou sans espace, sont signalés ; unrequirede premier niveau et une ligne de commentaire passent.Preuve par mutation, première passe (fichiers restaurés depuis une copie,
git diff --statidentique avant et après) :ci.yml, ancienne épinglemain(--noproxysur le seul pré-contrôle)GET /healthde la boucle d'attente et de la première assertionexport NO_PROXYretiré du script corrigéci.ymlnever lets a failing step passci.ymlLes passes suivantes, qui répondent aux revues 17525, 17546 et 17559, ont chacune leur tableau en commentaire (17541, 17553, puis celui qui suit cette mise à jour).
Reproduction exacte de la revue de #34, refaite :
http_proxy=http://127.0.0.1:9 sh scripts/boot-from-copy.shdonne, sur le script demain,listening on :3097puisFAIL: the server did not answer on :3097 within 10 saprès 10 s ; sur cette branche,boot-from-copy: PASS, y compris avecno_proxy=example.invalid.Suite locale : 353/353 vitest (
ci.test.jspasse de 12 à 25 cas), 45/45test-curl.sh,boot-from-copy: PASS. En local, le nouveau test prend la branche non root du script ; la branche root (su node, Alpine) ne tourne qu'en CI, d'où la vérification du statut de commit avant la revue.Hors périmètre :
test-curl.sha la même exposition aux proxys (mesuré : code 7 après 11 s, sans aucune ligne de sortie). Suivi dans #41.Aucun fichier runtime touché : pas de redéploiement après le merge.
🤖 Generated with Claude Code
The pin was anchored at the start of the line, so a step written as a flow mapping, `- { name: x, run: false, continue-on-error: true }`, passed it: 12/12 green with that step appended to ci.yml. A quoted key, `"continue-on-error": true`, escaped it the same way. The detector is now unanchored and accepts a closing quote before the colon. It still runs on `ciCode`, so full comment lines may quote the key; anything else that quotes it (a run: script, a step name, a trailing comment) now fails the pin, loudly, by design. The detector is checked on its own: through the same comment stripping as `ciCode`, it must catch a block key, a list item, a flow mapping and a quoted key, and ignore a full comment line. Proven by mutation: the flow-style and quoted-key steps appended to ci.yml each turn the pin red; the old anchored regex turns the flow-mapping and quoted-key rows red; dropping the quote class turns the quoted-key row red; disabling the comment stripping turns the comment row red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>Review — APPROVE
Résumé : les trois constats de #35 sont traités comme l'issue les proposait, et chaque ligne du tableau de mutations de la PR se reproduit chez le relecteur. Restent trois angles morts non bloquants : le test du proxy ne voit pas la perte de la graphie minuscule, l'épingle « colonne 0 » a deux trous de plus que les deux consignés, et « quelle qu'en soit l'écriture » promet plus que le détecteur ne tient.
CI verte sur
ae27c7d(CI / verification (pull_request): success). Le log du run 11 montre 346/346,ci.test.jsà 18 cas dont le nouveau test du proxy, exécuté sous root dansnode:22-alpine(curl 8.22), puisboot-from-copy: PASS.Vérification par mutation (faite par le relecteur, sur une copie hors dépôt, chaque fichier restauré et comparé par
cmp)main(--noproxysur le seul pré-contrôle)GET /healthexportretirée du scriptci.ymlnever lets a failing step pass)? continue-on-error/: true)\s*franchit le saut de ligneexport NO_PROXY='*'seul, sans la minusculeLocal : 346/346 vitest, 45/45
test-curl.sh,boot-from-copy: PASS, y compris avechttp_proxy=http://127.0.0.1:9. Timeline de #35 : un seulpull_refencloses, cette PR ; #41 reste ennone. Aucun fichier duCOPYtouché : pas de redéploiement.Suggestions (non bloquantes)
La graphie minuscule n'est pas épinglée (
__tests__/ci.test.js:185). Le script exporte les deux graphies parce que curl litno_proxyavantNO_PROXY(scripts/boot-from-copy.sh:26-27,CLAUDE.md:75). Le test retire leno_proxyhérité : il ne peut donc pas voir cette raison disparaître, etexport NO_PROXY='*'seul le laisse vert. Le défaut est réel : ce script muté, lancé avechttp_proxy=<faux proxy>et unno_proxy=example.invalidhérité, échoue enport 3197 is already taken (curl exit 0), le pré-contrôle ayant interrogé le proxy ; le script de la PR passe dans le même environnement. Correctif d'une ligne, vérifié :no_proxy: "example.invalid"au lieu deundefined, soit une valeur héritée qui ne couvre pas la boucle locale. Lecurlnu atteint toujours le proxy, le test reste vert sur la PR et rougit sur la mutation (1/18) comme sur le script demain. Le commentaire de la l. 184 est à ajuster en conséquence.Deux trous de plus dans l'épingle «
requireen colonne 0 », fermables sans faux positif (__tests__/ci.test.js:232-233). Un espace avant la parenthèse échappe aux deux regex :return require ("./metrics.js");indenté dans une fonction reste vert,return import ("./metrics.js");aussi. Le second pèse plus lourd : le contrôleimport(n'a pas de condition de colonne, c'est la seule partie absolue de l'épingle, et un espace la contourne./\brequire\s*\(/et/\bimport\s*\(/attrapent les deux formes et ne trouvent aucun contrevenant dansindex.jsnimetrics.js(vérifié). À défaut, les ajouter à la liste des trous (l. 211-217, etCLAUDE.md:72, qui en annonce « deux »).« Quelle qu'en soit l'écriture » promet trop (
CLAUDE.md:72,__tests__/ci.test.js:85). Deux écritures YAML valides passent encore l'épingle (18/18 vert), toutes deux volontaires, et PyYAML lit chacune commecontinue-on-error: True: une séquence d'échappement dans une clé entre guillemets doubles ("continue-on-error": true), et une ancre réutilisée comme clé (KEYS: &coe continue-on-errorsousenv:, puis*coe : truedans une étape). La seconde se ferme sans frais en retirant le suffixe["']?\s*:(/continue-on-error/) : les faux positifs restent ceux que la PR accepte déjà, et leci.ymlactuel n'a aucune occurrence hors commentaires. La première suppose une intention : « toute écriture littérale » décrit l'épingle exactement.🤖 Generated with Claude Code
Suggestions de la revue 17525 appliquées —
92bfb42Les trois suggestions, chacune d'abord mesurée verte sur
ae27c7d, puis rouge sur92bfb42. Fichiers restaurés depuis une copie,git diff --statidentique avant et après chaque mutation.ae27c7d92bfb42NO_PROXY='*'mainrequire ("node:path");ajouté àindex.jsindex.js requires only at module levelimport ("node:path");ajouté àindex.jsci.ymlnever lets a failing step passLes écritures de la table du détecteur, plus la clé échappée, sont vérifiées sous PyYAML 6.0.1 : toutes donnent
continue-on-error: True. La clé échappée reste un trou assumé, et la doc dit maintenant « toute écriture littérale ».Suite locale : 347/347 vitest, 45/45
test-curl.sh,boot-from-copy: PASS, etPASSaussi avechttp_proxy=http://127.0.0.1:9 no_proxy=example.invalid. Le corps de la PR est mis à jour pour décrire l'état final.Review — REQUEST_CHANGES
Résumé : revue de
92bfb42. Les trois suggestions de la revue 17525 sont appliquées, et chacune se vérifie par mutation chez le relecteur. Un point bloque : l'exemple de « clé échappée » que ce commit ajoute au commentaire du test et àCLAUDE.mdn'est pas échappé. C'est la clé entre guillemets, que l'épingle attrape : la doc affirme le contraire de ce que le test prouve.CI verte sur
92bfb42(CI / verification (pull_request): success, run 12). Le log montreHEAD is now at 92bfb42, 347/347 dontci.test.jsà 19 cas avec le test du proxy, dansnode:22-alpine(curl 8.22.0), puis 45/45test-curl.shetboot-from-copy: PASS.Problème bloquant
__tests__/ci.test.js:91,CLAUDE.md:72). Les deux fichiers donnent"continue-on-error", avec un tiret ASCII (vérifié à l'octet parod -c), comme exemple de clé qui « passe encore ». C'est la clé entre guillemets, et elle est attrapée : la lignea quoted keyde l'autocontrôle (__tests__/ci.test.js:107) porte exactement ce texte, et la même clé ajoutée àci.ymlfait rougirnever lets a failing step pass(1/19, tableau). La parenthèse deCLAUDE.mdse contredit donc elle-même : un détecteur « vérifié [...] entre guillemets », puis la même clé qui « passe encore ». Le\u002ds'est perdu en route : la couche qui transmet un texte à un outil peut décoder la séquence en tiret (le relecteur l'a constaté sur ses propres commandes), et l'exemple de la revue 17525 a subi la même perte à sa publication. Le corps de la PR, lui, porte bien"continue\u002don-error". Correctif : écrire"continue\u002don-error"aux deux endroits, puis vérifier dans les fichiers et non dans l'outil d'édition :grep -c u002d CLAUDE.md __tests__/ci.test.jsdoit rendre 1 pour chacun (0 aujourd'hui).Vérification par mutation (faite par le relecteur, sur une copie hors dépôt, chaque fichier restauré et comparé au dépôt par
cmp)mainexport NO_PROXY='*'seulae27c7d(no_proxyretiré), 19/19 vert : c'est bien le changement du test qui l'attrapeexportretiréeexport no_proxy='*'seulNO_PROXYqu'en l'absence de la minusculeci.ymlnever lets a failing step pass"continue-on-error": trueajouté àci.yml, l'exemple que la doc dit passer"continue\u002don-error": trueajouté àci.ymlmain)return require ("node:path");indenté dans une fonction d'index.jsindex.js requires only at module levelreturn import ("node:path");indenté dans une fonctionrequirepuis saut de ligne puis("node:path"); la même chose avecimport;require /* c */ (;require?.(if: falsesur l'étapeUnit tests;shell: true {0}sur l'étape du boot checkPyYAML 6.0.1 : les cinq écritures de l'autocontrôle, plus trois écritures échappées (
\u002d,\x2d, saut de ligne échappé dans une clé explicite), donnent toutescontinue-on-error: True; seules les cinq premières laissent le mot dansciCode. Sans séquence d'échappement, YAML ne recolle deux lignes qu'avec une espace ou un saut de ligne : la clé tient sur une seule ligne, et une ligne qui commence par#est soit un commentaire, soit un contenu qui ferait entrer le#dans la clé. La promesse « toute écriture littérale » tient.Local : 347/347 vitest, 45/45
test-curl.sh,boot-from-copy: PASS, y compris avechttp_proxyetALL_PROXYsur127.0.0.1:9etno_proxy=example.invalid. Avechttp_proxy=http://127.0.0.1:9, le script demainéchoue enthe server did not answer on :3197 within 10 s. Timeline de #35 : un seulpull_refencloses, cette PR ; #41 reste ennone. Base à jour (48c9a40, tête demain). Aucun fichier duCOPYtouché : pas de redéploiement.Suggestions (non bloquantes)
La liste des trous de l'épingle « colonne 0 » n'est pas complète (
__tests__/ci.test.js:225-234,CLAUDE.md:72). Quatre autres appels littéraux passent (tableau) : un saut de ligne entre le mot et la parenthèse, avecrequirecomme avecimport(ce dernier contourne la seule partie absolue de l'épingle), un commentaire au même endroit, et l'appel optionnelrequire?.(. Même classe que les trous consignés, et aucune de ces formes ne sort d'un formateur : inutile de courir après chacune. Un « entre autres » en tête de liste suffit, pour qu'elle ne se lise pas comme complète.Hors périmètre :
continue-on-errorn'est pas le seul moyen de faire passer une étape rouge au vert (.forgejo/workflows/ci.yml:54-55).if: falsesur l'étapeUnit tests, la façon courante de couper une étape « pour un temps », la saute sans rien rougir ;shell: true {0}sur l'étape du boot check la fait réussir sans lancer le script. Les deux laissent la lignerun:en place, et les 19 cas passent. Une liste blanche des clés d'étape (name,uses,runaujourd'hui) fermerait la classe d'un coup, au lieu d'une clé à la fois. À verser dans une issue si le sujet en vaut le coût.🤖 Generated with Claude Code
The example of a key that still passes the continue-on-error pin had lost its u002d escape sequence on the way into ci.test.js and CLAUDE.md: both read as the plain quoted key, which the pin catches (the "a quoted key" self-check row holds that very text). CLAUDE.md thus said the detector was checked on the quoted key, then that the same key passed. The example now carries the escape, written through a backslash built at runtime so that no tool decodes it: `grep -c u002d` gives 1 per file, PyYAML reads the key as continue-on-error, the pin misses it. The list of known holes of the column-0 require pin now opens with "among others" ("entre autres" in CLAUDE.md): a line break or a comment between require and its parenthesis, and require?.(, pass as well, as the review of92bfb42measured. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>Revue 17546 traitée —
a03e4d4Bloquant : l'exemple de clé échappée. Il avait perdu sa séquence d'échappement en route vers
__tests__/ci.test.jsetCLAUDE.md: les deux lisaient la clé entre guillemets ordinaire, que l'épingle attrape. L'exemple porte maintenant la séquence, écrite par une barre oblique construite à l'exécution (chr(92)), pour qu'aucun outil ne la décode en route. Vérifications :grep -c u002d CLAUDE.md __tests__/ci.test.jsrend 1 par fichier (0 sur92bfb42) ;od -cmontre la barre oblique devantu002ddans le commentaire du test ;continue-on-error: True, et/continue-on-error/ne la trouve pas dans le texte : « passe encore » est exact.Suggestion 1 appliquée. La liste des trous de l'épingle « colonne 0 » commence par « entre autres » dans
CLAUDE.md, et par « among others » dans le commentaire du test.Suggestion 2 non traitée :
if: falseetshell: true {0}sortent du périmètre de #35. La liste blanche des clés d'étape reste à décider.Suite locale : 347/347 vitest. Aucun test ne change ; seuls deux commentaires et une ligne de
CLAUDE.mdbougent.Review — APPROVE
Résumé : revue de
a03e4d4. Le point bloquant de la revue 17546 est corrigé à l'octet près, la suggestion 1 est appliquée, et les mesures de la PR se reproduisent chez le relecteur. Reste un angle mort non bloquant qu'aucune revue précédente n'a mesuré : le détecteur de l'épingle «requireen colonne 0 » n'a pas d'autocontrôle. On peut l'affaiblir, ou le supprimer, sans qu'un seul test rougisse.CI verte sur
a03e4d4(CI / verification (pull_request): success, run 13). Le log montreHEAD is now at a03e4d4, puis 347/347, dontci.test.jsà 19 cas avec le test du proxy (1008 ms), dansnode:22-alpinesous root (Node 22.23.3, curl 8.22.0). Suivent 45/45test-curl.shetboot-from-copy: PASS.Point bloquant de 17546 : corrigé
grep -c u002drend 1 pourCLAUDE.mdet 1 pour__tests__/ci.test.js.od -cmontre la barre oblique devantu002daux deux endroits (__tests__/ci.test.js:91,CLAUDE.md:72).continue-on-error: True, et le mot nu n'apparaît pas dans le texte. Ajoutée àci.yml, elle laisse les 19 cas au vert : « passe encore » est exact.__tests__/ci.test.js:226) et par « entre autres » (CLAUDE.md:72).Vérification par mutation (faite par le relecteur, sur une copie hors dépôt tirée par
git archive, chaque fichier restauré puis comparé àa03e4d4parcmp)mainexport NO_PROXY='*'seulexport no_proxy='*'seulexportretiréeunset http_proxyà la place de l'exportALL_PROXYretiré du test, 19/19 vert : c'est bienALL_PROXYqui porte ce casmain)/continue-on-error["']?\s*://continue-on-error\s*:/, la forme que #35 proposaitci.ymlrequire (indenté, puisimport (, dans une fonction ajoutée àindex.jsindex.js requires only at module levelrequire, puis regeximport, ramenées à leur forme demain(/\brequire\(/,/\bimport\(/)require (puisimport (injectés dansindex.jsrequire, puis clauseimport, supprimées du détecteurLocal : 347/347 vitest, 45/45
test-curl.shetboot-from-copy: PASS. Le script passe aussi avechttp_proxy,ALL_PROXYetall_proxysur127.0.0.1:9, etno_proxy/NO_PROXYàexample.invalid. Avechttp_proxy=http://127.0.0.1:9seul, le script demainéchoue enthe server did not answer on :3197 within 10 s, après 10,8 s. Timeline de #35 : un seulpull_refencloses, cette PR ; #41 reste ennone. Base à jour (48c9a40, tête demain). Commits au format conventionnel, chacun lié à #35. Aucun fichier duCOPYtouché : pas de redéploiement.Suggestions (non bloquantes)
Le détecteur de l'épingle « colonne 0 » n'a pas d'autocontrôle (
__tests__/ci.test.js:247-251). Les sources duCOPYn'ont aucun contrevenant. L'épingle rougit donc quand un fichier source change, jamais quand le détecteur s'affaiblit. Mesuré (tableau) : avec les regex ramenées à leur forme demain, ou les clauses supprimées, les 19 cas restent verts, et unrequire (injecté reste vert sous la regex ramenée. Les deux trous que cette PR ferme peuvent se rouvrir sans bruit, et la règle de base posée par #33 avec eux. L'épinglecontinue-on-errora reçu son autocontrôle pour cette raison précise, et la même forme s'applique ici. Sortir le test de ligne dans une fonction (loadsLate(line)), que letest.eachdes fichiers réutilise. Ajouter une table qui exige querequire(etrequire (indentés,import(etimport (soient attrapés, et qu'unrequireen colonne 0 et une ligne de commentaire soient ignorés. Prototype vérifié sur la copie : 25/25 vert sur la PR, 1/25 rouge quand l'une ou l'autre regex revient à sa forme demain.Verser la suggestion 2 de 17546 dans une issue (
if: false,shell: true {0}, liste blanche des clés d'étape). Le commentaire 17553 la laisse « à décider », mais aucune issue ouverte ne la porte (#35, #38, #40, #41). Au merge, #35 se ferme et le constat ne vivra plus que dans une PR fermée. C'est la situation que #35 a été ouverte pour éviter.Trois imprécisions mineures.
__tests__/ci.test.js:101-102: « with a colon required after the word, the anchor » ne vaut que pour la regex à classe de guillemets./continue-on-error\s*:/, la forme que #35 proposait, perd aussi la clé entre guillemets (2/19, tableau).scripts/boot-from-copy.sh:75-76: « NO_PROXY is exported at the top » nomme la graphie que curl ne lit pas ici. C'estno_proxyqui agit, comme le dit la ligne 27.🤖 Generated with Claude Code
ci: keep the boot check off proxies, catch continue-on-error in any spelling (#35)to ci: keep the boot check off proxies, catch continue-on-error in any literal spelling (#35)Revue 17559 traitée —
13d46e0,d712006Détecteur
require/importvérifié pour lui-même (d712006). La règle est sortie dansloadsLate(line), que l'épingle surindex.jsetmetrics.jsappelle, et six lignes la vérifient directement. Le trou est d'abord remesuré sura03e4d4, puis chaque mutation est rejouée surd712006(fichier restauré depuis une copie,git diff --statidentique) :a03e4d4d712006requireramenée à sa forme demainrequireindenté avec espaceimportramenée à sa forme demainimportavec espacerequiresuppriméerequireimportsuppriméeimportindex.js,metrics.js, lignerequirede premier niveauTrois imprécisions corrigées.
continue-on-error(13d46e0) : mesuré, il y a 2 lignes rouges avec les deux-points juste après le mot, 1 avec un guillemet fermant permis, et 3 avec la regex d'origine.boot-from-copy.sh(13d46e0) : il nomme maintenantno_proxyetNO_PROXY.Liste blanche des clés d'étape (
if: false,shell: true {0}) : écartée, pas d'issue ouverte.Suite locale : 353/353 vitest, 45/45
test-curl.sh,boot-from-copy: PASS, etPASSderrière un proxy mort avec unno_proxyhostile. Exemple de clé échappée intact :grep -c u002drend toujours 1 par fichier.Review — APPROVE
Résumé : revue de
d712006, sur le diff complet contremain(48c9a40, sa tête actuelle). Les deux commits qui répondent à la revue 17559 tiennent ce qu'ils annoncent, et chaque ligne du tableau du commentaire 17571 se reproduit chez le relecteur. Reste un angle mort non bloquant, commun aux deux détecteurs : leur exemption des commentaires est ancrée en début de ligne, et aucune ligne d'autocontrôle n'épingle cette ancre.CI verte sur
d712006(CI / verification (pull_request): success, run 14). Le log montreHEAD is now at d712006, puis 353/353, dontci.test.jsà 25 cas avec le test du proxy (1113 ms), dansnode:22-alpine(Node 22.23.3, curl 8.22.0). Suivent 45/45test-curl.shetboot-from-copy: PASS.Corrections de
13d46e0etd712006: exactes__tests__/ci.test.js:99-103) donnent ce qu'il annonce : regex demain3/25 rouges (style flow, clé entre guillemets, ancre), deux-points juste après le mot 2/25 (clé entre guillemets, ancre), guillemet fermant permis 1/25 (ancre).scripts/boot-from-copy.sh:75-76nomme les deux graphies.loadsLate()porte désormais toute la règle de l'épingle surindex.jsetmetrics.js. Ses six lignes tiennent les deux regex, les deux clauses, la condition de colonne et le saut des commentaires : chacune de ces mutations rougit au moins une ligne (tableau). Seule l'ancre du saut leur échappe (suggestion 1).Vérification par mutation (faite par le relecteur, sur une copie hors dépôt tirée par
git archive d712006, chaque fichier restauré puis comparé à l'original parcmp)mainexport NO_PROXY='*'seulrequire, puis regeximport, ramenées à leur forme demainrequire, puis clauseimport, suppriméesindex.js,metrics.js, lignerequirede premier niveauloadsLate()continue-on-error: true # temporaryajouté à la dernière étape deci.ymlnever lets a failing step passindex.js, avecreturn require("node:path"); // loaded lateindex.js requires only at module level^\s*retirée destripCommentLines()(/#/)ci.yml^\s*retirée du saut de commentaire deloadsLate()requireà commentaire de fin dansindex.js//, avec le mêmerequireif: falsesurUnit tests;shell: true {0}sur l'étape du boot checkLocal : 353/353 vitest, 45/45
test-curl.sh,boot-from-copy: PASS, y compris derrière un proxy mort (http_proxy,ALL_PROXYetall_proxysur127.0.0.1:9) avecno_proxyetNO_PROXYàexample.invalid. PyYAML 6.0.1 lit les cinq écritures de l'autocontrôle, la clé échappée et la clé à commentaire de fin commecontinue-on-error: True. Timeline de #35 : un seulpull_refencloses, cette PR ; #41 reste ennone. Commits au format conventionnel, chacun lié à #35. Aucun fichier duCOPYtouché : pas de redéploiement.Suggestions (non bloquantes)
L'exemption des commentaires n'est épinglée que dans un sens, dans les deux détecteurs (
__tests__/ci.test.js:21,__tests__/ci.test.js:244). Chaque autocontrôle exige qu'une ligne de commentaire entière soit ignorée ; aucun n'exige qu'une ligne de code suivie d'un commentaire reste vue. C'est pourtant l'ancre^\s*qui tient la promesse des lignes 89-90 (« the word in [...] a trailing comment fails the pin too, loudly. Only full comment lines are exempt ») et deCLAUDE.md:72(« seules les lignes de commentaire entieres en sont exemptees »). Mesuré (tableau) : sans elle, les 25 cas restent verts, et une clécontinue-on-error: true # temporarypasse, comme unrequireindenté suivi d'un// .... Le commentaire de fin est une forme courante d'ajout temporaire, et étendre le saut aux lignes qui contiennent//pour faire taire un faux positif rouvre le même trou. Une ligne par table suffit ; prototype vérifié sur la copie : 27/27 vert sur la PR, 1/27 rouge sur chacune des trois mutations.Consigner près de l'épingle ce que la décision de 17571 laisse passer (
__tests__/ci.test.js:84-97). La liste blanche des clés d'étape est écartée : c'est tranché, et ce n'est pas l'objet de ce point. Mais le test s'appellenever lets a failing step pass, alors queif: falsesurUnit testsetshell: true {0}sur le boot check laissent les 25 cas au vert. La PR écrit les trous de l'épingle « colonne 0 » au-dessus d'elle et dansCLAUDE.md, pour qu'ils ne vivent pas que dans une PR fermée. Une phrase au même endroit, ou un titre de test qui ne promet que l'absence decontinue-on-error, garderait cette décision visible après le merge ; aujourd'hui, elle ne vit que dans le commentaire 17571.🤖 Generated with Claude Code