perf(startup): lazy __version__ (−94ms/import) + session/turn telemetry join key - #65
Merged
Conversation
roam/__init__.py resolved the installed package version eagerly at module import, so every 'import roam' — and thus every roam CLI call, including the per-prompt compile hook — paid ~80-94ms importing importlib.metadata. The compile/hook hot path never reads __version__; a clear-and-reimport test confirms nothing on that path re-pulls the module. Defer resolution to first attribute access (PEP 562 module __getattr__). Measured (13.8.0, Windows): 'import roam' median 142ms -> 48ms; version-reading call sites (roam --version, SBOM/attest/supply-chain, index-bundle) unchanged. All access forms preserved: roam.__version__, 'from roam import __version__', hasattr. Updated the one test coupled to the eager attribute (delattr -> monkeypatch __getattr__ raising ImportError; same 'unknown'-fallback contract).
The compile telemetry row records the envelope's section list but nothing about the agent's downstream outcome; a consumer-side turn ledger records tool calls/result/session id but not the section list. Neither is joinable, so per-section value is unmeasurable and A/Bs are argued from small replays. Stamp session_id + turn_seq from env (ROAM_SESSION_ID/ROAM_TURN_SEQ), exactly like agent_mode, and forward the editor's session id from the prompt-submit hook payload. That one field makes the compile row joinable to the outcome ledger — the precondition for fleet-scale measurement. Additive and fail-open; empty when unset. Schema doc + schema guard test updated in lockstep.
roam-code AnalysisMode: incremental ( Health Score: 79/100 health: Fair codebase (79/100) — 48 critical, 7 warnings, focus: god_components Health Metrics
PR Risk
Quality Gate: PASSEDGate expression: SARIF Upload
Full analysis outputhealth{
"_meta": {
"cache_ttl_s": 300,
"cacheable": true,
"index_age_s": 2258,
"index_status": {
"dirty_files": 0,
"fresh": false,
"head_commit": "ad03a391bfb2",
"hint": "index latest commit cc3fb650262a != HEAD ad03a391bfb2 — git-derived metrics (commits, churn, co-change, weather) may be stale. Run `roam index --force`.",
"indexed_commit": "cc3fb650262a"
},
"latency_ms": null,
"response_tokens": 4088,
"roam_version": "13.9.0",
"timestamp": "2026-07-15T22:32:25Z"
},
"actionable_count": 15,
"actionable_cycles": 0,
"agent_contract": {
"confidence": null,
"facts": [
"Fair codebase (79/100) — 48 critical, 7 warnings, focus: god_components",
"health score 79",
"tangle ratio 0.0",
"0.0015 propagation cost findings",
"issue count 65"
],
"next_commands": [
"roam debt",
"roam trends --days 30"
],
"risks": []
},
"algebraic_connectivity": null,
"algebraic_connectivity_available": false,
"bottleneck_thresholds": {
"p70": 684.7,
"p90": 5029.9,
"population": 2361,
"utility_multiplier": 1.5
},
"category_severity": {
"bottlenecks": {
"critical": 15,
"info": 0,
"warning": 0
},
"cycles": {
"critical": 0,
"info": 0,
"warning": 0
},
"god_components": {
"critical": 33,
"info": 10,
"warning": 7
},
"layer_violations": {
"critical": 0,
"info": 0,
"warning": 0
}
},
"command": "health",
"cycles_actionable": 0,
"cycles_total": 17,
"framework_filtered": 0,
"health_score": 79,
"ignored_cycles": 17,
"imported_coverable_lines": 0,
"imported_coverage_files": 0,
"imported_coverage_pct": null,
"imported_covered_lines": 0,
"index_status": {
"dirty_files": 0,
"fresh": false,
"head_commit": "ad03a391bfb2",
"hint": "index latest commit cc3fb650262a != HEAD ad03a391bfb2 — git-derived metrics (commits, churn, co-change, weather) may be stale. Run `roam index --force`.",
"indexed_commit": "cc3fb650262a"
},
"issue_count": 65,
"list_counts": {
"bottlenecks": 15,
"cycle_break_suggestions": 0,
"cycles": 17,
"god_components": 50,
"layer_violations": 0,
"next_steps": 2,
"score_breakdown": 5
},
"project": "roam-code",
"propagation_cost": 0.0015,
"schema": "roam-envelope-v1",
"schema_version": "1.1.0",
"severity": {
"critical": 48,
"info": 27,
"warning": 7
},
"summary": {
"actionable_cycles": 0,
"algebraic_connectivity": null,
"algebraic_connectivity_available": false,
"category_severity": {
"bottlenecks": {
"critical": 15,
"info": 0,
"warning": 0
},
"cycles": {
"critical": 0,
"info": 0,
"warning": 0
},
"god_components": {
"critical": 33,
"info": 10,
"warning": 7
},
"layer_violations": {
"critical": 0,
"info": 0,
"warning": 0
}
},
"cycles_actionable": 0,
"cycles_definition": "Cycle counts derived from `roam.graph.cycles.find_cycles(G, min_size=2)` on the symbol graph. `cycles_total` = all SCCs of size >= 2; `cycles_actionable` = SCCs spanning >=2 files AND no test files (same-file and test-only cycles are informational). Run `roam health` for the per-cycle breakdown.",
"cycles_total": 17,
"detail_available": true,
"god_components": 50,
"god_components_definition": "God components: symbols where `(in_degree + out_degree) > 20` from the `graph_metrics` table, with utility-aware severity bands (standard >50=CRITICAL >30=WARNING; utility >150=CRITICAL >90=WARNING). Run `roam health` for the per-symbol breakdown. Legacy aliases: `god_objects` (fingerprint), `god_classes` (rules).",
"health_score": 79,
"health_score_definition": "weighted geometric mean (0-100) of 5 sigmoid health factors: tangle_ratio, god_components, bottlenecks, layer_violations, file_health (+coverage if available).",
"ignored_cycles": 17,
"imported_coverage_files": 0,
"imported_coverage_pct": null,
"issue_count": 65,
"partial_success": true,
"preserved_list_truncations": {},
"propagation_cost": 0.0015,
"severity": {
"critical": 48,
"info": 27,
"warning": 7
},
"tangle_ratio": 0,
"tangle_ratio_definition": "fraction of symbols inside non-trivial SCCs; higher = more cyclic coupling.",
"total_cycles": 17,
"truncated": true,
"verdict": "Fair codebase (79/100) — 48 critical, 7 warnings, focus: god_components",
"warnings_out": [
"health_algebraic_connectivity_warning:RuntimeWarning:algebraic_connectivity compute failed (ModuleNotFoundError): No module named 'numpy'; returning 0.0 sentinel — value is NOT a legitimate disconnected-graph reading"
]
},
"tangle_ratio": 0,
"total_cycles": 17,
"utility_count": 35,
"version": "13.9.0",
"warnings_out": [
"health_algebraic_connectivity_warning:RuntimeWarning:algebraic_connectivity compute failed (ModuleNotFoundError): No module named 'numpy'; returning 0.0 sentinel — value is NOT a legitimate disconnected-graph reading"
]
}pr-risk{
"_meta": {
"cache_ttl_s": 60,
"cacheable": true,
"index_age_s": 2260,
"index_status": {
"dirty_files": 0,
"fresh": false,
"head_commit": "ad03a391bfb2",
"hint": "index latest commit cc3fb650262a != HEAD ad03a391bfb2 — git-derived metrics (commits, churn, co-change, weather) may be stale. Run `roam index --force`.",
"indexed_commit": "cc3fb650262a"
},
"latency_ms": null,
"response_tokens": 1351,
"roam_version": "13.9.0",
"timestamp": "2026-07-15T22:32:27Z"
},
"actor": null,
"agent_contract": {
"confidence": null,
"facts": [
"High risk (52/100) — careful review needed (risk_level high) (driver: hotspot_score)",
"risk score 52",
"3 risk rank findings",
"7 changed files",
"82 lines added"
],
"next_commands": [],
"risks": [
"pr-risk: high (52/100) on d9dba291cea3e4eab519416f5e6c2127e9fd77e0..HEAD — driver: hotspot_score"
]
},
"author": null,
"blast_radius_pct": 1.8,
"bus_factor_risk": 1,
"change_shape": "mixed",
"changed_files": 7,
"closest_historical_pattern": [
"src/roam/commands/cmd_compile_stats.py",
"src/roam/commands/cmd_hooks.py",
"src/roam/plan/compiler.py",
"tests/test_compile_stats_schema.py"
],
"closest_similarity": 0.571,
"cluster_spread": 0.03,
"clusters_touched": 384,
"command": "pr-risk",
"coupling_score": 0.02,
"dead_code": [
{
"file": "src/roam/commands/cmd_hooks.py",
"kind": "function",
"name": "install"
},
{
"file": "src/roam/commands/cmd_hooks.py",
"kind": "function",
"name": "uninstall"
},
{
"file": "src/roam/commands/cmd_hooks.py",
"kind": "function",
"name": "status"
},
{
"file": "src/roam/commands/cmd_hooks.py",
"kind": "function",
"name": "claude_setup"
},
{
"file": "src/roam/plan/compiler.py",
"kind": "method",
"name": "key_for"
},
{
"file": "src/roam/plan/compiler.py",
"kind": "method",
"name": "to_envelope"
},
{
"file": "src/roam/plan/compiler.py",
"kind": "method",
"name": "to_lean_envelope"
},
{
"file": "src/roam/plan/compiler.py",
"kind": "method",
"name": "to_facts_contract_envelope"
},
{
"file": "src/roam/plan/compiler.py",
"kind": "method",
"name": "to_l1_probe_envelope"
},
{
"file": "src/roam/plan/compiler.py",
"kind": "method",
"name": "to_facts_envelope"
}
],
"dead_exports": 10,
"familiarity": {
"avg_familiarity": 1,
"files": [],
"files_assessed": 0
},
"findings": [
{
"claim": "pr-risk: high (52/100) on d9dba291cea3e4eab519416f5e6c2127e9fd77e0..HEAD — driver: hotspot_score",
"confidence": "heuristic",
"evidence": {
"actor": null,
"author": null,
"blast_radius_pct": 1.8,
"bus_factor_risk": 1,
"changed_files_count": 7,
"commit_range": "d9dba291cea3e4eab519416f5e6c2127e9fd77e0..HEAD",
"coupling_score": 0.024,
"created_at_epoch": 1784154747,
"diff_id": "ba3ec5944aff",
"familiarity_risk": 0,
"file_list": [
"src/roam/__init__.py",
"src/roam/commands/cmd_compile_stats.py",
"src/roam/commands/cmd_hooks.py",
"src/roam/plan/compiler.py",
"tests/test_compile_stats_schema.py",
"tests/test_evidence_v0.py",
"tests/test_stale_refs.py"
],
"hotspot_score": 1,
"label": "d9dba291cea3e4eab519416f5e6c2127e9fd77e0..HEAD",
"lines_added": 82,
"lines_removed": 32,
"minor_risk": 0,
"novelty_score": 0.429,
"reductive_change": false,
"risk_level": "high",
"risk_score": 52,
"staged": false,
"test_coverage_pct": 75,
"top_driver": "hotspot_score"
},
"finding_id_str": "pr-risk:composite-risk-score:ba3ec5944aff",
"kind": "pr-risk:composite-risk-score",
"severity": "high",
"source_detector": "pr-risk",
"source_version": "1.0.0",
"subject_id": null,
"subject_kind": "commit"
}
],
"hotspot_score": 1,
"label": "d9dba291cea3e4eab519416f5e6c2127e9fd77e0..HEAD",
"layer_spread": 0.42,
"layers_touched": 13,
"lines_added": 82,
"lines_removed": 32,
"minor_risk": {
"files": [],
"files_assessed": 0,
"minor_files": 0
},
"novelty_score": 0.429,
"per_file": [
{
"blast": 662,
"churn": 18204,
"is_test": false,
"lines_added": 11,
"lines_removed": 0,
"path": "src/roam/plan/compiler.py",
"symbols": 644
},
{
"blast": 137,
"churn": 476,
"is_test": false,
"lines_added": 2,
"lines_removed": 0,
"path": "src/roam/commands/cmd_compile_stats.py",
"symbols": 12
},
{
"blast": 86,
"churn": 1726,
"is_test": false,
"lines_added": 9,
"lines_removed": 0,
"path": "src/roam/commands/cmd_hooks.py",
"symbols": 39
},
{
"blast": 36,
"churn": 4120,
"is_test": true,
"lines_added": 9,
"lines_removed": 6,
"path": "tests/test_stale_refs.py",
"symbols": 274
},
{
"blast": 7,
"churn": 1678,
"is_test": true,
"lines_added": 24,
"lines_removed": 21,
"path": "tests/test_evidence_v0.py",
"symbols": 51
},
{
"blast": 1,
"churn": 114,
"is_test": true,
"lines_added": 2,
"lines_removed": 0,
"path": "tests/test_compile_stats_schema.py",
"symbols": 6
},
{
"blast": 0,
"churn": 50,
"is_test": false,
"lines_added": 25,
"lines_removed": 5,
"path": "src/roam/__init__.py",
"symbols": 1
}
],
"project": "roam-code",
"reductive_change": false,
"reductive_discount_applied": false,
"risk_level": "high",
"risk_level_canonical": "high",
"risk_rank": 3,
"risk_score": 52,
"schema": "roam-envelope-v1",
"schema_version": "1.1.0",
"suggested_reviewers": [
{
"actor": "Cranot",
"author": "Cranot",
"lines": 18007
}
],
"summary": {
"change_shape": "mixed",
"changed_files": 7,
"findings_count": 1,
"lines_added": 82,
"lines_removed": 32,
"partial_success": false,
"risk_level": "high",
"risk_level_canonical": "high",
"risk_rank": 3,
"risk_score": 52,
"score_classification": "classified",
"verdict": "High risk (52/100) — careful review needed (risk_level high) (driver: hotspot_score)"
},
"test_coverage_pct": 75,
"total_clusters": 13077,
"total_layers": 31,
"version": "13.9.0",
"warnings_out": []
}roam-code analysis | Commands: |
Roam Agent ReviewVerdict: SAFE (risk_level low) blast-radius 0/100 · ai-likelihood 22/100 · rule violations 0 · critique high-severity 0 Verdict: SAFE. All structural signals clean at the configured thresholds. Next steps
Powered by roam-code — Apache 2.0, 100% local. Customize thresholds in |
test_server_version_falls_back_when_package_version_missing used monkeypatch.delattr(roam, '__version__') to force the fallback — which no longer works now that __version__ resolves via a PEP 562 module __getattr__ (there is no real attribute to delete). Switch to monkeypatching roam.__getattr__ to raise ImportError, exercising the same 'unknown' fallback. Same fix already applied to test_evidence_v0.py in this branch; this was the second coupled test, caught by the full CI matrix (not the fast prepush tier).
Root cause of the CI-only stale-refs failure: the empty-string test used monkeypatch.setattr(roam, '__version__', '', raising=False). Under the new lazy __getattr__, getattr(roam, '__version__') SUCCEEDS (returns the resolved value), so monkeypatch saves it and RESTORES it as a *real* module attribute on teardown — leaking a real __version__ into roam.__dict__ that shadows the lazy resolver for every later test in the process. That is why test_stale_refs passed in isolation but failed in the full matrix (order-dependent). Patch roam.__getattr__ to return ''/None instead, which restores cleanly and never materializes a real attribute. Verified: leak-order repro now passes; __version__ stays out of __dict__.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two independent, low-risk improvements to the compile hot path.
cold-2 — lazy
__version__(PEP 562).roam/__init__.pyresolved the installed package version eagerly at import, so everyimport roam(and thus every CLI call, including the per-prompt compile hook) paid ~80–94ms importingimportlib.metadata. The hot path never reads__version__; a clear-and-reimport test confirms nothing on it re-pulls the module. Measured:import roam142→48ms median.E0 — session/turn join key. The compile telemetry row records the envelope's section list but nothing about the agent's downstream outcome; a consumer-side turn ledger records the outcome but not the sections — neither is joinable. Stamp
session_id/turn_seqfrom env (likeagent_mode) + forward the editor's session id from the prompt-submit hook. Additive, fail-open; schema doc + guard test in lockstep.Both neutral-by-construction. Full prepush gate green (7/7); 355 version-consumer + 84 telemetry/hook tests pass.