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,683 @@
1
+ """Human adjudication records for Semantic Support Auditor proposals."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import uuid
6
+ from pathlib import Path
7
+ from typing import Any, Mapping
8
+
9
+ from multi_agent_brief.orchestrator.runtime_state._io import (
10
+ _read_json_if_exists,
11
+ _read_state_bytes,
12
+ _restore_state_bytes,
13
+ _write_json_atomic,
14
+ )
15
+ from multi_agent_brief.orchestrator.runtime_state.errors import (
16
+ E_ARTIFACT_INVALID,
17
+ E_RUNTIME_STATE_NOT_INITIALIZED,
18
+ E_TRANSACTION_INTEGRITY,
19
+ RuntimeStateError,
20
+ )
21
+ from multi_agent_brief.orchestrator.runtime_state.event_log import append_event, read_event_log_records_strict
22
+ from multi_agent_brief.orchestrator.runtime_state.identity import _validate_runtime_run_id, utc_now
23
+ from multi_agent_brief.orchestrator.runtime_state.manifest import RUNTIME_MANIFEST_SCHEMA
24
+ from multi_agent_brief.orchestrator.runtime_state.paths import runtime_state_paths
25
+ from multi_agent_brief.orchestrator.runtime_state.semantic_assessment_report import (
26
+ build_semantic_assessment_checked_inputs,
27
+ project_semantic_assessment_report_from_workspace,
28
+ )
29
+
30
+
31
+ SEMANTIC_SUPPORT_ACCEPTANCE_LEDGER_SCHEMA = "briefloop.semantic_support_acceptance_ledger.v1"
32
+ SEMANTIC_SUPPORT_ACCEPTANCE_BOUNDARY = (
33
+ "human_semantic_support_adjudication_records_only_not_gate_or_release_authority"
34
+ )
35
+ SEMANTIC_SUPPORT_ACCEPTANCE_DECISIONS = {"accept", "reject"}
36
+ SEMANTIC_SUPPORT_ACCEPTANCE_FORBIDDEN_AUTHORITY_KEYS = {
37
+ "accepted_support_truth",
38
+ "approve_delivery",
39
+ "block_delivery",
40
+ "block_release",
41
+ "delivery_approval",
42
+ "gate_decision",
43
+ "repair_route",
44
+ "release_authority",
45
+ "semantic_truth_proof",
46
+ "writes_claim_support_matrix",
47
+ "writes_gate_report",
48
+ "writes_workflow_state",
49
+ }
50
+
51
+
52
+ def semantic_support_acceptance_ledger_path(workspace: str | Path) -> Path:
53
+ return (
54
+ Path(workspace).expanduser().resolve()
55
+ / "output"
56
+ / "intermediate"
57
+ / "semantic_support_acceptance_ledger.json"
58
+ )
59
+
60
+
61
+ def bind_semantic_assessment_checked_inputs_transaction(*, workspace: str | Path) -> dict[str, Any]:
62
+ """Seal a Semantic Assessment Report's checked inputs exactly once.
63
+
64
+ The Semantic Support Auditor writes proposal rows. This deterministic
65
+ transaction binds that report to the workspace inputs that were present at
66
+ seal time. Human adjudication later reads the binding but never writes it.
67
+ """
68
+
69
+ ws = Path(workspace).expanduser().resolve()
70
+ run_id = _current_run_id(ws)
71
+ paths = runtime_state_paths(ws)
72
+ report_path = ws / "output" / "intermediate" / "semantic_assessment_report.json"
73
+ snapshots = {
74
+ report_path: _read_state_bytes(report_path),
75
+ paths["event_log"]: _read_state_bytes(paths["event_log"]),
76
+ }
77
+ try:
78
+ _validated_event_log_for_current_run(ws, run_id=run_id)
79
+ report = _read_json_if_exists(report_path)
80
+ if not isinstance(report, dict):
81
+ raise RuntimeStateError(
82
+ "semantic_assessment_report.json is missing or not an object; nothing to bind.",
83
+ details={"path": str(report_path)},
84
+ error_code=E_ARTIFACT_INVALID,
85
+ )
86
+ existing = report.get("checked_inputs")
87
+ if isinstance(existing, dict) and existing:
88
+ projection = project_semantic_assessment_report_from_workspace(ws)
89
+ if projection.get("status") == "valid" and projection.get("checked_inputs_status") == "fresh":
90
+ return _bind_result(
91
+ bound=False,
92
+ reason="already_bound",
93
+ projection=projection,
94
+ event_id="",
95
+ )
96
+ raise RuntimeStateError(
97
+ "semantic_assessment_report.json already declares checked_inputs that are not fresh; rerun the Semantic Support Auditor instead of rebinding.",
98
+ details={
99
+ "status": projection.get("status"),
100
+ "reason": projection.get("reason"),
101
+ "checked_inputs_status": projection.get("checked_inputs_status"),
102
+ },
103
+ error_code=E_ARTIFACT_INVALID,
104
+ )
105
+ try:
106
+ report["checked_inputs"] = build_semantic_assessment_checked_inputs(ws)
107
+ except (FileNotFoundError, OSError) as exc:
108
+ raise RuntimeStateError(
109
+ "semantic_assessment_report.json cannot be bound to checked inputs because a required input is missing or unreadable.",
110
+ details={"reason": str(exc)},
111
+ error_code=E_ARTIFACT_INVALID,
112
+ ) from exc
113
+ _write_json_atomic(report_path, report)
114
+ projection = project_semantic_assessment_report_from_workspace(ws)
115
+ if projection.get("status") != "valid" or projection.get("checked_inputs_status") != "fresh":
116
+ raise RuntimeStateError(
117
+ "semantic_assessment_report.json did not project as fresh after checked_inputs binding.",
118
+ details={
119
+ "status": projection.get("status"),
120
+ "reason": projection.get("reason"),
121
+ "checked_inputs_status": projection.get("checked_inputs_status"),
122
+ },
123
+ error_code=E_ARTIFACT_INVALID,
124
+ )
125
+ event = append_event(
126
+ workspace=ws,
127
+ run_id=run_id,
128
+ event_type="semantic_assessment_checked_inputs_bound",
129
+ actor="cli",
130
+ artifact_id="semantic_assessment_report",
131
+ reason="Bound semantic_assessment_report.json checked_inputs for human adjudication.",
132
+ metadata={
133
+ "semantic_assessment_report_sha256": _clean_text(projection.get("report_sha256")),
134
+ "checked_inputs_digest": _clean_text(projection.get("checked_inputs_digest")),
135
+ "boundary": "checked_input_binding_only_not_support_truth",
136
+ },
137
+ )
138
+ return _bind_result(
139
+ bound=True,
140
+ reason="sealed",
141
+ projection=projection,
142
+ event_id=_clean_text(event.get("event_id")),
143
+ )
144
+ except Exception:
145
+ _restore_paths(snapshots)
146
+ raise
147
+
148
+
149
+ def record_semantic_support_adjudication(
150
+ *,
151
+ workspace: str | Path,
152
+ proposal_id: str,
153
+ decision: str,
154
+ reason: str,
155
+ actor_id: str = "human",
156
+ ) -> dict[str, Any]:
157
+ """Record a human accept/reject decision for one semantic support proposal.
158
+
159
+ The transaction writes only ``semantic_support_acceptance_ledger.json`` and
160
+ an event-log record. It does not mutate the Semantic Assessment Report,
161
+ Claim-Support Matrix, gate reports, workflow state, repair routing,
162
+ delivery state, or release state.
163
+ """
164
+
165
+ ws = Path(workspace).expanduser().resolve()
166
+ run_id = _current_run_id(ws)
167
+ clean_proposal_id = _require_text(proposal_id, field="proposal_id")
168
+ clean_decision = _require_decision(decision)
169
+ clean_reason = _require_text(reason, field="reason")
170
+ clean_actor = _clean_text(actor_id) or "human"
171
+ projection = project_semantic_assessment_report_from_workspace(ws)
172
+ ledger_path = semantic_support_acceptance_ledger_path(ws)
173
+ paths = runtime_state_paths(ws)
174
+ snapshots = {
175
+ ledger_path: _read_state_bytes(ledger_path),
176
+ paths["event_log"]: _read_state_bytes(paths["event_log"]),
177
+ }
178
+ try:
179
+ result = _record_semantic_support_adjudication_with_projection(
180
+ ws=ws,
181
+ run_id=run_id,
182
+ projection=projection,
183
+ proposal_id=clean_proposal_id,
184
+ decision=clean_decision,
185
+ reason=clean_reason,
186
+ actor_id=clean_actor,
187
+ ledger_path=ledger_path,
188
+ )
189
+ return result
190
+ except Exception:
191
+ _restore_paths(snapshots)
192
+ raise
193
+
194
+
195
+ def _record_semantic_support_adjudication_with_projection(
196
+ *,
197
+ ws: Path,
198
+ run_id: str,
199
+ projection: Mapping[str, Any],
200
+ proposal_id: str,
201
+ decision: str,
202
+ reason: str,
203
+ actor_id: str,
204
+ ledger_path: Path,
205
+ ) -> dict[str, Any]:
206
+ if projection.get("status") != "valid" or projection.get("checked_inputs_status") != "fresh":
207
+ raise RuntimeStateError(
208
+ "semantic_assessment_report.json must be present, valid, and checked-input fresh before human adjudication. Run `briefloop semantic-support bind --workspace <workspace>` after the auditor writes the report.",
209
+ details={
210
+ "status": projection.get("status"),
211
+ "reason": projection.get("reason"),
212
+ "checked_inputs_status": projection.get("checked_inputs_status"),
213
+ },
214
+ error_code=E_ARTIFACT_INVALID,
215
+ )
216
+ proposal = _proposal_from_projection(projection, proposal_id)
217
+ report_sha256 = _require_text(projection.get("report_sha256"), field="semantic_assessment_report_sha256")
218
+ checked_inputs_digest = _require_text(projection.get("checked_inputs_digest"), field="checked_inputs_digest")
219
+ _validated_event_log_for_current_run(ws, run_id=run_id)
220
+ ledger = _load_or_new_ledger(ledger_path)
221
+ validation_reason = validate_semantic_support_acceptance_ledger_for_workspace(ledger, artifact_path=ledger_path)
222
+ if validation_reason:
223
+ raise RuntimeStateError(
224
+ f"semantic_support_acceptance_ledger invalid: {validation_reason}",
225
+ details={"path": str(ledger_path), "reason": validation_reason},
226
+ error_code=E_ARTIFACT_INVALID,
227
+ )
228
+ now = utc_now()
229
+ acceptance_id = f"SSA-{uuid.uuid4().hex[:12]}"
230
+ event = append_event(
231
+ workspace=ws,
232
+ run_id=run_id,
233
+ event_type="semantic_support_finding_adjudicated",
234
+ actor="cli",
235
+ artifact_id="semantic_support_acceptance_ledger",
236
+ decision=decision,
237
+ reason=f"Recorded human {decision} decision for semantic proposal {proposal_id}.",
238
+ metadata={
239
+ "acceptance_id": acceptance_id,
240
+ "proposal_id": proposal_id,
241
+ "source_row_id": _clean_text(proposal.get("source_row_id")),
242
+ "claim_id": _clean_text(proposal.get("claim_id")),
243
+ "atom_id": _clean_text(proposal.get("atom_id")),
244
+ "calibration_label": _clean_text(proposal.get("calibration_label")),
245
+ "actor_id_present": bool(actor_id),
246
+ "reason_present": bool(reason),
247
+ "boundary": SEMANTIC_SUPPORT_ACCEPTANCE_BOUNDARY,
248
+ "semantic_assessment_report_sha256": report_sha256,
249
+ "checked_inputs_digest": checked_inputs_digest,
250
+ },
251
+ )
252
+ record = _acceptance_record(
253
+ acceptance_id=acceptance_id,
254
+ run_id=run_id,
255
+ proposal=proposal,
256
+ semantic_assessment_report_sha256=report_sha256,
257
+ checked_inputs_digest=checked_inputs_digest,
258
+ decision=decision,
259
+ reason=reason,
260
+ actor_id=actor_id,
261
+ recorded_at=now,
262
+ event_id=str(event["event_id"]),
263
+ )
264
+ ledger.setdefault("records", []).append(record)
265
+ ledger["updated_at"] = now
266
+ _write_json_atomic(ledger_path, ledger)
267
+ return {
268
+ "ok": True,
269
+ "schema_version": "briefloop.semantic_support_adjudication_result.v1",
270
+ "boundary": SEMANTIC_SUPPORT_ACCEPTANCE_BOUNDARY,
271
+ "ledger_path": "output/intermediate/semantic_support_acceptance_ledger.json",
272
+ "acceptance_id": acceptance_id,
273
+ "proposal_id": proposal_id,
274
+ "decision": decision,
275
+ "event_id": event["event_id"],
276
+ "authority_effects": _no_authority_effects(),
277
+ }
278
+
279
+ def validate_semantic_support_acceptance_ledger_payload(payload: Any) -> str | None:
280
+ if not isinstance(payload, Mapping):
281
+ return "not_object"
282
+ if payload.get("schema_version") != SEMANTIC_SUPPORT_ACCEPTANCE_LEDGER_SCHEMA:
283
+ return "schema_version"
284
+ if payload.get("boundary") != SEMANTIC_SUPPORT_ACCEPTANCE_BOUNDARY:
285
+ return "boundary"
286
+ for key in SEMANTIC_SUPPORT_ACCEPTANCE_FORBIDDEN_AUTHORITY_KEYS:
287
+ if payload.get(key) not in (None, False, [], {}, ""):
288
+ return f"forbidden_authority_key:{key}"
289
+ effects_reason = _authority_effects_error(payload.get("authority_effects"))
290
+ if effects_reason:
291
+ return f"authority_effects.{effects_reason}"
292
+ records = payload.get("records")
293
+ if not isinstance(records, list):
294
+ return "records"
295
+ for idx, record in enumerate(records):
296
+ reason = _validate_acceptance_record(record)
297
+ if reason:
298
+ return f"records[{idx}].{reason}"
299
+ return None
300
+
301
+
302
+ def _bind_result(
303
+ *,
304
+ bound: bool,
305
+ reason: str,
306
+ projection: Mapping[str, Any],
307
+ event_id: str,
308
+ ) -> dict[str, Any]:
309
+ return {
310
+ "ok": True,
311
+ "schema_version": "briefloop.semantic_assessment_checked_inputs_bind_result.v1",
312
+ "boundary": "checked_input_binding_only_not_support_truth",
313
+ "path": "output/intermediate/semantic_assessment_report.json",
314
+ "bound": bound,
315
+ "reason": reason,
316
+ "event_id": event_id,
317
+ "status": projection.get("status"),
318
+ "checked_inputs_status": projection.get("checked_inputs_status"),
319
+ "semantic_assessment_report_sha256": _clean_text(projection.get("report_sha256")),
320
+ "checked_inputs_digest": _clean_text(projection.get("checked_inputs_digest")),
321
+ "authority_effects": _no_authority_effects(),
322
+ }
323
+
324
+
325
+ def validate_semantic_support_acceptance_ledger_for_workspace(
326
+ payload: Any,
327
+ *,
328
+ artifact_path: str | Path,
329
+ ) -> str | None:
330
+ reason = validate_semantic_support_acceptance_ledger_payload(payload)
331
+ if reason:
332
+ return reason
333
+ assert isinstance(payload, Mapping)
334
+ artifact = Path(artifact_path).expanduser().resolve()
335
+ workspace = _workspace_from_ledger_path(artifact)
336
+ proposal_ids, reason = _workspace_proposal_ids(workspace)
337
+ if reason:
338
+ return reason
339
+ try:
340
+ events = read_event_log_records_strict(runtime_state_paths(workspace)["event_log"])
341
+ except RuntimeStateError as exc:
342
+ return f"event_log_invalid:{exc.error_code or 'read_error'}"
343
+ event_index = {
344
+ _clean_text(event.get("event_id")): event
345
+ for event in events
346
+ if _clean_text(event.get("event_id"))
347
+ }
348
+ records = payload.get("records")
349
+ for idx, record in enumerate(records if isinstance(records, list) else []):
350
+ if not isinstance(record, Mapping):
351
+ return f"records[{idx}].not_object"
352
+ proposal_id = _clean_text(record.get("proposal_id"))
353
+ if proposal_id not in proposal_ids:
354
+ return f"records[{idx}].proposal_missing:{proposal_id}"
355
+ reason = _event_link_error(record, event_index)
356
+ if reason:
357
+ return f"records[{idx}].{reason}"
358
+ if _record_has_current_linkage(record):
359
+ effectiveness = semantic_support_acceptance_record_current_effectiveness(record, workspace=workspace)
360
+ if not effectiveness.get("current_effective"):
361
+ reason = _clean_text(effectiveness.get("reason")) or "semantic_assessment_report_not_current"
362
+ return f"records[{idx}].current_effectiveness:{reason}"
363
+ return None
364
+
365
+
366
+ def semantic_support_acceptance_record_current_effectiveness(
367
+ record: Mapping[str, Any],
368
+ *,
369
+ workspace: str | Path,
370
+ ) -> dict[str, Any]:
371
+ """Return whether a historical adjudication still matches current SAR inputs."""
372
+
373
+ ws = Path(workspace).expanduser().resolve()
374
+ projection = project_semantic_assessment_report_from_workspace(ws)
375
+ if projection.get("status") != "valid" or projection.get("checked_inputs_status") != "fresh":
376
+ return {
377
+ "current_effective": False,
378
+ "reason": _clean_text(projection.get("reason"))
379
+ or _clean_text(projection.get("checked_inputs_status"))
380
+ or _clean_text(projection.get("status"))
381
+ or "semantic_assessment_report_not_current",
382
+ }
383
+ record_report_sha = _clean_text(record.get("semantic_assessment_report_sha256"))
384
+ if not record_report_sha:
385
+ return {"current_effective": False, "reason": "record_missing_semantic_assessment_report_sha256"}
386
+ if record_report_sha != _clean_text(projection.get("report_sha256")):
387
+ return {"current_effective": False, "reason": "semantic_assessment_report_sha256_changed"}
388
+ record_digest = _clean_text(record.get("checked_inputs_digest"))
389
+ if not record_digest:
390
+ return {"current_effective": False, "reason": "record_missing_checked_inputs_digest"}
391
+ if record_digest != _clean_text(projection.get("checked_inputs_digest")):
392
+ return {"current_effective": False, "reason": "checked_inputs_digest_changed"}
393
+ proposals = projection.get("proposed_claim_support_rows")
394
+ proposal_ids: set[str] = set()
395
+ for proposal in proposals if isinstance(proposals, list) else []:
396
+ if isinstance(proposal, Mapping):
397
+ proposal_ids.add(_clean_text(proposal.get("proposal_id")))
398
+ proposal_id = _clean_text(record.get("proposal_id"))
399
+ if proposal_id not in proposal_ids:
400
+ return {"current_effective": False, "reason": f"proposal_missing:{proposal_id}"}
401
+ return {"current_effective": True, "reason": None}
402
+
403
+
404
+ def _record_has_current_linkage(record: Mapping[str, Any]) -> bool:
405
+ return any(
406
+ _clean_text(record.get(field))
407
+ for field in ("semantic_assessment_report_sha256", "checked_inputs_digest")
408
+ )
409
+
410
+
411
+ def _validate_acceptance_record(record: Any) -> str | None:
412
+ if not isinstance(record, Mapping):
413
+ return "not_object"
414
+ for key in SEMANTIC_SUPPORT_ACCEPTANCE_FORBIDDEN_AUTHORITY_KEYS:
415
+ if record.get(key) not in (None, False, [], {}, ""):
416
+ return f"forbidden_authority_key:{key}"
417
+ for field in (
418
+ "acceptance_id",
419
+ "run_id",
420
+ "proposal_id",
421
+ "decision",
422
+ "reason",
423
+ "actor_id",
424
+ "recorded_at",
425
+ "event_id",
426
+ ):
427
+ if not _clean_text(record.get(field)):
428
+ return field
429
+ for field in ("semantic_assessment_report_sha256", "checked_inputs_digest"):
430
+ if field in record and not _clean_text(record.get(field)):
431
+ return field
432
+ if record.get("decision") not in SEMANTIC_SUPPORT_ACCEPTANCE_DECISIONS:
433
+ return "decision"
434
+ if record.get("boundary") != SEMANTIC_SUPPORT_ACCEPTANCE_BOUNDARY:
435
+ return "boundary"
436
+ effects = record.get("authority_effects")
437
+ effects_reason = _authority_effects_error(effects)
438
+ if effects_reason:
439
+ return f"authority_effects.{effects_reason}"
440
+ return None
441
+
442
+
443
+ def _authority_effects_error(effects: Any) -> str | None:
444
+ if not isinstance(effects, Mapping):
445
+ return "not_object"
446
+ allowed = set(_no_authority_effects())
447
+ for key, value in effects.items():
448
+ if key not in allowed:
449
+ return f"unknown_key:{key}"
450
+ if value is not False:
451
+ return str(key)
452
+ for key in allowed:
453
+ if effects.get(key) is not False:
454
+ return str(key)
455
+ return None
456
+
457
+
458
+ def _validated_event_log_for_current_run(workspace: Path, *, run_id: str) -> list[Mapping[str, Any]]:
459
+ event_path = runtime_state_paths(workspace)["event_log"]
460
+ if not event_path.exists():
461
+ raise RuntimeStateError(
462
+ "event_log.jsonl is required before semantic support adjudication.",
463
+ details={"path": str(event_path)},
464
+ error_code=E_TRANSACTION_INTEGRITY,
465
+ )
466
+ events = read_event_log_records_strict(event_path)
467
+ if not any(
468
+ _clean_text(event.get("run_id")) == run_id
469
+ and _clean_text(event.get("event_type")) in {"run_initialized", "run_reset"}
470
+ for event in events
471
+ ):
472
+ raise RuntimeStateError(
473
+ "event_log.jsonl does not contain a current-run initialization event.",
474
+ details={"path": str(event_path), "run_id": run_id},
475
+ error_code=E_TRANSACTION_INTEGRITY,
476
+ )
477
+ return events
478
+
479
+
480
+ def _workspace_from_ledger_path(path: Path) -> Path:
481
+ # Expected path: <workspace>/output/intermediate/semantic_support_acceptance_ledger.json
482
+ if path.parent.name == "intermediate" and path.parent.parent.name == "output":
483
+ return path.parent.parent.parent
484
+ return path.parent
485
+
486
+
487
+ def _workspace_proposal_ids(workspace: Path) -> tuple[set[str], str | None]:
488
+ projection = project_semantic_assessment_report_from_workspace(workspace)
489
+ if projection.get("status") in {"not_available", "invalid_report"}:
490
+ reason = _clean_text(projection.get("reason")) or _clean_text(projection.get("status")) or "invalid_report"
491
+ return set(), f"semantic_assessment_report_invalid:{reason}"
492
+ proposals = projection.get("proposed_claim_support_rows")
493
+ proposal_ids: set[str] = set()
494
+ for proposal in proposals if isinstance(proposals, list) else []:
495
+ if not isinstance(proposal, Mapping):
496
+ continue
497
+ proposal_id = _clean_text(proposal.get("proposal_id"))
498
+ if proposal_id:
499
+ proposal_ids.add(proposal_id)
500
+ return proposal_ids, None
501
+
502
+
503
+ def _event_link_error(record: Mapping[str, Any], event_index: Mapping[str, Mapping[str, Any]]) -> str | None:
504
+ event_id = _clean_text(record.get("event_id"))
505
+ event = event_index.get(event_id)
506
+ if event is None:
507
+ return f"event_missing:{event_id}"
508
+ if _clean_text(event.get("event_type")) != "semantic_support_finding_adjudicated":
509
+ return "event_type_mismatch"
510
+ if _clean_text(event.get("artifact_id")) != "semantic_support_acceptance_ledger":
511
+ return "event_artifact_mismatch"
512
+ if _clean_text(event.get("run_id")) != _clean_text(record.get("run_id")):
513
+ return "event_run_id_mismatch"
514
+ if _clean_text(event.get("decision")) != _clean_text(record.get("decision")):
515
+ return "event_decision_mismatch"
516
+ metadata = event.get("metadata") if isinstance(event.get("metadata"), Mapping) else {}
517
+ for field in ("acceptance_id", "proposal_id", "boundary"):
518
+ if _clean_text(metadata.get(field)) != _clean_text(record.get(field)):
519
+ return f"event_metadata_mismatch:{field}"
520
+ for field in ("semantic_assessment_report_sha256", "checked_inputs_digest"):
521
+ record_value = _clean_text(record.get(field))
522
+ metadata_value = _clean_text(metadata.get(field))
523
+ if (record_value or metadata_value) and metadata_value != record_value:
524
+ return f"event_metadata_mismatch:{field}"
525
+ return None
526
+
527
+
528
+ def _current_run_id(workspace: Path) -> str:
529
+ paths = runtime_state_paths(workspace)
530
+ manifest = _read_json_if_exists(paths["runtime_manifest"])
531
+ workflow = _read_json_if_exists(paths["workflow_state"])
532
+ if manifest is None or workflow is None:
533
+ raise RuntimeStateError(
534
+ "Runtime state is not initialized. Run `multi-agent-brief state init --workspace <workspace>` first.",
535
+ details={"workspace": str(workspace)},
536
+ error_code=E_RUNTIME_STATE_NOT_INITIALIZED,
537
+ )
538
+ if manifest.get("schema_version") != RUNTIME_MANIFEST_SCHEMA:
539
+ raise RuntimeStateError(
540
+ "runtime_manifest.json has an unsupported schema.",
541
+ details={"path": str(paths["runtime_manifest"]), "schema_version": manifest.get("schema_version")},
542
+ error_code=E_TRANSACTION_INTEGRITY,
543
+ )
544
+ run_id = _validate_runtime_run_id(manifest.get("run_id"), path=paths["runtime_manifest"])
545
+ if workflow.get("run_id") and _clean_text(workflow.get("run_id")) != run_id:
546
+ raise RuntimeStateError(
547
+ "workflow_state.json run_id does not match runtime_manifest.json.",
548
+ details={"manifest_run_id": run_id, "workflow_run_id": workflow.get("run_id")},
549
+ error_code=E_TRANSACTION_INTEGRITY,
550
+ )
551
+ return run_id
552
+
553
+
554
+ def _proposal_for_workspace(workspace: Path, proposal_id: str) -> Mapping[str, Any]:
555
+ projection = project_semantic_assessment_report_from_workspace(workspace)
556
+ if projection.get("status") != "valid":
557
+ raise RuntimeStateError(
558
+ "semantic_assessment_report.json must be present and valid before human adjudication.",
559
+ details={
560
+ "status": projection.get("status"),
561
+ "reason": projection.get("reason"),
562
+ },
563
+ error_code=E_ARTIFACT_INVALID,
564
+ )
565
+ return _proposal_from_projection(projection, proposal_id)
566
+
567
+
568
+ def _proposal_from_projection(projection: Mapping[str, Any], proposal_id: str) -> Mapping[str, Any]:
569
+ proposals = projection.get("proposed_claim_support_rows")
570
+ for proposal in proposals if isinstance(proposals, list) else []:
571
+ if isinstance(proposal, Mapping) and _clean_text(proposal.get("proposal_id")) == proposal_id:
572
+ return proposal
573
+ raise RuntimeStateError(
574
+ f"Semantic support proposal not found: {proposal_id}",
575
+ details={"proposal_id": proposal_id},
576
+ error_code=E_ARTIFACT_INVALID,
577
+ )
578
+
579
+
580
+ def _load_or_new_ledger(path: Path) -> dict[str, Any]:
581
+ payload = _read_json_if_exists(path)
582
+ if payload is None:
583
+ return _new_ledger()
584
+ return payload
585
+
586
+
587
+ def _new_ledger() -> dict[str, Any]:
588
+ now = utc_now()
589
+ return {
590
+ "schema_version": SEMANTIC_SUPPORT_ACCEPTANCE_LEDGER_SCHEMA,
591
+ "boundary": SEMANTIC_SUPPORT_ACCEPTANCE_BOUNDARY,
592
+ "created_at": now,
593
+ "updated_at": now,
594
+ "records": [],
595
+ "authority_effects": _no_authority_effects(),
596
+ }
597
+
598
+
599
+ def _acceptance_record(
600
+ *,
601
+ acceptance_id: str,
602
+ run_id: str,
603
+ proposal: Mapping[str, Any],
604
+ semantic_assessment_report_sha256: str,
605
+ checked_inputs_digest: str,
606
+ decision: str,
607
+ reason: str,
608
+ actor_id: str,
609
+ recorded_at: str,
610
+ event_id: str,
611
+ ) -> dict[str, Any]:
612
+ return {
613
+ "acceptance_id": acceptance_id,
614
+ "run_id": run_id,
615
+ "proposal_id": _clean_text(proposal.get("proposal_id")),
616
+ "source_row_id": _clean_text(proposal.get("source_row_id")),
617
+ "claim_id": _clean_text(proposal.get("claim_id")),
618
+ "atom_id": _clean_text(proposal.get("atom_id")),
619
+ "evidence_span_id": _clean_text(proposal.get("evidence_span_id")),
620
+ "calibration_label": _clean_text(proposal.get("calibration_label")),
621
+ "proposed_support_label": _clean_text(proposal.get("proposed_support_label")),
622
+ "semantic_assessment_report_sha256": semantic_assessment_report_sha256,
623
+ "checked_inputs_digest": checked_inputs_digest,
624
+ "decision": decision,
625
+ "reason": reason,
626
+ "actor_id": actor_id,
627
+ "recorded_at": recorded_at,
628
+ "event_id": event_id,
629
+ "boundary": SEMANTIC_SUPPORT_ACCEPTANCE_BOUNDARY,
630
+ "authority_effects": _no_authority_effects(),
631
+ }
632
+
633
+
634
+ def _no_authority_effects() -> dict[str, bool]:
635
+ return {
636
+ "writes_claim_support_matrix": False,
637
+ "writes_gate_report": False,
638
+ "writes_workflow_state": False,
639
+ "creates_repair_route": False,
640
+ "approves_delivery": False,
641
+ "authorizes_release": False,
642
+ }
643
+
644
+
645
+ def _restore_paths(snapshots: Mapping[Path, bytes | None]) -> None:
646
+ rollback_errors: list[dict[str, str]] = []
647
+ for path, data in snapshots.items():
648
+ try:
649
+ _restore_state_bytes(path, data)
650
+ except RuntimeStateError as exc:
651
+ rollback_errors.append({"path": str(path), "reason": str(exc)})
652
+ if rollback_errors:
653
+ raise RuntimeStateError(
654
+ "Semantic support transaction rollback failed after partial write.",
655
+ details={"rollback_errors": rollback_errors},
656
+ error_code=E_TRANSACTION_INTEGRITY,
657
+ )
658
+
659
+
660
+ def _require_decision(value: Any) -> str:
661
+ text = _require_text(value, field="decision")
662
+ if text not in SEMANTIC_SUPPORT_ACCEPTANCE_DECISIONS:
663
+ raise RuntimeStateError(
664
+ f"Unsupported semantic support adjudication decision: {text}",
665
+ details={"decision": text, "allowed_values": sorted(SEMANTIC_SUPPORT_ACCEPTANCE_DECISIONS)},
666
+ error_code=E_ARTIFACT_INVALID,
667
+ )
668
+ return text
669
+
670
+
671
+ def _require_text(value: Any, *, field: str) -> str:
672
+ text = _clean_text(value)
673
+ if not text:
674
+ raise RuntimeStateError(
675
+ f"semantic support adjudication requires {field}.",
676
+ details={"field": field},
677
+ error_code=E_ARTIFACT_INVALID,
678
+ )
679
+ return text
680
+
681
+
682
+ def _clean_text(value: Any) -> str:
683
+ return value.strip() if isinstance(value, str) else ""