Skip to content

fix(guard,#15666): le detecteur de voies lake voit l'executable tenu dans une variable - #20014

Merged
myia-ai-01 merged 1 commit into
mainfrom
feature/15666-lean-notebook-utils-canonical
Oct 9, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
feature/15666-lean-notebook-utils-canonical

Conversation

@jsboige

@jsboige jsboige commented Oct 9, 2026

Copy link
Copy Markdown
Owner

Grain: MED/guard — lane myia-po-2026:CoursIA — prev: LIGHT/guard #19978

Le defaut

Les formes 1 et 2 du garde check_lake_direct_invocation.py ne lisent que des litteraux. Une voie qui resout son binaire une fois puis le reutilise etait donc invisible :

lake = _find_lake()                       # resolu une fois
_run_capture([lake] + args.split(), ...)  # execute -- jamais vu

Mesure du 2026-10-09 sur MyIA.AI.Notebooks/SymbolicAI/Lean/lean_notebook_utils.py (case 1 de #15666) : 1 invocation directe detectee sur 3. Les deux voies natives (L239 [lake] + args.split(), L291 [lake, "env", "lean", str(tmp_path)]) echappaient ; seule la f-string WSL (L299) etait signalee.

Pourquoi ca compte plus qu'un chiffre

Le garde est un cliquet : il empeche la reintroduction d'une voie directe. Or il ne voyait pas la voie que la migration doit retirer. Consequence concrete : une migration partielle qui routerait run_lean_snippet mais laisserait run_lake appeller lake en direct rendrait rc=0 et un census inchange — la dette survivrait, invisible, et l'allowlist serait meme signalee STALE (« allowlistee sans violation : migrer puis retirer l'entree »), invitant a retirer une entree encore due.

C'est la forme exacte que la doctrine anti-regression decrit : un motif de detection se valide par ses faux negatifs, et celui-la rendait un chiffre plus petit et plus propre, jamais une erreur.

Le correctif

  • _lake_holder_names : ensemble des noms lies a un executable lake, par deux voies mesurees — shutil.which("lake") (la sonde de toolchain) et un appel a un helper dont le nom porte lake (_find_lake()), qui est la forme reellement ecrite.
  • Forme 2bis : tete de liste tenue par un de ces noms. La tete seule compte — c'est la position de commande, exactement comme la forme 2 dont elle est le pendant.

Verification

Mesure Avant Apres
Voies vues dans lean_notebook_utils.py 1 3 (L239, L291 nouvelles)
Lignes detectees, repo entier 12 14 (+2 exactement)
Verdict --all --check OK, rc=0 OK, rc=0
Entrees STALE 0 0
Tests du garde 24 28 (4 ajoutes)

python -m pytest scripts/lean/tests/test_check_lake_direct_invocation.py -q → 28 passed.

Les 4 tests tiennent les deux bouts : deux positifs (variable issue de shutil.which, variable issue d'un helper _find_lake) et deux negatifs — la sonde shutil.which("lake") seule reste propre (sinon la forme 2bis fabriquerait le bruit que la forme 2 exclut deja), et une tete de liste tenue par une variable ordinaire (tool = "pytest") n'est pas signalee.

Aucun autre fichier du depot n'est emporte : le rayon d'impact a ete mesure avant d'ecrire (une seule ligne de code reelle dans tout le depot, celle de lean_notebook_utils.py).

Ce que cette PR ne fait pas

Elle ne migre pas lean_notebook_utils.py vers l'organe canonique, bien que ce soit le case 1 de #15666 et l'objet de mon claim (c.6071904681). La mesure a montre que l'organe ne peut pas encore l'accueillir : lean_exec run derive son repertoire de travail de Path.cwd() (L992) et n'expose aucun --cwd, alors que run_lake/run_lean_snippet recoivent des chemins WSL et que run_lean_snippet ecrit son fichier temporaire dans WSL. Router ces voies exigerait une inversion de chemin et une reprise du temporaire sur une surface importee par tous les carnets Lean. Le blocage et l'ordre de migration sont mesures et consignes sur #15666.

See #15666

🤖 Generated with Claude Code

…dans une variable

Les formes 1 et 2 du garde ne lisent que des **litteraux** : une voie qui resout
son binaire une fois (`lake = _find_lake()`) puis l'execute
(`[lake] + args.split()`) etait **invisible**.

Mesure du 2026-10-09 sur `lean_notebook_utils.py` (case 1 de #15666) : le garde
y voyait **1 invocation directe sur 3** -- les deux voies natives (L239, L291)
echappaient, seule la f-string WSL (L299) etait signalee. Le cliquet ne pouvait
donc pas voir une migration partielle laissant une voie native derriere elle,
puisqu'il ne voyait pas la voie a retirer. Un motif de detection se valide par
ses **faux negatifs** : celui-la rendait un chiffre plus petit et plus propre,
jamais une erreur.

- `_lake_holder_names` : noms lies a un executable lake, par `shutil.which("lake")`
  ou par un helper dont le nom porte `lake`.
- Forme 2bis : tete de liste tenue par un de ces noms (position de commande,
  comme la forme 2 dont elle est le pendant).
- 4 tests ajoutes (2 positifs, 2 negatifs) ; 28 passent.
- Census inchange hors `lean_notebook_utils.py` : le verdict reste `OK` (le
  fichier est deja allowliste), +2 lignes detectees, 0 stale.

Verdict `check_lake_direct_invocation.py --all --check` : rc=0.

See #15666

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml).

Detector: python scripts/audit/detect_organ_duplication.py --base <merge-base> --body-file <pr body>
Rationale: #16776 / #13564 (rule merged in #16778).

@jsboige

jsboige commented Oct 9, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 20014
head: 04d5c7d
complete: true
body: read
comments-reviewed: 1
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: e4de539cbbcc8508d74ee4312d2613299e05dbce99bb6ae0bb776e390a11183f
diff-files: 2
diff-additions: 108
diff-deletions: 0
checks: latest-wins-green
b0: clear
scope: pass
domain: not-applicable
verdict: READY
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 20014
organ-rc: 0
[/ADJOINT PREFLIGHT]

@myia-ai-01
myia-ai-01 merged commit 3319f5b into main Oct 9, 2026
19 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants