Private
Public Access
0
0

feat(sdm): inject structural dependency mapping tags across codebase

Adds [C: caller] tags to functions/methods and [M: mutation] / [U: usage] tags to class variables based on cross-module call analysis.
This commit is contained in:
2026-05-13 22:35:41 -04:00
parent 5bb3a9026f
commit b5e512f483
110 changed files with 1673 additions and 1008 deletions
+39 -27
View File
@@ -61,7 +61,10 @@ def resolve_paths(base_dir: Path, entry: str) -> list[Path]:
return sorted(filtered)
def group_files_by_dir(files: list[Any]) -> dict[str, list[Any]]:
"""Groups FileItem objects by their relative directory path."""
"""
Groups FileItem objects by their relative directory path.
[C: src/gui_2.py:App._render_context_files_table, tests/test_context_composition_phase3.py:test_group_files_by_dir]
"""
grouped = {}
for f in files:
path_str = f.path if hasattr(f, 'path') else str(f)
@@ -76,7 +79,10 @@ def group_files_by_dir(files: list[Any]) -> dict[str, list[Any]]:
return grouped
def compute_file_stats(abs_path: str) -> dict[str, int]:
"""Computes lines and basic AST stats for a file."""
"""
Computes lines and basic AST stats for a file.
[C: src/gui_2.py:App._stats_worker, tests/test_context_composition_phase3.py:test_compute_file_stats]
"""
stats = {"lines": 0, "ast_elements": 0}
try:
with open(abs_path, 'r', encoding='utf-8') as f:
@@ -97,8 +103,9 @@ def build_discussion_section(history: list[Any]) -> str:
"""
Builds a markdown section for discussion history.
Handles both legacy list[str] and new list[dict].
Builds a markdown section for discussion history.
Handles both legacy list[str] and new list[dict].
"""
sections = []
for i, entry in enumerate(history, start=1):
@@ -133,20 +140,21 @@ def build_file_items(base_dir: Path, files: list[str | dict[str, Any]]) -> list[
"""
Return a list of dicts describing each file, for use by ai_client when it
wants to upload individual files rather than inline everything as markdown.
Each dict has:
path : Path (resolved absolute path)
entry : str (original config entry string)
content : str (file text, or error string)
error : bool
mtime : float (last modification time, for skip-if-unchanged optimization)
tier : int | None (optional tier for context management)
auto_aggregate : bool
force_full : bool
view_mode : str (summary, full, skeleton, outline, none)
[C: src/app_controller.py:AppController._bg_task, src/orchestrator_pm.py:module, tests/test_aggregate_flags.py:test_auto_aggregate_skip, tests/test_aggregate_flags.py:test_force_full, tests/test_tiered_context.py:test_build_file_items_with_tiers]
Return a list of dicts describing each file, for use by ai_client when it
wants to upload individual files rather than inline everything as markdown.
Each dict has:
path : Path (resolved absolute path)
entry : str (original config entry string)
content : str (file text, or error string)
error : bool
mtime : float (last modification time, for skip-if-unchanged optimization)
tier : int | None (optional tier for context management)
auto_aggregate : bool
force_full : bool
view_mode : str (summary, full, skeleton, outline, none)
[C: src/app_controller.py:AppController._bg_task, src/orchestrator_pm.py:module, tests/test_aggregate_flags.py:test_auto_aggregate_skip, tests/test_aggregate_flags.py:test_force_full, tests/test_context_composition_phase6.py:test_view_mode_custom, tests/test_context_composition_phase6.py:test_view_mode_custom_empty_default_to_summary, tests/test_context_composition_phase6.py:test_view_mode_default_summary, tests/test_context_composition_phase6.py:test_view_mode_full, tests/test_context_composition_phase6.py:test_view_mode_none, tests/test_context_composition_phase6.py:test_view_mode_outline, tests/test_context_composition_phase6.py:test_view_mode_skeleton, tests/test_context_composition_phase6.py:test_view_mode_summary, tests/test_tiered_context.py:test_build_file_items_with_tiers, tests/test_tiered_context.py:test_build_files_section_with_dicts]
"""
with get_monitor().scope("build_file_items"):
items: list[dict[str, Any]] = []
@@ -245,8 +253,9 @@ def build_file_items(base_dir: Path, files: list[str | dict[str, Any]]) -> list[
def _build_files_section_from_items(file_items: list[dict[str, Any]]) -> str:
"""
Build the files markdown section from pre-read file items (avoids double I/O).
[C: tests/test_aggregate_flags.py:test_auto_aggregate_skip, tests/test_ui_summary_only_removal.py:test_aggregate_from_items_respects_auto_aggregate]
Build the files markdown section from pre-read file items (avoids double I/O).
[C: tests/test_aggregate_flags.py:test_auto_aggregate_skip, tests/test_context_composition_phase6.py:test_files_section_rendering, tests/test_tiered_context.py:test_build_files_section_with_dicts, tests/test_ui_summary_only_removal.py:test_aggregate_from_items_respects_auto_aggregate]
"""
sections = []
for item in file_items:
@@ -323,7 +332,8 @@ def build_markdown_from_items(file_items: list[dict[str, Any]], screenshot_base_
def build_markdown_no_history(file_items: list[dict[str, Any]], screenshot_base_dir: Path, screenshots: list[str], summary_only: bool = False, aggregation_strategy: str = "auto") -> str:
"""
Build markdown with only files + screenshots (no history). Used for stable caching.
Build markdown with only files + screenshots (no history). Used for stable caching.
[C: src/app_controller.py:AppController._do_generate, tests/test_history_management.py:test_aggregate_blacklist]
"""
return build_markdown_from_items(file_items, screenshot_base_dir, screenshots, history=[], summary_only=summary_only, aggregation_strategy=aggregation_strategy)
@@ -331,7 +341,8 @@ def build_markdown_no_history(file_items: list[dict[str, Any]], screenshot_base_
def build_discussion_text(history: list[str]) -> str:
"""
Build just the discussion history section text. Returns empty string if no history.
Build just the discussion history section text. Returns empty string if no history.
[C: src/app_controller.py:AppController._do_generate, tests/test_history_management.py:test_aggregate_includes_segregated_history]
"""
if not history:
@@ -342,9 +353,10 @@ def build_tier3_context(file_items: list[dict[str, Any]], screenshot_base_dir: P
"""
Tier 3 Context: Execution/Worker.
Full content for focus_files and files with tier=3, summaries/skeletons for others.
[C: tests/test_aggregate_flags.py:test_auto_aggregate_skip, tests/test_aggregate_flags.py:test_force_full, tests/test_perf_aggregate.py:test_build_tier3_context_scaling, tests/test_tiered_context.py:test_build_tier3_context_ast_skeleton, tests/test_tiered_context.py:test_build_tier3_context_exists, tests/test_tiered_context.py:test_tiered_context_by_tier_field]
Tier 3 Context: Execution/Worker.
Full content for focus_files and files with tier=3, summaries/skeletons for others.
[C: tests/test_aggregate_flags.py:test_auto_aggregate_skip, tests/test_aggregate_flags.py:test_force_full, tests/test_ast_masking_core.py:test_ast_masking_gencpp_samples, tests/test_gencpp_full_suite.py:test_gencpp_full_suite, tests/test_perf_aggregate.py:test_build_tier3_context_scaling, tests/test_tiered_context.py:test_build_tier3_context_ast_skeleton, tests/test_tiered_context.py:test_build_tier3_context_exists, tests/test_tiered_context.py:test_tiered_context_by_tier_field]
"""
with get_monitor().scope("build_tier3_context"):
focus_set = set(focus_files)
@@ -446,7 +458,7 @@ def build_markdown(base_dir: Path, files: list[str | dict[str, Any]], screenshot
def run(config: dict[str, Any], aggregation_strategy: str = "auto") -> tuple[str, Path, list[dict[str, Any]]]:
"""
[C: simulation/sim_base.py:run_sim, src/ai_client.py:_send_anthropic, src/ai_client.py:_send_deepseek, src/ai_client.py:_send_gemini, src/ai_client.py:_send_gemini_cli, src/ai_client.py:_send_minimax, src/app_controller.py:AppController._cb_start_track, src/app_controller.py:AppController._do_generate, src/app_controller.py:AppController._process_event_queue, src/app_controller.py:AppController._start_track_logic, src/external_editor.py:_find_vscode_in_registry, src/gui_2.py:App._render_snapshot_tab, src/gui_2.py:App.run, src/gui_2.py:main, src/mcp_client.py:get_git_diff, src/project_manager.py:get_git_commit, src/project_manager.py:get_git_log, src/rag_engine.py:RAGEngine._search_mcp, src/shell_runner.py:run_powershell, tests/conftest.py:kill_process_tree, tests/conftest.py:live_gui, tests/test_conductor_abort_event.py:test_conductor_abort_event_populated, tests/test_conductor_engine_v2.py:test_conductor_engine_dynamic_parsing_and_execution, tests/test_conductor_engine_v2.py:test_conductor_engine_run_executes_tickets_in_order, tests/test_extended_sims.py:test_ai_settings_sim_live, tests/test_extended_sims.py:test_context_sim_live, tests/test_extended_sims.py:test_execution_sim_live, tests/test_extended_sims.py:test_tools_sim_live, tests/test_external_editor_gui.py:get_vscode_processes, tests/test_external_editor_gui.py:test_vscode_launches_with_diff_view, tests/test_gui_custom_window.py:test_app_window_is_borderless, tests/test_headless_simulation.py:module, tests/test_headless_verification.py:test_headless_verification_error_and_qa_interceptor, tests/test_headless_verification.py:test_headless_verification_full_run, tests/test_mock_gemini_cli.py:run_mock, tests/test_orchestration_logic.py:test_conductor_engine_run, tests/test_parallel_execution.py:test_conductor_engine_pool_integration, tests/test_sim_ai_settings.py:test_ai_settings_simulation_run, tests/test_sim_context.py:test_context_simulation_run, tests/test_sim_execution.py:test_execution_simulation_run, tests/test_sim_tools.py:test_tools_simulation_run]
[C: simulation/sim_base.py:run_sim, src/ai_client.py:_send_anthropic, src/ai_client.py:_send_deepseek, src/ai_client.py:_send_gemini, src/ai_client.py:_send_gemini_cli, src/ai_client.py:_send_minimax, src/app_controller.py:AppController._cb_start_track, src/app_controller.py:AppController._do_generate, src/app_controller.py:AppController._process_event_queue, src/app_controller.py:AppController._start_track_logic, src/external_editor.py:_find_vscode_in_registry, src/gui_2.py:App._render_snapshot_tab, src/gui_2.py:App.run, src/gui_2.py:main, src/mcp_client.py:get_git_diff, src/project_manager.py:get_git_commit, src/rag_engine.py:RAGEngine._search_mcp, src/shell_runner.py:run_powershell, tests/conftest.py:kill_process_tree, tests/conftest.py:live_gui, tests/test_conductor_abort_event.py:test_conductor_abort_event_populated, tests/test_conductor_engine_v2.py:test_conductor_engine_dynamic_parsing_and_execution, tests/test_conductor_engine_v2.py:test_conductor_engine_run_executes_tickets_in_order, tests/test_extended_sims.py:test_ai_settings_sim_live, tests/test_extended_sims.py:test_context_sim_live, tests/test_extended_sims.py:test_execution_sim_live, tests/test_extended_sims.py:test_tools_sim_live, tests/test_external_editor_gui.py:get_vscode_processes, tests/test_external_editor_gui.py:test_vscode_launches_with_diff_view, tests/test_gui_custom_window.py:test_app_window_is_borderless, tests/test_headless_simulation.py:module, tests/test_headless_verification.py:test_headless_verification_error_and_qa_interceptor, tests/test_headless_verification.py:test_headless_verification_full_run, tests/test_mock_gemini_cli.py:run_mock, tests/test_orchestration_logic.py:test_conductor_engine_run, tests/test_parallel_execution.py:test_conductor_engine_pool_integration, tests/test_sim_ai_settings.py:test_ai_settings_simulation_run, tests/test_sim_context.py:test_context_simulation_run, tests/test_sim_execution.py:test_execution_simulation_run, tests/test_sim_tools.py:test_tools_simulation_run]
"""
namespace = config.get("project", {}).get("name")
if not namespace:
@@ -472,7 +484,7 @@ def run(config: dict[str, Any], aggregation_strategy: str = "auto") -> tuple[str
def main() -> None:
# Load global config to find active project
"""
[C: simulation/live_walkthrough.py:module, simulation/ping_pong.py:module, src/api_hooks.py:WebSocketServer._run_loop, src/gui_2.py:module, tests/mock_concurrent_mma.py:module, tests/mock_gemini_cli.py:module, tests/test_cli_tool_bridge.py:TestCliToolBridge.test_allow_decision, tests/test_cli_tool_bridge.py:TestCliToolBridge.test_deny_decision, tests/test_cli_tool_bridge.py:TestCliToolBridge.test_unreachable_hook_server, tests/test_cli_tool_bridge.py:module, tests/test_cli_tool_bridge_mapping.py:TestCliToolBridgeMapping.test_mapping_from_api_format, tests/test_cli_tool_bridge_mapping.py:module, tests/test_discussion_takes.py:module, tests/test_external_editor_gui.py:module, tests/test_headless_service.py:TestHeadlessStartup.test_headless_flag_triggers_run, tests/test_headless_service.py:TestHeadlessStartup.test_normal_startup_calls_app_run, tests/test_mma_skeleton.py:module, tests/test_orchestrator_pm.py:module, tests/test_orchestrator_pm_history.py:module, tests/test_post_process.py:module, tests/test_presets.py:module, tests/test_project_serialization.py:module, tests/test_run_worker_lifecycle_abort.py:module, tests/test_symbol_lookup.py:module, tests/test_system_prompt_exposure.py:module, tests/test_theme_nerv_fx.py:module]
[C: simulation/live_walkthrough.py:module, simulation/ping_pong.py:module, src/ai_server.py:module, src/api_hooks.py:WebSocketServer._run_loop, src/gui_2.py:module, tests/mock_concurrent_mma.py:module, tests/mock_gemini_cli.py:module, tests/test_cli_tool_bridge.py:TestCliToolBridge.test_allow_decision, tests/test_cli_tool_bridge.py:TestCliToolBridge.test_deny_decision, tests/test_cli_tool_bridge.py:TestCliToolBridge.test_unreachable_hook_server, tests/test_cli_tool_bridge.py:module, tests/test_cli_tool_bridge_mapping.py:TestCliToolBridgeMapping.test_mapping_from_api_format, tests/test_cli_tool_bridge_mapping.py:module, tests/test_discussion_takes.py:module, tests/test_external_editor_gui.py:module, tests/test_headless_service.py:TestHeadlessStartup.test_headless_flag_triggers_run, tests/test_headless_service.py:TestHeadlessStartup.test_normal_startup_calls_app_run, tests/test_mma_skeleton.py:module, tests/test_orchestrator_pm.py:module, tests/test_orchestrator_pm_history.py:module, tests/test_presets.py:module, tests/test_project_serialization.py:module, tests/test_run_worker_lifecycle_abort.py:module, tests/test_symbol_lookup.py:module, tests/test_system_prompt_exposure.py:module, tests/test_theme_nerv_fx.py:module]
"""
from src.paths import get_config_path
config_path = get_config_path()