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.
- code_atlas/__init__.py +6 -0
- code_atlas/__main__.py +6 -0
- code_atlas/api/__init__.py +5 -0
- code_atlas/api/handlers.py +1514 -0
- code_atlas/api/server.py +394 -0
- code_atlas/cli.py +2084 -0
- code_atlas/config.py +149 -0
- code_atlas/context/__init__.py +66 -0
- code_atlas/context/contracts.py +277 -0
- code_atlas/context/domain.py +760 -0
- code_atlas/context/engine.py +442 -0
- code_atlas/context/expand.py +133 -0
- code_atlas/context/renderers.py +71 -0
- code_atlas/context/tokenizer.py +37 -0
- code_atlas/contracts/__init__.py +38 -0
- code_atlas/contracts/enums.py +67 -0
- code_atlas/contracts/models.py +175 -0
- code_atlas/contracts/ports.py +70 -0
- code_atlas/discovery/__init__.py +25 -0
- code_atlas/discovery/gitignore.py +119 -0
- code_atlas/discovery/identity.py +52 -0
- code_atlas/discovery/models.py +204 -0
- code_atlas/discovery/scanner.py +495 -0
- code_atlas/domains/__init__.py +107 -0
- code_atlas/domains/api/__init__.py +28 -0
- code_atlas/domains/api/adapter.py +405 -0
- code_atlas/domains/api/common.py +308 -0
- code_atlas/domains/api/consumers.py +224 -0
- code_atlas/domains/api/emit.py +231 -0
- code_atlas/domains/api/openapi.py +398 -0
- code_atlas/domains/api/routes.py +582 -0
- code_atlas/domains/api/yaml_subset.py +683 -0
- code_atlas/domains/aws/__init__.py +28 -0
- code_atlas/domains/aws/adapter.py +382 -0
- code_atlas/domains/aws/common.py +261 -0
- code_atlas/domains/aws/configs.py +1164 -0
- code_atlas/domains/aws/emit.py +411 -0
- code_atlas/domains/aws/pyfiles.py +2220 -0
- code_atlas/domains/aws/sqlbridge.py +448 -0
- code_atlas/domains/cicd/__init__.py +50 -0
- code_atlas/domains/cicd/adapter.py +762 -0
- code_atlas/domains/cicd/classify.py +136 -0
- code_atlas/domains/cicd/workflow.py +504 -0
- code_atlas/domains/cicd/yamlmini.py +946 -0
- code_atlas/domains/cli_surface.py +739 -0
- code_atlas/domains/contracts.py +274 -0
- code_atlas/domains/crossresolve.py +1208 -0
- code_atlas/domains/evidence.py +57 -0
- code_atlas/domains/identity.py +149 -0
- code_atlas/domains/model.py +202 -0
- code_atlas/domains/registry.py +250 -0
- code_atlas/domains/resolution.py +65 -0
- code_atlas/domains/spark/__init__.py +31 -0
- code_atlas/domains/spark/adapter.py +146 -0
- code_atlas/domains/spark/emit.py +344 -0
- code_atlas/domains/spark/extract.py +108 -0
- code_atlas/domains/spark/sqllit.py +192 -0
- code_atlas/domains/spark/walk.py +1943 -0
- code_atlas/domains/sql/__init__.py +30 -0
- code_atlas/domains/sql/adapter.py +382 -0
- code_atlas/domains/sql/extract.py +1271 -0
- code_atlas/domains/sql/nodes.py +264 -0
- code_atlas/domains/sql/parser.py +1510 -0
- code_atlas/domains/sql/tokens.py +318 -0
- code_atlas/domains/summarize.py +126 -0
- code_atlas/domains/terraform/__init__.py +20 -0
- code_atlas/domains/terraform/adapter.py +127 -0
- code_atlas/domains/terraform/catalog.py +43 -0
- code_atlas/domains/terraform/extract.py +1277 -0
- code_atlas/domains/terraform/hcl.py +538 -0
- code_atlas/domains/terraform/refs.py +181 -0
- code_atlas/domains/terraform/tfjson.py +163 -0
- code_atlas/domains/terraform/tfvars.py +98 -0
- code_atlas/domains/validation.py +120 -0
- code_atlas/env_override.py +27 -0
- code_atlas/eval/__init__.py +26 -0
- code_atlas/eval/domain_eval.py +681 -0
- code_atlas/eval/ground_truth.py +688 -0
- code_atlas/eval/impact_truth.py +758 -0
- code_atlas/eval/metrics.py +178 -0
- code_atlas/eval/pack_value.py +610 -0
- code_atlas/federation/__init__.py +72 -0
- code_atlas/federation/federation.py +676 -0
- code_atlas/federation/model.py +355 -0
- code_atlas/federation/store.py +194 -0
- code_atlas/gitbin.py +48 -0
- code_atlas/graph/__init__.py +20 -0
- code_atlas/graph/builder.py +378 -0
- code_atlas/graph/identity.py +54 -0
- code_atlas/graph/queries.py +47 -0
- code_atlas/graph/validation.py +92 -0
- code_atlas/impact/__init__.py +37 -0
- code_atlas/impact/blast_radius.py +171 -0
- code_atlas/impact/contract_analyzer.py +104 -0
- code_atlas/impact/contracts.py +315 -0
- code_atlas/impact/diff_reader.py +142 -0
- code_atlas/impact/domain_traversal.py +768 -0
- code_atlas/impact/engine.py +392 -0
- code_atlas/impact/packs.py +128 -0
- code_atlas/impact/report.py +136 -0
- code_atlas/impact/revision_binding.py +220 -0
- code_atlas/impact/risk_classifier.py +83 -0
- code_atlas/impact/snapshot_resolver.py +136 -0
- code_atlas/impact/symbol_diff.py +210 -0
- code_atlas/impact/test_selector.py +166 -0
- code_atlas/indexing/__init__.py +5 -0
- code_atlas/indexing/cache.py +396 -0
- code_atlas/indexing/change_detector.py +278 -0
- code_atlas/indexing/coordinator.py +1032 -0
- code_atlas/indexing/dependency_planner.py +268 -0
- code_atlas/indexing/persist.py +436 -0
- code_atlas/indexing/reuse.py +85 -0
- code_atlas/install/__init__.py +7 -0
- code_atlas/install/cli.py +168 -0
- code_atlas/install/lifecycle.py +286 -0
- code_atlas/mcp.py +674 -0
- code_atlas/observability/__init__.py +19 -0
- code_atlas/observability/logging.py +199 -0
- code_atlas/parsers/__init__.py +43 -0
- code_atlas/parsers/contracts.py +209 -0
- code_atlas/parsers/engine.py +125 -0
- code_atlas/parsers/languages/__init__.py +1 -0
- code_atlas/parsers/languages/python.py +391 -0
- code_atlas/parsers/languages/tsx.py +28 -0
- code_atlas/parsers/languages/typescript.py +909 -0
- code_atlas/parsers/registry.py +51 -0
- code_atlas/parsers/tree_sitter_runtime.py +118 -0
- code_atlas/resolvers/__init__.py +33 -0
- code_atlas/resolvers/bootstrap.py +246 -0
- code_atlas/resolvers/capabilities.py +33 -0
- code_atlas/resolvers/contracts.py +133 -0
- code_atlas/resolvers/coordinator.py +96 -0
- code_atlas/resolvers/enrichment.py +318 -0
- code_atlas/resolvers/lsp/__init__.py +26 -0
- code_atlas/resolvers/lsp/adapter.py +256 -0
- code_atlas/resolvers/lsp/lifecycle.py +251 -0
- code_atlas/resolvers/lsp/spawn.py +92 -0
- code_atlas/resolvers/lsp/transport.py +240 -0
- code_atlas/resolvers/registry.py +33 -0
- code_atlas/resolvers/scip/__init__.py +49 -0
- code_atlas/resolvers/scip/decoder.py +216 -0
- code_atlas/resolvers/scip/importer.py +248 -0
- code_atlas/resolvers/scip/loader.py +90 -0
- code_atlas/resolvers/scip/mapper.py +271 -0
- code_atlas/resolvers/scip/provenance.py +211 -0
- code_atlas/resolvers/scip/resolver.py +289 -0
- code_atlas/resolvers/scip/validation.py +101 -0
- code_atlas/resolvers/syntactic/__init__.py +8 -0
- code_atlas/resolvers/syntactic/resolver.py +254 -0
- code_atlas/search/__init__.py +32 -0
- code_atlas/search/contracts.py +176 -0
- code_atlas/search/domain.py +561 -0
- code_atlas/search/engine.py +530 -0
- code_atlas/search/federated.py +276 -0
- code_atlas/search/graph.py +282 -0
- code_atlas/search/hybrid.py +151 -0
- code_atlas/search/intent.py +48 -0
- code_atlas/search/lexical.py +176 -0
- code_atlas/search/refs.py +359 -0
- code_atlas/search/structural.py +505 -0
- code_atlas/search/tokenizer.py +43 -0
- code_atlas/search/vector/__init__.py +35 -0
- code_atlas/search/vector/contracts.py +76 -0
- code_atlas/search/vector/embeddings.py +96 -0
- code_atlas/search/vector/index.py +169 -0
- code_atlas/search/vector/provider.py +50 -0
- code_atlas/storage/__init__.py +14 -0
- code_atlas/storage/db.py +47 -0
- code_atlas/storage/migrations.py +552 -0
- code_atlas/storage/store.py +1045 -0
- code_atlas/ui/__init__.py +29 -0
- code_atlas/ui/i18n.py +143 -0
- code_atlas/ui/kit.py +689 -0
- code_atlas/ui/wizard.py +317 -0
- code_atlas_forge-1.1.0.dist-info/METADATA +246 -0
- code_atlas_forge-1.1.0.dist-info/RECORD +181 -0
- code_atlas_forge-1.1.0.dist-info/WHEEL +5 -0
- code_atlas_forge-1.1.0.dist-info/entry_points.txt +2 -0
- code_atlas_forge-1.1.0.dist-info/licenses/LICENSE +202 -0
- code_atlas_forge-1.1.0.dist-info/licenses/NOTICE +17 -0
- 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)
|