codegraph-brain 0.7.3__tar.gz → 0.7.5__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_brain-0.7.3 → codegraph_brain-0.7.5}/.github/workflows/autodoc.yml +7 -7
- codegraph_brain-0.7.5/.github/workflows/ci.yml +79 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/.github/workflows/guardian.yml +4 -4
- codegraph_brain-0.7.5/.github/workflows/pr-title.yml +51 -0
- codegraph_brain-0.7.5/.release-please-manifest.json +3 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/CHANGELOG.md +19 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/PKG-INFO +1 -1
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/benchmarks/guardian/CURATION.md +66 -0
- codegraph_brain-0.7.5/benchmarks/guardian/pr-313.yaml +43 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/how-to/MCP_REFERENCE.md +6 -1
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-07-31-finder-bug-class-taxonomy.md +90 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/pyproject.toml +1 -1
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/api/mcp_server.py +73 -1
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/findings.py +5 -1
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/render.py +1 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/resolver/engine.py +1 -1
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/resolver/indices.py +41 -22
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_cohesion.py +3 -1
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_chunker.py +3 -1
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_mcp_server.py +151 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_mermaid.py +4 -2
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_ontology_init.py +3 -1
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_resolver_indices.py +57 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/uv.lock +1 -1
- codegraph_brain-0.7.3/.github/workflows/ci.yml +0 -43
- codegraph_brain-0.7.3/.release-please-manifest.json +0 -3
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/.claude-plugin/marketplace.json +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/.github/workflows/release-please.yml +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/.gitignore +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/.pre-commit-config.yaml +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/.python-version +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/CLAUDE.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/CONTRIBUTING.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/LICENSE +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/Makefile +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/PRIVACY.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/README.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/benchmarks/guardian/pr-122.yaml +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/benchmarks/guardian/pr-140.yaml +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/benchmarks/guardian/pr-141.yaml +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/benchmarks/guardian/pr-142.yaml +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/benchmarks/guardian/pr-143.yaml +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/benchmarks/guardian/pr-144.yaml +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/benchmarks/guardian/pr-278.yaml +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/benchmarks/guardian/results.jsonl +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/data/.gitkeep +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/AUDIT.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/CASE_STUDY.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/architecture/HOW_IT_WORKS.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/architecture/ONTOLOGY.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/architecture/PATTERNS_AND_TRIADS.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/architecture/SELF_PORTRAIT.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/architecture/diagrams/pipeline_flow.mermaid +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/architecture/health_badge.json +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/assets/.gitignore +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/assets/cgis-app-avatar.png +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/assets/cgis-app-avatar.svg +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/assets/generate_avatar.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/examples/.gitkeep +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/how-to/AGENT_ONBOARDING.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/how-to/CLI_USAGE.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/lab-notes/2026-06-11-chunked-review-negative-result.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/ontology/.gitkeep +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/ontology/core.yaml +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/ontology/domains.yaml +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/ontology/patterns.yaml +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/ontology/tolerances.lock +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-09-domain-pattern-fingerprint-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-09-pattern-alphabet-motif-basis-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-10-guardian-sprint-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-11-fastapi-di-edges-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-11-guardian-chunked-review-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-11-guardian-chunker-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-11-mcp-drift-validate-fqn-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-11-resolver-split-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-11-symbol-import-edges-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-12-drift-empty-domains-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-12-gate-semantics-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-12-init-ontology-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-12-release-please-ci-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-13-suggest-packages-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-06-13-tangle-anti-pattern-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-07-29-guardian-skeptic-scoring-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-07-30-cgis-fractal-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-07-30-cgis-fractal-plan.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-07-30-chunk-source-filter-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-07-30-chunk-source-filter-plan.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-07-30-genai-client-close-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-07-30-genai-client-close-plan.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-07-30-guardian-precision-bench-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-07-30-guardian-precision-bench-plan.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-07-30-guardian-timeout-retry-design.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-07-30-guardian-timeout-retry-plan.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/BLUEPRINT.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/PRD.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/TDD.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-09-fingerprint-drift.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-10-guardian-context-skeptic-inline.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-10-guardian-structured-findings-bench.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-10-motif-basis-part-b.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-10-unified-pattern-alphabet.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-11-fastapi-di-edges.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-11-guardian-chunked-review.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-11-guardian-chunker.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-11-mcp-drift-validate-fqn.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-11-resolver-split.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-12-drift-empty-domains.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-12-gate-semantics.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-12-init-ontology.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-12-release-please-ci.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-12-symbol-import-edges.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-06-13-suggest-packages.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/plans/2026-07-29-guardian-skeptic-scoring.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/main.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/plugin/.claude-plugin/plugin.json +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/plugin/.mcp.json +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/plugin/README.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/plugin/skills/cgis/SKILL.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/plugin/skills/ingest/SKILL.md +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/release-please-config.json +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/scripts/gen_ideal_graph.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/scripts/generate_health.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/scripts/generate_mcp_ref.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/scripts/generate_schema_docs.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/scripts/guardian_bench.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/scripts/guardian_review.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/scripts/inject_readme_graph.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/scripts/probe_closure_gap.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/scripts/probe_tier_ladder.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/__init__.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/__main__.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/api/.gitkeep +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/api/__init__.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/cli.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/core/.gitkeep +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/core/models.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/extractors/.gitkeep +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/extractors/_python_ast.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/extractors/_python_classes.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/extractors/_python_functions.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/extractors/_python_imports.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/extractors/_python_types.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/extractors/base.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/extractors/python_extractor.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/extractors/typescript_extractor.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/__init__.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/bench.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/chunked.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/chunker.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/collector.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/core.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/diff_index.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/github_poster.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/metrics.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/prompts.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/providers/__init__.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/providers/base.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/providers/gemini.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/providers/mistral.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/providers/ollama.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/recording.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/runner.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/guardian/skeptic.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/pipeline.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/py.typed +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/analysis/__init__.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/analysis/analyzer.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/analysis/anomaly.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/analysis/cohesion.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/analysis/health.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/analysis/suggest_service.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/context/__init__.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/context/audit.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/context/context_service.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/context/prompt.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/context/snippet.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/drift/__init__.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/drift/_scc.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/drift/drift.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/drift/drift_service.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/drift/fingerprint.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/drift/fractal.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/drift/ontology_init.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/drift/quotient.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/drift/triads.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/engine.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/fqn.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/render/__init__.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/render/graph_json.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/render/mermaid.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/query/render/metrics.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/resolver/.gitkeep +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/resolver/__init__.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/resolver/symbols.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/resolver/uplift.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/storage/.gitkeep +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/src/cgis/storage/sqlite_store.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/integration/.gitkeep +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/self_parsing/.gitkeep +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/self_parsing/__init__.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/self_parsing/conftest.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/self_parsing/test_architecture.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/self_parsing/test_drift.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/self_parsing/test_fractal.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/self_parsing/test_init_ontology_roundtrip.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/self_parsing/test_self_parse.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/self_parsing/test_self_parse_ts.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/self_parsing/test_suggest.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/.gitkeep +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/conftest.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/guardian_stubs.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test___main__.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_analyzer.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_audit.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_cli.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_context_service.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_di_acceptance.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_drift.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_drift_service.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_fingerprint.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_fqn.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_fractal.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_gen_ideal_graph.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_generate_mcp_ref.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_graph_json.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_bench.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_chunked.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_collector.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_core.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_diff_index.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_findings.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_metrics.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_poster.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_providers.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_recording.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_render.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_runner.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_guardian_skeptic.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_health_scorer.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_import_acceptance.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_metrics.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_models.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_ontology_compliance.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_patterns_yaml.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_pipeline.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_prompt.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_python_extractor.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_quotient.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_resolver.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_resolver_symbols.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_snippet.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_sqlite_store.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_suggest_service.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_triads.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_typescript_extractor.py +0 -0
- {codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/tests/unit/test_uplift.py +0 -0
|
@@ -28,15 +28,15 @@ jobs:
|
|
|
28
28
|
enable-cache: true
|
|
29
29
|
|
|
30
30
|
- name: Install CGIS
|
|
31
|
-
run: uv sync
|
|
31
|
+
run: uv sync --frozen
|
|
32
32
|
|
|
33
33
|
- name: Self-ingest core engine
|
|
34
|
-
run: uv run cgis ingest ./src --output /tmp/self_graph.db
|
|
34
|
+
run: uv run --frozen cgis ingest ./src --output /tmp/self_graph.db
|
|
35
35
|
|
|
36
36
|
- name: Generate pipeline flow diagram
|
|
37
37
|
run: |
|
|
38
38
|
mkdir -p docs/architecture/diagrams
|
|
39
|
-
uv run cgis trace "cgis.pipeline.IngestionPipeline.run" \
|
|
39
|
+
uv run --frozen cgis trace "cgis.pipeline.IngestionPipeline.run" \
|
|
40
40
|
--db /tmp/self_graph.db \
|
|
41
41
|
--depth 1 \
|
|
42
42
|
--format mermaid \
|
|
@@ -44,21 +44,21 @@ jobs:
|
|
|
44
44
|
> docs/architecture/diagrams/pipeline_flow.mermaid
|
|
45
45
|
|
|
46
46
|
- name: Compute graph health badge
|
|
47
|
-
run: uv run python scripts/generate_health.py --db /tmp/self_graph.db
|
|
47
|
+
run: uv run --frozen python scripts/generate_health.py --db /tmp/self_graph.db
|
|
48
48
|
|
|
49
49
|
- name: Inject graph into README.md
|
|
50
50
|
run: |
|
|
51
|
-
uv run python scripts/inject_readme_graph.py \
|
|
51
|
+
uv run --frozen python scripts/inject_readme_graph.py \
|
|
52
52
|
--db /tmp/self_graph.db \
|
|
53
53
|
--fqn "cgis.pipeline.IngestionPipeline.run" \
|
|
54
54
|
--depth 1 \
|
|
55
55
|
--path-prefix "src/"
|
|
56
56
|
|
|
57
57
|
- name: Generate MCP reference manual
|
|
58
|
-
run: uv run python scripts/generate_mcp_ref.py
|
|
58
|
+
run: uv run --frozen python scripts/generate_mcp_ref.py
|
|
59
59
|
|
|
60
60
|
- name: Sync schema docs from source
|
|
61
|
-
run: uv run python scripts/generate_schema_docs.py
|
|
61
|
+
run: uv run --frozen python scripts/generate_schema_docs.py
|
|
62
62
|
|
|
63
63
|
- name: Open PR with generated docs
|
|
64
64
|
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
name: Continuous Integration
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main, dev, "feat/**", "fix/**", "docs/**" ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
python-ci:
|
|
11
|
+
name: Python Verification
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
# Job level, not step level: a step's own `env` block is not reliably visible
|
|
14
|
+
# to that same step's `if`, and a condition that silently never fires is a
|
|
15
|
+
# gate that looks like protection and is not.
|
|
16
|
+
env:
|
|
17
|
+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
18
|
+
steps:
|
|
19
|
+
- name: Checkout Code
|
|
20
|
+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
21
|
+
with:
|
|
22
|
+
# Full history: the scanner computes new-code metrics by diffing against
|
|
23
|
+
# the base branch, and a depth-1 clone makes it log
|
|
24
|
+
# WARN Could not find ref 'main' in refs/heads, refs/remotes…
|
|
25
|
+
# which silently degrades every new_* metric, new_coverage included.
|
|
26
|
+
fetch-depth: 0
|
|
27
|
+
|
|
28
|
+
- name: Setup uv
|
|
29
|
+
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
30
|
+
with:
|
|
31
|
+
enable-cache: true
|
|
32
|
+
|
|
33
|
+
- name: Lockfile in step with pyproject
|
|
34
|
+
# This is the only step that validates the lockfile. `--frozen` below stops
|
|
35
|
+
# uv rewriting uv.lock, but it does not check that the lock is current —
|
|
36
|
+
# that is `--locked`. Keeping the check explicit gives a clearer failure
|
|
37
|
+
# than a sync error, and it still runs first so an unfrozen uv could never
|
|
38
|
+
# repair the lock ahead of it.
|
|
39
|
+
run: uv lock --check
|
|
40
|
+
|
|
41
|
+
- name: Install Dependencies
|
|
42
|
+
run: uv sync --frozen --group dev
|
|
43
|
+
|
|
44
|
+
- name: Ruff Format Check
|
|
45
|
+
run: uv run --frozen ruff format --check .
|
|
46
|
+
|
|
47
|
+
- name: Ruff Lint
|
|
48
|
+
run: uv run --frozen ruff check .
|
|
49
|
+
|
|
50
|
+
- name: Interrogate (≥90% docstring coverage)
|
|
51
|
+
run: uv run --frozen interrogate -v --fail-under 90 src/cgis
|
|
52
|
+
|
|
53
|
+
- name: Mypy (strict)
|
|
54
|
+
run: uv run --frozen mypy src
|
|
55
|
+
|
|
56
|
+
- name: Pytest
|
|
57
|
+
# xml alongside term-missing: the console form is for a human reading the
|
|
58
|
+
# log, the XML is the only form SonarCloud can import.
|
|
59
|
+
run: uv run --frozen pytest --cov=cgis --cov-report=term-missing --cov-report=xml
|
|
60
|
+
|
|
61
|
+
- name: SonarQube Cloud scan
|
|
62
|
+
# Inert until SONAR_TOKEN exists, so this can land before the migration.
|
|
63
|
+
# Coverage cannot be imported by Automatic Analysis at all — see #317 —
|
|
64
|
+
# so the token must be added only AFTER Automatic Analysis is switched
|
|
65
|
+
# off in the SonarCloud UI, or the two modes conflict.
|
|
66
|
+
if: env.SONAR_TOKEN != ''
|
|
67
|
+
uses: SonarSource/sonarqube-scan-action@22918119ff8e1ca75a623e15c8296b6ea4fbe28f # v8.2.1
|
|
68
|
+
with:
|
|
69
|
+
# Passed as args rather than a committed sonar-project.properties:
|
|
70
|
+
# SonarCloud treats that file as a signal to disable Automatic
|
|
71
|
+
# Analysis, which would break the working setup the moment this
|
|
72
|
+
# merges rather than when the migration is actually performed.
|
|
73
|
+
args: >
|
|
74
|
+
-Dsonar.projectKey=zaebee_codegraph-brain
|
|
75
|
+
-Dsonar.organization=zaebee
|
|
76
|
+
-Dsonar.sources=src,scripts
|
|
77
|
+
-Dsonar.tests=tests
|
|
78
|
+
-Dsonar.python.version=3.12
|
|
79
|
+
-Dsonar.python.coverage.reportPaths=coverage.xml
|
|
@@ -67,10 +67,10 @@ jobs:
|
|
|
67
67
|
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
68
68
|
|
|
69
69
|
- name: Install dependencies
|
|
70
|
-
run: uv sync --extra guardian
|
|
70
|
+
run: uv sync --frozen --extra guardian
|
|
71
71
|
|
|
72
72
|
- name: Build code graph
|
|
73
|
-
run: uv run cgis ingest ./src --output graph.db
|
|
73
|
+
run: uv run --frozen cgis ingest ./src --output graph.db
|
|
74
74
|
|
|
75
75
|
- name: Restore metrics from data branch
|
|
76
76
|
run: |
|
|
@@ -91,7 +91,7 @@ jobs:
|
|
|
91
91
|
GUARDIAN_SKEPTIC: ${{ vars.GUARDIAN_SKEPTIC }}
|
|
92
92
|
GUARDIAN_SKEPTIC_MODEL: ${{ vars.GUARDIAN_SKEPTIC_MODEL }}
|
|
93
93
|
run: |
|
|
94
|
-
uv run python scripts/guardian_review.py \
|
|
94
|
+
uv run --frozen python scripts/guardian_review.py \
|
|
95
95
|
--output guardian_report.md \
|
|
96
96
|
--db graph.db \
|
|
97
97
|
--pr "$PR_NUMBER" \
|
|
@@ -219,7 +219,7 @@ jobs:
|
|
|
219
219
|
git show origin/data/guardian-metrics:guardian_metrics.jsonl \
|
|
220
220
|
> guardian_metrics.jsonl
|
|
221
221
|
|
|
222
|
-
uv run cgis guardian-rate "$PR_NUMBER" "$APPLIED" \
|
|
222
|
+
uv run --frozen cgis guardian-rate "$PR_NUMBER" "$APPLIED" \
|
|
223
223
|
--metrics guardian_metrics.jsonl
|
|
224
224
|
|
|
225
225
|
if git ls-remote --exit-code origin data/guardian-metrics > /dev/null 2>&1; then
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: PR Title
|
|
2
|
+
|
|
3
|
+
# The repository squash-merges, so the PR title becomes the commit subject that
|
|
4
|
+
# release-please parses. A title it does not recognise is dropped from the
|
|
5
|
+
# changelog silently — no warning, no failure. That has now happened twice:
|
|
6
|
+
# #297 ("drift trust batch: …", a descriptive title) and #313
|
|
7
|
+
# ("security(mcp): …", a type that does not exist), the second of which would
|
|
8
|
+
# have shipped a security fix invisibly.
|
|
9
|
+
on:
|
|
10
|
+
pull_request:
|
|
11
|
+
branches: [ main ]
|
|
12
|
+
# `edited` matters: without it, fixing a rejected title would not re-run
|
|
13
|
+
# the check. Kept in a separate workflow from ci.yml so retitling does not
|
|
14
|
+
# replay the whole test suite.
|
|
15
|
+
types: [ opened, edited, reopened, synchronize ]
|
|
16
|
+
|
|
17
|
+
permissions: {}
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
conventional-title:
|
|
21
|
+
name: Conventional commit title
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- name: Check the title release-please will parse
|
|
25
|
+
env:
|
|
26
|
+
# Never interpolate an untrusted title straight into `run:` — it is
|
|
27
|
+
# attacker-controlled text. Through the environment it is just data.
|
|
28
|
+
PR_TITLE: ${{ github.event.pull_request.title }}
|
|
29
|
+
run: |
|
|
30
|
+
set -euo pipefail
|
|
31
|
+
# Types release-please understands. Anything else is dropped from the
|
|
32
|
+
# changelog without complaint, which is the failure being prevented.
|
|
33
|
+
TYPES='feat|fix|docs|chore|style|refactor|perf|test|build|ci|revert'
|
|
34
|
+
if printf '%s' "$PR_TITLE" | grep -qE "^($TYPES)(\([a-z0-9._/-]+\))?!?: .+"; then
|
|
35
|
+
printf '::notice::PR title is a conventional commit.\n'
|
|
36
|
+
exit 0
|
|
37
|
+
fi
|
|
38
|
+
printf '::error::PR title is not a conventional commit: %s\n' "$PR_TITLE"
|
|
39
|
+
cat >&2 <<'MSG'
|
|
40
|
+
|
|
41
|
+
This repository squash-merges, so the PR title becomes the commit
|
|
42
|
+
subject release-please reads. An unrecognised type is dropped from the
|
|
43
|
+
CHANGELOG silently.
|
|
44
|
+
|
|
45
|
+
Expected: <type>(<optional scope>): <description>
|
|
46
|
+
Types: feat fix docs chore style refactor perf test build ci revert
|
|
47
|
+
|
|
48
|
+
Note there is no `security` type — use `fix` with a scope:
|
|
49
|
+
fix(mcp): validate db_path before cgis_ingest creates a database
|
|
50
|
+
MSG
|
|
51
|
+
exit 1
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.5](https://github.com/zaebee/codegraph-brain/compare/codegraph-brain-v0.7.4...codegraph-brain-v0.7.5) (2026-08-01)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Documentation
|
|
7
|
+
|
|
8
|
+
* **spec:** record what changed for [#258](https://github.com/zaebee/codegraph-brain/issues/258) — fixture, second lever, pre-registered gate ([#322](https://github.com/zaebee/codegraph-brain/issues/322)) ([fca8da8](https://github.com/zaebee/codegraph-brain/commit/fca8da8120a7542a71c875d9a960df615f59594e))
|
|
9
|
+
|
|
10
|
+
## [0.7.4](https://github.com/zaebee/codegraph-brain/compare/codegraph-brain-v0.7.3...codegraph-brain-v0.7.4) (2026-08-01)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **mcp:** validate db_path before cgis_ingest creates a database ([#313](https://github.com/zaebee/codegraph-brain/issues/313)) ([2c5499b](https://github.com/zaebee/codegraph-brain/commit/2c5499b8fb7f0d40a03144417c3210900371d499)), closes [#312](https://github.com/zaebee/codegraph-brain/issues/312)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Documentation
|
|
19
|
+
|
|
20
|
+
* auto-sync architecture graph and MCP reference ([#314](https://github.com/zaebee/codegraph-brain/issues/314)) ([7d5b666](https://github.com/zaebee/codegraph-brain/commit/7d5b66669f9dfa40e2fc86dd59a4baf492a9342e))
|
|
21
|
+
|
|
3
22
|
## [0.7.3](https://github.com/zaebee/codegraph-brain/compare/codegraph-brain-v0.7.2...codegraph-brain-v0.7.3) (2026-07-31)
|
|
4
23
|
|
|
5
24
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codegraph-brain
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.5
|
|
4
4
|
Summary: Semantic code graph for AI agents — deterministic FQN resolution, impact analysis and architectural drift gates, exposed over MCP.
|
|
5
5
|
Project-URL: Homepage, https://github.com/zaebee/codegraph-brain
|
|
6
6
|
Project-URL: Repository, https://github.com/zaebee/codegraph-brain
|
|
@@ -206,3 +206,69 @@ Fixed later by human-directed review as #283 (`b2ae97b`), which is the
|
|
|
206
206
|
Precision is unaffected: `matched` stays 0, so the entry still scores `0/10`. The
|
|
207
207
|
addition supplies a recall signal — a real **0/1** where the empty ground truth
|
|
208
208
|
gave a vacuous 1.0.
|
|
209
|
+
|
|
210
|
+
## pr-313 (added 2026-08-01, #315) — first security fixture
|
|
211
|
+
|
|
212
|
+
`security(mcp): validate db_path before cgis_ingest creates a database`.
|
|
213
|
+
|
|
214
|
+
Provenance is stronger than the rest of the corpus: neither entry was mined from
|
|
215
|
+
review dialogue. Both were **reproduced by execution** on the pre-fix code and
|
|
216
|
+
re-run after the fix.
|
|
217
|
+
|
|
218
|
+
- `dangling-symlink-write-primitive` (110-121, major, **security**, `fix-commit`
|
|
219
|
+
`8bcda77`). A `.db` symlink whose target does not exist passes every check —
|
|
220
|
+
`is_file()` is False for a dangling link, so the magic-byte test never runs —
|
|
221
|
+
and SQLite then follows it and creates the target. Demonstrated by writing a
|
|
222
|
+
SQLite header into a non-existent `.ssh/authorized_keys`; refused afterwards.
|
|
223
|
+
- `oserror-escapes-the-tool` (114-124, minor, `logic`, `fix-commit` `72c34eb`).
|
|
224
|
+
The guard runs before `cgis_ingest`'s own try/except and `Path.is_dir()`,
|
|
225
|
+
`.stat()`, `.open()` propagate `OSError`, so a `PermissionError` on the parent
|
|
226
|
+
crashes the MCP tool. Demonstrated with a `chmod 000` parent.
|
|
227
|
+
|
|
228
|
+
### Why `head` is `2d79671` and not the final pull head
|
|
229
|
+
|
|
230
|
+
Standard policy, restated because this PR has four commits: `2d79671` is the
|
|
231
|
+
snapshot the first review ran on and the only one where **both** findings are
|
|
232
|
+
present. The later three are the fixes.
|
|
233
|
+
|
|
234
|
+
### Overlapping ranges are deliberate
|
|
235
|
+
|
|
236
|
+
The two ranges overlap on 114-121. A reviewer can legitimately anchor the
|
|
237
|
+
symlink bypass either at the unresolved `Path(db_path)` (110) or at the
|
|
238
|
+
`is_file()` test where it slips through (121), and the OSError leak sits across
|
|
239
|
+
the whole probe block. Matching is greedy per entry, so one prediction still
|
|
240
|
+
consumes only one entry.
|
|
241
|
+
|
|
242
|
+
### Scoring the historical runs would be unfair
|
|
243
|
+
|
|
244
|
+
Three reviews ran over this PR, but on **different commits** — guardian started
|
|
245
|
+
at 23:38:58, after `72c34eb` had already fixed the OSError defect, so it never
|
|
246
|
+
had a shot at that entry:
|
|
247
|
+
|
|
248
|
+
| reviewer | commit reviewed | findings | GT available | GT hit |
|
|
249
|
+
|---|---|---|---|---|
|
|
250
|
+
| gemini (1st) | `2d79671` | 1 | 2 | 1 (OSError) |
|
|
251
|
+
| guardian | `72c34eb` | 5 | 1 | 0 |
|
|
252
|
+
| gemini (2nd) | `c90bbf8` | 2 | 1 | 1 (symlink) |
|
|
253
|
+
|
|
254
|
+
A replay at `head` gives every reviewer both findings, which is the point of
|
|
255
|
+
pinning the review head. The table above must not be read as guardian missing
|
|
256
|
+
two.
|
|
257
|
+
|
|
258
|
+
### A refuted claim that is deliberately absent
|
|
259
|
+
|
|
260
|
+
Guardian's `multi-dot suffix` finding on this PR was a false positive — it
|
|
261
|
+
asserted `graph.tar.db` should be rejected, when ending in `.db` is exactly the
|
|
262
|
+
stated policy, and its suggested `path.suffixes` fix would have broken a
|
|
263
|
+
legitimate `my.project.db`. Per the policy above, refuted claims are omitted
|
|
264
|
+
from ground truth entirely rather than filed as `ambiguous`, so that precision
|
|
265
|
+
failures stay observable. Recorded here because the cross-family skeptic
|
|
266
|
+
**confirmed** it (`Verified by gemini-2.5-flash`) — the cleanest example yet of
|
|
267
|
+
a skeptic passing a systematic reasoning error (#246).
|
|
268
|
+
|
|
269
|
+
### `category: security`
|
|
270
|
+
|
|
271
|
+
New value, added with this fixture (`findings.py`). The finder prompt does not
|
|
272
|
+
yet offer it — teaching the finder to emit it is #258 and needs bench
|
|
273
|
+
validation. Scoring is unaffected: `_entry_accepts` compares file and line
|
|
274
|
+
range, never category.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# PR 313 — security(mcp): validate db_path before cgis_ingest creates a database.
|
|
2
|
+
# See CURATION.md. First security fixture in the corpus (#315, taxonomy gap #258).
|
|
3
|
+
#
|
|
4
|
+
# Provenance is unusually strong: both findings were REPRODUCED BY EXECUTION on
|
|
5
|
+
# the pre-fix code and re-run after the fix, not mined from review dialogue.
|
|
6
|
+
#
|
|
7
|
+
# head = review head (the snapshot the first review ran on). The three later
|
|
8
|
+
# commits on that branch are the fixes, so replaying the final pull head would
|
|
9
|
+
# make both findings unfindable — CURATION.md erratum on spec §3.1.
|
|
10
|
+
#
|
|
11
|
+
# The two ranges overlap on 114-121. That is inherent rather than sloppy: a
|
|
12
|
+
# reviewer can legitimately anchor the symlink bypass either at the unresolved
|
|
13
|
+
# `Path(db_path)` (110) or at the `is_file()` test where it slips through (121),
|
|
14
|
+
# and the OSError leak sits across the whole probe block. Matching is greedy per
|
|
15
|
+
# entry, so one prediction still consumes only one entry.
|
|
16
|
+
pr: 313
|
|
17
|
+
base: 411f8c5894b6
|
|
18
|
+
head: 2d79671547d4
|
|
19
|
+
findings:
|
|
20
|
+
- id: dangling-symlink-write-primitive
|
|
21
|
+
file: src/cgis/api/mcp_server.py
|
|
22
|
+
lines: [110, 121]
|
|
23
|
+
severity: major
|
|
24
|
+
category: security
|
|
25
|
+
summary: >
|
|
26
|
+
db_path is validated unresolved, so a `.db` symlink whose target does not
|
|
27
|
+
exist passes every check — is_file() is False for a dangling link, so the
|
|
28
|
+
magic-byte test never runs — and SQLite then follows it and creates the
|
|
29
|
+
target. Demonstrated: a symlink to a non-existent .ssh/authorized_keys was
|
|
30
|
+
created as a SQLite database (header b'SQLite format 3\x00').
|
|
31
|
+
source: fix-commit
|
|
32
|
+
- id: oserror-escapes-the-tool
|
|
33
|
+
file: src/cgis/api/mcp_server.py
|
|
34
|
+
lines: [114, 124]
|
|
35
|
+
severity: minor
|
|
36
|
+
category: logic
|
|
37
|
+
summary: >
|
|
38
|
+
The guard runs before cgis_ingest's own try/except, and Path.is_dir(),
|
|
39
|
+
.stat() and .open() all propagate OSError, so a PermissionError on the
|
|
40
|
+
parent directory escapes the MCP tool as a crash instead of a message the
|
|
41
|
+
agent can act on. Demonstrated with a chmod 000 parent directory.
|
|
42
|
+
source: fix-commit
|
|
43
|
+
ambiguous: []
|
|
@@ -176,9 +176,14 @@ Show the structural layout (CONTAINS/DECLARES) of a module or class.
|
|
|
176
176
|
Scan a local directory, extract all symbols, resolve links, and build the graph DB.
|
|
177
177
|
|
|
178
178
|
Use this to initialise or refresh the code knowledge graph for a project.
|
|
179
|
-
|
|
179
|
+
Node FQNs are normalised relative to the workspace root so the graph is
|
|
180
180
|
portable across machines.
|
|
181
181
|
|
|
182
|
+
``db_path`` must name a database — it has to end in ``.db``, ``.sqlite`` or
|
|
183
|
+
``.sqlite3``, live in a directory that already exists, and not point at an
|
|
184
|
+
existing file that is not a SQLite database. cgis will not create parent
|
|
185
|
+
directories.
|
|
186
|
+
|
|
182
187
|
By default the ingest is **incremental**: only changed/new files are
|
|
183
188
|
re-scanned, and the summary reports both what changed this run and the
|
|
184
189
|
whole-graph total. Set ``full_rebuild=True`` to re-scan every file and
|
{codegraph_brain-0.7.3 → codegraph_brain-0.7.5}/docs/specs/2026-07-31-finder-bug-class-taxonomy.md
RENAMED
|
@@ -153,3 +153,93 @@ Steps 2–4 need a provider key, which is why they are not done here.
|
|
|
153
153
|
instructions (we have no such capability in the finder).
|
|
154
154
|
- Copying rule text verbatim — the source is Apache-2.0 Go/agentic tooling for a
|
|
155
155
|
different stack; #258 asks for the taxonomy only.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
# Addendum — 2026-08-01: the experiment is now runnable, and a second intervention appeared
|
|
160
|
+
|
|
161
|
+
Three things changed after this document was written. None of them changes the
|
|
162
|
+
conclusion above (**still nothing shipped to `prompts.py`**), but two of them
|
|
163
|
+
change what the deciding experiment should measure.
|
|
164
|
+
|
|
165
|
+
## 1. The top gap now has a fixture
|
|
166
|
+
|
|
167
|
+
When the table above was written, the Security-Sensitive Code row was **absent**
|
|
168
|
+
with no ground truth to test it against; only Resource Management (pr-278) had
|
|
169
|
+
one. `benchmarks/guardian/pr-313.yaml` (#315) now carries a real security defect:
|
|
170
|
+
|
|
171
|
+
dangling-symlink-write-primitive (major, category: security)
|
|
172
|
+
|
|
173
|
+
A `.db` symlink whose target does not exist defeats a path guard —
|
|
174
|
+
`is_file()` is False for a dangling link, so the magic-byte check never runs and
|
|
175
|
+
SQLite creates the target. Reproduced by execution, not mined from dialogue.
|
|
176
|
+
|
|
177
|
+
`category: security` was added to `Category` with that fixture. The finder prompt
|
|
178
|
+
does **not** offer it — that is this document's subject and still unshipped.
|
|
179
|
+
Scoring is unaffected: `_entry_accepts` compares file and line range, never
|
|
180
|
+
category.
|
|
181
|
+
|
|
182
|
+
So the experiment can now measure both evidenced gaps rather than one.
|
|
183
|
+
|
|
184
|
+
## 2. A second, better-evidenced intervention: exculpating guards
|
|
185
|
+
|
|
186
|
+
Production runs on 2026-07-31 produced a failure mode this document does not
|
|
187
|
+
consider, because it is not a missing class — it is a defect in the classes that
|
|
188
|
+
already exist.
|
|
189
|
+
|
|
190
|
+
On PR #297 the finder returned **12** "Unvalidated dictionary access" findings
|
|
191
|
+
against code that validates with `isinstance` one line above the use. On #313 it
|
|
192
|
+
returned "floating-point comparison may be flaky" on a line carrying an explicit
|
|
193
|
+
`+ 1e-9`. Both trace to focus-area wording that names a *shape* and never names
|
|
194
|
+
the guard that makes an instance a non-finding:
|
|
195
|
+
|
|
196
|
+
> **Unvalidated external data** — … used as a `dict`/… **without first checking
|
|
197
|
+
> its type or presence**
|
|
198
|
+
|
|
199
|
+
The finder matches the shape and does not check whether the guard is present.
|
|
200
|
+
|
|
201
|
+
This matters for sequencing: **adding classes to a checklist that already
|
|
202
|
+
over-fires multiplies noise.** The precision fix should be measured first, or at
|
|
203
|
+
least separately — otherwise a recall gain from new classes and a noise change
|
|
204
|
+
from the rewrite arrive in the same number and neither can be attributed.
|
|
205
|
+
|
|
206
|
+
It is also the cheaper experiment. It needs no new fixture: if adding an
|
|
207
|
+
exculpating clause to each existing focus area lowers `noise` without lowering
|
|
208
|
+
`matched` on the current corpus, that is the whole result.
|
|
209
|
+
|
|
210
|
+
## 3. Replay already exists
|
|
211
|
+
|
|
212
|
+
This document says steps 2–4 "need a provider key". True, but worth stating
|
|
213
|
+
plainly for whoever picks this up: the *machinery* is not missing.
|
|
214
|
+
`uv run --frozen python scripts/guardian_bench.py --replay-finder <recording.json>`
|
|
215
|
+
freezes a finder set and judges it, and `load_finder_recording` strips prior
|
|
216
|
+
verdicts on read so arms stay comparable.
|
|
217
|
+
(#302 was filed claiming this was absent and has been closed as redundant.)
|
|
218
|
+
|
|
219
|
+
The only blocker is credentials.
|
|
220
|
+
|
|
221
|
+
## Pre-registered gate
|
|
222
|
+
|
|
223
|
+
Writing pass/fail criteria before spending money is what made the chunked-review
|
|
224
|
+
no-go mechanical rather than motivated (#160). Same discipline here.
|
|
225
|
+
|
|
226
|
+
**Arm A — exculpating-guard rewrite** (no new classes):
|
|
227
|
+
1. mean `noise` per PR drops by ≥ 25% against the frozen baseline
|
|
228
|
+
2. `matched` does not drop on any PR
|
|
229
|
+
3. pr-141, the noise probe, does not regress
|
|
230
|
+
|
|
231
|
+
**Arm B — class checklist** (security, concurrency, resource, error-handling;
|
|
232
|
+
compact named classes, no per-class few-shot, per #247):
|
|
233
|
+
1. pr-278 `gemini-client-never-closed` OR pr-313 `dangling-symlink-write-primitive`
|
|
234
|
+
is matched at least once in three runs — the hypothesis must show where it matters
|
|
235
|
+
2. no PR drops more than 0.05 below its baseline recall
|
|
236
|
+
3. mean noise does not exceed the Arm A result
|
|
237
|
+
|
|
238
|
+
Ship each arm only on its own gate. If Arm B passes only with Arm A applied,
|
|
239
|
+
say so explicitly rather than reporting the combined delta.
|
|
240
|
+
|
|
241
|
+
## Still out of scope
|
|
242
|
+
|
|
243
|
+
Unchanged from above, plus: do not run Arm B before Arm A has a number. The
|
|
244
|
+
float few-shot regression happened because two effects were entangled in one
|
|
245
|
+
measurement.
|
|
@@ -7,7 +7,7 @@ packages = ["src/cgis"]
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "codegraph-brain"
|
|
10
|
-
version = "0.7.
|
|
10
|
+
version = "0.7.5"
|
|
11
11
|
description = "Semantic code graph for AI agents — deterministic FQN resolution, impact analysis and architectural drift gates, exposed over MCP."
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.12"
|
|
@@ -85,20 +85,92 @@ def _render_subgraph(
|
|
|
85
85
|
return f"❌ Unknown format '{output_format}'. Use 'mermaid' or 'json'."
|
|
86
86
|
|
|
87
87
|
|
|
88
|
+
#: Names cgis will create a database under. Everything else is refused, so an
|
|
89
|
+
#: agent cannot be talked into materialising `~/.ssh/authorized_keys` (#312).
|
|
90
|
+
_DB_SUFFIXES = frozenset({".db", ".sqlite", ".sqlite3"})
|
|
91
|
+
|
|
92
|
+
#: First 16 bytes of any SQLite file.
|
|
93
|
+
_SQLITE_MAGIC = b"SQLite format 3\x00"
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _reject_db_path(db_path: str) -> str | None:
|
|
97
|
+
"""Return a refusal message for an unusable ``db_path``, or None if it is fine.
|
|
98
|
+
|
|
99
|
+
``cgis_ingest`` is the only MCP tool that creates its database — the other
|
|
100
|
+
twelve refuse a path that does not already exist, which is guard enough for
|
|
101
|
+
them. It needs a different one: it reads untrusted repository content and is
|
|
102
|
+
then told by the same agent where to write, so ``db_path`` is attacker-
|
|
103
|
+
reachable in a way the read-only tools' paths are not.
|
|
104
|
+
|
|
105
|
+
Refuses an unexpected suffix, a missing parent directory (creating a tree is
|
|
106
|
+
never wanted), a directory target, and an existing file that is not a
|
|
107
|
+
database. The last is belt-and-braces — SQLite already declines to open a
|
|
108
|
+
non-database — but it fails with a message that says why.
|
|
109
|
+
|
|
110
|
+
Everything is judged on the **resolved** path. A dangling symlink is the
|
|
111
|
+
bypass this guard exists to stop: ``attack.db`` pointing at a target that
|
|
112
|
+
does not exist yet makes ``is_file()`` return False, every check passes, and
|
|
113
|
+
SQLite creates the target. Resolving first means the suffix rule applies to
|
|
114
|
+
where the write actually lands. (A symlink to an *existing* non-database was
|
|
115
|
+
already refused by the magic-byte check.)
|
|
116
|
+
|
|
117
|
+
The filesystem probes are wrapped: this runs *before* ``cgis_ingest``'s own
|
|
118
|
+
try/except, and ``Path.resolve()``, ``Path.is_dir()`` and friends propagate
|
|
119
|
+
``OSError`` (a ``PermissionError`` on the parent, or a symlink loop), which
|
|
120
|
+
would escape the tool as a crash instead of a message the agent can act on.
|
|
121
|
+
"""
|
|
122
|
+
try:
|
|
123
|
+
path = Path(db_path).resolve()
|
|
124
|
+
except OSError as exc:
|
|
125
|
+
return f"❌ Refusing db_path '{db_path}': path is inaccessible ({exc})."
|
|
126
|
+
# Case-insensitive: `.DB` carries the same intent, and on a case-insensitive
|
|
127
|
+
# filesystem it is literally the same file.
|
|
128
|
+
if path.suffix.lower() not in _DB_SUFFIXES:
|
|
129
|
+
allowed = ", ".join(sorted(_DB_SUFFIXES))
|
|
130
|
+
return f"❌ Refusing db_path '{db_path}': name must end in one of {allowed}."
|
|
131
|
+
try:
|
|
132
|
+
if path.is_dir():
|
|
133
|
+
return f"❌ Refusing db_path '{db_path}': it is a directory."
|
|
134
|
+
if not path.parent.is_dir():
|
|
135
|
+
return (
|
|
136
|
+
f"❌ Refusing db_path '{db_path}': parent directory does not exist. "
|
|
137
|
+
"cgis will not create one."
|
|
138
|
+
)
|
|
139
|
+
if path.is_file() and path.stat().st_size > 0:
|
|
140
|
+
with path.open("rb") as fh:
|
|
141
|
+
if fh.read(len(_SQLITE_MAGIC)) != _SQLITE_MAGIC:
|
|
142
|
+
return (
|
|
143
|
+
f"❌ Refusing db_path '{db_path}': existing file is not a SQLite database."
|
|
144
|
+
)
|
|
145
|
+
except OSError as exc:
|
|
146
|
+
return f"❌ Refusing db_path '{db_path}': path is inaccessible ({exc})."
|
|
147
|
+
return None
|
|
148
|
+
|
|
149
|
+
|
|
88
150
|
@mcp.tool()
|
|
89
151
|
def cgis_ingest(project_path: str, db_path: str = _DEFAULT_DB, full_rebuild: bool = False) -> str:
|
|
90
152
|
"""Scan a local directory, extract all symbols, resolve links, and build the graph DB.
|
|
91
153
|
|
|
92
154
|
Use this to initialise or refresh the code knowledge graph for a project.
|
|
93
|
-
|
|
155
|
+
Node FQNs are normalised relative to the workspace root so the graph is
|
|
94
156
|
portable across machines.
|
|
95
157
|
|
|
158
|
+
``db_path`` must name a database — it has to end in ``.db``, ``.sqlite`` or
|
|
159
|
+
``.sqlite3``, live in a directory that already exists, and not point at an
|
|
160
|
+
existing file that is not a SQLite database. cgis will not create parent
|
|
161
|
+
directories.
|
|
162
|
+
|
|
96
163
|
By default the ingest is **incremental**: only changed/new files are
|
|
97
164
|
re-scanned, and the summary reports both what changed this run and the
|
|
98
165
|
whole-graph total. Set ``full_rebuild=True`` to re-scan every file and
|
|
99
166
|
overwrite the database from scratch — use this to drop nodes for files that
|
|
100
167
|
were deleted or renamed, which an incremental run leaves behind.
|
|
101
168
|
"""
|
|
169
|
+
refusal = _reject_db_path(db_path)
|
|
170
|
+
if refusal is not None:
|
|
171
|
+
logger.warning("MCP ingest refused db_path", db=db_path)
|
|
172
|
+
return refusal
|
|
173
|
+
|
|
102
174
|
pipeline = IngestionPipeline(_EXTRACTORS)
|
|
103
175
|
try:
|
|
104
176
|
with SQLiteStore(db_path) as store:
|
|
@@ -5,7 +5,11 @@ from typing import Literal
|
|
|
5
5
|
from pydantic import BaseModel, Field
|
|
6
6
|
|
|
7
7
|
Severity = Literal["critical", "major", "minor"]
|
|
8
|
-
|
|
8
|
+
# "security" exists so curated ground truth can name an exploitable defect (#315).
|
|
9
|
+
# The finder prompt does not yet offer it as a choice — teaching the finder to
|
|
10
|
+
# emit it is #258, and needs bench validation. Scoring is unaffected either way:
|
|
11
|
+
# bench matching compares file and line range, never category.
|
|
12
|
+
Category = Literal["logic", "contract", "tests", "types", "ontology", "security"]
|
|
9
13
|
Verdict = Literal["confirmed", "refuted", "uncertain"]
|
|
10
14
|
|
|
11
15
|
|
|
@@ -126,7 +126,7 @@ class ResolverEngine:
|
|
|
126
126
|
|
|
127
127
|
def _ensure_virtual_node(self, target: str, virtual_nodes: dict[str, Node]) -> None:
|
|
128
128
|
"""Create a virtual boundary node for target if it is not already in the graph."""
|
|
129
|
-
if
|
|
129
|
+
if not self._index.has_node(target) and target not in virtual_nodes:
|
|
130
130
|
virtual_nodes[target] = self._make_virtual_node(
|
|
131
131
|
target, self._index.classify_fqn(target)
|
|
132
132
|
)
|