briefloop 0.11.12__py3-none-any.whl

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.
Files changed (424) hide show
  1. briefloop-0.11.12.dist-info/METADATA +473 -0
  2. briefloop-0.11.12.dist-info/RECORD +424 -0
  3. briefloop-0.11.12.dist-info/WHEEL +5 -0
  4. briefloop-0.11.12.dist-info/entry_points.txt +3 -0
  5. briefloop-0.11.12.dist-info/licenses/LICENSE +22 -0
  6. briefloop-0.11.12.dist-info/top_level.txt +1 -0
  7. multi_agent_brief/__init__.py +36 -0
  8. multi_agent_brief/analysis_blocks/__init__.py +11 -0
  9. multi_agent_brief/analysis_blocks/builder.py +206 -0
  10. multi_agent_brief/analysis_blocks/renderer.py +237 -0
  11. multi_agent_brief/analysis_blocks/schemas.py +52 -0
  12. multi_agent_brief/analysis_modules/__init__.py +8 -0
  13. multi_agent_brief/analysis_modules/base.py +87 -0
  14. multi_agent_brief/analysis_modules/market_competitor/__init__.py +68 -0
  15. multi_agent_brief/analysis_modules/market_competitor/auditor.py +290 -0
  16. multi_agent_brief/analysis_modules/market_competitor/config.py +187 -0
  17. multi_agent_brief/analysis_modules/market_competitor/event_builder.py +226 -0
  18. multi_agent_brief/analysis_modules/market_competitor/renderer.py +199 -0
  19. multi_agent_brief/analysis_modules/market_competitor/schemas.py +518 -0
  20. multi_agent_brief/analysis_modules/policy_regulatory/__init__.py +7 -0
  21. multi_agent_brief/analysis_modules/policy_regulatory/audit.py +195 -0
  22. multi_agent_brief/analysis_modules/policy_regulatory/module.py +387 -0
  23. multi_agent_brief/analysis_modules/policy_regulatory/schemas.py +129 -0
  24. multi_agent_brief/analysis_modules/registry.py +73 -0
  25. multi_agent_brief/audience/__init__.py +19 -0
  26. multi_agent_brief/audience/profiles.py +246 -0
  27. multi_agent_brief/audience_memory/__init__.py +23 -0
  28. multi_agent_brief/audience_memory/profile.py +358 -0
  29. multi_agent_brief/audit/__init__.py +36 -0
  30. multi_agent_brief/audit/case_applicability.py +181 -0
  31. multi_agent_brief/audit/deterministic.py +471 -0
  32. multi_agent_brief/audit/editorial_governance.py +404 -0
  33. multi_agent_brief/audit/final_quality.py +764 -0
  34. multi_agent_brief/audit/harness.py +242 -0
  35. multi_agent_brief/audit/interfaces.py +96 -0
  36. multi_agent_brief/audit/limitation_hygiene.py +238 -0
  37. multi_agent_brief/audit/proposal_boundary.py +34 -0
  38. multi_agent_brief/audit/redaction.py +27 -0
  39. multi_agent_brief/audit/rule_packs.py +96 -0
  40. multi_agent_brief/audit/semantic.py +435 -0
  41. multi_agent_brief/capabilities/__init__.py +22 -0
  42. multi_agent_brief/capabilities/catalog.py +215 -0
  43. multi_agent_brief/capabilities/detect.py +199 -0
  44. multi_agent_brief/capabilities/models.py +60 -0
  45. multi_agent_brief/capabilities/recommend.py +206 -0
  46. multi_agent_brief/cli/__init__.py +2 -0
  47. multi_agent_brief/cli/analysis_commands.py +140 -0
  48. multi_agent_brief/cli/approval_commands.py +107 -0
  49. multi_agent_brief/cli/audit_commands.py +59 -0
  50. multi_agent_brief/cli/capability_commands.py +548 -0
  51. multi_agent_brief/cli/claude_commands.py +159 -0
  52. multi_agent_brief/cli/competitors_commands.py +182 -0
  53. multi_agent_brief/cli/controls_commands.py +137 -0
  54. multi_agent_brief/cli/deliver_commands.py +942 -0
  55. multi_agent_brief/cli/eval_cases_commands.py +99 -0
  56. multi_agent_brief/cli/experiments_commands.py +395 -0
  57. multi_agent_brief/cli/feedback_commands.py +192 -0
  58. multi_agent_brief/cli/finalize_commands.py +153 -0
  59. multi_agent_brief/cli/gates_commands.py +174 -0
  60. multi_agent_brief/cli/hermes_commands.py +356 -0
  61. multi_agent_brief/cli/improve_commands.py +224 -0
  62. multi_agent_brief/cli/init_commands.py +564 -0
  63. multi_agent_brief/cli/init_wizard.py +1473 -0
  64. multi_agent_brief/cli/input_commands.py +237 -0
  65. multi_agent_brief/cli/main.py +288 -0
  66. multi_agent_brief/cli/onboard_commands.py +193 -0
  67. multi_agent_brief/cli/product_commands.py +1449 -0
  68. multi_agent_brief/cli/provenance_commands.py +100 -0
  69. multi_agent_brief/cli/release_commands.py +68 -0
  70. multi_agent_brief/cli/repair_commands.py +169 -0
  71. multi_agent_brief/cli/run_commands.py +292 -0
  72. multi_agent_brief/cli/runtime_commands.py +81 -0
  73. multi_agent_brief/cli/secrets_commands.py +232 -0
  74. multi_agent_brief/cli/semantic_support_commands.py +80 -0
  75. multi_agent_brief/cli/sources_commands.py +647 -0
  76. multi_agent_brief/cli/start_commands.py +8 -0
  77. multi_agent_brief/cli/state_commands.py +446 -0
  78. multi_agent_brief/cli/status_commands.py +26 -0
  79. multi_agent_brief/cli/workbuddy_commands.py +103 -0
  80. multi_agent_brief/configs/artifact_contracts.yaml +514 -0
  81. multi_agent_brief/configs/orchestrator_contract.yaml +181 -0
  82. multi_agent_brief/configs/policy_packs/default.yaml +65 -0
  83. multi_agent_brief/configs/policy_profiles/evidence_extract_default.yaml +58 -0
  84. multi_agent_brief/configs/policy_profiles/finance_default.yaml +44 -0
  85. multi_agent_brief/configs/policy_profiles/internet_default.yaml +44 -0
  86. multi_agent_brief/configs/policy_profiles/manufacturing_default.yaml +33 -0
  87. multi_agent_brief/configs/policy_profiles/solar_manufacturing_default.yaml +64 -0
  88. multi_agent_brief/configs/report_packs/evidence_extract.yaml +48 -0
  89. multi_agent_brief/configs/report_packs/management_monthly.yaml +36 -0
  90. multi_agent_brief/configs/report_packs/market_weekly.yaml +36 -0
  91. multi_agent_brief/configs/report_packs/solar_industry_periodic.yaml +50 -0
  92. multi_agent_brief/configs/report_templates/evidence_extract.yaml +55 -0
  93. multi_agent_brief/configs/report_templates/management_monthly.yaml +48 -0
  94. multi_agent_brief/configs/report_templates/market_weekly.yaml +49 -0
  95. multi_agent_brief/configs/report_templates/solar_industry_periodic.yaml +75 -0
  96. multi_agent_brief/configs/stage_specs.yaml +180 -0
  97. multi_agent_brief/contracts/__init__.py +41 -0
  98. multi_agent_brief/contracts/base.py +99 -0
  99. multi_agent_brief/contracts/errors.py +41 -0
  100. multi_agent_brief/contracts/migrations/__init__.py +5 -0
  101. multi_agent_brief/contracts/migrations/claim_v1_to_v2.py +33 -0
  102. multi_agent_brief/contracts/registry.py +159 -0
  103. multi_agent_brief/contracts/role_topology.py +25 -0
  104. multi_agent_brief/contracts/schemas/__init__.py +35 -0
  105. multi_agent_brief/contracts/schemas/analysis_pack.py +135 -0
  106. multi_agent_brief/contracts/schemas/atomic_claim_graph.py +304 -0
  107. multi_agent_brief/contracts/schemas/audit_report.py +80 -0
  108. multi_agent_brief/contracts/schemas/candidate_item.py +51 -0
  109. multi_agent_brief/contracts/schemas/claim.py +197 -0
  110. multi_agent_brief/contracts/schemas/claim_draft.py +386 -0
  111. multi_agent_brief/contracts/schemas/claim_support_matrix.py +334 -0
  112. multi_agent_brief/contracts/schemas/evidence_span_registry.py +270 -0
  113. multi_agent_brief/contracts/schemas/policy_profile.py +247 -0
  114. multi_agent_brief/contracts/schemas/report_spec.py +257 -0
  115. multi_agent_brief/contracts/schemas/semantic_assessment_report.py +480 -0
  116. multi_agent_brief/contracts/schemas/source_evidence_pack_manifest.py +233 -0
  117. multi_agent_brief/contracts/schemas/source_item.py +96 -0
  118. multi_agent_brief/contracts/semantic_assessment_status.py +12 -0
  119. multi_agent_brief/contracts/source_metadata.py +252 -0
  120. multi_agent_brief/contracts/target_contract.py +460 -0
  121. multi_agent_brief/contracts/validator.py +225 -0
  122. multi_agent_brief/controls/__init__.py +23 -0
  123. multi_agent_brief/controls/contract.py +106 -0
  124. multi_agent_brief/controls/switchboard.py +1076 -0
  125. multi_agent_brief/core/__init__.py +2 -0
  126. multi_agent_brief/core/citations.py +14 -0
  127. multi_agent_brief/core/claim_ledger.py +94 -0
  128. multi_agent_brief/core/config.py +191 -0
  129. multi_agent_brief/core/env.py +69 -0
  130. multi_agent_brief/core/previous.py +83 -0
  131. multi_agent_brief/core/schemas.py +181 -0
  132. multi_agent_brief/core/selection.py +189 -0
  133. multi_agent_brief/delivery/__init__.py +6 -0
  134. multi_agent_brief/delivery/base.py +36 -0
  135. multi_agent_brief/delivery/feishu.py +204 -0
  136. multi_agent_brief/delivery/gws.py +237 -0
  137. multi_agent_brief/evaluation_cases/__init__.py +15 -0
  138. multi_agent_brief/evaluation_cases/contract.py +429 -0
  139. multi_agent_brief/evaluation_cases/fixtures/cases/approved_guidance_materialized/workspace/config.yaml +18 -0
  140. multi_agent_brief/evaluation_cases/fixtures/cases/approved_guidance_materialized/workspace/improvement/ledger.jsonl +2 -0
  141. multi_agent_brief/evaluation_cases/fixtures/cases/approved_guidance_materialized/workspace/sources.yaml +2 -0
  142. multi_agent_brief/evaluation_cases/fixtures/cases/approved_guidance_materialized/workspace/user.md +4 -0
  143. multi_agent_brief/evaluation_cases/fixtures/cases/company_event_missing_latest_official_check/workspace/config.yaml +13 -0
  144. multi_agent_brief/evaluation_cases/fixtures/cases/company_event_missing_latest_official_check/workspace/sources.yaml +9 -0
  145. multi_agent_brief/evaluation_cases/fixtures/cases/company_event_missing_latest_official_check/workspace/user.md +4 -0
  146. multi_agent_brief/evaluation_cases/fixtures/cases/control_switchboard_selection_is_not_execution/workspace/config.yaml +12 -0
  147. multi_agent_brief/evaluation_cases/fixtures/cases/control_switchboard_selection_is_not_execution/workspace/sources.yaml +6 -0
  148. multi_agent_brief/evaluation_cases/fixtures/cases/control_switchboard_selection_is_not_execution/workspace/user.md +4 -0
  149. multi_agent_brief/evaluation_cases/fixtures/cases/feedback_triage_required/workspace/config.yaml +6 -0
  150. multi_agent_brief/evaluation_cases/fixtures/cases/feedback_triage_required/workspace/input/human_feedback.md +1 -0
  151. multi_agent_brief/evaluation_cases/fixtures/cases/feedback_triage_required/workspace/sources.yaml +2 -0
  152. multi_agent_brief/evaluation_cases/fixtures/cases/feedback_triage_required/workspace/user.md +3 -0
  153. multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/config.yaml +8 -0
  154. multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/output/brief.md +14 -0
  155. multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/output/intermediate/audit_report.json +1 -0
  156. multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/output/intermediate/audited_brief.md +5 -0
  157. multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/output/intermediate/candidate_claims.json +1 -0
  158. multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/output/intermediate/claim_ledger.json +1 -0
  159. multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/output/intermediate/screened_candidates.json +1 -0
  160. multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/sources.yaml +2 -0
  161. multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/user.md +3 -0
  162. multi_agent_brief/evaluation_cases/fixtures/cases/formal_release_missing_human_approval/workspace/config.yaml +13 -0
  163. multi_agent_brief/evaluation_cases/fixtures/cases/formal_release_missing_human_approval/workspace/sources.yaml +9 -0
  164. multi_agent_brief/evaluation_cases/fixtures/cases/formal_release_missing_human_approval/workspace/user.md +4 -0
  165. multi_agent_brief/evaluation_cases/fixtures/cases/guidance_manifestation_not_observable/workspace/config.yaml +4 -0
  166. multi_agent_brief/evaluation_cases/fixtures/cases/guidance_manifestation_not_observable/workspace/sources.yaml +2 -0
  167. multi_agent_brief/evaluation_cases/fixtures/cases/guidance_manifestation_not_observable/workspace/user.md +3 -0
  168. multi_agent_brief/evaluation_cases/fixtures/cases/media_only_legal_policy_blocks_research_review/workspace/config.yaml +13 -0
  169. multi_agent_brief/evaluation_cases/fixtures/cases/media_only_legal_policy_blocks_research_review/workspace/sources.yaml +9 -0
  170. multi_agent_brief/evaluation_cases/fixtures/cases/media_only_legal_policy_blocks_research_review/workspace/user.md +4 -0
  171. multi_agent_brief/evaluation_cases/fixtures/cases/mixed_metric_scope_support_blocker/workspace/config.yaml +13 -0
  172. multi_agent_brief/evaluation_cases/fixtures/cases/mixed_metric_scope_support_blocker/workspace/sources.yaml +9 -0
  173. multi_agent_brief/evaluation_cases/fixtures/cases/mixed_metric_scope_support_blocker/workspace/user.md +5 -0
  174. multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/config.yaml +6 -0
  175. multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/output/intermediate/audited_brief.md +3 -0
  176. multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/output/intermediate/candidate_claims.json +1 -0
  177. multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/output/intermediate/claim_ledger.json +1 -0
  178. multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/output/intermediate/feedback_issues.json +25 -0
  179. multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/output/intermediate/repair_plan.json +27 -0
  180. multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/output/intermediate/screened_candidates.json +1 -0
  181. multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/sources.yaml +2 -0
  182. multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/user.md +3 -0
  183. multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/config.yaml +8 -0
  184. multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/output/intermediate/audit_report.json +1 -0
  185. multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/output/intermediate/audited_brief.md +3 -0
  186. multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/output/intermediate/candidate_claims.json +1 -0
  187. multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/output/intermediate/claim_ledger.json +11 -0
  188. multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/output/intermediate/quality_gate_report.json +22 -0
  189. multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/output/intermediate/screened_candidates.json +1 -0
  190. multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/sources.yaml +2 -0
  191. multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/user.md +3 -0
  192. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/config.yaml +13 -0
  193. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/output/intermediate/audit_report.json +1 -0
  194. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/output/intermediate/audited_brief.md +5 -0
  195. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/output/intermediate/candidate_claims.json +1 -0
  196. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/output/intermediate/claim_ledger.json +40 -0
  197. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/output/intermediate/screened_candidates.json +1 -0
  198. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/sources.yaml +3 -0
  199. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/user.md +3 -0
  200. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/config.yaml +8 -0
  201. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/output/brief.md +3 -0
  202. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/output/intermediate/audit_report.json +1 -0
  203. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/output/intermediate/audited_brief.md +3 -0
  204. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/output/intermediate/candidate_claims.json +1 -0
  205. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/output/intermediate/claim_ledger.json +13 -0
  206. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/output/intermediate/screened_candidates.json +1 -0
  207. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/sources.yaml +2 -0
  208. multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/user.md +3 -0
  209. multi_agent_brief/evaluation_cases/fixtures/cases/release_readiness_forged_event_blocker/workspace/config.yaml +13 -0
  210. multi_agent_brief/evaluation_cases/fixtures/cases/release_readiness_forged_event_blocker/workspace/output/intermediate/release_readiness_report.json +31 -0
  211. multi_agent_brief/evaluation_cases/fixtures/cases/release_readiness_forged_event_blocker/workspace/sources.yaml +9 -0
  212. multi_agent_brief/evaluation_cases/fixtures/cases/release_readiness_forged_event_blocker/workspace/user.md +4 -0
  213. multi_agent_brief/evaluation_cases/fixtures/cases/reverted_entry_removed_from_next_snapshot/workspace/config.yaml +18 -0
  214. multi_agent_brief/evaluation_cases/fixtures/cases/reverted_entry_removed_from_next_snapshot/workspace/improvement/ledger.jsonl +3 -0
  215. multi_agent_brief/evaluation_cases/fixtures/cases/reverted_entry_removed_from_next_snapshot/workspace/improvement/memory.md +3 -0
  216. multi_agent_brief/evaluation_cases/fixtures/cases/reverted_entry_removed_from_next_snapshot/workspace/output/intermediate/improvement_memory_snapshot.md +3 -0
  217. multi_agent_brief/evaluation_cases/fixtures/cases/reverted_entry_removed_from_next_snapshot/workspace/sources.yaml +2 -0
  218. multi_agent_brief/evaluation_cases/fixtures/cases/reverted_entry_removed_from_next_snapshot/workspace/user.md +4 -0
  219. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/config.yaml +12 -0
  220. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/input/sources/source-001.txt +1 -0
  221. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/brief.md +37 -0
  222. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/delivery/brief.md +37 -0
  223. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/atomic_claim_graph.json +17 -0
  224. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/audit_report.json +5 -0
  225. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/audited_brief.md +37 -0
  226. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/claim_ledger.json +20 -0
  227. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/evidence_span_registry.json +20 -0
  228. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/finalize_report.json +40 -0
  229. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/gates/auditor_quality_gate_report.json +42 -0
  230. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/gates/finalize_quality_gate_report.json +42 -0
  231. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/screened_candidates.json +33 -0
  232. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/source_appendix.md +12 -0
  233. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/source_appendix_trace.md +10 -0
  234. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/report_spec.yaml +24 -0
  235. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/sources.yaml +4 -0
  236. multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/user.md +3 -0
  237. multi_agent_brief/evaluation_cases/fixtures/cases/source_evidence_pack_blocks_non_evidence_file/workspace/config.yaml +13 -0
  238. multi_agent_brief/evaluation_cases/fixtures/cases/source_evidence_pack_blocks_non_evidence_file/workspace/input/sources/README.md +4 -0
  239. multi_agent_brief/evaluation_cases/fixtures/cases/source_evidence_pack_blocks_non_evidence_file/workspace/output/intermediate/source_evidence_pack_manifest.json +26 -0
  240. multi_agent_brief/evaluation_cases/fixtures/cases/source_evidence_pack_blocks_non_evidence_file/workspace/sources.yaml +9 -0
  241. multi_agent_brief/evaluation_cases/fixtures/cases/source_evidence_pack_blocks_non_evidence_file/workspace/user.md +4 -0
  242. multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/config.yaml +9 -0
  243. multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/output/intermediate/audit_report.json +1 -0
  244. multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/output/intermediate/audited_brief.md +3 -0
  245. multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/output/intermediate/candidate_claims.json +1 -0
  246. multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/output/intermediate/claim_ledger.json +13 -0
  247. multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/output/intermediate/screened_candidates.json +1 -0
  248. multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/sources.yaml +2 -0
  249. multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/user.md +3 -0
  250. multi_agent_brief/evaluation_cases/fixtures/cases/third_party_price_snapshot_formal_block/workspace/config.yaml +13 -0
  251. multi_agent_brief/evaluation_cases/fixtures/cases/third_party_price_snapshot_formal_block/workspace/sources.yaml +9 -0
  252. multi_agent_brief/evaluation_cases/fixtures/cases/third_party_price_snapshot_formal_block/workspace/user.md +4 -0
  253. multi_agent_brief/evaluation_cases/fixtures/cases/trajectory_retry_budget_exhausted/workspace/config.yaml +4 -0
  254. multi_agent_brief/evaluation_cases/fixtures/cases/trajectory_retry_budget_exhausted/workspace/sources.yaml +2 -0
  255. multi_agent_brief/evaluation_cases/fixtures/cases/trajectory_retry_budget_exhausted/workspace/user.md +3 -0
  256. multi_agent_brief/evaluation_cases/fixtures/cases/unapproved_entry_not_materialized/workspace/config.yaml +18 -0
  257. multi_agent_brief/evaluation_cases/fixtures/cases/unapproved_entry_not_materialized/workspace/improvement/ledger.jsonl +1 -0
  258. multi_agent_brief/evaluation_cases/fixtures/cases/unapproved_entry_not_materialized/workspace/sources.yaml +2 -0
  259. multi_agent_brief/evaluation_cases/fixtures/cases/unapproved_entry_not_materialized/workspace/user.md +4 -0
  260. multi_agent_brief/evaluation_cases/fixtures/cases/unauthorized_institution_branding_blocks_release/workspace/config.yaml +18 -0
  261. multi_agent_brief/evaluation_cases/fixtures/cases/unauthorized_institution_branding_blocks_release/workspace/sources.yaml +9 -0
  262. multi_agent_brief/evaluation_cases/fixtures/cases/unauthorized_institution_branding_blocks_release/workspace/user.md +5 -0
  263. multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/config.yaml +8 -0
  264. multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/output/intermediate/audit_report.json +1 -0
  265. multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/output/intermediate/audited_brief.md +8 -0
  266. multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/output/intermediate/candidate_claims.json +1 -0
  267. multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/output/intermediate/claim_ledger.json +1 -0
  268. multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/output/intermediate/screened_candidates.json +1 -0
  269. multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/sources.yaml +2 -0
  270. multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/user.md +3 -0
  271. multi_agent_brief/evaluation_cases/fixtures/manifest.yaml +861 -0
  272. multi_agent_brief/evaluation_cases/fixtures.py +20 -0
  273. multi_agent_brief/evaluation_cases/runner.py +1603 -0
  274. multi_agent_brief/experiments/__init__.py +45 -0
  275. multi_agent_brief/experiments/experiment_080.py +5835 -0
  276. multi_agent_brief/experiments/schemas.py +63 -0
  277. multi_agent_brief/experiments/target_contract.py +10 -0
  278. multi_agent_brief/feedback/__init__.py +17 -0
  279. multi_agent_brief/feedback/feedback_contract.py +482 -0
  280. multi_agent_brief/feedback/feedback_state.py +898 -0
  281. multi_agent_brief/hermes/__init__.py +25 -0
  282. multi_agent_brief/hermes/adapter.py +832 -0
  283. multi_agent_brief/improvement/__init__.py +83 -0
  284. multi_agent_brief/improvement/contract.py +1114 -0
  285. multi_agent_brief/improvement/memory.py +451 -0
  286. multi_agent_brief/improvement/product_definition.py +228 -0
  287. multi_agent_brief/improvement/state.py +961 -0
  288. multi_agent_brief/inputs/__init__.py +2 -0
  289. multi_agent_brief/inputs/classifier.py +322 -0
  290. multi_agent_brief/inputs/contracts.py +59 -0
  291. multi_agent_brief/inputs/extractor.py +310 -0
  292. multi_agent_brief/install/__init__.py +2 -0
  293. multi_agent_brief/install/writer.py +97 -0
  294. multi_agent_brief/onboarding/__init__.py +11 -0
  295. multi_agent_brief/onboarding/io.py +103 -0
  296. multi_agent_brief/onboarding/mapper.py +484 -0
  297. multi_agent_brief/onboarding/schema.py +46 -0
  298. multi_agent_brief/orchestrator/__init__.py +2 -0
  299. multi_agent_brief/orchestrator/fact_layer_import.py +352 -0
  300. multi_agent_brief/orchestrator/handoff.py +2209 -0
  301. multi_agent_brief/orchestrator/role_topology.py +42 -0
  302. multi_agent_brief/orchestrator/run_archive.py +888 -0
  303. multi_agent_brief/orchestrator/run_integrity.py +346 -0
  304. multi_agent_brief/orchestrator/runtime_state/__init__.py +70 -0
  305. multi_agent_brief/orchestrator/runtime_state/_io.py +167 -0
  306. multi_agent_brief/orchestrator/runtime_state/_transactions.py +298 -0
  307. multi_agent_brief/orchestrator/runtime_state/artifact_registry.py +1825 -0
  308. multi_agent_brief/orchestrator/runtime_state/atomic_claim_graph.py +96 -0
  309. multi_agent_brief/orchestrator/runtime_state/claim_ledger_freeze.py +510 -0
  310. multi_agent_brief/orchestrator/runtime_state/claim_metadata_enrichment.py +836 -0
  311. multi_agent_brief/orchestrator/runtime_state/claim_support_matrix.py +582 -0
  312. multi_agent_brief/orchestrator/runtime_state/completion_gates.py +672 -0
  313. multi_agent_brief/orchestrator/runtime_state/contracts_loader.py +66 -0
  314. multi_agent_brief/orchestrator/runtime_state/decisions.py +239 -0
  315. multi_agent_brief/orchestrator/runtime_state/errors.py +61 -0
  316. multi_agent_brief/orchestrator/runtime_state/event_log.py +256 -0
  317. multi_agent_brief/orchestrator/runtime_state/evidence_span_registry.py +233 -0
  318. multi_agent_brief/orchestrator/runtime_state/fact_layer.py +755 -0
  319. multi_agent_brief/orchestrator/runtime_state/identity.py +90 -0
  320. multi_agent_brief/orchestrator/runtime_state/lifecycle.py +675 -0
  321. multi_agent_brief/orchestrator/runtime_state/manifest.py +82 -0
  322. multi_agent_brief/orchestrator/runtime_state/operations.py +224 -0
  323. multi_agent_brief/orchestrator/runtime_state/paths.py +38 -0
  324. multi_agent_brief/orchestrator/runtime_state/repair.py +984 -0
  325. multi_agent_brief/orchestrator/runtime_state/safety_surfaces.py +147 -0
  326. multi_agent_brief/orchestrator/runtime_state/semantic_assessment_report.py +692 -0
  327. multi_agent_brief/orchestrator/runtime_state/semantic_support_acceptance.py +683 -0
  328. multi_agent_brief/orchestrator/runtime_state/source_evidence_pack.py +131 -0
  329. multi_agent_brief/orchestrator/runtime_state/stage_completion.py +1320 -0
  330. multi_agent_brief/orchestrator/runtime_state/trajectory.py +200 -0
  331. multi_agent_brief/orchestrator/runtime_state/workflow.py +350 -0
  332. multi_agent_brief/orchestrator/source_evidence.py +43 -0
  333. multi_agent_brief/orchestrator/timing.py +410 -0
  334. multi_agent_brief/orchestrator_contract.py +96 -0
  335. multi_agent_brief/outputs/__init__.py +2 -0
  336. multi_agent_brief/outputs/atomic_reader_projection.py +288 -0
  337. multi_agent_brief/outputs/docx.py +32 -0
  338. multi_agent_brief/outputs/finalize.py +1036 -0
  339. multi_agent_brief/outputs/ib_docx.py +983 -0
  340. multi_agent_brief/outputs/naming.py +38 -0
  341. multi_agent_brief/outputs/pdf.py +20 -0
  342. multi_agent_brief/outputs/reader_final_gate.py +509 -0
  343. multi_agent_brief/outputs/reader_projection.py +397 -0
  344. multi_agent_brief/outputs/source_appendix.py +753 -0
  345. multi_agent_brief/outputs/templates/__init__.py +112 -0
  346. multi_agent_brief/product/__init__.py +49 -0
  347. multi_agent_brief/product/bundle_projection.py +686 -0
  348. multi_agent_brief/product/citation_profile.py +145 -0
  349. multi_agent_brief/product/guidance_manifestation.py +421 -0
  350. multi_agent_brief/product/materiality_selection.py +472 -0
  351. multi_agent_brief/product/policy_gate_adapter.py +116 -0
  352. multi_agent_brief/product/policy_profile.py +39 -0
  353. multi_agent_brief/product/policy_projection.py +161 -0
  354. multi_agent_brief/product/policy_registry.py +83 -0
  355. multi_agent_brief/product/policy_resolver.py +225 -0
  356. multi_agent_brief/product/quality_closeout.py +188 -0
  357. multi_agent_brief/product/quality_panel.py +2217 -0
  358. multi_agent_brief/product/release_approval.py +1034 -0
  359. multi_agent_brief/product/report_pack.py +130 -0
  360. multi_agent_brief/product/report_pack_aliases.py +68 -0
  361. multi_agent_brief/product/report_registry.py +101 -0
  362. multi_agent_brief/product/report_spec.py +181 -0
  363. multi_agent_brief/product/support_wording.py +525 -0
  364. multi_agent_brief/product/template_conformance.py +516 -0
  365. multi_agent_brief/product/template_projection.py +123 -0
  366. multi_agent_brief/product/template_registry.py +244 -0
  367. multi_agent_brief/product/template_render_plan.py +315 -0
  368. multi_agent_brief/product/template_renderer.py +224 -0
  369. multi_agent_brief/product/trajectory_regulation.py +441 -0
  370. multi_agent_brief/provenance/__init__.py +5 -0
  371. multi_agent_brief/provenance/builder.py +841 -0
  372. multi_agent_brief/provenance/contract.py +21 -0
  373. multi_agent_brief/provenance/io.py +144 -0
  374. multi_agent_brief/provenance/model.py +110 -0
  375. multi_agent_brief/provenance/references.py +43 -0
  376. multi_agent_brief/provenance/validator.py +135 -0
  377. multi_agent_brief/quality_gates/__init__.py +19 -0
  378. multi_agent_brief/quality_gates/contract.py +581 -0
  379. multi_agent_brief/quality_gates/state.py +2498 -0
  380. multi_agent_brief/repair/__init__.py +5 -0
  381. multi_agent_brief/repair/router.py +842 -0
  382. multi_agent_brief/runtime_assets.py +431 -0
  383. multi_agent_brief/sources/__init__.py +16 -0
  384. multi_agent_brief/sources/api_filings.py +236 -0
  385. multi_agent_brief/sources/api_news.py +174 -0
  386. multi_agent_brief/sources/base.py +142 -0
  387. multi_agent_brief/sources/cached_package.py +119 -0
  388. multi_agent_brief/sources/cli_provider.py +263 -0
  389. multi_agent_brief/sources/coverage.py +336 -0
  390. multi_agent_brief/sources/decider.py +756 -0
  391. multi_agent_brief/sources/doctor.py +373 -0
  392. multi_agent_brief/sources/evidence_pack.py +364 -0
  393. multi_agent_brief/sources/feishu_provider.py +326 -0
  394. multi_agent_brief/sources/filing_resolver.py +400 -0
  395. multi_agent_brief/sources/industry_packs.py +130 -0
  396. multi_agent_brief/sources/join.py +206 -0
  397. multi_agent_brief/sources/local_signal.py +81 -0
  398. multi_agent_brief/sources/local_signal_planner.py +636 -0
  399. multi_agent_brief/sources/manual.py +259 -0
  400. multi_agent_brief/sources/mcp_provider.py +309 -0
  401. multi_agent_brief/sources/mineru_provider.py +601 -0
  402. multi_agent_brief/sources/normalizer.py +95 -0
  403. multi_agent_brief/sources/opencli_provider.py +282 -0
  404. multi_agent_brief/sources/planner.py +178 -0
  405. multi_agent_brief/sources/registry.py +367 -0
  406. multi_agent_brief/sources/rss.py +190 -0
  407. multi_agent_brief/sources/search_backends/__init__.py +31 -0
  408. multi_agent_brief/sources/search_backends/base.py +51 -0
  409. multi_agent_brief/sources/search_backends/brave.py +192 -0
  410. multi_agent_brief/sources/search_backends/capabilities.py +94 -0
  411. multi_agent_brief/sources/search_backends/exa.py +180 -0
  412. multi_agent_brief/sources/search_backends/firecrawl.py +164 -0
  413. multi_agent_brief/sources/search_backends/serper.py +241 -0
  414. multi_agent_brief/sources/search_backends/tavily.py +124 -0
  415. multi_agent_brief/sources/sourcehub.py +505 -0
  416. multi_agent_brief/sources/web_search.py +267 -0
  417. multi_agent_brief/status.py +966 -0
  418. multi_agent_brief/tools/__init__.py +3 -0
  419. multi_agent_brief/tools/draft_cleanup.py +198 -0
  420. multi_agent_brief/workbuddy/__init__.py +1 -0
  421. multi_agent_brief/workbuddy/diagnose.py +569 -0
  422. multi_agent_brief/workbuddy/skill_pack.py +309 -0
  423. multi_agent_brief/workspace/__init__.py +1 -0
  424. multi_agent_brief/workspace/init_profile.py +45 -0
@@ -0,0 +1,206 @@
1
+ """Build AnalysisBlocks from a ClaimLedger.
2
+
3
+ Classification rules (from v0.5.3 PR 1 acceptance criteria):
4
+ - observed + direct → Fact
5
+ - analogous → Case
6
+ - hypothesis / interpreted → Interpretation
7
+ - action + direct evidence → Action
8
+ - action without evidence → To Verify (downgraded)
9
+ - hypothesis → also To Verify (pending validation)
10
+ - any claim with limitations → Limitation
11
+ """
12
+ from __future__ import annotations
13
+
14
+ from collections import defaultdict
15
+
16
+ from multi_agent_brief.analysis_blocks.schemas import AnalysisBlock, CaseApplicability
17
+ from multi_agent_brief.core.claim_ledger import ClaimLedger
18
+ from multi_agent_brief.core.schemas import Claim
19
+
20
+
21
+ def _infer_section(statement: str) -> str:
22
+ """Infer a topic from claim statement keywords.
23
+
24
+ Kept in sync with the analysis-block topic inference helper to avoid topic drift
25
+ between analysis_blocks (governance artifact) and legacy brief.md.
26
+ """
27
+ lowered = statement.lower()
28
+ if any(word in lowered for word in ["policy", "tariff", "regulation"]):
29
+ return "policy"
30
+ if any(word in lowered for word in ["compliance", "uflpa", "forced labor"]):
31
+ return "compliance"
32
+ if any(word in lowered for word in ["revenue", "margin", "earnings"]):
33
+ return "earnings"
34
+ if any(word in lowered for word in ["competitor", "capacity", "launch"]):
35
+ return "competitor"
36
+ if any(word in lowered for word in ["market", "price", "demand"]):
37
+ return "market"
38
+ if any(word in lowered for word in ["installation", "generation", "ppa"]):
39
+ return "demand"
40
+ if any(word in lowered for word in ["treasury", "yield", "sofr", "fed", "rate"]):
41
+ return "rates"
42
+ if any(word in lowered for word in ["acquisition", "investment", "fund", "capital"]):
43
+ return "capital"
44
+ if any(word in lowered for word in ["topcon", "hjt", "technology", "efficiency"]):
45
+ return "technology"
46
+ return "general"
47
+
48
+
49
+ def build_analysis_blocks(ledger: ClaimLedger) -> list[AnalysisBlock]:
50
+ """Group ledger claims into AnalysisBlocks by topic.
51
+
52
+ Each topic becomes one block. Claims are classified into epistemic
53
+ buckets based on their epistemic_type and evidence_relation.
54
+ """
55
+ # Group claims by topic — fall back to keyword inference for topicless claims,
56
+ # keeping parity with analysis-block topic inference.
57
+ by_topic: dict[str, list[Claim]] = defaultdict(list)
58
+ for claim in ledger:
59
+ topic = claim.metadata.get("topic") or _infer_section(claim.statement)
60
+ by_topic[topic].append(claim)
61
+
62
+ blocks: list[AnalysisBlock] = []
63
+ for topic, claims in by_topic.items():
64
+ block = _build_block(topic, claims)
65
+ blocks.append(block)
66
+
67
+ return blocks
68
+
69
+
70
+ def _build_block(topic: str, claims: list[Claim]) -> AnalysisBlock:
71
+ block_id = topic.replace(" ", "_").lower()
72
+ block = AnalysisBlock(block_id=block_id, title=topic.replace("_", " ").title())
73
+
74
+ for claim in claims:
75
+ _classify_claim(block, claim)
76
+
77
+ block.confidence = _compute_confidence(block, claims)
78
+ return block
79
+
80
+
81
+ def _classify_claim(block: AnalysisBlock, claim: Claim) -> None:
82
+ """Classify a single claim into the appropriate epistemic bucket."""
83
+ ep_type = claim.epistemic_type
84
+ ev_rel = claim.evidence_relation
85
+ has_evidence = bool(claim.evidence_text.strip())
86
+ has_limitations = bool(claim.limitations)
87
+
88
+ # 1. observed + direct → Fact
89
+ if ep_type == "observed" and ev_rel == "direct":
90
+ block.fact_claim_ids.append(claim.claim_id)
91
+ if has_limitations:
92
+ block.limitation_claim_ids.append(claim.claim_id)
93
+ return
94
+
95
+ # 2. analogous → Case (but hypothesis still goes to To Verify)
96
+ if ev_rel == "analogous":
97
+ block.case_claim_ids.append(claim.claim_id)
98
+ # Populate case_applicability from claim metadata if available
99
+ _populate_case_applicability(block, claim)
100
+ # hypothesis+analogous: must also be tracked for verification
101
+ if ep_type == "hypothesis":
102
+ block.to_verify_claim_ids.append(claim.claim_id)
103
+ if has_limitations:
104
+ block.limitation_claim_ids.append(claim.claim_id)
105
+ return
106
+
107
+ # 3. hypothesis / interpreted → Interpretation
108
+ if ep_type in ("hypothesis", "interpreted"):
109
+ block.interpretation_claim_ids.append(claim.claim_id)
110
+ # hypothesis also goes to To Verify
111
+ if ep_type == "hypothesis":
112
+ block.to_verify_claim_ids.append(claim.claim_id)
113
+ if has_limitations:
114
+ block.limitation_claim_ids.append(claim.claim_id)
115
+ return
116
+
117
+ # 4. action — gate on evidence
118
+ if ep_type == "action":
119
+ if has_evidence and ev_rel == "direct":
120
+ block.action_claim_ids.append(claim.claim_id)
121
+ else:
122
+ # Downgrade: action without direct evidence → To Verify
123
+ block.to_verify_claim_ids.append(claim.claim_id)
124
+ if has_limitations:
125
+ block.limitation_claim_ids.append(claim.claim_id)
126
+ return
127
+
128
+ # 5. observed + indirect/inferred → Interpretation (not strong enough for Fact)
129
+ if ep_type == "observed" and ev_rel in ("indirect", "inferred"):
130
+ block.interpretation_claim_ids.append(claim.claim_id)
131
+ block.to_verify_claim_ids.append(claim.claim_id)
132
+ if has_limitations:
133
+ block.limitation_claim_ids.append(claim.claim_id)
134
+ return
135
+
136
+ # Fallback: anything else goes to Interpretation + To Verify
137
+ block.interpretation_claim_ids.append(claim.claim_id)
138
+ block.to_verify_claim_ids.append(claim.claim_id)
139
+ if has_limitations:
140
+ block.limitation_claim_ids.append(claim.claim_id)
141
+
142
+
143
+ def _populate_case_applicability(block: AnalysisBlock, claim: Claim) -> None:
144
+ """Extract case applicability from claim metadata (PR 3)."""
145
+ meta = claim.metadata
146
+ if not meta:
147
+ return
148
+
149
+ comparable = meta.get("comparable_dimensions", [])
150
+ non_comparable = meta.get("non_comparable_dimensions", [])
151
+ market_ctx = meta.get("market_context", "")
152
+ stage_ctx = meta.get("stage_context", "")
153
+ audience_fit = meta.get("price_band_or_audience_fit", "")
154
+ needs_local = meta.get("local_verification_needed", False)
155
+ applicability = claim.applicability_reason or meta.get("applicability_reason", "")
156
+
157
+ if any([comparable, non_comparable, market_ctx, stage_ctx, audience_fit, needs_local, applicability]):
158
+ if block.case_applicability is None:
159
+ block.case_applicability = CaseApplicability()
160
+ if comparable:
161
+ block.case_applicability.comparable_dimensions.extend(comparable)
162
+ if non_comparable:
163
+ block.case_applicability.non_comparable_dimensions.extend(non_comparable)
164
+ if market_ctx:
165
+ block.case_applicability.market_context = market_ctx
166
+ if stage_ctx:
167
+ block.case_applicability.stage_context = stage_ctx
168
+ if audience_fit:
169
+ block.case_applicability.price_band_or_audience_fit = audience_fit
170
+ if needs_local:
171
+ block.case_applicability.local_verification_needed = True
172
+ if applicability:
173
+ if not block.applicability_note:
174
+ block.applicability_note = applicability
175
+ elif applicability not in block.applicability_note:
176
+ block.applicability_note += "; " + applicability
177
+
178
+
179
+ def _compute_confidence(block: AnalysisBlock, claims: list[Claim]) -> float:
180
+ """Compute block confidence from claim evidence quality.
181
+
182
+ Epistemic hierarchy (strongest → weakest):
183
+ observed+direct (1.0) > interpreted (0.5) > analogous (0.4) > hypothesis (0.2)
184
+ Action claims with direct evidence score 1.0 (equivalent to observed+direct).
185
+ """
186
+ if not claims:
187
+ return 0.0
188
+
189
+ score = 0.0
190
+ for claim in claims:
191
+ ep_type = claim.epistemic_type
192
+ ev_rel = claim.evidence_relation
193
+ if ep_type == "observed" and ev_rel == "direct":
194
+ score += 1.0
195
+ elif ep_type == "action" and ev_rel == "direct":
196
+ score += 1.0
197
+ elif ev_rel == "analogous":
198
+ score += 0.4
199
+ elif ep_type == "hypothesis":
200
+ score += 0.2
201
+ elif ep_type == "interpreted":
202
+ score += 0.5
203
+ else:
204
+ score += 0.3
205
+
206
+ return round(min(score / len(claims), 1.0), 2)
@@ -0,0 +1,237 @@
1
+ """Render AnalysisBlocks to structured markdown.
2
+
3
+ Produces a fixed-block format instead of prose:
4
+ Fact → Case/Comparison → Interpretation → Limitations → Action/To Verify
5
+
6
+ Different audiences get different heading labels, but the underlying
7
+ block structure is always the same.
8
+ """
9
+ from __future__ import annotations
10
+
11
+ from multi_agent_brief.analysis_blocks.schemas import AnalysisBlock
12
+ from multi_agent_brief.core.claim_ledger import ClaimLedger
13
+ from multi_agent_brief.core.schemas import Claim
14
+
15
+ # Audience-specific heading maps
16
+ _HEADING_MAPS: dict[str, dict[str, str]] = {
17
+ "management": {
18
+ "fact": "What Happened",
19
+ "case": "Comparable Context",
20
+ "interpretation": "Why It Matters",
21
+ "limitations": "Evidence Boundary",
22
+ "action": "What To Do",
23
+ "to_verify": "What To Verify Next",
24
+ },
25
+ "research": {
26
+ "fact": "Observed Facts",
27
+ "case": "Comparable Cases",
28
+ "interpretation": "Interpretation",
29
+ "limitations": "Limitations",
30
+ "action": "Recommended Actions",
31
+ "to_verify": "Pending Verification",
32
+ },
33
+ "default": {
34
+ "fact": "Fact",
35
+ "case": "Case / Comparison",
36
+ "interpretation": "Interpretation",
37
+ "limitations": "Limitations",
38
+ "action": "Action",
39
+ "to_verify": "To Verify",
40
+ },
41
+ }
42
+
43
+
44
+ def render_analysis_blocks(
45
+ blocks: list[AnalysisBlock],
46
+ ledger: ClaimLedger,
47
+ *,
48
+ project_name: str = "",
49
+ audience: str = "default",
50
+ language: str = "en-US",
51
+ ) -> str:
52
+ """Render analysis blocks to structured markdown.
53
+
54
+ Args:
55
+ blocks: AnalysisBlock instances from builder.
56
+ ledger: ClaimLedger for resolving claim details.
57
+ project_name: Optional project title shown at the top.
58
+ audience: Heading style key ("management", "research", "default").
59
+ language: "en-US" or "zh-CN".
60
+
61
+ Returns:
62
+ Structured markdown string.
63
+ """
64
+ headings = _HEADING_MAPS.get(audience, _HEADING_MAPS["default"])
65
+ is_zh = language.startswith("zh")
66
+
67
+ parts: list[str] = []
68
+ if project_name:
69
+ parts.append(f"# {project_name}")
70
+
71
+ sections: list[str] = []
72
+ for block in blocks:
73
+ section = _render_block(block, ledger, headings, is_zh)
74
+ if section:
75
+ sections.append(section)
76
+
77
+ if not sections:
78
+ return _empty_message(is_zh)
79
+
80
+ parts.extend(sections)
81
+ return "\n\n".join(parts) + "\n"
82
+
83
+
84
+ def _render_block(
85
+ block: AnalysisBlock,
86
+ ledger: ClaimLedger,
87
+ headings: dict[str, str],
88
+ is_zh: bool,
89
+ ) -> str:
90
+ lines: list[str] = [f"## {block.title}", ""]
91
+
92
+ # Fact section — conditional like all other sections
93
+ if block.fact_claim_ids:
94
+ lines.append(f"### {headings['fact']}")
95
+ lines.append("")
96
+ fact_lines = _render_claim_list(block.fact_claim_ids, ledger)
97
+ if fact_lines:
98
+ lines.extend(fact_lines)
99
+ else:
100
+ lines.append(_no_fact_message(is_zh))
101
+ lines.append("")
102
+
103
+ # Case / Comparison section
104
+ case_lines = _render_claim_list(block.case_claim_ids, ledger)
105
+ if case_lines:
106
+ lines.append(f"### {headings['case']}")
107
+ lines.append("")
108
+ lines.extend(case_lines)
109
+ # Applicability note (PR 3)
110
+ if block.applicability_note:
111
+ lines.append("")
112
+ lines.append(f"> **{ _applicability_label(is_zh) }:** {block.applicability_note}")
113
+ if block.case_applicability:
114
+ ca = block.case_applicability
115
+ if ca.comparable_dimensions:
116
+ lines.append(f"> **{ _comparable_label(is_zh) }:** {', '.join(ca.comparable_dimensions)}")
117
+ if ca.non_comparable_dimensions:
118
+ lines.append(f"> **{ _non_comparable_label(is_zh) }:** {', '.join(ca.non_comparable_dimensions)}")
119
+ if ca.local_verification_needed:
120
+ lines.append(f"> ⚠️ { _local_verify_label(is_zh) }")
121
+ lines.append("")
122
+
123
+ # Interpretation section
124
+ interp_lines = _render_claim_list(block.interpretation_claim_ids, ledger)
125
+ if interp_lines:
126
+ lines.append(f"### {headings['interpretation']}")
127
+ lines.append("")
128
+ lines.extend(interp_lines)
129
+ lines.append("")
130
+
131
+ # Limitations section
132
+ limit_lines = _render_limitations(block, ledger, is_zh)
133
+ if limit_lines:
134
+ lines.append(f"### {headings['limitations']}")
135
+ lines.append("")
136
+ lines.extend(limit_lines)
137
+ lines.append("")
138
+
139
+ # Action section (only claims with direct evidence)
140
+ action_lines = _render_claim_list(block.action_claim_ids, ledger)
141
+ if action_lines:
142
+ lines.append(f"### {headings['action']}")
143
+ lines.append("")
144
+ lines.extend(action_lines)
145
+ lines.append("")
146
+
147
+ # To Verify section
148
+ verify_lines = _render_claim_list(block.to_verify_claim_ids, ledger)
149
+ if verify_lines:
150
+ lines.append(f"### {headings['to_verify']}")
151
+ lines.append("")
152
+ lines.extend(verify_lines)
153
+ if block.verification_path:
154
+ lines.append("")
155
+ lines.append(f"> **{ _verification_path_label(is_zh) }:** {block.verification_path}")
156
+ lines.append("")
157
+
158
+ # Confidence footer (qualitative label, not percentage — avoids audit false positives)
159
+ lines.append(f"_{ _confidence_label(is_zh) }: { _confidence_level(block.confidence, is_zh) }_")
160
+ lines.append("")
161
+
162
+ return "\n".join(lines)
163
+
164
+
165
+ def _render_claim_list(claim_ids: list[str], ledger: ClaimLedger) -> list[str]:
166
+ lines = []
167
+ for cid in claim_ids:
168
+ claim = ledger.get_claim(cid)
169
+ if claim:
170
+ date_str = claim.metadata.get("published_at") or claim.metadata.get("retrieved_at", "")
171
+ date_prefix = f"{date_str} | " if date_str else ""
172
+ lines.append(f"- {date_prefix}{claim.statement} [src:{cid}]")
173
+ return lines
174
+
175
+
176
+ def _render_limitations(block: AnalysisBlock, ledger: ClaimLedger, is_zh: bool) -> list[str]:
177
+ lines = []
178
+ seen: set[str] = set()
179
+ for cid in block.limitation_claim_ids:
180
+ claim = ledger.get_claim(cid)
181
+ if not claim:
182
+ continue
183
+ for lim in claim.limitations:
184
+ normalized = lim.strip().lower()
185
+ if normalized not in seen:
186
+ seen.add(normalized)
187
+ lines.append(f"- {lim}")
188
+ return lines
189
+
190
+
191
+ def _no_fact_message(is_zh: bool) -> str:
192
+ if is_zh:
193
+ return "_未找到本期直接事实依据。_"
194
+ return "_No current-period direct fact found._"
195
+
196
+
197
+ def _empty_message(is_zh: bool) -> str:
198
+ if is_zh:
199
+ return "# 无可报告信号\n\n未发现符合条件的事实声明。\n"
200
+ return "# No Reportable Signals\n\nNo candidate claims were found.\n"
201
+
202
+
203
+ def _applicability_label(is_zh: bool) -> str:
204
+ return "适用性说明" if is_zh else "Applicability"
205
+
206
+
207
+ def _comparable_label(is_zh: bool) -> str:
208
+ return "可比维度" if is_zh else "Comparable Dimensions"
209
+
210
+
211
+ def _non_comparable_label(is_zh: bool) -> str:
212
+ return "不可比维度" if is_zh else "Non-Comparable Dimensions"
213
+
214
+
215
+ def _local_verify_label(is_zh: bool) -> str:
216
+ return "需要本地验证" if is_zh else "Local verification needed"
217
+
218
+
219
+ def _verification_path_label(is_zh: bool) -> str:
220
+ return "验证路径" if is_zh else "Verification Path"
221
+
222
+
223
+ def _confidence_label(is_zh: bool) -> str:
224
+ return "置信度" if is_zh else "Confidence"
225
+
226
+
227
+ def _confidence_level(score: float, is_zh: bool) -> str:
228
+ """Map numeric confidence to qualitative label.
229
+
230
+ Avoids precise percentages that trigger audit false positives
231
+ (e.g. '100%' flagged as number_without_source).
232
+ """
233
+ if score >= 0.8:
234
+ return "高" if is_zh else "High"
235
+ if score >= 0.5:
236
+ return "中" if is_zh else "Medium"
237
+ return "低" if is_zh else "Low"
@@ -0,0 +1,52 @@
1
+ """Analysis Block schemas — epistemic presentation layer."""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import asdict, dataclass, field
5
+ from typing import Any
6
+
7
+
8
+ @dataclass
9
+ class CaseApplicability:
10
+ """Comparable case boundary metadata (PR 3 of v0.5.3)."""
11
+
12
+ comparable_dimensions: list[str] = field(default_factory=list)
13
+ non_comparable_dimensions: list[str] = field(default_factory=list)
14
+ market_context: str = ""
15
+ stage_context: str = ""
16
+ price_band_or_audience_fit: str = ""
17
+ local_verification_needed: bool = False
18
+
19
+ def to_dict(self) -> dict[str, Any]:
20
+ return asdict(self)
21
+
22
+
23
+ @dataclass
24
+ class AnalysisBlock:
25
+ """One observation unit with epistemic classification.
26
+
27
+ Groups claim IDs by their epistemic role so the renderer can
28
+ present facts, cases, interpretations, limitations, and actions
29
+ in a fixed structure instead of prose.
30
+ """
31
+
32
+ block_id: str
33
+ title: str
34
+ # Claim IDs by epistemic role
35
+ fact_claim_ids: list[str] = field(default_factory=list) # epistemic_type=observed, evidence_relation=direct
36
+ case_claim_ids: list[str] = field(default_factory=list) # evidence_relation=analogous
37
+ interpretation_claim_ids: list[str] = field(default_factory=list) # epistemic_type=hypothesis or interpreted
38
+ limitation_claim_ids: list[str] = field(default_factory=list) # claims with limitations
39
+ action_claim_ids: list[str] = field(default_factory=list) # epistemic_type=action WITH direct evidence
40
+ to_verify_claim_ids: list[str] = field(default_factory=list) # action without evidence, or hypothesis
41
+ # Metadata
42
+ applicability_note: str = ""
43
+ verification_path: str = ""
44
+ confidence: float = 0.0
45
+ # PR 3: comparable case boundary
46
+ case_applicability: CaseApplicability | None = None
47
+
48
+ def to_dict(self) -> dict[str, Any]:
49
+ data = asdict(self)
50
+ if self.case_applicability:
51
+ data["case_applicability"] = self.case_applicability.to_dict()
52
+ return data
@@ -0,0 +1,8 @@
1
+ """Analysis Modules — pluggable post-Screener analysis pipeline extensions.
2
+
3
+ Each module consumes a screened ClaimLedger and produces structured artifacts
4
+ (AnalysisCards, events, coverage reports, etc.) before the Analyst agent
5
+ writes the final brief. Modules are registered in MODULE_REGISTRY and enabled
6
+ via config.yaml's ``modules`` section.
7
+ """
8
+
@@ -0,0 +1,87 @@
1
+ """Pluggable Analysis Module interface.
2
+
3
+ AnalysisModules run between Screener and Analyst in the pipeline.
4
+ They consume a screened ClaimLedger and produce structured artifacts
5
+ (analysis cards, events, coverage reports, etc.) — deterministically,
6
+ without external model calls. LLM subagents consume the artifacts
7
+ later to generate the final human-readable analysis.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from abc import ABC, abstractmethod
13
+ from dataclasses import dataclass, field
14
+ from typing import Any, TYPE_CHECKING
15
+
16
+ from multi_agent_brief.core.schemas import AuditFinding
17
+
18
+ if TYPE_CHECKING:
19
+ from multi_agent_brief.core.claim_ledger import ClaimLedger
20
+ from multi_agent_brief.core.schemas import PipelineContext
21
+
22
+
23
+ @dataclass
24
+ class ModuleOutput:
25
+ """Output from a single AnalysisModule.analyze() call."""
26
+
27
+ module_name: str
28
+ artifacts: dict[str, Any] = field(default_factory=dict)
29
+ findings: list[AuditFinding] = field(default_factory=list)
30
+ metadata: dict[str, Any] = field(default_factory=dict)
31
+
32
+ def to_dict(self) -> dict[str, Any]:
33
+ return {
34
+ "module_name": self.module_name,
35
+ "artifacts": self.artifacts,
36
+ "findings": [f.to_dict() for f in self.findings],
37
+ "metadata": self.metadata,
38
+ }
39
+
40
+
41
+ class AnalysisModule(ABC):
42
+ """Abstract base class for pluggable analysis modules.
43
+
44
+ Each module must provide:
45
+
46
+ - ``name`` — unique string key (e.g. ``"market_competitor"``).
47
+ - ``validate_config(config: dict) -> list[str]`` — return a list of
48
+ human-readable config errors (empty = valid).
49
+ - ``analyze(context, ledger) -> ModuleOutput`` — run the module's
50
+ deterministic analysis pass.
51
+ """
52
+
53
+ name: str = ""
54
+
55
+ @abstractmethod
56
+ def validate_config(self, config: dict[str, Any]) -> list[str]:
57
+ """Validate module-specific configuration.
58
+
59
+ Args:
60
+ config: The module's section from config.yaml's ``modules`` block
61
+ (e.g. ``config["modules"]["market_competitor"]``), or an
62
+ empty dict if not present.
63
+
64
+ Returns:
65
+ A list of error messages. An empty list means "valid".
66
+ """
67
+ raise NotImplementedError
68
+
69
+ @abstractmethod
70
+ def analyze(
71
+ self,
72
+ context: "PipelineContext",
73
+ ledger: "ClaimLedger",
74
+ ) -> ModuleOutput:
75
+ """Run the module's analysis on a screened ClaimLedger.
76
+
77
+ Modules MUST NOT modify the ClaimLedger — only read it.
78
+ Modules MUST NOT make external model/API calls — deterministic only.
79
+
80
+ Args:
81
+ context: The pipeline context containing sources, metadata, etc.
82
+ ledger: The screened ClaimLedger (post-Screener).
83
+
84
+ Returns:
85
+ A ModuleOutput with artifacts, findings, and metadata.
86
+ """
87
+ raise NotImplementedError
@@ -0,0 +1,68 @@
1
+ """Market & Competitor Intelligence Analysis Module.
2
+
3
+ Pluggable analysis module that transforms Claim Ledger entries into structured
4
+ competitive intelligence artifacts:
5
+ - MarketEvent — source-grounded competitor/market events
6
+ - AnalysisCard — multi-source analytical judgments (LLM-generated)
7
+ - CompetitorMatrix — entity × dimension comparison table
8
+ - CoverageReport — entity/dimension coverage gaps
9
+ - Watchlist — cross-period tracking items
10
+ """
11
+ from __future__ import annotations
12
+
13
+ from pathlib import Path
14
+ from typing import Any
15
+
16
+ from multi_agent_brief.analysis_modules.base import AnalysisModule, ModuleOutput
17
+ from multi_agent_brief.analysis_modules.market_competitor.config import (
18
+ load_competitor_universe,
19
+ )
20
+ from multi_agent_brief.analysis_modules.market_competitor.event_builder import (
21
+ build_events,
22
+ )
23
+ from multi_agent_brief.analysis_modules.market_competitor.renderer import render_all
24
+ from multi_agent_brief.core.claim_ledger import ClaimLedger
25
+ from multi_agent_brief.core.schemas import PipelineContext
26
+
27
+
28
+ class MarketCompetitorModule(AnalysisModule):
29
+ name = "market_competitor"
30
+
31
+ def validate_config(self, config: dict[str, Any]) -> list[str]:
32
+ errors: list[str] = []
33
+ if not isinstance(config, dict):
34
+ errors.append("market_competitor config must be a dict")
35
+ return errors
36
+ return errors
37
+
38
+ def analyze(self, context: PipelineContext, ledger: ClaimLedger) -> ModuleOutput:
39
+ config_dir = context.metadata.get("_config_dir", "")
40
+ output_dir = Path(context.output_dir)
41
+
42
+ # Load universe
43
+ universe_path = Path(config_dir) / "competitor_universe.yaml" if config_dir else None
44
+ universe = None
45
+ if universe_path and universe_path.exists():
46
+ universe = load_competitor_universe(universe_path)
47
+
48
+ if universe is None or not universe.enabled or not universe.entities:
49
+ return ModuleOutput(
50
+ module_name=self.name,
51
+ metadata={"status": "disabled", "reason": "no_entities"},
52
+ )
53
+
54
+ # Build events from entity-tagged claims
55
+ state_dir = str(Path(config_dir).parent / "state") if config_dir else None
56
+ events = build_events(ledger, universe, state_dir=state_dir)
57
+
58
+ # Render artifacts
59
+ artifact_paths = render_all(events, ledger, universe, output_dir)
60
+
61
+ return ModuleOutput(
62
+ module_name=self.name,
63
+ artifacts=artifact_paths,
64
+ metadata={
65
+ "event_count": len(events),
66
+ "entity_count": len(universe.entities),
67
+ },
68
+ )