gabriel / musehub public
feat BREAKING proposals task/proposal-models-v2 #14 / 19
AI Agent gabriel · 127 days ago · May 8, 2026 · Diff

feat(proposals): phase 5 — API surface enrichment

ProposalResponse: + blocked_by / blocks / is_blocked — DAG position; populated by get_proposal + latest_simulations — inline dict of cached simulation results per type

get_proposal: loads DAG via load_dag_for_proposals and simulations via list_simulations; both feed _to_proposal_response so every single-read includes full context

list_proposals — new DB predicates: + proposal_type list filter (was accepted but silently ignored) + is_draft bool filter + merge_strategy list filter

ProposalListFilters: + is_draft: bool | None + merge_strategy: list[str] | None

ProposalListEntry: + merge_strategy — surfaces the ORM value per row + simulation_conflict_count — int | None; from prefetched conflict_scan

_enrich_one: uses dimensional_risk dict (Phase 1 ORM) for multi-domain risk instead of scalar risk_score → code-only; falls back to scalar for backwards compat

_prefetch_for_batch — Query 4: loads latest conflict_scan result per proposal in the current page; passes conflict_count to _enrich_one with zero per-row I/O

21 unit + integration tests; 187 total passing across all 5 phases.

sha256:9daf3a0663bc8746a142735e585a136ab395abb72a8c5affe9d9c56fdf3c0d14 sha
+47 ~10 symbols
sha256:bfd5e650f11cdee4ac895b548971641468863b6042f8d2ce8ac838af6a48db33 snapshot
+47
symbols added
~10
symbols modified
0
dead code introduced
Semantic Changes 57 symbols
+ TestEnrichOneMultiDomainRisk class class TestEnrichOneMultiDomainRisk L442–512
+ test_aggregate_risk_uses_weighted_mean method async_method test_aggregate_risk_uses_weighted_mean L485–512
+ test_dimensional_risk_drives_domain_risk method async_method test_dimensional_risk_drives_domain_risk L444–482
+ TestGetProposalEnrichment class class TestGetProposalEnrichment L252–342
+ test_blocked_by_populated_when_dep_exists method async_method test_blocked_by_populated_when_dep_exists L254–276
+ test_is_blocked_false_when_dep_merged method async_method test_is_blocked_false_when_dep_merged L279–308
+ test_latest_simulations_empty_before_run method async_method test_latest_simulations_empty_before_run L330–342
+ test_latest_simulations_populated_after_run method async_method test_latest_simulations_populated_after_run L311–327
+ TestListProposalsFilters class class TestListProposalsFilters L350–434
+ test_is_draft_false_filter method async_method test_is_draft_false_filter L396–412
+ test_is_draft_true_filter method async_method test_is_draft_true_filter L377–393
+ test_merge_strategy_filter method async_method test_merge_strategy_filter L415–434
+ test_proposal_type_filter method async_method test_proposal_type_filter L352–374
+ TestProposalListEntryShape class class TestProposalListEntryShape L107–131
+ _entry method method _entry L108–119
+ test_merge_strategy_defaults_state_overlay method method test_merge_strategy_defaults_state_overlay L121–123
+ test_merge_strategy_round_trips method method test_merge_strategy_round_trips L129–131
+ test_simulation_conflict_count_defaults_none method method test_simulation_conflict_count_defaults_none L125–127
+ TestProposalListFiltersShape class class TestProposalListFiltersShape L134–149
+ test_is_draft_defaults_none method method test_is_draft_defaults_none L135–137
+ test_is_draft_true_accepted method method test_is_draft_true_accepted L143–145
+ test_merge_strategy_defaults_none method method test_merge_strategy_defaults_none L139–141
+ test_merge_strategy_list_accepted method method test_merge_strategy_list_accepted L147–149
+ TestProposalResponseShape class class TestProposalResponseShape L77–104
+ test_blocked_by_defaults_empty method method test_blocked_by_defaults_empty L78–91
+ test_latest_simulations_defaults_empty method method test_latest_simulations_defaults_empty L93–104
+ TestSimulationConflictCountInBatch class class TestSimulationConflictCountInBatch L520–574
+ test_conflict_count_none_before_run method async_method test_conflict_count_none_before_run L522–543
+ test_conflict_count_populated_after_run method async_method test_conflict_count_populated_after_run L546–574
+ _make_branch_with_commit function async_function _make_branch_with_commit L181–218
+ _make_proposal function async_function _make_proposal L221–244
+ _make_repo function async_function _make_repo L157–178
+ _now function function _now L60–61
+ _oid function function _oid L68–69
+ _uid function function _uid L64–65
+ AsyncSession import import AsyncSession L46–46
+ ProposalListEntry import import ProposalListEntry L48–48
+ ProposalListFilters import import ProposalListFilters L48–48
+ ProposalResponse import import ProposalResponse L48–48
+ annotations import import annotations L39–39
+ blob_id import import blob_id L45–45
+ datetime import import datetime L42–42
+ fake_id import import fake_id L45–45
+ os import import os L41–41
+ pytest import import pytest L44–44
+ short_id import import short_id L45–45
+ timezone import import timezone L42–42

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:9daf3a0663bc8746a142735e585a136ab395abb72a8c5affe9d9c56fdf3c0d14 --body "your comment"