eduevidence 5.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/LICENSE +21 -0
- package/README.md +506 -0
- package/README.zh-CN.md +434 -0
- package/SKILL.md +195 -0
- package/bin/eduevidence.js +127 -0
- package/domains/education/manifest.json +183 -0
- package/domains/education/outcome_taxonomy.json +127 -0
- package/domains/manifest.json +26 -0
- package/domains/policy/frame.schema.json +234 -0
- package/domains/policy/manifest.json +10 -0
- package/domains/policy/methodology_checklist.json +109 -0
- package/domains/policy/outcome_taxonomy.json +53 -0
- package/domains/policy/references/causal-identification.md +45 -0
- package/domains/policy/references/cost-evidence.md +44 -0
- package/domains/policy/references/equity.md +42 -0
- package/domains/policy/references/evidence-hierarchy.md +41 -0
- package/domains/policy/references/implementation-evidence.md +47 -0
- package/eduevidence_cli.py +26 -0
- package/engine/__init__.py +11 -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/engine/analysis.py +308 -0
- package/engine/bias.py +178 -0
- package/engine/briefs.py +106 -0
- package/engine/capabilities.py +99 -0
- package/engine/citation_check.py +192 -0
- package/engine/contracts.py +117 -0
- package/engine/datasets.py +165 -0
- package/engine/events.py +67 -0
- package/engine/evidence_graph.py +571 -0
- package/engine/evidence_review.py +88 -0
- package/engine/evidencecore.py +182 -0
- package/engine/gap_lens.py +132 -0
- package/engine/gaps.py +169 -0
- package/engine/graph_store.py +335 -0
- package/engine/graph_validate.py +87 -0
- package/engine/ids.py +77 -0
- package/engine/library.py +268 -0
- package/engine/library_builtin.py +301 -0
- package/engine/living.py +671 -0
- package/engine/log.py +39 -0
- package/engine/meta_analysis.py +333 -0
- package/engine/meta_synthesis.py +111 -0
- package/engine/migration.py +397 -0
- package/engine/mode_router.py +72 -0
- package/engine/paths.py +15 -0
- package/engine/pilot.py +368 -0
- package/engine/planner.py +126 -0
- package/engine/project.py +118 -0
- package/engine/projections.py +240 -0
- package/engine/robustness.py +109 -0
- package/engine/run.py +85 -0
- package/engine/semantics.py +135 -0
- package/engine/study_design.py +87 -0
- package/engine/synthesis.py +187 -0
- package/engine/tribunal.py +408 -0
- package/engine/update.py +113 -0
- package/engine/versions.py +12 -0
- package/install.sh +510 -0
- package/integrations/__init__.py +1 -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/integrations/agent_mcp.py +856 -0
- package/integrations/smart_web_fetch.py +59 -0
- package/package.json +50 -0
- package/pyproject.toml +55 -0
- package/references/applicability-policy.md +88 -0
- package/references/education-framing.md +132 -0
- package/references/effect_size_formulas.md +35 -0
- package/references/evaluation-design.md +111 -0
- package/references/evidence-quality.md +79 -0
- package/references/grade_framework.md +29 -0
- package/references/intervention-design.md +98 -0
- package/references/methodology-audit.md +103 -0
- package/references/outcome-taxonomy.md +106 -0
- package/references/retrieval-protocol.md +142 -0
- package/references/skeptic-protocol.md +93 -0
- package/references/social_science_pitfalls.md +48 -0
- package/references/source-validity.md +140 -0
- package/references/tribunal-policy.md +112 -0
- package/references/wwc_standards.md +29 -0
- package/retrieval/__init__.py +1 -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/retrieval/corpus_store.py +181 -0
- package/retrieval/dedupe.py +127 -0
- package/retrieval/failures.py +90 -0
- package/retrieval/fetch.py +435 -0
- package/retrieval/search.py +493 -0
- package/retrieval/source.py +160 -0
- package/retrieval/validate.py +257 -0
- package/schemas/agent-mcp-approval.schema.json +57 -0
- package/schemas/chart-spec.schema.json +88 -0
- package/schemas/cross-model-review.schema.json +28 -0
- package/schemas/education-frame.schema.json +106 -0
- package/schemas/evaluation.schema.json +35 -0
- package/schemas/evidence.schema.json +81 -0
- package/schemas/fetch-result.schema.json +119 -0
- package/schemas/intervention.schema.json +46 -0
- package/schemas/methodology.schema.json +102 -0
- package/schemas/report-result.schema.json +381 -0
- package/schemas/report-spec.schema.json +130 -0
- package/schemas/source.schema.json +311 -0
- package/schemas/v2/analysis-plan.schema.json +28 -0
- package/schemas/v2/analysis-run.schema.json +33 -0
- package/schemas/v2/claim.schema.json +26 -0
- package/schemas/v2/dataset-asset.schema.json +40 -0
- package/schemas/v2/decision-snapshot.schema.json +53 -0
- package/schemas/v2/evidence-link.schema.json +38 -0
- package/schemas/v2/finding.schema.json +47 -0
- package/schemas/v2/graph-revision.schema.json +30 -0
- package/schemas/v2/knowledge-gap.schema.json +40 -0
- package/schemas/v2/methodology-audit.schema.json +30 -0
- package/schemas/v2/outcome.schema.json +18 -0
- package/schemas/v2/project.schema.json +31 -0
- package/schemas/v2/research-intent.schema.json +24 -0
- package/schemas/v2/run.schema.json +43 -0
- package/schemas/v2/source.schema.json +24 -0
- package/schemas/v2/study-design.schema.json +67 -0
- package/schemas/v2/study.schema.json +37 -0
- package/schemas/v3/pilot-outcome.schema.json +132 -0
- package/schemas/v3/run-manifest.schema.json +193 -0
- package/schemas/v3/synthesis.schema.json +86 -0
- package/schemas/v4/drift-report.schema.json +66 -0
- package/schemas/v4/evidence-library.schema.json +42 -0
- package/schemas/v4/living-subscription.schema.json +55 -0
- package/schemas/v4/meta-analysis.schema.json +152 -0
- package/schemas/verdict.schema.json +56 -0
- package/scripts/__init__.py +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/scripts/audit_dois.py +292 -0
- package/scripts/bake_pack.sh +37 -0
- package/scripts/benchmark.py +183 -0
- package/scripts/benchmark_evaluator.py +371 -0
- package/scripts/benchmark_judge.py +535 -0
- package/scripts/benchmark_routing.py +120 -0
- package/scripts/benchmark_v2.py +304 -0
- package/scripts/benchmark_v3.py +552 -0
- package/scripts/build_esl_artifacts.py +1921 -0
- package/scripts/build_evidence_library.py +307 -0
- package/scripts/build_killer_demo.py +295 -0
- package/scripts/build_result.py +311 -0
- package/scripts/check_version_consistency.py +96 -0
- package/scripts/citation_check.py +123 -0
- package/scripts/claim_audit.py +157 -0
- package/scripts/complexity_gate.py +180 -0
- package/scripts/compute_confidence.py +176 -0
- package/scripts/dashboard_server.py +536 -0
- package/scripts/did_regression.py +315 -0
- package/scripts/effect_calculator.py +99 -0
- package/scripts/enrich_projects_human_and_lieflat.py +315 -0
- package/scripts/evidence_matrix.py +129 -0
- package/scripts/evidence_score.py +234 -0
- package/scripts/evidence_semantics.py +87 -0
- package/scripts/fetch_benchmark.py +177 -0
- package/scripts/generate_metrics.py +99 -0
- package/scripts/generate_new_projects.py +686 -0
- package/scripts/generate_promo.py +192 -0
- package/scripts/lint_report_layout.py +182 -0
- package/scripts/orchestrator.py +1456 -0
- package/scripts/pre_verdict_gate.py +513 -0
- package/scripts/quickstart.py +121 -0
- package/scripts/rebake_all_5themes.py +88 -0
- package/scripts/recompute_demo_quality.py +205 -0
- package/scripts/render_report.py +270 -0
- package/scripts/render_report_html.py +356 -0
- package/scripts/retraction_watch.py +110 -0
- package/scripts/run_workspace.py +337 -0
- package/scripts/serve_web.py +54 -0
- package/scripts/skill_lint.py +150 -0
- package/scripts/startup_probe.py +265 -0
- package/scripts/sync_killer_demo_report.py +270 -0
- package/scripts/test_adversarial_empirical.py +541 -0
- package/scripts/validate_schema.py +256 -0
- package/skill/agents/education-planner.md +80 -0
- package/skill/agents/evaluation-designer.md +74 -0
- package/skill/agents/evidence-analyst.md +106 -0
- package/skill/agents/evidence-judge.md +111 -0
- package/skill/agents/evidence-retriever.md +80 -0
- package/skill/agents/intervention-designer.md +82 -0
- package/skill/agents/method-reviewer.md +104 -0
- package/skill/agents/skeptic.md +89 -0
- package/skill/sub-skills/aihot-trend-analysis/SKILL.md +31 -0
- package/skill/sub-skills/contradiction-analysis/SKILL.md +17 -0
- package/skill/sub-skills/data-analysis/SKILL.md +23 -0
- package/skill/sub-skills/ethics-review/SKILL.md +25 -0
- package/skill/sub-skills/evidence-extraction/SKILL.md +19 -0
- package/skill/sub-skills/evidence-review/SKILL.md +18 -0
- package/skill/sub-skills/gap-analysis/SKILL.md +25 -0
- package/skill/sub-skills/literature-review/SKILL.md +21 -0
- package/skill/sub-skills/methodology-audit/SKILL.md +20 -0
- package/skill/sub-skills/report-generation/SKILL.md +51 -0
- package/skill/sub-skills/research-planning/SKILL.md +21 -0
- package/skill/sub-skills/study-design/SKILL.md +16 -0
- package/skill/task-briefs/adjudicate.md +17 -0
- package/skill/task-briefs/audit.md +15 -0
- package/skill/task-briefs/challenge.md +15 -0
- package/skill/task-briefs/evaluate.md +13 -0
- package/skill/task-briefs/extract.md +16 -0
- package/skill/task-briefs/frame.md +17 -0
- package/skill/task-briefs/intervene.md +14 -0
- package/skill/task-briefs/present.md +16 -0
- package/skill/task-briefs/retrieve.md +15 -0
- package/visualization/eduevidence-report/assets/base.css +337 -0
- package/visualization/eduevidence-report/motion/motion.css +157 -0
- package/visualization/eduevidence-report/motion/motion.js +107 -0
- package/visualization/eduevidence-report/references/bilingual-style.md +7 -0
- package/visualization/eduevidence-report/references/component-catalog.md +145 -0
- package/visualization/eduevidence-report/references/evidence-expansion.md +65 -0
- package/visualization/eduevidence-report/references/full-report-outline.md +86 -0
- package/visualization/eduevidence-report/references/layout-constraints.md +63 -0
- package/visualization/eduevidence-report/references/lieflat-composition.md +79 -0
- package/visualization/eduevidence-report/references/motion-system.md +31 -0
- package/visualization/eduevidence-report/schemas/adapter-envelope.schema.json +22 -0
- package/visualization/eduevidence-report/schemas/visual-layout.schema.json +87 -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/visualization/eduevidence-report/scripts/adapter_contract.py +72 -0
- package/visualization/eduevidence-report/scripts/build_artifact_manifest.py +70 -0
- package/visualization/eduevidence-report/scripts/build_charts.py +283 -0
- package/visualization/eduevidence-report/scripts/build_figures.py +515 -0
- package/visualization/eduevidence-report/scripts/build_infographics.py +268 -0
- package/visualization/eduevidence-report/scripts/build_report.py +3211 -0
- package/visualization/eduevidence-report/scripts/charts_data.py +617 -0
- package/visualization/eduevidence-report/scripts/check_mobile_layout.js +220 -0
- package/visualization/eduevidence-report/scripts/lieflat_engine.py +852 -0
- package/visualization/eduevidence-report/scripts/zh_labels.py +245 -0
- package/visualization/eduevidence-report/themes/academic.css +94 -0
- package/visualization/eduevidence-report/themes/claude.css +96 -0
- package/visualization/eduevidence-report/themes/datalab-dark.css +147 -0
- package/visualization/eduevidence-report/themes/datalab.css +151 -0
- package/visualization/eduevidence-report/themes/presentation.css +140 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""complexity_gate.py — Deterministic complexity grading gate (plan section 9, Phase 6).
|
|
3
|
+
|
|
4
|
+
Decides whether an EduEvidence task should run in single-agent mode (S),
|
|
5
|
+
with one independent check (M), or enter the full 8-role workflow (L), and
|
|
6
|
+
whether delegation to Agent MCP is warranted at all.
|
|
7
|
+
|
|
8
|
+
Pure local heuristics — zero tokens, no spawn. The result is a suggestion:
|
|
9
|
+
the main agent's judgment of the actual task always wins ("宁可不拆").
|
|
10
|
+
|
|
11
|
+
Rules (per EduEvidence 实施方案 §9 and agent-mcp 编排 skill):
|
|
12
|
+
- S: single question, single outcome, few sources, no obvious conflict
|
|
13
|
+
-> Frame → Retrieve → Extract → Verify → Answer (0 spawn)
|
|
14
|
+
- M: multiple studies, 2-3 outcomes, partial conflict, one independent check
|
|
15
|
+
-> Primary Analysis + Independent Check (<=2-3 roles)
|
|
16
|
+
- L: multiple outcomes, multiple learner groups, strong conflict,
|
|
17
|
+
needs teaching deployment plan -> full 8-role workflow
|
|
18
|
+
|
|
19
|
+
Do-NOT-delegate list (hit any -> delegate=False):
|
|
20
|
+
quick Q&A, single-source check, formatting-only task, trivial edit,
|
|
21
|
+
strong sequential dependency chain.
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
python scripts/complexity_gate.py --question "..." --depth standard \\
|
|
25
|
+
--target teaching_decision --outcomes retention transfer \\
|
|
26
|
+
--multi-learner --needs-pilot
|
|
27
|
+
"""
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import argparse
|
|
31
|
+
import json
|
|
32
|
+
import re
|
|
33
|
+
from typing import Any
|
|
34
|
+
|
|
35
|
+
# Signals that push complexity up (from plan §9 / §13)
|
|
36
|
+
L_SIGNALS = [
|
|
37
|
+
"长期", "迁移", "保持", "retention", "transfer", "长期效果",
|
|
38
|
+
"多学习者", "多群体", "不同学生", "全面部署", "全校", "试点", "pilot",
|
|
39
|
+
"风险", "依赖", "over-reliance", "ai dependency", "冲突", "矛盾",
|
|
40
|
+
]
|
|
41
|
+
M_SIGNALS = [
|
|
42
|
+
"是否有效", "提高", "影响", "比较", "对比", "vs", "与", "不同研究",
|
|
43
|
+
"证据", "研究", "结论",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
# Do-not-delegate triggers
|
|
47
|
+
NO_DELEGATE_SIGNALS = [
|
|
48
|
+
"一句话", "简要", "快速回答", "解释一下", "这个文件", "格式化",
|
|
49
|
+
"重命名", "改个名字", "简单回答",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _signal_count(text: str, signals: list[str]) -> int:
|
|
54
|
+
low = text.lower()
|
|
55
|
+
return sum(1 for s in signals if s.lower() in low)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _count_outcomes(outcomes: list[str] | None) -> int:
|
|
59
|
+
if not outcomes:
|
|
60
|
+
return 0
|
|
61
|
+
return len([o for o in outcomes if o])
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def grade(
|
|
65
|
+
question: str,
|
|
66
|
+
*,
|
|
67
|
+
depth: str = "standard",
|
|
68
|
+
target: str = "evidence_review",
|
|
69
|
+
outcomes: list[str] | None = None,
|
|
70
|
+
multi_learner: bool = False,
|
|
71
|
+
needs_pilot: bool = False,
|
|
72
|
+
needs_evaluation: bool = False,
|
|
73
|
+
conflict_hint: bool = False,
|
|
74
|
+
) -> dict[str, Any]:
|
|
75
|
+
"""Grade a task S/M/L and decide whether delegation is warranted.
|
|
76
|
+
|
|
77
|
+
Returns {level, rationale, delegate, suggestion}.
|
|
78
|
+
"""
|
|
79
|
+
question = question or ""
|
|
80
|
+
l_score = _signal_count(question, L_SIGNALS)
|
|
81
|
+
m_score = _signal_count(question, M_SIGNALS)
|
|
82
|
+
n_outcomes = _count_outcomes(outcomes)
|
|
83
|
+
no_delegate = _signal_count(question, NO_DELEGATE_SIGNALS) > 0
|
|
84
|
+
|
|
85
|
+
# --- do-not-delegate gate (hit any -> never spawn) ---
|
|
86
|
+
if no_delegate:
|
|
87
|
+
return {
|
|
88
|
+
"level": "S",
|
|
89
|
+
"rationale": "do-not-delegate signal in question (quick/simple/formulaic task)",
|
|
90
|
+
"delegate": False,
|
|
91
|
+
"suggestion": "主 Agent 直接执行,禁止 spawn。",
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# --- explicit inputs push complexity ---
|
|
95
|
+
score = 0
|
|
96
|
+
reasons: list[str] = []
|
|
97
|
+
|
|
98
|
+
if depth == "deep":
|
|
99
|
+
score += 2
|
|
100
|
+
reasons.append("depth=deep")
|
|
101
|
+
elif depth == "standard":
|
|
102
|
+
score += 1
|
|
103
|
+
reasons.append("depth=standard")
|
|
104
|
+
|
|
105
|
+
if target in ("teaching_decision", "pilot_design", "evaluation_design"):
|
|
106
|
+
score += 1
|
|
107
|
+
reasons.append(f"target={target}")
|
|
108
|
+
if multi_learner:
|
|
109
|
+
score += 1
|
|
110
|
+
reasons.append("multi-learner")
|
|
111
|
+
if needs_pilot or needs_evaluation:
|
|
112
|
+
score += 1
|
|
113
|
+
reasons.append("needs pilot/evaluation")
|
|
114
|
+
if conflict_hint:
|
|
115
|
+
score += 1
|
|
116
|
+
reasons.append("conflict hinted")
|
|
117
|
+
if n_outcomes >= 4:
|
|
118
|
+
score += 2
|
|
119
|
+
reasons.append(f"{n_outcomes} outcomes")
|
|
120
|
+
elif n_outcomes >= 2:
|
|
121
|
+
score += 1
|
|
122
|
+
reasons.append(f"{n_outcomes} outcomes")
|
|
123
|
+
|
|
124
|
+
# --- question-language signals ---
|
|
125
|
+
score += min(2, l_score)
|
|
126
|
+
score += min(1, m_score)
|
|
127
|
+
if l_score:
|
|
128
|
+
reasons.append(f"L-signals x{l_score}")
|
|
129
|
+
if m_score:
|
|
130
|
+
reasons.append(f"M-signals x{m_score}")
|
|
131
|
+
|
|
132
|
+
if score >= 4:
|
|
133
|
+
level = "L"
|
|
134
|
+
elif score >= 2:
|
|
135
|
+
level = "M"
|
|
136
|
+
else:
|
|
137
|
+
level = "S"
|
|
138
|
+
|
|
139
|
+
delegate = level in ("M", "L") and not no_delegate
|
|
140
|
+
suggestion = {
|
|
141
|
+
"S": "Frame → Retrieve → Extract → Verify → Answer(单 Agent 串行,0 spawn)",
|
|
142
|
+
"M": "Primary Analysis + Independent Check(增强模式 ≤2-3 角色)",
|
|
143
|
+
"L": "完整 8 角色工作流(Planner/Retriever/Analyst/Skeptic/Method Reviewer/Judge/Intervention Designer/Evaluation Designer)",
|
|
144
|
+
}[level]
|
|
145
|
+
|
|
146
|
+
rationale = f"complexity score {score} ({', '.join(reasons) if reasons else 'no signals'})"
|
|
147
|
+
return {"level": level, "rationale": rationale, "delegate": delegate, "suggestion": suggestion}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def main() -> int:
|
|
151
|
+
parser = argparse.ArgumentParser(description="EduEvidence deterministic complexity gate")
|
|
152
|
+
parser.add_argument("--question", required=True, help="education question text")
|
|
153
|
+
parser.add_argument("--depth", choices=["quick", "standard", "deep"], default="standard")
|
|
154
|
+
parser.add_argument("--target", choices=["evidence_review", "teaching_decision",
|
|
155
|
+
"pilot_design", "evaluation_design"],
|
|
156
|
+
default="evidence_review")
|
|
157
|
+
parser.add_argument("--outcomes", nargs="*", default=None)
|
|
158
|
+
parser.add_argument("--multi-learner", action="store_true")
|
|
159
|
+
parser.add_argument("--needs-pilot", action="store_true")
|
|
160
|
+
parser.add_argument("--needs-evaluation", action="store_true")
|
|
161
|
+
parser.add_argument("--conflict-hint", action="store_true")
|
|
162
|
+
args = parser.parse_args()
|
|
163
|
+
|
|
164
|
+
result = grade(
|
|
165
|
+
args.question,
|
|
166
|
+
depth=args.depth,
|
|
167
|
+
target=args.target,
|
|
168
|
+
outcomes=args.outcomes,
|
|
169
|
+
multi_learner=args.multi_learner,
|
|
170
|
+
needs_pilot=args.needs_pilot,
|
|
171
|
+
needs_evaluation=args.needs_evaluation,
|
|
172
|
+
conflict_hint=args.conflict_hint,
|
|
173
|
+
)
|
|
174
|
+
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
175
|
+
return 0
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
if __name__ == "__main__":
|
|
179
|
+
import sys
|
|
180
|
+
sys.exit(main())
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""compute_confidence.py — Deterministic confidence computation for final verdicts.
|
|
3
|
+
|
|
4
|
+
Pipeline entry for the Evidence Integrity Report (P0-05): reads the raw model
|
|
5
|
+
verdict plus the evidence registry and OVERRIDES the model's confidence values
|
|
6
|
+
with the deterministic rule-based computation, so the final verdict's
|
|
7
|
+
confidence is reproducible and auditable rather than model-generated.
|
|
8
|
+
|
|
9
|
+
Formula (identical policy to evidence_score.confidence, v2 — D-1/D-2):
|
|
10
|
+
|
|
11
|
+
score = 0.30 * Evidence Quality + 0.25 * Consistency + 0.20 * Directness
|
|
12
|
+
+ 0.25 * Evidence Count (independent-study weighted)
|
|
13
|
+
- Conflict Penalty - Unsupported Penalty
|
|
14
|
+
|
|
15
|
+
where Evidence Count = min(1.0, independent_studies / 4) — independent_samples
|
|
16
|
+
is reported separately instead of being added to the count term —,
|
|
17
|
+
Consistency is computed over decision_relation (support_adoption /
|
|
18
|
+
oppose_adoption / conditional / neutral) rather than relation_to_claim,
|
|
19
|
+
Conflict Penalty = 0.15 if any evidence opposes adoption, and
|
|
20
|
+
Unsupported Penalty = min(0.20, 0.05 * n_unsupported).
|
|
21
|
+
|
|
22
|
+
IMPORTANT: confidence_score is a rule-based index in [0, 1], NOT a
|
|
23
|
+
probability. It must never be presented as a percentage probability (e.g. "85%
|
|
24
|
+
confidence"); consumers should phrase it as an index/band (High | Moderate |
|
|
25
|
+
Low | Insufficient) with the policy version.
|
|
26
|
+
|
|
27
|
+
Usage:
|
|
28
|
+
python3 scripts/compute_confidence.py --verdict raw_verdict.json \
|
|
29
|
+
--evidence evidence.jsonl --out final_verdict.json
|
|
30
|
+
|
|
31
|
+
Output (final_verdict.json) carries the deterministic fields:
|
|
32
|
+
confidence / confidence_score / confidence_policy_version /
|
|
33
|
+
independent_studies / independent_samples / confidence_breakdown, plus the
|
|
34
|
+
raw model values preserved as raw_model_confidence* for audit comparison.
|
|
35
|
+
"""
|
|
36
|
+
from __future__ import annotations
|
|
37
|
+
|
|
38
|
+
import argparse
|
|
39
|
+
import json
|
|
40
|
+
import sys
|
|
41
|
+
from pathlib import Path
|
|
42
|
+
|
|
43
|
+
from evidence_score import (CONFIDENCE_POLICY_VERSION,
|
|
44
|
+
decision_consistency_score, directness_score,
|
|
45
|
+
independent_samples, independent_studies)
|
|
46
|
+
from evidence_semantics import decision_relation
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def compute_confidence(evidence_list: list[dict], *, target_outcome: str | None = None) -> dict:
|
|
50
|
+
"""Deterministic confidence over an evidence list (independent-study weighted).
|
|
51
|
+
|
|
52
|
+
Returns a breakdown dict plus the final label (High | Moderate | Low |
|
|
53
|
+
Insufficient). This is the P0-05 policy engine; the legacy
|
|
54
|
+
evidence_score.confidence() remains for backward-compatible callers.
|
|
55
|
+
"""
|
|
56
|
+
if not evidence_list:
|
|
57
|
+
return {"confidence": "Insufficient",
|
|
58
|
+
"confidence_policy_version": CONFIDENCE_POLICY_VERSION,
|
|
59
|
+
"independent_studies": 0,
|
|
60
|
+
"independent_samples": 0,
|
|
61
|
+
"confidence_breakdown": {"evidence_count": 0}}
|
|
62
|
+
|
|
63
|
+
# 1. Evidence Quality (mean of quality scores, scaled to 0-1)
|
|
64
|
+
quality_values = [e.get("quality_score") for e in evidence_list]
|
|
65
|
+
numeric = [q for q in quality_values if isinstance(q, (int, float))]
|
|
66
|
+
avg_quality = sum(numeric) / len(numeric) if numeric else 0.0
|
|
67
|
+
quality_term = avg_quality / 10.0
|
|
68
|
+
|
|
69
|
+
# 2. Consistency (decision_relation based, D-2): claim-level evidence is
|
|
70
|
+
# usually extracted to support its claim, so relation_to_claim would
|
|
71
|
+
# overstate agreement about the final teaching decision.
|
|
72
|
+
decisions = [decision_relation(e) for e in evidence_list]
|
|
73
|
+
consistency = decision_consistency_score(decisions)
|
|
74
|
+
|
|
75
|
+
# 3. Directness (0-2 -> 0-1)
|
|
76
|
+
directness = directness_score(evidence_list) / 2.0
|
|
77
|
+
|
|
78
|
+
# 4. Evidence count weighted by independent studies only (D-1): a typical
|
|
79
|
+
# study is 1 study + 1 sample, so adding independent_samples would count
|
|
80
|
+
# the same study twice. independent_samples is reported separately.
|
|
81
|
+
studies = independent_studies(evidence_list)
|
|
82
|
+
samples = independent_samples(evidence_list)
|
|
83
|
+
count_term = min(1.0, studies / 4.0)
|
|
84
|
+
|
|
85
|
+
# 5. Conflict penalty (0.15 when any evidence opposes adoption)
|
|
86
|
+
conflict_penalty = 0.15 if "oppose_adoption" in decisions else 0.0
|
|
87
|
+
|
|
88
|
+
# 6. Unsupported penalty (capped at 0.20)
|
|
89
|
+
unsupported = [e for e in evidence_list if e.get("status") in ("UNSUPPORTED", "DOWNGRADE_CONFIDENCE")]
|
|
90
|
+
unsupported_penalty = min(0.20, len(unsupported) * 0.05)
|
|
91
|
+
|
|
92
|
+
score = (0.30 * quality_term + 0.25 * consistency + 0.20 * directness
|
|
93
|
+
+ 0.25 * count_term - conflict_penalty - unsupported_penalty)
|
|
94
|
+
score = max(0.0, min(1.0, score))
|
|
95
|
+
|
|
96
|
+
if target_outcome:
|
|
97
|
+
relevant = [e for e in evidence_list if e.get("outcome_type") == target_outcome]
|
|
98
|
+
if relevant:
|
|
99
|
+
score *= 0.5 + 0.5 * (len(relevant) / max(1, len(evidence_list)))
|
|
100
|
+
|
|
101
|
+
label = _confidence_label(score)
|
|
102
|
+
return {
|
|
103
|
+
"confidence": label,
|
|
104
|
+
"confidence_policy_version": CONFIDENCE_POLICY_VERSION,
|
|
105
|
+
"independent_studies": studies,
|
|
106
|
+
"independent_samples": samples,
|
|
107
|
+
"confidence_breakdown": {
|
|
108
|
+
"score": round(score, 3),
|
|
109
|
+
"evidence_quality": round(quality_term, 3),
|
|
110
|
+
"consistency": round(consistency, 3),
|
|
111
|
+
"directness": round(directness, 3),
|
|
112
|
+
"evidence_count": len(evidence_list),
|
|
113
|
+
"independent_studies": studies,
|
|
114
|
+
"independent_samples": samples,
|
|
115
|
+
"count_term": round(count_term, 3),
|
|
116
|
+
"conflict_penalty": conflict_penalty,
|
|
117
|
+
"unsupported_penalty": round(unsupported_penalty, 3),
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _confidence_label(score: float) -> str:
|
|
123
|
+
if score >= 0.72:
|
|
124
|
+
return "High"
|
|
125
|
+
if score >= 0.45:
|
|
126
|
+
return "Moderate"
|
|
127
|
+
if score >= 0.2:
|
|
128
|
+
return "Low"
|
|
129
|
+
return "Insufficient"
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def main() -> int:
|
|
133
|
+
parser = argparse.ArgumentParser(
|
|
134
|
+
description="Compute deterministic confidence and merge it into the final verdict")
|
|
135
|
+
parser.add_argument("--verdict", required=True, help="Raw (model) verdict JSON file")
|
|
136
|
+
parser.add_argument("--evidence", required=True, help="Evidence JSONL file")
|
|
137
|
+
parser.add_argument("--out", required=True, help="Output final verdict JSON path")
|
|
138
|
+
args = parser.parse_args()
|
|
139
|
+
|
|
140
|
+
raw_verdict = json.loads(Path(args.verdict).read_text(encoding="utf-8"))
|
|
141
|
+
evidence_list = []
|
|
142
|
+
for lineno, line in enumerate(Path(args.evidence).read_text(encoding="utf-8").splitlines(), 1):
|
|
143
|
+
line = line.strip()
|
|
144
|
+
if not line:
|
|
145
|
+
continue
|
|
146
|
+
try:
|
|
147
|
+
evidence_list.append(json.loads(line))
|
|
148
|
+
except json.JSONDecodeError as exc:
|
|
149
|
+
print(f"{args.evidence}:{lineno}: invalid JSON line: {exc}", file=sys.stderr)
|
|
150
|
+
return 1
|
|
151
|
+
|
|
152
|
+
target_outcome = raw_verdict.get("target_outcome")
|
|
153
|
+
computed = compute_confidence(evidence_list, target_outcome=target_outcome)
|
|
154
|
+
|
|
155
|
+
# Override model-generated confidence fields with the deterministic values.
|
|
156
|
+
final = dict(raw_verdict)
|
|
157
|
+
final["confidence"] = computed["confidence"]
|
|
158
|
+
final["confidence_score"] = computed["confidence_breakdown"].get("score")
|
|
159
|
+
final["confidence_policy_version"] = computed["confidence_policy_version"]
|
|
160
|
+
final["independent_studies"] = computed["independent_studies"]
|
|
161
|
+
final["independent_samples"] = computed["independent_samples"]
|
|
162
|
+
final["confidence_breakdown"] = computed["confidence_breakdown"]
|
|
163
|
+
# 保留原始模型输出,供审计比对(模型值被覆盖而非丢弃)。
|
|
164
|
+
final["raw_model_confidence"] = raw_verdict.get("confidence")
|
|
165
|
+
final["raw_model_confidence_breakdown"] = raw_verdict.get("confidence_breakdown") or {}
|
|
166
|
+
|
|
167
|
+
out_path = Path(args.out)
|
|
168
|
+
out_path.write_text(json.dumps(final, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
169
|
+
print(f"confidence={computed['confidence']} score={computed['confidence_breakdown']['score']} "
|
|
170
|
+
f"studies={computed['independent_studies']} samples={computed['independent_samples']} "
|
|
171
|
+
f"policy={CONFIDENCE_POLICY_VERSION} -> {out_path}")
|
|
172
|
+
return 0
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
if __name__ == "__main__":
|
|
176
|
+
sys.exit(main())
|