eduevidence 6.0.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 (267) hide show
  1. package/CHANGELOG.md +395 -0
  2. package/CONTRIBUTING.md +105 -0
  3. package/README.md +113 -49
  4. package/README.zh-CN.md +39 -12
  5. package/SKILL.md +15 -5
  6. package/assets/readme/landing-tour.gif +0 -0
  7. package/assets/readme/studio-tour.gif +0 -0
  8. package/benchmarks/evidence-library.json +277 -1
  9. package/bin/eduevidence.js +2 -1
  10. package/docs/architecture.md +325 -46
  11. package/docs/demo-workplace-ai.md +1 -1
  12. package/docs/install-guide.md +1 -1
  13. package/docs/j-ev-experimental.md +250 -0
  14. package/docs/orchestration-role-model.md +1 -1
  15. package/docs/release-closeout/README.md +1 -1
  16. package/docs/reproducibility.md +138 -0
  17. package/docs/sciverse-api.md +125 -0
  18. package/domains/_neutral/copy/few_shots.json +21 -0
  19. package/domains/_neutral/copy/framing_lexicon.json +19 -0
  20. package/domains/_neutral/copy/module_labels.json +5 -0
  21. package/domains/_neutral/copy/module_labels_footer.json +102 -0
  22. package/domains/_neutral/copy/module_labels_modules.json +204 -0
  23. package/domains/_neutral/copy/module_labels_nav.json +126 -0
  24. package/domains/_neutral/copy/module_labels_summary.json +98 -0
  25. package/domains/_neutral/copy/module_labels_tables.json +164 -0
  26. package/domains/_neutral/copy/module_labels_v2.json +90 -0
  27. package/domains/_neutral/copy/risk_constructs.json +20 -0
  28. package/domains/_neutral/copy/section_titles.json +66 -0
  29. package/domains/_neutral/copy/terminology.json +11 -0
  30. package/domains/check_copy_packs.py +103 -0
  31. package/domains/education/copy/few_shots.json +22 -0
  32. package/domains/education/copy/framing_enums.json +167 -0
  33. package/domains/education/copy/framing_lexicon.json +166 -0
  34. package/domains/education/copy/module_labels.json +169 -0
  35. package/domains/education/copy/risk_constructs.json +48 -0
  36. package/domains/education/copy/section_titles.json +186 -0
  37. package/domains/education/copy/terminology.json +70 -0
  38. package/domains/education/manifest.json +1 -1
  39. package/domains/education/outcome_taxonomy.json +2 -2
  40. package/domains/manifest.json +1 -1
  41. package/domains/policy/copy/few_shots.json +22 -0
  42. package/domains/policy/copy/framing_enums.json +94 -0
  43. package/domains/policy/copy/framing_lexicon.json +174 -0
  44. package/domains/policy/copy/module_labels.json +168 -0
  45. package/domains/policy/copy/risk_constructs.json +33 -0
  46. package/domains/policy/copy/section_titles.json +186 -0
  47. package/domains/policy/copy/terminology.json +64 -0
  48. package/eduevidence_cli.py +10 -0
  49. package/engine/capabilities.py +57 -5
  50. package/engine/decision_policy.py +167 -0
  51. package/engine/evidence_graph.py +14 -10
  52. package/engine/gaps.py +42 -22
  53. package/engine/ids.py +2 -0
  54. package/engine/library.py +6 -2
  55. package/engine/library_builtin.py +7 -4
  56. package/engine/living.py +34 -4
  57. package/engine/migration.py +88 -3
  58. package/engine/orchestration.py +5 -5
  59. package/engine/paths.py +2 -0
  60. package/engine/pilot.py +34 -32
  61. package/engine/taxonomy.py +211 -0
  62. package/engine/tribunal.py +49 -43
  63. package/engine/versions.py +1 -1
  64. package/examples/ai-coding-assistant-evidence/EduEvidence_Report.html +1361 -147
  65. package/examples/ai-coding-assistant-evidence/artifact_manifest.json +3 -3
  66. package/examples/ai-coding-assistant-evidence/citation_check.json +1 -1
  67. package/examples/ai-coding-assistant-evidence/final_verdict.json +107 -0
  68. package/examples/ai-coding-assistant-evidence/gate_report.json +101 -0
  69. package/examples/ai-coding-assistant-evidence/report_spec.json +23 -12
  70. package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_academic.html +448 -128
  71. package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_claude.html +448 -128
  72. package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_datalab-dark.html +448 -128
  73. package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_datalab.html +448 -128
  74. package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_presentation.html +448 -128
  75. package/examples/ai-coding-assistant-evidence/reports-5themes/report_academic.html +1360 -146
  76. package/examples/ai-coding-assistant-evidence/reports-5themes/report_claude.html +1360 -146
  77. package/examples/ai-coding-assistant-evidence/reports-5themes/report_datalab-dark.html +1360 -146
  78. package/examples/ai-coding-assistant-evidence/reports-5themes/report_datalab.html +1360 -146
  79. package/examples/ai-coding-assistant-evidence/reports-5themes/report_presentation.html +1360 -146
  80. package/examples/ai-coding-assistant-evidence/result.json +13 -9
  81. package/examples/ai-coding-assistant-evidence/result.zh.json +45 -41
  82. package/examples/ai-coding-assistant-evidence/skeptic.json +72 -0
  83. package/examples/ai-coding-assistant-evidence/verdict.json +6 -2
  84. package/examples/spaced-retrieval-practice/EduEvidence_Report.html +2728 -0
  85. package/examples/spaced-retrieval-practice/applicability.json +14 -0
  86. package/examples/spaced-retrieval-practice/artifact_manifest.json +15 -0
  87. package/examples/spaced-retrieval-practice/claims.jsonl +3 -0
  88. package/examples/spaced-retrieval-practice/evidence.jsonl +6 -0
  89. package/examples/spaced-retrieval-practice/final_verdict.json +93 -0
  90. package/examples/spaced-retrieval-practice/frame.json +58 -0
  91. package/examples/spaced-retrieval-practice/gate_report.json +101 -0
  92. package/examples/spaced-retrieval-practice/methodology.json +78 -0
  93. package/examples/spaced-retrieval-practice/report.html +2522 -0
  94. package/examples/spaced-retrieval-practice/report_spec.json +212 -0
  95. package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_academic.html +2728 -0
  96. package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_claude.html +2728 -0
  97. package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_datalab-dark.html +2728 -0
  98. package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_datalab.html +2728 -0
  99. package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_presentation.html +2728 -0
  100. package/examples/spaced-retrieval-practice/reports-5themes/report_academic.html +2728 -0
  101. package/examples/spaced-retrieval-practice/reports-5themes/report_claude.html +2728 -0
  102. package/examples/spaced-retrieval-practice/reports-5themes/report_datalab-dark.html +2728 -0
  103. package/examples/spaced-retrieval-practice/reports-5themes/report_datalab.html +2728 -0
  104. package/examples/spaced-retrieval-practice/reports-5themes/report_presentation.html +2728 -0
  105. package/examples/spaced-retrieval-practice/result.json +942 -0
  106. package/examples/spaced-retrieval-practice/result.zh.json +942 -0
  107. package/examples/spaced-retrieval-practice/skeptic.json +70 -0
  108. package/examples/spaced-retrieval-practice/sources.jsonl +7 -0
  109. package/examples/spaced-retrieval-practice/verdict.json +93 -0
  110. package/examples/workplace-ai-assistant/EduEvidence_Report.html +2814 -0
  111. package/examples/workplace-ai-assistant/artifact_manifest.json +15 -0
  112. package/examples/workplace-ai-assistant/claims.jsonl +4 -4
  113. package/examples/workplace-ai-assistant/evidence.jsonl +4 -4
  114. package/examples/workplace-ai-assistant/evidence_graph.json +15 -15
  115. package/examples/workplace-ai-assistant/final_verdict.json +78 -0
  116. package/examples/workplace-ai-assistant/gate_report.json +101 -0
  117. package/examples/workplace-ai-assistant/report_spec.json +209 -40
  118. package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_academic.html +449 -119
  119. package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_claude.html +449 -119
  120. package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_datalab-dark.html +449 -119
  121. package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_datalab.html +449 -119
  122. package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_presentation.html +449 -119
  123. package/examples/workplace-ai-assistant/reports-5themes/report_academic.html +2814 -0
  124. package/examples/workplace-ai-assistant/reports-5themes/report_claude.html +2814 -0
  125. package/examples/workplace-ai-assistant/reports-5themes/report_datalab-dark.html +2814 -0
  126. package/examples/workplace-ai-assistant/reports-5themes/report_datalab.html +2814 -0
  127. package/examples/workplace-ai-assistant/reports-5themes/report_presentation.html +2814 -0
  128. package/examples/workplace-ai-assistant/result.json +82 -20
  129. package/examples/workplace-ai-assistant/result.zh.json +82 -20
  130. package/examples/workplace-ai-assistant/skeptic.json +72 -0
  131. package/examples/workplace-ai-assistant/verdict.json +36 -10
  132. package/integrations/agent_mcp.py +2 -2
  133. package/integrations/jev/__init__.py +115 -0
  134. package/integrations/jev/approval.py +212 -0
  135. package/integrations/jev/cli.py +84 -0
  136. package/integrations/jev/config.py +112 -0
  137. package/integrations/jev/gateway.py +128 -0
  138. package/integrations/jev/modes.py +38 -0
  139. package/integrations/jev/tools_classify.py +88 -0
  140. package/integrations/jev/tools_extract.py +111 -0
  141. package/integrations/jev/tools_rerank.py +71 -0
  142. package/integrations/jev/tools_screen.py +87 -0
  143. package/integrations/jev/tools_verify.py +95 -0
  144. package/integrations/jev_mcp.py +22 -0
  145. package/integrations/semantic_decide.py +286 -0
  146. package/integrations/semdecide_cli.py +55 -0
  147. package/package.json +19 -2
  148. package/pyproject.toml +4 -3
  149. package/references/report-copy-style.md +107 -0
  150. package/references/retrieval-compliance.md +75 -0
  151. package/references/retrieval-protocol.md +20 -0
  152. package/retrieval/audit.py +27 -3
  153. package/retrieval/fetch.py +96 -0
  154. package/retrieval/sciverse.py +398 -0
  155. package/retrieval/search.py +47 -7
  156. package/schemas/applicability.schema.json +94 -0
  157. package/schemas/chart-spec.schema.json +10 -3
  158. package/schemas/evidence.schema.json +316 -43
  159. package/schemas/fetch-result.schema.json +2 -1
  160. package/schemas/report-result.schema.json +3 -3
  161. package/schemas/report-spec.schema.json +98 -100
  162. package/schemas/skeptic.schema.json +86 -0
  163. package/schemas/source.schema.json +21 -2
  164. package/schemas/v2/decision-snapshot.schema.json +20 -9
  165. package/schemas/v2/finding.schema.json +5 -1
  166. package/schemas/v2/intake.schema.json +191 -0
  167. package/schemas/v2/methodology-audit.schema.json +5 -1
  168. package/schemas/v2/outcome.schema.json +28 -5
  169. package/schemas/v2/study.schema.json +5 -1
  170. package/schemas/vNext/autoevolve-session.schema.json +34 -1
  171. package/schemas/vNext/eval-snapshot.schema.json +77 -1
  172. package/schemas/vNext/execution-plan.schema.json +50 -1
  173. package/schemas/vNext/gap-priority.schema.json +54 -1
  174. package/schemas/vNext/negative-search-record.schema.json +68 -1
  175. package/schemas/vNext/research-iteration.schema.json +87 -1
  176. package/schemas/vNext/research-strategy.schema.json +62 -1
  177. package/schemas/vNext/skill-experiment.schema.json +90 -1
  178. package/schemas/vNext/task-spec.schema.json +156 -1
  179. package/schemas/vNext/worker-result.schema.json +60 -1
  180. package/schemas/verdict.schema.json +164 -28
  181. package/scripts/build_evidence_library.py +15 -5
  182. package/scripts/build_report_variants.py +18 -2
  183. package/scripts/build_result.py +74 -9
  184. package/scripts/check_package_parity.py +85 -0
  185. package/scripts/check_protocol_alignment.py +375 -0
  186. package/scripts/check_versioned_schemas.py +254 -0
  187. package/scripts/claim_audit.py +13 -8
  188. package/scripts/compute_confidence.py +10 -0
  189. package/scripts/dashboard_server.py +13 -2
  190. package/scripts/did_regression.py +12 -2
  191. package/scripts/evidence_score.py +5 -2
  192. package/scripts/intake/__init__.py +31 -0
  193. package/scripts/intake/__main__.py +18 -0
  194. package/scripts/intake/background.py +78 -0
  195. package/scripts/intake/browser.py +79 -0
  196. package/scripts/intake/cli.py +57 -0
  197. package/scripts/intake/constants.py +57 -0
  198. package/scripts/intake/depth.py +53 -0
  199. package/scripts/intake/enhancements.py +106 -0
  200. package/scripts/intake/hooks.py +90 -0
  201. package/scripts/intake/prefs.py +76 -0
  202. package/scripts/intake/prompts.py +85 -0
  203. package/scripts/intake/session.py +152 -0
  204. package/scripts/lint_file_layers.py +126 -0
  205. package/scripts/orchestrator.py +187 -40
  206. package/scripts/pre_verdict_gate.py +241 -29
  207. package/scripts/quickstart.py +18 -2
  208. package/scripts/run_workspace.py +7 -1
  209. package/scripts/skill_lint.py +11 -1
  210. package/scripts/skill_payload.py +6 -3
  211. package/scripts/test_adversarial_empirical.py +96 -25
  212. package/scripts/validate_schema.py +31 -1
  213. package/skill/agents/evaluation-designer.md +20 -4
  214. package/skill/agents/evidence-analyst.md +19 -3
  215. package/skill/agents/evidence-judge.md +98 -8
  216. package/skill/agents/evidence-retriever.md +20 -3
  217. package/skill/agents/intervention-designer.md +20 -4
  218. package/skill/agents/method-reviewer.md +18 -2
  219. package/skill/agents/{education-planner.md → research-planner.md} +19 -3
  220. package/skill/agents/skeptic.md +18 -2
  221. package/skill/roles/registry.yaml +11 -11
  222. package/skill/sub-skills/aihot-trend-analysis/SKILL.md +28 -9
  223. package/skill/sub-skills/contradiction-analysis/SKILL.md +31 -11
  224. package/skill/sub-skills/data-analysis/SKILL.md +34 -15
  225. package/skill/sub-skills/ethics-review/SKILL.md +33 -10
  226. package/skill/sub-skills/evidence-extraction/SKILL.md +29 -11
  227. package/skill/sub-skills/evidence-review/SKILL.md +31 -12
  228. package/skill/sub-skills/gap-analysis/SKILL.md +31 -9
  229. package/skill/sub-skills/literature-review/SKILL.md +35 -14
  230. package/skill/sub-skills/methodology-audit/SKILL.md +29 -12
  231. package/skill/sub-skills/report-generation/SKILL.md +28 -0
  232. package/skill/sub-skills/research-planning/SKILL.md +41 -14
  233. package/skill/sub-skills/study-design/SKILL.md +30 -9
  234. package/skill/task-briefs/adjudicate.md +32 -7
  235. package/skill/task-briefs/applicability.md +37 -2
  236. package/skill/task-briefs/audit.md +32 -7
  237. package/skill/task-briefs/challenge.md +34 -5
  238. package/skill/task-briefs/evaluate.md +30 -5
  239. package/skill/task-briefs/extract.md +31 -8
  240. package/skill/task-briefs/frame.md +39 -10
  241. package/skill/task-briefs/intervene.md +32 -6
  242. package/skill/task-briefs/present.md +32 -8
  243. package/skill/task-briefs/projection.md +36 -2
  244. package/skill/task-briefs/retrieve.md +36 -6
  245. package/skill/workflows/decision-and-pilot.md +76 -1
  246. package/skill/workflows/evaluate-and-update.md +83 -0
  247. package/skill/workflows/evidence-review.md +104 -0
  248. package/skill/workflows/experimental-jev.md +170 -0
  249. package/skill/workflows/intake.md +120 -0
  250. package/visualization/eduevidence-report/scripts/build_figures.py +25 -3
  251. package/visualization/eduevidence-report/scripts/build_infographics.py +37 -15
  252. package/visualization/eduevidence-report/scripts/build_report.py +435 -575
  253. package/visualization/eduevidence-report/scripts/charts_data.py +2 -0
  254. package/visualization/eduevidence-report/scripts/lieflat_engine.py +349 -38
  255. package/visualization/eduevidence-report/scripts/report_copy_pack.py +296 -0
  256. package/visualization/eduevidence-report/scripts/report_copy_policy_guard.py +47 -0
  257. package/visualization/eduevidence-report/scripts/zh_labels.py +141 -1
  258. package/web/architecture.html +14885 -0
  259. package/web/studio/assets/index-B8tkF44Q.css +1 -0
  260. package/web/studio/index.html +2 -2
  261. package/scripts/build_esl_artifacts.py +0 -1921
  262. package/scripts/build_killer_demo.py +0 -295
  263. package/scripts/enrich_projects_human_and_lieflat.py +0 -315
  264. package/scripts/generate_new_projects.py +0 -686
  265. package/scripts/sync_killer_demo_report.py +0 -270
  266. package/web/studio/assets/index-CzXocaGv.css +0 -1
  267. /package/web/studio/assets/{index-pa7jD7n4.js → index-CQ6Keoyc.js} +0 -0
@@ -38,10 +38,16 @@ from datetime import datetime, timezone
38
38
  from pathlib import Path
39
39
 
40
40
  from engine.contracts import validate_record
41
+ from engine.decision_policy import (
42
+ ADOPT_DIRECTNESS,
43
+ decision_outcome,
44
+ outcome_category,
45
+ primary_effect_categories,
46
+ )
41
47
  from engine.graph_store import GraphStore
42
48
  from engine.ids import new_local_id
43
49
  from engine.project import ProjectWorkspace
44
- from engine.semantics import claim_relation, decision_implication
50
+ from engine.semantics import decision_implication
45
51
  from engine.synthesis import ClaimSynthesis, synthesize_project
46
52
  from engine.versions import (
47
53
  CONFIDENCE_POLICY_VERSION,
@@ -193,6 +199,7 @@ def _confidence(store: GraphStore, syntheses: tuple[ClaimSynthesis, ...]) -> dic
193
199
  if relation in ("support_adoption", "oppose_adoption"):
194
200
  decisive[sid] = relation
195
201
  elif relation == "conditional":
202
+ decisive[sid] = "conditional"
196
203
  critical_uncertainty_units += 1
197
204
  quality_sum += (
198
205
  audit.get("design_quality", 0) + audit.get("sample_quality", 0)
@@ -203,7 +210,8 @@ def _confidence(store: GraphStore, syntheses: tuple[ClaimSynthesis, ...]) -> dic
203
210
  directness_sum += sum(dirs) / len(dirs) / 2.0
204
211
  directness_count += 1
205
212
 
206
- n_decisive = len(decisive)
213
+ n_decisive = sum(1 for r in decisive.values()
214
+ if r in ("support_adoption", "oppose_adoption"))
207
215
  n_usable = len(usable_studies)
208
216
  if n_decisive == 0:
209
217
  return {"score": 0.0, "label": "Insufficient",
@@ -230,16 +238,18 @@ def _confidence(store: GraphStore, syntheses: tuple[ClaimSynthesis, ...]) -> dic
230
238
  "decisive_relations": dict(decisive)}
231
239
 
232
240
 
233
- def _has_direct_learning_evidence(store: GraphStore,
234
- decisive_relations: dict[str, str]) -> bool:
235
- """True when at least one decisive support_adoption Study measures a
236
- learning outcome directly.
241
+ def _has_direct_primary_evidence(store: GraphStore,
242
+ decisive_relations: dict[str, str],
243
+ domain: str = "education") -> bool:
244
+ """True when a decisive support_adoption Study measures a primary outcome.
237
245
 
238
- Learning evidence means the finding's outcome is declared
239
- outcome_type == "learning" AND its evidence link carries directness == 2.
240
- Task performance / process / risk outcomes never qualify, and a missing
241
- outcome record or missing directness fails closed (False).
246
+ Primary means the finding's outcome_type maps — through the domain
247
+ registry — into one of :func:`primary_effect_categories` (education:
248
+ learning; policy: effectiveness/cost), AND its evidence link carries
249
+ directness == 2. Task-performance, process and risk outcomes never
250
+ qualify, and a missing outcome record or missing directness fails closed.
242
251
  """
252
+ primary = primary_effect_categories(domain)
243
253
  findings = {f["finding_id"]: f for f in store.read_table("findings")}
244
254
  outcomes = {o["outcome_id"]: o for o in store.read_table("outcomes")}
245
255
  links_by_finding: dict[str, list[dict]] = {}
@@ -254,40 +264,24 @@ def _has_direct_learning_evidence(store: GraphStore,
254
264
  if fnd.get("study_id") not in support_studies:
255
265
  continue
256
266
  outcome = outcomes.get(fnd.get("outcome_id"))
257
- if outcome is None or outcome.get("outcome_type") != "learning":
267
+ if outcome is None:
268
+ continue
269
+ value = str(outcome.get("outcome_type") or "")
270
+ category = outcome_category(domain, value, primary)
271
+ # Unknown value: fail closed rather than treating it as
272
+ # decision-grade evidence.
273
+ if category is None:
274
+ continue
275
+ if category not in primary:
258
276
  continue
259
277
  for link in links_by_finding.get(fid, []):
260
278
  directness = link.get("directness")
261
- if isinstance(directness, (int, float)) and int(directness) == 2:
279
+ if (isinstance(directness, (int, float))
280
+ and int(directness) == ADOPT_DIRECTNESS):
262
281
  return True
263
282
  return False
264
283
 
265
284
 
266
- def _decision_action(syn_statuses: dict[str, str], confidence: dict,
267
- decisive_relations: dict[str, str],
268
- has_direct_learning_evidence: bool = False) -> str:
269
- """Gate-enforced decision action.
270
-
271
- REJECT requires usable direct opposition evidence (an independent Study
272
- folded to oppose_adoption). Low/Insufficient can never yield ADOPT.
273
- ADOPT additionally requires direct learning/transfer evidence: High +
274
- decisive support WITHOUT a direct learning outcome downgrades to PILOT
275
- (task performance / procedural efficiency is not learning). Moderate +
276
- decisive support → PILOT; otherwise INSUFFICIENT_EVIDENCE.
277
- """
278
- label = confidence["label"]
279
- has_oppose = any(r == "oppose_adoption" for r in decisive_relations.values())
280
- has_support = any(r == "support_adoption" for r in decisive_relations.values())
281
- if has_oppose:
282
- return "REJECT"
283
- if label == "High" and has_support and has_direct_learning_evidence:
284
- return "ADOPT"
285
- if label in ("High", "Moderate") and has_support:
286
- return "PILOT"
287
- return "INSUFFICIENT_EVIDENCE"
288
-
289
-
290
-
291
285
  def adjudicate(store: GraphStore, *, project: ProjectWorkspace,
292
286
  claim_syntheses: tuple[ClaimSynthesis, ...] | None = None,
293
287
  applicability: dict | None = None,
@@ -297,12 +291,19 @@ def adjudicate(store: GraphStore, *, project: ProjectWorkspace,
297
291
  confidence = _confidence(store, syntheses)
298
292
  applicability = applicability or {"boundary": "evidence scope", "notes": ""}
299
293
 
300
- syn_statuses = {s.claim_id: s.status for s in syntheses}
301
294
  decisive_relations = confidence.get("decisive_relations", {})
302
- direct_learning = _has_direct_learning_evidence(store, decisive_relations)
303
-
304
- decision = _decision_action(syn_statuses, confidence, decisive_relations,
305
- has_direct_learning_evidence=direct_learning)
295
+ domain = str(project.manifest().get("domain") or "education")
296
+ direct_learning = _has_direct_primary_evidence(store, decisive_relations, domain)
297
+
298
+ # Single authority: engine.decision_policy owns the four-state matrix, and
299
+ # engine/tribunal.py keeps no private copy of the rule that could drift.
300
+ outcome = decision_outcome(
301
+ confidence_label=str(confidence.get("label") or ""),
302
+ decisive_relations=decisive_relations,
303
+ has_direct_primary_evidence=direct_learning,
304
+ )
305
+ decision = str(outcome["action"])
306
+ downgrade_reason = outcome.get("downgrade_reason")
306
307
 
307
308
  key_links: list[str] = []
308
309
  for syn in syntheses:
@@ -313,7 +314,8 @@ def adjudicate(store: GraphStore, *, project: ProjectWorkspace,
313
314
  for syn in syntheses:
314
315
  risks.extend(syn.unresolved_conflicts)
315
316
  if not risks and decision == "ADOPT":
316
- risks.append("long-term retention/transfer may still be untested")
317
+ risks.append(
318
+ "primary-outcome durability beyond the observed window may still be untested")
317
319
 
318
320
  missing: list[str] = []
319
321
  for syn in syntheses:
@@ -334,6 +336,7 @@ def adjudicate(store: GraphStore, *, project: ProjectWorkspace,
334
336
  snapshot = {
335
337
  "decision_snapshot_id": new_local_id("DEC", set()),
336
338
  "decision": decision,
339
+ "downgrade_reason": downgrade_reason,
337
340
  "confidence_label": confidence["label"],
338
341
  "confidence_score_internal": confidence["score"],
339
342
  "claim_assessments": claim_assessments,
@@ -351,6 +354,9 @@ def adjudicate(store: GraphStore, *, project: ProjectWorkspace,
351
354
  "extensions": {"confidence_components": {
352
355
  "decisive_studies": confidence.get("decisive_studies", 0),
353
356
  "usable_studies": confidence.get("usable_studies", 0),
357
+ "has_direct_primary_evidence": direct_learning,
358
+ # Backward-compatible alias under the education-era name,
359
+ # so readers written against the older contract keep working.
354
360
  "has_direct_learning_evidence": direct_learning,
355
361
  }},
356
362
  }
@@ -4,7 +4,7 @@ Policy versions are frozen identifiers, not free-form strings: changing a
4
4
  policy requires a new version, never silent mutation of an existing one.
5
5
  """
6
6
 
7
- ENGINE_VERSION = "6.0.0"
7
+ ENGINE_VERSION = "6.3.0"
8
8
  GRAPH_SCHEMA_VERSION = "2.0"
9
9
  SOURCE_VALIDATION_POLICY_VERSION = "2026-08-12.v2"
10
10
  METHODOLOGY_POLICY_VERSION = "2026-08-12.v2"