eduevidence 5.2.0 → 6.2.0
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.
- package/CONTRIBUTING.md +105 -0
- package/README.md +142 -75
- package/README.zh-CN.md +73 -30
- package/SKILL.md +397 -131
- package/agents/openai.yaml +4 -0
- package/assets/readme/controlled-execution.svg +34 -0
- package/assets/readme/landing-tour.gif +0 -0
- package/assets/readme/logo.png +0 -0
- package/assets/readme/research-workflow.svg +56 -0
- package/assets/readme/studio-graph.png +0 -0
- package/assets/readme/studio-overview.png +0 -0
- package/assets/readme/studio-reports.png +0 -0
- package/assets/readme/studio-tour.gif +0 -0
- package/autoevolve/config.yaml +17 -0
- package/autoevolve/program.md +25 -0
- package/autoevolve/protected.manifest.yaml +34 -0
- package/benchmarks/adversarial/cases.jsonl +7 -0
- package/benchmarks/evidence-library.json +5268 -0
- package/benchmarks/partitions.json +8 -0
- package/bin/eduevidence.js +2 -1
- package/docs/architecture.md +496 -0
- package/docs/autoresearch-evolution-plan.md +2903 -0
- package/docs/autoresearch-implementation-status.md +101 -0
- package/docs/demo-storyboard.md +20 -0
- package/docs/demo-workplace-ai.md +92 -0
- package/docs/demo.md +32 -0
- package/docs/install-guide.md +150 -0
- package/docs/orchestration-role-model.md +1254 -0
- package/docs/release-closeout/README.md +17 -0
- package/docs/release-closeout/frontend-acceptance.md +23 -0
- package/docs/release-closeout/issues.md +19 -0
- package/docs/release-closeout/verification.md +28 -0
- package/docs/release-contract.md +108 -0
- package/docs/research-studio-guide.zh-CN.md +166 -0
- package/docs/sciverse-api.md +125 -0
- package/eduevidence_cli.py +29 -13
- package/engine/_resources.py +13 -0
- package/engine/autoevolve/__init__.py +3 -0
- package/engine/autoevolve/agent_view.py +167 -0
- package/engine/autoevolve/core.py +357 -0
- package/engine/autoevolve/events.py +11 -0
- package/engine/autoevolve/git_workspace.py +77 -0
- package/engine/autoevolve/projection.py +23 -0
- package/engine/autoevolve/runner.py +413 -0
- package/engine/autoevolve/trust.py +146 -0
- package/engine/autoresearch/__init__.py +6 -0
- package/engine/autoresearch/commit.py +132 -0
- package/engine/autoresearch/contracts.py +126 -0
- package/engine/autoresearch/controller.py +207 -0
- package/engine/autoresearch/events.py +12 -0
- package/engine/autoresearch/gap_priority.py +168 -0
- package/engine/autoresearch/projection.py +30 -0
- package/engine/autoresearch/research_memory.py +59 -0
- package/engine/autoresearch/saturation.py +91 -0
- package/engine/briefs.py +2 -1
- package/engine/capabilities.py +1 -0
- package/engine/contracts.py +3 -1
- package/engine/decision_policy.py +96 -0
- package/engine/evidence_graph.py +14 -10
- package/engine/evidencecore.py +7 -5
- package/engine/gaps.py +132 -73
- package/engine/ids.py +2 -0
- package/engine/judge_pack.py +65 -0
- package/engine/library.py +6 -2
- package/engine/library_builtin.py +3 -1
- package/engine/living.py +36 -5
- package/engine/meta_synthesis.py +3 -1
- package/engine/migration.py +88 -3
- package/engine/orchestration.py +460 -0
- package/engine/paths.py +2 -0
- package/engine/pilot.py +36 -33
- package/engine/project.py +2 -2
- package/engine/research_service.py +113 -0
- package/engine/studio_read_model.py +400 -0
- package/engine/taxonomy.py +211 -0
- package/engine/tribunal.py +44 -33
- package/engine/update.py +1 -0
- package/engine/versions.py +1 -1
- package/engine/worker_result.py +109 -0
- package/engine/workflows.py +70 -0
- package/examples/ai-coding-assistant-evidence/EduEvidence_Report.html +2934 -0
- package/examples/ai-coding-assistant-evidence/artifact_manifest.json +15 -0
- package/examples/ai-coding-assistant-evidence/citation_check.json +79 -0
- package/examples/ai-coding-assistant-evidence/claims.jsonl +12 -0
- package/examples/ai-coding-assistant-evidence/evaluation.json +35 -0
- package/examples/ai-coding-assistant-evidence/evidence.jsonl +12 -0
- package/examples/ai-coding-assistant-evidence/final_verdict.json +107 -0
- package/examples/ai-coding-assistant-evidence/frame.json +48 -0
- package/examples/ai-coding-assistant-evidence/gate_report.json +101 -0
- package/examples/ai-coding-assistant-evidence/intervention.json +51 -0
- package/examples/ai-coding-assistant-evidence/methodology.json +36 -0
- package/examples/ai-coding-assistant-evidence/raw_verdict.json +86 -0
- package/examples/ai-coding-assistant-evidence/report_spec.json +230 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_academic.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_claude.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_datalab-dark.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_datalab.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_presentation.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/report_academic.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/report_claude.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/report_datalab-dark.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/report_datalab.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/report_presentation.html +2934 -0
- package/examples/ai-coding-assistant-evidence/result.json +1457 -0
- package/examples/ai-coding-assistant-evidence/result.zh.json +1457 -0
- package/examples/ai-coding-assistant-evidence/skeptic.json +72 -0
- package/examples/ai-coding-assistant-evidence/sources.jsonl +8 -0
- package/examples/ai-coding-assistant-evidence/verdict.json +107 -0
- package/examples/spaced-retrieval-practice/applicability.json +14 -0
- package/examples/spaced-retrieval-practice/artifact_manifest.json +15 -0
- package/examples/spaced-retrieval-practice/claims.jsonl +3 -0
- package/examples/spaced-retrieval-practice/evidence.jsonl +6 -0
- package/examples/spaced-retrieval-practice/final_verdict.json +93 -0
- package/examples/spaced-retrieval-practice/frame.json +58 -0
- package/examples/spaced-retrieval-practice/gate_report.json +101 -0
- package/examples/spaced-retrieval-practice/methodology.json +78 -0
- package/examples/spaced-retrieval-practice/report_spec.json +212 -0
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_academic.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_claude.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_datalab-dark.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_datalab.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_presentation.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/report_academic.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/report_claude.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/report_datalab-dark.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/report_datalab.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/report_presentation.html +2728 -0
- package/examples/spaced-retrieval-practice/result.json +942 -0
- package/examples/spaced-retrieval-practice/result.zh.json +942 -0
- package/examples/spaced-retrieval-practice/skeptic.json +70 -0
- package/examples/spaced-retrieval-practice/sources.jsonl +7 -0
- package/examples/spaced-retrieval-practice/verdict.json +93 -0
- package/examples/workplace-ai-assistant/artifact_manifest.json +15 -0
- package/examples/workplace-ai-assistant/claims.jsonl +4 -0
- package/examples/workplace-ai-assistant/evaluation.json +19 -0
- package/examples/workplace-ai-assistant/evidence.jsonl +4 -0
- package/examples/workplace-ai-assistant/evidence_graph.json +444 -0
- package/examples/workplace-ai-assistant/final_verdict.json +78 -0
- package/examples/workplace-ai-assistant/frame.json +41 -0
- package/examples/workplace-ai-assistant/gate_report.json +101 -0
- package/examples/workplace-ai-assistant/intervention.json +27 -0
- package/examples/workplace-ai-assistant/legacy-link-check.json +16 -0
- package/examples/workplace-ai-assistant/methodology.json +60 -0
- package/examples/workplace-ai-assistant/report_spec.json +224 -0
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_academic.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_claude.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_datalab-dark.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_datalab.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_presentation.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/report_academic.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/report_claude.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/report_datalab-dark.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/report_datalab.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/report_presentation.html +2814 -0
- package/examples/workplace-ai-assistant/result.json +615 -0
- package/examples/workplace-ai-assistant/result.zh.json +615 -0
- package/examples/workplace-ai-assistant/search_log.json +19 -0
- package/examples/workplace-ai-assistant/skeptic.json +72 -0
- package/examples/workplace-ai-assistant/sources.jsonl +3 -0
- package/examples/workplace-ai-assistant/validation_result.json +9 -0
- package/examples/workplace-ai-assistant/verdict.json +78 -0
- package/install.sh +7 -7
- package/integrations/agent_mcp.py +2 -2
- package/integrations/orchestration_dispatch.py +146 -0
- package/package.json +46 -3
- package/pyproject.toml +14 -22
- package/references/autoresearch.md +30 -0
- package/references/evaluation-policy.md +24 -0
- package/references/orchestration.md +22 -0
- package/references/report-copy-style.md +67 -0
- package/references/retrieval-compliance.md +75 -0
- package/references/retrieval-protocol.md +20 -0
- package/references/scientific-invariants.md +19 -0
- package/retrieval/audit.py +178 -0
- package/retrieval/fetch.py +96 -0
- package/retrieval/sciverse.py +398 -0
- package/retrieval/search.py +47 -7
- package/schemas/applicability.schema.json +94 -0
- package/schemas/chart-spec.schema.json +10 -3
- package/schemas/evidence.schema.json +316 -43
- package/schemas/fetch-result.schema.json +2 -1
- package/schemas/intervention.schema.json +106 -21
- package/schemas/report-result.schema.json +12 -4
- package/schemas/report-spec.schema.json +98 -100
- package/schemas/skeptic.schema.json +86 -0
- package/schemas/source.schema.json +21 -2
- package/schemas/v2/finding.schema.json +5 -1
- package/schemas/v2/methodology-audit.schema.json +5 -1
- package/schemas/v2/outcome.schema.json +28 -5
- package/schemas/v2/project.schema.json +2 -2
- package/schemas/v2/run.schema.json +1 -1
- package/schemas/v2/study.schema.json +5 -1
- package/schemas/vNext/autoevolve-session.schema.json +34 -0
- package/schemas/vNext/eval-snapshot.schema.json +77 -0
- package/schemas/vNext/execution-plan.schema.json +50 -0
- package/schemas/vNext/gap-priority.schema.json +54 -0
- package/schemas/vNext/negative-search-record.schema.json +68 -0
- package/schemas/vNext/research-iteration.schema.json +87 -0
- package/schemas/vNext/research-strategy.schema.json +62 -0
- package/schemas/vNext/skill-experiment.schema.json +90 -0
- package/schemas/vNext/task-spec.schema.json +156 -0
- package/schemas/vNext/worker-result.schema.json +60 -0
- package/schemas/verdict.schema.json +164 -28
- package/scripts/benchmark_judge.py +2 -2
- package/scripts/benchmark_v3.py +26 -43
- package/scripts/build_esl_artifacts.py +4 -4
- package/scripts/build_evidence_library.py +2 -2
- package/scripts/build_gh_pages.py +98 -0
- package/scripts/build_readme_diagrams.py +72 -0
- package/scripts/build_report_variants.py +101 -0
- package/scripts/build_result.py +74 -9
- package/scripts/check_autoresearch_invariants.py +95 -0
- package/scripts/check_package_parity.py +85 -0
- package/scripts/check_protocol_alignment.py +375 -0
- package/scripts/check_versioned_schemas.py +254 -0
- package/scripts/claim_audit.py +13 -8
- package/scripts/compute_confidence.py +10 -0
- package/scripts/daily_evolve.py +30 -0
- package/scripts/dashboard_server.py +130 -101
- package/scripts/did_regression.py +17 -32
- package/scripts/enrich_projects_human_and_lieflat.py +1 -1
- package/scripts/evidence_score.py +5 -2
- package/scripts/generate_metrics.py +4 -3
- package/scripts/generate_new_projects.py +5 -5
- package/scripts/orchestrator.py +286 -36
- package/scripts/pre_verdict_gate.py +224 -26
- package/scripts/quickstart.py +18 -2
- package/scripts/rebake_all_5themes.py +1 -2
- package/scripts/research_auto_cli.py +475 -0
- package/scripts/run_workspace.py +24 -8
- package/scripts/search_provenance.py +64 -0
- package/scripts/serve_web.py +9 -10
- package/scripts/skill_lint.py +1 -1
- package/scripts/skill_payload.py +81 -0
- package/scripts/test_adversarial_empirical.py +26 -19
- package/scripts/validate_schema.py +46 -2
- package/scripts/vnext_cli.py +133 -0
- package/setup.py +12 -0
- package/skill/agents/evaluation-designer.md +20 -4
- package/skill/agents/evidence-analyst.md +19 -3
- package/skill/agents/evidence-judge.md +50 -2
- package/skill/agents/evidence-retriever.md +20 -3
- package/skill/agents/intervention-designer.md +20 -4
- package/skill/agents/method-reviewer.md +18 -2
- package/skill/agents/{education-planner.md → research-planner.md} +19 -3
- package/skill/agents/skeptic.md +18 -2
- package/skill/roles/registry.yaml +45 -0
- package/skill/sub-skills/aihot-trend-analysis/SKILL.md +28 -9
- package/skill/sub-skills/contradiction-analysis/SKILL.md +31 -11
- package/skill/sub-skills/data-analysis/SKILL.md +34 -15
- package/skill/sub-skills/ethics-review/SKILL.md +33 -10
- package/skill/sub-skills/evidence-extraction/SKILL.md +29 -11
- package/skill/sub-skills/evidence-review/SKILL.md +31 -12
- package/skill/sub-skills/gap-analysis/SKILL.md +31 -9
- package/skill/sub-skills/literature-review/SKILL.md +35 -14
- package/skill/sub-skills/methodology-audit/SKILL.md +29 -12
- package/skill/sub-skills/report-generation/SKILL.md +40 -6
- package/skill/sub-skills/research-planning/SKILL.md +41 -14
- package/skill/sub-skills/study-design/SKILL.md +30 -9
- package/skill/task-briefs/adjudicate.md +32 -7
- package/skill/task-briefs/applicability.md +38 -0
- package/skill/task-briefs/audit.md +32 -7
- package/skill/task-briefs/challenge.md +34 -5
- package/skill/task-briefs/evaluate.md +30 -5
- package/skill/task-briefs/extract.md +31 -8
- package/skill/task-briefs/frame.md +39 -10
- package/skill/task-briefs/intervene.md +32 -6
- package/skill/task-briefs/present.md +32 -8
- package/skill/task-briefs/projection.md +37 -0
- package/skill/task-briefs/retrieve.md +36 -6
- package/skill/workflows/decision-and-pilot.md +85 -0
- package/skill/workflows/evaluate-and-update.md +93 -0
- package/skill/workflows/evidence-review.md +117 -0
- package/visualization/eduevidence-report/assets/base.css +2 -2
- package/visualization/eduevidence-report/assets/reader.css +752 -0
- package/visualization/eduevidence-report/assets/reader.js +132 -0
- package/visualization/eduevidence-report/references/chart-selection-catalog.md +109 -0
- package/visualization/eduevidence-report/references/lieflat-composition.md +3 -1
- package/visualization/eduevidence-report/scripts/build_figures.py +25 -3
- package/visualization/eduevidence-report/scripts/build_infographics.py +5 -1
- package/visualization/eduevidence-report/scripts/build_report.py +561 -121
- package/visualization/eduevidence-report/scripts/charts_data.py +2 -0
- package/visualization/eduevidence-report/scripts/lieflat_engine.py +371 -136
- package/visualization/eduevidence-report/scripts/zh_labels.py +80 -1
- package/visualization/eduevidence-report/themes/academic.css +1 -1
- package/visualization/eduevidence-report/themes/claude.css +1 -1
- package/visualization/eduevidence-report/themes/datalab-dark.css +2 -2
- package/visualization/eduevidence-report/themes/datalab.css +2 -2
- package/visualization/eduevidence-report/themes/presentation.css +2 -2
- package/web/README.md +18 -0
- package/web/architecture.html +14885 -0
- package/web/index.html +53 -0
- package/web/studio/THIRD_PARTY_LICENSES.txt +146 -0
- package/web/studio/assets/index-B8tkF44Q.css +1 -0
- package/web/studio/assets/index-CQ6Keoyc.js +230 -0
- package/web/studio/config.json +1 -0
- package/web/studio/index.html +14 -0
- package/engine/__pycache__/__init__.cpython-312.pyc +0 -0
- package/engine/__pycache__/analysis.cpython-312.pyc +0 -0
- package/engine/__pycache__/bias.cpython-312.pyc +0 -0
- package/engine/__pycache__/briefs.cpython-312.pyc +0 -0
- package/engine/__pycache__/capabilities.cpython-312.pyc +0 -0
- package/engine/__pycache__/citation_check.cpython-312.pyc +0 -0
- package/engine/__pycache__/contracts.cpython-312.pyc +0 -0
- package/engine/__pycache__/datasets.cpython-312.pyc +0 -0
- package/engine/__pycache__/events.cpython-312.pyc +0 -0
- package/engine/__pycache__/evidence_graph.cpython-312.pyc +0 -0
- package/engine/__pycache__/evidence_review.cpython-312.pyc +0 -0
- package/engine/__pycache__/evidencecore.cpython-312.pyc +0 -0
- package/engine/__pycache__/gap_lens.cpython-312.pyc +0 -0
- package/engine/__pycache__/gaps.cpython-312.pyc +0 -0
- package/engine/__pycache__/graph_store.cpython-312.pyc +0 -0
- package/engine/__pycache__/graph_validate.cpython-312.pyc +0 -0
- package/engine/__pycache__/ids.cpython-312.pyc +0 -0
- package/engine/__pycache__/library.cpython-312.pyc +0 -0
- package/engine/__pycache__/library_builtin.cpython-312.pyc +0 -0
- package/engine/__pycache__/living.cpython-312.pyc +0 -0
- package/engine/__pycache__/log.cpython-312.pyc +0 -0
- package/engine/__pycache__/meta_analysis.cpython-312.pyc +0 -0
- package/engine/__pycache__/meta_synthesis.cpython-312.pyc +0 -0
- package/engine/__pycache__/migration.cpython-312.pyc +0 -0
- package/engine/__pycache__/mode_router.cpython-312.pyc +0 -0
- package/engine/__pycache__/paths.cpython-312.pyc +0 -0
- package/engine/__pycache__/pilot.cpython-312.pyc +0 -0
- package/engine/__pycache__/planner.cpython-312.pyc +0 -0
- package/engine/__pycache__/project.cpython-312.pyc +0 -0
- package/engine/__pycache__/projections.cpython-312.pyc +0 -0
- package/engine/__pycache__/robustness.cpython-312.pyc +0 -0
- package/engine/__pycache__/run.cpython-312.pyc +0 -0
- package/engine/__pycache__/semantics.cpython-312.pyc +0 -0
- package/engine/__pycache__/study_design.cpython-312.pyc +0 -0
- package/engine/__pycache__/synthesis.cpython-312.pyc +0 -0
- package/engine/__pycache__/tribunal.cpython-312.pyc +0 -0
- package/engine/__pycache__/update.cpython-312.pyc +0 -0
- package/engine/__pycache__/versions.cpython-312.pyc +0 -0
- package/integrations/__pycache__/__init__.cpython-312.pyc +0 -0
- package/integrations/__pycache__/agent_mcp.cpython-312.pyc +0 -0
- package/integrations/__pycache__/smart_web_fetch.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/__init__.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/corpus_store.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/dedupe.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/failures.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/fetch.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/search.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/source.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/validate.cpython-312.pyc +0 -0
- package/scripts/__pycache__/__init__.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_evaluator.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_judge.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_routing.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_v2.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_v3.cpython-312.pyc +0 -0
- package/scripts/__pycache__/build_result.cpython-312.pyc +0 -0
- package/scripts/__pycache__/claim_audit.cpython-312.pyc +0 -0
- package/scripts/__pycache__/complexity_gate.cpython-312.pyc +0 -0
- package/scripts/__pycache__/compute_confidence.cpython-312.pyc +0 -0
- package/scripts/__pycache__/dashboard_server.cpython-312.pyc +0 -0
- package/scripts/__pycache__/did_regression.cpython-312.pyc +0 -0
- package/scripts/__pycache__/effect_calculator.cpython-312.pyc +0 -0
- package/scripts/__pycache__/evidence_matrix.cpython-312.pyc +0 -0
- package/scripts/__pycache__/evidence_score.cpython-312.pyc +0 -0
- package/scripts/__pycache__/evidence_semantics.cpython-312.pyc +0 -0
- package/scripts/__pycache__/fetch_benchmark.cpython-312.pyc +0 -0
- package/scripts/__pycache__/lint_report_layout.cpython-312.pyc +0 -0
- package/scripts/__pycache__/orchestrator.cpython-312.pyc +0 -0
- package/scripts/__pycache__/pre_verdict_gate.cpython-312.pyc +0 -0
- package/scripts/__pycache__/recompute_demo_quality.cpython-312.pyc +0 -0
- package/scripts/__pycache__/render_report.cpython-312.pyc +0 -0
- package/scripts/__pycache__/render_report_html.cpython-312.pyc +0 -0
- package/scripts/__pycache__/run_workspace.cpython-312.pyc +0 -0
- package/scripts/__pycache__/skill_lint.cpython-312.pyc +0 -0
- package/scripts/__pycache__/startup_probe.cpython-312.pyc +0 -0
- package/scripts/__pycache__/sync_killer_demo_report.cpython-312.pyc +0 -0
- package/scripts/__pycache__/test_adversarial_empirical.cpython-312-pytest-9.0.2.pyc +0 -0
- package/scripts/__pycache__/test_adversarial_empirical.cpython-312-pytest-9.1.1.pyc +0 -0
- package/scripts/__pycache__/validate_schema.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/adapter_contract.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_artifact_manifest.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_charts.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_figures.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_infographics.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_report.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/charts_data.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/lieflat_engine.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/zh_labels.cpython-312.pyc +0 -0
package/scripts/orchestrator.py
CHANGED
|
@@ -10,14 +10,14 @@ stages); the two deterministic stages it executes locally are:
|
|
|
10
10
|
adjudicate — Pre-Verdict Gate (scripts/pre_verdict_gate.py) + deterministic
|
|
11
11
|
confidence (scripts/compute_confidence.py) producing
|
|
12
12
|
final_verdict.json from raw_verdict.json + evidence.jsonl
|
|
13
|
-
|
|
13
|
+
projection — assemble result.json and renderable projections from artifacts
|
|
14
14
|
(decision = final_verdict.json; claims carry claim_id per
|
|
15
15
|
report-result.schema.json)
|
|
16
16
|
|
|
17
17
|
Stage machine (execution_plan.json / state.json):
|
|
18
18
|
|
|
19
19
|
frame -> retrieve -> extract -> challenge -> audit -> adjudicate
|
|
20
|
-
-> intervene -> evaluate ->
|
|
20
|
+
-> applicability -> intervene -> evaluate -> projection
|
|
21
21
|
|
|
22
22
|
Each stage writes exactly one primary artifact and is schema-gated against
|
|
23
23
|
schemas/*. When the artifact is missing the orchestrator either seeds it from
|
|
@@ -51,6 +51,9 @@ for _p in (str(ROOT), str(ROOT / "scripts")):
|
|
|
51
51
|
if _p not in sys.path:
|
|
52
52
|
sys.path.insert(0, _p)
|
|
53
53
|
|
|
54
|
+
from engine._resources import resource_root # noqa: E402
|
|
55
|
+
ROOT = resource_root()
|
|
56
|
+
|
|
54
57
|
from run_workspace import (RESOURCE_POLICY_VERSION, STAGES, RunWorkspace, # noqa: E402
|
|
55
58
|
load_json, load_jsonl, next_run_id, save_jsonl)
|
|
56
59
|
from pre_verdict_gate import apply_enforcement, evaluate_workspace # noqa: E402
|
|
@@ -64,15 +67,20 @@ DEPTHS = ("S", "M", "L")
|
|
|
64
67
|
|
|
65
68
|
#: Stage -> primary artifact + schema gate + whether it is locally executable.
|
|
66
69
|
STAGE_SPEC: dict[str, dict[str, Any]] = {
|
|
67
|
-
|
|
70
|
+
# The frame contract belongs to the run's domain; the placeholder is
|
|
71
|
+
# resolved by frame_schema_for() below (education-frame.schema.json
|
|
72
|
+
# for education, domains/policy/frame.schema.json for policy, and so
|
|
73
|
+
# on for any domain registered under domains/).
|
|
74
|
+
"frame": {"artifact": "frame.json", "schema": "@domain_frame", "jsonl": False, "local": False},
|
|
68
75
|
"retrieve": {"artifact": "sources.jsonl", "schema": "source.schema.json", "jsonl": True, "local": False},
|
|
69
76
|
"extract": {"artifact": "evidence.jsonl", "schema": "evidence.schema.json", "jsonl": True, "local": False},
|
|
70
|
-
"challenge": {"artifact": "skeptic.json", "schema":
|
|
77
|
+
"challenge": {"artifact": "skeptic.json", "schema": "skeptic.schema.json", "jsonl": False, "local": False},
|
|
71
78
|
"audit": {"artifact": "methodology.json", "schema": "methodology.schema.json", "jsonl": False, "local": False},
|
|
72
79
|
"adjudicate": {"artifact": "final_verdict.json", "schema": "verdict.schema.json", "jsonl": False, "local": True},
|
|
80
|
+
"applicability": {"artifact": "applicability.json", "schema": "applicability.schema.json", "jsonl": False, "local": False},
|
|
73
81
|
"intervene": {"artifact": "intervention.json", "schema": "intervention.schema.json", "jsonl": False, "local": False},
|
|
74
82
|
"evaluate": {"artifact": "evaluation.json", "schema": "evaluation.schema.json", "jsonl": False, "local": False},
|
|
75
|
-
"
|
|
83
|
+
"projection": {"artifact": "result.json", "schema": "report-result.schema.json", "jsonl": False, "local": True},
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
#: Phase 33 — canonical failure -> handling-action mapping. Extends the
|
|
@@ -143,11 +151,14 @@ _STAGE_BRIEFS: dict[str, str] = {
|
|
|
143
151
|
"adjudicate": ("Judge the evidence: write raw_verdict.json (model verdict). The orchestrator "
|
|
144
152
|
"then runs the Pre-Verdict Gate and deterministic confidence to produce "
|
|
145
153
|
"final_verdict.json."),
|
|
154
|
+
"applicability": ("Assess whether supported effects apply to the target population, setting, "
|
|
155
|
+
"implementation constraints and outcomes; write applicability.json. Do not "
|
|
156
|
+
"upgrade a decision merely because evidence is present."),
|
|
146
157
|
"intervene": ("Design the minimal verifiable teaching intervention (phased pilot, "
|
|
147
158
|
"stop conditions, evidence alignment); write intervention.json."),
|
|
148
159
|
"evaluate": ("Design the evaluation plan (baseline/post/retention/transfer, task vs learning "
|
|
149
160
|
"separation); write evaluation.json."),
|
|
150
|
-
"
|
|
161
|
+
"projection": ("Translate result.json into result.zh.json and render report_spec.json / "
|
|
151
162
|
"report.html via the visualization layer."),
|
|
152
163
|
}
|
|
153
164
|
|
|
@@ -179,11 +190,16 @@ def init_run(
|
|
|
179
190
|
run_id: str | None = None,
|
|
180
191
|
approve_agent_mcp: bool = False,
|
|
181
192
|
scp_available: bool | None = None,
|
|
193
|
+
approval_record: dict | None = None,
|
|
194
|
+
domain: str = "education",
|
|
182
195
|
) -> RunWorkspace:
|
|
183
196
|
"""Create the run workspace + manifest + planning artifacts (Phase 11-13)."""
|
|
184
197
|
depth = DEPTH_ALIASES.get(depth, depth)
|
|
185
198
|
if depth not in DEPTHS:
|
|
186
199
|
raise ValueError(f"unknown depth {depth!r}; use quick/standard/deep or S/M/L")
|
|
200
|
+
# Validate the domain up front: every later stage gate reads it from the
|
|
201
|
+
# manifest, so an unknown id must fail here rather than mid-run.
|
|
202
|
+
domain_frame_schema(domain)
|
|
187
203
|
|
|
188
204
|
try:
|
|
189
205
|
from integrations.agent_mcp import detect_agent_mcp
|
|
@@ -206,6 +222,7 @@ def init_run(
|
|
|
206
222
|
agent_mcp_available=agent_available,
|
|
207
223
|
agent_mcp_approved=approve_agent_mcp,
|
|
208
224
|
root=ROOT,
|
|
225
|
+
domain=domain,
|
|
209
226
|
)
|
|
210
227
|
ws.save_manifest(manifest)
|
|
211
228
|
|
|
@@ -256,7 +273,7 @@ def init_run(
|
|
|
256
273
|
"run_id": run_id,
|
|
257
274
|
"execution_mode": agent_mode,
|
|
258
275
|
"routing": {
|
|
259
|
-
"
|
|
276
|
+
"research-planner": "strong/reasoning",
|
|
260
277
|
"evidence-retriever": "fast/low-cost",
|
|
261
278
|
"evidence-analyst": "strong/structured",
|
|
262
279
|
"skeptic": "independent/reasoning",
|
|
@@ -275,6 +292,16 @@ def init_run(
|
|
|
275
292
|
"reason": ("user-approved via --approve-agent-mcp"
|
|
276
293
|
if approve_agent_mcp else "not yet approved; runs in platform-native mode"),
|
|
277
294
|
}
|
|
295
|
+
if approval_record:
|
|
296
|
+
agent_mcp_approval["approval_global_path"] = str(_global_approval_path())
|
|
297
|
+
agent_mcp_approval["role_mapping_hash"] = approval_record.get("role_mapping_hash")
|
|
298
|
+
agent_mcp_approval["roles"] = approval_record.get("roles", {})
|
|
299
|
+
agent_mcp_approval["approved_at"] = _utc_now()
|
|
300
|
+
agent_mcp_approval["reason"] = "user-confirmed role mapping (global approval, hash-verified)"
|
|
301
|
+
elif approve_agent_mcp:
|
|
302
|
+
agent_mcp_approval["reason"] = (
|
|
303
|
+
"user-approved via --approve-agent-mcp (boolean only; a role mapping "
|
|
304
|
+
"in the global approval is required before any spawn)")
|
|
278
305
|
|
|
279
306
|
for name, data in (("capability_plan", capability_plan),
|
|
280
307
|
("resource_plan", resource_plan),
|
|
@@ -301,27 +328,67 @@ def _load_artifact(ws: RunWorkspace, artifact: str) -> list[dict[str, Any]]:
|
|
|
301
328
|
return [data] if data else []
|
|
302
329
|
|
|
303
330
|
|
|
331
|
+
|
|
332
|
+
#: Placeholder replaced by the run's registered frame schema.
|
|
333
|
+
DOMAIN_FRAME_SENTINEL = "@domain_frame"
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def domain_frame_schema(domain: str) -> str:
|
|
337
|
+
"""Registered frame schema for a domain, relative to the repository root.
|
|
338
|
+
|
|
339
|
+
Raises ValueError for an unknown domain so a typo fails loudly instead of
|
|
340
|
+
silently validating against the education contract.
|
|
341
|
+
"""
|
|
342
|
+
try:
|
|
343
|
+
from engine.evidencecore import load_domain
|
|
344
|
+
|
|
345
|
+
entry = load_domain(domain)
|
|
346
|
+
except KeyError as exc:
|
|
347
|
+
raise ValueError(str(exc)) from exc
|
|
348
|
+
return str(entry["frame_schema"]) # type: ignore[return-value]
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def frame_schema_for(ws: "RunWorkspace") -> str:
|
|
352
|
+
"""The frame schema this run must satisfy (from its manifest domain)."""
|
|
353
|
+
domain = str(ws.load_manifest().get("domain") or "education")
|
|
354
|
+
return domain_frame_schema(domain)
|
|
355
|
+
|
|
356
|
+
|
|
304
357
|
def schema_gate(ws: RunWorkspace, stage: str) -> dict[str, Any]:
|
|
305
358
|
"""Validate a stage's primary artifact against its schema. Never raises."""
|
|
306
359
|
spec = STAGE_SPEC[stage]
|
|
307
360
|
artifact = spec["artifact"]
|
|
308
361
|
schema_name = spec["schema"]
|
|
309
|
-
if schema_name
|
|
362
|
+
if schema_name == DOMAIN_FRAME_SENTINEL:
|
|
363
|
+
# The frame contract is per-domain; resolve it from the run manifest.
|
|
364
|
+
try:
|
|
365
|
+
schema_name = frame_schema_for(ws)
|
|
366
|
+
except ValueError as exc:
|
|
367
|
+
return {"passed": False, "stage": stage, "artifact": artifact,
|
|
368
|
+
"schema": DOMAIN_FRAME_SENTINEL,
|
|
369
|
+
"issues": [f"unknown run domain: {exc}"]}
|
|
370
|
+
if schema_name is None: # lightweight parseability contract
|
|
310
371
|
data = load_json(ws.path / artifact)
|
|
311
372
|
ok = bool(data) and isinstance(data, dict)
|
|
312
373
|
return {"passed": ok, "stage": stage, "artifact": artifact,
|
|
313
|
-
"schema": None, "issues": [] if ok else ["
|
|
374
|
+
"schema": None, "issues": [] if ok else [f"{artifact} missing or unparseable"]}
|
|
314
375
|
|
|
315
376
|
from validate_schema import SchemaError, Validator
|
|
316
377
|
|
|
317
378
|
schemas_dir = ROOT / "schemas"
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
379
|
+
schema_path = schemas_dir / schema_name
|
|
380
|
+
if not schema_path.is_file():
|
|
381
|
+
# A domain may own its frame schema outside schemas/ (policy does).
|
|
382
|
+
candidate = ROOT / schema_name
|
|
383
|
+
if candidate.is_file():
|
|
384
|
+
schema_path = candidate
|
|
385
|
+
else:
|
|
386
|
+
share_candidates = (Path(sys.prefix) / "share" / "eduevidence" / schema_name,
|
|
387
|
+
Path(sys.prefix) / "share" / "eduevidence" / "schemas" / schema_name)
|
|
388
|
+
schema_path = next((c for c in share_candidates if c.is_file()), schema_path)
|
|
322
389
|
|
|
323
390
|
try:
|
|
324
|
-
schema = json.loads(
|
|
391
|
+
schema = json.loads(schema_path.read_text(encoding="utf-8"))
|
|
325
392
|
except OSError:
|
|
326
393
|
return {"passed": False, "stage": stage, "artifact": artifact,
|
|
327
394
|
"schema": schema_name, "issues": [f"schema file {schema_name} not found"]}
|
|
@@ -380,22 +447,52 @@ def derive_sources_from_evidence(evidence: list[dict[str, Any]]) -> list[dict[st
|
|
|
380
447
|
return list(seen.values())
|
|
381
448
|
|
|
382
449
|
|
|
450
|
+
#: The nine checks the skeptic contract requires (skill/task-briefs/challenge.md).
|
|
451
|
+
SKEPTIC_CHECKS = (
|
|
452
|
+
"1_null_result", "2_negative_result", "3_contradictory_evidence",
|
|
453
|
+
"4_alternative_explanation", "5_measurement_mismatch", "6_sampling_bias",
|
|
454
|
+
"7_novelty_effect", "8_ai_dependency", "9_scope_overreach",
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
|
|
383
458
|
def derive_skeptic_from_evidence(evidence: list[dict[str, Any]]) -> dict[str, Any]:
|
|
384
459
|
"""Deterministic skeptic summary derived from evidence directions (demo/test mode).
|
|
385
460
|
|
|
386
461
|
Records what the corpus itself contains (contradictions / null results /
|
|
387
|
-
confounders); it never invents counter-evidence.
|
|
462
|
+
confounders); it never invents counter-evidence. Field names follow the
|
|
463
|
+
challenge brief and the skeptic role prompt so the Pre-Verdict Gate reads
|
|
464
|
+
the same keys this writes.
|
|
388
465
|
"""
|
|
389
|
-
contradictions = [e.get("evidence_id") for e in evidence
|
|
390
|
-
|
|
466
|
+
contradictions = [e.get("evidence_id") for e in evidence
|
|
467
|
+
if (e.get("relation_to_claim") or e.get("direction")) == "contradict"]
|
|
468
|
+
null_results = [e.get("evidence_id") for e in evidence
|
|
469
|
+
if e.get("effect_direction") == "null"]
|
|
391
470
|
confounders = sorted({c for e in evidence for c in (e.get("confounders", []) or [])})
|
|
471
|
+
|
|
472
|
+
status_for = {
|
|
473
|
+
"1_null_result": "found" if null_results else "not_found",
|
|
474
|
+
"2_negative_result": "found" if any(
|
|
475
|
+
e.get("effect_direction") == "negative" for e in evidence) else "not_found",
|
|
476
|
+
"3_contradictory_evidence": "found" if contradictions else "not_found",
|
|
477
|
+
"4_alternative_explanation": "found" if confounders else "not_found",
|
|
478
|
+
}
|
|
479
|
+
findings = []
|
|
480
|
+
for check in SKEPTIC_CHECKS:
|
|
481
|
+
findings.append({
|
|
482
|
+
"check": check,
|
|
483
|
+
"status": status_for.get(check, "not_found"),
|
|
484
|
+
"detail": "derived from the evidence corpus in demo/test mode",
|
|
485
|
+
"related_evidence_ids": (contradictions if "contradict" in check
|
|
486
|
+
else null_results if "null" in check else []),
|
|
487
|
+
})
|
|
392
488
|
return {
|
|
393
489
|
"search_performed": True,
|
|
394
490
|
"method": "derived from evidence corpus directions (demo/test mode)",
|
|
395
|
-
"
|
|
396
|
-
"
|
|
397
|
-
"
|
|
398
|
-
|
|
491
|
+
"skeptic_findings": findings,
|
|
492
|
+
"contradictory_evidence_found": bool(contradictions),
|
|
493
|
+
"no_contradictory_evidence_statement": (
|
|
494
|
+
"" if contradictions else "NO CONTRADICTORY EVIDENCE FOUND"),
|
|
495
|
+
"threats_to_validity": confounders,
|
|
399
496
|
}
|
|
400
497
|
|
|
401
498
|
|
|
@@ -404,7 +501,13 @@ def _cap_verdict(gate: dict[str, Any], raw_verdict: dict[str, Any],
|
|
|
404
501
|
"""Build final_verdict.json: deterministic confidence + gate enforcement."""
|
|
405
502
|
final = copy.deepcopy(raw_verdict)
|
|
406
503
|
final["raw_model_confidence"] = raw_verdict.get("confidence")
|
|
407
|
-
|
|
504
|
+
# The schema types this as an object; a model verdict without the field
|
|
505
|
+
# produced None here, which made the written file schema-invalid and the
|
|
506
|
+
# gate fail on data the pipeline had just produced.
|
|
507
|
+
final["raw_model_confidence_breakdown"] = (
|
|
508
|
+
raw_verdict.get("confidence_breakdown")
|
|
509
|
+
if isinstance(raw_verdict.get("confidence_breakdown"), dict)
|
|
510
|
+
else {})
|
|
408
511
|
final["confidence"] = computed["confidence"]
|
|
409
512
|
final["confidence_score"] = computed["confidence_breakdown"].get("score")
|
|
410
513
|
final["confidence_policy_version"] = computed["confidence_policy_version"]
|
|
@@ -512,7 +615,8 @@ def _assemble_result(ws: RunWorkspace, manifest: dict[str, Any]) -> dict[str, An
|
|
|
512
615
|
"methodology_reviews": methodology_list,
|
|
513
616
|
"conflicts": [{"reason_for_disagreement": verdict.get("reason_for_disagreement", "")}]
|
|
514
617
|
if verdict.get("reason_for_disagreement") else [],
|
|
515
|
-
"applicability":
|
|
618
|
+
"applicability": (load_json(ws.path / "applicability.json")
|
|
619
|
+
or verdict.get("applicability", {})),
|
|
516
620
|
"intervention": intervention,
|
|
517
621
|
"evaluation": evaluation,
|
|
518
622
|
"benchmark": {},
|
|
@@ -520,14 +624,14 @@ def _assemble_result(ws: RunWorkspace, manifest: dict[str, Any]) -> dict[str, An
|
|
|
520
624
|
}
|
|
521
625
|
|
|
522
626
|
|
|
523
|
-
def
|
|
524
|
-
|
|
525
|
-
"""
|
|
627
|
+
def _run_projection(ws: RunWorkspace, manifest: dict[str, Any], question: str,
|
|
628
|
+
demo_pack: Path | None = None) -> dict[str, Any]:
|
|
629
|
+
"""Build projections after science; this is not a scientific protocol stage."""
|
|
526
630
|
required = ("final_verdict.json", "intervention.json", "evaluation.json")
|
|
527
631
|
missing = [name for name in required if not (ws.path / name).is_file()
|
|
528
632
|
or not load_json(ws.path / name)]
|
|
529
633
|
if missing:
|
|
530
|
-
ws.write_brief("
|
|
634
|
+
ws.write_brief("projection", question, _STAGE_BRIEFS["projection"])
|
|
531
635
|
return {"status": "pending",
|
|
532
636
|
"detail": f"missing prerequisite artifacts: {', '.join(missing)}"}
|
|
533
637
|
|
|
@@ -550,7 +654,7 @@ def _run_present(ws: RunWorkspace, manifest: dict[str, Any], question: str,
|
|
|
550
654
|
result = _assemble_result(ws, manifest)
|
|
551
655
|
(ws.path / "result.json").write_text(
|
|
552
656
|
json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
553
|
-
gate = schema_gate(ws, "
|
|
657
|
+
gate = schema_gate(ws, "projection")
|
|
554
658
|
if not gate["passed"]:
|
|
555
659
|
return {"status": "failed", "detail": f"result.json schema gate: {gate['issues']}"}
|
|
556
660
|
missing_render = [n for n in ("result.zh.json", "report_spec.json", "report.html")
|
|
@@ -576,6 +680,10 @@ def run_stage(ws: RunWorkspace, stage: str, *, demo_pack: Path | None = None) ->
|
|
|
576
680
|
Deterministic stages execute locally; external stages are either seeded
|
|
577
681
|
from ``demo_pack`` (demo/test mode) or handed off via a task brief.
|
|
578
682
|
"""
|
|
683
|
+
# Compatibility for callers of the retired name. State/manifests only
|
|
684
|
+
# record ``projection`` from this point forward.
|
|
685
|
+
if stage == "present":
|
|
686
|
+
stage = "projection"
|
|
579
687
|
ws.trace("stage_started", stage=stage)
|
|
580
688
|
log.info("stage=%s run=%s start", stage, ws.run_id)
|
|
581
689
|
spec = STAGE_SPEC[stage]
|
|
@@ -598,8 +706,8 @@ def run_stage(ws: RunWorkspace, stage: str, *, demo_pack: Path | None = None) ->
|
|
|
598
706
|
# local deterministic stages
|
|
599
707
|
if stage == "adjudicate":
|
|
600
708
|
result = _run_adjudicate(ws, question, demo_pack=demo_pack)
|
|
601
|
-
elif stage == "
|
|
602
|
-
result =
|
|
709
|
+
elif stage == "projection":
|
|
710
|
+
result = _run_projection(ws, ws.load_manifest(), question, demo_pack=demo_pack)
|
|
603
711
|
else:
|
|
604
712
|
# demo/test seeding
|
|
605
713
|
if demo_pack is not None:
|
|
@@ -666,6 +774,27 @@ def _seed_from_demo(ws: RunWorkspace, stage: str, demo_pack: Path) -> dict[str,
|
|
|
666
774
|
if (pack / "methodology.json").is_file():
|
|
667
775
|
(ws.path / "methodology.json").write_bytes((pack / "methodology.json").read_bytes())
|
|
668
776
|
return {"seeded": True, "detail": "methodology.json seeded from demo pack"}
|
|
777
|
+
elif stage == "applicability":
|
|
778
|
+
if (pack / "applicability.json").is_file():
|
|
779
|
+
(ws.path / "applicability.json").write_bytes((pack / "applicability.json").read_bytes())
|
|
780
|
+
else:
|
|
781
|
+
verdict = load_json(ws.path / "final_verdict.json") or load_json(pack / "verdict.json")
|
|
782
|
+
value = verdict.get("applicability") if isinstance(verdict, dict) else None
|
|
783
|
+
# A demo can only carry the decision's existing applicability
|
|
784
|
+
# boundary; absence remains explicit rather than inferred.
|
|
785
|
+
# The derived boundary is tagged ASSESSED so it satisfies the
|
|
786
|
+
# applicability contract instead of being an unlabelled dict.
|
|
787
|
+
if isinstance(value, dict) and value:
|
|
788
|
+
payload = {"status": "ASSESSED"}
|
|
789
|
+
payload.update(value)
|
|
790
|
+
else:
|
|
791
|
+
payload = {
|
|
792
|
+
"status": "NOT_CAPTURED",
|
|
793
|
+
"reason": "demo pack does not provide an applicability assessment",
|
|
794
|
+
}
|
|
795
|
+
(ws.path / "applicability.json").write_text(
|
|
796
|
+
json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
797
|
+
return {"seeded": True, "detail": "applicability.json seeded from decision boundary (demo)"}
|
|
669
798
|
elif stage == "intervene":
|
|
670
799
|
if (pack / "intervention.json").is_file():
|
|
671
800
|
(ws.path / "intervention.json").write_bytes((pack / "intervention.json").read_bytes())
|
|
@@ -732,6 +861,9 @@ def interactive_agent_mcp_setup(approved: bool) -> bool:
|
|
|
732
861
|
|
|
733
862
|
保留 GitHub 版全部行为(--approve-agent-mcp 旗标、agent_mcp_approval.json、
|
|
734
863
|
safe_spawn 门);此处只补 run 启动时的交互提示层。非交互终端直接返回原值。
|
|
864
|
+
新增:Agent MCP 可用时,生成角色→CLI→模型推荐表,询问用户是否采用并
|
|
865
|
+
固化到全局 ~/.eduevidence/agent_mcp_approval.json(含 hash 防篡改);
|
|
866
|
+
确认后返回 True,调用方可把该记录带入本次 run 的批准工件。
|
|
735
867
|
"""
|
|
736
868
|
if approved:
|
|
737
869
|
return True
|
|
@@ -779,13 +911,78 @@ def interactive_agent_mcp_setup(approved: bool) -> bool:
|
|
|
779
911
|
return False
|
|
780
912
|
|
|
781
913
|
answer = input("是否启用 Agent MCP 增强模式(推荐)?[Y/n] ").strip().lower()
|
|
782
|
-
|
|
914
|
+
if answer in ("n", "no"):
|
|
915
|
+
return False
|
|
916
|
+
|
|
917
|
+
# Agent MCP 可用:生成推荐表并询问是否固化到全局(简短的 8 角色表)。
|
|
918
|
+
approved_now, _ = _confirm_global_approval()
|
|
919
|
+
return approved_now
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
def _global_approval_path() -> Path:
|
|
923
|
+
"""全局用户批准文件:EDUEVIDENCE_HOME 优先,缺省 ~/.eduevidence。"""
|
|
924
|
+
home = Path(os.environ.get("EDUEVIDENCE_HOME", "~/.eduevidence")).expanduser()
|
|
925
|
+
return home / "agent_mcp_approval.json"
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
def _confirm_global_approval() -> tuple[bool, dict | None]:
|
|
929
|
+
"""构建角色推荐表 → 展示 → 询问 → 固化;返回 (approved, approval_record)。
|
|
930
|
+
|
|
931
|
+
- available CLIs 只扫描本机真实存在的(omp/codex/claude/grok/opencode),
|
|
932
|
+
不猜模型;无任何可用 CLI 时回退为布尔批准。
|
|
933
|
+
- 任何展示内容都只来自已验证模型清单;推荐行缺少 cli/model 的角色
|
|
934
|
+
不进映射(safe_spawn 会对该角色保持关闭)。
|
|
935
|
+
- 用户确认后写 ~/.eduevidence/agent_mcp_approval.json(含 role_mapping_hash),
|
|
936
|
+
后续 run 加载并校验:映射变更即失效,需重新确认。
|
|
937
|
+
"""
|
|
938
|
+
import shutil as _shutil
|
|
939
|
+
from integrations.agent_mcp import (build_recommendation_table,
|
|
940
|
+
scan_available_models, write_approval)
|
|
941
|
+
|
|
942
|
+
allowed_clis = [c for c in ("omp", "codex", "claude", "grok", "opencode")
|
|
943
|
+
if _shutil.which(c)]
|
|
944
|
+
if not allowed_clis:
|
|
945
|
+
return True, None
|
|
946
|
+
inventory = scan_available_models(allowed_clis, timeout=20)
|
|
947
|
+
table = build_recommendation_table(allowed_clis, inventory)
|
|
948
|
+
rows = [r for r in table["recommendations"] if r.get("cli") and r.get("model")]
|
|
949
|
+
if not rows:
|
|
950
|
+
print("[startup] 未能从已安装 CLI 解析到已验证模型;按布尔批准启用。")
|
|
951
|
+
return True, None
|
|
952
|
+
|
|
953
|
+
print("[startup] 角色 → CLI / 模型 推荐表(仅基于本机扫描到的可用模型,无固定推荐):")
|
|
954
|
+
for r in rows:
|
|
955
|
+
print(f" {r['role']:<20} → {r['cli']} / {r['model']}")
|
|
956
|
+
summary = table.get("summary", {})
|
|
957
|
+
print(f" cross_model_review(反证异族复核): {summary.get('cross_model_review', 'unknown')}"
|
|
958
|
+
f" | 角色数: {summary.get('role_count', len(rows))}")
|
|
959
|
+
answer = input("采用推荐表并固化到全局批准文件?[Y/n] ").strip().lower()
|
|
960
|
+
if answer in ("n", "no"):
|
|
961
|
+
print("[startup] 未固化;本次以平台原生模式运行(可用 --approve-agent-mcp 跳过询问)。")
|
|
962
|
+
return False, None
|
|
963
|
+
roles = {r["role"]: {"cli": r["cli"], "model": r["model"]} for r in rows}
|
|
964
|
+
path = _global_approval_path()
|
|
965
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
966
|
+
record = write_approval(path, roles, sorted(allowed_clis))
|
|
967
|
+
print(f"[startup] 已固化 → {path}")
|
|
968
|
+
return True, record
|
|
969
|
+
|
|
970
|
+
|
|
971
|
+
def load_global_approval() -> dict | None:
|
|
972
|
+
"""加载全局批准文件(missing/corrupt -> None;有效期交由
|
|
973
|
+
integrations.agent_mcp.is_approval_current 判定)。"""
|
|
974
|
+
from integrations.agent_mcp import load_approval
|
|
975
|
+
return load_approval(_global_approval_path())
|
|
783
976
|
|
|
784
977
|
|
|
785
978
|
def _cmd_run(args: argparse.Namespace) -> int:
|
|
786
979
|
approve = args.approve_agent_mcp or interactive_agent_mcp_setup(args.approve_agent_mcp)
|
|
980
|
+
approval_record = None
|
|
981
|
+
if approve:
|
|
982
|
+
approval_record = load_global_approval()
|
|
787
983
|
ws = init_run(Path(args.runs_dir), args.question, depth=args.depth, run_id=args.run_id,
|
|
788
|
-
approve_agent_mcp=approve
|
|
984
|
+
approve_agent_mcp=approve, approval_record=approval_record,
|
|
985
|
+
domain=getattr(args, "domain", "education"))
|
|
789
986
|
print(f"workspace created: {ws.path}")
|
|
790
987
|
print(f"manifest: {json.dumps(ws.load_manifest(), ensure_ascii=False, indent=2)}")
|
|
791
988
|
if args.dry_run:
|
|
@@ -984,9 +1181,15 @@ def _cmd_synthesize(args) -> int:
|
|
|
984
1181
|
def _cmd_benchmark(args) -> int:
|
|
985
1182
|
import benchmark_v3 as bv3
|
|
986
1183
|
if args.action == "run":
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1184
|
+
argv = ["run", "--baselines", args.baselines, "--questions", args.questions,
|
|
1185
|
+
"--repeats", str(args.repeats), "--out", args.out,
|
|
1186
|
+
"--budget-tokens", str(args.budget), "--model", args.model,
|
|
1187
|
+
"--thinking", args.thinking]
|
|
1188
|
+
if getattr(args, "ids", None):
|
|
1189
|
+
argv.extend(["--ids", args.ids])
|
|
1190
|
+
if args.driver:
|
|
1191
|
+
argv.extend(["--driver", args.driver])
|
|
1192
|
+
return bv3.main(argv)
|
|
990
1193
|
if args.action == "eval":
|
|
991
1194
|
return bv3.main(["eval", "--run", args.run, "--annotations", args.annotations])
|
|
992
1195
|
if args.action == "report":
|
|
@@ -1172,6 +1375,17 @@ def _cmd_report(args) -> int:
|
|
|
1172
1375
|
return 0
|
|
1173
1376
|
|
|
1174
1377
|
|
|
1378
|
+
def _cmd_export(args) -> int:
|
|
1379
|
+
from engine.judge_pack import export_judge_pack
|
|
1380
|
+
from engine.project import ProjectWorkspace
|
|
1381
|
+
project = ProjectWorkspace.open(_home(args), args.project)
|
|
1382
|
+
output = Path(args.out) if args.out else project.path / "exports" / "judge-pack"
|
|
1383
|
+
manifest = export_judge_pack(project, output)
|
|
1384
|
+
print(json.dumps({"output": str(output), "files": len(manifest["copied_files"]),
|
|
1385
|
+
"missing_categories": manifest["missing_categories"]}, ensure_ascii=False))
|
|
1386
|
+
return 0
|
|
1387
|
+
|
|
1388
|
+
|
|
1175
1389
|
def _cmd_migrate(args) -> int:
|
|
1176
1390
|
from engine.migration import migrate_v1_pack
|
|
1177
1391
|
result = migrate_v1_pack(args.pack, home=_home(args), title=args.title)
|
|
@@ -1194,6 +1408,17 @@ def _cmd_search(args) -> int:
|
|
|
1194
1408
|
return 0
|
|
1195
1409
|
|
|
1196
1410
|
|
|
1411
|
+
def _cmd_search_plan(args) -> int:
|
|
1412
|
+
from search_provenance import main as search_plan_main
|
|
1413
|
+
argv = [args.query, "--out", str(args.out), "--domain", args.domain,
|
|
1414
|
+
"--limit", str(args.limit), "--channel", args.channel, "--policy", args.policy]
|
|
1415
|
+
for concept in args.concept:
|
|
1416
|
+
argv.extend(["--concept", concept])
|
|
1417
|
+
for synonym in args.synonym:
|
|
1418
|
+
argv.extend(["--synonym", synonym])
|
|
1419
|
+
return search_plan_main(argv)
|
|
1420
|
+
|
|
1421
|
+
|
|
1197
1422
|
def _cmd_did(args) -> int:
|
|
1198
1423
|
from did_regression import run_did_analysis
|
|
1199
1424
|
res = run_did_analysis(str(args.csv))
|
|
@@ -1226,7 +1451,10 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1226
1451
|
sub = parser.add_subparsers(dest="command", required=True)
|
|
1227
1452
|
|
|
1228
1453
|
p_run = sub.add_parser("run", help="create a run workspace and advance stages")
|
|
1229
|
-
p_run.add_argument("--question", required=True, help="
|
|
1454
|
+
p_run.add_argument("--question", required=True, help="research question to investigate")
|
|
1455
|
+
p_run.add_argument("--domain", default="education", metavar="ID",
|
|
1456
|
+
help="registered research domain (default: education; "
|
|
1457
|
+
"see `domain list`)")
|
|
1230
1458
|
p_run.add_argument("--depth", default="M", choices=["quick", "standard", "deep", "S", "M", "L"],
|
|
1231
1459
|
help="complexity depth (default: standard/M)")
|
|
1232
1460
|
p_run.add_argument("--run-id", default=None, help="explicit run id (default: timestamp)")
|
|
@@ -1329,6 +1557,13 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1329
1557
|
p_report.add_argument("--home", default=None)
|
|
1330
1558
|
p_report.set_defaults(func=_cmd_report)
|
|
1331
1559
|
|
|
1560
|
+
p_export = sub.add_parser("export", help="export a project evidence pack")
|
|
1561
|
+
p_export.add_argument("kind", choices=["judge-pack"])
|
|
1562
|
+
p_export.add_argument("project", help="project id")
|
|
1563
|
+
p_export.add_argument("--home", default=None)
|
|
1564
|
+
p_export.add_argument("--out", default=None)
|
|
1565
|
+
p_export.set_defaults(func=_cmd_export)
|
|
1566
|
+
|
|
1332
1567
|
|
|
1333
1568
|
p_pilot = sub.add_parser("pilot", help="V3 Decision-to-Outcome Loop")
|
|
1334
1569
|
p_pilot.add_argument("action", choices=["register", "import", "analyze-link", "redecide"])
|
|
@@ -1363,11 +1598,15 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1363
1598
|
p_bench.add_argument("action", choices=["run", "eval", "report"])
|
|
1364
1599
|
p_bench.add_argument("--baselines", default="B2_standard_agent,B3_eduevidence_single")
|
|
1365
1600
|
p_bench.add_argument("--questions", default="benchmarks/questions.jsonl")
|
|
1601
|
+
p_bench.add_argument("--ids", default=None, help="comma-separated question ids to run")
|
|
1366
1602
|
p_bench.add_argument("--repeats", type=int, default=3)
|
|
1367
1603
|
p_bench.add_argument("--driver", default=None, choices=["api", "cli", "sim"],
|
|
1368
1604
|
help="api | cli (omp) | sim (harness validation only); default: auto (api > cli > sim)")
|
|
1369
1605
|
p_bench.add_argument("--out", default="benchmarks/empirical/run-001")
|
|
1370
1606
|
p_bench.add_argument("--budget", type=int, default=1000000)
|
|
1607
|
+
p_bench.add_argument("--model", default="",
|
|
1608
|
+
help="model for --driver cli (required; no unconfirmed default)")
|
|
1609
|
+
p_bench.add_argument("--thinking", default="max", choices=["low", "high", "max"])
|
|
1371
1610
|
p_bench.add_argument("--run", default=None, help="run dir (eval/report)")
|
|
1372
1611
|
p_bench.add_argument("--annotations", default="benchmarks/annotations")
|
|
1373
1612
|
p_bench.add_argument("--report", default="benchmarks/empirical/v3-report.md")
|
|
@@ -1414,6 +1653,17 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
1414
1653
|
p_srch.add_argument("--academic", action="store_true", help="academic only")
|
|
1415
1654
|
p_srch.set_defaults(func=_cmd_search)
|
|
1416
1655
|
|
|
1656
|
+
p_sp = sub.add_parser("search-plan", help="audited, bounded search with provenance export")
|
|
1657
|
+
p_sp.add_argument("query", help="research question")
|
|
1658
|
+
p_sp.add_argument("--out", required=True, type=Path)
|
|
1659
|
+
p_sp.add_argument("--domain", default="education", choices=["education", "policy"])
|
|
1660
|
+
p_sp.add_argument("--concept", action="append", default=[])
|
|
1661
|
+
p_sp.add_argument("--synonym", action="append", default=[])
|
|
1662
|
+
p_sp.add_argument("--limit", type=int, default=10)
|
|
1663
|
+
p_sp.add_argument("--channel", default="all", choices=["all", "academic", "web"])
|
|
1664
|
+
p_sp.add_argument("--policy", default="2026.09")
|
|
1665
|
+
p_sp.set_defaults(func=_cmd_search_plan)
|
|
1666
|
+
|
|
1417
1667
|
p_did = sub.add_parser("did", help="run DID regression on classroom CSV")
|
|
1418
1668
|
p_did.add_argument("csv", type=Path, help="CSV file path")
|
|
1419
1669
|
p_did.set_defaults(func=_cmd_did)
|