✅ fresh
last synced 2026-06-17T22:39:35.514075+00:00 · coverage 71% (
infrastructure)Validation by Beadloom
doc_sync— same source assync-check.
Infrastructure
Domain-agnostic SQLite database layer, health metrics, and git activity analysis.
Note: the cross-domain orchestrators (
reindex,doctor,debt_report,watcher) live in the application layer, not here, so thatinfrastructurenever imports a domain (the DDD Dependency Rule).
Components
Internal building blocks, each with a DOC.md:
- DB — the domain-agnostic SQLite layer (connection, schema, migrations,
meta). - Health — health snapshots + trend computation.
- Git Activity — per-node
git logactivity metrics. - MCP Tools — the canonical MCP tool-name catalog.
- Scan Paths — resolves source scan directories from
config.ymlso domains do not importapplication. - Atomic IO — atomic YAML writes (temp-file +
os.replace) so a crash mid-write never corrupts the source-of-truth graph YAML.
Specification
Modules
- db.py —
open_db()opens a SQLite connection with WAL mode and foreign keys enabled, returning a connection withsqlite3.Rowrow factory.create_schema()creates all tables and applies incremental migrations viaensure_schema_migrations().get_meta()/set_meta()for key-value metadata. ExportsSCHEMA_VERSIONconstant (currently"4"— BDL-038 G7 addedexternalto thenodes/edges/foreign_edgeslifecycleCHECK). Therulestable CHECK constraint covers all 7 rule types:deny,require,forbid_cycles,layers,cardinality,forbid_import,forbid_edge. - health.py —
take_snapshot()captures current index statistics (node/edge/doc counts, coverage percentage, stale docs, isolated nodes) and persists them to thehealth_snapshotstable.get_latest_snapshots()retrieves history for trend comparison.compute_trend()computes trend indicators (arrows and deltas) between two snapshots. - git_activity.py —
GitActivityfrozen dataclass holds per-node metrics:commits_30d,commits_90d,last_commit_date,top_contributors,activity_level.analyze_git_activity()runsgit log --since=90 days ago, parses output, maps changed files to nodes via longest source-prefix match, and classifies activity (hot: >20 commits/30d, warm: 5-20, cold: 1-4, dormant: 0 commits/90d). - mcp_tools.py — single-source catalog of MCP tool metadata used by AGENTS.md generation.
McpToolDocdescribes one tool;mcp_tool_names()returns the canonical tool-name list (pinned to the live MCP_TOOLSregistry by a drift-guard test) so the documented tool count cannot drift. - scan_paths.py —
resolve_scan_paths()readsscan_pathsfrom.beadloom/config.yml, falling back to("src", "lib", "app"). A domain-agnostic config reader at the lowest layer sograph(import resolution) andapplication(reindex) resolve scan directories without a domain importingapplication(closes the BDL-059 S3 layering inversion). - atomic_io.py —
write_yaml_atomic(path, data, **dump_kwargs)serializes withyaml.dump(**dump_kwargs), writes to a temp file in the same directory,fsyncs it, then commits withPath.replace(atomic on POSIX). Every graph-YAML writer (graphloader/patcher,serviceslink patcher,onboardingscaffolders) routes through it so a crash mid-write cannot corrupt the source-of-truth graph YAML; dump options pass through verbatim so output bytes are unchanged (BDL-060 S1 / G6).
Database Schema
Stored in .beadloom/beadloom.db (WAL mode):
nodes,edges— architecture graph. Theirkindcolumns are free-formTEXT(no CHECK) so any paradigm's vocabulary (DDDdomain/service, FSDpage/widget/repository, …) is stored and federated faithfully — Beadloom is paradigm-agnostic, not DDD-only (BDL-038 / U1). Both carry alifecyclecolumn (active/planned/deprecated/dead/external, defaultactive; BDL-037 + BDL-038 G7external).edgesalso carries acontract_keycolumn (default'') that is part of its primary key, so multiple AMQP contracts (produces/consumes) on the same(src,dst,kind)pair do not collapse (BDL-037 #102)foreign_edges— cross-repo edges whose at least one endpoint is a@repo:ref_idreference to a node in another repo; kept separate because a foreign endpoint cannot satisfy theedgesFK to local nodes (BDL-037 #100). Carries the samelifecycleCHECK (incl.external)docs,chunks— document indexcode_symbols— code symbol index (includesannotationsJSON andfile_hash)code_imports— resolved import relationshipssync_state— doc-code synchronization (includessymbols_hashcolumn for drift detection anddoc_hash_at_last_editcolumn for two-phase sync that survives reindex)file_index— file hash tracking for incremental reindex (includes__parser_fingerprint__sentinel row)health_snapshots— trend tracking (persists across reindexes)graph_snapshots— point-in-time architecture graph captures (nodes_json, edges_json, symbols_count, label)bundle_cache— L2 persistent bundle cachesearch_index— FTS5 full-text search indexrules— architecture rules fromrules.ymlmeta— index metadata
Parser Fingerprint
incremental_reindex() tracks available tree-sitter parsers via a fingerprint (sorted comma-separated supported_extensions()). Stored as a sentinel row in file_index with path='__parser_fingerprint__'. When the fingerprint changes (e.g. after uv tool install "beadloom[languages]"), a full code reindex is triggered automatically, ensuring new language parsers are used without requiring --full.
API
Module src/beadloom/infrastructure/db.py:
SCHEMA_VERSION— schema version constant (currently"4"; v3 → v4 rebuilt thelifecycleCHECK to admitexternal)open_db(db_path: Path)->sqlite3.Connection— opens DB with WAL mode, foreign keys, andRowfactoryensure_schema_migrations(conn)— applies incremental schema migrations (e.g.symbols_hashcolumn,doc_hash_at_last_editcolumn for two-phase sync, thelifecyclecolumn onnodes/edges, theedges.contract_keyrebuild, theforeign_edgestable for BDL-037 federation, the BDL-038 / U1 rebuild that drops the legacy DDD-onlykindCHECK onnodes/edgessokindis free-form, and the BDL-038 / G7 rebuild (_migrate_lifecycle_external, v3 → v4) that addsexternalto thenodes/edges/foreign_edgeslifecycleCHECK — all additive + idempotent, guarded on the stored DDL/columns; the rebuild usesPRAGMA legacy_alter_table=ONso renaming a rebuilt table does not dangle dependent FK references)create_schema(conn)— creates all tables and indexes, callsensure_schema_migrations()get_meta(conn, key, default=None)->str | Noneset_meta(conn, key, value)— upserts a key in themetatable
Module src/beadloom/infrastructure/health.py:
HealthSnapshot— frozen dataclass withtaken_at,nodes_count,edges_count,docs_count,coverage_pct,stale_count,isolated_counttake_snapshot(conn)->HealthSnapshot— computes and persists health metricsget_latest_snapshots(conn, n=2)->list[HealthSnapshot]compute_trend(current, previous)->dict[str, str]— computes trend indicators between two snapshots
Module src/beadloom/infrastructure/git_activity.py:
GitActivity— frozen dataclass:commits_30d,commits_90d,last_commit_date,top_contributors,activity_levelanalyze_git_activity(project_root, source_dirs)->dict[str, GitActivity]— parsesgit logfor 90 days, maps files to nodes, classifies activity level (hot/warm/cold/dormant)
The orchestrator modules
reindex,doctor,debt_report, andwatcherwere relocated to the application layer. Their API and tests are documented there.
Testing
Tests: tests/test_db.py, tests/test_health.py, tests/test_reindex_activity.py