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,206 @@
|
|
|
1
|
+
"""Build AnalysisBlocks from a ClaimLedger.
|
|
2
|
+
|
|
3
|
+
Classification rules (from v0.5.3 PR 1 acceptance criteria):
|
|
4
|
+
- observed + direct → Fact
|
|
5
|
+
- analogous → Case
|
|
6
|
+
- hypothesis / interpreted → Interpretation
|
|
7
|
+
- action + direct evidence → Action
|
|
8
|
+
- action without evidence → To Verify (downgraded)
|
|
9
|
+
- hypothesis → also To Verify (pending validation)
|
|
10
|
+
- any claim with limitations → Limitation
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from collections import defaultdict
|
|
15
|
+
|
|
16
|
+
from multi_agent_brief.analysis_blocks.schemas import AnalysisBlock, CaseApplicability
|
|
17
|
+
from multi_agent_brief.core.claim_ledger import ClaimLedger
|
|
18
|
+
from multi_agent_brief.core.schemas import Claim
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _infer_section(statement: str) -> str:
|
|
22
|
+
"""Infer a topic from claim statement keywords.
|
|
23
|
+
|
|
24
|
+
Kept in sync with the analysis-block topic inference helper to avoid topic drift
|
|
25
|
+
between analysis_blocks (governance artifact) and legacy brief.md.
|
|
26
|
+
"""
|
|
27
|
+
lowered = statement.lower()
|
|
28
|
+
if any(word in lowered for word in ["policy", "tariff", "regulation"]):
|
|
29
|
+
return "policy"
|
|
30
|
+
if any(word in lowered for word in ["compliance", "uflpa", "forced labor"]):
|
|
31
|
+
return "compliance"
|
|
32
|
+
if any(word in lowered for word in ["revenue", "margin", "earnings"]):
|
|
33
|
+
return "earnings"
|
|
34
|
+
if any(word in lowered for word in ["competitor", "capacity", "launch"]):
|
|
35
|
+
return "competitor"
|
|
36
|
+
if any(word in lowered for word in ["market", "price", "demand"]):
|
|
37
|
+
return "market"
|
|
38
|
+
if any(word in lowered for word in ["installation", "generation", "ppa"]):
|
|
39
|
+
return "demand"
|
|
40
|
+
if any(word in lowered for word in ["treasury", "yield", "sofr", "fed", "rate"]):
|
|
41
|
+
return "rates"
|
|
42
|
+
if any(word in lowered for word in ["acquisition", "investment", "fund", "capital"]):
|
|
43
|
+
return "capital"
|
|
44
|
+
if any(word in lowered for word in ["topcon", "hjt", "technology", "efficiency"]):
|
|
45
|
+
return "technology"
|
|
46
|
+
return "general"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def build_analysis_blocks(ledger: ClaimLedger) -> list[AnalysisBlock]:
|
|
50
|
+
"""Group ledger claims into AnalysisBlocks by topic.
|
|
51
|
+
|
|
52
|
+
Each topic becomes one block. Claims are classified into epistemic
|
|
53
|
+
buckets based on their epistemic_type and evidence_relation.
|
|
54
|
+
"""
|
|
55
|
+
# Group claims by topic — fall back to keyword inference for topicless claims,
|
|
56
|
+
# keeping parity with analysis-block topic inference.
|
|
57
|
+
by_topic: dict[str, list[Claim]] = defaultdict(list)
|
|
58
|
+
for claim in ledger:
|
|
59
|
+
topic = claim.metadata.get("topic") or _infer_section(claim.statement)
|
|
60
|
+
by_topic[topic].append(claim)
|
|
61
|
+
|
|
62
|
+
blocks: list[AnalysisBlock] = []
|
|
63
|
+
for topic, claims in by_topic.items():
|
|
64
|
+
block = _build_block(topic, claims)
|
|
65
|
+
blocks.append(block)
|
|
66
|
+
|
|
67
|
+
return blocks
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _build_block(topic: str, claims: list[Claim]) -> AnalysisBlock:
|
|
71
|
+
block_id = topic.replace(" ", "_").lower()
|
|
72
|
+
block = AnalysisBlock(block_id=block_id, title=topic.replace("_", " ").title())
|
|
73
|
+
|
|
74
|
+
for claim in claims:
|
|
75
|
+
_classify_claim(block, claim)
|
|
76
|
+
|
|
77
|
+
block.confidence = _compute_confidence(block, claims)
|
|
78
|
+
return block
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _classify_claim(block: AnalysisBlock, claim: Claim) -> None:
|
|
82
|
+
"""Classify a single claim into the appropriate epistemic bucket."""
|
|
83
|
+
ep_type = claim.epistemic_type
|
|
84
|
+
ev_rel = claim.evidence_relation
|
|
85
|
+
has_evidence = bool(claim.evidence_text.strip())
|
|
86
|
+
has_limitations = bool(claim.limitations)
|
|
87
|
+
|
|
88
|
+
# 1. observed + direct → Fact
|
|
89
|
+
if ep_type == "observed" and ev_rel == "direct":
|
|
90
|
+
block.fact_claim_ids.append(claim.claim_id)
|
|
91
|
+
if has_limitations:
|
|
92
|
+
block.limitation_claim_ids.append(claim.claim_id)
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
# 2. analogous → Case (but hypothesis still goes to To Verify)
|
|
96
|
+
if ev_rel == "analogous":
|
|
97
|
+
block.case_claim_ids.append(claim.claim_id)
|
|
98
|
+
# Populate case_applicability from claim metadata if available
|
|
99
|
+
_populate_case_applicability(block, claim)
|
|
100
|
+
# hypothesis+analogous: must also be tracked for verification
|
|
101
|
+
if ep_type == "hypothesis":
|
|
102
|
+
block.to_verify_claim_ids.append(claim.claim_id)
|
|
103
|
+
if has_limitations:
|
|
104
|
+
block.limitation_claim_ids.append(claim.claim_id)
|
|
105
|
+
return
|
|
106
|
+
|
|
107
|
+
# 3. hypothesis / interpreted → Interpretation
|
|
108
|
+
if ep_type in ("hypothesis", "interpreted"):
|
|
109
|
+
block.interpretation_claim_ids.append(claim.claim_id)
|
|
110
|
+
# hypothesis also goes to To Verify
|
|
111
|
+
if ep_type == "hypothesis":
|
|
112
|
+
block.to_verify_claim_ids.append(claim.claim_id)
|
|
113
|
+
if has_limitations:
|
|
114
|
+
block.limitation_claim_ids.append(claim.claim_id)
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
# 4. action — gate on evidence
|
|
118
|
+
if ep_type == "action":
|
|
119
|
+
if has_evidence and ev_rel == "direct":
|
|
120
|
+
block.action_claim_ids.append(claim.claim_id)
|
|
121
|
+
else:
|
|
122
|
+
# Downgrade: action without direct evidence → To Verify
|
|
123
|
+
block.to_verify_claim_ids.append(claim.claim_id)
|
|
124
|
+
if has_limitations:
|
|
125
|
+
block.limitation_claim_ids.append(claim.claim_id)
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
# 5. observed + indirect/inferred → Interpretation (not strong enough for Fact)
|
|
129
|
+
if ep_type == "observed" and ev_rel in ("indirect", "inferred"):
|
|
130
|
+
block.interpretation_claim_ids.append(claim.claim_id)
|
|
131
|
+
block.to_verify_claim_ids.append(claim.claim_id)
|
|
132
|
+
if has_limitations:
|
|
133
|
+
block.limitation_claim_ids.append(claim.claim_id)
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
# Fallback: anything else goes to Interpretation + To Verify
|
|
137
|
+
block.interpretation_claim_ids.append(claim.claim_id)
|
|
138
|
+
block.to_verify_claim_ids.append(claim.claim_id)
|
|
139
|
+
if has_limitations:
|
|
140
|
+
block.limitation_claim_ids.append(claim.claim_id)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _populate_case_applicability(block: AnalysisBlock, claim: Claim) -> None:
|
|
144
|
+
"""Extract case applicability from claim metadata (PR 3)."""
|
|
145
|
+
meta = claim.metadata
|
|
146
|
+
if not meta:
|
|
147
|
+
return
|
|
148
|
+
|
|
149
|
+
comparable = meta.get("comparable_dimensions", [])
|
|
150
|
+
non_comparable = meta.get("non_comparable_dimensions", [])
|
|
151
|
+
market_ctx = meta.get("market_context", "")
|
|
152
|
+
stage_ctx = meta.get("stage_context", "")
|
|
153
|
+
audience_fit = meta.get("price_band_or_audience_fit", "")
|
|
154
|
+
needs_local = meta.get("local_verification_needed", False)
|
|
155
|
+
applicability = claim.applicability_reason or meta.get("applicability_reason", "")
|
|
156
|
+
|
|
157
|
+
if any([comparable, non_comparable, market_ctx, stage_ctx, audience_fit, needs_local, applicability]):
|
|
158
|
+
if block.case_applicability is None:
|
|
159
|
+
block.case_applicability = CaseApplicability()
|
|
160
|
+
if comparable:
|
|
161
|
+
block.case_applicability.comparable_dimensions.extend(comparable)
|
|
162
|
+
if non_comparable:
|
|
163
|
+
block.case_applicability.non_comparable_dimensions.extend(non_comparable)
|
|
164
|
+
if market_ctx:
|
|
165
|
+
block.case_applicability.market_context = market_ctx
|
|
166
|
+
if stage_ctx:
|
|
167
|
+
block.case_applicability.stage_context = stage_ctx
|
|
168
|
+
if audience_fit:
|
|
169
|
+
block.case_applicability.price_band_or_audience_fit = audience_fit
|
|
170
|
+
if needs_local:
|
|
171
|
+
block.case_applicability.local_verification_needed = True
|
|
172
|
+
if applicability:
|
|
173
|
+
if not block.applicability_note:
|
|
174
|
+
block.applicability_note = applicability
|
|
175
|
+
elif applicability not in block.applicability_note:
|
|
176
|
+
block.applicability_note += "; " + applicability
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _compute_confidence(block: AnalysisBlock, claims: list[Claim]) -> float:
|
|
180
|
+
"""Compute block confidence from claim evidence quality.
|
|
181
|
+
|
|
182
|
+
Epistemic hierarchy (strongest → weakest):
|
|
183
|
+
observed+direct (1.0) > interpreted (0.5) > analogous (0.4) > hypothesis (0.2)
|
|
184
|
+
Action claims with direct evidence score 1.0 (equivalent to observed+direct).
|
|
185
|
+
"""
|
|
186
|
+
if not claims:
|
|
187
|
+
return 0.0
|
|
188
|
+
|
|
189
|
+
score = 0.0
|
|
190
|
+
for claim in claims:
|
|
191
|
+
ep_type = claim.epistemic_type
|
|
192
|
+
ev_rel = claim.evidence_relation
|
|
193
|
+
if ep_type == "observed" and ev_rel == "direct":
|
|
194
|
+
score += 1.0
|
|
195
|
+
elif ep_type == "action" and ev_rel == "direct":
|
|
196
|
+
score += 1.0
|
|
197
|
+
elif ev_rel == "analogous":
|
|
198
|
+
score += 0.4
|
|
199
|
+
elif ep_type == "hypothesis":
|
|
200
|
+
score += 0.2
|
|
201
|
+
elif ep_type == "interpreted":
|
|
202
|
+
score += 0.5
|
|
203
|
+
else:
|
|
204
|
+
score += 0.3
|
|
205
|
+
|
|
206
|
+
return round(min(score / len(claims), 1.0), 2)
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"""Render AnalysisBlocks to structured markdown.
|
|
2
|
+
|
|
3
|
+
Produces a fixed-block format instead of prose:
|
|
4
|
+
Fact → Case/Comparison → Interpretation → Limitations → Action/To Verify
|
|
5
|
+
|
|
6
|
+
Different audiences get different heading labels, but the underlying
|
|
7
|
+
block structure is always the same.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from multi_agent_brief.analysis_blocks.schemas import AnalysisBlock
|
|
12
|
+
from multi_agent_brief.core.claim_ledger import ClaimLedger
|
|
13
|
+
from multi_agent_brief.core.schemas import Claim
|
|
14
|
+
|
|
15
|
+
# Audience-specific heading maps
|
|
16
|
+
_HEADING_MAPS: dict[str, dict[str, str]] = {
|
|
17
|
+
"management": {
|
|
18
|
+
"fact": "What Happened",
|
|
19
|
+
"case": "Comparable Context",
|
|
20
|
+
"interpretation": "Why It Matters",
|
|
21
|
+
"limitations": "Evidence Boundary",
|
|
22
|
+
"action": "What To Do",
|
|
23
|
+
"to_verify": "What To Verify Next",
|
|
24
|
+
},
|
|
25
|
+
"research": {
|
|
26
|
+
"fact": "Observed Facts",
|
|
27
|
+
"case": "Comparable Cases",
|
|
28
|
+
"interpretation": "Interpretation",
|
|
29
|
+
"limitations": "Limitations",
|
|
30
|
+
"action": "Recommended Actions",
|
|
31
|
+
"to_verify": "Pending Verification",
|
|
32
|
+
},
|
|
33
|
+
"default": {
|
|
34
|
+
"fact": "Fact",
|
|
35
|
+
"case": "Case / Comparison",
|
|
36
|
+
"interpretation": "Interpretation",
|
|
37
|
+
"limitations": "Limitations",
|
|
38
|
+
"action": "Action",
|
|
39
|
+
"to_verify": "To Verify",
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def render_analysis_blocks(
|
|
45
|
+
blocks: list[AnalysisBlock],
|
|
46
|
+
ledger: ClaimLedger,
|
|
47
|
+
*,
|
|
48
|
+
project_name: str = "",
|
|
49
|
+
audience: str = "default",
|
|
50
|
+
language: str = "en-US",
|
|
51
|
+
) -> str:
|
|
52
|
+
"""Render analysis blocks to structured markdown.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
blocks: AnalysisBlock instances from builder.
|
|
56
|
+
ledger: ClaimLedger for resolving claim details.
|
|
57
|
+
project_name: Optional project title shown at the top.
|
|
58
|
+
audience: Heading style key ("management", "research", "default").
|
|
59
|
+
language: "en-US" or "zh-CN".
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Structured markdown string.
|
|
63
|
+
"""
|
|
64
|
+
headings = _HEADING_MAPS.get(audience, _HEADING_MAPS["default"])
|
|
65
|
+
is_zh = language.startswith("zh")
|
|
66
|
+
|
|
67
|
+
parts: list[str] = []
|
|
68
|
+
if project_name:
|
|
69
|
+
parts.append(f"# {project_name}")
|
|
70
|
+
|
|
71
|
+
sections: list[str] = []
|
|
72
|
+
for block in blocks:
|
|
73
|
+
section = _render_block(block, ledger, headings, is_zh)
|
|
74
|
+
if section:
|
|
75
|
+
sections.append(section)
|
|
76
|
+
|
|
77
|
+
if not sections:
|
|
78
|
+
return _empty_message(is_zh)
|
|
79
|
+
|
|
80
|
+
parts.extend(sections)
|
|
81
|
+
return "\n\n".join(parts) + "\n"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _render_block(
|
|
85
|
+
block: AnalysisBlock,
|
|
86
|
+
ledger: ClaimLedger,
|
|
87
|
+
headings: dict[str, str],
|
|
88
|
+
is_zh: bool,
|
|
89
|
+
) -> str:
|
|
90
|
+
lines: list[str] = [f"## {block.title}", ""]
|
|
91
|
+
|
|
92
|
+
# Fact section — conditional like all other sections
|
|
93
|
+
if block.fact_claim_ids:
|
|
94
|
+
lines.append(f"### {headings['fact']}")
|
|
95
|
+
lines.append("")
|
|
96
|
+
fact_lines = _render_claim_list(block.fact_claim_ids, ledger)
|
|
97
|
+
if fact_lines:
|
|
98
|
+
lines.extend(fact_lines)
|
|
99
|
+
else:
|
|
100
|
+
lines.append(_no_fact_message(is_zh))
|
|
101
|
+
lines.append("")
|
|
102
|
+
|
|
103
|
+
# Case / Comparison section
|
|
104
|
+
case_lines = _render_claim_list(block.case_claim_ids, ledger)
|
|
105
|
+
if case_lines:
|
|
106
|
+
lines.append(f"### {headings['case']}")
|
|
107
|
+
lines.append("")
|
|
108
|
+
lines.extend(case_lines)
|
|
109
|
+
# Applicability note (PR 3)
|
|
110
|
+
if block.applicability_note:
|
|
111
|
+
lines.append("")
|
|
112
|
+
lines.append(f"> **{ _applicability_label(is_zh) }:** {block.applicability_note}")
|
|
113
|
+
if block.case_applicability:
|
|
114
|
+
ca = block.case_applicability
|
|
115
|
+
if ca.comparable_dimensions:
|
|
116
|
+
lines.append(f"> **{ _comparable_label(is_zh) }:** {', '.join(ca.comparable_dimensions)}")
|
|
117
|
+
if ca.non_comparable_dimensions:
|
|
118
|
+
lines.append(f"> **{ _non_comparable_label(is_zh) }:** {', '.join(ca.non_comparable_dimensions)}")
|
|
119
|
+
if ca.local_verification_needed:
|
|
120
|
+
lines.append(f"> ⚠️ { _local_verify_label(is_zh) }")
|
|
121
|
+
lines.append("")
|
|
122
|
+
|
|
123
|
+
# Interpretation section
|
|
124
|
+
interp_lines = _render_claim_list(block.interpretation_claim_ids, ledger)
|
|
125
|
+
if interp_lines:
|
|
126
|
+
lines.append(f"### {headings['interpretation']}")
|
|
127
|
+
lines.append("")
|
|
128
|
+
lines.extend(interp_lines)
|
|
129
|
+
lines.append("")
|
|
130
|
+
|
|
131
|
+
# Limitations section
|
|
132
|
+
limit_lines = _render_limitations(block, ledger, is_zh)
|
|
133
|
+
if limit_lines:
|
|
134
|
+
lines.append(f"### {headings['limitations']}")
|
|
135
|
+
lines.append("")
|
|
136
|
+
lines.extend(limit_lines)
|
|
137
|
+
lines.append("")
|
|
138
|
+
|
|
139
|
+
# Action section (only claims with direct evidence)
|
|
140
|
+
action_lines = _render_claim_list(block.action_claim_ids, ledger)
|
|
141
|
+
if action_lines:
|
|
142
|
+
lines.append(f"### {headings['action']}")
|
|
143
|
+
lines.append("")
|
|
144
|
+
lines.extend(action_lines)
|
|
145
|
+
lines.append("")
|
|
146
|
+
|
|
147
|
+
# To Verify section
|
|
148
|
+
verify_lines = _render_claim_list(block.to_verify_claim_ids, ledger)
|
|
149
|
+
if verify_lines:
|
|
150
|
+
lines.append(f"### {headings['to_verify']}")
|
|
151
|
+
lines.append("")
|
|
152
|
+
lines.extend(verify_lines)
|
|
153
|
+
if block.verification_path:
|
|
154
|
+
lines.append("")
|
|
155
|
+
lines.append(f"> **{ _verification_path_label(is_zh) }:** {block.verification_path}")
|
|
156
|
+
lines.append("")
|
|
157
|
+
|
|
158
|
+
# Confidence footer (qualitative label, not percentage — avoids audit false positives)
|
|
159
|
+
lines.append(f"_{ _confidence_label(is_zh) }: { _confidence_level(block.confidence, is_zh) }_")
|
|
160
|
+
lines.append("")
|
|
161
|
+
|
|
162
|
+
return "\n".join(lines)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _render_claim_list(claim_ids: list[str], ledger: ClaimLedger) -> list[str]:
|
|
166
|
+
lines = []
|
|
167
|
+
for cid in claim_ids:
|
|
168
|
+
claim = ledger.get_claim(cid)
|
|
169
|
+
if claim:
|
|
170
|
+
date_str = claim.metadata.get("published_at") or claim.metadata.get("retrieved_at", "")
|
|
171
|
+
date_prefix = f"{date_str} | " if date_str else ""
|
|
172
|
+
lines.append(f"- {date_prefix}{claim.statement} [src:{cid}]")
|
|
173
|
+
return lines
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _render_limitations(block: AnalysisBlock, ledger: ClaimLedger, is_zh: bool) -> list[str]:
|
|
177
|
+
lines = []
|
|
178
|
+
seen: set[str] = set()
|
|
179
|
+
for cid in block.limitation_claim_ids:
|
|
180
|
+
claim = ledger.get_claim(cid)
|
|
181
|
+
if not claim:
|
|
182
|
+
continue
|
|
183
|
+
for lim in claim.limitations:
|
|
184
|
+
normalized = lim.strip().lower()
|
|
185
|
+
if normalized not in seen:
|
|
186
|
+
seen.add(normalized)
|
|
187
|
+
lines.append(f"- {lim}")
|
|
188
|
+
return lines
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _no_fact_message(is_zh: bool) -> str:
|
|
192
|
+
if is_zh:
|
|
193
|
+
return "_未找到本期直接事实依据。_"
|
|
194
|
+
return "_No current-period direct fact found._"
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _empty_message(is_zh: bool) -> str:
|
|
198
|
+
if is_zh:
|
|
199
|
+
return "# 无可报告信号\n\n未发现符合条件的事实声明。\n"
|
|
200
|
+
return "# No Reportable Signals\n\nNo candidate claims were found.\n"
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _applicability_label(is_zh: bool) -> str:
|
|
204
|
+
return "适用性说明" if is_zh else "Applicability"
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _comparable_label(is_zh: bool) -> str:
|
|
208
|
+
return "可比维度" if is_zh else "Comparable Dimensions"
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _non_comparable_label(is_zh: bool) -> str:
|
|
212
|
+
return "不可比维度" if is_zh else "Non-Comparable Dimensions"
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _local_verify_label(is_zh: bool) -> str:
|
|
216
|
+
return "需要本地验证" if is_zh else "Local verification needed"
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _verification_path_label(is_zh: bool) -> str:
|
|
220
|
+
return "验证路径" if is_zh else "Verification Path"
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _confidence_label(is_zh: bool) -> str:
|
|
224
|
+
return "置信度" if is_zh else "Confidence"
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _confidence_level(score: float, is_zh: bool) -> str:
|
|
228
|
+
"""Map numeric confidence to qualitative label.
|
|
229
|
+
|
|
230
|
+
Avoids precise percentages that trigger audit false positives
|
|
231
|
+
(e.g. '100%' flagged as number_without_source).
|
|
232
|
+
"""
|
|
233
|
+
if score >= 0.8:
|
|
234
|
+
return "高" if is_zh else "High"
|
|
235
|
+
if score >= 0.5:
|
|
236
|
+
return "中" if is_zh else "Medium"
|
|
237
|
+
return "低" if is_zh else "Low"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Analysis Block schemas — epistemic presentation layer."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import asdict, dataclass, field
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class CaseApplicability:
|
|
10
|
+
"""Comparable case boundary metadata (PR 3 of v0.5.3)."""
|
|
11
|
+
|
|
12
|
+
comparable_dimensions: list[str] = field(default_factory=list)
|
|
13
|
+
non_comparable_dimensions: list[str] = field(default_factory=list)
|
|
14
|
+
market_context: str = ""
|
|
15
|
+
stage_context: str = ""
|
|
16
|
+
price_band_or_audience_fit: str = ""
|
|
17
|
+
local_verification_needed: bool = False
|
|
18
|
+
|
|
19
|
+
def to_dict(self) -> dict[str, Any]:
|
|
20
|
+
return asdict(self)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class AnalysisBlock:
|
|
25
|
+
"""One observation unit with epistemic classification.
|
|
26
|
+
|
|
27
|
+
Groups claim IDs by their epistemic role so the renderer can
|
|
28
|
+
present facts, cases, interpretations, limitations, and actions
|
|
29
|
+
in a fixed structure instead of prose.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
block_id: str
|
|
33
|
+
title: str
|
|
34
|
+
# Claim IDs by epistemic role
|
|
35
|
+
fact_claim_ids: list[str] = field(default_factory=list) # epistemic_type=observed, evidence_relation=direct
|
|
36
|
+
case_claim_ids: list[str] = field(default_factory=list) # evidence_relation=analogous
|
|
37
|
+
interpretation_claim_ids: list[str] = field(default_factory=list) # epistemic_type=hypothesis or interpreted
|
|
38
|
+
limitation_claim_ids: list[str] = field(default_factory=list) # claims with limitations
|
|
39
|
+
action_claim_ids: list[str] = field(default_factory=list) # epistemic_type=action WITH direct evidence
|
|
40
|
+
to_verify_claim_ids: list[str] = field(default_factory=list) # action without evidence, or hypothesis
|
|
41
|
+
# Metadata
|
|
42
|
+
applicability_note: str = ""
|
|
43
|
+
verification_path: str = ""
|
|
44
|
+
confidence: float = 0.0
|
|
45
|
+
# PR 3: comparable case boundary
|
|
46
|
+
case_applicability: CaseApplicability | None = None
|
|
47
|
+
|
|
48
|
+
def to_dict(self) -> dict[str, Any]:
|
|
49
|
+
data = asdict(self)
|
|
50
|
+
if self.case_applicability:
|
|
51
|
+
data["case_applicability"] = self.case_applicability.to_dict()
|
|
52
|
+
return data
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Analysis Modules — pluggable post-Screener analysis pipeline extensions.
|
|
2
|
+
|
|
3
|
+
Each module consumes a screened ClaimLedger and produces structured artifacts
|
|
4
|
+
(AnalysisCards, events, coverage reports, etc.) before the Analyst agent
|
|
5
|
+
writes the final brief. Modules are registered in MODULE_REGISTRY and enabled
|
|
6
|
+
via config.yaml's ``modules`` section.
|
|
7
|
+
"""
|
|
8
|
+
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Pluggable Analysis Module interface.
|
|
2
|
+
|
|
3
|
+
AnalysisModules run between Screener and Analyst in the pipeline.
|
|
4
|
+
They consume a screened ClaimLedger and produce structured artifacts
|
|
5
|
+
(analysis cards, events, coverage reports, etc.) — deterministically,
|
|
6
|
+
without external model calls. LLM subagents consume the artifacts
|
|
7
|
+
later to generate the final human-readable analysis.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from abc import ABC, abstractmethod
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from typing import Any, TYPE_CHECKING
|
|
15
|
+
|
|
16
|
+
from multi_agent_brief.core.schemas import AuditFinding
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from multi_agent_brief.core.claim_ledger import ClaimLedger
|
|
20
|
+
from multi_agent_brief.core.schemas import PipelineContext
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class ModuleOutput:
|
|
25
|
+
"""Output from a single AnalysisModule.analyze() call."""
|
|
26
|
+
|
|
27
|
+
module_name: str
|
|
28
|
+
artifacts: dict[str, Any] = field(default_factory=dict)
|
|
29
|
+
findings: list[AuditFinding] = field(default_factory=list)
|
|
30
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
31
|
+
|
|
32
|
+
def to_dict(self) -> dict[str, Any]:
|
|
33
|
+
return {
|
|
34
|
+
"module_name": self.module_name,
|
|
35
|
+
"artifacts": self.artifacts,
|
|
36
|
+
"findings": [f.to_dict() for f in self.findings],
|
|
37
|
+
"metadata": self.metadata,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class AnalysisModule(ABC):
|
|
42
|
+
"""Abstract base class for pluggable analysis modules.
|
|
43
|
+
|
|
44
|
+
Each module must provide:
|
|
45
|
+
|
|
46
|
+
- ``name`` — unique string key (e.g. ``"market_competitor"``).
|
|
47
|
+
- ``validate_config(config: dict) -> list[str]`` — return a list of
|
|
48
|
+
human-readable config errors (empty = valid).
|
|
49
|
+
- ``analyze(context, ledger) -> ModuleOutput`` — run the module's
|
|
50
|
+
deterministic analysis pass.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
name: str = ""
|
|
54
|
+
|
|
55
|
+
@abstractmethod
|
|
56
|
+
def validate_config(self, config: dict[str, Any]) -> list[str]:
|
|
57
|
+
"""Validate module-specific configuration.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
config: The module's section from config.yaml's ``modules`` block
|
|
61
|
+
(e.g. ``config["modules"]["market_competitor"]``), or an
|
|
62
|
+
empty dict if not present.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
A list of error messages. An empty list means "valid".
|
|
66
|
+
"""
|
|
67
|
+
raise NotImplementedError
|
|
68
|
+
|
|
69
|
+
@abstractmethod
|
|
70
|
+
def analyze(
|
|
71
|
+
self,
|
|
72
|
+
context: "PipelineContext",
|
|
73
|
+
ledger: "ClaimLedger",
|
|
74
|
+
) -> ModuleOutput:
|
|
75
|
+
"""Run the module's analysis on a screened ClaimLedger.
|
|
76
|
+
|
|
77
|
+
Modules MUST NOT modify the ClaimLedger — only read it.
|
|
78
|
+
Modules MUST NOT make external model/API calls — deterministic only.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
context: The pipeline context containing sources, metadata, etc.
|
|
82
|
+
ledger: The screened ClaimLedger (post-Screener).
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
A ModuleOutput with artifacts, findings, and metadata.
|
|
86
|
+
"""
|
|
87
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Market & Competitor Intelligence Analysis Module.
|
|
2
|
+
|
|
3
|
+
Pluggable analysis module that transforms Claim Ledger entries into structured
|
|
4
|
+
competitive intelligence artifacts:
|
|
5
|
+
- MarketEvent — source-grounded competitor/market events
|
|
6
|
+
- AnalysisCard — multi-source analytical judgments (LLM-generated)
|
|
7
|
+
- CompetitorMatrix — entity × dimension comparison table
|
|
8
|
+
- CoverageReport — entity/dimension coverage gaps
|
|
9
|
+
- Watchlist — cross-period tracking items
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
from multi_agent_brief.analysis_modules.base import AnalysisModule, ModuleOutput
|
|
17
|
+
from multi_agent_brief.analysis_modules.market_competitor.config import (
|
|
18
|
+
load_competitor_universe,
|
|
19
|
+
)
|
|
20
|
+
from multi_agent_brief.analysis_modules.market_competitor.event_builder import (
|
|
21
|
+
build_events,
|
|
22
|
+
)
|
|
23
|
+
from multi_agent_brief.analysis_modules.market_competitor.renderer import render_all
|
|
24
|
+
from multi_agent_brief.core.claim_ledger import ClaimLedger
|
|
25
|
+
from multi_agent_brief.core.schemas import PipelineContext
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class MarketCompetitorModule(AnalysisModule):
|
|
29
|
+
name = "market_competitor"
|
|
30
|
+
|
|
31
|
+
def validate_config(self, config: dict[str, Any]) -> list[str]:
|
|
32
|
+
errors: list[str] = []
|
|
33
|
+
if not isinstance(config, dict):
|
|
34
|
+
errors.append("market_competitor config must be a dict")
|
|
35
|
+
return errors
|
|
36
|
+
return errors
|
|
37
|
+
|
|
38
|
+
def analyze(self, context: PipelineContext, ledger: ClaimLedger) -> ModuleOutput:
|
|
39
|
+
config_dir = context.metadata.get("_config_dir", "")
|
|
40
|
+
output_dir = Path(context.output_dir)
|
|
41
|
+
|
|
42
|
+
# Load universe
|
|
43
|
+
universe_path = Path(config_dir) / "competitor_universe.yaml" if config_dir else None
|
|
44
|
+
universe = None
|
|
45
|
+
if universe_path and universe_path.exists():
|
|
46
|
+
universe = load_competitor_universe(universe_path)
|
|
47
|
+
|
|
48
|
+
if universe is None or not universe.enabled or not universe.entities:
|
|
49
|
+
return ModuleOutput(
|
|
50
|
+
module_name=self.name,
|
|
51
|
+
metadata={"status": "disabled", "reason": "no_entities"},
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Build events from entity-tagged claims
|
|
55
|
+
state_dir = str(Path(config_dir).parent / "state") if config_dir else None
|
|
56
|
+
events = build_events(ledger, universe, state_dir=state_dir)
|
|
57
|
+
|
|
58
|
+
# Render artifacts
|
|
59
|
+
artifact_paths = render_all(events, ledger, universe, output_dir)
|
|
60
|
+
|
|
61
|
+
return ModuleOutput(
|
|
62
|
+
module_name=self.name,
|
|
63
|
+
artifacts=artifact_paths,
|
|
64
|
+
metadata={
|
|
65
|
+
"event_count": len(events),
|
|
66
|
+
"entity_count": len(universe.entities),
|
|
67
|
+
},
|
|
68
|
+
)
|