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,274 @@
1
+ """Contrato versionado dos adaptadores de domínio (lf-0110, Cycle 7).
2
+
3
+ Um ``DomainAdapter`` observa artefatos **não-código** do repositório
4
+ (SQL, PySpark, OpenAPI, Terraform, CI/CD…) e extrai entidades/relações
5
+ tipadas para o grafo unificado de domínio. Mesma disciplina dos
6
+ ``ParserAdapter``/``SemanticResolver``:
7
+
8
+ - **evidence-first**: todo fato carrega ``EvidenceRecord`` apontando
9
+ para conteúdo real do inventário — nada é inventado;
10
+ - **sem execução**: adapters nunca executam código, jobs, terraform ou
11
+ pipelines e nunca abrem conexões externas (ADR-0014);
12
+ - **resolução honesta**: alvos usam ``DomainResolution`` — ``inferred``
13
+ nunca vira ``resolved``;
14
+ - **diagnósticos, nunca exceções**: ``extract`` não levanta para
15
+ conteúdo ruim — registra ``DomainDiagnostic`` no resultado.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import fnmatch
21
+ from collections.abc import Mapping
22
+ from dataclasses import dataclass, field
23
+ from typing import Protocol, runtime_checkable
24
+
25
+ from code_atlas.contracts.enums import ConfidenceClass
26
+ from code_atlas.domains.identity import DomainIdentity
27
+ from code_atlas.domains.model import DomainEntityKind
28
+ from code_atlas.domains.resolution import DomainResolution
29
+ from code_atlas.parsers.contracts import EvidenceRecord, SourceSpan
30
+
31
+ DOMAIN_CONTRACT_VERSION = 1
32
+
33
+ # Ordem de força da evidência — espelha a precedência de resolvers
34
+ # (semantic > syntactic > heuristic > inferred; ADR-0021).
35
+ _CONFIDENCE_RANK: dict[ConfidenceClass, int] = {
36
+ ConfidenceClass.INFERRED: 0,
37
+ ConfidenceClass.HEURISTIC: 1,
38
+ ConfidenceClass.SYNTACTIC: 2,
39
+ ConfidenceClass.RESOLVED: 3,
40
+ }
41
+
42
+
43
+ def confidence_rank(cls: ConfidenceClass) -> int:
44
+ """Rank ordinal da classe de confiança (maior = evidência mais forte)."""
45
+ return _CONFIDENCE_RANK[ConfidenceClass(cls)]
46
+
47
+
48
+ @dataclass(frozen=True)
49
+ class ArtifactSupport:
50
+ """Artefatos que um adapter consegue interpretar.
51
+
52
+ ``extensions``: sufixos lowercase com ponto (ex.: ``frozenset({".sql",
53
+ ".tf"})``). ``globs``: padrões ``fnmatch`` sobre o path relativo
54
+ POSIX (ex.: ``"**/migrations/*.sql"``); ``"**"`` não tem semântica
55
+ recursiva especial no fnmatch stdlib — escrever padrões explícitos.
56
+ """
57
+
58
+ extensions: frozenset[str] = frozenset()
59
+ globs: tuple[str, ...] = ()
60
+
61
+ def matches(self, path: str) -> bool:
62
+ """True se ``path`` (relativo POSIX) é artefato suportado."""
63
+ if not path:
64
+ return False
65
+ lower = path.lower()
66
+ dot = lower.rfind(".")
67
+ if dot >= 0 and lower[dot:] in self.extensions:
68
+ return True
69
+ return any(fnmatch.fnmatchcase(path, g) for g in self.globs)
70
+
71
+
72
+ @dataclass(frozen=True)
73
+ class DiscoveryRule:
74
+ """Regra declarativa de descoberta de artefatos do domínio.
75
+
76
+ Descreve *onde* o domínio costuma viver — o scanner/coordinator pode
77
+ priorizar ou rotular artefatos por regra sem rodar o adapter.
78
+ """
79
+
80
+ glob: str # fnmatch sobre path relativo POSIX
81
+ artifact_kind: str # rótulo: "sql-script", "tf-module", …
82
+ required: bool = False # False = artefato opcional/ausente é ok
83
+ notes: str = ""
84
+
85
+
86
+ @dataclass(frozen=True)
87
+ class ConfidenceModel:
88
+ """Política de confiança declarada pelo adapter.
89
+
90
+ ``ceiling``: classe máxima que o adapter pode emitir **sem** passar
91
+ por um resolvedor externo. Default ``syntactic`` — extração local
92
+ honesta; ``resolved`` exige evidência de índice/resolver (ADR-0021).
93
+ ``allows_inferred=False`` proíbe o adapter de emitir ``inferred``
94
+ (adapters estritamente evidence-first devem recusar, não inferir).
95
+ """
96
+
97
+ ceiling: ConfidenceClass = ConfidenceClass.SYNTACTIC
98
+ default: ConfidenceClass = ConfidenceClass.SYNTACTIC
99
+ allows_inferred: bool = True
100
+ notes: str = ""
101
+
102
+ def __post_init__(self) -> None:
103
+ for f in ("ceiling", "default"):
104
+ object.__setattr__(
105
+ self, f, ConfidenceClass(getattr(self, f))
106
+ )
107
+ if _CONFIDENCE_RANK[self.default] > _CONFIDENCE_RANK[self.ceiling]:
108
+ raise ValueError("confidence default cannot exceed ceiling")
109
+
110
+ def admits(self, cls: ConfidenceClass) -> bool:
111
+ """True se a classe respeita o teto e a política de inferência."""
112
+ cls = ConfidenceClass(cls)
113
+ if cls is ConfidenceClass.INFERRED and not self.allows_inferred:
114
+ return False
115
+ return _CONFIDENCE_RANK[cls] <= _CONFIDENCE_RANK[self.ceiling]
116
+
117
+
118
+ @dataclass(frozen=True)
119
+ class DiscoveredArtifact:
120
+ """Artefato concreto encontrado no repositório."""
121
+
122
+ path: str # relativo POSIX
123
+ artifact_kind: str = "" # rótulo vindo da DiscoveryRule, se houver
124
+ sha256: str = "" # hash do inventário, quando conhecido
125
+
126
+
127
+ @dataclass(frozen=True)
128
+ class DomainExtractionRequest:
129
+ """Entrada de extração — recorte estável do workspace.
130
+
131
+ ``repository`` é a ``identity_key`` lógica (lf-0021); ``snapshot`` é
132
+ um rótulo de revisão (commit/digest) opcional — a ligação com a row
133
+ ``snapshots.id`` é feita pelo coordinator, não pelo adapter.
134
+ ``root`` isola sub-projetos de monorepo (entra na identidade).
135
+ """
136
+
137
+ repository: str
138
+ artifacts: tuple[DiscoveredArtifact, ...] = ()
139
+ snapshot: str = ""
140
+ root: str = ""
141
+ environment: str = ""
142
+
143
+
144
+ @dataclass(frozen=True)
145
+ class ExtractedDomainEntity:
146
+ """Entidade extraída por um adapter — ainda sem row ids.
147
+
148
+ ``path`` é o artefato de origem ("" só para entidades sintetizadas
149
+ por derivação declarada). ``evidence`` são índices em
150
+ ``DomainExtractionResult.evidence`` — mesmo desenho posicional de
151
+ ``GraphEdge.evidence_index``.
152
+ """
153
+
154
+ identity: DomainIdentity
155
+ kind: DomainEntityKind
156
+ name: str
157
+ path: str = ""
158
+ span: SourceSpan | None = None
159
+ content_hash: str = ""
160
+ attributes: Mapping[str, str] = field(default_factory=dict)
161
+ evidence: tuple[int, ...] = ()
162
+
163
+ def __post_init__(self) -> None:
164
+ object.__setattr__(
165
+ self, "kind", DomainEntityKind(self.kind)
166
+ )
167
+
168
+
169
+ @dataclass(frozen=True)
170
+ class ExtractedDomainRelation:
171
+ """Relação candidata entre endpoints de domínio ou código.
172
+
173
+ Origem: ``from_identity`` (entidade de domínio) **ou**
174
+ ``from_symbol`` (qualified name de símbolo de código — a ponte
175
+ código→domínio). Alvo: ``to_identity``, ``to_symbol`` ou
176
+ ``to_unresolved`` (texto honesto). ``resolution`` carrega o estado
177
+ declarado pelo adapter; quando ``None`` o coordinator trata como
178
+ ``unresolved`` + ``syntactic``.
179
+ """
180
+
181
+ relation_type: str
182
+ path: str # artefato de origem da observação
183
+ from_identity: DomainIdentity | None = None
184
+ from_symbol: str = "" # qualified name do símbolo de origem
185
+ to_identity: DomainIdentity | None = None
186
+ to_symbol: str = ""
187
+ to_unresolved: str = ""
188
+ resolution: DomainResolution | None = None
189
+ span: SourceSpan | None = None
190
+ evidence: tuple[int, ...] = ()
191
+
192
+ def __post_init__(self) -> None:
193
+ if self.from_identity is None and not self.from_symbol:
194
+ raise ValueError("extracted relation requires a from endpoint")
195
+ if (
196
+ self.to_identity is None
197
+ and not self.to_symbol
198
+ and not self.to_unresolved
199
+ ):
200
+ raise ValueError(
201
+ "extracted relation requires to endpoint or to_unresolved"
202
+ )
203
+
204
+
205
+ @dataclass(frozen=True)
206
+ class DomainDiagnostic:
207
+ """Diagnóstico de adapter (artefato inválido, ambiguidade, recusa)."""
208
+
209
+ code: str # ex.: "unsupported-artifact", "parse-error"
210
+ severity: str # info | warning | error
211
+ message: str
212
+ path: str = ""
213
+ adapter_id: str = ""
214
+
215
+
216
+ @dataclass(frozen=True)
217
+ class DomainExtractionResult:
218
+ """Envelope versionado da saída de ``DomainAdapter.extract``."""
219
+
220
+ domain_id: str
221
+ adapter_version: str
222
+ schema_version: int = DOMAIN_CONTRACT_VERSION
223
+ entities: tuple[ExtractedDomainEntity, ...] = ()
224
+ relations: tuple[ExtractedDomainRelation, ...] = ()
225
+ evidence: tuple[EvidenceRecord, ...] = ()
226
+ diagnostics: tuple[DomainDiagnostic, ...] = ()
227
+ stats: Mapping[str, int] = field(default_factory=dict)
228
+
229
+
230
+ @runtime_checkable
231
+ class DomainAdapter(Protocol):
232
+ """Interface implementada por qualquer adapter de domínio.
233
+
234
+ Adapters são puros: recebem artefatos descobertos, devolvem
235
+ entidades/relações/evidência — nunca leem disco fora do request,
236
+ nunca executam conteúdo, nunca abrem rede.
237
+ """
238
+
239
+ @property
240
+ def domain_id(self) -> str:
241
+ """Id estável do domínio (``sql``, ``pyspark``, ``terraform``…)."""
242
+ ...
243
+
244
+ @property
245
+ def adapter_version(self) -> str:
246
+ """Versão do adapter (semver interno) — entra em analyzer_versions."""
247
+ ...
248
+
249
+ def supported_artifacts(self) -> ArtifactSupport:
250
+ """Extensões/globs que o adapter interpreta."""
251
+ ...
252
+
253
+ def entity_kinds(self) -> frozenset[DomainEntityKind]:
254
+ """Subconjunto de ``DomainEntityKind`` que o adapter emite."""
255
+ ...
256
+
257
+ def relation_kinds(self) -> frozenset[str]:
258
+ """Subconjunto do vocabulário de relações que o adapter emite."""
259
+ ...
260
+
261
+ def confidence_model(self) -> ConfidenceModel:
262
+ """Teto/default de confiança e política de inferência."""
263
+ ...
264
+
265
+ def discovery_rules(self) -> tuple[DiscoveryRule, ...]:
266
+ """Regras declarativas de onde os artefatos do domínio vivem."""
267
+ ...
268
+
269
+ def extract(
270
+ self, request: DomainExtractionRequest
271
+ ) -> DomainExtractionResult:
272
+ """Extrai entidades/relações dos artefatos — nunca levanta para
273
+ conteúdo ruim; falhas viram ``DomainDiagnostic``."""
274
+ ...