gabriel / musehub public
musehub_intel_models.py python
694 lines 31.4 KB
Raw
sha256:73f24973678ceefd56628ee17c6d0535d86e33533828af6c63348f50941515ad Merge branch 'fix/smoke-test-tag-label' into dev Human 15 days ago
1 """ORM models for code intelligence, symbol analytics, and structural analysis.
2
3 Tables:
4 - musehub_intel_results: Domain-agnostic intelligence result cache
5 - musehub_symbol_history_entries: Normalized symbol history per (repo, address, commit)
6 - musehub_symbol_vitals: Pre-computed symbol vitals per (repo, address)
7 - musehub_symbol_coupling: Pre-computed co-change coupling per (repo, address, co_address)
8 - musehub_symbol_intel: Per-symbol intel metrics (churn, blast, gravity)
9 - musehub_hash_occurrence_entries: Clone detection index per (content_id, repo, address)
10 - musehub_intel_coupling: Co-changing file pairs
11 - musehub_intel_entangle: Symbol entanglement pairs
12 - musehub_intel_dead: Dead-code candidates
13 - musehub_intel_blast_risk: Composite pre-release risk per symbol
14 - musehub_intel_stable: Per-symbol stability records
15 - musehub_intel_velocity: Module growth velocity
16 - musehub_intel_clones: Duplicate code clusters
17 - musehub_intel_type: Per-symbol type health
18 - musehub_intel_api_surface: Public API surface entries
19 - musehub_intel_languages: Language composition per push
20 - musehub_intel_refactor_events: Detected refactoring events
21 - musehub_intel_codemap_modules: Structural dependency topology per file
22 - musehub_intel_codemap_meta: Aggregate code-map statistics per repo
23 - musehub_intel_breakage_issues: Stale-import issues detected at push time
24 - musehub_intel_breakage_meta: Aggregate breakage statistics per repo
25 - musehub_file_last_commits: Materialized per-file last-commit attribution
26 """
27
28 from __future__ import annotations
29
30 from datetime import datetime, timezone
31
32 import sqlalchemy as sa
33 from sqlalchemy import Boolean, DateTime, ForeignKey, Index, Integer, String, Text, UniqueConstraint
34 from sqlalchemy.orm import Mapped, MappedAsDataclass, mapped_column
35 from sqlalchemy.dialects.postgresql import JSONB
36
37 from musehub.db.database import Base
38 from musehub.types.json_types import JSONValue # noqa: F401 — needed for ForwardRef resolution in Mapped[]
39
40
41 def _utc_now() -> datetime:
42 return datetime.now(tz=timezone.utc)
43
44
45 class MusehubIntelResult(Base):
46 """Domain-agnostic intelligence result cache — one row per (repo, intel_type).
47
48 Replaces the old code-only ``musehub_symbol_index`` and
49 ``musehub_file_intel_cache`` tables with a single, extensible store.
50
51 ``intel_type`` is a namespaced string that identifies what was computed:
52 - ``code.symbol_history`` — address → commit op history (JSON)
53 - ``code.hash_occurrence`` — content_id → address list (clone data)
54 - ``code.intel_snapshot`` — full IntelSnapshot as_dict() output
55 - ``code.intel_summary`` — condensed summary for the repo home page
56 - ``code.per_symbol_intel`` — per-symbol {churn, blast, gravity, …}
57 - ``structural.velocity`` — commit velocity across all domains
58 - ``midi.tags`` — MIDI tag statistics (future)
59 - … any future domain prefix …
60
61 ``ref`` is the commit_id at which the result was computed. ``schema_version``
62 lets readers skip stale entries whose format has changed without a migration.
63
64 Upsert semantics: the unique constraint on ``(repo_id, intel_type)`` means
65 each push overwrites the previous result for that type — always the latest.
66 ``result_id`` is a genesis hash of (repo_id, intel_type, ref) and updates
67 alongside the data columns.
68 """
69
70 __tablename__ = "musehub_intel_results"
71 __table_args__ = (
72 UniqueConstraint("repo_id", "intel_type", name="uq_musehub_intel_results_repo_type"),
73 Index("ix_musehub_intel_results_repo_type", "repo_id", "intel_type"),
74 )
75
76 result_id: Mapped[str] = mapped_column(String(128), primary_key=True)
77 repo_id: Mapped[str] = mapped_column(
78 String(128),
79 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
80 nullable=False,
81 index=True,
82 )
83 # Namespaced type string, e.g. "code.intel_snapshot", "structural.velocity"
84 intel_type: Mapped[str] = mapped_column(String(128), nullable=False, index=True)
85 # Domain prefix extracted from intel_type for easier filtering, e.g. "code"
86 domain: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
87 # Commit ID at which this result was computed
88 ref: Mapped[str] = mapped_column(String(128), nullable=False)
89 # The computed result — JSON text; schema defined per intel_type
90 data_json: Mapped[str] = mapped_column(sa.Text, nullable=False, default="{}")
91 # Incremented when the data_json schema changes; readers skip mismatched versions
92 schema_version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
93 computed_at: Mapped[datetime] = mapped_column(
94 DateTime(timezone=True), nullable=False, default=_utc_now
95 )
96
97
98 class MusehubSymbolHistoryEntry(Base):
99 """One row per (repo_id, address, commit_id) — normalized symbol history.
100
101 Replaces the code.symbol_history JSON blob in musehub_intel_results.
102 Enables O(1) point lookups and file-scoped range scans without deserializing
103 a per-repo megabyte blob.
104 """
105
106 __tablename__ = "musehub_symbol_history_entries"
107 __table_args__ = (
108 Index("ix_symbol_history_repo_address", "repo_id", "address"),
109 Index("ix_symbol_history_repo_address_ts", "repo_id", "address", "committed_at"),
110 )
111
112 repo_id: Mapped[str] = mapped_column(
113 String(128),
114 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
115 primary_key=True,
116 )
117 address: Mapped[str] = mapped_column(String(512), primary_key=True)
118 commit_id: Mapped[str] = mapped_column(String(128), primary_key=True)
119 committed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
120 author: Mapped[str | None] = mapped_column(String(256), nullable=True)
121 op: Mapped[str] = mapped_column(String(32), nullable=False)
122 op_payload: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
123 content_id: Mapped[str | None] = mapped_column(String(128), nullable=True)
124 message: Mapped[str | None] = mapped_column(sa.Text, nullable=True)
125 commit_branch: Mapped[str | None] = mapped_column(String(512), nullable=True)
126
127
128 class MusehubSymbolVitals(Base):
129 """One row per (repo_id, address) — pre-computed symbol vitals.
130
131 Populated by the indexer background job at push time so the symbol
132 detail page never needs to load all history rows to derive these values.
133 """
134
135 __tablename__ = "musehub_symbol_vitals"
136 __table_args__ = (
137 Index("ix_symbol_vitals_repo", "repo_id"),
138 )
139
140 repo_id: Mapped[str] = mapped_column(
141 String(128),
142 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
143 primary_key=True,
144 )
145 address: Mapped[str] = mapped_column(String(512), primary_key=True)
146 first_introduced: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
147 change_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
148 version_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
149 op_add: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
150 op_modify: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
151 op_delete: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
152 op_move: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
153 coupling_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0")
154
155
156 class MusehubSymbolCoupling(Base):
157 """One row per (repo_id, address, co_address) — pre-computed co-change coupling.
158
159 Populated by the indexer background job at push time. Replaces the
160 request-time GROUP BY + IN (...) coupling query.
161 """
162
163 __tablename__ = "musehub_symbol_coupling"
164 __table_args__ = (
165 Index("ix_symbol_coupling_repo_address", "repo_id", "address"),
166 )
167
168 repo_id: Mapped[str] = mapped_column(
169 String(128),
170 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
171 primary_key=True,
172 )
173 address: Mapped[str] = mapped_column(String(512), primary_key=True)
174 co_address: Mapped[str] = mapped_column(String(512), primary_key=True)
175 shared_commits: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
176
177
178 class MusehubSymbolIntel(MappedAsDataclass, Base):
179 """One row per (repo_id, address) — per-symbol intel metrics.
180
181 Replaces the code.per_symbol_intel JSON blob in musehub_intel_results.
182 Updated via upsert on every push. Enables indexed hotspot, gravity,
183 and blast queries without in-process deserialization.
184 """
185
186 __tablename__ = "musehub_symbol_intel"
187 __table_args__ = (
188 Index("ix_symbol_intel_repo_churn", "repo_id", "churn"),
189 Index("ix_symbol_intel_repo_gravity", "repo_id", "gravity"),
190 Index("ix_symbol_intel_repo_gravity_pct", "repo_id", "gravity_pct"),
191 )
192
193 repo_id: Mapped[str] = mapped_column(
194 String(128),
195 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
196 primary_key=True,
197 )
198 address: Mapped[str] = mapped_column(String(512), primary_key=True)
199 churn: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
200 churn_30d: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
201 churn_90d: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
202 blast: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
203 blast_direct: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
204 blast_cross: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
205 blast_top: Mapped[list[str]] = mapped_column(sa.ARRAY(sa.Text), nullable=False, default_factory=list)
206 last_changed: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, default=None)
207 last_author: Mapped[str | None] = mapped_column(String(256), nullable=True, default=None)
208 author_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
209 gravity: Mapped[float] = mapped_column(sa.Float, nullable=False, default=0.0)
210 weekly: Mapped[list[int]] = mapped_column(sa.ARRAY(sa.Integer), nullable=False, default_factory=list)
211 last_commit_id: Mapped[str | None] = mapped_column(String(128), nullable=True, default=None)
212 op: Mapped[str | None] = mapped_column(String(32), nullable=True, default=None)
213 gravity_pct: Mapped[float | None] = mapped_column(sa.Float, nullable=True, default=None)
214 gravity_direct_dependents: Mapped[int | None] = mapped_column(Integer, nullable=True, default=None)
215 gravity_transitive_dependents: Mapped[int | None] = mapped_column(Integer, nullable=True, default=None)
216 gravity_max_depth: Mapped[int | None] = mapped_column(sa.SmallInteger, nullable=True, default=None)
217 gravity_depth_distribution: Mapped[dict | None] = mapped_column(JSONB, nullable=True, default=None)
218 symbol_kind: Mapped[str | None] = mapped_column(String(64), nullable=True, default=None)
219
220
221 class MusehubHashOccurrenceEntry(Base):
222 """One row per (content_id, repo_id, address) — clone detection index.
223
224 Replaces the code.hash_occurrence JSON blob in musehub_intel_results.
225 Enables O(1) clone lookups: given a content_id, find all addresses
226 that share the same body.
227 """
228
229 __tablename__ = "musehub_hash_occurrence_entries"
230 __table_args__ = (
231 Index("ix_hash_occurrence_repo_content", "repo_id", "content_id"),
232 )
233
234 content_id: Mapped[str] = mapped_column(String(128), primary_key=True)
235 repo_id: Mapped[str] = mapped_column(
236 String(128),
237 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
238 primary_key=True,
239 )
240 address: Mapped[str] = mapped_column(String(512), primary_key=True)
241
242
243 class MusehubIntelCoupling(Base):
244 """Co-changing file pairs detected by muse code coupling."""
245
246 __tablename__ = "musehub_intel_coupling"
247 __table_args__ = (
248 Index("ix_intel_coupling_repo", "repo_id"),
249 Index("ix_intel_coupling_repo_co", "repo_id", "co_changes"),
250 Index("ix_intel_coupling_repo_file_a", "repo_id", "file_a"),
251 )
252
253 repo_id: Mapped[str] = mapped_column(
254 String(128),
255 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
256 primary_key=True,
257 )
258 file_a: Mapped[str] = mapped_column(String(512), primary_key=True)
259 file_b: Mapped[str] = mapped_column(String(512), primary_key=True)
260 co_changes: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
261 ref: Mapped[str] = mapped_column(String(128), nullable=False)
262
263
264 class MusehubIntelEntangle(Base):
265 """Symbol entanglement pairs detected by muse code entangle."""
266
267 __tablename__ = "musehub_intel_entangle"
268 __table_args__ = (
269 Index("ix_intel_entangle_repo", "repo_id"),
270 Index("ix_intel_entangle_repo_file_a", "repo_id", "file_a"),
271 Index("ix_intel_entangle_repo_rate", "repo_id", "co_change_rate"),
272 Index("ix_intel_entangle_repo_symbol_a", "repo_id", "symbol_a"),
273 Index("ix_intel_entangle_repo_symbol_b", "repo_id", "symbol_b"),
274 )
275
276 repo_id: Mapped[str] = mapped_column(
277 String(128),
278 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
279 primary_key=True,
280 )
281 symbol_a: Mapped[str] = mapped_column(String(512), primary_key=True)
282 symbol_b: Mapped[str] = mapped_column(String(512), primary_key=True)
283 co_change_rate: Mapped[float] = mapped_column(sa.Float, nullable=False, default=0.0)
284 co_changes: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
285 commits_both_active: Mapped[int | None] = mapped_column(Integer, nullable=True)
286 structurally_linked: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, server_default=sa.false())
287 file_a: Mapped[str | None] = mapped_column(String(512), nullable=True)
288 file_b: Mapped[str | None] = mapped_column(String(512), nullable=True)
289 same_file: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
290 a_in_test: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
291 b_in_test: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
292 ref: Mapped[str] = mapped_column(String(128), nullable=False)
293
294
295 class MusehubIntelDead(Base):
296 """Dead-code candidates detected by muse code dead."""
297
298 __tablename__ = "musehub_intel_dead"
299 __table_args__ = (
300 Index("ix_intel_dead_repo", "repo_id"),
301 )
302
303 repo_id: Mapped[str] = mapped_column(
304 String(128),
305 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
306 primary_key=True,
307 )
308 address: Mapped[str] = mapped_column(String(512), primary_key=True)
309 kind: Mapped[str] = mapped_column(String(64), nullable=False)
310 confidence: Mapped[str] = mapped_column(String(16), nullable=False)
311 reason: Mapped[str | None] = mapped_column(Text, nullable=True)
312 ref: Mapped[str] = mapped_column(String(128), nullable=False)
313 dismissed: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, default=False, server_default="false")
314
315
316 class MusehubIntelBlastRisk(Base):
317 """Composite pre-release risk per symbol from muse code blast-risk."""
318
319 __tablename__ = "musehub_intel_blast_risk"
320 __table_args__ = (
321 Index("ix_intel_blast_risk_repo", "repo_id"),
322 )
323
324 repo_id: Mapped[str] = mapped_column(
325 String(128),
326 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
327 primary_key=True,
328 )
329 address: Mapped[str] = mapped_column(String(512), primary_key=True)
330 kind: Mapped[str] = mapped_column(String(64), nullable=False)
331 risk: Mapped[str] = mapped_column(String(16), nullable=False)
332 risk_score: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
333 impact_score: Mapped[float] = mapped_column(sa.Float, nullable=False, default=0.0)
334 churn_score: Mapped[float] = mapped_column(sa.Float, nullable=False, default=0.0)
335 test_gap_score: Mapped[float] = mapped_column(sa.Float, nullable=False, default=0.0)
336 coupling_score: Mapped[float] = mapped_column(sa.Float, nullable=False, default=0.0)
337 ref: Mapped[str] = mapped_column(String(128), nullable=False)
338
339
340 class MusehubIntelStable(Base):
341 """Per-symbol stability record — days since last modification.
342
343 Populated by ``StableProvider`` on every ``intel.code.stable`` job.
344 A symbol qualifies when ``churn_30d = 0`` and ``churn_90d = 0`` in
345 ``musehub_symbol_intel``, meaning it has not been touched in at least
346 90 days. ``days_stable`` is derived from ``last_changed`` and
347 ``last_changed_commit`` carries the commit that last modified the symbol
348 (NULL for symbols that have never been modified).
349 """
350
351 __tablename__ = "musehub_intel_stable"
352 __table_args__ = (
353 Index("ix_intel_stable_repo", "repo_id"),
354 )
355
356 repo_id: Mapped[str] = mapped_column(
357 String(128),
358 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
359 primary_key=True,
360 )
361 address: Mapped[str] = mapped_column(String(512), primary_key=True)
362 days_stable: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
363 since_start: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, server_default=sa.false())
364 last_changed_commit: Mapped[str | None] = mapped_column(String(128), nullable=True)
365 symbol_kind: Mapped[str | None] = mapped_column(String(64), nullable=True)
366 ref: Mapped[str] = mapped_column(String(128), nullable=False)
367
368
369 class MusehubIntelVelocity(Base):
370 """Module growth velocity from muse code velocity."""
371
372 __tablename__ = "musehub_intel_velocity"
373 __table_args__ = (
374 Index("ix_intel_velocity_repo", "repo_id"),
375 )
376
377 repo_id: Mapped[str] = mapped_column(
378 String(128),
379 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
380 primary_key=True,
381 )
382 module: Mapped[str] = mapped_column(String(512), primary_key=True)
383 added: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
384 removed: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
385 net: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
386 modified: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
387 active_commits: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
388 prior_added: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
389 prior_net: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
390 prior_modified: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
391 prior_active_commits: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
392 acceleration: Mapped[float] = mapped_column(sa.Float, nullable=False, default=0.0)
393 stagnant_commits: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
394 window_size: Mapped[int] = mapped_column(Integer, nullable=False, default=20)
395 commits_analysed: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
396 ref: Mapped[str] = mapped_column(String(128), nullable=False)
397
398
399 class MusehubIntelClones(Base):
400 """Duplicate code clusters from muse code clones."""
401
402 __tablename__ = "musehub_intel_clones"
403 __table_args__ = (
404 Index("ix_intel_clones_repo", "repo_id"),
405 )
406
407 repo_id: Mapped[str] = mapped_column(
408 String(128),
409 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
410 primary_key=True,
411 )
412 cluster_hash: Mapped[str] = mapped_column(String(128), primary_key=True)
413 tier: Mapped[str] = mapped_column(String(32), nullable=False)
414 member_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
415 members_json: Mapped[str] = mapped_column(Text, nullable=False, default="[]")
416 ref: Mapped[str] = mapped_column(String(128), nullable=False)
417
418
419 class MusehubIntelType(Base):
420 """Per-symbol type health from muse code type."""
421
422 __tablename__ = "musehub_intel_type"
423 __table_args__ = (
424 Index("ix_intel_type_repo", "repo_id"),
425 )
426
427 repo_id: Mapped[str] = mapped_column(
428 String(128),
429 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
430 primary_key=True,
431 )
432 address: Mapped[str] = mapped_column(String(512), primary_key=True)
433 kind: Mapped[str] = mapped_column(String(64), nullable=False)
434 return_is_any: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, server_default=sa.false())
435 params_total: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
436 params_annotated: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
437 params_with_any: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
438 type_score: Mapped[float] = mapped_column(sa.Float, nullable=False, default=0.0)
439 return_annotation: Mapped[str | None] = mapped_column(String(256), nullable=True)
440 ref: Mapped[str] = mapped_column(String(128), nullable=False)
441
442
443 class MusehubIntelApiSurface(Base):
444 """Public API surface entries from muse api-surface."""
445
446 __tablename__ = "musehub_intel_api_surface"
447 __table_args__ = (
448 Index("ix_intel_api_surface_repo", "repo_id"),
449 )
450
451 repo_id: Mapped[str] = mapped_column(
452 String(128),
453 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
454 primary_key=True,
455 )
456 address: Mapped[str] = mapped_column(String(512), primary_key=True)
457 kind: Mapped[str] = mapped_column(String(64), nullable=False)
458 signature_id: Mapped[str | None] = mapped_column(String(128), nullable=True)
459 visibility: Mapped[str] = mapped_column(String(32), nullable=False, default="public", server_default="public")
460 ref: Mapped[str] = mapped_column(String(128), nullable=False)
461
462
463 class MusehubIntelLanguages(Base):
464 """Language composition per push — files, symbols, and kind breakdown.
465
466 One row per (repo_id, language) pair. Upserted on every push by
467 ``LanguagesProvider`` which derives all data from stored snapshot objects
468 using ``language_of()`` (pure extension map) and ``parse_symbols()``
469 (pure AST) — no subprocess, no on-disk repo checkout required.
470
471 Columns
472 -------
473 repo_id FK to musehub_repos; CASCADE delete clears rows when repo is removed.
474 language Display name from ``language_of()``, e.g. ``"Python"``, ``"HTML"``.
475 symbol_count Total semantic symbols (imports excluded) across all files of this language.
476 file_count Number of tracked files of this language in the HEAD snapshot.
477 pct symbol_count / total_symbols * 100; 0.0 when no symbols exist.
478 kinds_json Dict mapping symbol kind → count, e.g. ``{"function": 1346, "class": 1447}``.
479 ``None`` for languages with no parseable symbols (assets, config, docs).
480 ref Branch or commit ref at harvest time.
481 """
482
483 __tablename__ = "musehub_intel_languages"
484 __table_args__ = (
485 Index("ix_intel_languages_repo", "repo_id"),
486 )
487
488 repo_id: Mapped[str] = mapped_column(
489 String(128),
490 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
491 primary_key=True,
492 )
493 language: Mapped[str] = mapped_column(String(128), primary_key=True)
494 symbol_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
495 file_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
496 pct: Mapped[float] = mapped_column(sa.Float, nullable=False, default=0.0)
497 kinds_json: Mapped[dict | None] = mapped_column(JSONB, nullable=True, default=None)
498 ref: Mapped[str] = mapped_column(String(128), nullable=False)
499
500
501 class MusehubIntelRefactorEvent(Base):
502 """Detected refactoring events from muse code detect-refactor."""
503
504 __tablename__ = "musehub_intel_refactor_events"
505 __table_args__ = (
506 Index("ix_intel_refactor_events_repo", "repo_id"),
507 Index("ix_intel_refactor_events_commit", "commit_id"),
508 Index("ix_intel_refactor_events_repo_kind", "repo_id", "kind"),
509 )
510
511 event_id: Mapped[str] = mapped_column(String(128), primary_key=True)
512 repo_id: Mapped[str] = mapped_column(
513 String(128),
514 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
515 nullable=False,
516 index=True,
517 )
518 kind: Mapped[str] = mapped_column(String(64), nullable=False)
519 address: Mapped[str] = mapped_column(String(512), nullable=False)
520 detail: Mapped[str | None] = mapped_column(Text, nullable=True)
521 commit_id: Mapped[str] = mapped_column(String(128), nullable=False)
522 commit_message: Mapped[str | None] = mapped_column(Text, nullable=True)
523 committed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
524
525
526 class MusehubIntelCodemapModule(Base):
527 """Structural dependency topology for one file in the HEAD snapshot.
528
529 One row per (repo_id, file_path) pair. Upserted on every push by
530 ``CodemapProvider`` which walks the snapshot manifest, calls
531 ``parse_symbols()`` per file to extract import records, resolves dotted
532 module names back to tracked file paths, and computes fan_in / fan_out
533 without spawning any subprocess.
534
535 Columns
536 -------
537 repo_id FK to musehub_repos; CASCADE delete clears rows when repo removed.
538 file_path Repo-relative path, e.g. ``"musehub/api/routes/musehub/ui_intel.py"``.
539 symbol_count Non-import symbols declared in this file (functions, classes, methods).
540 fan_in Number of other tracked files that import this file.
541 fan_out Number of tracked files this file imports.
542 language Display name from ``language_of()``, e.g. ``"Python"``.
543 ref Branch or commit ref at harvest time.
544
545 Notes
546 -----
547 Stdlib and third-party imports that cannot be resolved to a tracked file
548 path are silently skipped — they inflate ``fan_out`` only when the target
549 is actually in the manifest.
550 """
551
552 __tablename__ = "musehub_intel_codemap_modules"
553 __table_args__ = (
554 Index("ix_intel_codemap_modules_repo", "repo_id"),
555 )
556
557 repo_id: Mapped[str] = mapped_column(
558 String(128),
559 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
560 primary_key=True,
561 )
562 file_path: Mapped[str] = mapped_column(String(512), primary_key=True)
563 symbol_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
564 fan_in: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
565 fan_out: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
566 language: Mapped[str] = mapped_column(String(128), nullable=False, default="")
567 ref: Mapped[str] = mapped_column(String(128), nullable=False)
568
569
570 class MusehubIntelCodemapMeta(Base):
571 """Aggregate code-map statistics for a repo — one row per repo.
572
573 Written by ``CodemapProvider`` after the full module pass completes.
574 Drives the stat chips on the codemap intel page and the dashboard card
575 without requiring a COUNT aggregate query on every page load.
576
577 Columns
578 -------
579 repo_id FK to musehub_repos; CASCADE delete clears this row.
580 total_modules Total tracked files processed in the last push.
581 total_edges Sum of all resolved import edges across the module graph.
582 cycle_count Number of strongly-connected components of size ≥ 2 (import cycles).
583 cycles_json List of cycle paths as ``[["a.py", "b.py", "a.py"], ...]``;
584 ``None`` when no cycles exist.
585 ref Branch or commit ref at harvest time.
586 """
587
588 __tablename__ = "musehub_intel_codemap_meta"
589
590 repo_id: Mapped[str] = mapped_column(
591 String(128),
592 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
593 primary_key=True,
594 )
595 total_modules: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
596 total_edges: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
597 cycle_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
598 cycles_json: Mapped[dict | None] = mapped_column(JSONB, nullable=True, default=None)
599 ref: Mapped[str] = mapped_column(String(128), nullable=False)
600
601
602 class MusehubIntelBreakageIssue(Base):
603 """One stale-import issue detected by BreakageProvider at push time.
604
605 Columns
606 -------
607 issue_id Stable hash: ``blob_id(repo_id:file_path:symbol_name:issue_type)``.
608 Idempotent across re-runs on the same snapshot.
609 repo_id FK to musehub_repos; CASCADE delete removes all issues.
610 file_path Repo-relative path of the file containing the stale import.
611 issue_type Currently always ``"stale_import"``.
612 description Human-readable string matching ``muse code breakage`` output.
613 severity ``"warning"`` (default) or ``"error"``.
614 ref Branch or commit ref at harvest time.
615 """
616
617 __tablename__ = "musehub_intel_breakage_issues"
618 __table_args__ = (
619 Index("ix_intel_breakage_issues_repo", "repo_id"),
620 Index("ix_intel_breakage_issues_repo_type", "repo_id", "issue_type"),
621 )
622
623 issue_id: Mapped[str] = mapped_column(String(128), primary_key=True)
624 repo_id: Mapped[str] = mapped_column(
625 String(128),
626 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
627 nullable=False,
628 index=True,
629 )
630 file_path: Mapped[str] = mapped_column(String(512), nullable=False)
631 issue_type: Mapped[str] = mapped_column(String(64), nullable=False)
632 description: Mapped[str] = mapped_column(Text, nullable=False)
633 severity: Mapped[str] = mapped_column(String(32), nullable=False, default="warning", server_default="warning")
634 ref: Mapped[str] = mapped_column(String(128), nullable=False)
635
636
637 class MusehubIntelBreakageMeta(Base):
638 """Aggregate breakage statistics for a repo — one row per repo.
639
640 Written by ``BreakageProvider`` after the full issue pass completes.
641 Drives the stat chips on the breakage intel page and the dashboard card.
642
643 Columns
644 -------
645 repo_id FK to musehub_repos; CASCADE delete removes this row.
646 total_issues Total breakage issues detected in the last push.
647 warning_count Issues with severity="warning".
648 error_count Issues with severity="error".
649 file_count Number of unique files affected.
650 ref Branch or commit ref at harvest time.
651 """
652
653 __tablename__ = "musehub_intel_breakage_meta"
654
655 repo_id: Mapped[str] = mapped_column(
656 String(128),
657 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
658 primary_key=True,
659 )
660 total_issues: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
661 warning_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
662 error_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
663 file_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
664 ref: Mapped[str] = mapped_column(String(128), nullable=False)
665
666
667 class MusehubFileLastCommit(Base):
668 """Materialized per-file last-commit attribution.
669
670 Populated at push time by compute_and_store_file_last_commits.
671 Queried at page-load time by get_file_last_commits, replacing the
672 O(N_commits × manifest_blob) walk with a single indexed SQL read.
673
674 PK: (repo_id, branch, path) — upserted on every push.
675 """
676
677 __tablename__ = "musehub_file_last_commits"
678 __table_args__ = (
679 Index("ix_file_last_commits_repo_branch", "repo_id", "branch"),
680 )
681
682 repo_id: Mapped[str] = mapped_column(
683 String(128),
684 ForeignKey("musehub_repos.repo_id", ondelete="CASCADE"),
685 primary_key=True,
686 )
687 branch: Mapped[str] = mapped_column(String(255), primary_key=True)
688 path: Mapped[str] = mapped_column(Text, primary_key=True)
689 commit_id: Mapped[str] = mapped_column(String(128), nullable=False)
690 commit_message: Mapped[str] = mapped_column(Text, nullable=False, default="")
691 commit_author: Mapped[str] = mapped_column(String(255), nullable=False, default="")
692 commit_timestamp: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
693 agent_id: Mapped[str | None] = mapped_column(String(128), nullable=True, default=None)
694 model_id: Mapped[str | None] = mapped_column(String(128), nullable=True, default=None)
File History 12 commits
sha256:cfefc25a166c3c3eed8ea3529aee19ea350bc05f2954d007420e924133b7d8ce chore: pivot to nightly channel — bump version to 0.2.0.dev… Sonnet 5 patch 13 days ago
sha256:d035733f21ccff27735fddebfbbe0ed24565a32a22db8de5885402262671ecd2 chore: bump version to 0.2.0rc15 for musehub#113 fix release Sonnet 4.6 patch 15 days ago
sha256:0032d6cfa33bc3c8367436ad768e7dd0e339b4332153160247da8266cb5fa352 Merge branch 'task/version-tags-phase3-server' into dev Human 17 days ago
sha256:4669620efda9ff41c55bdefd1f7bfe1c239d468428744c84ead9957e5a003a53 merge: rescue snapshot-recovery hardening (c00aa21d) into d… Opus 4.8 minor 30 days ago
sha256:a59da49c4611b970fc4b6ae48678ce4943261c213a07ddbd73ce9201df869b4a fix: remove false-positive proposal_comments index drop fro… Sonnet 4.6 patch 34 days ago
sha256:0a240d6dbff234f07d98a28a4a9a68db702f3f9ff9260196f24219bdb1c0b6f3 feat: render markdown mists as HTML with heading anchor links Sonnet 4.6 patch 35 days ago
sha256:24a7d47486ebc4ebd1832830580e177ec6f877b48dced8c000e198cdec4ce9d6 Merge 'task/bump-version-rc12' into 'dev' — proposal: Bump … Human 36 days ago
sha256:b9ff931d147e0114a1f17060f415b89ed551c170a91ff226c70437aa5c85f9ee Merge 'task/bump-version-rc12' into 'dev' — proposal: Bump … Human 36 days ago
sha256:d1122d21e73471879b460037b22c0b50fded7c423444a176f248428f75dac39c Merge 'task/fix-issue-pagination-cursor' into 'dev' — propo… Human 36 days ago
sha256:01e18975e73d2b3cd5b6db7929c895bef9aa6e0d4391dc5b2adfc548b41318dd Merge 'feat/adding-debug-logs-to-staging' into 'dev' — prop… Human 36 days ago
sha256:6b1949fc2797ca4c1936a637a4cbfec828ef56cf52398a2e74ca3c4f494e728f fix: use wire_bytes not mpack_bytes_raw in compute_object_b… Sonnet 4.6 patch 48 days ago
sha256:b99f2455dc346966d040133f5203297e6e3ef5803a93728a2c30568d0a0f7583 rename: delta_add → delta_upsert across wire format, models… Sonnet 4.6 patch 51 days ago