eduevidence 5.2.0 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +105 -0
- package/README.md +142 -75
- package/README.zh-CN.md +73 -30
- package/SKILL.md +397 -131
- package/agents/openai.yaml +4 -0
- package/assets/readme/controlled-execution.svg +34 -0
- package/assets/readme/landing-tour.gif +0 -0
- package/assets/readme/logo.png +0 -0
- package/assets/readme/research-workflow.svg +56 -0
- package/assets/readme/studio-graph.png +0 -0
- package/assets/readme/studio-overview.png +0 -0
- package/assets/readme/studio-reports.png +0 -0
- package/assets/readme/studio-tour.gif +0 -0
- package/autoevolve/config.yaml +17 -0
- package/autoevolve/program.md +25 -0
- package/autoevolve/protected.manifest.yaml +34 -0
- package/benchmarks/adversarial/cases.jsonl +7 -0
- package/benchmarks/evidence-library.json +5268 -0
- package/benchmarks/partitions.json +8 -0
- package/bin/eduevidence.js +2 -1
- package/docs/architecture.md +496 -0
- package/docs/autoresearch-evolution-plan.md +2903 -0
- package/docs/autoresearch-implementation-status.md +101 -0
- package/docs/demo-storyboard.md +20 -0
- package/docs/demo-workplace-ai.md +92 -0
- package/docs/demo.md +32 -0
- package/docs/install-guide.md +150 -0
- package/docs/orchestration-role-model.md +1254 -0
- package/docs/release-closeout/README.md +17 -0
- package/docs/release-closeout/frontend-acceptance.md +23 -0
- package/docs/release-closeout/issues.md +19 -0
- package/docs/release-closeout/verification.md +28 -0
- package/docs/release-contract.md +108 -0
- package/docs/research-studio-guide.zh-CN.md +166 -0
- package/docs/sciverse-api.md +125 -0
- package/eduevidence_cli.py +29 -13
- package/engine/_resources.py +13 -0
- package/engine/autoevolve/__init__.py +3 -0
- package/engine/autoevolve/agent_view.py +167 -0
- package/engine/autoevolve/core.py +357 -0
- package/engine/autoevolve/events.py +11 -0
- package/engine/autoevolve/git_workspace.py +77 -0
- package/engine/autoevolve/projection.py +23 -0
- package/engine/autoevolve/runner.py +413 -0
- package/engine/autoevolve/trust.py +146 -0
- package/engine/autoresearch/__init__.py +6 -0
- package/engine/autoresearch/commit.py +132 -0
- package/engine/autoresearch/contracts.py +126 -0
- package/engine/autoresearch/controller.py +207 -0
- package/engine/autoresearch/events.py +12 -0
- package/engine/autoresearch/gap_priority.py +168 -0
- package/engine/autoresearch/projection.py +30 -0
- package/engine/autoresearch/research_memory.py +59 -0
- package/engine/autoresearch/saturation.py +91 -0
- package/engine/briefs.py +2 -1
- package/engine/capabilities.py +1 -0
- package/engine/contracts.py +3 -1
- package/engine/decision_policy.py +96 -0
- package/engine/evidence_graph.py +14 -10
- package/engine/evidencecore.py +7 -5
- package/engine/gaps.py +132 -73
- package/engine/ids.py +2 -0
- package/engine/judge_pack.py +65 -0
- package/engine/library.py +6 -2
- package/engine/library_builtin.py +3 -1
- package/engine/living.py +36 -5
- package/engine/meta_synthesis.py +3 -1
- package/engine/migration.py +88 -3
- package/engine/orchestration.py +460 -0
- package/engine/paths.py +2 -0
- package/engine/pilot.py +36 -33
- package/engine/project.py +2 -2
- package/engine/research_service.py +113 -0
- package/engine/studio_read_model.py +400 -0
- package/engine/taxonomy.py +211 -0
- package/engine/tribunal.py +44 -33
- package/engine/update.py +1 -0
- package/engine/versions.py +1 -1
- package/engine/worker_result.py +109 -0
- package/engine/workflows.py +70 -0
- package/examples/ai-coding-assistant-evidence/EduEvidence_Report.html +2934 -0
- package/examples/ai-coding-assistant-evidence/artifact_manifest.json +15 -0
- package/examples/ai-coding-assistant-evidence/citation_check.json +79 -0
- package/examples/ai-coding-assistant-evidence/claims.jsonl +12 -0
- package/examples/ai-coding-assistant-evidence/evaluation.json +35 -0
- package/examples/ai-coding-assistant-evidence/evidence.jsonl +12 -0
- package/examples/ai-coding-assistant-evidence/final_verdict.json +107 -0
- package/examples/ai-coding-assistant-evidence/frame.json +48 -0
- package/examples/ai-coding-assistant-evidence/gate_report.json +101 -0
- package/examples/ai-coding-assistant-evidence/intervention.json +51 -0
- package/examples/ai-coding-assistant-evidence/methodology.json +36 -0
- package/examples/ai-coding-assistant-evidence/raw_verdict.json +86 -0
- package/examples/ai-coding-assistant-evidence/report_spec.json +230 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_academic.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_claude.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_datalab-dark.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_datalab.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/EduEvidence_Report_presentation.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/report_academic.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/report_claude.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/report_datalab-dark.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/report_datalab.html +2934 -0
- package/examples/ai-coding-assistant-evidence/reports-5themes/report_presentation.html +2934 -0
- package/examples/ai-coding-assistant-evidence/result.json +1457 -0
- package/examples/ai-coding-assistant-evidence/result.zh.json +1457 -0
- package/examples/ai-coding-assistant-evidence/skeptic.json +72 -0
- package/examples/ai-coding-assistant-evidence/sources.jsonl +8 -0
- package/examples/ai-coding-assistant-evidence/verdict.json +107 -0
- package/examples/spaced-retrieval-practice/applicability.json +14 -0
- package/examples/spaced-retrieval-practice/artifact_manifest.json +15 -0
- package/examples/spaced-retrieval-practice/claims.jsonl +3 -0
- package/examples/spaced-retrieval-practice/evidence.jsonl +6 -0
- package/examples/spaced-retrieval-practice/final_verdict.json +93 -0
- package/examples/spaced-retrieval-practice/frame.json +58 -0
- package/examples/spaced-retrieval-practice/gate_report.json +101 -0
- package/examples/spaced-retrieval-practice/methodology.json +78 -0
- package/examples/spaced-retrieval-practice/report_spec.json +212 -0
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_academic.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_claude.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_datalab-dark.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_datalab.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/EduEvidence_Report_presentation.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/report_academic.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/report_claude.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/report_datalab-dark.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/report_datalab.html +2728 -0
- package/examples/spaced-retrieval-practice/reports-5themes/report_presentation.html +2728 -0
- package/examples/spaced-retrieval-practice/result.json +942 -0
- package/examples/spaced-retrieval-practice/result.zh.json +942 -0
- package/examples/spaced-retrieval-practice/skeptic.json +70 -0
- package/examples/spaced-retrieval-practice/sources.jsonl +7 -0
- package/examples/spaced-retrieval-practice/verdict.json +93 -0
- package/examples/workplace-ai-assistant/artifact_manifest.json +15 -0
- package/examples/workplace-ai-assistant/claims.jsonl +4 -0
- package/examples/workplace-ai-assistant/evaluation.json +19 -0
- package/examples/workplace-ai-assistant/evidence.jsonl +4 -0
- package/examples/workplace-ai-assistant/evidence_graph.json +444 -0
- package/examples/workplace-ai-assistant/final_verdict.json +78 -0
- package/examples/workplace-ai-assistant/frame.json +41 -0
- package/examples/workplace-ai-assistant/gate_report.json +101 -0
- package/examples/workplace-ai-assistant/intervention.json +27 -0
- package/examples/workplace-ai-assistant/legacy-link-check.json +16 -0
- package/examples/workplace-ai-assistant/methodology.json +60 -0
- package/examples/workplace-ai-assistant/report_spec.json +224 -0
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_academic.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_claude.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_datalab-dark.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_datalab.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/EduEvidence_Report_presentation.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/report_academic.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/report_claude.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/report_datalab-dark.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/report_datalab.html +2814 -0
- package/examples/workplace-ai-assistant/reports-5themes/report_presentation.html +2814 -0
- package/examples/workplace-ai-assistant/result.json +615 -0
- package/examples/workplace-ai-assistant/result.zh.json +615 -0
- package/examples/workplace-ai-assistant/search_log.json +19 -0
- package/examples/workplace-ai-assistant/skeptic.json +72 -0
- package/examples/workplace-ai-assistant/sources.jsonl +3 -0
- package/examples/workplace-ai-assistant/validation_result.json +9 -0
- package/examples/workplace-ai-assistant/verdict.json +78 -0
- package/install.sh +7 -7
- package/integrations/agent_mcp.py +2 -2
- package/integrations/orchestration_dispatch.py +146 -0
- package/package.json +46 -3
- package/pyproject.toml +14 -22
- package/references/autoresearch.md +30 -0
- package/references/evaluation-policy.md +24 -0
- package/references/orchestration.md +22 -0
- package/references/report-copy-style.md +67 -0
- package/references/retrieval-compliance.md +75 -0
- package/references/retrieval-protocol.md +20 -0
- package/references/scientific-invariants.md +19 -0
- package/retrieval/audit.py +178 -0
- package/retrieval/fetch.py +96 -0
- package/retrieval/sciverse.py +398 -0
- package/retrieval/search.py +47 -7
- package/schemas/applicability.schema.json +94 -0
- package/schemas/chart-spec.schema.json +10 -3
- package/schemas/evidence.schema.json +316 -43
- package/schemas/fetch-result.schema.json +2 -1
- package/schemas/intervention.schema.json +106 -21
- package/schemas/report-result.schema.json +12 -4
- package/schemas/report-spec.schema.json +98 -100
- package/schemas/skeptic.schema.json +86 -0
- package/schemas/source.schema.json +21 -2
- package/schemas/v2/finding.schema.json +5 -1
- package/schemas/v2/methodology-audit.schema.json +5 -1
- package/schemas/v2/outcome.schema.json +28 -5
- package/schemas/v2/project.schema.json +2 -2
- package/schemas/v2/run.schema.json +1 -1
- package/schemas/v2/study.schema.json +5 -1
- package/schemas/vNext/autoevolve-session.schema.json +34 -0
- package/schemas/vNext/eval-snapshot.schema.json +77 -0
- package/schemas/vNext/execution-plan.schema.json +50 -0
- package/schemas/vNext/gap-priority.schema.json +54 -0
- package/schemas/vNext/negative-search-record.schema.json +68 -0
- package/schemas/vNext/research-iteration.schema.json +87 -0
- package/schemas/vNext/research-strategy.schema.json +62 -0
- package/schemas/vNext/skill-experiment.schema.json +90 -0
- package/schemas/vNext/task-spec.schema.json +156 -0
- package/schemas/vNext/worker-result.schema.json +60 -0
- package/schemas/verdict.schema.json +164 -28
- package/scripts/benchmark_judge.py +2 -2
- package/scripts/benchmark_v3.py +26 -43
- package/scripts/build_esl_artifacts.py +4 -4
- package/scripts/build_evidence_library.py +2 -2
- package/scripts/build_gh_pages.py +98 -0
- package/scripts/build_readme_diagrams.py +72 -0
- package/scripts/build_report_variants.py +101 -0
- package/scripts/build_result.py +74 -9
- package/scripts/check_autoresearch_invariants.py +95 -0
- package/scripts/check_package_parity.py +85 -0
- package/scripts/check_protocol_alignment.py +375 -0
- package/scripts/check_versioned_schemas.py +254 -0
- package/scripts/claim_audit.py +13 -8
- package/scripts/compute_confidence.py +10 -0
- package/scripts/daily_evolve.py +30 -0
- package/scripts/dashboard_server.py +130 -101
- package/scripts/did_regression.py +17 -32
- package/scripts/enrich_projects_human_and_lieflat.py +1 -1
- package/scripts/evidence_score.py +5 -2
- package/scripts/generate_metrics.py +4 -3
- package/scripts/generate_new_projects.py +5 -5
- package/scripts/orchestrator.py +286 -36
- package/scripts/pre_verdict_gate.py +224 -26
- package/scripts/quickstart.py +18 -2
- package/scripts/rebake_all_5themes.py +1 -2
- package/scripts/research_auto_cli.py +475 -0
- package/scripts/run_workspace.py +24 -8
- package/scripts/search_provenance.py +64 -0
- package/scripts/serve_web.py +9 -10
- package/scripts/skill_lint.py +1 -1
- package/scripts/skill_payload.py +81 -0
- package/scripts/test_adversarial_empirical.py +26 -19
- package/scripts/validate_schema.py +46 -2
- package/scripts/vnext_cli.py +133 -0
- package/setup.py +12 -0
- package/skill/agents/evaluation-designer.md +20 -4
- package/skill/agents/evidence-analyst.md +19 -3
- package/skill/agents/evidence-judge.md +50 -2
- package/skill/agents/evidence-retriever.md +20 -3
- package/skill/agents/intervention-designer.md +20 -4
- package/skill/agents/method-reviewer.md +18 -2
- package/skill/agents/{education-planner.md → research-planner.md} +19 -3
- package/skill/agents/skeptic.md +18 -2
- package/skill/roles/registry.yaml +45 -0
- package/skill/sub-skills/aihot-trend-analysis/SKILL.md +28 -9
- package/skill/sub-skills/contradiction-analysis/SKILL.md +31 -11
- package/skill/sub-skills/data-analysis/SKILL.md +34 -15
- package/skill/sub-skills/ethics-review/SKILL.md +33 -10
- package/skill/sub-skills/evidence-extraction/SKILL.md +29 -11
- package/skill/sub-skills/evidence-review/SKILL.md +31 -12
- package/skill/sub-skills/gap-analysis/SKILL.md +31 -9
- package/skill/sub-skills/literature-review/SKILL.md +35 -14
- package/skill/sub-skills/methodology-audit/SKILL.md +29 -12
- package/skill/sub-skills/report-generation/SKILL.md +40 -6
- package/skill/sub-skills/research-planning/SKILL.md +41 -14
- package/skill/sub-skills/study-design/SKILL.md +30 -9
- package/skill/task-briefs/adjudicate.md +32 -7
- package/skill/task-briefs/applicability.md +38 -0
- package/skill/task-briefs/audit.md +32 -7
- package/skill/task-briefs/challenge.md +34 -5
- package/skill/task-briefs/evaluate.md +30 -5
- package/skill/task-briefs/extract.md +31 -8
- package/skill/task-briefs/frame.md +39 -10
- package/skill/task-briefs/intervene.md +32 -6
- package/skill/task-briefs/present.md +32 -8
- package/skill/task-briefs/projection.md +37 -0
- package/skill/task-briefs/retrieve.md +36 -6
- package/skill/workflows/decision-and-pilot.md +85 -0
- package/skill/workflows/evaluate-and-update.md +93 -0
- package/skill/workflows/evidence-review.md +117 -0
- package/visualization/eduevidence-report/assets/base.css +2 -2
- package/visualization/eduevidence-report/assets/reader.css +752 -0
- package/visualization/eduevidence-report/assets/reader.js +132 -0
- package/visualization/eduevidence-report/references/chart-selection-catalog.md +109 -0
- package/visualization/eduevidence-report/references/lieflat-composition.md +3 -1
- package/visualization/eduevidence-report/scripts/build_figures.py +25 -3
- package/visualization/eduevidence-report/scripts/build_infographics.py +5 -1
- package/visualization/eduevidence-report/scripts/build_report.py +561 -121
- package/visualization/eduevidence-report/scripts/charts_data.py +2 -0
- package/visualization/eduevidence-report/scripts/lieflat_engine.py +371 -136
- package/visualization/eduevidence-report/scripts/zh_labels.py +80 -1
- package/visualization/eduevidence-report/themes/academic.css +1 -1
- package/visualization/eduevidence-report/themes/claude.css +1 -1
- package/visualization/eduevidence-report/themes/datalab-dark.css +2 -2
- package/visualization/eduevidence-report/themes/datalab.css +2 -2
- package/visualization/eduevidence-report/themes/presentation.css +2 -2
- package/web/README.md +18 -0
- package/web/architecture.html +14885 -0
- package/web/index.html +53 -0
- package/web/studio/THIRD_PARTY_LICENSES.txt +146 -0
- package/web/studio/assets/index-B8tkF44Q.css +1 -0
- package/web/studio/assets/index-CQ6Keoyc.js +230 -0
- package/web/studio/config.json +1 -0
- package/web/studio/index.html +14 -0
- package/engine/__pycache__/__init__.cpython-312.pyc +0 -0
- package/engine/__pycache__/analysis.cpython-312.pyc +0 -0
- package/engine/__pycache__/bias.cpython-312.pyc +0 -0
- package/engine/__pycache__/briefs.cpython-312.pyc +0 -0
- package/engine/__pycache__/capabilities.cpython-312.pyc +0 -0
- package/engine/__pycache__/citation_check.cpython-312.pyc +0 -0
- package/engine/__pycache__/contracts.cpython-312.pyc +0 -0
- package/engine/__pycache__/datasets.cpython-312.pyc +0 -0
- package/engine/__pycache__/events.cpython-312.pyc +0 -0
- package/engine/__pycache__/evidence_graph.cpython-312.pyc +0 -0
- package/engine/__pycache__/evidence_review.cpython-312.pyc +0 -0
- package/engine/__pycache__/evidencecore.cpython-312.pyc +0 -0
- package/engine/__pycache__/gap_lens.cpython-312.pyc +0 -0
- package/engine/__pycache__/gaps.cpython-312.pyc +0 -0
- package/engine/__pycache__/graph_store.cpython-312.pyc +0 -0
- package/engine/__pycache__/graph_validate.cpython-312.pyc +0 -0
- package/engine/__pycache__/ids.cpython-312.pyc +0 -0
- package/engine/__pycache__/library.cpython-312.pyc +0 -0
- package/engine/__pycache__/library_builtin.cpython-312.pyc +0 -0
- package/engine/__pycache__/living.cpython-312.pyc +0 -0
- package/engine/__pycache__/log.cpython-312.pyc +0 -0
- package/engine/__pycache__/meta_analysis.cpython-312.pyc +0 -0
- package/engine/__pycache__/meta_synthesis.cpython-312.pyc +0 -0
- package/engine/__pycache__/migration.cpython-312.pyc +0 -0
- package/engine/__pycache__/mode_router.cpython-312.pyc +0 -0
- package/engine/__pycache__/paths.cpython-312.pyc +0 -0
- package/engine/__pycache__/pilot.cpython-312.pyc +0 -0
- package/engine/__pycache__/planner.cpython-312.pyc +0 -0
- package/engine/__pycache__/project.cpython-312.pyc +0 -0
- package/engine/__pycache__/projections.cpython-312.pyc +0 -0
- package/engine/__pycache__/robustness.cpython-312.pyc +0 -0
- package/engine/__pycache__/run.cpython-312.pyc +0 -0
- package/engine/__pycache__/semantics.cpython-312.pyc +0 -0
- package/engine/__pycache__/study_design.cpython-312.pyc +0 -0
- package/engine/__pycache__/synthesis.cpython-312.pyc +0 -0
- package/engine/__pycache__/tribunal.cpython-312.pyc +0 -0
- package/engine/__pycache__/update.cpython-312.pyc +0 -0
- package/engine/__pycache__/versions.cpython-312.pyc +0 -0
- package/integrations/__pycache__/__init__.cpython-312.pyc +0 -0
- package/integrations/__pycache__/agent_mcp.cpython-312.pyc +0 -0
- package/integrations/__pycache__/smart_web_fetch.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/__init__.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/corpus_store.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/dedupe.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/failures.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/fetch.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/search.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/source.cpython-312.pyc +0 -0
- package/retrieval/__pycache__/validate.cpython-312.pyc +0 -0
- package/scripts/__pycache__/__init__.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_evaluator.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_judge.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_routing.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_v2.cpython-312.pyc +0 -0
- package/scripts/__pycache__/benchmark_v3.cpython-312.pyc +0 -0
- package/scripts/__pycache__/build_result.cpython-312.pyc +0 -0
- package/scripts/__pycache__/claim_audit.cpython-312.pyc +0 -0
- package/scripts/__pycache__/complexity_gate.cpython-312.pyc +0 -0
- package/scripts/__pycache__/compute_confidence.cpython-312.pyc +0 -0
- package/scripts/__pycache__/dashboard_server.cpython-312.pyc +0 -0
- package/scripts/__pycache__/did_regression.cpython-312.pyc +0 -0
- package/scripts/__pycache__/effect_calculator.cpython-312.pyc +0 -0
- package/scripts/__pycache__/evidence_matrix.cpython-312.pyc +0 -0
- package/scripts/__pycache__/evidence_score.cpython-312.pyc +0 -0
- package/scripts/__pycache__/evidence_semantics.cpython-312.pyc +0 -0
- package/scripts/__pycache__/fetch_benchmark.cpython-312.pyc +0 -0
- package/scripts/__pycache__/lint_report_layout.cpython-312.pyc +0 -0
- package/scripts/__pycache__/orchestrator.cpython-312.pyc +0 -0
- package/scripts/__pycache__/pre_verdict_gate.cpython-312.pyc +0 -0
- package/scripts/__pycache__/recompute_demo_quality.cpython-312.pyc +0 -0
- package/scripts/__pycache__/render_report.cpython-312.pyc +0 -0
- package/scripts/__pycache__/render_report_html.cpython-312.pyc +0 -0
- package/scripts/__pycache__/run_workspace.cpython-312.pyc +0 -0
- package/scripts/__pycache__/skill_lint.cpython-312.pyc +0 -0
- package/scripts/__pycache__/startup_probe.cpython-312.pyc +0 -0
- package/scripts/__pycache__/sync_killer_demo_report.cpython-312.pyc +0 -0
- package/scripts/__pycache__/test_adversarial_empirical.cpython-312-pytest-9.0.2.pyc +0 -0
- package/scripts/__pycache__/test_adversarial_empirical.cpython-312-pytest-9.1.1.pyc +0 -0
- package/scripts/__pycache__/validate_schema.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/adapter_contract.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_artifact_manifest.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_charts.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_figures.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_infographics.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/build_report.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/charts_data.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/lieflat_engine.cpython-312.pyc +0 -0
- package/visualization/eduevidence-report/scripts/__pycache__/zh_labels.cpython-312.pyc +0 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Generate GitHub-safe vector diagrams from the canonical protocol registry."""
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import sys
|
|
4
|
+
from html import escape
|
|
5
|
+
|
|
6
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
7
|
+
sys.path.insert(0, str(ROOT))
|
|
8
|
+
from engine.workflows import SCIENTIFIC_STAGE_IDS # noqa: E402
|
|
9
|
+
|
|
10
|
+
OUT = ROOT / 'assets/readme'
|
|
11
|
+
OUT.mkdir(parents=True, exist_ok=True)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def start(title, subtitle, height):
|
|
15
|
+
return [f'''<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="{height}" viewBox="0 0 1200 {height}" role="img" aria-label="{escape(title)}">
|
|
16
|
+
<title>{escape(title)}</title><desc>{escape(subtitle)}</desc>
|
|
17
|
+
<defs><marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"><path d="M0 0L10 5L0 10" fill="none" stroke="#a15c40" stroke-width="1.5"/></marker></defs>
|
|
18
|
+
<rect width="1200" height="{height}" rx="24" fill="#f7f5f0"/>
|
|
19
|
+
<g font-family="-apple-system,BlinkMacSystemFont,Segoe UI,Arial,sans-serif">
|
|
20
|
+
<text x="48" y="43" font-size="12" letter-spacing="3" fill="#9b5e45">EDUEVIDENCE / RESEARCH STUDIO</text>
|
|
21
|
+
<text x="48" y="92" font-size="32" font-weight="600" fill="#272924">{escape(title)}</text>
|
|
22
|
+
<text x="48" y="126" font-size="16" fill="#6f7068">{escape(subtitle)}</text>''']
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def card(parts, x, y, w, num, title, detail, accent=False):
|
|
26
|
+
fill = '#eee2d8' if accent else '#ffffff'
|
|
27
|
+
parts.append(f'<rect x="{x}" y="{y}" width="{w}" height="96" rx="14" fill="{fill}" stroke="#dcd8ce"/>')
|
|
28
|
+
parts.append(f'<text x="{x+20}" y="{y+28}" font-size="12" fill="#a15c40">{escape(num)}</text>')
|
|
29
|
+
parts.append(f'<text x="{x+20}" y="{y+54}" font-size="21" font-weight="600" fill="#30332e">{escape(title)}</text>')
|
|
30
|
+
parts.append(f'<text x="{x+20}" y="{y+78}" font-size="13" fill="#6f7068">{escape(detail)}</text>')
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def line(parts, d):
|
|
34
|
+
parts.append(f'<path d="{d}" fill="none" stroke="#a15c40" stroke-width="1.7" marker-end="url(#arrow)"/>')
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
labels = {
|
|
38
|
+
'frame': ('Frame / 定义问题', 'Question, population, comparison, outcomes'),
|
|
39
|
+
'retrieve': ('Retrieve / 检索来源', 'Primary sources and retrieval provenance'),
|
|
40
|
+
'extract': ('Extract / 提取证据', 'Study findings, measures and uncertainty'),
|
|
41
|
+
'challenge': ('Challenge / 反证质疑', 'Counter-evidence and alternative explanations'),
|
|
42
|
+
'audit': ('Audit / 方法审计', 'Study quality, bias and evidence limitations'),
|
|
43
|
+
'adjudicate': ('Adjudicate / 证据裁决', 'Supported claims and bounded decisions'),
|
|
44
|
+
'applicability': ('Applicability / 适用边界', 'For whom, where and under which conditions'),
|
|
45
|
+
'intervene': ('Intervene / 设计试点', 'A grounded knowledge gap before a new design'),
|
|
46
|
+
'evaluate': ('Evaluate / 评估更新', 'Validate new data and revise the decision'),
|
|
47
|
+
}
|
|
48
|
+
p=start('From evidence to a decision you can inspect', 'Nine scientific stages · 三条公开工作流 · Education + organizational policy', 704)
|
|
49
|
+
for i, stage in enumerate(SCIENTIFIC_STAGE_IDS):
|
|
50
|
+
row,col=divmod(i,3)
|
|
51
|
+
if row==1: col=2-col
|
|
52
|
+
x,y=48+col*376,166+row*128
|
|
53
|
+
card(p,x,y,352,f'{i+1:02d}',*labels[stage],stage=='adjudicate')
|
|
54
|
+
if i in (0,1,6,7): line(p,f'M{x+352} {y+48} H{x+370}')
|
|
55
|
+
if i in (3,4): line(p,f'M{x} {y+48} H{x-18}')
|
|
56
|
+
if i in (2,5): line(p,f'M{x+176} {y+96} V{y+121}')
|
|
57
|
+
p.append('<rect x="48" y="568" width="1104" height="88" rx="14" fill="#e9eee7"/>')
|
|
58
|
+
p.append('<text x="70" y="600" font-size="18" font-weight="600" fill="#456450">Projection / 展示制品</text>')
|
|
59
|
+
p.append('<text x="70" y="627" font-size="15" fill="#456450">Read-only Studio · Five report themes · Bilingual HTML · A report is not proof of an executed study.</text>')
|
|
60
|
+
p.append('<text x="48" y="682" font-size="12" fill="#6f7068">Evidence Review 01–07 / Decision & Pilot 01–08 / Evaluate & Update 09</text></g></svg>')
|
|
61
|
+
(OUT/'research-workflow.svg').write_text('\n'.join(p))
|
|
62
|
+
p=start('One research record. Controlled contributions.', 'Roles describe scientific responsibilities. Workers contribute only when the host supports delegation.',600)
|
|
63
|
+
card(p,48,178,290,'01 / LEAD','Plan the work','Bounded tasks and input snapshots')
|
|
64
|
+
card(p,442,178,310,'02 / EXECUTION','Native or delegated','Same scientific protocol and validation gates')
|
|
65
|
+
card(p,854,178,298,'03 / STAGING','Review contributions','Evidence, critique and audit artifacts')
|
|
66
|
+
line(p,'M338 226 H432'); line(p,'M752 226 H844');line(p,'M1004 274 V330 H599 V358')
|
|
67
|
+
card(p,442,368,310,'04 / VALIDATED COMMIT','Single writer','Lead commits a new immutable graph revision',True)
|
|
68
|
+
line(p,'M762 416 H844');card(p,854,368,298,'05 / PROJECTION','Read and trace','Studio, reports and revision history')
|
|
69
|
+
p.append('<text x="48" y="520" font-size="17" fill="#456450">Append evidence. Preserve provenance. Derive the decision from validated facts.</text>')
|
|
70
|
+
p.append('<text x="48" y="550" font-size="14" fill="#6f7068">Native execution needs no worker service. Cross-backend empirical performance is a separate verification task.</text></g></svg>')
|
|
71
|
+
(OUT/'controlled-execution.svg').write_text('\n'.join(p))
|
|
72
|
+
print('Generated research-workflow.svg and controlled-execution.svg from current protocol.')
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Bake all five report identities from the same validated bilingual inputs.
|
|
3
|
+
|
|
4
|
+
This is a build step, never a read endpoint. No evidence or decision is changed.
|
|
5
|
+
Failures are explicit and never replaced with a synthetic success document.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
import argparse
|
|
9
|
+
import hashlib
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
import subprocess
|
|
13
|
+
import sys
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
17
|
+
THEMES = ('claude', 'academic', 'datalab', 'datalab-dark', 'presentation')
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def bake(examples: Path, *, force: bool = False) -> list[dict]:
|
|
21
|
+
renderer_dir = ROOT / 'visualization' / 'eduevidence-report'
|
|
22
|
+
renderer = renderer_dir / 'scripts' / 'build_report.py'
|
|
23
|
+
digest = hashlib.sha256()
|
|
24
|
+
for path in sorted(renderer_dir.rglob('*')):
|
|
25
|
+
if path.suffix in {'.py', '.css', '.js', '.json'} and '__pycache__' not in path.parts:
|
|
26
|
+
digest.update(path.relative_to(renderer_dir).as_posix().encode())
|
|
27
|
+
digest.update(path.read_bytes())
|
|
28
|
+
engine_hash = digest.hexdigest()
|
|
29
|
+
reports = []
|
|
30
|
+
for directory in sorted(examples.iterdir()):
|
|
31
|
+
if not directory.is_dir() or directory.is_symlink():
|
|
32
|
+
continue
|
|
33
|
+
source, parallel = directory / 'result.json', directory / 'result.zh.json'
|
|
34
|
+
if not source.exists() or not parallel.exists():
|
|
35
|
+
continue
|
|
36
|
+
result_hash = hashlib.sha256(source.read_bytes()).hexdigest()
|
|
37
|
+
cache_key = hashlib.sha256((engine_hash + result_hash + hashlib.sha256(parallel.read_bytes()).hexdigest()).encode()).hexdigest()
|
|
38
|
+
out_dir = directory / 'reports-5themes'
|
|
39
|
+
manifest = out_dir / 'reader-manifest.json'
|
|
40
|
+
if not force and manifest.is_file():
|
|
41
|
+
try:
|
|
42
|
+
prior = json.loads(manifest.read_text(encoding='utf-8'))
|
|
43
|
+
main = prior.get('main_report') or {}
|
|
44
|
+
main_ok = bool(main.get('file')) and (directory / main['file']).is_file() and hashlib.sha256((directory / main['file']).read_bytes()).hexdigest() == main.get('sha256')
|
|
45
|
+
valid = prior.get('cache_key') == cache_key and main_ok and all(
|
|
46
|
+
(out_dir / record['file']).is_file() and hashlib.sha256((out_dir / record['file']).read_bytes()).hexdigest() == record['sha256']
|
|
47
|
+
for record in prior.get('reports', [])) and len(prior.get('reports', [])) == len(THEMES)
|
|
48
|
+
if valid:
|
|
49
|
+
reports.append(prior)
|
|
50
|
+
continue
|
|
51
|
+
except (ValueError, KeyError, OSError):
|
|
52
|
+
pass
|
|
53
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
54
|
+
records = []
|
|
55
|
+
for theme in THEMES:
|
|
56
|
+
target = out_dir / f'EduEvidence_Report_{theme}.html'
|
|
57
|
+
# Build to temporary files, promote only after scientific gates pass.
|
|
58
|
+
temporary = out_dir / f'.{theme}.pending.html'
|
|
59
|
+
spec = out_dir / f'report_spec_{theme}.json'
|
|
60
|
+
completed = subprocess.run([sys.executable, str(renderer), '--result', str(source),
|
|
61
|
+
'--result-zh', str(parallel), '--theme', theme,
|
|
62
|
+
'--out', str(temporary), '--spec-out', str(spec)],
|
|
63
|
+
cwd=ROOT, capture_output=True, text=True, timeout=120)
|
|
64
|
+
if completed.returncode:
|
|
65
|
+
temporary.unlink(missing_ok=True)
|
|
66
|
+
raise RuntimeError(f'{directory.name}/{theme}: renderer rejected input\n{completed.stdout}\n{completed.stderr}')
|
|
67
|
+
os.replace(temporary, target)
|
|
68
|
+
records.append({'theme': theme, 'file': target.name, 'sha256': hashlib.sha256(target.read_bytes()).hexdigest()})
|
|
69
|
+
# Also refresh the pack-root report. This used to write only the themed
|
|
70
|
+
# variants, so examples/*/EduEvidence_Report.html kept whatever bytes it
|
|
71
|
+
# was first rendered with - the packaged example shipped a report the
|
|
72
|
+
# current renderer would not produce.
|
|
73
|
+
from_default = next((r for r in records if r['theme'] == 'claude'), records[0])
|
|
74
|
+
main_target = directory / 'EduEvidence_Report.html'
|
|
75
|
+
main_temp = directory / '.EduEvidence_Report.pending.html'
|
|
76
|
+
main_temp.write_bytes((out_dir / from_default['file']).read_bytes())
|
|
77
|
+
os.replace(main_temp, main_target)
|
|
78
|
+
main_sha = hashlib.sha256(main_target.read_bytes()).hexdigest()
|
|
79
|
+
|
|
80
|
+
value = {'schema_version': 1, 'project': directory.name, 'cache_key': cache_key,
|
|
81
|
+
'result_sha256': result_hash, 'renderer_sha256': engine_hash,
|
|
82
|
+
'main_report': {'file': main_target.name, 'sha256': main_sha,
|
|
83
|
+
'theme': from_default['theme']},
|
|
84
|
+
'reports': records}
|
|
85
|
+
manifest.write_text(json.dumps(value, indent=2) + '\n', encoding='utf-8')
|
|
86
|
+
reports.append(value)
|
|
87
|
+
print(f'{directory.name}: {len(records)} verified report variants')
|
|
88
|
+
return reports
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def main() -> int:
|
|
92
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
93
|
+
parser.add_argument('--examples', type=Path, default=ROOT / 'examples')
|
|
94
|
+
parser.add_argument('--force', action='store_true')
|
|
95
|
+
args = parser.parse_args()
|
|
96
|
+
bake(args.examples, force=args.force)
|
|
97
|
+
return 0
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == '__main__':
|
|
101
|
+
raise SystemExit(main())
|
package/scripts/build_result.py
CHANGED
|
@@ -30,14 +30,14 @@ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
|
30
30
|
from evidence_semantics import effect_direction
|
|
31
31
|
from engine.versions import ENGINE_VERSION
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
def _outcome_order() -> list[str]:
|
|
34
|
+
"""Registered outcome tokens in registry order (was a hard-coded list)."""
|
|
35
|
+
from engine.taxonomy import all_tokens_ordered
|
|
36
|
+
|
|
37
|
+
return list(all_tokens_ordered())
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
OUTCOME_ORDER = _outcome_order()
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
def _load_json(path: Path) -> dict[str, Any] | None:
|
|
@@ -221,12 +221,74 @@ def build_claims(evidence: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
|
221
221
|
return list(claims.values())
|
|
222
222
|
|
|
223
223
|
|
|
224
|
+
def _applicability(pack_dir: Path, verdict: dict) -> dict:
|
|
225
|
+
"""Stage-7 applicability assessment, falling back to the verdict boundary.
|
|
226
|
+
|
|
227
|
+
applicability.json is the dedicated deliverable of the Applicability stage.
|
|
228
|
+
It used to be written and then ignored, because the renderer only looked at
|
|
229
|
+
the verdict; this is where it re-enters the result.
|
|
230
|
+
"""
|
|
231
|
+
import json as _json
|
|
232
|
+
|
|
233
|
+
path = pack_dir / "applicability.json"
|
|
234
|
+
if path.is_file():
|
|
235
|
+
try:
|
|
236
|
+
data = _json.loads(path.read_text(encoding="utf-8"))
|
|
237
|
+
except (OSError, _json.JSONDecodeError):
|
|
238
|
+
data = None
|
|
239
|
+
if isinstance(data, dict) and data and data.get("status") != "NOT_CAPTURED":
|
|
240
|
+
return data
|
|
241
|
+
value = verdict.get("applicability") if isinstance(verdict, dict) else None
|
|
242
|
+
return value if isinstance(value, dict) else {}
|
|
243
|
+
|
|
244
|
+
def _derive_study_audits(methodology: list[dict], evidence: list[dict]) -> list[dict]:
|
|
245
|
+
"""Per-study audit rows derived from the audits and evidence present.
|
|
246
|
+
|
|
247
|
+
Each row names the study and reports the audit verdict that covers it,
|
|
248
|
+
so the per-study axis the schema advertises actually exists downstream.
|
|
249
|
+
Rows are only emitted for studies the audits or evidence actually name.
|
|
250
|
+
"""
|
|
251
|
+
by_study: dict[str, dict] = {}
|
|
252
|
+
for audit in methodology:
|
|
253
|
+
if not isinstance(audit, dict):
|
|
254
|
+
continue
|
|
255
|
+
target = audit.get("target") or "overall"
|
|
256
|
+
if target == "overall":
|
|
257
|
+
# The aggregate audit is not a study row; label it as the
|
|
258
|
+
# body-of-evidence review so it cannot be mistaken for one.
|
|
259
|
+
target = "body_of_evidence"
|
|
260
|
+
entry = by_study.setdefault(target, {
|
|
261
|
+
"study_id": target,
|
|
262
|
+
"verdict": audit.get("verdict"),
|
|
263
|
+
"audit_items": audit.get("audit_items") or {},
|
|
264
|
+
"limitations": list(audit.get("limitations") or []),
|
|
265
|
+
"task_vs_learning_guard": audit.get("task_vs_learning_guard"),
|
|
266
|
+
})
|
|
267
|
+
entry.setdefault("evidence_ids", [])
|
|
268
|
+
known = {e.get("study_id") for e in evidence if e.get("study_id")}
|
|
269
|
+
for study_id in sorted(known):
|
|
270
|
+
by_study.setdefault(study_id, {
|
|
271
|
+
"study_id": study_id,
|
|
272
|
+
"verdict": None,
|
|
273
|
+
"audit_items": {},
|
|
274
|
+
"limitations": [],
|
|
275
|
+
"task_vs_learning_guard": None,
|
|
276
|
+
"evidence_ids": [e.get("evidence_id") for e in evidence
|
|
277
|
+
if e.get("study_id") == study_id],
|
|
278
|
+
})
|
|
279
|
+
return list(by_study.values())
|
|
280
|
+
|
|
281
|
+
|
|
224
282
|
def build_result(pack_dir: Path, *, mode: str = "platform_native") -> dict[str, Any]:
|
|
225
283
|
frame = _load_json(pack_dir / "frame.json") or {}
|
|
226
284
|
evidence = _load_jsonl(pack_dir / "evidence.jsonl")
|
|
227
285
|
# methodology.json is a single MethodologyAudit object (or a JSONL list)
|
|
228
286
|
methodology_single = _load_json(pack_dir / "methodology.json")
|
|
229
287
|
methodology = [methodology_single] if methodology_single else _load_jsonl(pack_dir / "methodology.jsonl")
|
|
288
|
+
# Per-study audits: the contract advertised them but nothing produced
|
|
289
|
+
# them, so a multi-study review silently shipped a single audit object.
|
|
290
|
+
# Derive the per-study axis from the audits actually present.
|
|
291
|
+
study_audits = _derive_study_audits(methodology, evidence)
|
|
230
292
|
verdict = _load_json(pack_dir / "verdict.json") or {}
|
|
231
293
|
intervention = _load_json(pack_dir / "intervention.json") or {}
|
|
232
294
|
evaluation = _load_json(pack_dir / "evaluation.json") or {}
|
|
@@ -268,9 +330,12 @@ def build_result(pack_dir: Path, *, mode: str = "platform_native") -> dict[str,
|
|
|
268
330
|
"sources": sources,
|
|
269
331
|
"evidence": evidence,
|
|
270
332
|
"methodology_reviews": methodology,
|
|
333
|
+
"study_audits": study_audits,
|
|
271
334
|
"conflicts": [{"reason_for_disagreement": verdict.get("reason_for_disagreement", "")}]
|
|
272
335
|
if verdict.get("reason_for_disagreement") else [],
|
|
273
|
-
|
|
336
|
+
# Prefer the dedicated stage-7 assessment; fall back to the verdict-embedded
|
|
337
|
+
# boundary when the run carries no separate applicability.json.
|
|
338
|
+
"applicability": _applicability(pack_dir, verdict),
|
|
274
339
|
"intervention": intervention,
|
|
275
340
|
"evaluation": evaluation,
|
|
276
341
|
"benchmark": {},
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def fail(message: str) -> None:
|
|
12
|
+
print(f"ERROR: {message}", file=sys.stderr)
|
|
13
|
+
raise SystemExit(1)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def main() -> int:
|
|
17
|
+
invariants = ROOT / "references" / "scientific-invariants.md"
|
|
18
|
+
if not invariants.is_file():
|
|
19
|
+
fail("missing scientific invariants")
|
|
20
|
+
text = invariants.read_text(encoding="utf-8").lower()
|
|
21
|
+
for phrase in (
|
|
22
|
+
"optimize the research process, never the conclusion.",
|
|
23
|
+
"single writer",
|
|
24
|
+
"append-only",
|
|
25
|
+
):
|
|
26
|
+
if phrase not in text:
|
|
27
|
+
fail(f"missing invariant: {phrase}")
|
|
28
|
+
|
|
29
|
+
registry = ROOT / "skill" / "roles" / "registry.yaml"
|
|
30
|
+
if not registry.is_file():
|
|
31
|
+
fail("missing role registry")
|
|
32
|
+
registry_text = registry.read_text(encoding="utf-8")
|
|
33
|
+
for role in ("evidence-retriever", "skeptic", "method-reviewer", "evidence-judge"):
|
|
34
|
+
if role not in registry_text:
|
|
35
|
+
fail(f"role missing: {role}")
|
|
36
|
+
|
|
37
|
+
from engine.orchestration import CanonicalWriteGuard, ExecutionPlanner
|
|
38
|
+
for level, cap in (("S", 0), ("M", 3), ("L", 6)):
|
|
39
|
+
plan = ExecutionPlanner().plan(level)
|
|
40
|
+
if level == "S" and plan.delegated_tasks:
|
|
41
|
+
fail("S must delegate zero tasks")
|
|
42
|
+
if len(plan.delegated_tasks) > cap:
|
|
43
|
+
fail(f"{level} delegated worker plan exceeds policy cap")
|
|
44
|
+
if max((len(group) for group in plan.parallel_groups), default=0) > plan.max_parallel_workers:
|
|
45
|
+
fail(f"{level} execution group exceeds max_parallel_workers")
|
|
46
|
+
try:
|
|
47
|
+
CanonicalWriteGuard().require("worker", "GraphRevision")
|
|
48
|
+
fail("single writer guard did not block worker")
|
|
49
|
+
except PermissionError:
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
schema_dir = ROOT / "schemas" / "vNext"
|
|
53
|
+
required = {
|
|
54
|
+
"research-iteration.schema.json",
|
|
55
|
+
"research-strategy.schema.json",
|
|
56
|
+
"negative-search-record.schema.json",
|
|
57
|
+
"gap-priority.schema.json",
|
|
58
|
+
"task-spec.schema.json",
|
|
59
|
+
"worker-result.schema.json",
|
|
60
|
+
"execution-plan.schema.json",
|
|
61
|
+
"skill-experiment.schema.json",
|
|
62
|
+
"eval-snapshot.schema.json",
|
|
63
|
+
"autoevolve-session.schema.json",
|
|
64
|
+
}
|
|
65
|
+
missing = [name for name in required if not (schema_dir / name).is_file()]
|
|
66
|
+
if missing:
|
|
67
|
+
fail("missing schemas: " + ",".join(sorted(missing)))
|
|
68
|
+
for name in required:
|
|
69
|
+
json.loads((schema_dir / name).read_text(encoding="utf-8"))
|
|
70
|
+
|
|
71
|
+
head = os.getenv("GITHUB_HEAD_REF", "") or os.getenv("GITHUB_REF_NAME", "")
|
|
72
|
+
if head.startswith("autoresearch/"):
|
|
73
|
+
base = os.getenv("GITHUB_BASE_REF", "main")
|
|
74
|
+
subprocess.run(
|
|
75
|
+
["git", "fetch", "origin", base, "--depth=1"],
|
|
76
|
+
cwd=ROOT,
|
|
77
|
+
check=True,
|
|
78
|
+
stdout=subprocess.DEVNULL,
|
|
79
|
+
)
|
|
80
|
+
changed = subprocess.check_output(
|
|
81
|
+
["git", "diff", "--name-only", f"origin/{base}...HEAD"],
|
|
82
|
+
cwd=ROOT,
|
|
83
|
+
text=True,
|
|
84
|
+
).splitlines()
|
|
85
|
+
from engine.autoevolve import ProtectedManifest
|
|
86
|
+
ok, bad = ProtectedManifest.from_repo(ROOT).validate_changes(changed)
|
|
87
|
+
if not ok:
|
|
88
|
+
fail("protected mutation on autoresearch branch: " + ",".join(bad))
|
|
89
|
+
|
|
90
|
+
print("autoresearch invariants OK")
|
|
91
|
+
return 0
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""check_package_parity.py - prove the shipped package matches the source tree.
|
|
3
|
+
|
|
4
|
+
The upload package is a projection of this repository. If a source file changed
|
|
5
|
+
and the package still carries the old bytes, reviewers receive a different
|
|
6
|
+
product from the one under source control. CI previously compared only
|
|
7
|
+
SKILL.md, so a renamed role file went unnoticed for a whole change set.
|
|
8
|
+
|
|
9
|
+
Compares every file the shared payload allowlist ships: content must match and
|
|
10
|
+
nothing may be missing. Stdlib only; exit 1 on any drift.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import hashlib
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
19
|
+
sys.path.insert(0, str(ROOT))
|
|
20
|
+
sys.path.insert(0, str(ROOT / "scripts"))
|
|
21
|
+
|
|
22
|
+
PACKAGE = ROOT / "dist" / "eduevidence-submission"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def digest(path: Path) -> str:
|
|
26
|
+
return hashlib.sha256(path.read_bytes()).hexdigest()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def main() -> int:
|
|
30
|
+
if not PACKAGE.is_dir():
|
|
31
|
+
print(f"ERROR: no package at {PACKAGE}; run bash packaging/make_upload.sh")
|
|
32
|
+
return 1
|
|
33
|
+
|
|
34
|
+
from skill_payload import payload_files
|
|
35
|
+
|
|
36
|
+
expected = set(payload_files(ROOT))
|
|
37
|
+
# The manifest and the packaging notes are written by the build, not copied.
|
|
38
|
+
generated = {"submission-manifest.json", "UPLOAD-README.md", "START-HERE.md",
|
|
39
|
+
"scp-manifest.json", "upload-layout.md", "README.zh-CN.md"}
|
|
40
|
+
expected |= {name for name in generated if (PACKAGE / name).is_file()}
|
|
41
|
+
|
|
42
|
+
missing = sorted(rel for rel in expected if not (PACKAGE / rel).is_file())
|
|
43
|
+
|
|
44
|
+
# Reverse direction: a file the package carries but the source does not is
|
|
45
|
+
# stale output from an earlier build. A one-way check cannot see that,
|
|
46
|
+
# which is how pre-rename report copies once survived inside a package.
|
|
47
|
+
unexpected = []
|
|
48
|
+
for path in sorted(PACKAGE.rglob("*")):
|
|
49
|
+
if not path.is_file():
|
|
50
|
+
continue
|
|
51
|
+
rel = path.relative_to(PACKAGE).as_posix()
|
|
52
|
+
if rel in expected or rel == "submission-manifest.json":
|
|
53
|
+
continue
|
|
54
|
+
if any(part in {"__pycache__", ".git"} for part in path.parts):
|
|
55
|
+
continue
|
|
56
|
+
if path.suffix in {".pyc", ".pyo"} or path.name == ".DS_Store":
|
|
57
|
+
continue
|
|
58
|
+
if not (ROOT / rel).exists():
|
|
59
|
+
unexpected.append(rel)
|
|
60
|
+
differing = []
|
|
61
|
+
for rel in sorted(expected):
|
|
62
|
+
source = ROOT / rel
|
|
63
|
+
shipped = PACKAGE / rel
|
|
64
|
+
if not source.is_file() or not shipped.is_file():
|
|
65
|
+
continue
|
|
66
|
+
if digest(source) != digest(shipped):
|
|
67
|
+
differing.append(rel)
|
|
68
|
+
|
|
69
|
+
if missing or differing or unexpected:
|
|
70
|
+
print("ERROR: package does not match the source tree", file=sys.stderr)
|
|
71
|
+
for rel in missing[:20]:
|
|
72
|
+
print(f" missing from package: {rel}", file=sys.stderr)
|
|
73
|
+
for rel in differing[:20]:
|
|
74
|
+
print(f" differs from source: {rel}", file=sys.stderr)
|
|
75
|
+
for rel in unexpected[:20]:
|
|
76
|
+
print(f" stale in package: {rel}", file=sys.stderr)
|
|
77
|
+
print(" fix: bash packaging/make_upload.sh", file=sys.stderr)
|
|
78
|
+
return 1
|
|
79
|
+
|
|
80
|
+
print(f"package parity OK ({len(expected)} files byte-identical to source)")
|
|
81
|
+
return 0
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
if __name__ == "__main__":
|
|
85
|
+
sys.exit(main())
|