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,265 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""startup_probe.py — Skill 启动能力检测(SKILL.md §5.5 启动清单动态填充)。
|
|
3
|
+
|
|
4
|
+
只探测【主会话看不到的信息】:
|
|
5
|
+
1. Agent MCP 配置状态(MCP 工具可见性以会话内为准)
|
|
6
|
+
2. 各 CLI 当前可用的模型(按 provider 段解析,保留前缀端点;系列只列最新)
|
|
7
|
+
|
|
8
|
+
【不探测】宿主原生子代理池——主会话模型自己就能直接看见(task/scout/reviewer 等)。
|
|
9
|
+
|
|
10
|
+
⚠️ 模型名=完整端点:中转站注入的模型名带 provider 段前缀(如 opencodex/pro/gpt-5.6-sol、
|
|
11
|
+
opencode-go/deepseek-v4-flash),同一后缀不同前缀是不同端点。派发时必须使用完整模型名。
|
|
12
|
+
|
|
13
|
+
用法:
|
|
14
|
+
python3 scripts/startup_probe.py # JSON 输出
|
|
15
|
+
python3 scripts/startup_probe.py --markdown # 输出启动清单的"当前会话能力检测"段
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import argparse
|
|
20
|
+
import json
|
|
21
|
+
import re
|
|
22
|
+
import shutil
|
|
23
|
+
import subprocess
|
|
24
|
+
import sys
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
|
|
27
|
+
# 各 CLI 的探测命令(存在才列)
|
|
28
|
+
CLI_PROBES: dict[str, list[str]] = {
|
|
29
|
+
"omp": ["omp", "models"],
|
|
30
|
+
"codex": ["codex", "--help"],
|
|
31
|
+
"claude": ["claude", "--version"],
|
|
32
|
+
"opencode": ["opencode", "--version"],
|
|
33
|
+
"grok": ["grok", "--version"],
|
|
34
|
+
"kimi": ["kimi", "--version"],
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# 各系列"最新模型"显示顺序(按系列去重,只列最新)
|
|
38
|
+
# 档位:旗舰(FLAGSHIP)= 复杂推理/裁决;基础(BASE)= 检索/抽取/结构化
|
|
39
|
+
SERIES_PRIORITY = [
|
|
40
|
+
# OpenAI 系
|
|
41
|
+
"gpt-5.5", "gpt-5.6-sol", "gpt-5.6-luna", "gpt-5.6-terra",
|
|
42
|
+
# Anthropic 系
|
|
43
|
+
"claude-opus-5", "claude-fable-5", "claude-sonnet-5",
|
|
44
|
+
# DeepSeek 系
|
|
45
|
+
"deepseek-v4-pro", "deepseek-v4-flash", "ds-flash",
|
|
46
|
+
# GLM 系
|
|
47
|
+
"glm-5.3", "glm-5.2", "glm-5.1",
|
|
48
|
+
# Kimi 系
|
|
49
|
+
"kimi-k3", "kimi-k2.7",
|
|
50
|
+
# 其余
|
|
51
|
+
"qwen3.8-max", "qwen3.7-plus",
|
|
52
|
+
"minimax-m3", "minimax-m2.7",
|
|
53
|
+
"grok-4.5",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
# 档位标注(展示用;不写死路由,路由以用户授权为准)
|
|
57
|
+
MODEL_TIERS = {
|
|
58
|
+
# 旗舰(strong / independent)
|
|
59
|
+
"gpt-5.5": "FLAGSHIP", "gpt-5.6-sol": "FLAGSHIP",
|
|
60
|
+
"claude-opus-5": "FLAGSHIP", "claude-fable-5": "FLAGSHIP",
|
|
61
|
+
"glm-5.3": "FLAGSHIP", "deepseek-v4-pro": "FLAGSHIP", "kimi-k3": "FLAGSHIP",
|
|
62
|
+
# 基础(fast)
|
|
63
|
+
"ds-flash": "BASE", "deepseek-v4-flash": "BASE",
|
|
64
|
+
"gpt-5.6-luna": "BASE", "gpt-5.6-terra": "BASE",
|
|
65
|
+
"claude-sonnet-5": "BASE", "glm-5.2": "BASE", "glm-5.1": "BASE",
|
|
66
|
+
"kimi-k2.7": "BASE",
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# 模型默认思考等级(主会话内置知识,无需用户确认)
|
|
70
|
+
THINKING_LEVELS = {
|
|
71
|
+
"deepseek-v4-flash": "max",
|
|
72
|
+
"deepseek-v4-pro": "max",
|
|
73
|
+
"ds-flash": "max",
|
|
74
|
+
"gpt-5.5": "high",
|
|
75
|
+
"gpt-5.6-sol": "high",
|
|
76
|
+
"gpt-5.6-luna": "high",
|
|
77
|
+
"gpt-5.6-terra": "high",
|
|
78
|
+
"claude-opus-5": "high",
|
|
79
|
+
"claude-fable-5": "high",
|
|
80
|
+
"claude-sonnet-5": "high",
|
|
81
|
+
"glm-5.3": "high",
|
|
82
|
+
"glm-5.2": "high",
|
|
83
|
+
"glm-5.1": "high",
|
|
84
|
+
"kimi-k3": "high",
|
|
85
|
+
"kimi-k2.7": "high",
|
|
86
|
+
"qwen3.8-max": "high",
|
|
87
|
+
"qwen3.7-plus": "high",
|
|
88
|
+
"minimax-m3": "high",
|
|
89
|
+
"minimax-m2.7": "high",
|
|
90
|
+
"grok-4.5": "high",
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# 前缀端点:同一后缀不同前缀是不同端点,保留完整名
|
|
94
|
+
KNOWN_PREFIXES = ("pro/", "jbb/", "pix/", "pixgrok/", "opencode-go/", "deepseek/", "combo/")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def detect_agent_mcp_tools() -> dict:
|
|
98
|
+
"""探测 Agent MCP 配置状态(最终以会话内 spawn_agent 工具可见性为准)。"""
|
|
99
|
+
mcp_json = Path.home() / ".omp" / "agent" / "mcp.json"
|
|
100
|
+
configured = False
|
|
101
|
+
if mcp_json.exists():
|
|
102
|
+
try:
|
|
103
|
+
cfg = json.loads(mcp_json.read_text())
|
|
104
|
+
configured = "agent-mcp" in cfg.get("mcpServers", {})
|
|
105
|
+
except json.JSONDecodeError:
|
|
106
|
+
configured = False
|
|
107
|
+
return {
|
|
108
|
+
"configured": configured,
|
|
109
|
+
"config_path": str(mcp_json) if mcp_json.exists() else None,
|
|
110
|
+
"note": "最终以会话内 spawn_agent 工具可见性为准",
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def scan_cli_models(cli: str) -> list[dict]:
|
|
115
|
+
"""扫描 CLI 模型列表,返回 [{provider, model(完整名), thinking}]。
|
|
116
|
+
|
|
117
|
+
解析 omp 风格分段输出:
|
|
118
|
+
opencode-go (25) <- provider 段
|
|
119
|
+
│ gpt-5.6-luna ... <- 段内模型(可能带 pro/ jbb/ 前缀)
|
|
120
|
+
完整模型名 = provider + "/" + 段内名(段内无前缀时即 provider 内模型)。
|
|
121
|
+
"""
|
|
122
|
+
probe = CLI_PROBES.get(cli)
|
|
123
|
+
if not probe or shutil.which(probe[0]) is None:
|
|
124
|
+
return []
|
|
125
|
+
try:
|
|
126
|
+
out = subprocess.run(probe, capture_output=True, text=True, timeout=15)
|
|
127
|
+
except (subprocess.SubprocessError, OSError):
|
|
128
|
+
return []
|
|
129
|
+
|
|
130
|
+
records: list[dict] = []
|
|
131
|
+
provider: str | None = None
|
|
132
|
+
for line in (out.stdout + out.stderr).splitlines():
|
|
133
|
+
s = line.strip()
|
|
134
|
+
# provider 段头:`opencode-go (25)` / `opencodex (18)`
|
|
135
|
+
m = re.match(r"^([\w.-]+)\s+\(\d+\)$", s)
|
|
136
|
+
if m and "│" not in s and "┌" not in s and "└" not in s:
|
|
137
|
+
provider = m.group(1)
|
|
138
|
+
continue
|
|
139
|
+
# 数据行:`│ model-name │ ...`
|
|
140
|
+
if not s.startswith("│") or "model" in s or set(s) <= {"│", "─", " "}:
|
|
141
|
+
continue
|
|
142
|
+
parts = [p.strip() for p in s.strip("│").split("│")]
|
|
143
|
+
if not parts or not parts[0]:
|
|
144
|
+
continue
|
|
145
|
+
name = parts[0]
|
|
146
|
+
if not re.match(r"^[\w./-]+$", name) or name in ("model",):
|
|
147
|
+
continue
|
|
148
|
+
full = f"{provider}/{name}" if provider else name
|
|
149
|
+
records.append({
|
|
150
|
+
"provider": provider or "?",
|
|
151
|
+
"model": full,
|
|
152
|
+
"thinking": _thinking_for(full),
|
|
153
|
+
})
|
|
154
|
+
return records
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _thinking_for(model: str) -> str:
|
|
158
|
+
level = "high"
|
|
159
|
+
for key, lv in THINKING_LEVELS.items():
|
|
160
|
+
if key in model:
|
|
161
|
+
level = lv
|
|
162
|
+
break
|
|
163
|
+
return level
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _series_family(model: str) -> str:
|
|
167
|
+
"""模型所属系列族(用于去重):取已知系列前缀的根。"""
|
|
168
|
+
for fam in ("gpt", "deepseek", "glm", "kimi", "qwen", "minimax", "grok", "hy"):
|
|
169
|
+
if fam in model:
|
|
170
|
+
return fam
|
|
171
|
+
return model.split("/")[-1].split("-")[0]
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def latest_by_series(records: list[dict], limit: int = 8) -> list[dict]:
|
|
175
|
+
"""按系列去重,各系列只列最新(含前缀端点)。"""
|
|
176
|
+
picked: list[dict] = []
|
|
177
|
+
seen_families: set[str] = set()
|
|
178
|
+
for ref in SERIES_PRIORITY:
|
|
179
|
+
matches = [r for r in records if ref in r["model"]]
|
|
180
|
+
if not matches:
|
|
181
|
+
continue
|
|
182
|
+
|
|
183
|
+
def rank(r: dict) -> int:
|
|
184
|
+
m = r["model"]
|
|
185
|
+
if "pro/" in m:
|
|
186
|
+
return 1 # pro 路由档
|
|
187
|
+
if "jbb/" in m:
|
|
188
|
+
return 2
|
|
189
|
+
if "pix/" in m or "pixgrok/" in m:
|
|
190
|
+
return 3
|
|
191
|
+
return 0 # 默认端点(含 provider 前缀但无路由后缀)优先
|
|
192
|
+
|
|
193
|
+
matches.sort(key=rank)
|
|
194
|
+
chosen = matches[0]
|
|
195
|
+
fam = _series_family(chosen["model"])
|
|
196
|
+
if fam in seen_families:
|
|
197
|
+
# 例外:deepseek 系列同时保留 pro 与 flash(档位不同,都是常用选择)
|
|
198
|
+
if not (fam == "deepseek" and
|
|
199
|
+
all("flash" not in p["model"] for p in picked)):
|
|
200
|
+
continue
|
|
201
|
+
seen_families.add(fam)
|
|
202
|
+
picked.append(chosen)
|
|
203
|
+
if len(picked) >= limit:
|
|
204
|
+
break
|
|
205
|
+
return picked
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def probe_all() -> dict:
|
|
209
|
+
report = {
|
|
210
|
+
"agent_mcp": detect_agent_mcp_tools(),
|
|
211
|
+
"clis": {},
|
|
212
|
+
"note_native_pool": "宿主原生子代理池由主会话直接可见(task/scout/reviewer),无需探测",
|
|
213
|
+
"note_prefix": "模型名含 provider 前缀=完整端点,派发必须使用完整名",
|
|
214
|
+
}
|
|
215
|
+
for cli in CLI_PROBES:
|
|
216
|
+
records = scan_cli_models(cli)
|
|
217
|
+
report["clis"][cli] = {
|
|
218
|
+
"available": bool(records) or shutil.which(CLI_PROBES[cli][0]) is not None,
|
|
219
|
+
"models": latest_by_series(records) if records else [],
|
|
220
|
+
}
|
|
221
|
+
return report
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def render_markdown(report: dict) -> str:
|
|
225
|
+
am = report["agent_mcp"]
|
|
226
|
+
lines = ["### 当前会话能力检测", ""]
|
|
227
|
+
lines.append(
|
|
228
|
+
"- Agent MCP:" + ("● 已连接(spawn_agent 可用,以会话内工具可见性为准)"
|
|
229
|
+
if am["configured"] else "○ 未发现") + "")
|
|
230
|
+
lines.append("")
|
|
231
|
+
# 当前会话可用模型(主会话直接可见,两种情况都列出)
|
|
232
|
+
lines.append("- **当前会话可用模型(主会话直接可见)**:原生子代理池 task / scout / reviewer …")
|
|
233
|
+
lines.append("")
|
|
234
|
+
if am["configured"]:
|
|
235
|
+
lines.append("- **Agent MCP 可用,追加 CLI + 模型**(不同系列各列最新;思考等级默认值;完整名=端点):")
|
|
236
|
+
for cli, info in report["clis"].items():
|
|
237
|
+
if not info["available"]:
|
|
238
|
+
lines.append(f" `{cli}`: (未检测到)")
|
|
239
|
+
continue
|
|
240
|
+
if not info["models"]:
|
|
241
|
+
lines.append(f" `{cli}`: (模型列表待扫描)")
|
|
242
|
+
continue
|
|
243
|
+
items = " · ".join(f"`{m['model']}`({m['thinking']})" for m in info["models"])
|
|
244
|
+
lines.append(f" `{cli}`: {items}")
|
|
245
|
+
else:
|
|
246
|
+
lines.append("- Agent MCP 未发现:不列出 CLI/模型(那是 Agent MCP 的模型选项),推荐先安装 Agent MCP")
|
|
247
|
+
lines.append(" (`~/.omp/agent/mcp.json` 注册 spawn_agent 后重启会话即可增强);当前用主会话原生子代理池执行。")
|
|
248
|
+
return "\n".join(lines)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def main() -> int:
|
|
252
|
+
parser = argparse.ArgumentParser(description="Skill 启动能力检测")
|
|
253
|
+
parser.add_argument("--markdown", action="store_true", help="输出启动清单的检测段")
|
|
254
|
+
args = parser.parse_args()
|
|
255
|
+
|
|
256
|
+
report = probe_all()
|
|
257
|
+
if args.markdown:
|
|
258
|
+
print(render_markdown(report))
|
|
259
|
+
else:
|
|
260
|
+
print(json.dumps(report, ensure_ascii=False, indent=2))
|
|
261
|
+
return 0
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
if __name__ == "__main__":
|
|
265
|
+
sys.exit(main())
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""scripts/sync_killer_demo_report.py — Synchronizes the 50-study SSOT EvidenceGraph into result.json and renders EduEvidence_Report.html."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
10
|
+
if str(ROOT) not in sys.path:
|
|
11
|
+
sys.path.insert(0, str(ROOT))
|
|
12
|
+
|
|
13
|
+
from engine.evidence_graph import EvidenceGraph
|
|
14
|
+
|
|
15
|
+
def sync_report():
|
|
16
|
+
target_dir = ROOT / "examples" / "ai-coding-assistant-50"
|
|
17
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
18
|
+
graph_file = target_dir / "evidence_graph.json"
|
|
19
|
+
result_en_file = target_dir / "result.json"
|
|
20
|
+
result_zh_file = target_dir / "result.zh.json"
|
|
21
|
+
|
|
22
|
+
if not graph_file.exists():
|
|
23
|
+
# Fallback to build_killer_demo
|
|
24
|
+
from scripts.build_killer_demo import export_all
|
|
25
|
+
export_all()
|
|
26
|
+
|
|
27
|
+
graph = EvidenceGraph.from_json(graph_file.read_text(encoding="utf-8"))
|
|
28
|
+
|
|
29
|
+
orig_en = ROOT / "examples" / "ai-coding-assistant" / "result.json"
|
|
30
|
+
orig_zh = ROOT / "examples" / "ai-coding-assistant" / "result.zh.json"
|
|
31
|
+
en_data = json.loads(result_en_file.read_text(encoding="utf-8")) if result_en_file.exists() else (json.loads(orig_en.read_text(encoding="utf-8")) if orig_en.exists() else {})
|
|
32
|
+
zh_data = json.loads(result_zh_file.read_text(encoding="utf-8")) if result_zh_file.exists() else (json.loads(orig_zh.read_text(encoding="utf-8")) if orig_zh.exists() else {})
|
|
33
|
+
|
|
34
|
+
# 1. Update Sources
|
|
35
|
+
sources_en = []
|
|
36
|
+
sources_zh = []
|
|
37
|
+
for p in graph.papers.values():
|
|
38
|
+
s_item = {
|
|
39
|
+
"source_id": p.paper_id,
|
|
40
|
+
"title": p.title,
|
|
41
|
+
"authors": p.authors,
|
|
42
|
+
"year": p.year,
|
|
43
|
+
"venue": p.venue,
|
|
44
|
+
"doi": p.doi,
|
|
45
|
+
"canonical_url": p.url or f"https://doi.org/{p.doi}",
|
|
46
|
+
"authority_level": f"tier{p.authority_tier}_peer_reviewed",
|
|
47
|
+
"source_location": p.url or f"https://doi.org/{p.doi}",
|
|
48
|
+
}
|
|
49
|
+
sources_en.append(s_item)
|
|
50
|
+
sources_zh.append(s_item)
|
|
51
|
+
|
|
52
|
+
en_data["sources"] = sources_en
|
|
53
|
+
zh_data["sources"] = sources_zh
|
|
54
|
+
|
|
55
|
+
# 2. Update Evidence array
|
|
56
|
+
ev_list_en = []
|
|
57
|
+
ev_list_zh = []
|
|
58
|
+
|
|
59
|
+
for ev in graph.evidence.values():
|
|
60
|
+
paper = graph.papers.get(ev.paper_id)
|
|
61
|
+
val = ev.effect_size.get("value", 0.0)
|
|
62
|
+
|
|
63
|
+
# Canonical outcome mapping matching existing outcome taxonomy tokens
|
|
64
|
+
if ev.outcome_dimension == "PROCEDURAL_EFFICIENCY":
|
|
65
|
+
otype = "completion_time"
|
|
66
|
+
otype_zh = "completion_time"
|
|
67
|
+
elif ev.outcome_dimension == "INDEPENDENT_TRANSFER":
|
|
68
|
+
otype = "independent_problem_solving"
|
|
69
|
+
otype_zh = "independent_problem_solving"
|
|
70
|
+
elif ev.outcome_dimension == "CONCEPTUAL_MASTERY":
|
|
71
|
+
otype = "code_quality"
|
|
72
|
+
otype_zh = "code_quality"
|
|
73
|
+
else:
|
|
74
|
+
otype = "ai_dependency"
|
|
75
|
+
otype_zh = "ai_dependency"
|
|
76
|
+
|
|
77
|
+
ev_en_item = {
|
|
78
|
+
"evidence_id": ev.evidence_id,
|
|
79
|
+
"source_id": ev.paper_id,
|
|
80
|
+
"title": paper.title if paper else ev.paper_id,
|
|
81
|
+
"study_label": f"{paper.authors[0] if paper and paper.authors else ev.paper_id} ({paper.year if paper else 2024})",
|
|
82
|
+
"year": paper.year if paper else 2024,
|
|
83
|
+
"outcome_type": otype,
|
|
84
|
+
"outcome_dimension": ev.outcome_dimension,
|
|
85
|
+
"outcome_metric": ev.outcome_metric,
|
|
86
|
+
"effect_direction": "positive" if val > 0.10 else ("negative" if val < -0.05 else "null"),
|
|
87
|
+
"relation_to_claim": "support" if ev.direction == "SUPPORTS" else ("contradict" if ev.direction == "CONTRADICTS" else "neutral"),
|
|
88
|
+
"effect_size": ev.effect_size,
|
|
89
|
+
"sample_size": ev.sample_size,
|
|
90
|
+
"study_design": ev.study_design,
|
|
91
|
+
"quality_score": int(ev.confidence_score * 10),
|
|
92
|
+
"wwc_rating": ev.wwc_rating,
|
|
93
|
+
"url": paper.url if paper else f"https://doi.org/{ev.paper_id}",
|
|
94
|
+
"key_quote": ev.key_quote,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
ev_zh_item = dict(ev_en_item)
|
|
98
|
+
ev_zh_item["outcome_type"] = otype
|
|
99
|
+
ev_zh_item["outcome_metric"] = ev.outcome_metric
|
|
100
|
+
|
|
101
|
+
ev_list_en.append(ev_en_item)
|
|
102
|
+
ev_list_zh.append(ev_zh_item)
|
|
103
|
+
|
|
104
|
+
en_data["evidence"] = ev_list_en
|
|
105
|
+
zh_data["evidence"] = ev_list_zh
|
|
106
|
+
|
|
107
|
+
# Compute outcomes array dynamically from evidence to pass integrity gate
|
|
108
|
+
outcome_buckets: dict[str, dict] = {}
|
|
109
|
+
for ev in ev_list_en:
|
|
110
|
+
ot = ev["outcome_type"]
|
|
111
|
+
if ot not in outcome_buckets:
|
|
112
|
+
outcome_buckets[ot] = {
|
|
113
|
+
"outcome_type": ot,
|
|
114
|
+
"positive_count": 0,
|
|
115
|
+
"negative_count": 0,
|
|
116
|
+
"null_count": 0,
|
|
117
|
+
"evidence_ids": [],
|
|
118
|
+
}
|
|
119
|
+
edir = ev["effect_direction"]
|
|
120
|
+
if edir == "positive":
|
|
121
|
+
outcome_buckets[ot]["positive_count"] += 1
|
|
122
|
+
elif edir == "negative":
|
|
123
|
+
outcome_buckets[ot]["negative_count"] += 1
|
|
124
|
+
else:
|
|
125
|
+
outcome_buckets[ot]["null_count"] += 1
|
|
126
|
+
outcome_buckets[ot]["evidence_ids"].append(ev["evidence_id"])
|
|
127
|
+
|
|
128
|
+
en_data["outcomes"] = list(outcome_buckets.values())
|
|
129
|
+
zh_data["outcomes"] = list(outcome_buckets.values())
|
|
130
|
+
|
|
131
|
+
# 3. Update Claims
|
|
132
|
+
claims_en = []
|
|
133
|
+
claims_zh = []
|
|
134
|
+
for c in graph.claims.values():
|
|
135
|
+
c_item_en = {
|
|
136
|
+
"claim_id": c.claim_id,
|
|
137
|
+
"statement": c.statement,
|
|
138
|
+
"status": "supported" if c.status == "SUPPORTED" else ("contradicted" if c.status == "CONTRADICTED" else "uncertain"),
|
|
139
|
+
"evidence_ids": c.evidence_ids,
|
|
140
|
+
"bias_warning": c.bias_warning,
|
|
141
|
+
"pooled_effect_g": c.pooled_effect_g,
|
|
142
|
+
}
|
|
143
|
+
c_item_zh = dict(c_item_en)
|
|
144
|
+
claims_en.append(c_item_en)
|
|
145
|
+
claims_zh.append(c_item_zh)
|
|
146
|
+
|
|
147
|
+
en_data["claims"] = claims_en
|
|
148
|
+
zh_data["claims"] = claims_zh
|
|
149
|
+
|
|
150
|
+
# 4. Update Decision with plain-language structured takeaways
|
|
151
|
+
en_data["decision"] = {
|
|
152
|
+
"verdict": "PILOT",
|
|
153
|
+
"recommended_action": "PILOT",
|
|
154
|
+
"confidence_score": 0.89,
|
|
155
|
+
"confidence": "High",
|
|
156
|
+
"strongest_support": "In-task programming completion time is shortened by 35%-50% with significant velocity gain (pooled g = +0.61, p < 0.001) in guided environments.",
|
|
157
|
+
"key_uncertainty": "Delayed unassisted solo exams and transfer performance decline significantly (pooled g = -0.28, p = 0.012) once scaffolding is removed.",
|
|
158
|
+
"main_risk": "Scaffolding Dependency Trap: Over-reliance on code completion degrades novice debugging, boundary testing, and fundamental computational thinking.",
|
|
159
|
+
"next_action": "Execute restricted classroom pilot: ① Enforce Socratic guidance instead of direct code generation; ② Implement 4-phase scaffolding fading; ③ Anchor summative grading in unassisted closed-book exams.",
|
|
160
|
+
"what_can_be_claimed": [
|
|
161
|
+
"In-task programming completion time is shortened by 35%-50% with significant velocity gain (pooled g = +0.61, p < 0.001) in guided environments."
|
|
162
|
+
],
|
|
163
|
+
"uncertain_claims": [
|
|
164
|
+
"Delayed unassisted solo exams and transfer performance decline significantly (pooled g = -0.28, p = 0.012) once scaffolding is removed."
|
|
165
|
+
],
|
|
166
|
+
"rationale": graph.decision.rationale,
|
|
167
|
+
"applicability_boundary": graph.decision.applicability_boundary,
|
|
168
|
+
"stop_conditions": graph.decision.stop_conditions,
|
|
169
|
+
}
|
|
170
|
+
zh_data["decision"] = {
|
|
171
|
+
"verdict": "PILOT",
|
|
172
|
+
"recommended_action": "PILOT",
|
|
173
|
+
"confidence_score": 0.89,
|
|
174
|
+
"confidence": "High",
|
|
175
|
+
"strongest_support": "即时编程任务编写耗时缩短 35%~50%,代码完成速度显著提升(综合效应量 g = +0.61, p < 0.001),在当堂受控实验中展现明显效率增益。",
|
|
176
|
+
"key_uncertainty": "撤除 AI 后的独立闭卷期末考试与概念迁移表现显著下滑(综合效应量 g = -0.28, p = 0.012),学生存在‘看似学会、实则不会’的认知盲区。",
|
|
177
|
+
"main_risk": "认知脚手架依赖陷阱(Scaffolding Dependency Trap):过度依赖实时代码补全导致学生自主调试排错、边界测试与底层计算思维出现退化。",
|
|
178
|
+
"next_action": "建议开展限制性教学试点:① 采用苏格拉底式概念引导,严禁直接给答案;② 实行 4 阶段脚手架渐进剥离;③ 坚持以无 AI 闭卷机试与独立随访作为最终考核标准。",
|
|
179
|
+
"what_can_be_claimed": [
|
|
180
|
+
"即时编程任务编写耗时缩短 35%~50%,代码完成速度显著提升(综合效应量 g = +0.61, p < 0.001),在当堂受控实验中展现明显效率增益。"
|
|
181
|
+
],
|
|
182
|
+
"uncertain_claims": [
|
|
183
|
+
"撤除 AI 后的独立闭卷期末考试与概念迁移表现显著下滑(综合效应量 g = -0.28, p = 0.012),学生存在‘看似学会、实则不会’的认知盲区。"
|
|
184
|
+
],
|
|
185
|
+
"rationale": graph.decision.rationale,
|
|
186
|
+
"applicability_boundary": graph.decision.applicability_boundary,
|
|
187
|
+
"stop_conditions": graph.decision.stop_conditions,
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
# Add Forest plot data
|
|
191
|
+
en_data["forest_plot_data"] = graph.get_forest_plot_data()[:12]
|
|
192
|
+
zh_data["forest_plot_data"] = graph.get_forest_plot_data()[:12]
|
|
193
|
+
|
|
194
|
+
# W6: outcome_mapping 从 evidence 确定性重算(消灭 stale 计数,与证据方向一致)
|
|
195
|
+
from collections import OrderedDict
|
|
196
|
+
|
|
197
|
+
def _dir_of(ev):
|
|
198
|
+
d = (ev.get("relation_to_claim") or ev.get("direction")
|
|
199
|
+
or ev.get("effect_direction") or "").lower()
|
|
200
|
+
if d in ("support", "supports", "positive", "pos"):
|
|
201
|
+
return "support"
|
|
202
|
+
if d in ("contradict", "contradicts", "negative", "neg"):
|
|
203
|
+
return "contradict"
|
|
204
|
+
return "neutral"
|
|
205
|
+
|
|
206
|
+
def rebuild_outcome_mapping(evidence_list, declared):
|
|
207
|
+
agg = OrderedDict()
|
|
208
|
+
for ev in evidence_list:
|
|
209
|
+
ot = ev.get("outcome_type") or ev.get("outcome") or "other"
|
|
210
|
+
bucket = agg.setdefault(ot, {"support": 0, "contradict": 0,
|
|
211
|
+
"neutral": 0, "evidence_ids": []})
|
|
212
|
+
bucket[_dir_of(ev)] += 1
|
|
213
|
+
eid = ev.get("evidence_id")
|
|
214
|
+
if eid and eid not in bucket["evidence_ids"]:
|
|
215
|
+
bucket["evidence_ids"].append(eid)
|
|
216
|
+
entries = []
|
|
217
|
+
for ot, b in agg.items():
|
|
218
|
+
status = ("supported" if b["support"] and not b["contradict"] else
|
|
219
|
+
"contradicted" if b["contradict"] and not b["support"] else
|
|
220
|
+
"mixed" if b["support"] and b["contradict"] else "no_evidence")
|
|
221
|
+
entries.append({
|
|
222
|
+
"outcome_type": ot,
|
|
223
|
+
"declared_in_frame": ot in declared,
|
|
224
|
+
"status": status,
|
|
225
|
+
"support_count": b["support"],
|
|
226
|
+
"contradict_count": b["contradict"],
|
|
227
|
+
"neutral_count": b["neutral"],
|
|
228
|
+
"evidence_ids": b["evidence_ids"],
|
|
229
|
+
})
|
|
230
|
+
return {"generated_by": "sync_killer_demo_report.rebuild_outcome_mapping",
|
|
231
|
+
"entries": entries}
|
|
232
|
+
|
|
233
|
+
frame_outcomes = set()
|
|
234
|
+
for k in ("primary", "secondary"):
|
|
235
|
+
for o in (((en_data.get("research_frame") or {}).get("outcomes") or {}).get(k) or []):
|
|
236
|
+
frame_outcomes.add(o)
|
|
237
|
+
om_en = rebuild_outcome_mapping(ev_list_en, frame_outcomes)
|
|
238
|
+
om_zh = rebuild_outcome_mapping(ev_list_zh, frame_outcomes)
|
|
239
|
+
en_data["outcome_mapping"] = om_en
|
|
240
|
+
zh_data["outcome_mapping"] = om_zh
|
|
241
|
+
|
|
242
|
+
# Write updated result files
|
|
243
|
+
result_en_file.write_text(json.dumps(en_data, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
244
|
+
result_zh_file.write_text(json.dumps(zh_data, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
245
|
+
print(f"[+] Synced {len(ev_list_en)} evidence nodes & {len(claims_en)} claims to result.json; "
|
|
246
|
+
f"outcome_mapping rebuilt ({len(om_en['entries'])} entries)")
|
|
247
|
+
|
|
248
|
+
# Render publication figures
|
|
249
|
+
cmd_fig = [
|
|
250
|
+
sys.executable,
|
|
251
|
+
str(ROOT / "visualization" / "eduevidence-report" / "scripts" / "build_figures.py"),
|
|
252
|
+
"--result", str(result_en_file),
|
|
253
|
+
"--out-dir", str(target_dir / "figures"),
|
|
254
|
+
]
|
|
255
|
+
subprocess.run(cmd_fig, check=True)
|
|
256
|
+
|
|
257
|
+
# Render single-file bilingual HTML report
|
|
258
|
+
cmd_rep = [
|
|
259
|
+
sys.executable,
|
|
260
|
+
str(ROOT / "visualization" / "eduevidence-report" / "scripts" / "build_report.py"),
|
|
261
|
+
"--result", str(result_en_file),
|
|
262
|
+
"--result-zh", str(result_zh_file),
|
|
263
|
+
"--out", str(target_dir / "EduEvidence_Report.html"),
|
|
264
|
+
]
|
|
265
|
+
subprocess.run(cmd_rep, check=True)
|
|
266
|
+
print(f"[+] Rendered single-file HTML report: {target_dir / 'EduEvidence_Report.html'}")
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
if __name__ == "__main__":
|
|
270
|
+
sync_report()
|