codegraph-brain 0.16.0__tar.gz → 0.17.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.
Files changed (344) hide show
  1. codegraph_brain-0.17.0/.github/test-count-baseline +1 -0
  2. codegraph_brain-0.17.0/.release-please-manifest.json +3 -0
  3. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/CHANGELOG.md +17 -0
  4. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/PKG-INFO +18 -5
  5. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/README.md +17 -4
  6. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/architecture/diagrams/pipeline_flow.mermaid +12 -2
  7. codegraph_brain-0.17.0/docs/specs/2026-09-05-annotation-graph-design.md +382 -0
  8. codegraph_brain-0.17.0/docs/specs/plans/2026-09-05-annotation-graph-pr1.md +1042 -0
  9. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/pyproject.toml +1 -1
  10. codegraph_brain-0.17.0/src/cgis/extractors/_python_annotations.py +139 -0
  11. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/extractors/_python_ast.py +54 -0
  12. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/extractors/_python_functions.py +186 -11
  13. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/extractors/python_extractor.py +65 -2
  14. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/render/mermaid.py +14 -1
  15. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/resolver/engine.py +34 -6
  16. codegraph_brain-0.17.0/tests/self_parsing/test_annotation_calibration.py +93 -0
  17. codegraph_brain-0.17.0/tests/unit/test_annotation_edges.py +197 -0
  18. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_mermaid.py +54 -0
  19. codegraph_brain-0.17.0/tests/unit/test_python_annotations.py +250 -0
  20. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_resolver.py +26 -5
  21. codegraph_brain-0.17.0/tests/unit/test_self_types.py +177 -0
  22. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/uv.lock +1 -1
  23. codegraph_brain-0.16.0/.github/test-count-baseline +0 -1
  24. codegraph_brain-0.16.0/.release-please-manifest.json +0 -3
  25. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/.claude-plugin/marketplace.json +0 -0
  26. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/.gitattributes +0 -0
  27. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/.github/workflows/autodoc.yml +0 -0
  28. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/.github/workflows/ci.yml +0 -0
  29. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/.github/workflows/guardian.yml +0 -0
  30. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/.github/workflows/pr-title.yml +0 -0
  31. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/.github/workflows/release-please.yml +0 -0
  32. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/.gitignore +0 -0
  33. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/.pre-commit-config.yaml +0 -0
  34. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/.python-version +0 -0
  35. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/CLAUDE.md +0 -0
  36. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/CONTRIBUTING.md +0 -0
  37. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/LICENSE +0 -0
  38. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/Makefile +0 -0
  39. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/PRIVACY.md +0 -0
  40. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/CURATION.md +0 -0
  41. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/calibration.jsonl +0 -0
  42. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/experiments/246-cross-vendor/README.md +0 -0
  43. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/experiments/246-cross-vendor/free-nemotron-quota-cutoff.jsonl +0 -0
  44. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/experiments/401-evidence/README.md +0 -0
  45. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/experiments/401-evidence/pr-399-control-rows.jsonl +0 -0
  46. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/experiments/401-evidence/pr-399-recording.json +0 -0
  47. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/experiments/401-evidence/pr-399-treatment-rows.jsonl +0 -0
  48. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/experiments/407-no-checker-appeal/README.md +0 -0
  49. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/experiments/407-no-checker-appeal/pr-399-control-directive-rows.jsonl +0 -0
  50. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/experiments/407-no-checker-appeal/pr-399-control-prohibition-rows.jsonl +0 -0
  51. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/pr-122.yaml +0 -0
  52. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/pr-140.yaml +0 -0
  53. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/pr-141.yaml +0 -0
  54. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/pr-142.yaml +0 -0
  55. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/pr-143.yaml +0 -0
  56. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/pr-144.yaml +0 -0
  57. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/pr-278.yaml +0 -0
  58. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/pr-313.yaml +0 -0
  59. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/guardian/results.jsonl +0 -0
  60. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian/README.md +0 -0
  61. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian/cal_dot_com.json +0 -0
  62. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian/discourse.json +0 -0
  63. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian/grafana.json +0 -0
  64. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian/keycloak.json +0 -0
  65. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian/sentry.json +0 -0
  66. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian-judged.jsonl +0 -0
  67. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian-p3-judged-run1.jsonl +0 -0
  68. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian-p3-judged-run1.jsonl.corrupted-backup +0 -0
  69. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian-p3-run1.jsonl +0 -0
  70. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian-p3-run2.jsonl +0 -0
  71. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian-p3-run3.jsonl +0 -0
  72. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian-plan.json +0 -0
  73. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian-repeat-judged.jsonl +0 -0
  74. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian-repeat-reviews.jsonl +0 -0
  75. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/benchmarks/martian-reviews.jsonl +0 -0
  76. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/data/.gitkeep +0 -0
  77. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/AUDIT.md +0 -0
  78. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/CASE_STUDY.md +0 -0
  79. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/GUARDIAN_LOCAL_BENCH.md +0 -0
  80. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/GUARDIAN_REMOTE_OLLAMA.md +0 -0
  81. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/architecture/HOW_IT_WORKS.md +0 -0
  82. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/architecture/ONTOLOGY.md +0 -0
  83. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/architecture/PATTERNS_AND_TRIADS.md +0 -0
  84. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/architecture/SELF_PORTRAIT.md +0 -0
  85. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/architecture/health_badge.json +0 -0
  86. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/assets/.gitignore +0 -0
  87. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/assets/cgis-app-avatar.png +0 -0
  88. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/assets/cgis-app-avatar.svg +0 -0
  89. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/assets/generate_avatar.py +0 -0
  90. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/examples/.gitkeep +0 -0
  91. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/how-to/AGENT_ONBOARDING.md +0 -0
  92. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/how-to/CLI_USAGE.md +0 -0
  93. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/how-to/MCP_REFERENCE.md +0 -0
  94. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/lab-notes/2026-06-11-chunked-review-negative-result.md +0 -0
  95. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/ontology/.gitkeep +0 -0
  96. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/ontology/core.yaml +0 -0
  97. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/ontology/domains.yaml +0 -0
  98. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/ontology/patterns.yaml +0 -0
  99. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/ontology/tolerances.lock +0 -0
  100. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-09-domain-pattern-fingerprint-design.md +0 -0
  101. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-09-pattern-alphabet-motif-basis-design.md +0 -0
  102. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-10-guardian-sprint-design.md +0 -0
  103. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-11-fastapi-di-edges-design.md +0 -0
  104. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-11-guardian-chunked-review-design.md +0 -0
  105. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-11-guardian-chunker-design.md +0 -0
  106. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-11-mcp-drift-validate-fqn-design.md +0 -0
  107. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-11-resolver-split-design.md +0 -0
  108. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-11-symbol-import-edges-design.md +0 -0
  109. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-12-drift-empty-domains-design.md +0 -0
  110. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-12-gate-semantics-design.md +0 -0
  111. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-12-init-ontology-design.md +0 -0
  112. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-12-release-please-ci-design.md +0 -0
  113. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-13-suggest-packages-design.md +0 -0
  114. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-06-13-tangle-anti-pattern-design.md +0 -0
  115. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-07-29-guardian-skeptic-scoring-design.md +0 -0
  116. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-07-30-cgis-fractal-design.md +0 -0
  117. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-07-30-cgis-fractal-plan.md +0 -0
  118. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-07-30-chunk-source-filter-design.md +0 -0
  119. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-07-30-chunk-source-filter-plan.md +0 -0
  120. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-07-30-genai-client-close-design.md +0 -0
  121. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-07-30-genai-client-close-plan.md +0 -0
  122. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-07-30-guardian-precision-bench-design.md +0 -0
  123. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-07-30-guardian-precision-bench-plan.md +0 -0
  124. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-07-30-guardian-timeout-retry-design.md +0 -0
  125. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-07-30-guardian-timeout-retry-plan.md +0 -0
  126. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-07-31-finder-bug-class-taxonomy.md +0 -0
  127. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-08-01-aura-autoevolution-poc.md +0 -0
  128. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-08-11-guardian-code-review-bench.md +0 -0
  129. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/2026-08-14-review-fingerprint-design.md +0 -0
  130. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/BLUEPRINT.md +0 -0
  131. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/PRD.md +0 -0
  132. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/TDD.md +0 -0
  133. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-09-fingerprint-drift.md +0 -0
  134. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-10-guardian-context-skeptic-inline.md +0 -0
  135. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-10-guardian-structured-findings-bench.md +0 -0
  136. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-10-motif-basis-part-b.md +0 -0
  137. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-10-unified-pattern-alphabet.md +0 -0
  138. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-11-fastapi-di-edges.md +0 -0
  139. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-11-guardian-chunked-review.md +0 -0
  140. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-11-guardian-chunker.md +0 -0
  141. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-11-mcp-drift-validate-fqn.md +0 -0
  142. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-11-resolver-split.md +0 -0
  143. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-12-drift-empty-domains.md +0 -0
  144. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-12-gate-semantics.md +0 -0
  145. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-12-init-ontology.md +0 -0
  146. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-12-release-please-ci.md +0 -0
  147. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-12-symbol-import-edges.md +0 -0
  148. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-06-13-suggest-packages.md +0 -0
  149. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-07-29-guardian-skeptic-scoring.md +0 -0
  150. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/docs/specs/plans/2026-08-14-review-fingerprint.md +0 -0
  151. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/main.py +0 -0
  152. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/plugin/.claude-plugin/plugin.json +0 -0
  153. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/plugin/.mcp.json +0 -0
  154. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/plugin/README.md +0 -0
  155. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/plugin/skills/cgis/SKILL.md +0 -0
  156. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/plugin/skills/ingest/SKILL.md +0 -0
  157. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/release-please-config.json +0 -0
  158. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/backfill_calibration_fingerprint.py +0 -0
  159. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/backfill_review_fingerprint.py +0 -0
  160. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/check_pytest_raises.py +0 -0
  161. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/check_test_count.py +0 -0
  162. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/colab_bench.sh +0 -0
  163. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/gen_ideal_graph.py +0 -0
  164. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/generate_health.py +0 -0
  165. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/generate_mcp_ref.py +0 -0
  166. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/generate_schema_docs.py +0 -0
  167. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/guardian_bench.py +0 -0
  168. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/guardian_calibrate.py +0 -0
  169. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/guardian_martian.py +0 -0
  170. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/guardian_replay_skeptic.py +0 -0
  171. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/guardian_review.py +0 -0
  172. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/inject_readme_graph.py +0 -0
  173. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/ollama_visitor.sh +0 -0
  174. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/probe_closure_gap.py +0 -0
  175. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/probe_tier_ladder.py +0 -0
  176. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/recordings_from_corpus.py +0 -0
  177. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/scripts/skeptic_arms.py +0 -0
  178. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/__init__.py +0 -0
  179. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/__main__.py +0 -0
  180. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/api/.gitkeep +0 -0
  181. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/api/__init__.py +0 -0
  182. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/api/mcp_server.py +0 -0
  183. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/cli.py +0 -0
  184. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/core/.gitkeep +0 -0
  185. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/core/models.py +0 -0
  186. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/extractors/.gitkeep +0 -0
  187. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/extractors/_python_classes.py +0 -0
  188. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/extractors/_python_imports.py +0 -0
  189. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/extractors/_python_types.py +0 -0
  190. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/extractors/base.py +0 -0
  191. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/extractors/registry.py +0 -0
  192. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/extractors/typescript_extractor.py +0 -0
  193. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/__init__.py +0 -0
  194. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/axes.py +0 -0
  195. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/bench.py +0 -0
  196. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/calibrate.py +0 -0
  197. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/chunked.py +0 -0
  198. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/chunker.py +0 -0
  199. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/collector.py +0 -0
  200. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/core.py +0 -0
  201. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/diff_index.py +0 -0
  202. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/evidence.py +0 -0
  203. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/findings.py +0 -0
  204. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/github_poster.py +0 -0
  205. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/martian.py +0 -0
  206. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/metrics.py +0 -0
  207. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/prompts.py +0 -0
  208. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/providers/__init__.py +0 -0
  209. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/providers/base.py +0 -0
  210. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/providers/gemini.py +0 -0
  211. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/providers/mistral.py +0 -0
  212. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/providers/ollama.py +0 -0
  213. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/providers/openrouter.py +0 -0
  214. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/recording.py +0 -0
  215. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/render.py +0 -0
  216. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/review_fingerprint.py +0 -0
  217. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/runner.py +0 -0
  218. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/guardian/skeptic.py +0 -0
  219. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/pipeline.py +0 -0
  220. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/py.typed +0 -0
  221. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/analysis/__init__.py +0 -0
  222. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/analysis/analyzer.py +0 -0
  223. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/analysis/anomaly.py +0 -0
  224. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/analysis/cohesion.py +0 -0
  225. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/analysis/health.py +0 -0
  226. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/analysis/suggest_service.py +0 -0
  227. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/context/__init__.py +0 -0
  228. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/context/audit.py +0 -0
  229. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/context/context_service.py +0 -0
  230. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/context/prompt.py +0 -0
  231. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/context/snippet.py +0 -0
  232. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/drift/__init__.py +0 -0
  233. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/drift/_scc.py +0 -0
  234. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/drift/drift.py +0 -0
  235. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/drift/drift_service.py +0 -0
  236. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/drift/fingerprint.py +0 -0
  237. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/drift/fractal.py +0 -0
  238. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/drift/ontology_init.py +0 -0
  239. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/drift/quotient.py +0 -0
  240. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/drift/triads.py +0 -0
  241. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/engine.py +0 -0
  242. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/fqn.py +0 -0
  243. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/render/__init__.py +0 -0
  244. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/render/graph_json.py +0 -0
  245. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/query/render/metrics.py +0 -0
  246. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/resolver/.gitkeep +0 -0
  247. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/resolver/__init__.py +0 -0
  248. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/resolver/indices.py +0 -0
  249. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/resolver/symbols.py +0 -0
  250. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/resolver/uplift.py +0 -0
  251. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/storage/.gitkeep +0 -0
  252. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/src/cgis/storage/sqlite_store.py +0 -0
  253. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/integration/.gitkeep +0 -0
  254. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/self_parsing/.gitkeep +0 -0
  255. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/self_parsing/__init__.py +0 -0
  256. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/self_parsing/conftest.py +0 -0
  257. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/self_parsing/test_architecture.py +0 -0
  258. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/self_parsing/test_drift.py +0 -0
  259. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/self_parsing/test_fractal.py +0 -0
  260. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/self_parsing/test_init_ontology_roundtrip.py +0 -0
  261. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/self_parsing/test_self_parse.py +0 -0
  262. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/self_parsing/test_self_parse_ts.py +0 -0
  263. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/self_parsing/test_suggest.py +0 -0
  264. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/.gitkeep +0 -0
  265. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/conftest.py +0 -0
  266. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/guardian_stubs.py +0 -0
  267. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/review_path_inventory.txt +0 -0
  268. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test___main__.py +0 -0
  269. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_analyzer.py +0 -0
  270. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_audit.py +0 -0
  271. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_backfill_calibration_fingerprint.py +0 -0
  272. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_backfill_review_fingerprint.py +0 -0
  273. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_check_pytest_raises.py +0 -0
  274. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_check_test_count.py +0 -0
  275. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_cli.py +0 -0
  276. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_cohesion.py +0 -0
  277. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_context_service.py +0 -0
  278. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_di_acceptance.py +0 -0
  279. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_drift.py +0 -0
  280. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_drift_service.py +0 -0
  281. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_extractor_registry.py +0 -0
  282. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_fingerprint.py +0 -0
  283. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_fqn.py +0 -0
  284. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_fractal.py +0 -0
  285. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_gen_ideal_graph.py +0 -0
  286. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_generate_mcp_ref.py +0 -0
  287. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_graph_json.py +0 -0
  288. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_axes.py +0 -0
  289. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_bench.py +0 -0
  290. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_bench_script.py +0 -0
  291. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_calibrate.py +0 -0
  292. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_calibrate_script.py +0 -0
  293. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_chunked.py +0 -0
  294. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_chunker.py +0 -0
  295. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_collector.py +0 -0
  296. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_core.py +0 -0
  297. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_diff_index.py +0 -0
  298. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_evidence.py +0 -0
  299. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_findings.py +0 -0
  300. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_martian.py +0 -0
  301. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_martian_script.py +0 -0
  302. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_martian_union.py +0 -0
  303. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_metrics.py +0 -0
  304. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_mistral_sampling.py +0 -0
  305. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_ollama_sampling.py +0 -0
  306. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_ollama_truncation.py +0 -0
  307. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_openrouter.py +0 -0
  308. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_poster.py +0 -0
  309. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_providers.py +0 -0
  310. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_providers_name.py +0 -0
  311. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_recording.py +0 -0
  312. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_render.py +0 -0
  313. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_replay_skeptic.py +0 -0
  314. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_review_script.py +0 -0
  315. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_runner.py +0 -0
  316. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_salvage.py +0 -0
  317. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_guardian_skeptic.py +0 -0
  318. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_health_scorer.py +0 -0
  319. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_import_acceptance.py +0 -0
  320. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_mcp_server.py +0 -0
  321. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_metrics.py +0 -0
  322. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_models.py +0 -0
  323. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_ontology_compliance.py +0 -0
  324. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_ontology_init.py +0 -0
  325. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_patterns_yaml.py +0 -0
  326. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_pipeline.py +0 -0
  327. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_prompt.py +0 -0
  328. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_python_extractor.py +0 -0
  329. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_quotient.py +0 -0
  330. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_recordings_from_corpus.py +0 -0
  331. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_resolver_indices.py +0 -0
  332. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_resolver_symbols.py +0 -0
  333. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_review_fingerprint_closure.py +0 -0
  334. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_review_fingerprint_contract.py +0 -0
  335. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_review_fingerprint_digest.py +0 -0
  336. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_review_fingerprint_record.py +0 -0
  337. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_skeptic_arms.py +0 -0
  338. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_snippet.py +0 -0
  339. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_sqlite_store.py +0 -0
  340. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_suggest_service.py +0 -0
  341. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_temperature_source.py +0 -0
  342. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_triads.py +0 -0
  343. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_typescript_extractor.py +0 -0
  344. {codegraph_brain-0.16.0 → codegraph_brain-0.17.0}/tests/unit/test_uplift.py +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.17.0"
3
+ }
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.17.0](https://github.com/zaebee/codegraph-brain/compare/codegraph-brain-v0.16.0...codegraph-brain-v0.17.0) (2026-09-05)
4
+
5
+
6
+ ### Features
7
+
8
+ * **extractors:** record what annotations say — self_types and REFERENCES edges ([#414](https://github.com/zaebee/codegraph-brain/issues/414), [#415](https://github.com/zaebee/codegraph-brain/issues/415)) ([#418](https://github.com/zaebee/codegraph-brain/issues/418)) ([eeaa60b](https://github.com/zaebee/codegraph-brain/commit/eeaa60b831956bb85fff88c987789ea179c2dc71))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **render:** draw one arrow per distinct triple in a mermaid diagram ([#421](https://github.com/zaebee/codegraph-brain/issues/421)) ([19a6067](https://github.com/zaebee/codegraph-brain/commit/19a6067f7c98d84f9d0a3e02e132f85ba0791817))
14
+
15
+
16
+ ### Documentation
17
+
18
+ * auto-sync architecture graph after the annotation-edge work ([#420](https://github.com/zaebee/codegraph-brain/issues/420)) ([061843d](https://github.com/zaebee/codegraph-brain/commit/061843dd0ba997d2fd7549acaa72e7290b10f9cf))
19
+
3
20
  ## [0.16.0](https://github.com/zaebee/codegraph-brain/compare/codegraph-brain-v0.15.0...codegraph-brain-v0.16.0) (2026-08-17)
4
21
 
5
22
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: codegraph-brain
3
- Version: 0.16.0
3
+ Version: 0.17.0
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
@@ -197,6 +197,10 @@ classDef defaultNode fill:#fafafa,stroke:#9e9e9e,stroke-width:1.5px,color:#21212
197
197
  classDef stdlibNode fill:#eceff1,stroke:#607d8b,stroke-width:1px,color:#455a64;
198
198
  classDef externalNode fill:#fff3e0,stroke:#e65100,stroke-width:1px,stroke-dasharray: 3 3,color:#bf360c;
199
199
 
200
+ subgraph sg_models["models.py"]
201
+ models_Edge["Edge (models.py:117)"]:::classNode
202
+ models_Node["Node (models.py:83)"]:::classNode
203
+ end
200
204
  subgraph sg_pipeline["pipeline.py"]
201
205
  pipeline_IngestionPipeline_get_extractor["_get_extractor (pipeline.py:245)"]:::methodNode
202
206
  pipeline_IngestionPipeline_is_noop_incremental["_is_noop_incremental (pipeline.py:185)"]:::methodNode
@@ -205,13 +209,19 @@ classDef externalNode fill:#fff3e0,stroke:#e65100,stroke-width:1px,stroke-dashar
205
209
  pipeline_IngestionPipeline_run["run (pipeline.py:51)"]:::methodNode
206
210
  end
207
211
  subgraph sg_engine["engine.py"]
208
- engine_ResolverEngine["ResolverEngine (engine.py:18)"]:::classNode
209
- engine_ResolverEngine_resolve["resolve (engine.py:35)"]:::methodNode
212
+ engine_ResolverEngine["ResolverEngine (engine.py:19)"]:::classNode
213
+ engine_ResolverEngine_resolve["resolve (engine.py:36)"]:::methodNode
210
214
  end
211
215
  subgraph sg_uplift["uplift.py"]
212
216
  uplift_SemanticUpliftEngine["SemanticUpliftEngine (uplift.py:66)"]:::classNode
213
217
  uplift_SemanticUpliftEngine_execute_uplift["execute_uplift (uplift.py:91)"]:::methodNode
214
218
  end
219
+ subgraph sg_sqlite_store["sqlite_store.py"]
220
+ sqlite_store_SQLiteStore["SQLiteStore (sqlite_store.py:28)"]:::classNode
221
+ end
222
+ pipeline_IngestionPipeline_run -->|REFERENCES| models_Node
223
+ pipeline_IngestionPipeline_run -->|REFERENCES| models_Edge
224
+ pipeline_IngestionPipeline_run -->|REFERENCES| sqlite_store_SQLiteStore
215
225
  pipeline_IngestionPipeline_run -->|CALLS| pipeline_IngestionPipeline_get_extractor
216
226
  pipeline_IngestionPipeline_run -->|CALLS| pipeline_IngestionPipeline_process_file
217
227
  pipeline_IngestionPipeline_run -->|CALLS| pipeline_IngestionPipeline_is_noop_incremental
@@ -224,15 +234,18 @@ classDef externalNode fill:#fff3e0,stroke:#e65100,stroke-width:1px,stroke-dashar
224
234
 
225
235
  | Symbol | Type | File |
226
236
  |--------|------|------|
237
+ | `Node` | CLASS | [`models.py:83`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/core/models.py#L83) |
238
+ | `Edge` | CLASS | [`models.py:117`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/core/models.py#L117) |
227
239
  | `run` | METHOD | [`pipeline.py:51`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/pipeline.py#L51) |
228
240
  | `_process_file` | METHOD | [`pipeline.py:155`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/pipeline.py#L155) |
229
241
  | `_is_noop_incremental` | METHOD | [`pipeline.py:185`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/pipeline.py#L185) |
230
242
  | `_persist_incremental` | METHOD | [`pipeline.py:204`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/pipeline.py#L204) |
231
243
  | `_get_extractor` | METHOD | [`pipeline.py:245`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/pipeline.py#L245) |
232
- | `ResolverEngine` | CLASS | [`engine.py:18`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/resolver/engine.py#L18) |
233
- | `resolve` | METHOD | [`engine.py:35`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/resolver/engine.py#L35) |
244
+ | `ResolverEngine` | CLASS | [`engine.py:19`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/resolver/engine.py#L19) |
245
+ | `resolve` | METHOD | [`engine.py:36`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/resolver/engine.py#L36) |
234
246
  | `SemanticUpliftEngine` | CLASS | [`uplift.py:66`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/resolver/uplift.py#L66) |
235
247
  | `execute_uplift` | METHOD | [`uplift.py:91`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/resolver/uplift.py#L91) |
248
+ | `SQLiteStore` | CLASS | [`sqlite_store.py:28`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/storage/sqlite_store.py#L28) |
236
249
  <!-- END_CGIS_GRAPH -->
237
250
 
238
251
  ---
@@ -147,6 +147,10 @@ classDef defaultNode fill:#fafafa,stroke:#9e9e9e,stroke-width:1.5px,color:#21212
147
147
  classDef stdlibNode fill:#eceff1,stroke:#607d8b,stroke-width:1px,color:#455a64;
148
148
  classDef externalNode fill:#fff3e0,stroke:#e65100,stroke-width:1px,stroke-dasharray: 3 3,color:#bf360c;
149
149
 
150
+ subgraph sg_models["models.py"]
151
+ models_Edge["Edge (models.py:117)"]:::classNode
152
+ models_Node["Node (models.py:83)"]:::classNode
153
+ end
150
154
  subgraph sg_pipeline["pipeline.py"]
151
155
  pipeline_IngestionPipeline_get_extractor["_get_extractor (pipeline.py:245)"]:::methodNode
152
156
  pipeline_IngestionPipeline_is_noop_incremental["_is_noop_incremental (pipeline.py:185)"]:::methodNode
@@ -155,13 +159,19 @@ classDef externalNode fill:#fff3e0,stroke:#e65100,stroke-width:1px,stroke-dashar
155
159
  pipeline_IngestionPipeline_run["run (pipeline.py:51)"]:::methodNode
156
160
  end
157
161
  subgraph sg_engine["engine.py"]
158
- engine_ResolverEngine["ResolverEngine (engine.py:18)"]:::classNode
159
- engine_ResolverEngine_resolve["resolve (engine.py:35)"]:::methodNode
162
+ engine_ResolverEngine["ResolverEngine (engine.py:19)"]:::classNode
163
+ engine_ResolverEngine_resolve["resolve (engine.py:36)"]:::methodNode
160
164
  end
161
165
  subgraph sg_uplift["uplift.py"]
162
166
  uplift_SemanticUpliftEngine["SemanticUpliftEngine (uplift.py:66)"]:::classNode
163
167
  uplift_SemanticUpliftEngine_execute_uplift["execute_uplift (uplift.py:91)"]:::methodNode
164
168
  end
169
+ subgraph sg_sqlite_store["sqlite_store.py"]
170
+ sqlite_store_SQLiteStore["SQLiteStore (sqlite_store.py:28)"]:::classNode
171
+ end
172
+ pipeline_IngestionPipeline_run -->|REFERENCES| models_Node
173
+ pipeline_IngestionPipeline_run -->|REFERENCES| models_Edge
174
+ pipeline_IngestionPipeline_run -->|REFERENCES| sqlite_store_SQLiteStore
165
175
  pipeline_IngestionPipeline_run -->|CALLS| pipeline_IngestionPipeline_get_extractor
166
176
  pipeline_IngestionPipeline_run -->|CALLS| pipeline_IngestionPipeline_process_file
167
177
  pipeline_IngestionPipeline_run -->|CALLS| pipeline_IngestionPipeline_is_noop_incremental
@@ -174,15 +184,18 @@ classDef externalNode fill:#fff3e0,stroke:#e65100,stroke-width:1px,stroke-dashar
174
184
 
175
185
  | Symbol | Type | File |
176
186
  |--------|------|------|
187
+ | `Node` | CLASS | [`models.py:83`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/core/models.py#L83) |
188
+ | `Edge` | CLASS | [`models.py:117`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/core/models.py#L117) |
177
189
  | `run` | METHOD | [`pipeline.py:51`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/pipeline.py#L51) |
178
190
  | `_process_file` | METHOD | [`pipeline.py:155`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/pipeline.py#L155) |
179
191
  | `_is_noop_incremental` | METHOD | [`pipeline.py:185`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/pipeline.py#L185) |
180
192
  | `_persist_incremental` | METHOD | [`pipeline.py:204`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/pipeline.py#L204) |
181
193
  | `_get_extractor` | METHOD | [`pipeline.py:245`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/pipeline.py#L245) |
182
- | `ResolverEngine` | CLASS | [`engine.py:18`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/resolver/engine.py#L18) |
183
- | `resolve` | METHOD | [`engine.py:35`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/resolver/engine.py#L35) |
194
+ | `ResolverEngine` | CLASS | [`engine.py:19`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/resolver/engine.py#L19) |
195
+ | `resolve` | METHOD | [`engine.py:36`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/resolver/engine.py#L36) |
184
196
  | `SemanticUpliftEngine` | CLASS | [`uplift.py:66`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/resolver/uplift.py#L66) |
185
197
  | `execute_uplift` | METHOD | [`uplift.py:91`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/resolver/uplift.py#L91) |
198
+ | `SQLiteStore` | CLASS | [`sqlite_store.py:28`](https://github.com/zaebee/codegraph-brain/blob/main/src/cgis/storage/sqlite_store.py#L28) |
186
199
  <!-- END_CGIS_GRAPH -->
187
200
 
188
201
  ---
@@ -7,6 +7,10 @@ classDef defaultNode fill:#fafafa,stroke:#9e9e9e,stroke-width:1.5px,color:#21212
7
7
  classDef stdlibNode fill:#eceff1,stroke:#607d8b,stroke-width:1px,color:#455a64;
8
8
  classDef externalNode fill:#fff3e0,stroke:#e65100,stroke-width:1px,stroke-dasharray: 3 3,color:#bf360c;
9
9
 
10
+ subgraph sg_models["models.py"]
11
+ models_Edge["Edge (models.py:117)"]:::classNode
12
+ models_Node["Node (models.py:83)"]:::classNode
13
+ end
10
14
  subgraph sg_pipeline["pipeline.py"]
11
15
  pipeline_IngestionPipeline_get_extractor["_get_extractor (pipeline.py:245)"]:::methodNode
12
16
  pipeline_IngestionPipeline_is_noop_incremental["_is_noop_incremental (pipeline.py:185)"]:::methodNode
@@ -15,13 +19,19 @@ classDef externalNode fill:#fff3e0,stroke:#e65100,stroke-width:1px,stroke-dashar
15
19
  pipeline_IngestionPipeline_run["run (pipeline.py:51)"]:::methodNode
16
20
  end
17
21
  subgraph sg_engine["engine.py"]
18
- engine_ResolverEngine["ResolverEngine (engine.py:18)"]:::classNode
19
- engine_ResolverEngine_resolve["resolve (engine.py:35)"]:::methodNode
22
+ engine_ResolverEngine["ResolverEngine (engine.py:19)"]:::classNode
23
+ engine_ResolverEngine_resolve["resolve (engine.py:36)"]:::methodNode
20
24
  end
21
25
  subgraph sg_uplift["uplift.py"]
22
26
  uplift_SemanticUpliftEngine["SemanticUpliftEngine (uplift.py:66)"]:::classNode
23
27
  uplift_SemanticUpliftEngine_execute_uplift["execute_uplift (uplift.py:91)"]:::methodNode
24
28
  end
29
+ subgraph sg_sqlite_store["sqlite_store.py"]
30
+ sqlite_store_SQLiteStore["SQLiteStore (sqlite_store.py:28)"]:::classNode
31
+ end
32
+ pipeline_IngestionPipeline_run -->|REFERENCES| models_Node
33
+ pipeline_IngestionPipeline_run -->|REFERENCES| models_Edge
34
+ pipeline_IngestionPipeline_run -->|REFERENCES| sqlite_store_SQLiteStore
25
35
  pipeline_IngestionPipeline_run -->|CALLS| pipeline_IngestionPipeline_get_extractor
26
36
  pipeline_IngestionPipeline_run -->|CALLS| pipeline_IngestionPipeline_process_file
27
37
  pipeline_IngestionPipeline_run -->|CALLS| pipeline_IngestionPipeline_is_noop_incremental
@@ -0,0 +1,382 @@
1
+ # Annotation-aware graph: receiver resolution (#414) and orphan classes (#415)
2
+
3
+ Status: approved design, revised after independent fact-check
4
+ Issues: [#414](https://github.com/zaebee/codegraph-brain/issues/414), [#415](https://github.com/zaebee/codegraph-brain/issues/415)
5
+
6
+ ## Problem
7
+
8
+ Two reports, one missing capability underneath both: the graph does not record
9
+ what a name's *type annotation* says.
10
+
11
+ **#414** — a call through an injected collaborator (`self.client.search(...)`)
12
+ never resolves. The edge lands on a placeholder node named `self.client.search`,
13
+ so a dependency-injected layer reads as calling nothing.
14
+
15
+ **#415** — there is no query for "classes nothing constructs or extends", and it
16
+ cannot be precise without an annotation edge: an abstract port that three modules
17
+ type against but nobody constructs looks identical to dead code.
18
+
19
+ ## Measurement basis
20
+
21
+ All figures below are from `src/cgis/` at HEAD and a graph ingested from it:
22
+
23
+ ```
24
+ uv run cgis ingest src --source-root src --output <scratch>.db
25
+ → 1 563 nodes / 5 011 edges
26
+ ```
27
+
28
+ **Do not use the repo-root `graph.db` for these numbers.** It is untracked,
29
+ gitignored, and dated 2026-07-29 — the v0.4.0 ingest, 113 commits behind. An
30
+ earlier draft of this spec mixed counts from that stale graph with counts from
31
+ HEAD source, and every graph-derived figure in it was wrong. Any future
32
+ re-measurement must re-ingest first.
33
+
34
+ | Measurement | Value |
35
+ |---|---|
36
+ | Total edges | 5 011 |
37
+ | `self.*` placeholder edges | 139 |
38
+ | …classified `INTERNAL` (i.e. counted as **resolved**) | 139 / 139 |
39
+ | …with exactly two segments after `self` (in scope for D8) | 118 |
40
+ | …deeper or shallower (out of scope for D8) | 21 |
41
+ | `self.<attr>.<method>()` call sites in source | 117 |
42
+ | …receiver resolvable from an annotation | 105 (90%) |
43
+ | Annotation positions (param / return / AnnAssign) | 2 328 |
44
+ | …naming at least one internal CLASS | 577 |
45
+ | `REFERENCES` edges emitted (D9 rule) | **583 measured** (predicted 596) |
46
+ | Current `unresolved_ratio` | 0.2030 |
47
+ | Projected after PR2 | 0.2095 (gate: 0.30) |
48
+ | Projected after PR1's edges also land | 0.1873 |
49
+
50
+ Positions exclude 106 bare `-> None` returns, which name no type.
51
+
52
+ ### Validated on owner-api
53
+
54
+ The implemented feature was run against `Ownima/owner-api` (`ownima-backend/app`,
55
+ 15 928 nodes / 65 792 edges, ~11s) — the DI-heavy codebase #414 was filed from:
56
+
57
+ | Measurement | Value |
58
+ |---|---|
59
+ | `REFERENCES` edges | 2 004 (0 pointing at a non-CLASS node) |
60
+ | classes carrying `self_types` | 677 (2 847 attributes) |
61
+ | `self.<attr>.<method>` sites, **production only** | 554 |
62
+ | …receiver resolvable | **476 (86%)** |
63
+ | …same, tests only | 445 / 1 732 (26%) |
64
+
65
+ 86% against the 66% #414 predicted from its two-source rule: the two sources this
66
+ design adds (`self.x: T = ...` and `self.x = SomeClass()`) are worth ~20 points on
67
+ the very repository the issue was filed from. The 26% in tests is 876 unannotated
68
+ `self.client` (httpx) fixtures, which the rule correctly declines to guess at —
69
+ exactly as #414 anticipated. A figure blending the two reads as 40% and is
70
+ meaningless; #414 measured production only, and so must any comparison to it.
71
+
72
+ **The clearest evidence for D9:** of 367 production classes with no incoming
73
+ production `CALLS`/`EXTENDS`, **180 are held alive solely by the new annotation
74
+ edges**. Without D9 all 180 would read as dead code.
75
+
76
+ ### Two findings that change the issues as filed
77
+
78
+ **The placeholder is INTERNAL, so it improves the health verdict.**
79
+ `SymbolIndex.classify_fqn` (`resolver/indices.py:91`) returns `INTERNAL` for any
80
+ FQN starting with `self.`, and `get_edge_stats` (`storage/sqlite_store.py:511`)
81
+ counts `INTERNAL` as resolved. All 139 placeholder edges are counted on the good
82
+ side of `unresolved_ratio`. The metric moves the *wrong way* as a codebase adopts
83
+ more DI. #414 filed this as "resolved-to-EXTERNAL"; it is worse than that.
84
+
85
+ **The rule as filed reaches 19%, not 66%.** Attributing each of the 117 call
86
+ sites to the construct that would let its receiver resolve:
87
+
88
+ | attr → type source | sites | in #414 as filed |
89
+ |---|---|---|
90
+ | `__init__(self, x: T)` + `self.x = x` | 17 | yes |
91
+ | class-body annotation `x: T` | 5 | yes |
92
+ | `self.x: T = ...` (annotated assignment) | 68 | **no** |
93
+ | `self.x = SomeClass(...)` (constructor assignment) | 15 | **no** |
94
+ | **total** | **105 / 117 (90%)** | 22 / 117 (19%) |
95
+
96
+ One site carries both an `__init__` parameter and a class-body annotation; it is
97
+ counted once, under class-body. The 66% reported on `owner-api` reflects that
98
+ repo's DI style. On code that annotates attributes directly, the dominant
99
+ construct is the annotated assignment, which the proposed rule does not mention.
100
+
101
+ ## Decisions
102
+
103
+ ### D1 — `attr → type` map lives in CLASS node metadata as `self_types`
104
+
105
+ Exact mirror of `local_types`, which already lives in FUNCTION/METHOD node
106
+ metadata and is already read by `_resolve_local_type_call`
107
+ (`resolver/symbols.py:147`). No new index, no new storage shape.
108
+
109
+ For a generic attribute (`items: list[Node]`), `self_types` records the
110
+ *container*, not the argument — `{"items": "pkg.mod.list"}` — because
111
+ `local_types` semantics (what type is this attribute for method-resolution
112
+ purposes) are correct for it, unlike D9's annotation-edge collection below.
113
+
114
+ ### D2 — annotation edges reuse `REFERENCES`; no new EdgeType
115
+
116
+ `REFERENCES` already exists and already carries a property this work needs: it is
117
+ deliberately excluded from `_ENFORCEMENT_EDGE_TYPES` (`query/context/audit.py:31`),
118
+ documented as protection against a false "covered" verdict in an authz audit.
119
+
120
+ A new EdgeType inherits nothing. `BEHAVIORAL_EDGE_TYPES` (`query/engine.py:8-11`)
121
+ is defined as *everything that is not structural*, so any new type silently joins
122
+ every default traversal, and each consumer would have to be re-audited to restore
123
+ the safety `REFERENCES` already has.
124
+
125
+ **Drift exposure, stated precisely.** The fingerprint's *censuses* read only
126
+ `IMPORTS` and `CALLS` (`query/drift/fingerprint.py:331-332`), and `quotient.py`
127
+ and `fractal.py` likewise — so `t_imports`/`t_calls` cannot move. But
128
+ `edge_count = len(internal_edges)` (`fingerprint.py:346`) counts **every** edge
129
+ type, and `drift.py:365` returns `status="no_signal"` when it is zero. A
130
+ `REFERENCES` edge can therefore flip a domain from `no_signal` to scored. No
131
+ realistic domain is exposed (anything with a file and a child already has
132
+ `CONTAINS` edges), but "cannot move a drift baseline" is stronger than the code
133
+ guarantees, and PR1 must check the self-drift status column rather than assume.
134
+
135
+ ### D3 — emit an annotation edge only when the type resolves to an INTERNAL node
136
+
137
+ Stdlib, external, and unresolved annotations are dropped. Edging every position
138
+ regardless of namespace would add 2 328 edges (+46%) of `str`/`dict`/library
139
+ noise and swamp every metric; an `x: str` annotation says nothing about orphan
140
+ classes. Scoped to internal classes it is 583 edges (+11.6%), measured on the
141
+ implemented feature; the 596 in an earlier draft was an AST prediction.
142
+
143
+ ### D4 — annotation positions: parameter, return, `AnnAssign`
144
+
145
+ Parameters already traverse most of the path: `collect_param_type`
146
+ (`extractors/_python_functions.py:267`) emits `raw_dep:<Type>`, and
147
+ `_resolved_dep_edge` (`resolver/engine.py:103`) drops it unless it resolves to a
148
+ VARIABLE. The resolution branch is an extension, not a new mechanism:
149
+
150
+ ```
151
+ raw_dep:<T> → VARIABLE (DI alias) → DEPENDS_ON (unchanged)
152
+ → internal CLASS → REFERENCES (new)
153
+ → anything else → dropped (unchanged)
154
+ ```
155
+
156
+ Return and `AnnAssign` positions reuse that road with new emissions. **What they
157
+ cannot reuse is the type-name extraction — see D9.**
158
+
159
+ **Deliberately excluded: `response_model=SomeSchema`.** That is a value in a call
160
+ keyword, not an annotation — a different extraction path. Request schemas are
161
+ caught as parameter annotations; **response schemas will not be**. #415 reports
162
+ that 11 of its 14 `app/domains` findings are request/response schemas, so this
163
+ leaves a known precision gap on the response half. It is measured in PR3, where
164
+ the false positives it causes are observable, rather than guessed at now.
165
+
166
+ ### D5 — `is_test` is a column, populated at ingest from one `is_test_path()` helper
167
+
168
+ cgis has no notion of a test source today. `_TEST_FILE_PATTERN`
169
+ (`pipeline.py:243`) matches only `foo.test.py` — a JS convention — while
170
+ `tests/`, `test_*.py` and `conftest.py` are ingested as ordinary code. Verified
171
+ on a fixture: a test's construction of a class becomes an ordinary `CALLS` edge,
172
+ identical in every column but source and location. #415's own table shows that
173
+ without this filter all six of its rows read as live, including both real orphans.
174
+
175
+ A column follows the `namespace` precedent exactly, including the `ALTER TABLE`
176
+ path in `_migrate()` (`storage/sqlite_store.py:113`). The decision itself lives in
177
+ a single `is_test_path()` function so that "what is a test" has one definition;
178
+ the column is its cached result, visible to the schema and filterable in SQL.
179
+
180
+ Patterns are hardcoded: any path segment named `tests`, plus `test_*.py`,
181
+ `*_test.py`, `conftest.py`. That covers both repositories that exist —
182
+ `codegraph-brain/tests/` and `owner-api/app/tests/_shared/`. Configuration is
183
+ deferred until a third layout gives it something concrete to express.
184
+
185
+ **Scope limit, deliberate.** The existing `_get_extractor` drop of `.test.py` /
186
+ `.test.ts` files is left alone. Marking Python tests is purely additive — no node
187
+ appears or disappears, so every existing metric is byte-identical and a drift
188
+ movement cannot be blamed on this work. Unifying the drop would add nodes to the
189
+ `ui/` TypeScript graph and move its fingerprint in the same diff, making both
190
+ changes unmeasurable. The inconsistency that remains (Python tests marked, JS
191
+ tests dropped) gets an explanatory comment at `_TEST_FILE_PATTERN` and a
192
+ follow-up issue — it is not left silent.
193
+
194
+ ### D6 — resolution confidence 0.9, not 0.8
195
+
196
+ In `_resolved_call_edge` (`resolver/engine.py:84`), the `0.8` at line 100 is the
197
+ value assigned on resolution *failure*. Reusing it for an annotation-based
198
+ success would make the two indistinguishable on the column that `min_confidence`
199
+ traversal filters read.
200
+
201
+ ### D7 — reuse the existing hierarchy walk and phantom-method policy
202
+
203
+ `_resolve_method_on_class_hierarchy` (`resolver/symbols.py:115`) already walks
204
+ EXTENDS with cycle protection. `_resolve_local_type_call` (`symbols.py:147`)
205
+ already implements the policy #414 needs for its motivating bug: a method that
206
+ does not exist is kept only when the receiver's type is EXTERNAL or STDLIB, and
207
+ dropped for internal *and unknown* types rather than fabricated. Routing
208
+ `self.<attr>.<method>` through that path is what makes a
209
+ deleted-`# type: ignore[attr-defined]`-shaped call visible, and it needs no new
210
+ policy.
211
+
212
+ ### D8 — receiver resolution covers exactly two segments after `self`
213
+
214
+ `self.<attr>.<method>` only — 118 of the 139 placeholder edges. The remaining 21
215
+ are deeper chains (`self._conn.execute(...).fetchall()`, which the extractor
216
+ flattens to target `self._conn.execute.fetchall`) or bare `self._pick_source_root`
217
+ attribute calls.
218
+
219
+ **Those 21 do not keep their current behavior.** PR2's `classify_fqn` split (see
220
+ PR2 below) reclassifies *every* `self.`-prefixed FQN, so all 21 flip from
221
+ counting as resolved to counting as unresolved, even though no resolution is
222
+ attempted for them. That is the honest accounting — they were never resolved —
223
+ but it is a change, and the projected ratio above includes it: 12 unresolvable
224
+ two-segment sites plus 21 out-of-scope placeholders, `(1017+33)/5011 = 0.2095`.
225
+
226
+ ### D9 — an annotation names every internal class inside it, not its cleaned head
227
+
228
+ `clean_python_type_string` (`extractors/_python_types.py:44`) reduces `list[Node]`
229
+ to `list`: it answers "what type is this variable" — correct for `local_types`,
230
+ where the receiver of `x.append()` really is a `list`. It is the wrong question
231
+ for a reference edge.
232
+
233
+ Measured on HEAD: of 577 annotation positions naming an internal class, that
234
+ function surfaces the class in only 247. **330 (57%) are swallowed by a generic
235
+ wrapper** — `list[...]` (211), `tuple[...]` (33), `dict[...]` (30), `frozenset`
236
+ (16), `Sequence` (15) and others. Eleven internal classes are referenced *only*
237
+ from inside generics and would receive zero annotation edges:
238
+
239
+ ```
240
+ AmbiguousEntry, ArchitecturalAnomaly, Bridge, Community, DuckDBAnalyzer,
241
+ GoldenComment, NodeMetric, PrPlan, SliceCounts, _IdAllocator
242
+ ```
243
+
244
+ (An earlier draft listed `UnionRun` here too. That was wrong: its only
245
+ external-looking mention is the self-referencing return annotation described
246
+ above, so it is a genuine orphan candidate rather than a D9 rescue.)
247
+
248
+ Any of those that is also constructed only from tests would be reported as a
249
+ false orphan by #415 — the exact failure the annotation edge exists to prevent.
250
+
251
+ So annotation extraction collects **all** type names appearing in the annotation
252
+ (walking `Name`/`Attribute` nodes, and parsing string annotations), emitting one
253
+ `REFERENCES` edge per distinct internal class. `clean_python_type_string` is left
254
+ untouched and keeps serving `local_types`. This is what raises the edge count
255
+ from 247 to 583.
256
+
257
+ **Two exclusions, discovered during implementation and not in the original
258
+ design.** "Every name in the annotation" is too literal on its own:
259
+
260
+ * **Typing wrappers unwrap rather than count.** `Optional`, `Union` and
261
+ `Annotated` are not classes anyone would reference, so they are dropped while
262
+ their arguments are kept — `Optional[Node]` yields `Node`, not both. Qualified
263
+ forms (`typing.Optional[X]`) unwrap identically; the module prefix is stripped
264
+ before the wrapper test, matching `clean_python_type_string`. Note that
265
+ tree-sitter parses `Optional[X]` as `generic_type` but `typing.Optional[X]` as
266
+ `subscript`, so both shapes must be handled — an early implementation handled
267
+ only the first and leaked `raw_dep:typing.Optional`.
268
+ * **Call nodes are skipped.** In `Annotated[Session, Depends(get_db)]` the second
269
+ argument is metadata, not a type; collecting it would emit candidates for
270
+ `Depends` and `get_db`. The annotation yields `Session` alone.
271
+
272
+ Ordinary containers are NOT wrappers and keep both parts: `list[Node]` yields
273
+ `list` and `Node`, which is the entire point of D9. A dotted non-wrapper base is
274
+ preserved whole — `collections.abc.Sequence[Node]` yields both.
275
+
276
+ **A self-reference is not a reference.** `-> "UnionRun"` on `UnionRun`'s own
277
+ classmethod produces no incoming edge for `UnionRun`. This is implemented, not
278
+ emergent: `_resolved_dep_edge` (`resolver/engine.py`) drops the candidate when
279
+ `edge.source` equals the resolved class target or lives inside it (a method,
280
+ or a nested class — checked as `edge.source.startswith(f"{class_target}.")`,
281
+ a dot-boundary test so `Foo` is not treated as inside `FooBar`). A class
282
+ naming itself is not evidence anyone uses it, and counting it would
283
+ manufacture a false negative in the orphan query.
284
+
285
+ ## Work breakdown
286
+
287
+ Three sequential PRs. Each merges before the next starts.
288
+
289
+ ### PR1 — extractor foundation
290
+
291
+ * `self_types` on CLASS node metadata, from all four sources in the table above.
292
+ * Type-name collection per D9, separate from `clean_python_type_string`.
293
+ * `raw_dep:` emission extended to return and `AnnAssign` positions.
294
+ * `_resolved_dep_edge` gains the internal-CLASS → `REFERENCES` branch (D4).
295
+ * Check the self-drift `status` column for any domain moving off `no_signal` (D2).
296
+
297
+ Serves both issues; neither can be precise without it.
298
+
299
+ ### PR2 — #414 receiver resolution
300
+
301
+ * `resolve_self_call` handles the dotted form: split `client.search` into
302
+ receiver and method, look up `self_types`, then delegate to the existing
303
+ hierarchy walk (D7).
304
+ * `classify_fqn` stops reporting `self.`-prefixed FQNs as `INTERNAL`. The
305
+ leading-`.` (relative import) branch is unchanged; the two currently share one
306
+ condition (`indices.py:91`) and must be split.
307
+ * Fixes the placeholder collision as a consequence: two unrelated classes with a
308
+ same-named attribute no longer share one vertex.
309
+
310
+ ### PR3 — #415 orphan query
311
+
312
+ * `is_test_path()` + `Node.is_test` + column migration (D5).
313
+ * Orphans query: internal CLASS nodes with no incoming `CALLS` or `EXTENDS` from
314
+ a non-test source. `IMPORTS_SYMBOL` excluded.
315
+ * Surfaced as a CLI command and an MCP tool, following the existing
316
+ `audit_reachability` shape.
317
+ * Measure the `response_model=` precision gap (D4) and decide it here.
318
+
319
+ ## Testing
320
+
321
+ Every assertion below must be able to fail. The paired "would fail if" is part of
322
+ the test, not commentary — a self-parsing assertion that merely counts nodes
323
+ passes whether or not the feature works. Counts are calibrated against HEAD and
324
+ must be re-derived from a fresh ingest, never from the stale root `graph.db`.
325
+
326
+ | Test | Would fail if |
327
+ |---|---|
328
+ | Fixture: `VehicleAdapter.search` resolves to `SearchClient.search` | receiver resolution regresses to a placeholder |
329
+ | Fixture: `self.client.search_available_vehicles` resolves to nothing and is dropped | the phantom-method policy (D7) stops applying to `self.` receivers |
330
+ | Fixture: two classes with a same-named attribute produce two distinct targets | the placeholder collision returns |
331
+ | Self-parse: `self.*` placeholder edges drop 139 → ≤ 33 | any of the four `self_types` sources stops being collected |
332
+ | Self-parse: `unresolved_ratio` stays under the 0.30 gate | the `classify_fqn` split miscounts |
333
+ | Self-parse: `REFERENCES` edge count is 583 ± 60 | D3's internal-only filter or D9's collection breaks in either direction |
334
+ | Fixture: a class referenced only as `list[OnlyInGeneric]` is **not** an orphan | D9 regresses to `clean_python_type_string` |
335
+ | Fixture: a class constructed only from `tests/` is reported as an orphan | the `is_test` filter stops being applied |
336
+ | Fixture: a class referenced only by a parameter annotation is **not** an orphan | the annotation edge stops being emitted |
337
+
338
+ The last two are the pair #415 identifies as load-bearing: without the first all
339
+ six of its rows read as live, and without the second every abstract port reads as
340
+ dead. The `list[...]` case is the one this spec's fact-check added — it fails
341
+ against the design as originally written.
342
+
343
+ ## Risks
344
+
345
+ * **`classify_fqn` split (PR2).** Changing what counts as INTERNAL touches
346
+ virtual-node creation and every namespace-filtered query, and moves 21 edges
347
+ that D8 does not otherwise address. The `.`-prefixed relative-import case
348
+ shares the condition and must keep its current behavior. Verify each
349
+ `NodeNamespace.INTERNAL` consumer before the split.
350
+ * **Traversal density (PR1).** `impact` and `trace_flow` apply no edge-type
351
+ filter by default, so +583 `REFERENCES` edges will widen their results.
352
+ Arguably correct — an annotation is a real dependency — but it changes existing
353
+ output and should be stated in the PR, not discovered.
354
+ * **Response-schema precision (PR3).** Known and deliberate (D4). PR3 must report
355
+ the measured false-positive rate rather than ship silently.
356
+ * **`self_types` is wrong in two rare shapes — PR2 reads this map, so its author
357
+ must know.** Both were found by an adversarial pass over the extractor's
358
+ heuristics and both measure **zero occurrences** across this repository and
359
+ `owner-api`, which is why they are recorded rather than fixed:
360
+ - An unannotated `self.x = name` in a method other than `__init__` takes its
361
+ type from `__init__`'s parameter of the same name, even when the enclosing
362
+ method annotates it differently — the right answer is sitting in that
363
+ method's own `local_types`. The same lookup is order-dependent: a method
364
+ written above `__init__` sees an empty map. Wrongly *accepted* in the first
365
+ half, wrongly rejected in the second.
366
+ - The constructor heuristic accepts `self.x = HANDLERS[key]()` (the subscript's
367
+ container name is ALL-CAPS and passes the capitalisation test) and
368
+ `self.x = Registry.Instance()` (an uppercase-named classmethod on an imported
369
+ class). It rejects a caseless-script class name (`类`) and a parenthesised
370
+ construction `(Widget())`. The first two write a phantom type; `local_types`
371
+ and `self_types` disagree on the third.
372
+ * **Measurement basis.** Every number here has a five-week-stale twin in the root
373
+ `graph.db`. Re-ingest before re-measuring.
374
+ * **Module-level construction is invisible — [#416](https://github.com/zaebee/codegraph-brain/issues/416).**
375
+ A constructor called at module level emits no `CALLS` edge at all: `_walk`
376
+ dispatches a call node only when there is an enclosing function. A class built
377
+ only in a registry dict, a singleton, or DI wiring therefore has no incoming
378
+ `CALLS`, and PR3's orphan query would report it as dead. On this repository
379
+ `PythonExtractor` and `TypeScriptExtractor` are already in that state. This is
380
+ a **second** precision limit alongside the `response_model=` gap in D4, and
381
+ probably the larger one — it was found while validating PR1, not predicted
382
+ here. PR3 must measure it before the query is trusted.