docs: REVIEW.md with review levels and a calibration script (#63) #65

Merged
maximus merged 5 commits from infra/review-md-63 into main 2026-10-20 00:27:04 +00:00
Owner

Fixes #63

Ce que la PR ajoute

  • REVIEW.md, sur le modèle de simpl-resultat : niveaux (tableau Haut avec conditions, Bas, Normal, Calibration), règles par zone avec leur source (routage et auth, surfaces d'écriture et montages, contrats servis au dashboard, image et démarrage, agents du poste, CI et gardes), commandes de vérification, pièges de revue.
  • scripts/review-levels.py, adapté de simpl-resultat : rejoue les niveaux sur les PR intégrées et offre --check (sans réseau).
  • CLAUDE.md : la section « Deploy » disait « Pas d'auto-deploy ». C'est faux depuis le 2026-10-12 (hook Forgejo id 9, coolify-ops.md) : le merge est le déploiement, en même temps que la CI du push et sans l'attendre. Corrigé, plus un renvoi vers REVIEW.md (nouvelle section « Documents de reference »).

Sources récoltées

CLAUDE.md, agent/README.md, la-compagnie-maximus/docs/{coolify,forgejo}-ops.md, en-tête de ci.yml, épingles des tests, et les blocages des revues passées : #39 (garantie d'écriture plus large que la couverture), #42 (exemple de clé échappée décodé), #45 (wait_for et un port voisin), #51 (seuil de scan qui vidait des jours ouverts), #59 (trois passes : la rotation pouvait vider la copie hors site).

Calibration

Ensemble : les 31 PR dont la tête a atteint main (#2 à #62), liste figée dans le script. Forgejo marque « fermées » les PR d'une pile intégrée en avance rapide (#18 à #23, #31, #34, #37). /pulls/{n}/files répond 500 quand leur base a disparu, donc le script lit la liste des fichiers dans le .diff. Trois PR ont un .diff vide parce que leur merge_base vaut leur tête (#18, #31, #34) : elles sont lues dans le clone local.

python3 scripts/review-levels.py :

#2	haut	index.js (side effect)
#5	normal	
#6	haut	test-curl.sh (added at top level)
#8	normal	
#9	haut	index.js (routing or auth); index.js (side effect); package-lock.json; package-lock.json (added at top level); package.json; vitest.config.js; vitest.config.js (added at top level)
#18	haut	Dockerfile; index.js (side effect); metrics.js (added at top level); metrics.js (side effect)
#19	normal	
#20	haut	index.js (routing or auth); index.js (side effect)
#21	normal	
#22	haut	agent/push-metrics.js; agent/run-push.sh
#23	haut	__tests__/auth.test.js (existing line changed); agent/run-push.sh
#26	normal	
#28	haut	__tests__/auth.test.js (existing line changed); index.js (routing or auth)
#30	haut	index.js (routing or auth)
#31	haut	.forgejo/workflows/ci.yml; scripts/boot-from-copy.sh
#34	haut	scripts/boot-from-copy.sh
#37	haut	index.js (routing or auth); index.js (side effect)
#39	normal	
#42	haut	scripts/boot-from-copy.sh
#43	normal	
#44	haut	__tests__/writes.test.js (existing line changed)
#45	normal	
#47	normal	
#51	normal	
#52	haut	Dockerfile; __tests__/auth.test.js (existing line changed); __tests__/writes.test.js (existing line changed); claude-usage.js (added at top level); claude-usage.js (side effect); index.js (routing or auth); index.js (side effect)
#53	haut	agent/claude-usage/limits.js; agent/claude-usage/push-claude-usage.js; agent/claude-usage/run-claude-usage.sh
#56	haut	agent/claude-usage/limits.js; agent/claude-usage/push-claude-usage.js; index.js (side effect)
#57	haut	Dockerfile; __tests__/writes.test.js (existing line changed); claude-usage-history.js (added at top level); claude-usage-history.js (side effect); index.js (routing or auth)
#59	haut	agent/pg-backup-pull/maximus-pg-backup-pull.service; agent/pg-backup-pull/maximus-pg-backup-pull.timer; agent/pg-backup-pull/run-pg-backup-pull.sh
#60	haut	Dockerfile; backups.js (added at top level); backups.js (side effect); index.js (routing or auth); index.js (side effect)
#62	normal	
31 PRs: {'bas': 0, 'normal': 11, 'haut': 20} -> haut 64.5 %

python3 scripts/review-levels.py --check :

ok: 18 patterns, identical to the Haut table of REVIEW.md

Il échoue (code 1) quand on retire un motif d'un côté. Vérifié en renommant Dockerfile dans le tableau (REVIEW.md only: Dockerfil / script only: Dockerfile), puis en supprimant la ligne .gitignore (script only: .gitignore).

65 % de PR hautes, pour une cible de 20 %. C'est voulu. L'historique est celui de la construction des surfaces sensibles (quatre tokens, trois routes d'écriture, deux agents qui tiennent un secret ou la copie hors site), et chaque surface a été livrée par la PR qui l'a créée. Le merge part en production. Les PR qui étendent une surface existante, une route de lecture ou des tests restent normales (11). Deux resserrements faits pendant la calibration : __tests__/ci.test.js est sorti des gardes (le workflow et boot-from-copy.sh sont déjà hauts), et une lecture de process.env ou une ligne de journal ne suffisent plus à rendre haut un module livré. On est passé de 71 % à 65 %.

Vérification dans le worktree

  • npm ci && npm test : 13 fichiers, 879 cas verts
  • bash test-curl.sh : 57 passed, 0 failed
  • sh scripts/boot-from-copy.sh : PASS
  • aucune variable d'environnement à poser

Choix de Max (2026-10-19)

Consignés dans ### Calibration de REVIEW.md (commentaire 25657) :

  1. Le taux de 65 % est gardé.
  2. Une montée de version d'un paquet déjà présent reste normale.
  3. Les agents du poste restent toujours hauts.
  4. La liste des fichiers jamais bas est inchangée.
  5. Les gardes auth.test.js et writes.test.js sont hautes dès qu'une ligne existante change.
  6. Les nettoyeurs restent normaux.

Suggestions de la revue 25515 : 1, 2 et 3 sont appliquées (.claude/hooks/** haut, niveau bas restreint à **/*.md et LICENSE, déplacement vers dependencies classé haut). La 4 (rangement dans --check) est écartée. Les trois passes de /pr-review : 25498 (REQUEST_CHANGES, corrigé), 25515 et 25665 (APPROVE).

Prête à merger. Une fois mergé, les PR ouvertes seront jugées avec ces niveaux.

🤖 Generated with Claude Code

Fixes #63 ## Ce que la PR ajoute - `REVIEW.md`, sur le modèle de simpl-resultat : niveaux (tableau Haut avec conditions, Bas, Normal, Calibration), règles par zone avec leur source (routage et auth, surfaces d'écriture et montages, contrats servis au dashboard, image et démarrage, agents du poste, CI et gardes), commandes de vérification, pièges de revue. - `scripts/review-levels.py`, adapté de simpl-resultat : rejoue les niveaux sur les PR intégrées et offre `--check` (sans réseau). - `CLAUDE.md` : la section « Deploy » disait « Pas d'auto-deploy ». C'est faux depuis le 2026-10-12 (hook Forgejo id 9, `coolify-ops.md`) : **le merge est le déploiement**, en même temps que la CI du `push` et sans l'attendre. Corrigé, plus un renvoi vers `REVIEW.md` (nouvelle section « Documents de reference »). ## Sources récoltées `CLAUDE.md`, `agent/README.md`, `la-compagnie-maximus/docs/{coolify,forgejo}-ops.md`, en-tête de `ci.yml`, épingles des tests, et les blocages des revues passées : #39 (garantie d'écriture plus large que la couverture), #42 (exemple de clé échappée décodé), #45 (`wait_for` et un port voisin), #51 (seuil de scan qui vidait des jours ouverts), #59 (trois passes : la rotation pouvait vider la copie hors site). ## Calibration Ensemble : les 31 PR dont la tête a atteint `main` (#2 à #62), liste figée dans le script. Forgejo marque « fermées » les PR d'une pile intégrée en avance rapide (#18 à #23, #31, #34, #37). `/pulls/{n}/files` répond 500 quand leur base a disparu, donc le script lit la liste des fichiers dans le `.diff`. Trois PR ont un `.diff` vide parce que leur `merge_base` vaut leur tête (#18, #31, #34) : elles sont lues dans le clone local. `python3 scripts/review-levels.py` : ``` #2 haut index.js (side effect) #5 normal #6 haut test-curl.sh (added at top level) #8 normal #9 haut index.js (routing or auth); index.js (side effect); package-lock.json; package-lock.json (added at top level); package.json; vitest.config.js; vitest.config.js (added at top level) #18 haut Dockerfile; index.js (side effect); metrics.js (added at top level); metrics.js (side effect) #19 normal #20 haut index.js (routing or auth); index.js (side effect) #21 normal #22 haut agent/push-metrics.js; agent/run-push.sh #23 haut __tests__/auth.test.js (existing line changed); agent/run-push.sh #26 normal #28 haut __tests__/auth.test.js (existing line changed); index.js (routing or auth) #30 haut index.js (routing or auth) #31 haut .forgejo/workflows/ci.yml; scripts/boot-from-copy.sh #34 haut scripts/boot-from-copy.sh #37 haut index.js (routing or auth); index.js (side effect) #39 normal #42 haut scripts/boot-from-copy.sh #43 normal #44 haut __tests__/writes.test.js (existing line changed) #45 normal #47 normal #51 normal #52 haut Dockerfile; __tests__/auth.test.js (existing line changed); __tests__/writes.test.js (existing line changed); claude-usage.js (added at top level); claude-usage.js (side effect); index.js (routing or auth); index.js (side effect) #53 haut agent/claude-usage/limits.js; agent/claude-usage/push-claude-usage.js; agent/claude-usage/run-claude-usage.sh #56 haut agent/claude-usage/limits.js; agent/claude-usage/push-claude-usage.js; index.js (side effect) #57 haut Dockerfile; __tests__/writes.test.js (existing line changed); claude-usage-history.js (added at top level); claude-usage-history.js (side effect); index.js (routing or auth) #59 haut agent/pg-backup-pull/maximus-pg-backup-pull.service; agent/pg-backup-pull/maximus-pg-backup-pull.timer; agent/pg-backup-pull/run-pg-backup-pull.sh #60 haut Dockerfile; backups.js (added at top level); backups.js (side effect); index.js (routing or auth); index.js (side effect) #62 normal 31 PRs: {'bas': 0, 'normal': 11, 'haut': 20} -> haut 64.5 % ``` `python3 scripts/review-levels.py --check` : ``` ok: 18 patterns, identical to the Haut table of REVIEW.md ``` Il échoue (code 1) quand on retire un motif d'un côté. Vérifié en renommant `Dockerfile` dans le tableau (`REVIEW.md only: Dockerfil` / `script only: Dockerfile`), puis en supprimant la ligne `.gitignore` (`script only: .gitignore`). **65 % de PR hautes, pour une cible de 20 %.** C'est voulu. L'historique est celui de la construction des surfaces sensibles (quatre tokens, trois routes d'écriture, deux agents qui tiennent un secret ou la copie hors site), et chaque surface a été livrée par la PR qui l'a créée. Le merge part en production. Les PR qui étendent une surface existante, une route de lecture ou des tests restent normales (11). Deux resserrements faits pendant la calibration : `__tests__/ci.test.js` est sorti des gardes (le workflow et `boot-from-copy.sh` sont déjà hauts), et une lecture de `process.env` ou une ligne de journal ne suffisent plus à rendre haut un module livré. On est passé de 71 % à 65 %. ## Vérification dans le worktree - `npm ci && npm test` : 13 fichiers, 879 cas verts - `bash test-curl.sh` : 57 passed, 0 failed - `sh scripts/boot-from-copy.sh` : PASS - aucune variable d'environnement à poser ## Choix de Max (2026-10-19) Consignés dans `### Calibration` de `REVIEW.md` (commentaire 25657) : 1. Le taux de 65 % est gardé. 2. Une montée de version d'un paquet déjà présent reste normale. 3. Les agents du poste restent toujours hauts. 4. La liste des fichiers jamais bas est inchangée. 5. Les gardes `auth.test.js` et `writes.test.js` sont hautes dès qu'une ligne existante change. 6. Les nettoyeurs restent normaux. Suggestions de la revue 25515 : 1, 2 et 3 sont appliquées (`.claude/hooks/**` haut, niveau bas restreint à `**/*.md` et `LICENSE`, déplacement vers `dependencies` classé haut). La 4 (rangement dans `--check`) est écartée. Les trois passes de `/pr-review` : 25498 (REQUEST_CHANGES, corrigé), 25515 et 25665 (APPROVE). Prête à merger. Une fois mergé, les PR ouvertes seront jugées avec ces niveaux. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
maximus added 1 commit 2026-10-19 23:49:57 +00:00
docs: add REVIEW.md with review levels and a calibration script (#63)
All checks were successful
CI / verification (pull_request) Successful in 38s
0b351e3937
REVIEW.md sets the review level of a PR from the files it touches
(routing and auth, write surfaces, image, workstation agents, CI and
guards), the rules of each zone with their source, the verification
commands and the review pitfalls. scripts/review-levels.py replays the
levels on the 31 PRs that reached main and checks, offline, that its
patterns match the Haut table.

CLAUDE.md said "no auto-deploy": since 2026-10-12 a push to main
redeploys through the Forgejo webhook. The Deploy section now says so
and points to REVIEW.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
maximus added 1 commit 2026-10-19 23:53:34 +00:00
docs: correct the backups-pull mount, the mounts' status and the rotation rule (#63)
All checks were successful
CI / verification (pull_request) Successful in 34s
1d3be3ca49
The host side of the backups-pull mount is /srv/vps-health-api/backups-pull
(docker inspect, 2026-10-19), and the three mounts marked "to set up" are
in place. The test list gains agent-pg-backup-pull.test.js, missing until
now. REVIEW.md stated the rotation was anchored on the workstation's date:
it is anchored on the newest valid backup not after today.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Owner

Niveau : normal (pas de REVIEW.md)

Verdict : REQUEST_CHANGES

Résumé. Le REVIEW.md est solide : chaque règle de zone cite une source qui existe (vérifié : hook id 9 et auto-deploy du 2026-10-12, absence de watch_paths, montage /srv/vps-health-api/backups-pull et son root:root du 2026-10-16 dans coolify-ops.md, runner linux-builder à portée instance dans forgejo-ops.md, apk add git bash curl et l'absence de concurrency: dans ci.yml, .env/.env.local dans .gitignore). La correction de la section « Deploy » de CLAUDE.md est juste. Un seul défaut bloquant : le piège n° 5 de REVIEW.md a lui-même subi le piège qu'il décrit.

Ce qui a tourné (copie hors dépôt de la tête 1d3be3c)

  • npm ci && npx vitest run : 13 fichiers, 879 cas verts ; agent-pg-backup-pull.test.js compte bien 21 cas (la ligne ajoutée à CLAUDE.md est exacte).
  • python3 scripts/review-levels.py --check : ok: 17 patterns, code 0.
  • Sonde : retrait de "agent/push-metrics.js" de HIGH_ALWAYS → REVIEW.md only: agent/push-metrics.js, code 1. La garde sait échouer.
  • Rejeu réseau sur #18, #60, #62 : mêmes niveaux et mêmes déclencheurs que dans le corps de la PR (#18 passe par le chemin EMPTY_DIFF du clone local).
  • Statut de commit de la tête : CI / verification (pull_request) = success.
  • Fermeture : la timeline de #63 porte un pull_ref closes depuis #65.

Problème bloquant

  1. REVIEW.md:159 : « Un - tapé dans un outil arrive décodé dans le fichier ». L'exemple d'origine était la séquence d'échappement \u002d (celle de PR #42, toujours présente telle quelle dans CLAUDE.md, section ci.test.js : "continue\u002don-error"). Elle est arrivée décodée en - : la phrase ne dit plus rien, et le relecteur ne sait pas quoi chercher. Réécrire l'exemple en construisant la barre oblique hors de l'outil d'édition (chr(92) en Python, cf. la mémoire « Escapes decoded in tool calls »), puis vérifier par grep -n 'u002d' REVIEW.md (l'occurrence doit être précédée d'une barre oblique inverse) ou od -c.

Suggestions (non bloquantes)

  • scripts/review-levels.py:20-23 (docstring) : la liste des effets approchés cite encore « environment » et « log lines ». Le corps de la PR dit que ces deux déclencheurs ont été retirés pendant la calibration, et EFFECTS ne les contient plus. Mettre la docstring à jour.
  • AUTH reconnaît aussi timingSafeEqual et createHash, absents de la condition du tableau Haut. Le script est plus strict que le document : sans effet sur la calibration (aucune PR ne change de niveau à cause d'eux), mais à aligner dans un sens ou dans l'autre.
  • CLAUDE.md : les trois montages passent à « Pose (releve du 2026-10-19) », alors que le relevé consigné dans coolify-ops.md date du 2026-10-16. Si un relevé a bien été fait aujourd'hui, l'ajouter à coolify-ops.md ; sinon citer celui du 2026-10-16. Point non vérifié par la revue (pas de SSH vers le VPS).

Les six choix posés à Max dans le corps de la PR relèvent de son arbitrage et ne sont pas jugés ici. Une remarque factuelle sur le choix n° 1 : avec touches(), un hunk dont la ligne de contexte @@ nomme une fonction à effet de bord (readBody, writeHostSnapshot…) rend index.js haut même si la ligne changée n'y touche pas. Le taux de 65 % en est un peu gonflé, dans le sens prudent.

Actions faites

  • Copie hors dépôt (scratchpad/pr65, rl.py) supprimée en fin de revue.
  • Label : #63 ne porte pas status:review (labels actuels : source:human, type:infra), donc rien n'est changé.
Niveau : normal (pas de REVIEW.md) **Verdict : REQUEST_CHANGES** **Résumé.** Le `REVIEW.md` est solide : chaque règle de zone cite une source qui existe (vérifié : hook id 9 et auto-deploy du 2026-10-12, absence de `watch_paths`, montage `/srv/vps-health-api/backups-pull` et son `root:root` du 2026-10-16 dans `coolify-ops.md`, runner `linux-builder` à portée instance dans `forgejo-ops.md`, `apk add git bash curl` et l'absence de `concurrency:` dans `ci.yml`, `.env`/`.env.local` dans `.gitignore`). La correction de la section « Deploy » de `CLAUDE.md` est juste. Un seul défaut bloquant : le piège n° 5 de `REVIEW.md` a lui-même subi le piège qu'il décrit. ### Ce qui a tourné (copie hors dépôt de la tête `1d3be3c`) - `npm ci && npx vitest run` : 13 fichiers, **879 cas verts** ; `agent-pg-backup-pull.test.js` compte bien 21 cas (la ligne ajoutée à `CLAUDE.md` est exacte). - `python3 scripts/review-levels.py --check` : `ok: 17 patterns`, code 0. - **Sonde** : retrait de `"agent/push-metrics.js"` de `HIGH_ALWAYS` → `REVIEW.md only: agent/push-metrics.js`, code 1. La garde sait échouer. - Rejeu réseau sur #18, #60, #62 : mêmes niveaux et mêmes déclencheurs que dans le corps de la PR (#18 passe par le chemin `EMPTY_DIFF` du clone local). - Statut de commit de la tête : `CI / verification (pull_request)` = success. - Fermeture : la timeline de #63 porte un `pull_ref` `closes` depuis #65. ### Problème bloquant 1. **`REVIEW.md:159`** : « Un `-` tapé dans un outil arrive décodé dans le fichier ». L'exemple d'origine était la séquence d'échappement `\u002d` (celle de PR #42, toujours présente telle quelle dans `CLAUDE.md`, section `ci.test.js` : `"continue\u002don-error"`). Elle est arrivée décodée en `-` : la phrase ne dit plus rien, et le relecteur ne sait pas quoi chercher. Réécrire l'exemple en construisant la barre oblique hors de l'outil d'édition (`chr(92)` en Python, cf. la mémoire « Escapes decoded in tool calls »), puis vérifier par `grep -n 'u002d' REVIEW.md` (l'occurrence doit être précédée d'une barre oblique inverse) ou `od -c`. ### Suggestions (non bloquantes) - `scripts/review-levels.py:20-23` (docstring) : la liste des effets approchés cite encore « environment » et « log lines ». Le corps de la PR dit que ces deux déclencheurs ont été retirés pendant la calibration, et `EFFECTS` ne les contient plus. Mettre la docstring à jour. - `AUTH` reconnaît aussi `timingSafeEqual` et `createHash`, absents de la condition du tableau Haut. Le script est plus strict que le document : sans effet sur la calibration (aucune PR ne change de niveau à cause d'eux), mais à aligner dans un sens ou dans l'autre. - `CLAUDE.md` : les trois montages passent à « Pose (releve du 2026-10-19) », alors que le relevé consigné dans `coolify-ops.md` date du 2026-10-16. Si un relevé a bien été fait aujourd'hui, l'ajouter à `coolify-ops.md` ; sinon citer celui du 2026-10-16. Point non vérifié par la revue (pas de SSH vers le VPS). Les six choix posés à Max dans le corps de la PR relèvent de son arbitrage et ne sont pas jugés ici. Une remarque factuelle sur le choix n° 1 : avec `touches()`, un hunk dont la ligne de contexte `@@` nomme une fonction à effet de bord (`readBody`, `writeHostSnapshot`…) rend `index.js` haut même si la ligne changée n'y touche pas. Le taux de 65 % en est un peu gonflé, dans le sens prudent. ### Actions faites - Copie hors dépôt (`scratchpad/pr65`, `rl.py`) supprimée en fin de revue. - Label : #63 ne porte pas `status:review` (labels actuels : `source:human`, `type:infra`), donc rien n'est changé.
maximus added 1 commit 2026-10-19 23:56:50 +00:00
docs: keep the escaped example escaped, align the script with the table (#63)
All checks were successful
CI / verification (pull_request) Successful in 35s
9547965c9d
The escape-sequence pitfall had lost its own example on the way: the
backslash-u002d sequence landed decoded as a plain dash. It is written
back with the backslash built by chr(92) and checked with od -c.

The script's docstring no longer lists the environment and log-line
triggers dropped during calibration, and AUTH no longer matches
timingSafeEqual and createHash, which the Haut table does not name.
Replay unchanged: 20 haut out of 31.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Owner

Niveau : normal (pas de REVIEW.md)

Verdict : APPROVE

Résumé. REVIEW.md est fidèle à ses sources, scripts/review-levels.py reproduit exactement la calibration annoncée, et --check sait échouer. Les corrections de CLAUDE.md (montage backups-pull, auto-deploy) concordent avec coolify-ops.md. Il reste quatre suggestions, aucune bloquante.

Ce qui a été vérifié (copie hors dépôt de la tête 9547965)

  • npm ci && npx vitest run : 13 fichiers, 879 cas verts. agent-pg-backup-pull.test.js compte bien 21 cas, comme le dit la ligne ajoutée à CLAUDE.md.
  • python3 scripts/review-levels.py : sortie identique ligne pour ligne à celle du corps de la PR (31 PR : 0 / 11 / 20, haut 64,5 %). Les six SHA d'EMPTY_DIFF existent dans le clone.
  • --check : ok: 17 patterns. Mutation : "Dockerfile" renommé en "Dockerfil" dans HIGH_ALWAYS donne REVIEW.md only: Dockerfile / script only: Dockerfil et rc=1. Annulée, le check revient à ok.
  • review-levels.py 65 classe cette PR haut (REVIEW.md, « Niveaux » à vérifier à la main). C'est cohérent avec la règle « jugée par la version de main », qui la laisse en normal ici.
  • Faits cités : handler, resolveRoute, checkAuth, tokenMatches, logRejection, safeLogValue et GHSA-376v-xgjx-7mfr existent dans index.js. L'en-tête de ci.yml porte bien « pas de defaults: / working-directory sur uses: / pas de concurrency: ». forgejo-ops.md confirme linux-builder à portée instance, et coolify-ops.md le hook id 9 (auto-deploy depuis le 2026-10-12), /srv/vps-health-api/backups-pull -> /data/backups-pull rw=true et le root:root du 2026-10-16.
  • L'exemple "continue-on-error" de CLAUDE.md est resté échappé dans le fichier (od -c : \ u 0 0 2 d).
  • CI de la tête : CI / verification (pull_request) = success.
  • Fermeture : la timeline de #63 porte pull_ref closes depuis #65.

Suggestions (non bloquantes)

  1. .claude/hooks/** n'est pas haut. Le tableau justifie .claude/settings.json par « hooks, permissions et serveurs MCP décident de ce que les agents exécutent ». Or le corps d'un script de hook est ce qui s'exécute, et le modifier ne touche pas settings.json. Sonde : un nouveau .claude/hooks/x.sh est classé normal. Ajouter .claude/hooks/** (ou « tout fichier que settings.json référence ») au tableau et à HIGH_ALWAYS. Rien n'est versionné sous .claude/ aujourd'hui.
  2. reports/** et docs/** acceptent n'importe quel type de fichier en Bas. Sonde : reports/run.sh ajouté est classé bas. reports/ ne reçoit que des DAILY-REPORT-*.md, donc reports/**/*.md suffirait.
  3. package_json_changes() ignore les changements de bloc. Une clé présente des deux côtés avec une valeur de version passe pour une montée de version. Sonde : vitest déplacé de devDependencies vers un bloc dependencies déjà présent donne normal. Aujourd'hui, l'absence de bloc dependencies fait apparaître une ligne "dependencies": { qui rattrape le cas. Le défaut devient réel dès qu'un bloc existe. Comparer clé et bloc, ou le dire dans la docstring.
  4. --check compare l'union des motifs, pas leur rangement. Déplacer Dockerfile de HIGH_ALWAYS vers CONDITIONAL laisse le check vert, alors que Dockerfile ne déclencherait plus rien. Ce risque est faible, mais une ligne de doc ou une comparaison par liste (sans condition, ou avec) le fermerait.

Sur le choix 1 (65 %) : les 20 PR hautes correspondent toutes à une surface créée ou à un garde modifié, sans faux positif évident dans la liste. Le taux me paraît défendable tel quel.

Actions faites

  • Revue sur une copie hors dépôt (scratchpad/pr65), supprimée en fin de revue.
  • Aucun label changé : #63 ne porte pas status:review (labels actuels : source:human, type:infra).
Niveau : normal (pas de REVIEW.md) **Verdict : APPROVE** **Résumé.** `REVIEW.md` est fidèle à ses sources, `scripts/review-levels.py` reproduit exactement la calibration annoncée, et `--check` sait échouer. Les corrections de `CLAUDE.md` (montage `backups-pull`, auto-deploy) concordent avec `coolify-ops.md`. Il reste quatre suggestions, aucune bloquante. ### Ce qui a été vérifié (copie hors dépôt de la tête `9547965`) - `npm ci && npx vitest run` : 13 fichiers, **879 cas verts**. `agent-pg-backup-pull.test.js` compte bien 21 cas, comme le dit la ligne ajoutée à `CLAUDE.md`. - `python3 scripts/review-levels.py` : sortie identique ligne pour ligne à celle du corps de la PR (31 PR : 0 / 11 / 20, haut 64,5 %). Les six SHA d'`EMPTY_DIFF` existent dans le clone. - `--check` : `ok: 17 patterns`. **Mutation** : `"Dockerfile"` renommé en `"Dockerfil"` dans `HIGH_ALWAYS` donne `REVIEW.md only: Dockerfile` / `script only: Dockerfil` et rc=1. Annulée, le check revient à ok. - `review-levels.py 65` classe cette PR haut (`REVIEW.md`, « Niveaux » à vérifier à la main). C'est cohérent avec la règle « jugée par la version de `main` », qui la laisse en normal ici. - Faits cités : `handler`, `resolveRoute`, `checkAuth`, `tokenMatches`, `logRejection`, `safeLogValue` et GHSA-376v-xgjx-7mfr existent dans `index.js`. L'en-tête de `ci.yml` porte bien « pas de `defaults:` / `working-directory` sur `uses:` / pas de `concurrency:` ». `forgejo-ops.md` confirme `linux-builder` à portée instance, et `coolify-ops.md` le hook id 9 (auto-deploy depuis le 2026-10-12), `/srv/vps-health-api/backups-pull -> /data/backups-pull rw=true` et le `root:root` du 2026-10-16. - L'exemple `"continue-on-error"` de `CLAUDE.md` est resté échappé dans le fichier (`od -c` : `\ u 0 0 2 d`). - CI de la tête : `CI / verification (pull_request)` = success. - Fermeture : la timeline de #63 porte `pull_ref` `closes` depuis #65. ### Suggestions (non bloquantes) 1. **`.claude/hooks/**` n'est pas haut.** Le tableau justifie `.claude/settings.json` par « hooks, permissions et serveurs MCP décident de ce que les agents exécutent ». Or le corps d'un script de hook est ce qui s'exécute, et le modifier ne touche pas `settings.json`. Sonde : un nouveau `.claude/hooks/x.sh` est classé `normal`. Ajouter `.claude/hooks/**` (ou « tout fichier que `settings.json` référence ») au tableau et à `HIGH_ALWAYS`. Rien n'est versionné sous `.claude/` aujourd'hui. 2. **`reports/**` et `docs/**` acceptent n'importe quel type de fichier en Bas.** Sonde : `reports/run.sh` ajouté est classé `bas`. `reports/` ne reçoit que des `DAILY-REPORT-*.md`, donc `reports/**/*.md` suffirait. 3. **`package_json_changes()` ignore les changements de bloc.** Une clé présente des deux côtés avec une valeur de version passe pour une montée de version. Sonde : `vitest` déplacé de `devDependencies` vers un bloc `dependencies` déjà présent donne `normal`. Aujourd'hui, l'absence de bloc `dependencies` fait apparaître une ligne `"dependencies": {` qui rattrape le cas. Le défaut devient réel dès qu'un bloc existe. Comparer clé et bloc, ou le dire dans la docstring. 4. **`--check` compare l'union des motifs, pas leur rangement.** Déplacer `Dockerfile` de `HIGH_ALWAYS` vers `CONDITIONAL` laisse le check vert, alors que `Dockerfile` ne déclencherait plus rien. Ce risque est faible, mais une ligne de doc ou une comparaison par liste (sans condition, ou avec) le fermerait. Sur le choix 1 (65 %) : les 20 PR hautes correspondent toutes à une surface créée ou à un garde modifié, sans faux positif évident dans la liste. Le taux me paraît défendable tel quel. ### Actions faites - Revue sur une copie hors dépôt (`scratchpad/pr65`), supprimée en fin de revue. - Aucun label changé : #63 ne porte pas `status:review` (labels actuels : `source:human`, `type:infra`).
Author
Owner

Choix de Max (2026-10-19), consignes dans ### Calibration de REVIEW.md (44d5897) :

  1. Taux de 65 % garde.
  2. Une montee de version d un paquet deja present reste normale.
  3. Agents du poste toujours hauts.
  4. Liste des fichiers jamais bas inchangee.
  5. Gardes auth.test.js / writes.test.js hautes des qu une ligne existante change.
  6. Nettoyeurs normaux.

Suggestions de la revue 25515 appliquees : 1 (.claude/hooks/** haut), 2 (Bas restreint a **/*.md et LICENSE), 3 (package.json : deplacement vers dependencies). La suggestion 4 (rangement dans --check) est ecartee. Calibration rejouee : inchangee, 20 hautes sur 31.

Choix de Max (2026-10-19), consignes dans `### Calibration` de `REVIEW.md` (44d5897) : 1. Taux de 65 % garde. 2. Une montee de version d un paquet deja present reste normale. 3. Agents du poste toujours hauts. 4. Liste des fichiers jamais bas inchangee. 5. Gardes `auth.test.js` / `writes.test.js` hautes des qu une ligne existante change. 6. Nettoyeurs normaux. Suggestions de la revue 25515 appliquees : 1 (`.claude/hooks/**` haut), 2 (Bas restreint a `**/*.md` et `LICENSE`), 3 (`package.json` : deplacement vers `dependencies`). La suggestion 4 (rangement dans `--check`) est ecartee. Calibration rejouee : inchangee, 20 hautes sur 31.
maximus added 1 commit 2026-10-20 00:21:32 +00:00
docs: apply three review suggestions, record Max's choices (#63)
All checks were successful
CI / verification (pull_request) Successful in 38s
44d58970ad
- .claude/hooks/** joins the always-high row: a hook script runs on the
  workstation.
- Bas narrows to **/*.md and LICENSE: a script or an image added under
  docs/ or reports/ is no longer low.
- package.json: a package moved between devDependencies and dependencies,
  or any line of the dependencies block, is high; the script now tracks
  the block each package line belongs to.
- Calibration records the choices Max confirmed on 2026-10-19.

Replay unchanged: 20 haut out of 31.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Owner

Niveau : normal (pas de REVIEW.md)

Verdict : APPROVE

Résumé. Troisième passe, centrée sur 44d5897, le commit qui suit l'APPROVE 25515. Les trois suggestions retenues sont appliquées correctement et chacune sait échouer. Les choix de Max consignés dans ### Calibration reprennent fidèlement le commentaire 25657. La calibration ne bouge pas : 31 PR, 0 basse, 11 normales, 20 hautes.

Ce qui a été vérifié (copie hors dépôt de la tête 44d5897)

  • npm ci && npx vitest run : 13 fichiers, 879 cas verts. Aucun test ne lit REVIEW.md ni le script.
  • python3 scripts/review-levels.py : la sortie est identique ligne pour ligne à celle du corps de la PR (comparaison par diff).
  • --check : ok: 18 patterns, avec .claude/hooks/** en plus. Mutation : retirer .claude/hooks/** de HIGH_ALWAYS donne REVIEW.md only: .claude/hooks/**, rc=1.
  • Sondes, une par suggestion :
    • un nouveau .claude/hooks/x.sh est classé haut ;
    • reports/run.sh est classé normal, reports/x.md bas ;
    • vitest déplacé de devDependencies vers un bloc dependencies existant (déplacement pur, sans autre changement) est classé haut ;
    • une montée de version de vitest et une montée du version de l'app restent normales.
  • Mutation de package_json_changes() : sans la clé de bloc et sans le retour sur dependencies, le déplacement pur retombe en normal. La sonde distingue donc l'ancien comportement du nouveau.
  • CI de la tête : CI / verification (pull_request) = success.
  • Fermeture : la timeline de #63 porte un pull_ref closes depuis #65.

Suggestions (non bloquantes)

  1. Corps de la PR périmé. La section « Choix à confirmer par Max » et la phrase « Ne pas merger avant tes réponses » sont toujours là, alors que les réponses sont consignées (25657, 44d5897). Le corps annonce aussi 17 patterns, au lieu de 18 aujourd'hui. Le mettre à jour avant le merge, pour qu'un lecteur ne croie pas le merge bloqué.
  2. package_json_changes() ne connaît le bloc que si son en-tête figure dans le contexte du hunk. Exemple : une montée de version au milieu d'un bloc dependencies de plus de trois entrées, dont la ligne "dependencies": { sort des 3 lignes de contexte. Elle est classée normale, alors que le tableau dit « toute ligne du bloc dependencies ». Ce cas est impossible aujourd'hui, le runtime n'ayant aucune dépendance, et le script ne sert qu'à la calibration. Une ligne dans la docstring suffit.

Actions faites

  • Revue sur une copie hors dépôt (scratchpad/pr65, plus les fichiers pr65-*), supprimée en fin de revue.
  • Aucun label changé : #63 ne porte pas status:review (labels : source:human, type:infra).
Niveau : normal (pas de REVIEW.md) **Verdict : APPROVE** **Résumé.** Troisième passe, centrée sur `44d5897`, le commit qui suit l'APPROVE 25515. Les trois suggestions retenues sont appliquées correctement et chacune sait échouer. Les choix de Max consignés dans `### Calibration` reprennent fidèlement le commentaire 25657. La calibration ne bouge pas : 31 PR, 0 basse, 11 normales, 20 hautes. ### Ce qui a été vérifié (copie hors dépôt de la tête `44d5897`) - `npm ci && npx vitest run` : 13 fichiers, **879 cas verts**. Aucun test ne lit `REVIEW.md` ni le script. - `python3 scripts/review-levels.py` : la sortie est identique ligne pour ligne à celle du corps de la PR (comparaison par `diff`). - `--check` : `ok: 18 patterns`, avec `.claude/hooks/**` en plus. **Mutation** : retirer `.claude/hooks/**` de `HIGH_ALWAYS` donne `REVIEW.md only: .claude/hooks/**`, rc=1. - **Sondes**, une par suggestion : - un nouveau `.claude/hooks/x.sh` est classé haut ; - `reports/run.sh` est classé normal, `reports/x.md` bas ; - `vitest` déplacé de `devDependencies` vers un bloc `dependencies` existant (déplacement pur, sans autre changement) est classé haut ; - une montée de version de `vitest` et une montée du `version` de l'app restent normales. - **Mutation** de `package_json_changes()` : sans la clé de bloc et sans le retour sur `dependencies`, le déplacement pur retombe en normal. La sonde distingue donc l'ancien comportement du nouveau. - CI de la tête : `CI / verification (pull_request)` = success. - Fermeture : la timeline de #63 porte un `pull_ref` `closes` depuis #65. ### Suggestions (non bloquantes) 1. **Corps de la PR périmé.** La section « Choix à confirmer par Max » et la phrase « Ne pas merger avant tes réponses » sont toujours là, alors que les réponses sont consignées (25657, `44d5897`). Le corps annonce aussi `17 patterns`, au lieu de 18 aujourd'hui. Le mettre à jour avant le merge, pour qu'un lecteur ne croie pas le merge bloqué. 2. **`package_json_changes()` ne connaît le bloc que si son en-tête figure dans le contexte du hunk.** Exemple : une montée de version au milieu d'un bloc `dependencies` de plus de trois entrées, dont la ligne `"dependencies": {` sort des 3 lignes de contexte. Elle est classée normale, alors que le tableau dit « toute ligne du bloc `dependencies` ». Ce cas est impossible aujourd'hui, le runtime n'ayant aucune dépendance, et le script ne sert qu'à la calibration. Une ligne dans la docstring suffit. ### Actions faites - Revue sur une copie hors dépôt (`scratchpad/pr65`, plus les fichiers `pr65-*`), supprimée en fin de revue. - Aucun label changé : #63 ne porte pas `status:review` (labels : `source:human`, `type:infra`).
maximus added 1 commit 2026-10-20 00:24:15 +00:00
docs(review-levels): name the package.json block blind spot (#63)
All checks were successful
CI / verification (pull_request) Successful in 39s
CI / verification (push) Successful in 47s
1dff0c805e
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
maximus merged commit 1dff0c805e into main 2026-10-20 00:27:04 +00:00
maximus deleted branch infra/review-md-63 2026-10-20 00:27:04 +00:00
Author
Owner

Merge fast-forward par l API sur 1dff0c8 (tete validee : npm ci, sonde rouge en code 1, npm test 879 cas, test-curl.sh 57 cas, boot-from-copy.sh PASS, --check 18 motifs). 1dff0c8 a ete ajoute apres l APPROVE 25665 et n a pas ete relu : il ne touche que la docstring de scripts/review-levels.py (angle mort de package.json nomme). Redeploiement automatique Coolify termine sur 1dff0c8 ; production : /health sans token 401, route inconnue 404.

Remarques non bloquantes restantes : aucune a reprendre. La suggestion 4 (rangement dans --check) est ecartee par Max, l angle mort de package.json est documente, et le declenchement d index.js sur la ligne de contexte @@ entre dans le taux de 65 % que Max a garde.

Merge fast-forward par l API sur `1dff0c8` (tete validee : `npm ci`, sonde rouge en code 1, `npm test` 879 cas, `test-curl.sh` 57 cas, `boot-from-copy.sh` PASS, `--check` 18 motifs). `1dff0c8` a ete ajoute apres l APPROVE 25665 et n a pas ete relu : il ne touche que la docstring de `scripts/review-levels.py` (angle mort de `package.json` nomme). Redeploiement automatique Coolify termine sur `1dff0c8` ; production : `/health` sans token 401, route inconnue 404. Remarques non bloquantes restantes : aucune a reprendre. La suggestion 4 (rangement dans `--check`) est ecartee par Max, l angle mort de `package.json` est documente, et le declenchement d `index.js` sur la ligne de contexte `@@` entre dans le taux de 65 % que Max a garde.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/vps-health-api#65
No description provided.