codegraph-ir 0.2.1__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codegraph_ir-0.4.0/.pre-commit-hooks.yaml +19 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/Code-IR.md +3 -1
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/PKG-INFO +31 -3
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/README.md +26 -1
- codegraph_ir-0.4.0/docs/agents.md +70 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/docs/architecture-rules.md +20 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/docs/gate-noise.md +9 -1
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/docs/languages.md +44 -0
- codegraph_ir-0.4.0/docs/lsp.md +40 -0
- codegraph_ir-0.4.0/docs/plan-0.3.md +109 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/docs/roadmap.md +1 -1
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/docs/status.md +12 -1
- codegraph_ir-0.4.0/docs/writing-an-adapter.md +309 -0
- codegraph_ir-0.4.0/examples/rust-adapter/NOTES.md +145 -0
- codegraph_ir-0.4.0/examples/rust-adapter/README.md +15 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/pyproject.toml +12 -5
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/schemas/component_spec.schema.json +6 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/__init__.py +1 -1
- codegraph_ir-0.4.0/src/cgir/analyses/coverage_link.py +152 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/analyses/effects.py +49 -15
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/analyses/symbols.py +46 -1
- codegraph_ir-0.4.0/src/cgir/api/lsp_server.py +168 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/api/mcp_server.py +10 -14
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/cli.py +53 -1
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/hooks.py +4 -1
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/ir/component_spec.py +3 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/languages/base.py +20 -1
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/languages/go.py +20 -10
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/languages/python.py +53 -27
- codegraph_ir-0.4.0/src/cgir/languages/registry.py +104 -0
- codegraph_ir-0.4.0/src/cgir/languages/rust.py +982 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/languages/typescript.py +32 -15
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/pipeline.py +40 -2
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/report/diff.py +29 -1
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/report/lint.py +90 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/report/pack.py +6 -1
- codegraph_ir-0.4.0/src/cgir/report/search.py +182 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/slicing/slicer.py +8 -1
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/sources/tree_sitter_source.py +20 -1
- codegraph_ir-0.4.0/tests/unit/test_confidence.py +122 -0
- codegraph_ir-0.4.0/tests/unit/test_coverage_link.py +128 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_go_adapter.py +44 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_lint.py +72 -0
- codegraph_ir-0.4.0/tests/unit/test_lsp.py +112 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_pins.py +18 -0
- codegraph_ir-0.4.0/tests/unit/test_plugin_registry.py +117 -0
- codegraph_ir-0.4.0/tests/unit/test_rust_adapter.py +634 -0
- codegraph_ir-0.4.0/tests/unit/test_search.py +136 -0
- codegraph_ir-0.2.1/src/cgir/languages/registry.py +0 -27
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/.github/workflows/ci.yml +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/.github/workflows/release.yml +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/.gitignore +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/.pre-commit-config.yaml +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/.python-version +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/CLAUDE.md +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/LICENSE +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/RELEASING.md +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/action.yml +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/docs/README.md +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/docs/architecture.md +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/docs/development.md +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/docs/experiment-log.md +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/docs/feature-research.md +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/docs/github-action.md +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/docs/plan-0.2-0.4.md +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/docs/strategy.md +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/examples/agent-pr-contract-drift.md +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/analyses/__init__.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/analyses/call_graph.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/analyses/cfg.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/analyses/entrypoints.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/analyses/param_flow.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/analyses/pdg.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/analyses/purity.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/analyses/reaching_defs.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/api/__init__.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/api/server.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/config.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/export/__init__.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/export/graphml.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/export/html_viz.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/export/json_export.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/export/mermaid.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/export/neo4j.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/ir/__init__.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/ir/edges.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/ir/graph.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/ir/nodes.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/languages/__init__.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/languages/cache.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/manifest.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/py.typed +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/regenerate/__init__.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/regenerate/prompt_pack.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/regenerate/regenerator.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/report/__init__.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/report/flow.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/report/impact.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/report/pins.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/report/stats.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/slicing/__init__.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/sources/__init__.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/sources/base.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/sources/codeql_source.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/sources/joern_source.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/trace/__init__.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/trace/trace_map.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/verify.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/src/cgir/watch.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/__init__.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/conftest.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/fixtures/python_sample/orchestrator.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/fixtures/python_sample/pricing.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/fixtures/ts_sample/api/service.ts +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/fixtures/ts_sample/util.ts +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/integration/__init__.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/integration/test_api.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/integration/test_cli_scan.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/integration/test_hook.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/integration/test_init.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/__init__.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_action.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_call_graph.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_cfg.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_component_spec.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_diff.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_effects.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_entrypoints.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_graphml.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_html_viz.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_impact.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_impact_run.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_ir_graph.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_language_adapter.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_manifest.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_mcp_tools.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_mermaid.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_pack.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_param_flow.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_pdg.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_purity.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_python_di.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_reaching_defs.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_regenerator.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_shapes.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_slicer.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_source_cache.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_stats.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_symbols.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_trace_map.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_tree_sitter_source.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_typescript_adapter.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_verify.py +0 -0
- {codegraph_ir-0.2.1 → codegraph_ir-0.4.0}/tests/unit/test_watch.py +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# CGIR contract seatbelt for the pre-commit framework (https://pre-commit.com).
|
|
2
|
+
# In your repo's .pre-commit-config.yaml:
|
|
3
|
+
#
|
|
4
|
+
# repos:
|
|
5
|
+
# - repo: https://github.com/asonkiya/llm-semantic-compilers
|
|
6
|
+
# rev: v0.2.1
|
|
7
|
+
# hooks:
|
|
8
|
+
# - id: cgir-contract-check
|
|
9
|
+
#
|
|
10
|
+
- id: cgir-contract-check
|
|
11
|
+
name: cgir contract seatbelt
|
|
12
|
+
description: >-
|
|
13
|
+
Block commits that alter component contracts: effect gain/loss on
|
|
14
|
+
net/fs/db, pin violations (cgir: pure / stable-signature / frozen),
|
|
15
|
+
and referenced type-shape drift.
|
|
16
|
+
entry: cgir hook run
|
|
17
|
+
language: python
|
|
18
|
+
pass_filenames: false
|
|
19
|
+
types_or: [python, ts, tsx, go]
|
|
@@ -60,7 +60,9 @@ H --> I[LLM regenerate / test / trace]
|
|
|
60
60
|
"trace":{"type":"array","items":{"type":"string"}}}}
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
`
|
|
63
|
+
`lexical_effects` marks the subset of `effects` backed only by lexical
|
|
64
|
+
(suffix/receiver-name) evidence — lower confidence, reported but not
|
|
65
|
+
build-failing by default. `pins` are developer-declared invariants extracted from `cgir:` comment
|
|
64
66
|
pragmas (`pure`, `no-<tag>`, `stable-signature`, `frozen`): state pins hold on
|
|
65
67
|
every scan; change pins hold across scan pairs and are always enforced.
|
|
66
68
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codegraph-ir
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: The deterministic contract layer for AI-modified codebases — effects, purity, contracts, and blast radius, with zero LLM calls.
|
|
5
5
|
Project-URL: Homepage, https://github.com/asonkiya/llm-semantic-compilers
|
|
6
6
|
Project-URL: Repository, https://github.com/asonkiya/llm-semantic-compilers
|
|
@@ -43,8 +43,9 @@ Requires-Python: >=3.11
|
|
|
43
43
|
Requires-Dist: jsonschema>=4.21
|
|
44
44
|
Requires-Dist: networkx>=3.2
|
|
45
45
|
Requires-Dist: pydantic>=2.6
|
|
46
|
-
Requires-Dist: tree-sitter-go<0.
|
|
46
|
+
Requires-Dist: tree-sitter-go<0.24,>=0.23
|
|
47
47
|
Requires-Dist: tree-sitter-python<0.24,>=0.23
|
|
48
|
+
Requires-Dist: tree-sitter-rust<0.23.3,>=0.23
|
|
48
49
|
Requires-Dist: tree-sitter-typescript<0.24,>=0.23
|
|
49
50
|
Requires-Dist: tree-sitter<0.25,>=0.23
|
|
50
51
|
Requires-Dist: typer>=0.12
|
|
@@ -61,6 +62,8 @@ Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
|
61
62
|
Requires-Dist: types-jsonschema; extra == 'dev'
|
|
62
63
|
Provides-Extra: llm
|
|
63
64
|
Requires-Dist: anthropic>=0.40; extra == 'llm'
|
|
65
|
+
Provides-Extra: lsp
|
|
66
|
+
Requires-Dist: pygls>=1.3; extra == 'lsp'
|
|
64
67
|
Provides-Extra: mcp
|
|
65
68
|
Requires-Dist: mcp>=1.2; extra == 'mcp'
|
|
66
69
|
Description-Content-Type: text/markdown
|
|
@@ -90,13 +93,14 @@ For library/agent use in a project: `uv pip install codegraph-ir`
|
|
|
90
93
|
## The local loop
|
|
91
94
|
|
|
92
95
|
```bash
|
|
93
|
-
cgir scan . # build the .cgir index (Python, TypeScript, Go)
|
|
96
|
+
cgir scan . # build the .cgir index (Python, TypeScript, Go, Rust)
|
|
94
97
|
cgir watch . # keep it live: re-scan + show contract drift on save
|
|
95
98
|
cgir pack app.service.charge --repo . # minimal context bundle for one component
|
|
96
99
|
cgir impact app.service.charge # blast radius: affected callers, entrypoints, tests
|
|
97
100
|
cgir impact app.service.charge --candidate new.py --repo . # radius narrowed by the real delta
|
|
98
101
|
cgir verify app.service.charge --candidate new.py --repo . # contract-check an edit
|
|
99
102
|
cgir hook install # pre-commit seatbelt: block contract-breaking commits
|
|
103
|
+
cgir lsp # editor squiggles for pin violations + drift (cgir[lsp])
|
|
100
104
|
```
|
|
101
105
|
|
|
102
106
|
`pack` → edit → `impact` → `verify` → `hook`, with `watch` keeping the index
|
|
@@ -127,6 +131,30 @@ change touches, and `verify` / `impact_of_change` to contract-check its own
|
|
|
127
131
|
edit before proposing it. See [`examples/`](./examples) for a worked
|
|
128
132
|
agent-PR case study.
|
|
129
133
|
|
|
134
|
+
Setup guide for agents (MCP config + CLAUDE.md snippet): [`docs/agents.md`](./docs/agents.md).
|
|
135
|
+
Or via the [pre-commit framework](https://pre-commit.com): hook id `cgir-contract-check`.
|
|
136
|
+
|
|
137
|
+
## How it compares (honestly)
|
|
138
|
+
|
|
139
|
+
| | **CGIR** | CodeGraph-style MCP graphs | Greptile / CodeRabbit | import-linter / ArchUnit | oasdiff / Pact |
|
|
140
|
+
|---|---|---|---|---|---|
|
|
141
|
+
| Effects & purity contracts per function | ✅ | ❌ | ❌ LLM judgment | ❌ | ❌ |
|
|
142
|
+
| Invariants declared in source (`# cgir: pure`) & enforced | ✅ | ❌ | ❌ | imports only | API boundary only |
|
|
143
|
+
| Deterministic (same input → same verdict, zero LLM) | ✅ | ✅ structure only | ❌ | ✅ | ✅ |
|
|
144
|
+
| Catches "service silently stopped calling the backend" | ✅ | ❌ | sometimes | ❌ | at spec boundaries |
|
|
145
|
+
| Blast radius + coverage-grounded test selection | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
146
|
+
| Agent context over MCP | ✅ contract packs | ✅ broader retrieval | ❌ | ❌ | ❌ |
|
|
147
|
+
| Finds logic bugs | ❌ | ❌ | ✅ | ❌ | ❌ |
|
|
148
|
+
| Languages | 4 builtin + [plugin API](./docs/languages.md) | 30+ | most | per-tool | spec-level |
|
|
149
|
+
| Cycle / layer rules | ✅ | ❌ | ❌ | ✅ mature | ❌ |
|
|
150
|
+
| Cost | free, local | mostly free | ~$24–30/user/mo | free | free |
|
|
151
|
+
|
|
152
|
+
Where CGIR loses, we say so: it does **not** find logic bugs (a subtly wrong
|
|
153
|
+
algorithm with unchanged effects passes the gate — pair it with tests or a
|
|
154
|
+
reviewer), supports 3 languages not 38, and its effect detection is static
|
|
155
|
+
analysis with [documented, measured limits](./docs/gate-noise.md) — every
|
|
156
|
+
tag carries a confidence tier so you know which claims are verified.
|
|
157
|
+
|
|
130
158
|
## Docs
|
|
131
159
|
|
|
132
160
|
- [`docs/strategy.md`](./docs/strategy.md) — positioning: the deterministic contract layer
|
|
@@ -23,13 +23,14 @@ For library/agent use in a project: `uv pip install codegraph-ir`
|
|
|
23
23
|
## The local loop
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
cgir scan . # build the .cgir index (Python, TypeScript, Go)
|
|
26
|
+
cgir scan . # build the .cgir index (Python, TypeScript, Go, Rust)
|
|
27
27
|
cgir watch . # keep it live: re-scan + show contract drift on save
|
|
28
28
|
cgir pack app.service.charge --repo . # minimal context bundle for one component
|
|
29
29
|
cgir impact app.service.charge # blast radius: affected callers, entrypoints, tests
|
|
30
30
|
cgir impact app.service.charge --candidate new.py --repo . # radius narrowed by the real delta
|
|
31
31
|
cgir verify app.service.charge --candidate new.py --repo . # contract-check an edit
|
|
32
32
|
cgir hook install # pre-commit seatbelt: block contract-breaking commits
|
|
33
|
+
cgir lsp # editor squiggles for pin violations + drift (cgir[lsp])
|
|
33
34
|
```
|
|
34
35
|
|
|
35
36
|
`pack` → edit → `impact` → `verify` → `hook`, with `watch` keeping the index
|
|
@@ -60,6 +61,30 @@ change touches, and `verify` / `impact_of_change` to contract-check its own
|
|
|
60
61
|
edit before proposing it. See [`examples/`](./examples) for a worked
|
|
61
62
|
agent-PR case study.
|
|
62
63
|
|
|
64
|
+
Setup guide for agents (MCP config + CLAUDE.md snippet): [`docs/agents.md`](./docs/agents.md).
|
|
65
|
+
Or via the [pre-commit framework](https://pre-commit.com): hook id `cgir-contract-check`.
|
|
66
|
+
|
|
67
|
+
## How it compares (honestly)
|
|
68
|
+
|
|
69
|
+
| | **CGIR** | CodeGraph-style MCP graphs | Greptile / CodeRabbit | import-linter / ArchUnit | oasdiff / Pact |
|
|
70
|
+
|---|---|---|---|---|---|
|
|
71
|
+
| Effects & purity contracts per function | ✅ | ❌ | ❌ LLM judgment | ❌ | ❌ |
|
|
72
|
+
| Invariants declared in source (`# cgir: pure`) & enforced | ✅ | ❌ | ❌ | imports only | API boundary only |
|
|
73
|
+
| Deterministic (same input → same verdict, zero LLM) | ✅ | ✅ structure only | ❌ | ✅ | ✅ |
|
|
74
|
+
| Catches "service silently stopped calling the backend" | ✅ | ❌ | sometimes | ❌ | at spec boundaries |
|
|
75
|
+
| Blast radius + coverage-grounded test selection | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
76
|
+
| Agent context over MCP | ✅ contract packs | ✅ broader retrieval | ❌ | ❌ | ❌ |
|
|
77
|
+
| Finds logic bugs | ❌ | ❌ | ✅ | ❌ | ❌ |
|
|
78
|
+
| Languages | 4 builtin + [plugin API](./docs/languages.md) | 30+ | most | per-tool | spec-level |
|
|
79
|
+
| Cycle / layer rules | ✅ | ❌ | ❌ | ✅ mature | ❌ |
|
|
80
|
+
| Cost | free, local | mostly free | ~$24–30/user/mo | free | free |
|
|
81
|
+
|
|
82
|
+
Where CGIR loses, we say so: it does **not** find logic bugs (a subtly wrong
|
|
83
|
+
algorithm with unchanged effects passes the gate — pair it with tests or a
|
|
84
|
+
reviewer), supports 3 languages not 38, and its effect detection is static
|
|
85
|
+
analysis with [documented, measured limits](./docs/gate-noise.md) — every
|
|
86
|
+
tag carries a confidence tier so you know which claims are verified.
|
|
87
|
+
|
|
63
88
|
## Docs
|
|
64
89
|
|
|
65
90
|
- [`docs/strategy.md`](./docs/strategy.md) — positioning: the deterministic contract layer
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# CGIR for agents — setup and protocol
|
|
2
|
+
|
|
3
|
+
Agents are CGIR's first-class users: instead of grepping and reading whole
|
|
4
|
+
files, an agent queries the semantic index and contract-checks its own edits
|
|
5
|
+
before proposing them.
|
|
6
|
+
|
|
7
|
+
## 1. Serve the index over MCP
|
|
8
|
+
|
|
9
|
+
Scan once (or run `cgir watch` to keep it live), then register the server:
|
|
10
|
+
|
|
11
|
+
```jsonc
|
|
12
|
+
// .mcp.json at the repo root (Claude Code picks this up automatically)
|
|
13
|
+
{
|
|
14
|
+
"mcpServers": {
|
|
15
|
+
"cgir": {
|
|
16
|
+
"command": "cgir",
|
|
17
|
+
"args": ["mcp", "--index", ".cgir"]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Requires `cgir` on PATH with the mcp extra (`uv tool install "codegraph-ir[mcp]"`
|
|
24
|
+
or `uv pip install "codegraph-ir[mcp]"`).
|
|
25
|
+
|
|
26
|
+
## 2. Teach the agent the protocol (CLAUDE.md / AGENTS.md snippet)
|
|
27
|
+
|
|
28
|
+
Paste into the repo's agent instructions:
|
|
29
|
+
|
|
30
|
+
```markdown
|
|
31
|
+
## Semantic index (CGIR)
|
|
32
|
+
|
|
33
|
+
This repo has a semantic contract index served over MCP (server: `cgir`).
|
|
34
|
+
Prefer it over grepping:
|
|
35
|
+
|
|
36
|
+
- **Finding code**: `search(query)` — ranked free terms + contract
|
|
37
|
+
predicates: `kind:pure`, `effects:net`, `effects:none`, `lexical:false`,
|
|
38
|
+
`callers:>3`, `pins:pure`, `entrypoint:HTTP`, `lang:go`, `covered:false`.
|
|
39
|
+
E.g. "effects:net lexical:false callers:>2" = verified network code with
|
|
40
|
+
real fan-in — queries grep and vector search cannot answer.
|
|
41
|
+
- **Loading context to edit a component**: `pack(component_id)` — the
|
|
42
|
+
minimal contract bundle (signature, effects, pins, callee interfaces,
|
|
43
|
+
linked tests). Do NOT read whole files for context first.
|
|
44
|
+
- **Before changing a component**: `impact(component_id)` — blast radius:
|
|
45
|
+
affected callers, entrypoints at risk, exactly which tests to run.
|
|
46
|
+
- **After drafting an edit**: `impact_of_change(repo, component_id,
|
|
47
|
+
candidate)` — the radius narrowed by your edit's real contract delta;
|
|
48
|
+
`verify(repo, component_id, candidate)` — contract-check before proposing.
|
|
49
|
+
|
|
50
|
+
Respect `Pinned:` lines in packs — they are hard invariants (`pure`,
|
|
51
|
+
`no-net`, `stable-signature`, `frozen`), enforced by the pre-commit hook
|
|
52
|
+
and CI. A rewrite that violates a pin will be rejected; don't attempt it.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 3. What the agent gets out of it
|
|
56
|
+
|
|
57
|
+
- **Fewer tokens, better context**: a pack is ~60–800 tokens vs ~400–20,000
|
|
58
|
+
for raw files, and benchmarks show it *beats* whole-file context as
|
|
59
|
+
rewrite input (`docs/experiment-log.md`).
|
|
60
|
+
- **Fewer rejected edits**: `verify`/`impact_of_change` catch contract
|
|
61
|
+
drift before the human (or the hook, or CI) does.
|
|
62
|
+
- **No hallucinated wiring**: packs name DI receivers (`self.svc.method` /
|
|
63
|
+
`this.svc.method`), the exact field names an edit must use.
|
|
64
|
+
|
|
65
|
+
## 4. The enforcement backstop
|
|
66
|
+
|
|
67
|
+
The same contracts the agent consults are enforced deterministically:
|
|
68
|
+
`cgir hook install` (pre-commit), the [GitHub Action](./github-action.md)
|
|
69
|
+
(per-PR), and `cgir: ` pins in source. The agent can't drift from what the
|
|
70
|
+
index says without something noticing — that's the point.
|
|
@@ -58,3 +58,23 @@ component id (`aspen.zones.*` matches `aspen.zones.contains.point_in_polygon`).
|
|
|
58
58
|
- **Kind-aware**: "handlers must be orchestrators, not effect adapters."
|
|
59
59
|
- **Call-target-aware**: layer boundaries over *resolved calls*, catching
|
|
60
60
|
a cross-layer call even when the import is indirect.
|
|
61
|
+
|
|
62
|
+
## Cycles and layers
|
|
63
|
+
|
|
64
|
+
```toml
|
|
65
|
+
[[rule]]
|
|
66
|
+
name = "core is acyclic"
|
|
67
|
+
in = "app.*"
|
|
68
|
+
forbid-cycle = true # Tarjan SCCs over resolved CALLS; self-recursion OK
|
|
69
|
+
|
|
70
|
+
[[rule]]
|
|
71
|
+
name = "layered architecture"
|
|
72
|
+
layers = ["app.api.*", "app.core.*", "app.db.*"] # top -> bottom
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`forbid-cycle` fires once per strongly-connected component (size >= 2),
|
|
76
|
+
naming the cycle. `layers` requires dependencies to point *downward*:
|
|
77
|
+
a `db` component calling an `api` component is a violation; same-layer and
|
|
78
|
+
layer-skipping downward calls are fine; components matching no layer are
|
|
79
|
+
ignored. Unlike import linters, these run over the resolved *call* graph —
|
|
80
|
+
and the same index tells you whether the violating edge also carries `net`.
|
|
@@ -88,7 +88,15 @@ the `io` / `nondeterm` effect tags (a `print`/timestamp shouldn't fail CI).
|
|
|
88
88
|
Trade-off (documented in `diff.violations`): a true removal paired with a
|
|
89
89
|
new unrelated effectful call is masked — the loss stays visible in the
|
|
90
90
|
diff report, it just doesn't fail the build.
|
|
91
|
-
2. **
|
|
91
|
+
2. **Confidence tiers** *(landed 0.3.0)* — every effect tag now carries
|
|
92
|
+
provenance: `high` (exact/prefix table match) vs `lexical` (bare-suffix /
|
|
93
|
+
receiver-name heuristics — `self.now()`, `db.query()`). Gate rules fire
|
|
94
|
+
on high-confidence tags by default; `:any` opts in
|
|
95
|
+
(`effect-gain:db:any`). Measured on camera-tracking: fs evidence is 89%
|
|
96
|
+
lexical, and 48% of the `calls_effectful` taint tree rests on lexical
|
|
97
|
+
evidence — all still *reported*, no longer build-failing. Lexical means
|
|
98
|
+
unverified, not wrong.
|
|
99
|
+
3. **Import-resolution stability** — kind/purity flipping on stub-vs-real
|
|
92
100
|
imports is the dominant `kind-change`/`purity-drop` noise source. A
|
|
93
101
|
scan run compares two checkouts in one environment (CI does this), so it
|
|
94
102
|
only bites when the stub *source itself* changes — but it's worth
|
|
@@ -28,6 +28,7 @@ full test suite green.
|
|
|
28
28
|
| 3 | ingest structural dispatch + attr extraction (normalized `Declaration`s) | ✅ done |
|
|
29
29
|
| 4 | `TypeScriptAdapter` + per-file language dispatch | ✅ done |
|
|
30
30
|
| 5 | `GoAdapter` (package=directory merge, struct-field DI, panic≙raise) | ✅ done |
|
|
31
|
+
| 6 | `RustAdapter` (agent-written from the docs, reviewed & promoted; structs/impl, use-trees, match CFG) | ✅ done |
|
|
31
32
|
|
|
32
33
|
**Two languages ship (Python, TypeScript); a mixed repo scans both.**
|
|
33
34
|
Zero grammar node-type strings remain outside `cgir/languages/`. The CFG builder is pure topology over statement
|
|
@@ -66,3 +67,46 @@ closure, symbol-table resolution, slicing, and all seven product surfaces.
|
|
|
66
67
|
Register it in `cgir/languages/__init__.py:ADAPTERS`. The effect *taxonomy*
|
|
67
68
|
(`io`/`net`/`fs`/`db`/`nondeterm`/`raise`) is language-neutral and fixed in
|
|
68
69
|
`analyses/effects.py`; the adapter only decides which calls map to which tag.
|
|
70
|
+
|
|
71
|
+
**Full authoring guide: [`writing-an-adapter.md`](./writing-an-adapter.md)** — self-contained; written so an implementer (human or agent) needs no other source.
|
|
72
|
+
|
|
73
|
+
## Packaging a language plugin
|
|
74
|
+
|
|
75
|
+
Adapters are discovered via the ``cgir.languages`` entry-point group — no
|
|
76
|
+
fork needed. A minimal plugin package:
|
|
77
|
+
|
|
78
|
+
```toml
|
|
79
|
+
# pyproject.toml of cgir-rust
|
|
80
|
+
[project]
|
|
81
|
+
name = "cgir-rust"
|
|
82
|
+
dependencies = ["codegraph-ir", "tree-sitter-rust"]
|
|
83
|
+
|
|
84
|
+
[project.entry-points."cgir.languages"]
|
|
85
|
+
rust = "cgir_rust:RustAdapter"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
# cgir_rust/__init__.py
|
|
90
|
+
from cgir.languages.base import ADAPTER_API_VERSION, LanguageAdapter
|
|
91
|
+
|
|
92
|
+
class RustAdapter(LanguageAdapter):
|
|
93
|
+
name = "rust"
|
|
94
|
+
file_extensions = (".rs",)
|
|
95
|
+
api_version = ADAPTER_API_VERSION
|
|
96
|
+
# implement: parse, locate_function, direct_effects, call_sites,
|
|
97
|
+
# function_body, block_statements, describe_statement,
|
|
98
|
+
# module_declarations — see GoAdapter for the most recent template.
|
|
99
|
+
# Optional (defaults provided): direct_effects_confidence,
|
|
100
|
+
# global_declared_names.
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`pip install cgir-rust` and `cgir languages` shows it. Safety rules:
|
|
104
|
+
builtins win extension conflicts; a plugin that fails to load, isn't a
|
|
105
|
+
`LanguageAdapter`, or reuses a language name is skipped with a warning —
|
|
106
|
+
a broken plugin never crashes cgir. An `api_version` mismatch warns but
|
|
107
|
+
loads (new adapter methods get base-class defaults, so older plugins
|
|
108
|
+
usually keep working).
|
|
109
|
+
|
|
110
|
+
Start from `src/cgir/languages/go.py` — the newest adapter and the best
|
|
111
|
+
template — and mirror `tests/unit/test_go_adapter.py` for the expected
|
|
112
|
+
pipeline-level test coverage.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# LSP diagnostics — contract drift in your editor
|
|
2
|
+
|
|
3
|
+
`cgir lsp` is a diagnostics-only language server: on every save it rescans
|
|
4
|
+
the repo and publishes
|
|
5
|
+
|
|
6
|
+
- **errors** for pin violations (`# cgir: pure` that isn't) — visible the
|
|
7
|
+
moment you open the workspace;
|
|
8
|
+
- **warnings** for contract drift vs your previous save (the default
|
|
9
|
+
low-noise gate rules: effect gain/loss on net/fs/db, change pins).
|
|
10
|
+
|
|
11
|
+
Side effect worth having: every refresh rewrites `.cgir`, so MCP, `pack`,
|
|
12
|
+
and `impact` stay fresh while you edit.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
uv tool install "codegraph-ir[lsp]" # or add the lsp extra to your env
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Neovim
|
|
19
|
+
|
|
20
|
+
```lua
|
|
21
|
+
vim.api.nvim_create_autocmd("FileType", {
|
|
22
|
+
pattern = { "python", "typescript", "go" },
|
|
23
|
+
callback = function()
|
|
24
|
+
vim.lsp.start({ name = "cgir", cmd = { "cgir", "lsp" },
|
|
25
|
+
root_dir = vim.fs.root(0, ".cgir") or vim.fn.getcwd() })
|
|
26
|
+
end,
|
|
27
|
+
})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## VS Code
|
|
31
|
+
|
|
32
|
+
Use any generic LSP client extension (e.g. "LSP Proxy"/"Generic LSP
|
|
33
|
+
Client") with command `cgir lsp`, or wire it into an existing extension's
|
|
34
|
+
`serverCommand` setting. A dedicated extension is on the roadmap.
|
|
35
|
+
|
|
36
|
+
## Latency honesty
|
|
37
|
+
|
|
38
|
+
Each save triggers a full rescan (~0.5s small repos, ~3–5s large ones).
|
|
39
|
+
Diagnostics update when the scan lands; per-component incremental analysis
|
|
40
|
+
(docs/plan-0.3.md) is the planned fix.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Plan: 0.3 and beyond — trust, reach, and the developer loop
|
|
2
|
+
|
|
3
|
+
Written 2026-07-12 as a durable handoff: any session (any model) should be
|
|
4
|
+
able to pick up any thread from here. Prior art: `plan-0.2-0.4.md` (all
|
|
5
|
+
landed), `gate-noise.md` (measured rule noise), `experiment-log.md`
|
|
6
|
+
(benchmarks), `status.md` (what runs).
|
|
7
|
+
|
|
8
|
+
## Shipped in the 0.3 cook (see git log 2026-07-12)
|
|
9
|
+
|
|
10
|
+
1. **Hook UX** — blocked-commit message explains the staged-state trap
|
|
11
|
+
(`git restore -S -W <file>`), found dogfooding.
|
|
12
|
+
2. **pre-commit framework integration** — `.pre-commit-hooks.yaml` so
|
|
13
|
+
`repo: llm-semantic-compilers` works in anyone's `.pre-commit-config.yaml`.
|
|
14
|
+
3. **Agent onboarding** — `docs/agents.md`: the MCP config + CLAUDE.md/
|
|
15
|
+
AGENTS.md snippet teaching agents the protocol (search → pack → edit →
|
|
16
|
+
impact_of_change → verify).
|
|
17
|
+
4. **go.mod cross-package resolution** — ingest reads the `module` directive
|
|
18
|
+
and stashes it on the Repository node; symbols strips the prefix from Go
|
|
19
|
+
import targets and binds the alias to the target *package directory*
|
|
20
|
+
(any module in it — the directory merge exposes all package members).
|
|
21
|
+
5. **Confidence tiers on effects** — every effect tag carries provenance:
|
|
22
|
+
`high` (exact/prefix table match, import-alias verified) vs `lexical`
|
|
23
|
+
(bare suffix / receiver-name heuristics: `.now`, db-receiver gating).
|
|
24
|
+
New spec field `lexical_effects` (subset of `effects`). Gate rules
|
|
25
|
+
(`effect-gain`/`effect-loss`) fire on high-confidence tags by default;
|
|
26
|
+
`:any` suffix opts into lexical (e.g. `effect-gain:db:any`). This is the
|
|
27
|
+
systematic fix for the `self.now()` false-positive class measured in
|
|
28
|
+
gate-noise.md.
|
|
29
|
+
|
|
30
|
+
## In flight: market-driven quick strikes (designed 2026-07-12)
|
|
31
|
+
|
|
32
|
+
**A. Ranked, structured search** (`report/search.py`, pure over specs; MCP
|
|
33
|
+
`search` delegates; new `cgir search` CLI command).
|
|
34
|
+
|
|
35
|
+
- Free terms rank: exact name (100) > name-word (50) > id substring (20) >
|
|
36
|
+
entrypoint (15) > doc (5); sum across terms, sort desc, cap 25.
|
|
37
|
+
- Structured predicates (colon syntax, AND-combined, mixable with terms):
|
|
38
|
+
`kind:pure_function` (alias `kind:pure`), `effects:net`, `effects:none`,
|
|
39
|
+
`lexical:true|false`, `callers:>3|0`, `calls:>5`, `pins:pure`,
|
|
40
|
+
`pinned:true`, `lang:go`, `entrypoint:true|HTTP`, `covered:false`.
|
|
41
|
+
Caller counts computed from the spec set (reverse of `calls`).
|
|
42
|
+
- The moat angle: contract predicates no vector index can answer
|
|
43
|
+
("effects:net lexical:false callers:>3").
|
|
44
|
+
|
|
45
|
+
**B. Cycles + layers in `cgir lint`** (existing `[[rule]]` config).
|
|
46
|
+
|
|
47
|
+
- `forbid-cycle = true` (+ `in` scope glob): Tarjan SCCs over the spec-level
|
|
48
|
+
call graph within scope; every SCC of size ≥2 is a violation naming the
|
|
49
|
+
cycle. Self-recursion (size-1) is NOT a violation — recursion is normal.
|
|
50
|
+
- `layers = ["app.api.*", "app.core.*", "app.db.*"]` (top→bottom): a
|
|
51
|
+
component in a lower layer calling one in a higher layer is a violation
|
|
52
|
+
(dependencies must point down; same-layer calls fine; unmatched
|
|
53
|
+
components ignored).
|
|
54
|
+
- Neutralizes the import-linter/ArchUnit objection using graph data we
|
|
55
|
+
already have — and our violations can say the edge *also* carries `net`.
|
|
56
|
+
|
|
57
|
+
**C. Coverage-grounded test linkage** *(landed)* — `.coverage` (sqlite,
|
|
58
|
+
numbits decoded via stdlib) / `coverage.json --show-contexts` per-test
|
|
59
|
+
contexts mapped onto component spans, unioned with static linkage. On CGIR
|
|
60
|
+
itself (pytest-cov --cov-context=test): components with test linkage went
|
|
61
|
+
48 → 345 of 389 (12% → 89%). Hot components link many tests (integration
|
|
62
|
+
tests execute the pipeline — accurate); pack embeds at most 5 test sources,
|
|
63
|
+
impact --run keeps the full set. Staleness limit: an old .coverage may
|
|
64
|
+
reference moved lines; static linkage is the floor.
|
|
65
|
+
|
|
66
|
+
## Not built — next up, in value order
|
|
67
|
+
|
|
68
|
+
1. **Per-component incremental analysis** (the latency lever). Watch/hook
|
|
69
|
+
re-scan everything (~0.5–4.5s). Design sketch: content-hash manifest
|
|
70
|
+
identifies changed files → re-ingest only those modules → recompute
|
|
71
|
+
analyses for changed components + their upstream closure
|
|
72
|
+
(`compute_typed_impact` IS the scoping machinery) → splice into the
|
|
73
|
+
cached graph. Correctness traps: effect closure is global (a leaf change
|
|
74
|
+
can flip distant orchestrators — the closure must be re-run over the
|
|
75
|
+
merged spec set, which is cheap since it's pure over specs); symbol
|
|
76
|
+
tables must be rebuilt when imports/decls change, else only call-graph
|
|
77
|
+
edges from changed files. Validate: randomized edit-replay equivalence
|
|
78
|
+
(incremental result == full-scan result on N random historical edits).
|
|
79
|
+
2. **vitest/jest execution for `impact --run`** — runner detection from
|
|
80
|
+
package.json; currently prints the command for TS.
|
|
81
|
+
3. **Go: struct-in-one-file/methods-in-another field DI** — the class-stub
|
|
82
|
+
merge (registry of package-level types before method attachment).
|
|
83
|
+
4. **Data-shape v1.1** — full type text for Python fields (needs a second,
|
|
84
|
+
non-DI fields channel), literal-key fingerprints for un-annotated dict
|
|
85
|
+
returns, base-class field inheritance.
|
|
86
|
+
5. **LSP diagnostics** — watch already computes live drift; publish as
|
|
87
|
+
editor diagnostics (pygls; diagnostics-only server, no completion).
|
|
88
|
+
6. **`cgir decompose`** — the spec's long-term flagship (PDG-sliced
|
|
89
|
+
functional-core/imperative-shell suggestions + verify loop).
|
|
90
|
+
7. **Marketplace listing** for the Action; badges; a demo GIF in README.
|
|
91
|
+
|
|
92
|
+
## The developer loop (what "useful for me" means, concretely)
|
|
93
|
+
|
|
94
|
+
The user's repos and their CGIR state:
|
|
95
|
+
- **camera-tracking** (Py+TS): pins live on branch `cgir-pins`; pre-commit
|
|
96
|
+
hook INSTALLED on the repo (uses PATH cgir = uv tool). `.mcp.json` +
|
|
97
|
+
CLAUDE.md snippet added in this cook so agents use the semantic index.
|
|
98
|
+
- **Indra** (Go): scans clean (301 components). Candidate for pins next.
|
|
99
|
+
- **novel-chrome-extension** (TS/Angular): benchmark corpus, index at
|
|
100
|
+
~/.cgir-indexes/novel-frontend.
|
|
101
|
+
|
|
102
|
+
Daily loop: `cgir watch` in a terminal (live drift), agents route through
|
|
103
|
+
MCP (`pack`/`impact`/`verify` instead of grep), the hook gates commits, CI
|
|
104
|
+
gates PRs (Action), pins encode the invariants worth keeping.
|
|
105
|
+
|
|
106
|
+
## Release discipline
|
|
107
|
+
|
|
108
|
+
Tag-triggered trusted publishing (RELEASING.md). Bump BOTH version spots.
|
|
109
|
+
The maintainer pushes tags — releases are a human decision.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Roadmap
|
|
2
2
|
|
|
3
|
-
**Active plan: [`plan-0.
|
|
3
|
+
**Active plan: [`plan-0.3.md`](./plan-0.3.md)** — trust (confidence tiers), reach (go.mod resolution, pre-commit, agents), and the incremental-analysis design. `plan-0.2-0.4.md` is fully landed.
|
|
4
4
|
|
|
5
5
|
Forward-looking sequencing. The grouping mirrors `Code-IR.md` §Architecture: **P0** is "you can produce a `ComponentSpec`," **P1** is "you can trust it," **P2** is "you can scale it." Within each tier the order below reflects current dependencies, not strict chronology — feel free to interleave when dependencies allow.
|
|
6
6
|
|
|
@@ -71,6 +71,17 @@ cgir scan tests/fixtures/python_sample --out /tmp/cgir-out
|
|
|
71
71
|
| `cgir impact --run` (execute the blast-radius tests via pytest node-ids) | done | `report/impact.py:runnable_selectors` |
|
|
72
72
|
| Data-shape contracts (`types` diff section + opt-in `shape-change` rule; TS interfaces/type-aliases, Py TypedDict/dataclass) | done | `report/diff.py:_type_shape_changes`, `json_export.read_types` |
|
|
73
73
|
| Go adapter (package=dir symbol merge, struct-field DI, panic≙raise, effects tables) | done | `src/cgir/languages/go.py` |
|
|
74
|
+
| Go cross-package resolution (go.mod module-prefix strip; unique dir-suffix fallback) | done | `analyses/symbols.py:_resolve_go_package` |
|
|
75
|
+
| Confidence tiers (`lexical_effects`; gates fire high-confidence by default, `:any` opts in; pack marks `tag?`) | done | `analyses/effects.py:classify_with_confidence` |
|
|
76
|
+
| Global/nonlocal rebinding as mutation (`global_declared_names` hook) | done | `languages/base.py`, `analyses/cfg.py` |
|
|
77
|
+
| pre-commit framework hook (`cgir-contract-check`) + agents guide | done | `.pre-commit-hooks.yaml`, `docs/agents.md` |
|
|
78
|
+
| Ranked/structured search (`cgir search`, MCP `search`): term ranking + contract predicates (kind/effects/lexical/callers/pins/entrypoint/lang/covered) | done | `src/cgir/report/search.py` |
|
|
79
|
+
| `forbid-cycle` (Tarjan SCCs) + `layers` rules in lint | done | `report/lint.py:_cycle_violations`, `_layer_violations` |
|
|
80
|
+
| Coverage-grounded test linkage (.coverage/coverage.json contexts ∪ static; pack test sources capped) | done | `analyses/coverage_link.py` |
|
|
81
|
+
| LSP diagnostics (`cgir lsp`, `cgir[lsp]` extra): pin violations as errors, gate drift as warnings, on save | done | `src/cgir/api/lsp_server.py`, `docs/lsp.md` |
|
|
82
|
+
| Language plugin registry (`cgir.languages` entry points, `cgir languages`, ADAPTER_API_VERSION; builtins win conflicts, broken plugins degrade to warnings) | done | `languages/registry.py:discover_adapters` |
|
|
83
|
+
| Adapter authoring guide, validated by a docs-only agent experiment (Rust adapter, 36/36, 9/9 bar; gaps folded back; PinIndex line_comment fix) | done | `docs/writing-an-adapter.md`, `examples/rust-adapter/` |
|
|
84
|
+
| Rust adapter (structs+impl methods w/ field DI, use-tree imports, match/loop CFG, effect tiers; agent-written, reviewed+promoted) | done | `src/cgir/languages/rust.py` |
|
|
74
85
|
| Entrypoint recognition (HTTP/CLI/task decorators) | done | `src/cgir/analyses/entrypoints.py` |
|
|
75
86
|
| Context packer (`cgir pack`, budget-aware, type closure + docstrings + raises) | done | `src/cgir/report/pack.py` |
|
|
76
87
|
| Docstring / raises / module-variable extraction | done | `tree_sitter_source._docstring_text`, `_raised_names`, `_add_module_variables` |
|
|
@@ -90,7 +101,7 @@ cgir scan tests/fixtures/python_sample --out /tmp/cgir-out
|
|
|
90
101
|
|
|
91
102
|
## Test coverage
|
|
92
103
|
|
|
93
|
-
`pytest -q` runs
|
|
104
|
+
`pytest -q` runs 541 tests, all green (the table below lists the load-bearing files; newer suites — `test_impact.py`, `test_watch.py`, `test_hook.py`, `test_python_di.py`, `test_typescript_adapter.py`, `test_diff.py` — are described by their docstrings):
|
|
94
105
|
|
|
95
106
|
| File | Covers |
|
|
96
107
|
|---|---|
|