Repository navigation
refactor(languages): step 2 — per-pack project readers - #599
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Readers (step 2) need every pack before the first file; the grammar can wait for the first parse. TS module naming moves to a tree-sitter-free naming.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
python_dependencies -> languages/python/dependencies; npm_dependencies,
workspaces, tsconfig_paths -> languages/typescript/{npm,workspaces,tsconfig}.
Pure move plus imports; snapshot and ingest_state unchanged. Extraction domain
drift 0.305, unresolved 0.347 (lock 0.40/0.37).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…out knowing languages ProjectReader/ProjectFacts (cgis.core.project) per pack: Python reads declared dependencies, TypeScript npm names, workspace packages and tsconfig aliases. Facts are data keyed by their ingest_state key; the collector records and compares them through the store, since a pack never touches storage (ruling S1). Store keys, ImportNames and the snapshot (ingest_state included) unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…grammar WorkspacePackages.note asked for the TS extractor before learning the manifest was the repository root's, which it skips anyway; a Python repo with a tooling package.json (prettier, commitlint) loaded the grammar for nothing. Step-1 deferred minor; pinned by a fresh-interpreter CLI ingest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rs on the review path from_facts read only the four keys it knows and cast their values: a new pack's fact under another key vanished without a trace, and a tuple where the store reads back a list rebuilt the graph on every incremental run. Unknown keys now raise ValueError and wrong shapes TypeError (final review I1). Each pack's __init__ imports its project reader, so the seven config-reader modules are now in the review-fingerprint closure (a side effect of ruling S2); the inventory is regenerated so dropping one fails again (final review I2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request implements Step 2 of the Language Packs design, refactoring project configuration reading to be decentralized and language-specific. It introduces the ProjectReader and ProjectFacts protocols in cgis.core.project, allowing each language pack (Python and TypeScript) to read its own project configurations (dependencies, workspaces, and tsconfig paths) without coupling the core collector to specific languages. Additionally, language pack modules are updated to import their tree-sitter grammars lazily inside extractor(), preventing unnecessary grammar loading (e.g., loading TypeScript grammar in Python-only repositories with a root package.json). The ImportNameCollector is refactored into a language-free collector that routes files to pack-specific readers and merges their facts. No review comments were provided for this pull request, so there is no feedback to evaluate.
|



Step 2 of the language-packs migration (spec
docs/specs/2026-10-14-language-packs-design.md"Project facts", plandocs/plans/2026-10-14-language-packs-step2.md, part of #146). Each pack reads its own project configs;import_names.pyno longer knows any language. No graph and noingest_statevalue changes.What moved
cgis/python_dependencies.pylanguages/python/dependencies.pycgis/npm_dependencies.py,workspaces.py,tsconfig_paths.pylanguages/typescript/{npm,workspaces,tsconfig}.pyImportNameCollector(_note_configs_above,note, three lines ofcollect)languages/typescript/project.py→TypeScriptProjectReader/TypeScriptFactslanguages/python/project.py→PythonProjectReader/PythonFactscgis/core/project.py→ProjectReader,ProjectFactsprotocols;LanguagePack.project_reader(root, extractors); registryproject_readers()languages/typescript/naming.py(tree-sitter-free)import_names.pyroutes walk files and the directories above the root to every pack's reader and merges their facts withImportNames.from_facts;ImportNamesfields,record,differ_fromand the store keys are unchanged, so the pipeline and resolver are untouched.Identity report
graph_identity.py diff(nodes, edges andingest_state), main's cgis 64e05c6 vs this branch over the same tree:src/@ 715cd9a — identical (2019 / 7858)python_dependenciesnon-empty)ui/— identical (286 / 497;npm_dependenciesnon-empty)ingest_state) untouched;test_configs_above_root.pychanged by one moved import line only..py-only mapping: identical facts throughout; a stored graph missing the facts rebuilds once, then stays stable.Acceptance
tree_sitter_typescript(mutation-checked: a top-levelPythonExtractorimport in the Python pack fails it).package.jsonat its root loads onlytree_sitter_python(step-1 deferred minor; main loaded both).ingest_statekey, a key the collector cannot store, or a fact of the wrong JSON shape all fail loudly.extractiondomain: drift 0.315 → 0.250, unresolved 0.346 → 0.334 (lock 0.40 / 0.37).Rulings (where the code departs from the spec's text)
ProjectFacts.record(store)/differs_from(store)contradicts "a pack never touches storage" (thepack-isolationgate). Facts arestate()data keyed byingest_statekey; the collector records and compares them. Spec carries an implementation note.extractor(). Supersedes step 1's R7. Side effect: the seven config-reader modules joined the review-fingerprint closure — editing one now changes the reviewer's identity; the inventory pins them..git);note_aboveis the TS reader's..py-only test pipeline keeps today's TS facts.Final review (independent, execution tools)
from_factssilently dropped unknown keys andcasthid wrong shapes (a tuple would rebuild on every incremental run); the review-path inventory was stale after the readers joined the closure.tsconfig.jsonstill loads the TS grammar (TsconfigPaths.aliasesasks for the namer before scoping — pre-existing, same class as the package.json fix); the "Reading tsconfig.json above the ingest root" log line now comes fromcgis.languages.typescript.project.Gate: format, lint, mypy strict, 3191 passed, docstring 99%.
🤖 Generated with Claude Code