gabriel / musehub public
feat patch proposals task/proposal-models-v2 #15 / 19
AI Agent gabriel · 131 days ago · May 8, 2026 · Diff

feat(proposals): phase 4 — simulation engine

Three simulation types cached in musehub_proposal_simulations:

conflict_scan — dry-runs the merge strategy and returns per-domain conflict breakdown (conflict_count, conflicting_files, conflicts_by_domain, files_added/modified/removed)

risk_projection — projects post-merge dimensional risk using a weighted blend of change_ratio (40%) + conflict_ratio (40%) + existing dimensional_risk (20%); returns risk_band and risk_delta

dependency_order — topological sort of the live dependency DAG; groups nodes into parallel execution phases; surfaces cycles

New symbols: genesis.py: compute_simulation_id(proposal_id, simulation_type, from_branch_commit_id) models/musehub.py: SimulationType enum, SimulationResponse, SimulationListResponse proposal_simulation.py: pure engine — simulate_conflict_scan, simulate_risk_projection, simulate_dependency_order (no DB I/O) musehub_proposals.py: run_simulation, get_simulation, list_simulations service functions; upsert semantics on re-run; is_stale=True when from_branch advances proposals.py routes: POST/GET /simulations/{type}, GET /simulations (list)

38 tests all passing.

sha256:18d2953fc912010676a67b6797f26ef794a268a0479a9ab0c9d5fdfa8769f02d sha
+94 ~32 symbols
sha256:ad452948b675b580c813acf914c591b9ab2b84c01dfc5c253fed044ce7e4c2fb snapshot
+94
symbols added
~32
symbols modified
0
dead code introduced
Semantic Changes 126 symbols
+ StrDict variable variable StrDict L24–24
+ CycleError import import CycleError L21–21
+ ProposalDag import import ProposalDag L21–21
+ annotations import import annotations L19–19
+ classify_domain class import classify_domain L22–22
+ execute_merge_strategy import import execute_merge_strategy L22–22
+ topological_sort import import topological_sort L21–21
+ simulate_conflict_scan function function simulate_conflict_scan L32–74
+ simulate_dependency_order function function simulate_dependency_order L180–229
+ simulate_risk_projection function function simulate_risk_projection L82–172
+ TestComputeSimulationId class class TestComputeSimulationId L318–340
+ test_deterministic method method test_deterministic L319–323
+ test_different_commit_different_id method method test_different_commit_different_id L331–335
+ test_different_type_different_id method method test_different_type_different_id L325–329
+ test_sha256_prefixed method method test_sha256_prefixed L337–340
+ TestConflictScan class class TestConflictScan L118–173
+ test_conflicts_by_domain_groups_paths method method test_conflicts_by_domain_groups_paths L141–150
+ test_conflicts_surfaced_with_ancestor method method test_conflicts_surfaced_with_ancestor L126–132
+ test_domains_affected_lists_changed_domains method method test_domains_affected_lists_changed_domains L162–166
+ test_empty_manifests_zero_conflicts method method test_empty_manifests_zero_conflicts L168–173
+ test_files_added_count method method test_files_added_count L152–156
+ test_no_conflict_when_only_one_side_changed method method test_no_conflict_when_only_one_side_changed L134–139
+ test_no_conflicts_when_disjoint_files method method test_no_conflicts_when_disjoint_files L119–124
+ test_strategy_used_reflected method method test_strategy_used_reflected L158–160
+ TestDependencyOrder class class TestDependencyOrder L248–310
+ test_cycle_detected method method test_cycle_detected L277–284
+ test_empty_dag_returns_empty method method test_empty_dag_returns_empty L299–310
+ test_linear_chain_correct_order method method test_linear_chain_correct_order L256–262
+ test_merged_deps_excluded_from_blocking method method test_merged_deps_excluded_from_blocking L286–292
+ test_node_with_dep_in_phase_2 method method test_node_with_dep_in_phase_2 L270–275
+ test_phase_count_equals_len_phases method method test_phase_count_equals_len_phases L294–297
+ test_single_node_no_deps method method test_single_node_no_deps L249–254
+ test_two_independent_nodes_in_phase_1 method method test_two_independent_nodes_in_phase_1 L264–268
+ TestGetSimulation class class TestGetSimulation L527–603
+ test_is_stale_when_branch_advances method async_method test_is_stale_when_branch_advances L557–603
+ test_returns_cached_after_run method async_method test_returns_cached_after_run L541–554
+ test_returns_none_before_run method async_method test_returns_none_before_run L529–538
+ TestListSimulations class class TestListSimulations L606–635
+ test_all_three_types_listed method async_method test_all_three_types_listed L621–635
+ test_empty_before_any_run method async_method test_empty_before_any_run L608–618
+ TestRiskProjection class class TestRiskProjection L181–240
+ test_conflict_count_matches_merge_result method method test_conflict_count_matches_merge_result L235–240
+ test_domains_affected_populated method method test_domains_affected_populated L222–227
+ test_existing_risk_factored_in method method test_existing_risk_factored_in L205–213
+ test_files_changed_count method method test_files_changed_count L229–233
+ test_risk_band_increases_with_conflicts method method test_risk_band_increases_with_conflicts L196–203
+ test_risk_band_low_for_small_change method method test_risk_band_low_for_small_change L189–194
+ test_risk_delta_positive_when_risk_increases method method test_risk_delta_positive_when_risk_increases L215–220
+ test_zero_risk_when_nothing_changes method method test_zero_risk_when_nothing_changes L182–187
+ TestRunSimulation class class TestRunSimulation L435–524
+ test_conflict_scan_runs method async_method test_conflict_scan_runs L437–455
+ test_dependency_order_runs method async_method test_dependency_order_runs L475–488
+ test_rerun_upserts_row method async_method test_rerun_upserts_row L491–512
+ test_risk_projection_runs method async_method test_risk_projection_runs L458–472
+ test_unknown_type_raises method async_method test_unknown_type_raises L515–524
+ _dag function function _dag L86–110
+ _make_branch_with_commit function async_function _make_branch_with_commit L372–412
+ _make_proposal function async_function _make_proposal L415–432
+ _make_repo function async_function _make_repo L348–369
+ _now function function _now L74–75
+ _oid function function _oid L82–83
+ _uid function function _uid L78–79
+ Any import import Any L55–55
+ AsyncSession import import AsyncSession L59–59
+ ProposalDag import import ProposalDag L66–66
+ annotations import import annotations L51–51
+ blob_id import import blob_id L58–58
+ datetime import import datetime L54–54
+ fake_id import import fake_id L58–58
+ os import import os L53–53
+ pytest import import pytest L57–57
+ short_id import import short_id L58–58
+ simulate_conflict_scan import import simulate_conflict_scan L61–61
+ simulate_dependency_order import import simulate_dependency_order L61–61
+ simulate_risk_projection import import simulate_risk_projection L61–61
+ timezone import import timezone L54–54
~ musehub/api/routes/musehub/proposals.py .py 5 symbols added, 17 symbols modified
+ get_proposal_simulation function async_function get_proposal_simulation L888–919
+ SimulationListResponse import import SimulationListResponse L31–31
+ SimulationResponse import import SimulationResponse L31–31
+ list_proposal_simulations function async_function list_proposal_simulations L929–944
+ run_proposal_simulation function async_function run_proposal_simulation L838–878
~ musehub/core/genesis.py .py 1 symbol added
+ compute_simulation_id function function compute_simulation_id L584–598
~ musehub/models/musehub.py .py 3 symbols added
+ SimulationListResponse class class SimulationListResponse L1542–1546
+ SimulationResponse class class SimulationResponse L1516–1539
+ SimulationType class class SimulationType L1503–1513
~ musehub/services/musehub_proposals.py .py 9 symbols added, 15 symbols modified
+ _VALID_SIMULATION_TYPES variable variable _VALID_SIMULATION_TYPES L1586–1586
+ _current_from_commit function async_function _current_from_commit L1603–1610
+ _to_simulation_response function function _to_simulation_response L1589–1600
+ get_simulation function async_function get_simulation L1737–1773
+ SimulationListResponse import import SimulationListResponse L42–42
+ SimulationResponse import import SimulationResponse L42–42
+ compute_simulation_id import import compute_simulation_id L29–29
+ list_simulations function async_function list_simulations L1776–1807
+ run_simulation function async_function run_simulation L1613–1734

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:18d2953fc912010676a67b6797f26ef794a268a0479a9ab0c9d5fdfa8769f02d --body "your comment"