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.
- briefloop-0.11.12.dist-info/METADATA +473 -0
- briefloop-0.11.12.dist-info/RECORD +424 -0
- briefloop-0.11.12.dist-info/WHEEL +5 -0
- briefloop-0.11.12.dist-info/entry_points.txt +3 -0
- briefloop-0.11.12.dist-info/licenses/LICENSE +22 -0
- briefloop-0.11.12.dist-info/top_level.txt +1 -0
- multi_agent_brief/__init__.py +36 -0
- multi_agent_brief/analysis_blocks/__init__.py +11 -0
- multi_agent_brief/analysis_blocks/builder.py +206 -0
- multi_agent_brief/analysis_blocks/renderer.py +237 -0
- multi_agent_brief/analysis_blocks/schemas.py +52 -0
- multi_agent_brief/analysis_modules/__init__.py +8 -0
- multi_agent_brief/analysis_modules/base.py +87 -0
- multi_agent_brief/analysis_modules/market_competitor/__init__.py +68 -0
- multi_agent_brief/analysis_modules/market_competitor/auditor.py +290 -0
- multi_agent_brief/analysis_modules/market_competitor/config.py +187 -0
- multi_agent_brief/analysis_modules/market_competitor/event_builder.py +226 -0
- multi_agent_brief/analysis_modules/market_competitor/renderer.py +199 -0
- multi_agent_brief/analysis_modules/market_competitor/schemas.py +518 -0
- multi_agent_brief/analysis_modules/policy_regulatory/__init__.py +7 -0
- multi_agent_brief/analysis_modules/policy_regulatory/audit.py +195 -0
- multi_agent_brief/analysis_modules/policy_regulatory/module.py +387 -0
- multi_agent_brief/analysis_modules/policy_regulatory/schemas.py +129 -0
- multi_agent_brief/analysis_modules/registry.py +73 -0
- multi_agent_brief/audience/__init__.py +19 -0
- multi_agent_brief/audience/profiles.py +246 -0
- multi_agent_brief/audience_memory/__init__.py +23 -0
- multi_agent_brief/audience_memory/profile.py +358 -0
- multi_agent_brief/audit/__init__.py +36 -0
- multi_agent_brief/audit/case_applicability.py +181 -0
- multi_agent_brief/audit/deterministic.py +471 -0
- multi_agent_brief/audit/editorial_governance.py +404 -0
- multi_agent_brief/audit/final_quality.py +764 -0
- multi_agent_brief/audit/harness.py +242 -0
- multi_agent_brief/audit/interfaces.py +96 -0
- multi_agent_brief/audit/limitation_hygiene.py +238 -0
- multi_agent_brief/audit/proposal_boundary.py +34 -0
- multi_agent_brief/audit/redaction.py +27 -0
- multi_agent_brief/audit/rule_packs.py +96 -0
- multi_agent_brief/audit/semantic.py +435 -0
- multi_agent_brief/capabilities/__init__.py +22 -0
- multi_agent_brief/capabilities/catalog.py +215 -0
- multi_agent_brief/capabilities/detect.py +199 -0
- multi_agent_brief/capabilities/models.py +60 -0
- multi_agent_brief/capabilities/recommend.py +206 -0
- multi_agent_brief/cli/__init__.py +2 -0
- multi_agent_brief/cli/analysis_commands.py +140 -0
- multi_agent_brief/cli/approval_commands.py +107 -0
- multi_agent_brief/cli/audit_commands.py +59 -0
- multi_agent_brief/cli/capability_commands.py +548 -0
- multi_agent_brief/cli/claude_commands.py +159 -0
- multi_agent_brief/cli/competitors_commands.py +182 -0
- multi_agent_brief/cli/controls_commands.py +137 -0
- multi_agent_brief/cli/deliver_commands.py +942 -0
- multi_agent_brief/cli/eval_cases_commands.py +99 -0
- multi_agent_brief/cli/experiments_commands.py +395 -0
- multi_agent_brief/cli/feedback_commands.py +192 -0
- multi_agent_brief/cli/finalize_commands.py +153 -0
- multi_agent_brief/cli/gates_commands.py +174 -0
- multi_agent_brief/cli/hermes_commands.py +356 -0
- multi_agent_brief/cli/improve_commands.py +224 -0
- multi_agent_brief/cli/init_commands.py +564 -0
- multi_agent_brief/cli/init_wizard.py +1473 -0
- multi_agent_brief/cli/input_commands.py +237 -0
- multi_agent_brief/cli/main.py +288 -0
- multi_agent_brief/cli/onboard_commands.py +193 -0
- multi_agent_brief/cli/product_commands.py +1449 -0
- multi_agent_brief/cli/provenance_commands.py +100 -0
- multi_agent_brief/cli/release_commands.py +68 -0
- multi_agent_brief/cli/repair_commands.py +169 -0
- multi_agent_brief/cli/run_commands.py +292 -0
- multi_agent_brief/cli/runtime_commands.py +81 -0
- multi_agent_brief/cli/secrets_commands.py +232 -0
- multi_agent_brief/cli/semantic_support_commands.py +80 -0
- multi_agent_brief/cli/sources_commands.py +647 -0
- multi_agent_brief/cli/start_commands.py +8 -0
- multi_agent_brief/cli/state_commands.py +446 -0
- multi_agent_brief/cli/status_commands.py +26 -0
- multi_agent_brief/cli/workbuddy_commands.py +103 -0
- multi_agent_brief/configs/artifact_contracts.yaml +514 -0
- multi_agent_brief/configs/orchestrator_contract.yaml +181 -0
- multi_agent_brief/configs/policy_packs/default.yaml +65 -0
- multi_agent_brief/configs/policy_profiles/evidence_extract_default.yaml +58 -0
- multi_agent_brief/configs/policy_profiles/finance_default.yaml +44 -0
- multi_agent_brief/configs/policy_profiles/internet_default.yaml +44 -0
- multi_agent_brief/configs/policy_profiles/manufacturing_default.yaml +33 -0
- multi_agent_brief/configs/policy_profiles/solar_manufacturing_default.yaml +64 -0
- multi_agent_brief/configs/report_packs/evidence_extract.yaml +48 -0
- multi_agent_brief/configs/report_packs/management_monthly.yaml +36 -0
- multi_agent_brief/configs/report_packs/market_weekly.yaml +36 -0
- multi_agent_brief/configs/report_packs/solar_industry_periodic.yaml +50 -0
- multi_agent_brief/configs/report_templates/evidence_extract.yaml +55 -0
- multi_agent_brief/configs/report_templates/management_monthly.yaml +48 -0
- multi_agent_brief/configs/report_templates/market_weekly.yaml +49 -0
- multi_agent_brief/configs/report_templates/solar_industry_periodic.yaml +75 -0
- multi_agent_brief/configs/stage_specs.yaml +180 -0
- multi_agent_brief/contracts/__init__.py +41 -0
- multi_agent_brief/contracts/base.py +99 -0
- multi_agent_brief/contracts/errors.py +41 -0
- multi_agent_brief/contracts/migrations/__init__.py +5 -0
- multi_agent_brief/contracts/migrations/claim_v1_to_v2.py +33 -0
- multi_agent_brief/contracts/registry.py +159 -0
- multi_agent_brief/contracts/role_topology.py +25 -0
- multi_agent_brief/contracts/schemas/__init__.py +35 -0
- multi_agent_brief/contracts/schemas/analysis_pack.py +135 -0
- multi_agent_brief/contracts/schemas/atomic_claim_graph.py +304 -0
- multi_agent_brief/contracts/schemas/audit_report.py +80 -0
- multi_agent_brief/contracts/schemas/candidate_item.py +51 -0
- multi_agent_brief/contracts/schemas/claim.py +197 -0
- multi_agent_brief/contracts/schemas/claim_draft.py +386 -0
- multi_agent_brief/contracts/schemas/claim_support_matrix.py +334 -0
- multi_agent_brief/contracts/schemas/evidence_span_registry.py +270 -0
- multi_agent_brief/contracts/schemas/policy_profile.py +247 -0
- multi_agent_brief/contracts/schemas/report_spec.py +257 -0
- multi_agent_brief/contracts/schemas/semantic_assessment_report.py +480 -0
- multi_agent_brief/contracts/schemas/source_evidence_pack_manifest.py +233 -0
- multi_agent_brief/contracts/schemas/source_item.py +96 -0
- multi_agent_brief/contracts/semantic_assessment_status.py +12 -0
- multi_agent_brief/contracts/source_metadata.py +252 -0
- multi_agent_brief/contracts/target_contract.py +460 -0
- multi_agent_brief/contracts/validator.py +225 -0
- multi_agent_brief/controls/__init__.py +23 -0
- multi_agent_brief/controls/contract.py +106 -0
- multi_agent_brief/controls/switchboard.py +1076 -0
- multi_agent_brief/core/__init__.py +2 -0
- multi_agent_brief/core/citations.py +14 -0
- multi_agent_brief/core/claim_ledger.py +94 -0
- multi_agent_brief/core/config.py +191 -0
- multi_agent_brief/core/env.py +69 -0
- multi_agent_brief/core/previous.py +83 -0
- multi_agent_brief/core/schemas.py +181 -0
- multi_agent_brief/core/selection.py +189 -0
- multi_agent_brief/delivery/__init__.py +6 -0
- multi_agent_brief/delivery/base.py +36 -0
- multi_agent_brief/delivery/feishu.py +204 -0
- multi_agent_brief/delivery/gws.py +237 -0
- multi_agent_brief/evaluation_cases/__init__.py +15 -0
- multi_agent_brief/evaluation_cases/contract.py +429 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/approved_guidance_materialized/workspace/config.yaml +18 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/approved_guidance_materialized/workspace/improvement/ledger.jsonl +2 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/approved_guidance_materialized/workspace/sources.yaml +2 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/approved_guidance_materialized/workspace/user.md +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/company_event_missing_latest_official_check/workspace/config.yaml +13 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/company_event_missing_latest_official_check/workspace/sources.yaml +9 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/company_event_missing_latest_official_check/workspace/user.md +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/control_switchboard_selection_is_not_execution/workspace/config.yaml +12 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/control_switchboard_selection_is_not_execution/workspace/sources.yaml +6 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/control_switchboard_selection_is_not_execution/workspace/user.md +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/feedback_triage_required/workspace/config.yaml +6 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/feedback_triage_required/workspace/input/human_feedback.md +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/feedback_triage_required/workspace/sources.yaml +2 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/feedback_triage_required/workspace/user.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/config.yaml +8 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/output/brief.md +14 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/output/intermediate/audit_report.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/output/intermediate/audited_brief.md +5 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/output/intermediate/candidate_claims.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/output/intermediate/claim_ledger.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/output/intermediate/screened_candidates.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/sources.yaml +2 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/final_abstract_quality_warning_surface/workspace/user.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/formal_release_missing_human_approval/workspace/config.yaml +13 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/formal_release_missing_human_approval/workspace/sources.yaml +9 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/formal_release_missing_human_approval/workspace/user.md +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/guidance_manifestation_not_observable/workspace/config.yaml +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/guidance_manifestation_not_observable/workspace/sources.yaml +2 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/guidance_manifestation_not_observable/workspace/user.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/media_only_legal_policy_blocks_research_review/workspace/config.yaml +13 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/media_only_legal_policy_blocks_research_review/workspace/sources.yaml +9 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/media_only_legal_policy_blocks_research_review/workspace/user.md +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/mixed_metric_scope_support_blocker/workspace/config.yaml +13 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/mixed_metric_scope_support_blocker/workspace/sources.yaml +9 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/mixed_metric_scope_support_blocker/workspace/user.md +5 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/config.yaml +6 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/output/intermediate/audited_brief.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/output/intermediate/candidate_claims.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/output/intermediate/claim_ledger.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/output/intermediate/feedback_issues.json +25 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/output/intermediate/repair_plan.json +27 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/output/intermediate/screened_candidates.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/sources.yaml +2 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/planned_blocking_issue_cannot_continue/workspace/user.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/config.yaml +8 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/output/intermediate/audit_report.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/output/intermediate/audited_brief.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/output/intermediate/candidate_claims.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/output/intermediate/claim_ledger.json +11 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/output/intermediate/quality_gate_report.json +22 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/output/intermediate/screened_candidates.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/sources.yaml +2 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/provenance_projection_minimal/workspace/user.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/config.yaml +13 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/output/intermediate/audit_report.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/output/intermediate/audited_brief.md +5 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/output/intermediate/candidate_claims.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/output/intermediate/claim_ledger.json +40 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/output/intermediate/screened_candidates.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/sources.yaml +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_source_appendix/workspace/user.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/config.yaml +8 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/output/brief.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/output/intermediate/audit_report.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/output/intermediate/audited_brief.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/output/intermediate/candidate_claims.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/output/intermediate/claim_ledger.json +13 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/output/intermediate/screened_candidates.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/sources.yaml +2 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reader_facing_target_relevance/workspace/user.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/release_readiness_forged_event_blocker/workspace/config.yaml +13 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/release_readiness_forged_event_blocker/workspace/output/intermediate/release_readiness_report.json +31 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/release_readiness_forged_event_blocker/workspace/sources.yaml +9 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/release_readiness_forged_event_blocker/workspace/user.md +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reverted_entry_removed_from_next_snapshot/workspace/config.yaml +18 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reverted_entry_removed_from_next_snapshot/workspace/improvement/ledger.jsonl +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reverted_entry_removed_from_next_snapshot/workspace/improvement/memory.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reverted_entry_removed_from_next_snapshot/workspace/output/intermediate/improvement_memory_snapshot.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reverted_entry_removed_from_next_snapshot/workspace/sources.yaml +2 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/reverted_entry_removed_from_next_snapshot/workspace/user.md +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/config.yaml +12 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/input/sources/source-001.txt +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/brief.md +37 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/delivery/brief.md +37 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/atomic_claim_graph.json +17 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/audit_report.json +5 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/audited_brief.md +37 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/claim_ledger.json +20 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/evidence_span_registry.json +20 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/finalize_report.json +40 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/gates/auditor_quality_gate_report.json +42 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/gates/finalize_quality_gate_report.json +42 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/intermediate/screened_candidates.json +33 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/source_appendix.md +12 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/output/source_appendix_trace.md +10 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/report_spec.yaml +24 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/sources.yaml +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/same_evidence_reader_quality_regression/workspace/user.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/source_evidence_pack_blocks_non_evidence_file/workspace/config.yaml +13 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/source_evidence_pack_blocks_non_evidence_file/workspace/input/sources/README.md +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/source_evidence_pack_blocks_non_evidence_file/workspace/output/intermediate/source_evidence_pack_manifest.json +26 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/source_evidence_pack_blocks_non_evidence_file/workspace/sources.yaml +9 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/source_evidence_pack_blocks_non_evidence_file/workspace/user.md +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/config.yaml +9 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/output/intermediate/audit_report.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/output/intermediate/audited_brief.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/output/intermediate/candidate_claims.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/output/intermediate/claim_ledger.json +13 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/output/intermediate/screened_candidates.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/sources.yaml +2 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/stale_current_claim/workspace/user.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/third_party_price_snapshot_formal_block/workspace/config.yaml +13 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/third_party_price_snapshot_formal_block/workspace/sources.yaml +9 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/third_party_price_snapshot_formal_block/workspace/user.md +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/trajectory_retry_budget_exhausted/workspace/config.yaml +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/trajectory_retry_budget_exhausted/workspace/sources.yaml +2 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/trajectory_retry_budget_exhausted/workspace/user.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unapproved_entry_not_materialized/workspace/config.yaml +18 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unapproved_entry_not_materialized/workspace/improvement/ledger.jsonl +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unapproved_entry_not_materialized/workspace/sources.yaml +2 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unapproved_entry_not_materialized/workspace/user.md +4 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unauthorized_institution_branding_blocks_release/workspace/config.yaml +18 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unauthorized_institution_branding_blocks_release/workspace/sources.yaml +9 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unauthorized_institution_branding_blocks_release/workspace/user.md +5 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/config.yaml +8 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/output/intermediate/audit_report.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/output/intermediate/audited_brief.md +8 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/output/intermediate/candidate_claims.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/output/intermediate/claim_ledger.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/output/intermediate/screened_candidates.json +1 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/sources.yaml +2 -0
- multi_agent_brief/evaluation_cases/fixtures/cases/unsupported_material_fact/workspace/user.md +3 -0
- multi_agent_brief/evaluation_cases/fixtures/manifest.yaml +861 -0
- multi_agent_brief/evaluation_cases/fixtures.py +20 -0
- multi_agent_brief/evaluation_cases/runner.py +1603 -0
- multi_agent_brief/experiments/__init__.py +45 -0
- multi_agent_brief/experiments/experiment_080.py +5835 -0
- multi_agent_brief/experiments/schemas.py +63 -0
- multi_agent_brief/experiments/target_contract.py +10 -0
- multi_agent_brief/feedback/__init__.py +17 -0
- multi_agent_brief/feedback/feedback_contract.py +482 -0
- multi_agent_brief/feedback/feedback_state.py +898 -0
- multi_agent_brief/hermes/__init__.py +25 -0
- multi_agent_brief/hermes/adapter.py +832 -0
- multi_agent_brief/improvement/__init__.py +83 -0
- multi_agent_brief/improvement/contract.py +1114 -0
- multi_agent_brief/improvement/memory.py +451 -0
- multi_agent_brief/improvement/product_definition.py +228 -0
- multi_agent_brief/improvement/state.py +961 -0
- multi_agent_brief/inputs/__init__.py +2 -0
- multi_agent_brief/inputs/classifier.py +322 -0
- multi_agent_brief/inputs/contracts.py +59 -0
- multi_agent_brief/inputs/extractor.py +310 -0
- multi_agent_brief/install/__init__.py +2 -0
- multi_agent_brief/install/writer.py +97 -0
- multi_agent_brief/onboarding/__init__.py +11 -0
- multi_agent_brief/onboarding/io.py +103 -0
- multi_agent_brief/onboarding/mapper.py +484 -0
- multi_agent_brief/onboarding/schema.py +46 -0
- multi_agent_brief/orchestrator/__init__.py +2 -0
- multi_agent_brief/orchestrator/fact_layer_import.py +352 -0
- multi_agent_brief/orchestrator/handoff.py +2209 -0
- multi_agent_brief/orchestrator/role_topology.py +42 -0
- multi_agent_brief/orchestrator/run_archive.py +888 -0
- multi_agent_brief/orchestrator/run_integrity.py +346 -0
- multi_agent_brief/orchestrator/runtime_state/__init__.py +70 -0
- multi_agent_brief/orchestrator/runtime_state/_io.py +167 -0
- multi_agent_brief/orchestrator/runtime_state/_transactions.py +298 -0
- multi_agent_brief/orchestrator/runtime_state/artifact_registry.py +1825 -0
- multi_agent_brief/orchestrator/runtime_state/atomic_claim_graph.py +96 -0
- multi_agent_brief/orchestrator/runtime_state/claim_ledger_freeze.py +510 -0
- multi_agent_brief/orchestrator/runtime_state/claim_metadata_enrichment.py +836 -0
- multi_agent_brief/orchestrator/runtime_state/claim_support_matrix.py +582 -0
- multi_agent_brief/orchestrator/runtime_state/completion_gates.py +672 -0
- multi_agent_brief/orchestrator/runtime_state/contracts_loader.py +66 -0
- multi_agent_brief/orchestrator/runtime_state/decisions.py +239 -0
- multi_agent_brief/orchestrator/runtime_state/errors.py +61 -0
- multi_agent_brief/orchestrator/runtime_state/event_log.py +256 -0
- multi_agent_brief/orchestrator/runtime_state/evidence_span_registry.py +233 -0
- multi_agent_brief/orchestrator/runtime_state/fact_layer.py +755 -0
- multi_agent_brief/orchestrator/runtime_state/identity.py +90 -0
- multi_agent_brief/orchestrator/runtime_state/lifecycle.py +675 -0
- multi_agent_brief/orchestrator/runtime_state/manifest.py +82 -0
- multi_agent_brief/orchestrator/runtime_state/operations.py +224 -0
- multi_agent_brief/orchestrator/runtime_state/paths.py +38 -0
- multi_agent_brief/orchestrator/runtime_state/repair.py +984 -0
- multi_agent_brief/orchestrator/runtime_state/safety_surfaces.py +147 -0
- multi_agent_brief/orchestrator/runtime_state/semantic_assessment_report.py +692 -0
- multi_agent_brief/orchestrator/runtime_state/semantic_support_acceptance.py +683 -0
- multi_agent_brief/orchestrator/runtime_state/source_evidence_pack.py +131 -0
- multi_agent_brief/orchestrator/runtime_state/stage_completion.py +1320 -0
- multi_agent_brief/orchestrator/runtime_state/trajectory.py +200 -0
- multi_agent_brief/orchestrator/runtime_state/workflow.py +350 -0
- multi_agent_brief/orchestrator/source_evidence.py +43 -0
- multi_agent_brief/orchestrator/timing.py +410 -0
- multi_agent_brief/orchestrator_contract.py +96 -0
- multi_agent_brief/outputs/__init__.py +2 -0
- multi_agent_brief/outputs/atomic_reader_projection.py +288 -0
- multi_agent_brief/outputs/docx.py +32 -0
- multi_agent_brief/outputs/finalize.py +1036 -0
- multi_agent_brief/outputs/ib_docx.py +983 -0
- multi_agent_brief/outputs/naming.py +38 -0
- multi_agent_brief/outputs/pdf.py +20 -0
- multi_agent_brief/outputs/reader_final_gate.py +509 -0
- multi_agent_brief/outputs/reader_projection.py +397 -0
- multi_agent_brief/outputs/source_appendix.py +753 -0
- multi_agent_brief/outputs/templates/__init__.py +112 -0
- multi_agent_brief/product/__init__.py +49 -0
- multi_agent_brief/product/bundle_projection.py +686 -0
- multi_agent_brief/product/citation_profile.py +145 -0
- multi_agent_brief/product/guidance_manifestation.py +421 -0
- multi_agent_brief/product/materiality_selection.py +472 -0
- multi_agent_brief/product/policy_gate_adapter.py +116 -0
- multi_agent_brief/product/policy_profile.py +39 -0
- multi_agent_brief/product/policy_projection.py +161 -0
- multi_agent_brief/product/policy_registry.py +83 -0
- multi_agent_brief/product/policy_resolver.py +225 -0
- multi_agent_brief/product/quality_closeout.py +188 -0
- multi_agent_brief/product/quality_panel.py +2217 -0
- multi_agent_brief/product/release_approval.py +1034 -0
- multi_agent_brief/product/report_pack.py +130 -0
- multi_agent_brief/product/report_pack_aliases.py +68 -0
- multi_agent_brief/product/report_registry.py +101 -0
- multi_agent_brief/product/report_spec.py +181 -0
- multi_agent_brief/product/support_wording.py +525 -0
- multi_agent_brief/product/template_conformance.py +516 -0
- multi_agent_brief/product/template_projection.py +123 -0
- multi_agent_brief/product/template_registry.py +244 -0
- multi_agent_brief/product/template_render_plan.py +315 -0
- multi_agent_brief/product/template_renderer.py +224 -0
- multi_agent_brief/product/trajectory_regulation.py +441 -0
- multi_agent_brief/provenance/__init__.py +5 -0
- multi_agent_brief/provenance/builder.py +841 -0
- multi_agent_brief/provenance/contract.py +21 -0
- multi_agent_brief/provenance/io.py +144 -0
- multi_agent_brief/provenance/model.py +110 -0
- multi_agent_brief/provenance/references.py +43 -0
- multi_agent_brief/provenance/validator.py +135 -0
- multi_agent_brief/quality_gates/__init__.py +19 -0
- multi_agent_brief/quality_gates/contract.py +581 -0
- multi_agent_brief/quality_gates/state.py +2498 -0
- multi_agent_brief/repair/__init__.py +5 -0
- multi_agent_brief/repair/router.py +842 -0
- multi_agent_brief/runtime_assets.py +431 -0
- multi_agent_brief/sources/__init__.py +16 -0
- multi_agent_brief/sources/api_filings.py +236 -0
- multi_agent_brief/sources/api_news.py +174 -0
- multi_agent_brief/sources/base.py +142 -0
- multi_agent_brief/sources/cached_package.py +119 -0
- multi_agent_brief/sources/cli_provider.py +263 -0
- multi_agent_brief/sources/coverage.py +336 -0
- multi_agent_brief/sources/decider.py +756 -0
- multi_agent_brief/sources/doctor.py +373 -0
- multi_agent_brief/sources/evidence_pack.py +364 -0
- multi_agent_brief/sources/feishu_provider.py +326 -0
- multi_agent_brief/sources/filing_resolver.py +400 -0
- multi_agent_brief/sources/industry_packs.py +130 -0
- multi_agent_brief/sources/join.py +206 -0
- multi_agent_brief/sources/local_signal.py +81 -0
- multi_agent_brief/sources/local_signal_planner.py +636 -0
- multi_agent_brief/sources/manual.py +259 -0
- multi_agent_brief/sources/mcp_provider.py +309 -0
- multi_agent_brief/sources/mineru_provider.py +601 -0
- multi_agent_brief/sources/normalizer.py +95 -0
- multi_agent_brief/sources/opencli_provider.py +282 -0
- multi_agent_brief/sources/planner.py +178 -0
- multi_agent_brief/sources/registry.py +367 -0
- multi_agent_brief/sources/rss.py +190 -0
- multi_agent_brief/sources/search_backends/__init__.py +31 -0
- multi_agent_brief/sources/search_backends/base.py +51 -0
- multi_agent_brief/sources/search_backends/brave.py +192 -0
- multi_agent_brief/sources/search_backends/capabilities.py +94 -0
- multi_agent_brief/sources/search_backends/exa.py +180 -0
- multi_agent_brief/sources/search_backends/firecrawl.py +164 -0
- multi_agent_brief/sources/search_backends/serper.py +241 -0
- multi_agent_brief/sources/search_backends/tavily.py +124 -0
- multi_agent_brief/sources/sourcehub.py +505 -0
- multi_agent_brief/sources/web_search.py +267 -0
- multi_agent_brief/status.py +966 -0
- multi_agent_brief/tools/__init__.py +3 -0
- multi_agent_brief/tools/draft_cleanup.py +198 -0
- multi_agent_brief/workbuddy/__init__.py +1 -0
- multi_agent_brief/workbuddy/diagnose.py +569 -0
- multi_agent_brief/workbuddy/skill_pack.py +309 -0
- multi_agent_brief/workspace/__init__.py +1 -0
- multi_agent_brief/workspace/init_profile.py +45 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
"""Audience profile runtime surface helpers.
|
|
2
|
+
|
|
3
|
+
This module owns workspace-local taste context files. It deliberately does not
|
|
4
|
+
import CLI profile types so runtime code can use it without a CLI dependency.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import hashlib
|
|
10
|
+
import os
|
|
11
|
+
import uuid
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from datetime import datetime, timezone
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any, Mapping
|
|
16
|
+
|
|
17
|
+
import yaml
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
AUDIENCE_MEMORY_FILES = {
|
|
21
|
+
"audience_profile": "audience_profile.md",
|
|
22
|
+
"audience_profile_snapshot": "output/intermediate/audience_profile_snapshot.md",
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
_SNAPSHOT_MARKER = "<!-- mabw:audience-profile-snapshot"
|
|
26
|
+
_SNAPSHOT_END = "-->"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True)
|
|
30
|
+
class AudienceProfileResult:
|
|
31
|
+
path: Path
|
|
32
|
+
relative_path: str
|
|
33
|
+
created: bool
|
|
34
|
+
missing: bool
|
|
35
|
+
sha256: str
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass(frozen=True)
|
|
39
|
+
class AudienceSnapshotResult:
|
|
40
|
+
path: Path
|
|
41
|
+
relative_path: str
|
|
42
|
+
created: bool
|
|
43
|
+
stale_rebuilt: bool
|
|
44
|
+
run_id: str
|
|
45
|
+
source_sha256: str
|
|
46
|
+
captured_body_sha256: str
|
|
47
|
+
snapshot_sha256: str
|
|
48
|
+
profile_created: bool
|
|
49
|
+
profile_missing: bool
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def utc_now() -> str:
|
|
53
|
+
return datetime.now(timezone.utc).replace(microsecond=0).isoformat()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def sha256_text(text: str) -> str:
|
|
57
|
+
return hashlib.sha256(text.encode("utf-8")).hexdigest()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def sha256_file(path: Path) -> str:
|
|
61
|
+
digest = hashlib.sha256()
|
|
62
|
+
with path.open("rb") as fh:
|
|
63
|
+
for chunk in iter(lambda: fh.read(1024 * 1024), b""):
|
|
64
|
+
digest.update(chunk)
|
|
65
|
+
return digest.hexdigest()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _workspace_path(workspace: str | Path, rel_path: str) -> Path:
|
|
69
|
+
ws = Path(workspace).expanduser().resolve()
|
|
70
|
+
path = (ws / rel_path).resolve()
|
|
71
|
+
try:
|
|
72
|
+
path.relative_to(ws)
|
|
73
|
+
except ValueError as exc:
|
|
74
|
+
raise ValueError(f"Audience memory path escapes workspace: {rel_path}") from exc
|
|
75
|
+
return path
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _write_text_atomic(path: Path, text: str) -> None:
|
|
79
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
80
|
+
tmp = path.with_name(f".{path.name}.{uuid.uuid4().hex}.tmp")
|
|
81
|
+
try:
|
|
82
|
+
tmp.write_text(text, encoding="utf-8")
|
|
83
|
+
os.replace(tmp, path)
|
|
84
|
+
finally:
|
|
85
|
+
try:
|
|
86
|
+
tmp.unlink(missing_ok=True)
|
|
87
|
+
except OSError:
|
|
88
|
+
pass
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _as_text(value: Any, default: str = "") -> str:
|
|
92
|
+
if value is None:
|
|
93
|
+
return default
|
|
94
|
+
text = str(value).strip()
|
|
95
|
+
return text if text else default
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _as_list(value: Any) -> list[str]:
|
|
99
|
+
if value is None:
|
|
100
|
+
return []
|
|
101
|
+
if isinstance(value, (list, tuple, set)):
|
|
102
|
+
return [str(item).strip() for item in value if str(item).strip()]
|
|
103
|
+
text = str(value).strip()
|
|
104
|
+
if not text:
|
|
105
|
+
return []
|
|
106
|
+
return [part.strip() for part in text.replace(";", ",").split(",") if part.strip()]
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def profile_data_from_object(profile: Any) -> dict[str, Any]:
|
|
110
|
+
"""Convert an arbitrary profile-like object into plain profile data."""
|
|
111
|
+
fields = [
|
|
112
|
+
"company",
|
|
113
|
+
"industry",
|
|
114
|
+
"industry_text",
|
|
115
|
+
"role",
|
|
116
|
+
"audience",
|
|
117
|
+
"audience_profile",
|
|
118
|
+
"brief_title",
|
|
119
|
+
"task_objective",
|
|
120
|
+
"interface_language",
|
|
121
|
+
"output_language",
|
|
122
|
+
"cadence",
|
|
123
|
+
"source_profile",
|
|
124
|
+
"focus_areas",
|
|
125
|
+
"forbidden_sources",
|
|
126
|
+
"output_formats",
|
|
127
|
+
]
|
|
128
|
+
return {field: getattr(profile, field, "") for field in fields}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def profile_data_from_workspace_config(workspace: str | Path) -> dict[str, Any]:
|
|
132
|
+
"""Extract audience profile defaults from an existing workspace config."""
|
|
133
|
+
config_path = Path(workspace).expanduser().resolve() / "config.yaml"
|
|
134
|
+
if not config_path.exists():
|
|
135
|
+
return {}
|
|
136
|
+
data = yaml.safe_load(config_path.read_text(encoding="utf-8")) or {}
|
|
137
|
+
if not isinstance(data, dict):
|
|
138
|
+
return {}
|
|
139
|
+
|
|
140
|
+
project = data.get("project") or {}
|
|
141
|
+
audience_profile = data.get("audience_profile") or {}
|
|
142
|
+
language = data.get("language") or {}
|
|
143
|
+
report = data.get("report") or {}
|
|
144
|
+
source = data.get("source") or {}
|
|
145
|
+
source_strategy = data.get("source_strategy") or {}
|
|
146
|
+
output = data.get("output") or {}
|
|
147
|
+
task = data.get("task") or {}
|
|
148
|
+
|
|
149
|
+
formats = output.get("formats") if isinstance(output, dict) else []
|
|
150
|
+
if not isinstance(formats, list):
|
|
151
|
+
formats = []
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
"company": project.get("company") or project.get("organization") or project.get("name") or "",
|
|
155
|
+
"industry": project.get("industry") or "",
|
|
156
|
+
"industry_text": project.get("industry") or "",
|
|
157
|
+
"role": project.get("role") or "",
|
|
158
|
+
"audience": project.get("audience") or "",
|
|
159
|
+
"audience_profile": audience_profile.get("id") or "",
|
|
160
|
+
"brief_title": project.get("name") or "",
|
|
161
|
+
"task_objective": task.get("objective") or "",
|
|
162
|
+
"interface_language": language.get("interface") or "",
|
|
163
|
+
"output_language": language.get("output") or "",
|
|
164
|
+
"cadence": report.get("cadence") or "",
|
|
165
|
+
"source_profile": source.get("mode") or source_strategy.get("profile") or "",
|
|
166
|
+
"output_formats": formats,
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def build_default_audience_profile(profile_data: Mapping[str, Any] | None = None) -> str:
|
|
171
|
+
"""Build a human-editable audience profile Markdown template."""
|
|
172
|
+
data = dict(profile_data or {})
|
|
173
|
+
company = _as_text(data.get("company"), "Unknown organization")
|
|
174
|
+
industry = _as_text(data.get("industry_text") or data.get("industry"), "Unknown industry/theme")
|
|
175
|
+
audience = _as_text(data.get("audience"), "management")
|
|
176
|
+
profile_id = _as_text(data.get("audience_profile"), "default")
|
|
177
|
+
title = _as_text(data.get("brief_title"), "Workspace brief")
|
|
178
|
+
objective = _as_text(data.get("task_objective"), "Summarize material updates for the target reader.")
|
|
179
|
+
language = _as_text(data.get("output_language") or data.get("interface_language"), "en-US")
|
|
180
|
+
cadence = _as_text(data.get("cadence"), "weekly")
|
|
181
|
+
role = _as_text(data.get("role"), "strategy_office")
|
|
182
|
+
source_profile = _as_text(data.get("source_profile"), "llm_decide")
|
|
183
|
+
focus_areas = _as_list(data.get("focus_areas"))
|
|
184
|
+
forbidden_sources = _as_list(data.get("forbidden_sources"))
|
|
185
|
+
output_formats = _as_list(data.get("output_formats"))
|
|
186
|
+
|
|
187
|
+
focus_lines = "\n".join(f"- {item}" for item in focus_areas) or "- Add durable audience priorities here."
|
|
188
|
+
avoid_lines = "\n".join(f"- {item}" for item in forbidden_sources) or "- Do not let taste preferences override evidence or audit constraints."
|
|
189
|
+
output_lines = "\n".join(f"- {item}" for item in output_formats) or "- Markdown\n- DOCX"
|
|
190
|
+
|
|
191
|
+
return (
|
|
192
|
+
"# Audience Profile\n\n"
|
|
193
|
+
"This workspace-local file records reader taste, department preferences, and recurring editorial guidance.\n"
|
|
194
|
+
"It is not source evidence, not a correctness contract, and not a stage gate.\n"
|
|
195
|
+
"Human edits are allowed. Mid-run edits apply to the next run after a new snapshot is created.\n\n"
|
|
196
|
+
"## Reader Context\n\n"
|
|
197
|
+
f"- Organization: {company}\n"
|
|
198
|
+
f"- Industry/theme: {industry}\n"
|
|
199
|
+
f"- Reader/audience: {audience}\n"
|
|
200
|
+
f"- Audience profile id: {profile_id}\n"
|
|
201
|
+
f"- Internal role/use context: {role}\n"
|
|
202
|
+
f"- Brief title: {title}\n"
|
|
203
|
+
f"- Cadence: {cadence}\n"
|
|
204
|
+
f"- Output language: {language}\n"
|
|
205
|
+
f"- Source mode: {source_profile}\n\n"
|
|
206
|
+
"## Decision Use\n\n"
|
|
207
|
+
f"{objective}\n\n"
|
|
208
|
+
"## Preferred Brief Style\n\n"
|
|
209
|
+
"- Start with the decision-useful conclusion when evidence supports it.\n"
|
|
210
|
+
"- Keep claims bounded by source quality, freshness, and uncertainty.\n"
|
|
211
|
+
"- Prefer concise, concrete implications over generic narrative.\n\n"
|
|
212
|
+
"## Tone And Structure Preferences\n\n"
|
|
213
|
+
"- Write for the stated reader, not for a generic public audience.\n"
|
|
214
|
+
"- Preserve auditability during drafting; reader-facing cleanup happens after audit.\n"
|
|
215
|
+
"- Surface risks, caveats, and missing evidence clearly when relevant.\n\n"
|
|
216
|
+
"## Focus Areas\n\n"
|
|
217
|
+
f"{focus_lines}\n\n"
|
|
218
|
+
"## Output Expectations\n\n"
|
|
219
|
+
f"{output_lines}\n\n"
|
|
220
|
+
"## Recurring Feedback\n\n"
|
|
221
|
+
"- Add durable feedback patterns here after human review.\n\n"
|
|
222
|
+
"## Avoid\n\n"
|
|
223
|
+
f"{avoid_lines}\n\n"
|
|
224
|
+
"## Human Notes\n\n"
|
|
225
|
+
"- Add workspace-specific taste notes here.\n"
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def ensure_audience_profile(
|
|
230
|
+
workspace: str | Path,
|
|
231
|
+
profile_data: Mapping[str, Any] | None = None,
|
|
232
|
+
) -> AudienceProfileResult:
|
|
233
|
+
"""Ensure the workspace has an audience profile."""
|
|
234
|
+
path = _workspace_path(workspace, AUDIENCE_MEMORY_FILES["audience_profile"])
|
|
235
|
+
missing = not path.exists()
|
|
236
|
+
created = False
|
|
237
|
+
if missing:
|
|
238
|
+
_write_text_atomic(path, build_default_audience_profile(profile_data))
|
|
239
|
+
created = True
|
|
240
|
+
return AudienceProfileResult(
|
|
241
|
+
path=path,
|
|
242
|
+
relative_path=AUDIENCE_MEMORY_FILES["audience_profile"],
|
|
243
|
+
created=created,
|
|
244
|
+
missing=missing,
|
|
245
|
+
sha256=sha256_file(path),
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def _parse_snapshot_metadata(text: str) -> dict[str, str] | None:
|
|
250
|
+
"""Parse only the strict top-of-file audience snapshot metadata block."""
|
|
251
|
+
if not text.startswith(_SNAPSHOT_MARKER):
|
|
252
|
+
return None
|
|
253
|
+
end = text.find(_SNAPSHOT_END)
|
|
254
|
+
if end == -1:
|
|
255
|
+
return None
|
|
256
|
+
block = text[len(_SNAPSHOT_MARKER):end].strip()
|
|
257
|
+
metadata: dict[str, str] = {}
|
|
258
|
+
for line in block.splitlines():
|
|
259
|
+
line = line.strip()
|
|
260
|
+
if not line:
|
|
261
|
+
continue
|
|
262
|
+
if ":" not in line:
|
|
263
|
+
return None
|
|
264
|
+
key, value = line.split(":", 1)
|
|
265
|
+
key = key.strip()
|
|
266
|
+
value = value.strip()
|
|
267
|
+
if not key or not value:
|
|
268
|
+
return None
|
|
269
|
+
metadata[key] = value
|
|
270
|
+
required = {"run_id", "source", "created_at", "source_sha256", "captured_body_sha256"}
|
|
271
|
+
if not required.issubset(metadata):
|
|
272
|
+
return None
|
|
273
|
+
if metadata.get("source") != AUDIENCE_MEMORY_FILES["audience_profile"]:
|
|
274
|
+
return None
|
|
275
|
+
return metadata
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def _snapshot_text(
|
|
279
|
+
*,
|
|
280
|
+
run_id: str,
|
|
281
|
+
created_at: str,
|
|
282
|
+
source_sha256: str,
|
|
283
|
+
captured_body_sha256: str,
|
|
284
|
+
profile_body: str,
|
|
285
|
+
) -> str:
|
|
286
|
+
body = profile_body.rstrip() + "\n"
|
|
287
|
+
return (
|
|
288
|
+
"<!-- mabw:audience-profile-snapshot\n"
|
|
289
|
+
f"run_id: {run_id}\n"
|
|
290
|
+
f"source: {AUDIENCE_MEMORY_FILES['audience_profile']}\n"
|
|
291
|
+
f"created_at: {created_at}\n"
|
|
292
|
+
f"source_sha256: {source_sha256}\n"
|
|
293
|
+
f"captured_body_sha256: {captured_body_sha256}\n"
|
|
294
|
+
"-->\n\n"
|
|
295
|
+
"# Audience Profile Snapshot\n\n"
|
|
296
|
+
f"- Run ID: {run_id}\n"
|
|
297
|
+
f"- Source: {AUDIENCE_MEMORY_FILES['audience_profile']}\n"
|
|
298
|
+
f"- Created at: {created_at}\n"
|
|
299
|
+
f"- Source SHA256: {source_sha256}\n"
|
|
300
|
+
f"- Captured Body SHA256: {captured_body_sha256}\n"
|
|
301
|
+
"- Run behavior: use this snapshot for the current run.\n"
|
|
302
|
+
f"- Mid-run edits to {AUDIENCE_MEMORY_FILES['audience_profile']} apply to later runs only.\n\n"
|
|
303
|
+
"## Captured Audience Profile\n\n"
|
|
304
|
+
f"{body}"
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def create_audience_profile_snapshot(
|
|
309
|
+
workspace: str | Path,
|
|
310
|
+
*,
|
|
311
|
+
run_id: str,
|
|
312
|
+
profile_data: Mapping[str, Any] | None = None,
|
|
313
|
+
) -> AudienceSnapshotResult:
|
|
314
|
+
"""Create or reuse the active run audience profile snapshot."""
|
|
315
|
+
profile = ensure_audience_profile(workspace, profile_data)
|
|
316
|
+
snapshot_path = _workspace_path(workspace, AUDIENCE_MEMORY_FILES["audience_profile_snapshot"])
|
|
317
|
+
|
|
318
|
+
if snapshot_path.exists():
|
|
319
|
+
existing_text = snapshot_path.read_text(encoding="utf-8")
|
|
320
|
+
metadata = _parse_snapshot_metadata(existing_text)
|
|
321
|
+
if metadata and metadata.get("run_id") == run_id:
|
|
322
|
+
return AudienceSnapshotResult(
|
|
323
|
+
path=snapshot_path,
|
|
324
|
+
relative_path=AUDIENCE_MEMORY_FILES["audience_profile_snapshot"],
|
|
325
|
+
created=False,
|
|
326
|
+
stale_rebuilt=False,
|
|
327
|
+
run_id=run_id,
|
|
328
|
+
source_sha256=metadata["source_sha256"],
|
|
329
|
+
captured_body_sha256=metadata["captured_body_sha256"],
|
|
330
|
+
snapshot_sha256=sha256_file(snapshot_path),
|
|
331
|
+
profile_created=profile.created,
|
|
332
|
+
profile_missing=profile.missing,
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
profile_body = profile.path.read_text(encoding="utf-8")
|
|
336
|
+
source_sha256 = sha256_text(profile_body)
|
|
337
|
+
captured_body_sha256 = source_sha256
|
|
338
|
+
text = _snapshot_text(
|
|
339
|
+
run_id=run_id,
|
|
340
|
+
created_at=utc_now(),
|
|
341
|
+
source_sha256=source_sha256,
|
|
342
|
+
captured_body_sha256=captured_body_sha256,
|
|
343
|
+
profile_body=profile_body,
|
|
344
|
+
)
|
|
345
|
+
stale_rebuilt = snapshot_path.exists()
|
|
346
|
+
_write_text_atomic(snapshot_path, text)
|
|
347
|
+
return AudienceSnapshotResult(
|
|
348
|
+
path=snapshot_path,
|
|
349
|
+
relative_path=AUDIENCE_MEMORY_FILES["audience_profile_snapshot"],
|
|
350
|
+
created=True,
|
|
351
|
+
stale_rebuilt=stale_rebuilt,
|
|
352
|
+
run_id=run_id,
|
|
353
|
+
source_sha256=source_sha256,
|
|
354
|
+
captured_body_sha256=captured_body_sha256,
|
|
355
|
+
snapshot_sha256=sha256_file(snapshot_path),
|
|
356
|
+
profile_created=profile.created,
|
|
357
|
+
profile_missing=profile.missing,
|
|
358
|
+
)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Audit utilities."""
|
|
2
|
+
|
|
3
|
+
from multi_agent_brief.audit.deterministic import DeterministicAuditAgent, run_deterministic_audit
|
|
4
|
+
from multi_agent_brief.audit.final_quality import FinalQualityAuditAgent, FinalQualityConfig
|
|
5
|
+
from multi_agent_brief.audit.harness import QualityHarnessAuditAgent
|
|
6
|
+
from multi_agent_brief.audit.interfaces import AuditAgentInterface, CompositeAuditAgent
|
|
7
|
+
from multi_agent_brief.audit.semantic import (
|
|
8
|
+
SEMANTIC_SUPPORT_CALIBRATION_METADATA_KEY,
|
|
9
|
+
SEMANTIC_SUPPORT_INVALID_CALIBRATION_LABEL,
|
|
10
|
+
SEMANTIC_SUPPORT_PROPOSAL_FINDING_TYPE,
|
|
11
|
+
SEMANTIC_SUPPORT_PROPOSAL_LABELS,
|
|
12
|
+
NoOpSemanticAuditAgent,
|
|
13
|
+
SemanticAuditPromptBuilder,
|
|
14
|
+
findings_from_semantic_proposal_rows,
|
|
15
|
+
normalize_calibration_label,
|
|
16
|
+
semantic_support_proposal_finding,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"SEMANTIC_SUPPORT_CALIBRATION_METADATA_KEY",
|
|
21
|
+
"SEMANTIC_SUPPORT_INVALID_CALIBRATION_LABEL",
|
|
22
|
+
"SEMANTIC_SUPPORT_PROPOSAL_FINDING_TYPE",
|
|
23
|
+
"SEMANTIC_SUPPORT_PROPOSAL_LABELS",
|
|
24
|
+
"normalize_calibration_label",
|
|
25
|
+
"AuditAgentInterface",
|
|
26
|
+
"CompositeAuditAgent",
|
|
27
|
+
"DeterministicAuditAgent",
|
|
28
|
+
"FinalQualityAuditAgent",
|
|
29
|
+
"FinalQualityConfig",
|
|
30
|
+
"NoOpSemanticAuditAgent",
|
|
31
|
+
"QualityHarnessAuditAgent",
|
|
32
|
+
"SemanticAuditPromptBuilder",
|
|
33
|
+
"findings_from_semantic_proposal_rows",
|
|
34
|
+
"run_deterministic_audit",
|
|
35
|
+
"semantic_support_proposal_finding",
|
|
36
|
+
]
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""Comparable Case Applicability audit (v0.5.3 PR 3).
|
|
2
|
+
|
|
3
|
+
Enforces boundaries on analogous/comparable evidence:
|
|
4
|
+
1. evidence_relation=analogous MUST have applicability_reason.
|
|
5
|
+
2. Single comparable case can only support hypothesis/to_verify, NOT strong action.
|
|
6
|
+
3. No local direct evidence → must generate verification_path.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
|
|
12
|
+
from multi_agent_brief.analysis_blocks.schemas import AnalysisBlock
|
|
13
|
+
from multi_agent_brief.core.claim_ledger import ClaimLedger
|
|
14
|
+
from multi_agent_brief.core.schemas import Claim
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class CaseApplicabilityFinding:
|
|
19
|
+
"""One audit finding for case applicability."""
|
|
20
|
+
|
|
21
|
+
finding_type: str
|
|
22
|
+
severity: str # "warning" or "fail"
|
|
23
|
+
block_id: str
|
|
24
|
+
claim_id: str
|
|
25
|
+
description: str
|
|
26
|
+
recommendation: str
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def audit_case_applicability(
|
|
30
|
+
blocks: list[AnalysisBlock],
|
|
31
|
+
ledger: ClaimLedger,
|
|
32
|
+
) -> list[CaseApplicabilityFinding]:
|
|
33
|
+
"""Audit case applicability across all analysis blocks.
|
|
34
|
+
|
|
35
|
+
Returns findings for:
|
|
36
|
+
- analogous claims without applicability_reason
|
|
37
|
+
- single comparable case supporting strong action
|
|
38
|
+
- missing verification_path when no local direct evidence
|
|
39
|
+
"""
|
|
40
|
+
findings: list[CaseApplicabilityFinding] = []
|
|
41
|
+
|
|
42
|
+
for block in blocks:
|
|
43
|
+
_check_analogous_applicability(block, ledger, findings)
|
|
44
|
+
_check_single_case_action(block, ledger, findings)
|
|
45
|
+
_check_verification_path(block, findings)
|
|
46
|
+
|
|
47
|
+
return findings
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _check_analogous_applicability(
|
|
51
|
+
block: AnalysisBlock,
|
|
52
|
+
ledger: ClaimLedger,
|
|
53
|
+
findings: list[CaseApplicabilityFinding],
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Rule 1: analogous claims MUST have applicability_reason."""
|
|
56
|
+
for cid in block.case_claim_ids:
|
|
57
|
+
claim = ledger.get_claim(cid)
|
|
58
|
+
if not claim:
|
|
59
|
+
continue
|
|
60
|
+
if claim.evidence_relation == "analogous" and not claim.applicability_reason.strip():
|
|
61
|
+
findings.append(CaseApplicabilityFinding(
|
|
62
|
+
finding_type="missing_applicability_reason",
|
|
63
|
+
severity="warning",
|
|
64
|
+
block_id=block.block_id,
|
|
65
|
+
claim_id=cid,
|
|
66
|
+
description=(
|
|
67
|
+
f"Claim {cid} uses analogous evidence but has no applicability_reason. "
|
|
68
|
+
"Readers cannot judge when this comparison applies."
|
|
69
|
+
),
|
|
70
|
+
recommendation=(
|
|
71
|
+
"Add applicability_reason explaining why this comparable case is relevant "
|
|
72
|
+
"and what dimensions are not comparable."
|
|
73
|
+
),
|
|
74
|
+
))
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _check_single_case_action(
|
|
78
|
+
block: AnalysisBlock,
|
|
79
|
+
ledger: ClaimLedger,
|
|
80
|
+
findings: list[CaseApplicabilityFinding],
|
|
81
|
+
) -> None:
|
|
82
|
+
"""Rule 2: single comparable case cannot support strong action."""
|
|
83
|
+
# Check two scenarios:
|
|
84
|
+
# A) action_claim_ids contain analogous evidence (direct action on analogy)
|
|
85
|
+
# B) case_claim_ids contain epistemic_type=action (builder classified by evidence_relation first)
|
|
86
|
+
if not block.case_claim_ids:
|
|
87
|
+
return
|
|
88
|
+
if block.fact_claim_ids:
|
|
89
|
+
# There are direct facts, so analogous evidence is supplementary
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
# Scenario A: explicit action claims with analogous evidence
|
|
93
|
+
for action_cid in block.action_claim_ids:
|
|
94
|
+
action_claim = ledger.get_claim(action_cid)
|
|
95
|
+
if not action_claim:
|
|
96
|
+
continue
|
|
97
|
+
if action_claim.evidence_relation == "analogous":
|
|
98
|
+
findings.append(CaseApplicabilityFinding(
|
|
99
|
+
finding_type="analogous_evidence_supports_action",
|
|
100
|
+
severity="fail",
|
|
101
|
+
block_id=block.block_id,
|
|
102
|
+
claim_id=action_cid,
|
|
103
|
+
description=(
|
|
104
|
+
f"Action claim {action_cid} is supported only by comparable/analogous evidence "
|
|
105
|
+
"with no direct fact backing. Single comparable cases cannot support strong actions."
|
|
106
|
+
),
|
|
107
|
+
recommendation=(
|
|
108
|
+
"Downgrade to 'to_verify' or add direct evidence. "
|
|
109
|
+
"Comparable cases can support hypothesis or trend judgment, not actionable recommendations."
|
|
110
|
+
),
|
|
111
|
+
))
|
|
112
|
+
|
|
113
|
+
# Scenario B: case claims that were originally action-type (builder put them in case due to analogous)
|
|
114
|
+
for case_cid in block.case_claim_ids:
|
|
115
|
+
case_claim = ledger.get_claim(case_cid)
|
|
116
|
+
if not case_claim:
|
|
117
|
+
continue
|
|
118
|
+
if case_claim.epistemic_type == "action":
|
|
119
|
+
findings.append(CaseApplicabilityFinding(
|
|
120
|
+
finding_type="analogous_evidence_supports_action",
|
|
121
|
+
severity="fail",
|
|
122
|
+
block_id=block.block_id,
|
|
123
|
+
claim_id=case_cid,
|
|
124
|
+
description=(
|
|
125
|
+
f"Claim {case_cid} has epistemic_type='action' but evidence_relation='analogous'. "
|
|
126
|
+
"It was classified as a case (correct), but an action claim based solely on "
|
|
127
|
+
"comparable evidence cannot support a strong recommendation."
|
|
128
|
+
),
|
|
129
|
+
recommendation=(
|
|
130
|
+
"Downgrade epistemic_type to 'hypothesis' or 'interpreted', "
|
|
131
|
+
"or add direct local evidence to support the action."
|
|
132
|
+
),
|
|
133
|
+
))
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _check_verification_path(
|
|
137
|
+
block: AnalysisBlock,
|
|
138
|
+
findings: list[CaseApplicabilityFinding],
|
|
139
|
+
) -> None:
|
|
140
|
+
"""Rule 3: no local direct evidence → must have verification_path."""
|
|
141
|
+
has_direct_fact = bool(block.fact_claim_ids)
|
|
142
|
+
has_case = bool(block.case_claim_ids)
|
|
143
|
+
has_verification = bool(block.verification_path.strip())
|
|
144
|
+
|
|
145
|
+
if has_case and not has_direct_fact and not has_verification:
|
|
146
|
+
findings.append(CaseApplicabilityFinding(
|
|
147
|
+
finding_type="missing_verification_path",
|
|
148
|
+
severity="warning",
|
|
149
|
+
block_id=block.block_id,
|
|
150
|
+
claim_id="",
|
|
151
|
+
description=(
|
|
152
|
+
f"Block '{block.title}' uses comparable cases but has no direct local facts "
|
|
153
|
+
"and no verification_path. Readers don't know how to validate the comparison."
|
|
154
|
+
),
|
|
155
|
+
recommendation=(
|
|
156
|
+
"Add verification_path describing what data or action would confirm "
|
|
157
|
+
"whether the comparable case applies locally."
|
|
158
|
+
),
|
|
159
|
+
))
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def format_case_applicability_report(findings: list[CaseApplicabilityFinding]) -> str:
|
|
163
|
+
"""Format findings into a readable report."""
|
|
164
|
+
if not findings:
|
|
165
|
+
return "Case applicability audit: all checks passed.\n"
|
|
166
|
+
|
|
167
|
+
lines = ["Case Applicability Audit Report", "=" * 34, ""]
|
|
168
|
+
for f in findings:
|
|
169
|
+
icon = "❌" if f.severity == "fail" else "⚠️"
|
|
170
|
+
lines.append(f"{icon} [{f.severity.upper()}] {f.finding_type}")
|
|
171
|
+
lines.append(f" Block: {f.block_id}")
|
|
172
|
+
if f.claim_id:
|
|
173
|
+
lines.append(f" Claim: {f.claim_id}")
|
|
174
|
+
lines.append(f" {f.description}")
|
|
175
|
+
lines.append(f" → {f.recommendation}")
|
|
176
|
+
lines.append("")
|
|
177
|
+
|
|
178
|
+
fails = sum(1 for f in findings if f.severity == "fail")
|
|
179
|
+
warns = sum(1 for f in findings if f.severity == "warning")
|
|
180
|
+
lines.append(f"Result: {fails} fail(s), {warns} warning(s)")
|
|
181
|
+
return "\n".join(lines)
|