codegraph-engine 3.0.0__2-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 (130) hide show
  1. codegraph/__init__.py +37 -0
  2. codegraph/agent.py +26 -0
  3. codegraph/agent_brain.py +2212 -0
  4. codegraph/agent_capabilities.py +4058 -0
  5. codegraph/agent_rules.py +531 -0
  6. codegraph/api_drift.py +455 -0
  7. codegraph/architecture.py +371 -0
  8. codegraph/async_queue/__init__.py +50 -0
  9. codegraph/async_queue/detectors/__init__.py +48 -0
  10. codegraph/async_queue/detectors/celery.py +160 -0
  11. codegraph/async_queue/detectors/kafka.py +168 -0
  12. codegraph/async_queue/detectors/rabbitmq.py +116 -0
  13. codegraph/async_queue/detectors/redis.py +130 -0
  14. codegraph/async_queue/detectors/sqs.py +135 -0
  15. codegraph/async_queue/models.py +161 -0
  16. codegraph/async_queue/otel_models.py +74 -0
  17. codegraph/async_queue/otel_parser.py +337 -0
  18. codegraph/async_queue/reconciler.py +427 -0
  19. codegraph/async_queue/scanner.py +291 -0
  20. codegraph/async_queue/traversal.py +447 -0
  21. codegraph/audit.py +106 -0
  22. codegraph/binding_resolver.py +616 -0
  23. codegraph/branch_comparison.py +197 -0
  24. codegraph/cache.py +95 -0
  25. codegraph/change_impact.py +547 -0
  26. codegraph/cli.py +2436 -0
  27. codegraph/cli_output.py +205 -0
  28. codegraph/config.py +45 -0
  29. codegraph/constraints.py +238 -0
  30. codegraph/context.py +2182 -0
  31. codegraph/context_freshness.py +351 -0
  32. codegraph/database/__init__.py +72 -0
  33. codegraph/database/extractor.py +3651 -0
  34. codegraph/database/interrogation.py +1494 -0
  35. codegraph/database/models.py +310 -0
  36. codegraph/database/schema_drift.py +862 -0
  37. codegraph/epistemic.py +200 -0
  38. codegraph/errors.py +282 -0
  39. codegraph/evidence/__init__.py +15 -0
  40. codegraph/evidence/citations.py +418 -0
  41. codegraph/evidence_contract.py +486 -0
  42. codegraph/frameworks.py +960 -0
  43. codegraph/frameworks_nestjs.py +502 -0
  44. codegraph/frameworks_nextjs.py +337 -0
  45. codegraph/frameworks_react.py +457 -0
  46. codegraph/freshness.py +335 -0
  47. codegraph/frontend_html.py +109 -0
  48. codegraph/git.py +362 -0
  49. codegraph/git_state.py +545 -0
  50. codegraph/graph/__init__.py +46 -0
  51. codegraph/graph/models.py +56 -0
  52. codegraph/graph/traversal.py +1993 -0
  53. codegraph/indexing/__init__.py +24 -0
  54. codegraph/indexing/classifier.py +564 -0
  55. codegraph/indexing/indexer.py +2578 -0
  56. codegraph/indexing/models.py +427 -0
  57. codegraph/indexing/parser.py +3404 -0
  58. codegraph/indexing/pool.py +136 -0
  59. codegraph/indexing/scanner.py +211 -0
  60. codegraph/indexing/telemetry.py +326 -0
  61. codegraph/indexing/templates.py +418 -0
  62. codegraph/indexing/test_framework.py +116 -0
  63. codegraph/installer.py +1702 -0
  64. codegraph/interrogation.py +2355 -0
  65. codegraph/llm/__init__.py +3 -0
  66. codegraph/llm/base.py +15 -0
  67. codegraph/llm/context.py +20 -0
  68. codegraph/mcp/__init__.py +3 -0
  69. codegraph/mcp/server.py +1476 -0
  70. codegraph/mcp_diagnostics.py +882 -0
  71. codegraph/memory/__init__.py +3 -0
  72. codegraph/memory/store.py +46 -0
  73. codegraph/models.py +310 -0
  74. codegraph/monorepo.py +925 -0
  75. codegraph/observability.py +262 -0
  76. codegraph/optimizer.py +1014 -0
  77. codegraph/planner.py +417 -0
  78. codegraph/process_lifecycle.py +1153 -0
  79. codegraph/py.typed +1 -0
  80. codegraph/query_expansion.py +199 -0
  81. codegraph/ranking.py +408 -0
  82. codegraph/refactor/__init__.py +36 -0
  83. codegraph/refactor/models.py +114 -0
  84. codegraph/refactor/renamer.py +844 -0
  85. codegraph/refactor/transactions.py +414 -0
  86. codegraph/resolver.py +3968 -0
  87. codegraph/resources/__init__.py +46 -0
  88. codegraph/resources/cache.py +117 -0
  89. codegraph/resources/coalescer.py +83 -0
  90. codegraph/resources/debouncer.py +98 -0
  91. codegraph/resources/governor.py +219 -0
  92. codegraph/resources/monitor.py +102 -0
  93. codegraph/resources/policy.py +123 -0
  94. codegraph/retrieval_policy.py +320 -0
  95. codegraph/roblox.py +2174 -0
  96. codegraph/route_composer.py +363 -0
  97. codegraph/route_topology.py +172 -0
  98. codegraph/runtime/__init__.py +51 -0
  99. codegraph/runtime/collector.py +155 -0
  100. codegraph/runtime/db_watcher.py +191 -0
  101. codegraph/runtime/ingestor.py +692 -0
  102. codegraph/runtime/models.py +130 -0
  103. codegraph/runtime/port_inspector.py +304 -0
  104. codegraph/runtime/reconciliation.py +492 -0
  105. codegraph/runtime/runner.py +353 -0
  106. codegraph/runtime/trace_linker.py +175 -0
  107. codegraph/search/__init__.py +25 -0
  108. codegraph/search/hybrid.py +846 -0
  109. codegraph/search/semantic.py +28 -0
  110. codegraph/security/__init__.py +51 -0
  111. codegraph/security/paths.py +189 -0
  112. codegraph/security/redaction.py +633 -0
  113. codegraph/semantic_conflicts.py +270 -0
  114. codegraph/semantic_decorators.py +372 -0
  115. codegraph/structural_diff.py +542 -0
  116. codegraph/styles.py +144 -0
  117. codegraph/symbol_history.py +277 -0
  118. codegraph/target_resolver.py +348 -0
  119. codegraph/task.py +637 -0
  120. codegraph/tool_selection_eval.py +1158 -0
  121. codegraph/tsconfig.py +236 -0
  122. codegraph/ui/__init__.py +6 -0
  123. codegraph/ui/server.py +755 -0
  124. codegraph/watcher.py +323 -0
  125. codegraph_engine-3.0.0.dist-info/METADATA +868 -0
  126. codegraph_engine-3.0.0.dist-info/RECORD +130 -0
  127. codegraph_engine-3.0.0.dist-info/WHEEL +6 -0
  128. codegraph_engine-3.0.0.dist-info/entry_points.txt +2 -0
  129. codegraph_engine-3.0.0.dist-info/licenses/LICENSE +21 -0
  130. codegraph_engine-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,310 @@
1
+ """Canonical Database Schema & Evidence Models for CodeGraph (Phases 2, 3, 4, 5, 6, 7).
2
+
3
+ Provides deterministic canonical IDs and structured dataclasses for:
4
+ - Database
5
+ - Schema
6
+ - Table
7
+ - Column
8
+ - PrimaryKey
9
+ - ForeignKey
10
+ - Index
11
+ - UniqueConstraint
12
+ - CheckConstraint
13
+ - View
14
+ - Sequence
15
+ - Migration
16
+ - ORMModel
17
+
18
+ Architectural Rules:
19
+ 1. Never assume database dialect or schema name when not statically provable; use `UNKNOWN` or `AMBIGUOUS`.
20
+ 2. Every database entity and relationship carries source file, line range, parser version, index generation,
21
+ relationship type, evidence class, confidence, and canonical IDs.
22
+ 3. All connection strings and defaults pass through secret redaction before model construction.
23
+ """
24
+ from __future__ import annotations
25
+
26
+ from dataclasses import dataclass, field
27
+ from enum import StrEnum
28
+ from typing import Any
29
+
30
+ from codegraph.security.redaction import redact_secrets
31
+
32
+
33
+ class DatabaseEntityKind(StrEnum):
34
+ DATABASE = "Database"
35
+ SCHEMA = "Schema"
36
+ TABLE = "Table"
37
+ COLUMN = "Column"
38
+ PRIMARY_KEY = "PrimaryKey"
39
+ FOREIGN_KEY = "ForeignKey"
40
+ INDEX = "Index"
41
+ UNIQUE_CONSTRAINT = "UniqueConstraint"
42
+ CHECK_CONSTRAINT = "CheckConstraint"
43
+ VIEW = "View"
44
+ SEQUENCE = "Sequence"
45
+ MIGRATION = "Migration"
46
+ ORM_MODEL = "ORMModel"
47
+
48
+
49
+ def normalize_dialect(raw_dialect: str | None) -> str:
50
+ """Normalize database dialect/provider string, defaulting to UNKNOWN when unproven."""
51
+ if not raw_dialect:
52
+ return "UNKNOWN"
53
+ val = raw_dialect.strip().lower()
54
+ if val in ("amg", "ambiguous"):
55
+ return "AMBIGUOUS"
56
+ if val in ("unknown", ""):
57
+ return "UNKNOWN"
58
+ if val.startswith(("postgres", "psycopg", "asyncpg", "pg")):
59
+ return "postgres"
60
+ if val.startswith(("mysql", "pymysql", "mariadb")):
61
+ return "mysql"
62
+ if val.startswith(("sqlite", "aiosqlite")):
63
+ return "sqlite"
64
+ if val.startswith(("mongo", "mongodb")):
65
+ return "mongodb"
66
+ if val.startswith("redis"):
67
+ return "redis"
68
+ if val.startswith(("mssql", "sqlserver")):
69
+ return "mssql"
70
+ return val
71
+
72
+
73
+ def normalize_schema_name(raw_schema: str | None, dialect: str = "UNKNOWN") -> str:
74
+ """Normalize schema name without fabricating unproven schemas."""
75
+ if raw_schema and raw_schema.strip():
76
+ s = raw_schema.strip()
77
+ if s.upper() in ("UNKNOWN", "AMBIGUOUS"):
78
+ return s.upper()
79
+ return s.lower()
80
+ norm_dialect = normalize_dialect(dialect)
81
+ if norm_dialect == "postgres":
82
+ return "public"
83
+ if norm_dialect == "sqlite":
84
+ return "main"
85
+ if norm_dialect == "AMBIGUOUS":
86
+ return "AMBIGUOUS"
87
+ return "UNKNOWN"
88
+
89
+
90
+ def build_db_canonical_id(
91
+ kind: DatabaseEntityKind | str,
92
+ table: str = "",
93
+ column: str = "",
94
+ name: str = "",
95
+ dialect: str = "UNKNOWN",
96
+ schema: str = "UNKNOWN",
97
+ module: str = "",
98
+ ) -> str:
99
+ """Build a deterministic canonical ID for any database entity.
100
+
101
+ Examples:
102
+ Table: db.postgres.public.users or db.UNKNOWN.UNKNOWN.users
103
+ Column: db.postgres.public.users.id
104
+ PrimaryKey: db.postgres.public.users.pk.id
105
+ ForeignKey: db.postgres.public.orders.fk.user_id
106
+ Index: db.postgres.public.users.idx.ix_users_email
107
+ Migration: db.migration.alembic.0001_initial
108
+ ORMModel: orm.app.models.User
109
+ """
110
+ k_str = kind.value if isinstance(kind, DatabaseEntityKind) else str(kind)
111
+ d = normalize_dialect(dialect)
112
+ s = normalize_schema_name(schema, d)
113
+ tbl = table.strip().lower() if table else ""
114
+ col = column.strip().lower() if column else ""
115
+ nm = name.strip() if name else ""
116
+
117
+ if k_str == DatabaseEntityKind.DATABASE.value:
118
+ return f"db.{d}.{nm.lower() or s}"
119
+ if k_str == DatabaseEntityKind.SCHEMA.value:
120
+ return f"db.{d}.{nm.lower() or s}"
121
+ if k_str == DatabaseEntityKind.TABLE.value:
122
+ return f"db.{d}.{s}.{tbl or nm.lower() or 'unknown'}"
123
+ if k_str == DatabaseEntityKind.VIEW.value:
124
+ return f"db.{d}.{s}.view.{tbl or nm.lower() or 'unknown'}"
125
+ if k_str == DatabaseEntityKind.SEQUENCE.value:
126
+ return f"db.{d}.{s}.seq.{nm.lower() or tbl or 'unknown'}"
127
+ if k_str == DatabaseEntityKind.COLUMN.value:
128
+ return f"db.{d}.{s}.{tbl or 'unknown'}.{col or nm.lower() or 'unknown'}"
129
+ if k_str == DatabaseEntityKind.PRIMARY_KEY.value:
130
+ return f"db.{d}.{s}.{tbl or 'unknown'}.pk.{col or nm.lower() or 'pk'}"
131
+ if k_str == DatabaseEntityKind.FOREIGN_KEY.value:
132
+ return f"db.{d}.{s}.{tbl or 'unknown'}.fk.{col or nm.lower() or 'fk'}"
133
+ if k_str == DatabaseEntityKind.INDEX.value:
134
+ return f"db.{d}.{s}.{tbl or 'unknown'}.idx.{nm.lower() or col or 'idx'}"
135
+ if k_str == DatabaseEntityKind.UNIQUE_CONSTRAINT.value:
136
+ return f"db.{d}.{s}.{tbl or 'unknown'}.uq.{nm.lower() or col or 'uq'}"
137
+ if k_str == DatabaseEntityKind.CHECK_CONSTRAINT.value:
138
+ return f"db.{d}.{s}.{tbl or 'unknown'}.ck.{nm.lower() or 'ck'}"
139
+ if k_str == DatabaseEntityKind.MIGRATION.value:
140
+ sys_name = (module or "sql").strip().lower()
141
+ return f"db.migration.{sys_name}.{nm or 'unknown'}"
142
+ if k_str == DatabaseEntityKind.ORM_MODEL.value:
143
+ if module:
144
+ return f"{module}.{nm}"
145
+ return f"orm.{nm}"
146
+ return f"db.{d}.{s}.{nm.lower() or tbl or 'unknown'}"
147
+
148
+
149
+ @dataclass(frozen=True)
150
+ class DatabaseEntity:
151
+ """Canonical representation of a discovered database schema or ORM entity."""
152
+
153
+ canonical_id: str
154
+ kind: str # DatabaseEntityKind value
155
+ name: str
156
+ dialect: str = "UNKNOWN"
157
+ schema_name: str = "UNKNOWN"
158
+ table_name: str = ""
159
+ column_name: str = ""
160
+ data_type: str = ""
161
+ nullable: bool = True
162
+ default_value: str | None = None
163
+ is_primary_key: bool = False
164
+ is_foreign_key: bool = False
165
+ is_unique: bool = False
166
+ is_indexed: bool = False
167
+ target_table: str | None = None
168
+ target_column: str | None = None
169
+ orm_model_id: str | None = None
170
+ framework: str = ""
171
+ file_path: str = ""
172
+ start_line: int = 1
173
+ end_line: int = 1
174
+ evidence: str = ""
175
+ confidence: str = "HIGH"
176
+ evidence_class: str = "AST_VERIFIED"
177
+ status: str = "FACT"
178
+ metadata: dict[str, Any] = field(default_factory=dict)
179
+
180
+ def __post_init__(self) -> None:
181
+ if self.default_value is not None:
182
+ object.__setattr__(self, "default_value", redact_secrets(str(self.default_value)))
183
+ if self.evidence:
184
+ object.__setattr__(self, "evidence", redact_secrets(self.evidence))
185
+
186
+ def as_dict(self) -> dict[str, Any]:
187
+ return {
188
+ "canonical_id": self.canonical_id,
189
+ "kind": self.kind,
190
+ "name": self.name,
191
+ "dialect": self.dialect,
192
+ "schema_name": self.schema_name,
193
+ "table_name": self.table_name,
194
+ "column_name": self.column_name,
195
+ "data_type": self.data_type,
196
+ "nullable": self.nullable,
197
+ "default_value": self.default_value,
198
+ "is_primary_key": self.is_primary_key,
199
+ "is_foreign_key": self.is_foreign_key,
200
+ "is_unique": self.is_unique,
201
+ "is_indexed": self.is_indexed,
202
+ "target_table": self.target_table,
203
+ "target_column": self.target_column,
204
+ "orm_model_id": self.orm_model_id,
205
+ "framework": self.framework,
206
+ "file_path": self.file_path,
207
+ "file": self.file_path,
208
+ "start_line": self.start_line,
209
+ "end_line": self.end_line,
210
+ "evidence": self.evidence,
211
+ "confidence": self.confidence,
212
+ "evidence_class": self.evidence_class,
213
+ "status": self.status,
214
+ "metadata": dict(self.metadata),
215
+ }
216
+
217
+
218
+ @dataclass(frozen=True)
219
+ class DatabaseQueryFact:
220
+ """Static database query or ORM operation extracted from source code."""
221
+
222
+ query_id: str
223
+ caller_symbol_id: str
224
+ operation: str # SELECT | INSERT | UPDATE | DELETE | DDL | UNKNOWN
225
+ relationship: str # READS_TABLE | WRITES_TABLE | POSSIBLE_TABLE | UNKNOWN_TABLE | QUERIES_DATABASE
226
+ table_name: str # table name or UNKNOWN / POSSIBLE candidate
227
+ table_canonical_id: str
228
+ columns: tuple[str, ...] = ()
229
+ framework: str = "raw_sql"
230
+ normalized_sql: str = ""
231
+ file_path: str = ""
232
+ start_line: int = 1
233
+ end_line: int = 1
234
+ evidence: str = ""
235
+ confidence: str = "HIGH"
236
+ evidence_class: str = "AST_VERIFIED"
237
+ status: str = "FACT"
238
+
239
+ def as_dict(self) -> dict[str, Any]:
240
+ return {
241
+ "query_id": self.query_id,
242
+ "caller_symbol_id": self.caller_symbol_id,
243
+ "symbol": self.caller_symbol_id,
244
+ "operation": self.operation,
245
+ "relationship": self.relationship,
246
+ "table_name": self.table_name,
247
+ "table_canonical_id": self.table_canonical_id,
248
+ "columns": list(self.columns),
249
+ "framework": self.framework,
250
+ "normalized_sql": self.normalized_sql,
251
+ "file_path": self.file_path,
252
+ "file": self.file_path,
253
+ "start_line": self.start_line,
254
+ "end_line": self.end_line,
255
+ "evidence": self.evidence,
256
+ "confidence": self.confidence,
257
+ "evidence_class": self.evidence_class,
258
+ "status": self.status,
259
+ }
260
+
261
+
262
+ @dataclass(frozen=True)
263
+ class MigrationFact:
264
+ """Extracted schema migration record (Alembic, Django migrations, Prisma, raw SQL)."""
265
+
266
+ migration_id: str
267
+ canonical_id: str
268
+ system: str # alembic | django | prisma | sql
269
+ revision: str
270
+ down_revision: str | None = None
271
+ file_path: str = ""
272
+ start_line: int = 1
273
+ end_line: int = 1
274
+ created_tables: tuple[str, ...] = ()
275
+ dropped_tables: tuple[str, ...] = ()
276
+ added_columns: tuple[str, ...] = () # "table.column"
277
+ removed_columns: tuple[str, ...] = () # "table.column"
278
+ renamed_columns: tuple[str, ...] = () # "table.old_col->new_col"
279
+ indexes: tuple[str, ...] = ()
280
+ foreign_keys: tuple[str, ...] = ()
281
+ constraints: tuple[str, ...] = ()
282
+ affected_tables: tuple[str, ...] = ()
283
+ evidence: str = ""
284
+ confidence: str = "HIGH"
285
+ evidence_class: str = "AST_VERIFIED"
286
+
287
+ def as_dict(self) -> dict[str, Any]:
288
+ return {
289
+ "migration_id": self.migration_id,
290
+ "canonical_id": self.canonical_id,
291
+ "system": self.system,
292
+ "revision": self.revision,
293
+ "down_revision": self.down_revision,
294
+ "file_path": self.file_path,
295
+ "file": self.file_path,
296
+ "start_line": self.start_line,
297
+ "end_line": self.end_line,
298
+ "created_tables": list(self.created_tables),
299
+ "dropped_tables": list(self.dropped_tables),
300
+ "added_columns": list(self.added_columns),
301
+ "removed_columns": list(self.removed_columns),
302
+ "renamed_columns": list(self.renamed_columns),
303
+ "indexes": list(self.indexes),
304
+ "foreign_keys": list(self.foreign_keys),
305
+ "constraints": list(self.constraints),
306
+ "affected_tables": list(self.affected_tables),
307
+ "evidence": self.evidence,
308
+ "confidence": self.confidence,
309
+ "evidence_class": self.evidence_class,
310
+ }