eduevidence 6.2.0 → 6.3.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.
Files changed (114) hide show
  1. package/CHANGELOG.md +395 -0
  2. package/README.md +22 -13
  3. package/README.zh-CN.md +15 -8
  4. package/SKILL.md +10 -9
  5. package/benchmarks/evidence-library.json +277 -1
  6. package/docs/architecture.md +6 -3
  7. package/docs/j-ev-experimental.md +250 -0
  8. package/docs/reproducibility.md +138 -0
  9. package/domains/_neutral/copy/few_shots.json +21 -0
  10. package/domains/_neutral/copy/framing_lexicon.json +19 -0
  11. package/domains/_neutral/copy/module_labels.json +5 -0
  12. package/domains/_neutral/copy/module_labels_footer.json +102 -0
  13. package/domains/_neutral/copy/module_labels_modules.json +204 -0
  14. package/domains/_neutral/copy/module_labels_nav.json +126 -0
  15. package/domains/_neutral/copy/module_labels_summary.json +98 -0
  16. package/domains/_neutral/copy/module_labels_tables.json +164 -0
  17. package/domains/_neutral/copy/module_labels_v2.json +90 -0
  18. package/domains/_neutral/copy/risk_constructs.json +20 -0
  19. package/domains/_neutral/copy/section_titles.json +66 -0
  20. package/domains/_neutral/copy/terminology.json +11 -0
  21. package/domains/check_copy_packs.py +103 -0
  22. package/domains/education/copy/few_shots.json +22 -0
  23. package/domains/education/copy/framing_enums.json +167 -0
  24. package/domains/education/copy/framing_lexicon.json +166 -0
  25. package/domains/education/copy/module_labels.json +169 -0
  26. package/domains/education/copy/risk_constructs.json +48 -0
  27. package/domains/education/copy/section_titles.json +186 -0
  28. package/domains/education/copy/terminology.json +70 -0
  29. package/domains/education/manifest.json +1 -1
  30. package/domains/education/outcome_taxonomy.json +2 -2
  31. package/domains/manifest.json +1 -1
  32. package/domains/policy/copy/few_shots.json +22 -0
  33. package/domains/policy/copy/framing_enums.json +94 -0
  34. package/domains/policy/copy/framing_lexicon.json +174 -0
  35. package/domains/policy/copy/module_labels.json +168 -0
  36. package/domains/policy/copy/risk_constructs.json +33 -0
  37. package/domains/policy/copy/section_titles.json +186 -0
  38. package/domains/policy/copy/terminology.json +64 -0
  39. package/engine/capabilities.py +57 -5
  40. package/engine/decision_policy.py +88 -17
  41. package/engine/library_builtin.py +7 -4
  42. package/engine/tribunal.py +17 -23
  43. package/engine/versions.py +1 -1
  44. package/examples/ai-coding-assistant-evidence/EduEvidence_Report.html +4 -4
  45. package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_academic.html +4 -4
  46. package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_claude.html +4 -4
  47. package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_datalab-dark.html +4 -4
  48. package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_datalab.html +4 -4
  49. package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_presentation.html +4 -4
  50. package/examples/spaced-retrieval-practice/EduEvidence_Report.html +2728 -0
  51. package/examples/spaced-retrieval-practice/report.html +2522 -0
  52. package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_academic.html +4 -4
  53. package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_claude.html +4 -4
  54. package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_datalab-dark.html +4 -4
  55. package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_datalab.html +4 -4
  56. package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_presentation.html +4 -4
  57. package/examples/workplace-ai-assistant/EduEvidence_Report.html +2814 -0
  58. package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_academic.html +36 -36
  59. package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_claude.html +36 -36
  60. package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_datalab-dark.html +36 -36
  61. package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_datalab.html +36 -36
  62. package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_presentation.html +36 -36
  63. package/integrations/jev/__init__.py +115 -0
  64. package/integrations/jev/approval.py +212 -0
  65. package/integrations/jev/cli.py +84 -0
  66. package/integrations/jev/config.py +112 -0
  67. package/integrations/jev/gateway.py +128 -0
  68. package/integrations/jev/modes.py +38 -0
  69. package/integrations/jev/tools_classify.py +88 -0
  70. package/integrations/jev/tools_extract.py +111 -0
  71. package/integrations/jev/tools_rerank.py +71 -0
  72. package/integrations/jev/tools_screen.py +87 -0
  73. package/integrations/jev/tools_verify.py +95 -0
  74. package/integrations/jev_mcp.py +22 -0
  75. package/integrations/semantic_decide.py +286 -0
  76. package/integrations/semdecide_cli.py +55 -0
  77. package/package.json +9 -1
  78. package/pyproject.toml +1 -1
  79. package/references/report-copy-style.md +43 -3
  80. package/schemas/v2/decision-snapshot.schema.json +20 -9
  81. package/schemas/v2/intake.schema.json +191 -0
  82. package/scripts/build_evidence_library.py +15 -5
  83. package/scripts/dashboard_server.py +13 -2
  84. package/scripts/intake/__init__.py +31 -0
  85. package/scripts/intake/__main__.py +18 -0
  86. package/scripts/intake/background.py +78 -0
  87. package/scripts/intake/browser.py +79 -0
  88. package/scripts/intake/cli.py +57 -0
  89. package/scripts/intake/constants.py +57 -0
  90. package/scripts/intake/depth.py +53 -0
  91. package/scripts/intake/enhancements.py +106 -0
  92. package/scripts/intake/hooks.py +90 -0
  93. package/scripts/intake/prefs.py +76 -0
  94. package/scripts/intake/prompts.py +85 -0
  95. package/scripts/intake/session.py +152 -0
  96. package/scripts/lint_file_layers.py +126 -0
  97. package/scripts/orchestrator.py +68 -17
  98. package/scripts/pre_verdict_gate.py +21 -7
  99. package/scripts/skill_lint.py +11 -1
  100. package/scripts/skill_payload.py +3 -3
  101. package/scripts/test_adversarial_empirical.py +70 -6
  102. package/skill/agents/evidence-judge.md +49 -7
  103. package/skill/workflows/experimental-jev.md +170 -0
  104. package/skill/workflows/intake.md +120 -0
  105. package/visualization/eduevidence-report/scripts/build_infographics.py +32 -14
  106. package/visualization/eduevidence-report/scripts/build_report.py +75 -662
  107. package/visualization/eduevidence-report/scripts/report_copy_pack.py +296 -0
  108. package/visualization/eduevidence-report/scripts/report_copy_policy_guard.py +47 -0
  109. package/visualization/eduevidence-report/scripts/zh_labels.py +61 -0
  110. package/scripts/build_esl_artifacts.py +0 -1921
  111. package/scripts/build_killer_demo.py +0 -295
  112. package/scripts/enrich_projects_human_and_lieflat.py +0 -315
  113. package/scripts/generate_new_projects.py +0 -686
  114. package/scripts/sync_killer_demo_report.py +0 -270
@@ -1,270 +0,0 @@
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()