roam-code 12.2.0__tar.gz → 12.3.1__tar.gz
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.
- {roam_code-12.2.0/src/roam_code.egg-info → roam_code-12.3.1}/PKG-INFO +4 -2
- {roam_code-12.2.0 → roam_code-12.3.1}/pyproject.toml +23 -2
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_critique.py +63 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_dead.py +24 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_diagnose.py +9 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_entry_points.py +7 -1
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_fan.py +41 -2
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_health.py +30 -6
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_oracle.py +64 -22
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_preflight.py +45 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_retrieve.py +100 -1
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_rules.py +14 -1
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_search.py +10 -1
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_smells.py +77 -3
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_taint.py +22 -1
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_weather.py +12 -2
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/metrics_history.py +16 -11
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/resolve.py +58 -1
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/pagerank.py +16 -6
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/kotlin_lang.py +92 -1
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/mcp_server.py +9 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/retrieve/pipeline.py +198 -6
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/retrieve/rerank.py +197 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/retrieve/seeds.py +38 -13
- {roam_code-12.2.0 → roam_code-12.3.1/src/roam_code.egg-info}/PKG-INFO +4 -2
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam_code.egg-info/SOURCES.txt +3 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam_code.egg-info/requires.txt +3 -1
- roam_code-12.3.1/tests/test_extractor_grammar_drift.py +171 -0
- roam_code-12.3.1/tests/test_fallback_contracts.py +225 -0
- roam_code-12.3.1/tests/test_retrieve_cross_repo.py +249 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_retrieve_seeds.py +12 -4
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_surface_counts.py +2 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/LICENSE +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/README.md +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/setup.cfg +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/__main__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/analysis/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/analysis/effects.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/analysis/taint.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/api.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/ask/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/ask/classifier.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/ask/recipes.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/ask/runner.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/attest/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/attest/cga.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/bridges/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/bridges/base.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/bridges/bridge_config.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/bridges/bridge_django.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/bridges/bridge_protobuf.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/bridges/bridge_rest_api.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/bridges/bridge_salesforce.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/bridges/bridge_template.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/bridges/registry.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/catalog/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/catalog/detectors.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/catalog/fixes.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/catalog/smells.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/catalog/tasks.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/cli.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/changed_files.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_adrs.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_adversarial.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_affected.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_affected_tests.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_agent_context.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_agent_export.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_agent_plan.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_ai_ratio.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_ai_readiness.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_alerts.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_annotate.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_api_changes.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_api_drift.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_ask.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_attest.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_auth_gaps.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_bisect.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_breaking.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_budget.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_bus_factor.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_capsule.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_cga.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_check_rules.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_ci_setup.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_clean.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_clones.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_closure.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_clusters.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_codeowners.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_complexity.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_config.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_congestion.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_context.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_conventions.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_coupling.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_coverage_gaps.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_cut.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_dark_matter.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_dashboard.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_debt.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_deps.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_describe.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_dev_profile.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_diff.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_doc_staleness.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_docs_coverage.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_doctor.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_drift.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_duplicates.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_effects.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_endpoints.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_eval_retrieve.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_file.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_fingerprint.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_fitness.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_flag_dead.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_fleet.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_fn_coupling.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_forecast.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_grep.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_guard.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_hooks.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_hotspots.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_impact.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_index.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_index_bundle.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_ingest_trace.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_init.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_intent.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_invariants.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_layers.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_map.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_math.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_mcp_setup.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_metrics.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_migration_safety.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_minimap.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_missing_index.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_module.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_mutate.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_n1.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_orchestrate.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_orphan_routes.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_over_fetch.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_owner.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_partition.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_path_coverage.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_patterns.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_plan.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_plan_refactor.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_pr_diff.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_pr_risk.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_relate.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_report.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_reset.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_risk.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_safe_delete.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_safe_zones.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_sbom.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_schema.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_search_semantic.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_secrets.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_semantic_diff.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_simulate.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_simulate_departure.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_sketch.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_spectral.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_split.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_suggest_refactoring.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_suggest_reviewers.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_supply_chain.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_symbol.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_syntax_check.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_test_gaps.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_test_scaffold.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_testmap.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_tour.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_trace.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_trends.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_triage.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_understand.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_uses.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_verify.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_verify_imports.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_vibe_check.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_visualize.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_vuln_map.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_vuln_reach.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_vulns.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_watch.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_why.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_ws.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/cmd_xlang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/codeowners_helpers.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/context_helpers.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/gate_presets.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/graph_helpers.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/next_steps.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/commands/suppression.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/competitor_site_data.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/config.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/coverage_reports.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/critique/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/critique/aggregator.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/critique/checks.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/db/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/db/connection.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/db/queries.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/db/schema.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/eval/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/eval/harness.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/exit_codes.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/fleet/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/fleet/adapters.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/fleet/manifest.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/git_utils.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/anomaly.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/builder.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/clone_detect.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/clusters.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/cycles.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/dark_matter.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/diff.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/fingerprint.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/layers.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/partition.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/pathfinding.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/propagation.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/simulate.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/spectral.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/graph/stats.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/index/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/index/complexity.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/index/discovery.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/index/django_post.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/index/file_roles.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/index/git_stats.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/index/gitignore.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/index/incremental.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/index/indexer.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/index/parser.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/index/relations.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/index/symbols.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/index/test_conventions.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/apex_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/aura_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/base.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/c_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/csharp_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/extractor_schema.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/foxpro_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/generic_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/go_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/hcl_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/java_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/javascript_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/php_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/python_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/query_engine.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/registry.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/ruby_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/rust_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/scala_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/sfxml_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/sql_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/swift_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/typescript_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/visualforce_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/languages/yaml_lang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/mcp_extras/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/mcp_extras/completions.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/mcp_extras/progress.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/mcp_extras/sampling.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/mcp_extras/session.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/mcp_extras/watcher.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/output/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/output/formatter.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/output/mermaid.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/output/sarif.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/output/schema_registry.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/plugins.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/refactor/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/refactor/codegen.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/refactor/transforms.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/retrieve/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/retrieve/learned_ranker.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/retrieve/semantic.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/rules/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/rules/ast_match.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/rules/builtin.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/rules/dataflow.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/rules/engine.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/runtime/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/runtime/daemon.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/runtime/graph_backend.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/runtime/hotspots.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/runtime/lock_modes.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/runtime/lockmgr.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/runtime/trace_ingest.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/search/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/search/framework_packs.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/search/index_embeddings.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/search/onnx_embeddings.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/search/tfidf.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/security/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/security/aibom_extension.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/security/taint_classifier.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/security/taint_engine.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/security/vuln_reach.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/security/vuln_store.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/surface_counts.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/templates/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/templates/ci/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/workspace/__init__.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/workspace/aggregator.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/workspace/api_scanner.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/workspace/config.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam/workspace/db.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam_code.egg-info/dependency_links.txt +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam_code.egg-info/entry_points.txt +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/src/roam_code.egg-info/top_level.txt +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_adrs.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_adversarial.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_affected.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_agent_export.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_agent_mode.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_agent_plan_context.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_ai_ratio.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_ai_readiness.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_alerts_cmd.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_annotations.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_anomaly.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_api_changes.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_api_drift.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_ask.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_attest.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_auth_gaps.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_backend_fixes_round2.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_backend_fixes_round3.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_basic.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_batch_mcp.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_bisect.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_bridge_django.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_bridges.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_bridges_extended.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_budget.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_budget_flag.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_budget_phase2.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_bus_factor.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_capsule.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_cga.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_check_rules.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_ci_gate_eval.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_ci_sarif_guard.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_ci_setup.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_clones.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_closure.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_codeowners.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_commands_architecture.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_commands_exploration.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_commands_health.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_commands_refactoring.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_commands_workflow.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_competitor_site_data.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_comprehensive.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_config.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_congestion.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_context_propagation.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_conventions_cmd.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_coverage_gaps_cmd.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_coverage_ingestion.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_critique.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_cut.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_dark_matter.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_dark_matter_helpers.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_dashboard.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_dataflow_dead.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_dead_aging.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_defer_loading.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_demo_gif_asset.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_describe.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_detail_flag_hints.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_deterministic_output.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_dev_profile.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_difficulty_scoring.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_doc_staleness.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_docker_assets.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_docs_coverage.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_docs_site_quality.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_doctor.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_drift.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_duplicates.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_effects.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_effects_propagation.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_endpoints.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_entry_points_cmd.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_eval_retrieve.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_exclude_patterns.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_exit_codes.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_file_roles.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_fingerprint.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_fixes.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_flag_dead.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_fleet.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_fn_coupling.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_forecast.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_formatters.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_foxpro.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_framework_detection.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_gate_presets.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_git_utils.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_guard.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_health_gate.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_hooks.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_hotspots.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_index.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_index_bundle.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_init_cmd.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_install_check.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_intent.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_invariants.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_json_contracts.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_json_error_envelope.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_kotlin_swift_extractors.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_language_corpus.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_languages.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_library_api.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_math.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_math_tips.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_mcp_extras.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_mcp_server.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_mcp_setup.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_mermaid.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_metrics_cmd.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_migration_safety.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_minimap.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_missing_index.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_mutate.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_n1.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_next_steps.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_onboard.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_oracle.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_orchestrate.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_orphan_routes.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_oss_bench_harness.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_over_fetch.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_pagerank_truncation.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_partition.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_path_coverage.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_patterns_cmd.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_performance.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_personalized_pagerank.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_plan.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_plugin_discovery.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_pr_comment_script.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_pr_diff.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_pr_risk_author.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_progress.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_progressive_disclosure.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_properties.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_python_extractor_v2.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_readme_surface_consistency.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_refactoring_intelligence.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_relate.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_report.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_reset_clean.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_resolve.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_retrieve.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_risk.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_ruby.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_rule_profiles.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_rules.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_rules_ast_match.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_rules_community_pack.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_rules_dataflow.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_rules_symbol_requirements.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_runtime.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_runtime_score.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_salesforce.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_sarif_flag.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_sbom.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_scala.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_schema_versioning.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_search_explain.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_secrets.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_secrets_v2.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_semantic_diff.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_semantic_onnx.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_semantic_search.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_simulate.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_simulate_departure.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_sketch.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_smells.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_smoke.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_sna_metrics.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_spectral.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_split_cmd.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_sql.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_suggest_reviewers.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_supply_chain.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_syntax_check.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_taint.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_taint_analysis.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_taint_classifier.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_test_conventions.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_test_gaps.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_test_scaffold.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_testmap.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_top_flag_consistency.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_tour_cmd.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_trends.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_trends_cohort.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_triage.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_uses_cmd.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_v12_2.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_v6_features.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_v71_features.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_v7_features.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_v82_features.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_verify.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_verify_imports.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_vibe_check.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_visualize.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_vuln.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_vulns_cmd.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_watch.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_why.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_workspace.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_ws_resolve_fixes.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_xlang.py +0 -0
- {roam_code-12.2.0 → roam_code-12.3.1}/tests/test_yaml_hcl.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: roam-code
|
|
3
|
-
Version: 12.
|
|
3
|
+
Version: 12.3.1
|
|
4
4
|
Summary: Instant codebase comprehension for AI coding agents
|
|
5
5
|
Author: CosmoHac
|
|
6
6
|
License-Expression: MIT
|
|
@@ -29,7 +29,7 @@ Description-Content-Type: text/markdown
|
|
|
29
29
|
License-File: LICENSE
|
|
30
30
|
Requires-Dist: click>=8.0
|
|
31
31
|
Requires-Dist: tree-sitter>=0.23
|
|
32
|
-
Requires-Dist: tree-sitter-language-pack
|
|
32
|
+
Requires-Dist: tree-sitter-language-pack<1.6.3,>=0.6
|
|
33
33
|
Requires-Dist: networkx>=3.0
|
|
34
34
|
Provides-Extra: mcp
|
|
35
35
|
Requires-Dist: fastmcp>=2.0; extra == "mcp"
|
|
@@ -49,6 +49,8 @@ Requires-Dist: lightgbm>=4.0; extra == "learned"
|
|
|
49
49
|
Provides-Extra: dev
|
|
50
50
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
51
51
|
Requires-Dist: pytest-xdist>=3.0; extra == "dev"
|
|
52
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
53
|
+
Requires-Dist: scipy>=1.11; extra == "dev"
|
|
52
54
|
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
53
55
|
Requires-Dist: build>=1.0; extra == "dev"
|
|
54
56
|
Requires-Dist: twine>=5.0; extra == "dev"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "roam-code"
|
|
7
|
-
version = "12.
|
|
7
|
+
version = "12.3.1"
|
|
8
8
|
description = "Instant codebase comprehension for AI coding agents"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -32,7 +32,11 @@ classifiers = [
|
|
|
32
32
|
dependencies = [
|
|
33
33
|
"click>=8.0",
|
|
34
34
|
"tree-sitter>=0.23",
|
|
35
|
-
|
|
35
|
+
# Pinned upper bound: 1.6.3's cp312 wheel ships a manylinux_2_34
|
|
36
|
+
# tarball that fails to register the ``tree_sitter_language_pack``
|
|
37
|
+
# module post-install (CI run 25217131296). 1.6.2 (cp310-abi3) works
|
|
38
|
+
# cleanly across 3.9–3.13.
|
|
39
|
+
"tree-sitter-language-pack>=0.6,<1.6.3",
|
|
36
40
|
"networkx>=3.0",
|
|
37
41
|
]
|
|
38
42
|
|
|
@@ -81,6 +85,16 @@ learned = [
|
|
|
81
85
|
dev = [
|
|
82
86
|
"pytest>=7.0",
|
|
83
87
|
"pytest-xdist>=3.0",
|
|
88
|
+
# pytest-asyncio is required by tests/test_taint_classifier.py — those
|
|
89
|
+
# tests use ``@pytest.mark.asyncio`` to verify the MCP-sampling-based
|
|
90
|
+
# taint classifier under a controlled async loop.
|
|
91
|
+
"pytest-asyncio>=0.23",
|
|
92
|
+
# scipy is required by ``nx.pagerank`` on networkx 3.x; without it,
|
|
93
|
+
# the personalized-pagerank tests exercise the degree-based fallback
|
|
94
|
+
# which doesn't honour ``alpha`` and trivially fails the
|
|
95
|
+
# alpha-override / chain-propagation invariants. Production users
|
|
96
|
+
# without scipy still get the (less accurate but correct) fallback.
|
|
97
|
+
"scipy>=1.11",
|
|
84
98
|
"ruff>=0.4",
|
|
85
99
|
"build>=1.0",
|
|
86
100
|
"twine>=5.0",
|
|
@@ -92,10 +106,17 @@ where = ["src"]
|
|
|
92
106
|
[tool.pytest.ini_options]
|
|
93
107
|
testpaths = ["tests"]
|
|
94
108
|
addopts = "-q --tb=short"
|
|
109
|
+
# v12.2: pytest-asyncio strict-mode + auto fixture loop scope. Avoids the
|
|
110
|
+
# 11 PytestUnknownMarkWarning warnings on `@pytest.mark.asyncio` in
|
|
111
|
+
# test_taint_classifier.py when pytest-asyncio is installed (it ships
|
|
112
|
+
# under the `[dev]` extra).
|
|
113
|
+
asyncio_mode = "strict"
|
|
114
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
95
115
|
markers = [
|
|
96
116
|
"smoke: fast, high-signal tests for local iteration",
|
|
97
117
|
"core: broader local suite for pre-push checks",
|
|
98
118
|
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
|
|
119
|
+
"asyncio: marks async tests requiring pytest-asyncio (skip when missing)",
|
|
99
120
|
]
|
|
100
121
|
|
|
101
122
|
[tool.ruff]
|
|
@@ -31,6 +31,57 @@ from roam.critique.checks import (
|
|
|
31
31
|
from roam.db.connection import open_db
|
|
32
32
|
from roam.output.formatter import json_envelope, to_json
|
|
33
33
|
|
|
34
|
+
# Hot-path → bench command. When a diff touches any of these path
|
|
35
|
+
# prefixes, the default critique rules can pass while the change
|
|
36
|
+
# materially alters retrieval/scoring/graph algorithms. The hint
|
|
37
|
+
# names the bench so the user includes it in their verification
|
|
38
|
+
# loop. Order matters: first match wins (most specific first).
|
|
39
|
+
_BENCH_RELEVANCE_RULES = [
|
|
40
|
+
(
|
|
41
|
+
("src/roam/retrieve/", "src/roam/eval/"),
|
|
42
|
+
"pytest tests/test_retrieve_cross_repo.py + roam eval-retrieve --tasks bench/retrieve/roam_self.jsonl",
|
|
43
|
+
),
|
|
44
|
+
(
|
|
45
|
+
("src/roam/graph/pagerank.py", "src/roam/graph/clusters.py"),
|
|
46
|
+
"pytest tests/test_personalized_pagerank.py tests/test_fallback_contracts.py",
|
|
47
|
+
),
|
|
48
|
+
(("src/roam/graph/",), "pytest tests/ -k graph_ -m 'not slow'"),
|
|
49
|
+
(
|
|
50
|
+
("src/roam/languages/", "src/roam/index/parser.py"),
|
|
51
|
+
"pytest tests/test_languages.py tests/test_extractor_grammar_drift.py",
|
|
52
|
+
),
|
|
53
|
+
(("src/roam/security/taint",), "pytest tests/test_taint_analysis.py tests/test_taint_classifier.py"),
|
|
54
|
+
(("src/roam/critique/",), "pytest tests/test_critique.py"),
|
|
55
|
+
(
|
|
56
|
+
("src/roam/commands/cmd_oracle.py", "src/roam/commands/cmd_health.py"),
|
|
57
|
+
"pytest tests/test_oracle.py tests/test_commands_health.py",
|
|
58
|
+
),
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _bench_relevance_hint(regions) -> str:
|
|
63
|
+
"""Return a one-line bench/test suggestion when the diff touches a
|
|
64
|
+
structurally-significant path. ``regions`` is the
|
|
65
|
+
``critique.checks.ChangedRegion`` list from the diff parser; we
|
|
66
|
+
look at each region's file path and pick the first matching rule.
|
|
67
|
+
"""
|
|
68
|
+
paths = []
|
|
69
|
+
for r in regions:
|
|
70
|
+
path = getattr(r, "file_path", None) or getattr(r, "file", None) or ""
|
|
71
|
+
if path:
|
|
72
|
+
paths.append(path.replace("\\", "/"))
|
|
73
|
+
if not paths:
|
|
74
|
+
return ""
|
|
75
|
+
seen: set[str] = set()
|
|
76
|
+
for path in paths:
|
|
77
|
+
for prefixes, hint in _BENCH_RELEVANCE_RULES:
|
|
78
|
+
if any(path.startswith(p) or p in path for p in prefixes):
|
|
79
|
+
if hint in seen:
|
|
80
|
+
return hint
|
|
81
|
+
seen.add(hint)
|
|
82
|
+
return hint
|
|
83
|
+
return ""
|
|
84
|
+
|
|
34
85
|
|
|
35
86
|
@click.command()
|
|
36
87
|
@click.option(
|
|
@@ -163,5 +214,17 @@ def critique(ctx, input_path, high_callers, intent_text):
|
|
|
163
214
|
click.echo(f" {line}")
|
|
164
215
|
click.echo()
|
|
165
216
|
|
|
217
|
+
# Bench-relevance hint (dogfood notes 2026-05-01): when the diff
|
|
218
|
+
# touches files in the retrieve / graph / catalog hot path, the
|
|
219
|
+
# default rule set ("clones not edited", "blast radius") can
|
|
220
|
+
# legitimately say "no concerns" while the change quietly
|
|
221
|
+
# alters the structural-rerank scoring formula. Surfacing the
|
|
222
|
+
# bench command makes the verifier conversation include the
|
|
223
|
+
# one validation that actually exercises the modified code.
|
|
224
|
+
bench_hint = _bench_relevance_hint(regions)
|
|
225
|
+
if bench_hint:
|
|
226
|
+
click.echo()
|
|
227
|
+
click.echo(f"BENCH HINT: {bench_hint}")
|
|
228
|
+
|
|
166
229
|
if result["severity_breakdown"].get("high", 0) > 0:
|
|
167
230
|
ctx.exit(5)
|
|
@@ -358,6 +358,19 @@ def _group_dead(dead_items, by):
|
|
|
358
358
|
# ---------------------------------------------------------------------------
|
|
359
359
|
|
|
360
360
|
|
|
361
|
+
_TOOLING_PATH_HINTS = ("/dev/", "/benchmarks/", "/.github/", "\\dev\\", "\\benchmarks\\", "\\.github\\")
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def _is_tooling_path(path: str) -> bool:
|
|
365
|
+
"""Same hint set as cmd_fan / cmd_smells. Excluded from dead-code
|
|
366
|
+
headline by default (dogfood notes 2026-05-01) — CI scripts are
|
|
367
|
+
expected to have unreferenced helper functions."""
|
|
368
|
+
if not path:
|
|
369
|
+
return False
|
|
370
|
+
p = "/" + path.replace("\\", "/")
|
|
371
|
+
return any(hint.replace("\\", "/") in p for hint in _TOOLING_PATH_HINTS)
|
|
372
|
+
|
|
373
|
+
|
|
361
374
|
def _analyze_dead(conn):
|
|
362
375
|
"""Run the full dead code analysis.
|
|
363
376
|
|
|
@@ -366,6 +379,9 @@ def _analyze_dead(conn):
|
|
|
366
379
|
rows = conn.execute(UNREFERENCED_EXPORTS).fetchall()
|
|
367
380
|
# Exclude test files — their symbols are discovered by pytest, not imported
|
|
368
381
|
rows = [r for r in rows if not _is_test_path(r["file_path"])]
|
|
382
|
+
# Exclude tooling/CI/benchmarks/dev — same default-exclusion that
|
|
383
|
+
# ``cmd_smells`` and ``cmd_fan`` apply.
|
|
384
|
+
rows = [r for r in rows if not _is_tooling_path(r["file_path"])]
|
|
369
385
|
if not rows:
|
|
370
386
|
return [], [], set()
|
|
371
387
|
|
|
@@ -1098,6 +1114,7 @@ def dead(
|
|
|
1098
1114
|
return
|
|
1099
1115
|
if json_mode:
|
|
1100
1116
|
summary = {
|
|
1117
|
+
"verdict": "no dead exports",
|
|
1101
1118
|
"safe": 0,
|
|
1102
1119
|
"review": 0,
|
|
1103
1120
|
"intentional": 0,
|
|
@@ -1265,7 +1282,14 @@ def dead(
|
|
|
1265
1282
|
d["decay_score"] = ext["decay_score"]
|
|
1266
1283
|
return d
|
|
1267
1284
|
|
|
1285
|
+
total = n_safe + n_review + n_intent
|
|
1286
|
+
verdict = (
|
|
1287
|
+
f"{total} dead export(s): {n_safe} safe, {n_review} review, {n_intent} intentional"
|
|
1288
|
+
if total
|
|
1289
|
+
else "no dead exports"
|
|
1290
|
+
)
|
|
1268
1291
|
summary = {
|
|
1292
|
+
"verdict": verdict,
|
|
1269
1293
|
"safe": n_safe,
|
|
1270
1294
|
"review": n_review,
|
|
1271
1295
|
"intentional": n_intent,
|
|
@@ -315,6 +315,15 @@ def diagnose(ctx, name, depth):
|
|
|
315
315
|
|
|
316
316
|
# Text output
|
|
317
317
|
click.echo(f"VERDICT: {verdict}")
|
|
318
|
+
# Index-staleness hint (dogfood notes 2026-05-01): when index
|
|
319
|
+
# is older than HEAD, commit_count / churn columns are
|
|
320
|
+
# unreliable — surface this so the user knows whether to trust
|
|
321
|
+
# the numbers or re-index.
|
|
322
|
+
from roam.commands.resolve import index_staleness_hint as _stale_hint
|
|
323
|
+
|
|
324
|
+
_stale = _stale_hint()
|
|
325
|
+
if _stale:
|
|
326
|
+
click.echo(f"NOTE: {_stale}")
|
|
318
327
|
sym_name = sym["qualified_name"] or sym["name"]
|
|
319
328
|
click.echo(f"Diagnose: {sym_name}")
|
|
320
329
|
click.echo(f" {loc(target_metrics['file_path'], sym['line_start'])}")
|
|
@@ -103,7 +103,13 @@ _NAME_PATTERNS = [
|
|
|
103
103
|
("Scheduled", re.compile(r"cron|schedule|periodic|tick", re.IGNORECASE)),
|
|
104
104
|
("Message", re.compile(r"consume|subscriber|on_message|process_message", re.IGNORECASE)),
|
|
105
105
|
("CLI", re.compile(r"^cmd_|_command$|_cmd$", re.IGNORECASE)),
|
|
106
|
-
|
|
106
|
+
# HTTP name patterns: only the strong endpoint/controller suffixes.
|
|
107
|
+
# ``_view$`` and ``_handler$`` matched too broadly — dogfood notes
|
|
108
|
+
# 2026-05-01 caught ``_extract_create_view`` (a SQL parser method)
|
|
109
|
+
# and ``error_handler`` (signal handler) being classified as HTTP
|
|
110
|
+
# routes. The decorator pattern above already catches genuine
|
|
111
|
+
# ``@app.route`` etc. — name fallback can be conservative.
|
|
112
|
+
("HTTP", re.compile(r"_endpoint$|_controller$", re.IGNORECASE)),
|
|
107
113
|
]
|
|
108
114
|
|
|
109
115
|
|
|
@@ -107,12 +107,43 @@ _FRAMEWORK_NAMES = frozenset(
|
|
|
107
107
|
)
|
|
108
108
|
|
|
109
109
|
|
|
110
|
+
_TOOLING_PATH_HINTS = ("/dev/", "/benchmarks/", "/.github/", "\\dev\\", "\\benchmarks\\", "\\.github\\")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _is_tooling_path(path: str) -> bool:
|
|
114
|
+
"""Return True for paths that belong to tooling/CI/benchmarks/dev.
|
|
115
|
+
|
|
116
|
+
Default-excluded from headline metrics so first-time users aren't
|
|
117
|
+
dominated by ``pr-comment.js`` and ``roam-bench.py`` rows.
|
|
118
|
+
Matches the hint set used by ``cmd_smells._file_role_lookup``.
|
|
119
|
+
"""
|
|
120
|
+
if not path:
|
|
121
|
+
return False
|
|
122
|
+
p = "/" + path.replace("\\", "/")
|
|
123
|
+
return any(hint.replace("\\", "/") in p for hint in _TOOLING_PATH_HINTS)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _filter_tooling_rows(rows):
|
|
127
|
+
"""Filter out rows whose ``file_path`` is in a tooling location."""
|
|
128
|
+
return [r for r in rows if not _is_tooling_path(r["file_path"] or "")]
|
|
129
|
+
|
|
130
|
+
|
|
110
131
|
@click.command()
|
|
111
132
|
@click.argument("mode", default="symbol", type=click.Choice(["symbol", "file"]))
|
|
112
133
|
@click.option("-n", "count", default=20, help="Number of items to show")
|
|
113
134
|
@click.option("--no-framework", is_flag=True, help="Filter out framework/boilerplate symbols")
|
|
135
|
+
@click.option(
|
|
136
|
+
"--include-tooling",
|
|
137
|
+
is_flag=True,
|
|
138
|
+
default=False,
|
|
139
|
+
help=(
|
|
140
|
+
"Include CI scripts, dev tooling, build, and generated files. "
|
|
141
|
+
"Excluded by default — high fan-in in dev/.github/benchmarks "
|
|
142
|
+
"is expected and dominates the headline (dogfood notes 2026-05-01)."
|
|
143
|
+
),
|
|
144
|
+
)
|
|
114
145
|
@click.pass_context
|
|
115
|
-
def fan(ctx, mode, count, no_framework):
|
|
146
|
+
def fan(ctx, mode, count, no_framework, include_tooling):
|
|
116
147
|
"""Show fan-in/fan-out: most connected symbols or files.
|
|
117
148
|
|
|
118
149
|
Unlike ``coupling`` (which measures temporal co-change frequency), this
|
|
@@ -124,6 +155,10 @@ def fan(ctx, mode, count, no_framework):
|
|
|
124
155
|
ensure_index()
|
|
125
156
|
|
|
126
157
|
with open_db(readonly=True) as conn:
|
|
158
|
+
# Pull more rows than ``count`` when filtering, so the displayed
|
|
159
|
+
# top-N still has ``count`` entries after exclusions. 5x is a
|
|
160
|
+
# comfortable safety factor for typical tooling shares.
|
|
161
|
+
fetch_limit = count * 5 if not include_tooling else count
|
|
127
162
|
if mode == "symbol":
|
|
128
163
|
rows = conn.execute(
|
|
129
164
|
"""
|
|
@@ -138,9 +173,13 @@ def fan(ctx, mode, count, no_framework):
|
|
|
138
173
|
ORDER BY total DESC
|
|
139
174
|
LIMIT ?
|
|
140
175
|
""",
|
|
141
|
-
(
|
|
176
|
+
(fetch_limit,),
|
|
142
177
|
).fetchall()
|
|
143
178
|
|
|
179
|
+
if not include_tooling:
|
|
180
|
+
rows = _filter_tooling_rows(rows)
|
|
181
|
+
rows = rows[:count]
|
|
182
|
+
|
|
144
183
|
if no_framework:
|
|
145
184
|
rows = [r for r in rows if r["name"] not in _FRAMEWORK_NAMES]
|
|
146
185
|
|
|
@@ -473,18 +473,34 @@ def health(ctx, no_framework, gate):
|
|
|
473
473
|
"""Sigmoid health factor: 1 for no issues, → 0 for many."""
|
|
474
474
|
return math.exp(-value / scale) if scale > 0 else 1.0
|
|
475
475
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
476
|
+
# Score signals — count *actionable* items only. Utilities
|
|
477
|
+
# (string/path/datetime helpers) are expected to have high fan-in
|
|
478
|
+
# and would dominate the formula otherwise. Per dogfood notes
|
|
479
|
+
# 2026-05-01: this repo had 50 god components total but 27 were
|
|
480
|
+
# expected utilities; the old formula penalised the score for
|
|
481
|
+
# all 50 and produced a misleading 2/100 verdict. The display
|
|
482
|
+
# already classifies them ("23 actionable, 27 expected utilities");
|
|
483
|
+
# the score should match the display.
|
|
484
|
+
god_actionable = [g for g in god_items if g.get("category") == "actionable"]
|
|
485
|
+
god_critical = sum(1 for g in god_actionable if g.get("severity") == "CRITICAL")
|
|
486
|
+
# Normalise by codebase size so a 14k-symbol repo with 23 actionable
|
|
487
|
+
# god components (0.16%) doesn't score the same as a 100-symbol
|
|
488
|
+
# repo with 23 (23%). 1k symbols is the unit; signal scales linearly.
|
|
489
|
+
size_norm = max(1.0, total_symbols / 1000.0)
|
|
490
|
+
god_signal = (god_critical * 3 + len(god_actionable) * 0.5) / size_norm
|
|
491
|
+
bn_actionable_items = [b for b in bn_items if b.get("category") == "actionable"]
|
|
492
|
+
bn_critical = sum(1 for b in bn_actionable_items if b.get("severity") == "CRITICAL")
|
|
493
|
+
bn_signal = (bn_critical * 2 + len(bn_actionable_items) * 0.3) / size_norm
|
|
480
494
|
|
|
481
495
|
coverage_import = imported_coverage_overview(conn)
|
|
482
496
|
|
|
483
497
|
# Base factors (weights sum to 1.0 before optional imported coverage).
|
|
498
|
+
# Scales tuned post-normalisation so a normal repo (low percent of
|
|
499
|
+
# actionable god components) scores in the 60-90 range.
|
|
484
500
|
base_factors = [
|
|
485
501
|
(_health_factor(tangle_ratio, 10), 0.30), # tangle ratio
|
|
486
|
-
(_health_factor(god_signal, 5), 0.20), # god components
|
|
487
|
-
(_health_factor(bn_signal,
|
|
502
|
+
(_health_factor(god_signal, 1.5), 0.20), # god components (normalised /1k symbols)
|
|
503
|
+
(_health_factor(bn_signal, 1.0), 0.15), # bottlenecks (normalised /1k symbols)
|
|
488
504
|
(_health_factor(len(violations), 5), 0.15), # layer violations
|
|
489
505
|
]
|
|
490
506
|
# File-level health: map avg [0-10] to a factor
|
|
@@ -756,6 +772,14 @@ def health(ctx, no_framework, gate):
|
|
|
756
772
|
|
|
757
773
|
# --- Text output ---
|
|
758
774
|
click.echo(f"VERDICT: {verdict}\n")
|
|
775
|
+
# Index-staleness hint — only when relevant. Surfaces here
|
|
776
|
+
# because git_file_changes feed health's tangle/coupling/churn
|
|
777
|
+
# signals; an out-of-date index quietly degrades all of them.
|
|
778
|
+
from roam.commands.resolve import index_staleness_hint as _stale_hint
|
|
779
|
+
|
|
780
|
+
_stale = _stale_hint()
|
|
781
|
+
if _stale:
|
|
782
|
+
click.echo(f"NOTE: {_stale}\n")
|
|
759
783
|
issue_count = len(cycles) + len(god_items) + len(bn_items) + len(violations)
|
|
760
784
|
parts = []
|
|
761
785
|
if cycles:
|
|
@@ -87,33 +87,57 @@ def oracle_route_exists(conn: sqlite3.Connection, path: str) -> tuple[bool, str]
|
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
def oracle_is_test_only(conn: sqlite3.Connection, name: str) -> tuple[bool, str]:
|
|
90
|
-
"""
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
"""Is this symbol used only by test code?
|
|
91
|
+
|
|
92
|
+
Resolution order (matches dogfood expectations 2026-05-01):
|
|
93
|
+
|
|
94
|
+
1. **Symbol lives in a test file** → ``True``. The previous heuristic
|
|
95
|
+
was "all callers in test files", but a test method like
|
|
96
|
+
``test_check_count`` has zero callers (pytest invokes it by
|
|
97
|
+
reflection), and the heuristic returned ``False`` for the most
|
|
98
|
+
canonically test-only thing in the codebase. We now check the
|
|
99
|
+
symbol's *own* ``file_role`` first — anything in
|
|
100
|
+
``file_role='test'`` is test-only by definition.
|
|
101
|
+
2. **Symbol is in a non-test file with all callers in test files**
|
|
102
|
+
→ ``True``. Catches helpers that live in production but are
|
|
103
|
+
only ever called from tests (genuinely test-only).
|
|
104
|
+
3. **Symbol has no callers and is in a non-test file** → ``False``
|
|
105
|
+
with a clearer "orphan" reason than before.
|
|
95
106
|
"""
|
|
96
107
|
if not name:
|
|
97
108
|
return False, "empty query"
|
|
98
109
|
target_rows = conn.execute(
|
|
99
|
-
"
|
|
110
|
+
"""
|
|
111
|
+
SELECT s.id, COALESCE(f.file_role, 'unknown') AS role
|
|
112
|
+
FROM symbols s
|
|
113
|
+
JOIN files f ON f.id = s.file_id
|
|
114
|
+
WHERE s.name = ? OR s.qualified_name = ?
|
|
115
|
+
""",
|
|
100
116
|
(name, name),
|
|
101
117
|
).fetchall()
|
|
102
118
|
if not target_rows:
|
|
103
119
|
return False, f"no symbol named '{name}'"
|
|
104
|
-
target_ids = [int(r[0]) for r in target_rows]
|
|
105
120
|
|
|
121
|
+
# 1) Symbol's own file_role is 'test' → trivially test-only.
|
|
122
|
+
own_test = [r for r in target_rows if r[1] == "test"]
|
|
123
|
+
if own_test and len(own_test) == len(target_rows):
|
|
124
|
+
return True, "symbol lives in a test file (file_role='test')"
|
|
125
|
+
# Mixed (e.g. same name in test + source) — fall through to caller
|
|
126
|
+
# analysis so the answer reflects actual usage.
|
|
127
|
+
|
|
128
|
+
target_ids = [int(r[0]) for r in target_rows]
|
|
106
129
|
placeholders = ",".join("?" * len(target_ids))
|
|
107
130
|
caller_rows = conn.execute(
|
|
108
131
|
f"SELECT s.id, COALESCE(f.file_role, 'unknown') AS role "
|
|
109
132
|
f"FROM edges e "
|
|
110
133
|
f"JOIN symbols s ON s.id = e.source_id "
|
|
111
134
|
f"JOIN files f ON f.id = s.file_id "
|
|
112
|
-
f"WHERE e.target_id IN ({placeholders}) AND e.kind IN ('calls', 'references')",
|
|
135
|
+
f"WHERE e.target_id IN ({placeholders}) AND e.kind IN ('call', 'reference', 'calls', 'references')",
|
|
113
136
|
target_ids,
|
|
114
137
|
).fetchall()
|
|
115
138
|
if not caller_rows:
|
|
116
|
-
|
|
139
|
+
# 3) No callers AND no callees lives in a test file ⇒ orphan in source.
|
|
140
|
+
return False, f"no callers found for '{name}' (orphan in source)"
|
|
117
141
|
test_count = sum(1 for r in caller_rows if r[1] == "test")
|
|
118
142
|
total = len(caller_rows)
|
|
119
143
|
if test_count == total:
|
|
@@ -143,24 +167,42 @@ def oracle_is_reachable_from_entry(conn: sqlite3.Connection, name: str, *, max_h
|
|
|
143
167
|
return False, f"no symbol named '{name}'"
|
|
144
168
|
target_ids = {int(r[0]) for r in target_rows}
|
|
145
169
|
|
|
146
|
-
#
|
|
147
|
-
#
|
|
170
|
+
# Entry-point definition (dogfood notes 2026-05-01, two iterations):
|
|
171
|
+
#
|
|
172
|
+
# First attempt — files with no incoming ``file_edges``. Caught the
|
|
173
|
+
# previous bug (``no entry-point symbols indexed`` on every query)
|
|
174
|
+
# but mis-classified ``cli`` itself: ``src/roam/cli.py`` IS imported
|
|
175
|
+
# by tests + internal helpers so it had incoming edges and wasn't
|
|
176
|
+
# an entry point. The user expects ``is-reachable cli`` to be True.
|
|
177
|
+
#
|
|
178
|
+
# Second attempt — same import-graph definition PLUS name-based
|
|
179
|
+
# fallback for canonical entry symbols (``cli``, ``main``,
|
|
180
|
+
# ``__main__``, ``run``, ``app``, ``serve``). Anything with one of
|
|
181
|
+
# these names IS treated as an entry point regardless of whether
|
|
182
|
+
# someone imported its file. Catches the "main is the entry point
|
|
183
|
+
# but tests import it" case without false-positives elsewhere.
|
|
148
184
|
try:
|
|
149
|
-
entry_rows = conn.execute(
|
|
185
|
+
entry_rows = conn.execute(
|
|
186
|
+
"""
|
|
187
|
+
SELECT s.id FROM symbols s
|
|
188
|
+
JOIN files f ON f.id = s.file_id
|
|
189
|
+
WHERE f.id NOT IN (SELECT DISTINCT target_file_id FROM file_edges)
|
|
190
|
+
"""
|
|
191
|
+
).fetchall()
|
|
150
192
|
entry_ids = {int(r[0]) for r in entry_rows}
|
|
151
193
|
except sqlite3.OperationalError:
|
|
152
194
|
entry_ids = set()
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
195
|
+
|
|
196
|
+
try:
|
|
197
|
+
named_entry_rows = conn.execute(
|
|
198
|
+
"SELECT id FROM symbols WHERE name IN ('cli', 'main', '__main__', 'run', 'app', 'serve', 'entrypoint')"
|
|
199
|
+
).fetchall()
|
|
200
|
+
entry_ids.update(int(r[0]) for r in named_entry_rows)
|
|
201
|
+
except sqlite3.OperationalError:
|
|
202
|
+
pass
|
|
161
203
|
|
|
162
204
|
if not entry_ids:
|
|
163
|
-
return False, "no entry-point symbols indexed (run `roam
|
|
205
|
+
return False, "no entry-point symbols indexed (run `roam init` to (re)build the index)"
|
|
164
206
|
|
|
165
207
|
if entry_ids & target_ids:
|
|
166
208
|
return True, "target is itself an entry point"
|
|
@@ -176,7 +218,7 @@ def oracle_is_reachable_from_entry(conn: sqlite3.Connection, name: str, *, max_h
|
|
|
176
218
|
rows = conn.execute(
|
|
177
219
|
f"SELECT target_id FROM edges "
|
|
178
220
|
f"WHERE source_id IN ({placeholders}) "
|
|
179
|
-
f" AND kind IN ('calls', 'references')",
|
|
221
|
+
f" AND kind IN ('call', 'reference', 'calls', 'references')",
|
|
180
222
|
chunk,
|
|
181
223
|
).fetchall()
|
|
182
224
|
for r in rows:
|
|
@@ -106,6 +106,42 @@ def _overall_risk(*severities: str) -> str:
|
|
|
106
106
|
return "LOW"
|
|
107
107
|
|
|
108
108
|
|
|
109
|
+
def _risk_driver(blast, tests, compl, coupl, convs, fitns) -> str:
|
|
110
|
+
"""Identify the row driving the overall risk verdict.
|
|
111
|
+
|
|
112
|
+
Returns a one-line summary like ``complexity (cc=17, HIGH)`` so
|
|
113
|
+
an agent reading the preflight output knows *why* the overall
|
|
114
|
+
verdict is what it is — it doesn't have to scan all six rows
|
|
115
|
+
looking for the worst severity.
|
|
116
|
+
|
|
117
|
+
Tie-break by actionability: complexity > fitness > tests > coupling
|
|
118
|
+
> blast > conventions. A complexity warning is more actionable than
|
|
119
|
+
a convention warning even at equal severity.
|
|
120
|
+
"""
|
|
121
|
+
rows = [
|
|
122
|
+
("complexity", compl, f"cc={compl['max_cognitive_complexity']:.0f}"),
|
|
123
|
+
("fitness", fitns, f"{fitns.get('rules_failed', 0)} rules would fail"),
|
|
124
|
+
("tests", tests, f"{tests.get('direct', 0)} direct, {tests.get('transitive', 0)} transitive"),
|
|
125
|
+
("coupling", coupl, f"{coupl.get('coupled_files', 0)} coupled files"),
|
|
126
|
+
(
|
|
127
|
+
"blast radius",
|
|
128
|
+
blast,
|
|
129
|
+
f"{blast.get('affected_symbols', 0)} symbols in {blast.get('affected_files', 0)} files",
|
|
130
|
+
),
|
|
131
|
+
("conventions", convs, f"{convs.get('violation_count', 0)} violations"),
|
|
132
|
+
]
|
|
133
|
+
# Find max severity
|
|
134
|
+
worst: tuple[int, str, str] | None = None
|
|
135
|
+
for label, row, detail in rows:
|
|
136
|
+
sev = row.get("severity", "OK").upper()
|
|
137
|
+
order = _SEVERITY_ORDER.get(sev, 0)
|
|
138
|
+
if order <= 1: # OK / LOW — not driving the verdict
|
|
139
|
+
continue
|
|
140
|
+
if worst is None or order > worst[0]:
|
|
141
|
+
worst = (order, label, f"{label} ({detail}, {sev})")
|
|
142
|
+
return worst[2] if worst else ""
|
|
143
|
+
|
|
144
|
+
|
|
109
145
|
def _severity_tag(sev: str) -> str:
|
|
110
146
|
return f"[{sev}]"
|
|
111
147
|
|
|
@@ -708,6 +744,15 @@ def preflight(ctx, target, staged):
|
|
|
708
744
|
# Overall
|
|
709
745
|
click.echo(f"\n Overall risk: {risk}")
|
|
710
746
|
|
|
747
|
+
# Risk driver — name the row that's pushing the verdict so an
|
|
748
|
+
# agent doesn't have to deduce it (dogfood notes 2026-05-01).
|
|
749
|
+
# Pick the highest-severity row, breaking ties by category
|
|
750
|
+
# priority (complexity > fitness > tests > coupling > blast >
|
|
751
|
+
# conventions — most actionable first).
|
|
752
|
+
driver = _risk_driver(blast, tests, compl, coupl, convs, fitns)
|
|
753
|
+
if driver:
|
|
754
|
+
click.echo(f" Risk driver: {driver}")
|
|
755
|
+
|
|
711
756
|
# Suggested tests
|
|
712
757
|
if tests["pytest_command"]:
|
|
713
758
|
click.echo(f" Suggested tests: {tests['pytest_command']}")
|