Skip to content

perf: defer unused pipeline hook imports (W2-1a) - #482

Merged
cdeust merged 9 commits into
mainfrom
fix/green-lazy-hook-imports
Sep 6, 2026
Merged

cdeust merged 9 commits into
mainfrom
fix/green-lazy-hook-imports

Conversation

@cdeust

@cdeust cdeust commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Symptôme

W2-1 / F2, première PR : le hook pipeline importe le store à la fermeture de
chaque processus, y compris pour les outils qu'il ne traite pas. PR empilée
sur #481 ; les matchers seront traités dans la seconde PR de W2-1.

Cause racine

Le scope de close_shared_store_on_exit entourait tout le programme et son
finally importait memory_store même si aucun store n'avait été utilisé.
Les helpers de recherche du graphe importaient aussi le client MCP amont dès
leur chargement. Le checkout actuel n'importe déjà plus mcp_server.__main__
sur ce chemin : les références de la revue ont été vérifiées sur la base réelle.

Changement

Le scope de fermeture commence après les gardes outil/fichier/cooldown. Le
teardown consulte sys.modules et ferme les stores déjà chargés sans créer
le graphe d'imports qu'il doit seulement nettoyer. Le client et son limiteur
amont sont importés uniquement quand call_upstream est réellement appelé.
La résolution canonique des graphes, y compris leurs chemins personnalisés,
et la fermeture sur succès/erreur/SystemExit sont conservées.

Une sonde stdlib documente les mesures directes de module. Son environnement
isole aussi les paramètres libpq hérités : une chaîne vide sélectionnerait les
paramètres locaux par défaut, donc elle utilise un répertoire de socket inexistant
encodé dans l'autorité du DSN.
Source : PostgreSQL — URI de connexion.
Les mesures d'acceptation ci-dessous utilisent le véritable launcher.

Preuve

Base exacte d0f7c19bf64a2d994b2e9a2a9818244c994bc972, avant en checkout détaché,
après avec le diff de cette PR, sans rebase ultérieur. Python 3.13.7 identique,
macOS ARM64 / 10 cœurs, SQLite jetable, dépendances du launcher préparées hors
mesure, aucun téléchargement ni serveur MCP lancé.

Commandes exactes :

.venv/bin/python /private/tmp/cortex-green-launcher-measure.py /private/tmp/cortex-green-w2-1a-before /private/tmp/cortex-green-w2-1a-launcher-before pipeline
.venv/bin/python /private/tmp/cortex-green-launcher-measure.py /Users/cdeust/Developments/anthropic-partnership/Cortex /private/tmp/cortex-green-w2-1a-launcher-after pipeline

Le driver exécute /usr/bin/time -l -o <log> <python> <checkout>/scripts/launcher.py mcp_server.hooks.pipeline_impact_bump < <payload>, quatre processus par payload,
premier exclu ; les traces -X importtime sont séparées. Tous les processus
terminent avec le code 0, sans erreur de lookup dans leurs journaux.
Payloads identiques avant/après : Read example.py, Bash python -m unittest example,
Edit example.py sans graphe, dans /private/tmp/cortex-green-hook-fixture/project.
Les payloads JSON complets et environnements sont conservés dans les deux reports.

Payload CPU avant : trois valeurs (s) CPU après (s) RSS avant max (octets) RSS après max (octets)
Read 0.16 / 0.14 / 0.12 0.05 / 0.04 / 0.04 49496064 25575424
Bash 0.12 / 0.11 / 0.12 0.04 / 0.04 / 0.04 49397760 25559040
Edit sans graphe 0.14 / 0.18 / 0.14 0.14 / 0.13 / 0.13 51609600 51232768

Valeurs CPU user+sys affichées par BSD time (précision du journal conservée).
Read/Bash après : aucun memory_store, _store_lifecycle, mcp_client_pool ou
mcp_server.__main__ dans les traces d'import. Edit sans graphe après : le client
amont disparaît ; store et lifecycle restent nécessaires à la recherche canonique.

Limite d'acceptation : la borne stricte CPU <0,05 s n'est pas démontrée pour
chaque échantillon Read et ne tient pas pour l'Edit sans graphe (0,13–0,14 s).
Le script ne remplace pas la recherche canonique par une hypothèse sur le chemin
du graphe pour atteindre ce seuil. L'optimisation des sorties Read/Bash est
mesurée ; l'acceptation complète « sans graphe » de W2-1a reste partielle.

Avant : charge 3,57→3,44 / 10, disque61→62 GiB. Après : charge3,91→3,83 /10,
disque61→61 GiB. Un seul travail local lourd. Rapports, mesures et traces :
/private/tmp/cortex-green-w2-1a-launcher-{before,after}/, agrégation
/private/tmp/cortex-green-w2-1a-launcher-comparison.json.

16 tests ciblés passent : sorties anticipées, absence/vidage du graphe,
chemin de graphe personnalisé, appel amont, fermeture après exception/SystemExit,
isolation de l'environnement et quatre répétitions avec première exclue.

Gates locaux ordonnés terminés avec le code 0 : Ruff/format 1 418 fichiers,
craftsmanship, Pyright zéro diagnostic ; couches hooks+scripts 1 121 passed,
17 skipped, 292 subtests en 22,33 s
; suite complète 7 593 passed,
221 skipped, 292 subtests en 142,00 s
. PostgreSQL explicitement indisponible
au socket inexistant ; aucun skip présenté comme un test PG exécuté.
Charge initiale 3,61 / 10 cœurs, disque 61 GiB avant/après.

bash /private/tmp/cortex-green-local-gates.sh w2-1a tests_py/hooks/ tests_py/scripts/

Le driver suit les deux uv sync --locked et les extras/groupes du contrat,
puis Ruff, craftsmanship, Pyright mcp_server/, couches affectées et pytest
complet dans l'ordre. Log : /private/tmp/cortex-green-w2-1a-gates.log.
Commit final : 1f4196ef20ee0c52c18990924a2c3d1be80a76bf. CI externe 34043261590 terminée verte sur ce SHA.

Conformité

Aucune entrée baseline ajoutée. Nouveaux fichiers sous 300 lignes, fonctions
sous 40 lignes et quatre paramètres ; aucun import de couche supplémentaire.
Comportement du graphe et du teardown conservé, aucun fallback silencieux.
La mesure ne touche ni une base de production ni un modèle. La nouvelle sonde
ne mélange pas launcher et module direct dans ses chiffres.

Candidats issues

Le seuil « Edit sans graphe <0,05 s » nécessiterait un contrat distinct pour
trouver les graphes sans charger le store, tout en conservant les chemins
personnalisés. Dette préexistante des fichiers touchés inchangée ; aucun
refactoring général ni nouveau ticket. Les bornes cumulées des quatre hooks
seront mesurées dans W2-1b, en conservant le coût réel de la capture.

Runbook

Aucune opération de données. Le propriétaire décide de la fusion. Les fichiers
et bases de mesure sont temporaires, le mode de capture n'est pas modifié ici.

@cdeust
cdeust changed the base branch from build/green-docker-context to main September 6, 2026 21:52
@cdeust
cdeust merged commit 0f62f88 into main Sep 6, 2026
29 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.

1 participant