code-atlas-forge 1.1.0__py3-none-any.whl

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 (181) hide show
  1. code_atlas/__init__.py +6 -0
  2. code_atlas/__main__.py +6 -0
  3. code_atlas/api/__init__.py +5 -0
  4. code_atlas/api/handlers.py +1514 -0
  5. code_atlas/api/server.py +394 -0
  6. code_atlas/cli.py +2084 -0
  7. code_atlas/config.py +149 -0
  8. code_atlas/context/__init__.py +66 -0
  9. code_atlas/context/contracts.py +277 -0
  10. code_atlas/context/domain.py +760 -0
  11. code_atlas/context/engine.py +442 -0
  12. code_atlas/context/expand.py +133 -0
  13. code_atlas/context/renderers.py +71 -0
  14. code_atlas/context/tokenizer.py +37 -0
  15. code_atlas/contracts/__init__.py +38 -0
  16. code_atlas/contracts/enums.py +67 -0
  17. code_atlas/contracts/models.py +175 -0
  18. code_atlas/contracts/ports.py +70 -0
  19. code_atlas/discovery/__init__.py +25 -0
  20. code_atlas/discovery/gitignore.py +119 -0
  21. code_atlas/discovery/identity.py +52 -0
  22. code_atlas/discovery/models.py +204 -0
  23. code_atlas/discovery/scanner.py +495 -0
  24. code_atlas/domains/__init__.py +107 -0
  25. code_atlas/domains/api/__init__.py +28 -0
  26. code_atlas/domains/api/adapter.py +405 -0
  27. code_atlas/domains/api/common.py +308 -0
  28. code_atlas/domains/api/consumers.py +224 -0
  29. code_atlas/domains/api/emit.py +231 -0
  30. code_atlas/domains/api/openapi.py +398 -0
  31. code_atlas/domains/api/routes.py +582 -0
  32. code_atlas/domains/api/yaml_subset.py +683 -0
  33. code_atlas/domains/aws/__init__.py +28 -0
  34. code_atlas/domains/aws/adapter.py +382 -0
  35. code_atlas/domains/aws/common.py +261 -0
  36. code_atlas/domains/aws/configs.py +1164 -0
  37. code_atlas/domains/aws/emit.py +411 -0
  38. code_atlas/domains/aws/pyfiles.py +2220 -0
  39. code_atlas/domains/aws/sqlbridge.py +448 -0
  40. code_atlas/domains/cicd/__init__.py +50 -0
  41. code_atlas/domains/cicd/adapter.py +762 -0
  42. code_atlas/domains/cicd/classify.py +136 -0
  43. code_atlas/domains/cicd/workflow.py +504 -0
  44. code_atlas/domains/cicd/yamlmini.py +946 -0
  45. code_atlas/domains/cli_surface.py +739 -0
  46. code_atlas/domains/contracts.py +274 -0
  47. code_atlas/domains/crossresolve.py +1208 -0
  48. code_atlas/domains/evidence.py +57 -0
  49. code_atlas/domains/identity.py +149 -0
  50. code_atlas/domains/model.py +202 -0
  51. code_atlas/domains/registry.py +250 -0
  52. code_atlas/domains/resolution.py +65 -0
  53. code_atlas/domains/spark/__init__.py +31 -0
  54. code_atlas/domains/spark/adapter.py +146 -0
  55. code_atlas/domains/spark/emit.py +344 -0
  56. code_atlas/domains/spark/extract.py +108 -0
  57. code_atlas/domains/spark/sqllit.py +192 -0
  58. code_atlas/domains/spark/walk.py +1943 -0
  59. code_atlas/domains/sql/__init__.py +30 -0
  60. code_atlas/domains/sql/adapter.py +382 -0
  61. code_atlas/domains/sql/extract.py +1271 -0
  62. code_atlas/domains/sql/nodes.py +264 -0
  63. code_atlas/domains/sql/parser.py +1510 -0
  64. code_atlas/domains/sql/tokens.py +318 -0
  65. code_atlas/domains/summarize.py +126 -0
  66. code_atlas/domains/terraform/__init__.py +20 -0
  67. code_atlas/domains/terraform/adapter.py +127 -0
  68. code_atlas/domains/terraform/catalog.py +43 -0
  69. code_atlas/domains/terraform/extract.py +1277 -0
  70. code_atlas/domains/terraform/hcl.py +538 -0
  71. code_atlas/domains/terraform/refs.py +181 -0
  72. code_atlas/domains/terraform/tfjson.py +163 -0
  73. code_atlas/domains/terraform/tfvars.py +98 -0
  74. code_atlas/domains/validation.py +120 -0
  75. code_atlas/env_override.py +27 -0
  76. code_atlas/eval/__init__.py +26 -0
  77. code_atlas/eval/domain_eval.py +681 -0
  78. code_atlas/eval/ground_truth.py +688 -0
  79. code_atlas/eval/impact_truth.py +758 -0
  80. code_atlas/eval/metrics.py +178 -0
  81. code_atlas/eval/pack_value.py +610 -0
  82. code_atlas/federation/__init__.py +72 -0
  83. code_atlas/federation/federation.py +676 -0
  84. code_atlas/federation/model.py +355 -0
  85. code_atlas/federation/store.py +194 -0
  86. code_atlas/gitbin.py +48 -0
  87. code_atlas/graph/__init__.py +20 -0
  88. code_atlas/graph/builder.py +378 -0
  89. code_atlas/graph/identity.py +54 -0
  90. code_atlas/graph/queries.py +47 -0
  91. code_atlas/graph/validation.py +92 -0
  92. code_atlas/impact/__init__.py +37 -0
  93. code_atlas/impact/blast_radius.py +171 -0
  94. code_atlas/impact/contract_analyzer.py +104 -0
  95. code_atlas/impact/contracts.py +315 -0
  96. code_atlas/impact/diff_reader.py +142 -0
  97. code_atlas/impact/domain_traversal.py +768 -0
  98. code_atlas/impact/engine.py +392 -0
  99. code_atlas/impact/packs.py +128 -0
  100. code_atlas/impact/report.py +136 -0
  101. code_atlas/impact/revision_binding.py +220 -0
  102. code_atlas/impact/risk_classifier.py +83 -0
  103. code_atlas/impact/snapshot_resolver.py +136 -0
  104. code_atlas/impact/symbol_diff.py +210 -0
  105. code_atlas/impact/test_selector.py +166 -0
  106. code_atlas/indexing/__init__.py +5 -0
  107. code_atlas/indexing/cache.py +396 -0
  108. code_atlas/indexing/change_detector.py +278 -0
  109. code_atlas/indexing/coordinator.py +1032 -0
  110. code_atlas/indexing/dependency_planner.py +268 -0
  111. code_atlas/indexing/persist.py +436 -0
  112. code_atlas/indexing/reuse.py +85 -0
  113. code_atlas/install/__init__.py +7 -0
  114. code_atlas/install/cli.py +168 -0
  115. code_atlas/install/lifecycle.py +286 -0
  116. code_atlas/mcp.py +674 -0
  117. code_atlas/observability/__init__.py +19 -0
  118. code_atlas/observability/logging.py +199 -0
  119. code_atlas/parsers/__init__.py +43 -0
  120. code_atlas/parsers/contracts.py +209 -0
  121. code_atlas/parsers/engine.py +125 -0
  122. code_atlas/parsers/languages/__init__.py +1 -0
  123. code_atlas/parsers/languages/python.py +391 -0
  124. code_atlas/parsers/languages/tsx.py +28 -0
  125. code_atlas/parsers/languages/typescript.py +909 -0
  126. code_atlas/parsers/registry.py +51 -0
  127. code_atlas/parsers/tree_sitter_runtime.py +118 -0
  128. code_atlas/resolvers/__init__.py +33 -0
  129. code_atlas/resolvers/bootstrap.py +246 -0
  130. code_atlas/resolvers/capabilities.py +33 -0
  131. code_atlas/resolvers/contracts.py +133 -0
  132. code_atlas/resolvers/coordinator.py +96 -0
  133. code_atlas/resolvers/enrichment.py +318 -0
  134. code_atlas/resolvers/lsp/__init__.py +26 -0
  135. code_atlas/resolvers/lsp/adapter.py +256 -0
  136. code_atlas/resolvers/lsp/lifecycle.py +251 -0
  137. code_atlas/resolvers/lsp/spawn.py +92 -0
  138. code_atlas/resolvers/lsp/transport.py +240 -0
  139. code_atlas/resolvers/registry.py +33 -0
  140. code_atlas/resolvers/scip/__init__.py +49 -0
  141. code_atlas/resolvers/scip/decoder.py +216 -0
  142. code_atlas/resolvers/scip/importer.py +248 -0
  143. code_atlas/resolvers/scip/loader.py +90 -0
  144. code_atlas/resolvers/scip/mapper.py +271 -0
  145. code_atlas/resolvers/scip/provenance.py +211 -0
  146. code_atlas/resolvers/scip/resolver.py +289 -0
  147. code_atlas/resolvers/scip/validation.py +101 -0
  148. code_atlas/resolvers/syntactic/__init__.py +8 -0
  149. code_atlas/resolvers/syntactic/resolver.py +254 -0
  150. code_atlas/search/__init__.py +32 -0
  151. code_atlas/search/contracts.py +176 -0
  152. code_atlas/search/domain.py +561 -0
  153. code_atlas/search/engine.py +530 -0
  154. code_atlas/search/federated.py +276 -0
  155. code_atlas/search/graph.py +282 -0
  156. code_atlas/search/hybrid.py +151 -0
  157. code_atlas/search/intent.py +48 -0
  158. code_atlas/search/lexical.py +176 -0
  159. code_atlas/search/refs.py +359 -0
  160. code_atlas/search/structural.py +505 -0
  161. code_atlas/search/tokenizer.py +43 -0
  162. code_atlas/search/vector/__init__.py +35 -0
  163. code_atlas/search/vector/contracts.py +76 -0
  164. code_atlas/search/vector/embeddings.py +96 -0
  165. code_atlas/search/vector/index.py +169 -0
  166. code_atlas/search/vector/provider.py +50 -0
  167. code_atlas/storage/__init__.py +14 -0
  168. code_atlas/storage/db.py +47 -0
  169. code_atlas/storage/migrations.py +552 -0
  170. code_atlas/storage/store.py +1045 -0
  171. code_atlas/ui/__init__.py +29 -0
  172. code_atlas/ui/i18n.py +143 -0
  173. code_atlas/ui/kit.py +689 -0
  174. code_atlas/ui/wizard.py +317 -0
  175. code_atlas_forge-1.1.0.dist-info/METADATA +246 -0
  176. code_atlas_forge-1.1.0.dist-info/RECORD +181 -0
  177. code_atlas_forge-1.1.0.dist-info/WHEEL +5 -0
  178. code_atlas_forge-1.1.0.dist-info/entry_points.txt +2 -0
  179. code_atlas_forge-1.1.0.dist-info/licenses/LICENSE +202 -0
  180. code_atlas_forge-1.1.0.dist-info/licenses/NOTICE +17 -0
  181. code_atlas_forge-1.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,178 @@
1
+ """Métricas de retrieval — definições canônicas, sem atalhos.
2
+
3
+ Convenções (auditadas no baseline cycle-4.1):
4
+ - ``precision_at_k`` = |relevantes ∩ top-K| / K (denominador K, não
5
+ len(returned) — o bug do avaliador v1).
6
+ - ``recall_at_k`` = |relevantes ∩ top-K| / |relevantes|; None quando a
7
+ consulta não tem relevantes (excluída da agregação, contada em
8
+ ``no_relevant``).
9
+ - ``ndcg_at_k`` aceita relevância graduada (``dict[id -> grade]``);
10
+ binária é o caso grade=1.
11
+ - Agregação: macro-mean (por consulta) + micro (somas globais) +
12
+ mediana — nunca uma só estatística.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import math
18
+ import statistics
19
+ from dataclasses import dataclass, field
20
+
21
+ Relevant = dict[str, int] # doc_id -> grau de relevância (>=1)
22
+
23
+
24
+ def _topk(ranked: list[str], k: int) -> list[str]:
25
+ return list(ranked[: max(0, k)])
26
+
27
+
28
+ def precision_at_k(ranked: list[str], relevant: Relevant, k: int) -> float:
29
+ if k <= 0:
30
+ return 0.0
31
+ tp = sum(1 for d in _topk(ranked, k) if relevant.get(d, 0) > 0)
32
+ return tp / k
33
+
34
+
35
+ def recall_at_k(ranked: list[str], relevant: Relevant, k: int) -> float | None:
36
+ rel = {d for d, g in relevant.items() if g > 0}
37
+ if not rel:
38
+ return None # sem relevantes → excluída da agregação
39
+ tp = sum(1 for d in _topk(ranked, k) if d in rel)
40
+ return tp / len(rel)
41
+
42
+
43
+ def mrr(ranked: list[str], relevant: Relevant) -> float:
44
+ for i, d in enumerate(ranked):
45
+ if relevant.get(d, 0) > 0:
46
+ return 1.0 / (i + 1)
47
+ return 0.0
48
+
49
+
50
+ def _dcg(gains: list[int]) -> float:
51
+ return sum(
52
+ (2.0 ** g - 1.0) / math.log2(i + 2) for i, g in enumerate(gains)
53
+ )
54
+
55
+
56
+ def ndcg_at_k(ranked: list[str], relevant: Relevant, k: int) -> float:
57
+ if not relevant or k <= 0:
58
+ return 0.0
59
+ gains = [relevant.get(d, 0) for d in _topk(ranked, k)]
60
+ ideal = sorted(relevant.values(), reverse=True)[:k]
61
+ idcg = _dcg(ideal)
62
+ return _dcg(gains) / idcg if idcg else 0.0
63
+
64
+
65
+ def average_precision_at_k(
66
+ ranked: list[str], relevant: Relevant, k: int,
67
+ ) -> float:
68
+ """AP@K — média das precision@i nos ranks relevantes."""
69
+ rel = {d for d, g in relevant.items() if g > 0}
70
+ if not rel:
71
+ return 0.0
72
+ hits = 0
73
+ acc = 0.0
74
+ for i, d in enumerate(_topk(ranked, k)):
75
+ if d in rel:
76
+ hits += 1
77
+ acc += hits / (i + 1)
78
+ return acc / min(len(rel), k)
79
+
80
+
81
+ def hit_rate_at_k(ranked: list[str], relevant: Relevant, k: int) -> float:
82
+ return 1.0 if any(
83
+ relevant.get(d, 0) > 0 for d in _topk(ranked, k)) else 0.0
84
+
85
+
86
+ def diversity(ranked: list[str]) -> float:
87
+ """Fração de identidades distintas — 1.0 = sem duplicatas."""
88
+ return len(set(ranked)) / len(ranked) if ranked else 1.0
89
+
90
+
91
+ @dataclass
92
+ class MetricRecord:
93
+ """Uma consulta avaliada — micro-agregação deriva dos contadores."""
94
+
95
+ query_id: str
96
+ k: int
97
+ tp: int = 0
98
+ returned: int = 0
99
+ relevant: int = 0
100
+ metrics: dict[str, float] = field(default_factory=dict)
101
+
102
+
103
+ @dataclass
104
+ class EvalReport:
105
+ macro: dict[str, float]
106
+ micro: dict[str, float]
107
+ median: dict[str, float]
108
+ n_queries: int
109
+ no_relevant: int
110
+
111
+ def to_dict(self) -> dict[str, object]:
112
+ return {
113
+ "macro": self.macro, "micro": self.micro,
114
+ "median": self.median,
115
+ "n_queries": self.n_queries,
116
+ "no_relevant": self.no_relevant,
117
+ }
118
+
119
+
120
+ def aggregate(records: list[MetricRecord]) -> EvalReport:
121
+ keys = sorted({k for r in records for k in r.metrics})
122
+ macro: dict[str, float] = {}
123
+ median: dict[str, float] = {}
124
+ for key in keys:
125
+ vals = [r.metrics[key] for r in records if key in r.metrics]
126
+ if vals:
127
+ macro[key] = statistics.fmean(vals)
128
+ median[key] = statistics.median(vals)
129
+ n_ret = sum(r.returned for r in records)
130
+ n_rel = sum(r.relevant for r in records)
131
+ n_tp = sum(r.tp for r in records)
132
+ micro = {
133
+ "precision": n_tp / n_ret if n_ret else 0.0,
134
+ "recall": n_tp / n_rel if n_rel else 0.0,
135
+ }
136
+ return EvalReport(
137
+ macro=macro, micro=micro, median=median,
138
+ n_queries=len(records),
139
+ no_relevant=sum(1 for r in records if r.relevant == 0),
140
+ )
141
+
142
+
143
+ def evaluate_query(
144
+ query_id: str,
145
+ ranked: list[str],
146
+ relevant: Relevant,
147
+ k: int,
148
+ ) -> MetricRecord:
149
+ """Calcula todas as métricas de uma consulta.
150
+
151
+ Dedup por identidade preservando ordem — hits duplicados não
152
+ inflam tp/precision (audit: unidade de avaliação = identidade
153
+ canônica, não ocorrência)."""
154
+ seen: set[str] = set()
155
+ div = diversity(ranked)
156
+ dedup: list[str] = []
157
+ for d in ranked:
158
+ if d not in seen:
159
+ seen.add(d)
160
+ dedup.append(d)
161
+ ranked = dedup
162
+ top = _topk(ranked, k)
163
+ tp = sum(1 for d in top if relevant.get(d, 0) > 0)
164
+ rel = sum(1 for g in relevant.values() if g > 0)
165
+ metrics: dict[str, float] = {
166
+ "precision_at_k": precision_at_k(ranked, relevant, k),
167
+ "mrr": mrr(ranked, relevant),
168
+ "ndcg_at_k": ndcg_at_k(ranked, relevant, k),
169
+ "ap_at_k": average_precision_at_k(ranked, relevant, k),
170
+ "hit_rate_at_k": hit_rate_at_k(ranked, relevant, k),
171
+ "diversity": div,
172
+ }
173
+ rec = recall_at_k(ranked, relevant, k)
174
+ if rec is not None:
175
+ metrics["recall_at_k"] = rec
176
+ return MetricRecord(
177
+ query_id=query_id, k=k, tp=tp, returned=len(top),
178
+ relevant=rel, metrics=metrics)