diff --git a/README.md b/README.md index 9a7f111..7c72db9 100644 --- a/README.md +++ b/README.md @@ -58,17 +58,17 @@ That single command: one-shot indexing is never a problem. 5. Validates the graph scope: no `test_*` addon modules indexed, no missing and no extra module roots compared to the expected module list, and **every indexed file carrying one of the - configured extensions** (`SOURCE_GLOBS`: `.py .xml .js .rst .md .css .scss .csv`) — anything + configured extensions** (`SOURCE_GLOBS`: `.py .xml .js .scss .csv .sql`) — anything else means `.cbmignore` did not apply. Counts per extension are logged, unexpected ones marked `(!)`: ```text - extensions_configured=.css,.csv,.js,.md,.py,.rst,.scss,.xml + extensions_configured=.csv,.js,.py,.scss,.sql,.xml extensions_indexed=5 files=12057 extension .py files=4949 extension .xml files=3276 extension .json files=39 (!) - unexpected_extensions=1 files=39 (not in SOURCE_GLOBS: .json) + unexpected_extensions=1 files=39 (not in the configured extensions: .json) ``` Both checks read the graph with `query_graph` over its `File` nodes, not with `search_code`: diff --git a/src/codebase_memory_deployv/indexer.py b/src/codebase_memory_deployv/indexer.py index 3449564..9f25a52 100644 --- a/src/codebase_memory_deployv/indexer.py +++ b/src/codebase_memory_deployv/indexer.py @@ -39,7 +39,28 @@ DEFAULT_PROJECT = "odoo_instance" CORE_DIRS = ("odoo/odoo",) CORE_PREFIX = "odoo/odoo/" -SOURCE_GLOBS = ("*.py", "*.xml", "*.js", "*.rst", "*.md", "*.css", "*.scss", "*.csv", "*.sql") +# Prose formats are deliberately absent. Measured on a real Odoo instance (188 modules, +# 77935 DEFINES edges), every extension earns its place by how much of the graph it builds: +# +# .py 2755 files 55603 definitions 20.2 per file 71.3% of the graph +# .xml 1883 files 14844 definitions 7.9 per file 19.0% +# .js 890 files 6368 definitions 7.2 per file 8.2% +# .scss 232 files 912 definitions 3.9 per file 1.2% +# .csv 86 files 86 definitions 1.0 per file 0.1% +# .sql 20 files 35 definitions 1.8 per file 0.0% +# .rst 73 files 73 definitions 1.0 per file 0.1% <- dropped +# .css 8 files 8 definitions 1.0 per file 0.0% <- dropped +# .md 2 files 6 definitions 3.0 per file 0.0% <- dropped +# +# ".rst" and ".css" build exactly one node each — the File node itself, nothing inside it — +# and ".md" only adds the headings of a README (every Section node in that graph came from +# two markdown files). They are module prose, so the graph gains a path and no structure. +# +# ".csv" scores the same 1.0 and stays anyway: an indexed file is also greppable through +# search_code, and ir.model.access.csv is a file people really do search. Extensions are a +# weak lever on memory in any case (these three are 1.4% of the files, where .js is 15%), +# so this is about keeping the graph free of prose, not about making a scope fit. +SOURCE_GLOBS = ("*.py", "*.xml", "*.js", "*.scss", "*.csv", "*.sql") # What .cbmignore lets through, so what the graph is expected to hold: ".py", ".xml", ... SOURCE_EXTENSIONS = tuple(sorted(pattern[1:] for pattern in SOURCE_GLOBS)) MANIFEST_NAMES = ("__manifest__.py", "__openerp__.py") diff --git a/tests/test_indexer.py b/tests/test_indexer.py index 82f88dc..5dc72e9 100644 --- a/tests/test_indexer.py +++ b/tests/test_indexer.py @@ -480,3 +480,26 @@ def test_check_layout_requires_odoo_bin(tmp_path): odoo_dir.mkdir() (odoo_dir / "odoo-bin").write_text("") assert indexer.check_layout(str(tmp_path)) == os.path.join(str(tmp_path), "odoo", "odoo-bin") + + +def test_source_globs_exclude_module_prose(): + """.rst/.md/.css build a File node and nothing inside it; the graph gains no structure.""" + assert ".rst" not in indexer.SOURCE_EXTENSIONS + assert ".md" not in indexer.SOURCE_EXTENSIONS + assert ".css" not in indexer.SOURCE_EXTENSIONS + + +def test_source_globs_keep_csv_for_text_search(): + """ir.model.access.csv builds no structure either, but an indexed file stays greppable.""" + assert ".csv" in indexer.SOURCE_EXTENSIONS + + +def test_render_cbmignore_stops_letting_prose_through(): + content = indexer.render_cbmignore(["extra_addons/vauxoo/sale_extended"]) + assert "!extra_addons/vauxoo/sale_extended/**/*.py" in content + assert "!extra_addons/vauxoo/sale_extended/**/*.csv" in content + assert "*.rst" not in content + assert "*.md" not in content + assert "*.css" not in content + # ".scss" must survive a naive "*.css" removal: it ends with the same three letters. + assert "!extra_addons/vauxoo/sale_extended/**/*.scss" in content