Repository navigation
Description
Summary
Cortex runs about 9000 tests on Linux and only 20 hand-picked test files on Windows. A one-off measurement of the full suite on Windows found 194 failing tests (188 failed, 6 errors) against 0 on the Linux control and 3 on macOS. This issue tracks the Windows debt as a sequence of root causes; the verified product defects and the bash question have their own issues.
Evidence
Measured on 2026-10-10 at main 18bd25b, SQLite backend, Python 3.12, dependencies from uv.lock, the process-leak guard active, no -x. Two identical runs gave the identical set of failing ids.
- Run 1: https://github.com/cdeust/Cortex/actions/runs/38008915302, run 2: https://github.com/cdeust/Cortex/actions/runs/38011318496, diagnostics: https://github.com/cdeust/Cortex/actions/runs/38012683041.
- Totals: ubuntu 9197 passed, 0 failed; macos 9194 passed, 3 failed; windows 8933 passed, 194 failing, 78 more skips than the control. The Windows full suite takes about 32 minutes against about 5 for Linux.
- By directory: tests_py/scripts 104, benchmarks 40, hooks 23, infrastructure 16, handlers 6, core 2, shared 2, invariants 1.
Failure classes (mutually exclusive, they sum to 194):
- 50 tests: the
empty_envfixture oftests_py/scripts/test_launcher_platform_coverage.py(line 92) returnsScripts/pythonwithout.exe. Once fixed, uv's cross-platform resolution runs on Windows for the first time and may expose more. - 42 tests: bare
bashresolves to the WSL launcher (tracked in its own issue). - 16 tests: default text encoding is cp1252; 4 of them are a product defect in
auto_recall(tracked in its own issue), 12 are tests that callread_text()without an encoding or compare mojibake. - 13 tests:
benchmarks/lib/machine_load_snapshot.py:54calls the POSIX-onlyos.getloadavg. - 21 tests assume a POSIX path or branch:
/a.pyis not absolute on Windows (test_preemptive_context 9),os.getppidpatched while_window_claude_pidtakes the Windows branch (session_registry.py:210-212, test_session_registry 5; PR fix(session-registry): resolve the window's claude.exe on Windows and probe liveness without os.kill (#665) #678 made its own tests platform aware but not this file),~/stateunder USERPROFILE,is_supported()false sodispatchtakes the spool branch (test_capture_dispatch), a path regex overtmp_path(test_validate_memory 4). - 4 tests use a POSIX primitive without a platform guard (
os.O_NOFOLLOW,multiprocessing.get_context("fork"),select.selecton a pipe). - 2 tests:
tests_py/_hermetic_hook_env.py:91sets HOME only, andPath.home()reads USERPROFILE on Windows. - 23 tests, suspected CRLF translation of fixtures written with
write_text(test_migrate_decision_blocks 9, test_wiki_rebucket_file_docs 9, test_wiki_bulk_migrate 5); inferred from the code, not run. - 23 tests not isolated (first error lines recorded): installer rerun fixtures 6, file priming aliases 6 (heat 0.5 against 0.6: a symlinked project alias is scoped differently, possibly a product defect in the ADR-1086 scoping), mcp client spawn 2, a mocked
Path.resolve2, a TTL on a coarse Windows clock 1,test_capture_drain1 (tracked in its own issue), and 5 singles.
Expected
Fix the classes in this order, one pull request each, re-measuring on Windows after each one with the scratch workflow used for the measurement: 1 (50 tests), then 3 (the product defect first), 2, 4, 8, then 5, 6 and 7 together, then class 9 one by one. After the first four steps 73 ids remain, after 5 to 7 about 20. The required Windows job then grows one directory at a time (not straight to the full suite), and the per-system skip counts (Windows 78, macOS 6 more than the control) are pinned in CI so that a new platform skip is a visible decision.
Activity
fix(hooks): write hook and launcher output as UTF-8 through one share…
fix(windows): CI runs the plugin hook commands without bash on PATH; …
test(windows): return the executable from the empty launcher environm…
test(windows): return the executable from the empty launcher environm…
fix(bench): machine-load snapshot reports no load average where os.ge…
cdeust commentedon Nov 4, 2026
Tranche classe 4 proposée dans #861 (commit d0f0ab9) :
os.getloadavgest Unix-only, l'AttributeErrorsous Windows échappait auexcept OSErrordebenchmarks/lib/machine_load_snapshot.py. Le test qui échouait avant (os sansgetloadavg) passe maintenant. Sous Linux,tests_py/benchmarksdonne 386 passés et 12 ignorés. Rien n'a tourné sous Windows.Tranches restantes, dans l'ordre de l'issue : classe 3 (encodage cp1252, 12 tests ; le défaut produit
auto_recalla sa propre issue), classe 8 (CRLF, 23 tests), classes 5 à 7 ensemble, puis la classe 9 une par une. Les classes 1 et 2 sont déjà fusionnées : #824 pour la classe 1, #738 pour la classe 2.Generated by Claude Code
fix(bench): machine-load snapshot reports no load average where os.ge…
cdeust commentedon Nov 5, 2026
Tranche classe 3 (encodage) proposée dans #888 (commit 6d31872),
Refs #692.UnicodeDecodeError: 'charmap'danstest_pg_recall_plans,test_codex_plugin_contract,test_generate_repo_badges) lisent déjà enencoding="utf-8"surmain.post_commit_reindex(écrit en UTF-8 pargated_files.write_json, relu jusqu'ici dans le code page de la locale), et nomme UTF-8 dans les 6 fichiers de test qui ouvraient encore du texte sans encodage (ruff --preview --select PLW1514)..claude-pluginetpluginsn'étaient pas copiés, donc toute PR touchantpost_commit_reindex.pyéchouait avant le premier mutant.test_subprocess_safe.py::test_encoding_parameter_is_honored('' == 'café'sous Windows) reste inexpliqué.Tranches restantes, dans l'ordre de l'issue : re-mesure Windows pour confirmer que la classe 3 est vide, classe 8 (CRLF, 23 tests), classes 5 à 7 ensemble, puis la classe 9 une par une.
Generated by Claude Code
fix(hooks): read the post-commit cooldown as UTF-8, and name UTF-8 in…
Merge pull request #888 from cdeust/fix/692-windows-utf8-text-io
cdeust commentedon Nov 5, 2026
Class 8 slice proposed in #896 (commit d18493a),
Refs #692.wiki_bulk_migrate.planandwiki_rebucket_file_docs.planrecordedstr(rel), i.e.adr\_general\…on Windows, which the detectors andredirect_todo not expect. They now useas_posix().test_migrate_decision_blocksfixture went throughwrite_text(\r\non Windows), while the block id is a hash of the file's bytes.main, the newline simulation reproduces the 9 failure ids and the separator simulation the 14 ids, plus one (test_apply_is_idempotent). On the branch, all pass. Nothing ran on real Windows.Remaining slices, in the issue's order: Windows re-measure (classes 3, 4 and 8), classes 5 to 7 together, then class 9 one by one. The same
str(relative_to(...))pattern exists outside class 8; the list is in the PR, not diagnosed.Generated by Claude Code
fix(wiki): POSIX wiki paths and byte-exact decision fixtures on Windo…
fix(tests): name the Windows home and wait on pipes without select (#692
16 remaining items
fix(mcp-client): the real-child stdio tests spawn on a subprocess-cap…
docs(changelog): single backslashes in the #692 reranker entry
cdeust commentedon Nov 9, 2026
J'ai ouvert #952 pour la tranche classe 9 « chemins du cache reranker » (2 tests, commits a8e47f2 puis b68a26b pour le CHANGELOG,
Refs #692).test_falls_back_to_home_cachecomparait\fake\home\.cache\flashrankà un littéral POSIX ;test_cell_model_cache_and_state_restore_without_changing_defaultscomparait le chemin joint par/decore/reranker_model._model_path()(core n'importe pas pathlib, ADR-0244) à unstr(Path)natif. Le diff ne porte que sur les séparateurs.Path; aucun code de production touché.Tranches restantes de la classe 9, à confirmer par une nouvelle mesure Windows : installer rerun (6), file priming aliases (4 + 2),
Path.resolvemocké (2), et les tests isolés listés dans le corps de l'issue.Generated by Claude Code
fixup! fix(tests): reranker cache-path tests compare paths, not strin…
fix(tests): reranker cache-path tests compare paths, not strings (#692)…
cdeust commentedon Nov 9, 2026
J'ai ouvert #954 pour la tranche classe 9 «
Path.resolvemocké » (2 tests detest_issue_147_write_class_and_grading, commit 2e27ef4,Refs #692).FileNotFoundErrorlevé depuis<frozen ntpath>:719, dans lePath(db).resolve()du store. Les tests remplaçaientos.getcwdpour tout l'interpréteur, et sous Windowsntpath.realpathlit le cwd même pour un chemin absolu. Windows refuse aussi de supprimer le cwd d'un processus. C'est un défaut du test, pas du produit.os.getcwd()deremember_helpers._grade_content_best_effort. Aucun code de production n'est touché.tests_py/handlers(Linux). En simulantntpath.realpath, l'ancien test donne 2 failed et le nouveau passe. Le mutant « getcwd ne lève pas » est tué.Tranches restantes de la classe 9, à confirmer par une nouvelle mesure Windows : installer rerun (6), file priming aliases (4 + 2, défaut produit possible dans le périmètre ADR-1086), et les tests isolés listés dans le corps de l'issue.
Generated by Claude Code
fix(tests): issue-147 cwd fault hits only the grading fallback (#692) (…
cdeust commentedon Nov 9, 2026
J'ai ouvert #956 pour la tranche classe 9 « installer rerun » (6 erreurs de setup dans
test_installer_rerun_keeps_entries, plustest_fake_uv_pip_filename, commit ed03acf,Refs #692).uvdes tests était un script sans extension. Sous Windows,shutil.whichne retient que les noms dePATHEXT, donc le lanceur prenait le vraiuvdu runner et installait le vraiuv.lock: le répertoire deps contientFlashRank-0…et_yaml, sansprobeyamlniprobens. Pour la même raison,CreateProcessrefusait de lancer le script directement (WinError 193).uv.cmdqui lance le même script avecsys.executable. POSIX ne change pas, et aucun code de production n'est touché.tests_py/scriptssous Linux donne 1922 passed. Les 6 échecs detest_ci_mutation_scopeexistent aussi sans le diff (mutmutabsent de l'environnement). Le nouveau testtest_fake_uv_resolution.pyvérifie la résolution par PATH et le contenu du wrapper.Tranches restantes de la classe 9, à confirmer par une nouvelle mesure Windows : file priming aliases (4 + 2, défaut produit possible dans le périmètre ADR-1086),
test_installer_upgrade_single_version(bash résolu vers WSL, une autre cause) et les tests isolés listés dans le corps de l'issue.Generated by Claude Code
fix(tests): the uv stand-in is a uv.cmd on Windows so PATH lookup rea…
cdeust commentedon Nov 10, 2026
J'ai ouvert #959 pour la tranche classe 9 « file priming aliases » (6 tests :
test_file_priming_aliases×4 ettest_file_memory_priming::test_alias_project_read_preserves_stored_scope×2 ; commit 3ac8699,Refs #692).assert 0.5 == 0.6) :project_ancestorsnormalise la racine en/, etmemory_matches_projectnormalise aussi la colonne. Les prédicats SQL, eux, comparaient la liste àdirectory_contextbrut. Sous Windows, une mémoire stockée sousC:\…\aliasne correspondait donc jamais en SQL. Ce n'est pas un défaut de portée ADR-1086 sur les alias, mais une asymétrie de normalisation. Elle touche aussi les requêtes de session-start, d'auto-recall et d'agent-briefing.RTRIM(REPLACE(directory_context, '\', '/'), '/')(pg_scope_clause.normalized_directory_column), utilisée par les deux clauses et par les 6 requêtes PG brutes des hooks.test_scope_clause_separators.pydonne 6 failed sur main et 9 passed avec le correctif, sous Linux.tests_py/infrastructure,hooksetsharedont les mêmes 6 échecs environnementaux que main (torch absent).Tranches restantes de la classe 9, à confirmer par une nouvelle mesure Windows :
test_installer_upgrade_single_version(bash résolu vers WSL) et les tests isolés listés dans le corps de l'issue.Generated by Claude Code
fix(hooks): the PG briefing passes are tested on a Windows directory (#…
fix(tests): the scope clauses and auto-recall query are tested in pro…
fix(scope): the SQL project predicate normalizes Windows separators l…
cdeust commentedon Nov 10, 2026
CI autopilot : #692 mise en
autopilot:hold— les tranches restantes ne sont plus identifiables sans nouvelle mesure Windows.État de la classe 9 relevé sur
main(origin/mainau 2026-11-10 07:3x UTC) contre le log du run 38008915302 (job 114084097957, 192 lignesFAILED/ERROR) :Path.resolvemocké (2) : fusionnés (fix(tests): the uv stand-in is a uv.cmd on Windows so PATH lookup reaches it (#692) #956, fix(scope): the SQL project predicate normalizes Windows separators like the Python rule (#692) #959, fix(mcp-client): the real-child stdio tests spawn on a subprocess-capable loop (#692) #951, fix(tests): issue-147 cwd fault hits only the grading fallback (#692) #954).test_pipeline_graph_ttl::test_ttl_zero_everything_stale) : déjà corrigé par e7c1ddc (fix(infra): a zero graph TTL is stale even when the clock reads the mtime back (#692) #950), le testtest_ttl_zero_is_stale_at_age_zerofige l'horloge sur le mtime.test_capture_drain(1) ettest_installer_upgrade_single_version(bashrésolu vers WSL, classe 2) : suivis dans leur propre issue d'après le corps de Windows: full-suite debt of 194 failing tests (measured 2026-10-10), fix order by root cause #692.mainsans une nouvelle mesure.Ce qui bloque : aucun workflow
workflow_dispatchne lance la suite sous Windows (aucun check Windows sur le dernier commit demain, aucun workflow Windows déclenchable dans.github/workflows), et le token de la routine ne peut pas ajouter le workflow de mesure (permissionworkflowsabsente).À décider par un humain : relancer le workflow scratch de mesure Windows sur le
mainactuel (ou ajouter un job Windows déclenchable à la main). Avec le nouveau log, la routine reprendra les singles restants un par un ; un commentaire de @cdeust ou l'édition du corps avec la liste mesurée lève ce hold.Generated by Claude Code