psyclaw 0.27.23 → 0.28.1
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/README.md +11 -5
- package/agents/recommended/catalog.json +99 -0
- package/dist/apps/panel/index.html +5 -5
- package/dist/src/adapters/pi/extension.js +339 -94
- package/dist/src/adapters/pi/extension.js.map +1 -1
- package/dist/src/adapters/pi/rpc.d.ts +2 -0
- package/dist/src/adapters/pi/rpc.js +9 -2
- package/dist/src/adapters/pi/rpc.js.map +1 -1
- package/dist/src/agents/import.js +44 -32
- package/dist/src/agents/import.js.map +1 -1
- package/dist/src/agents/recommended-personas.d.ts +42 -0
- package/dist/src/agents/recommended-personas.js +135 -0
- package/dist/src/agents/recommended-personas.js.map +1 -0
- package/dist/src/analysis/hooks.d.ts +1 -0
- package/dist/src/analysis/hooks.js +20 -1
- package/dist/src/analysis/hooks.js.map +1 -1
- package/dist/src/ars/bridge.d.ts +20 -0
- package/dist/src/ars/bridge.js +132 -0
- package/dist/src/ars/bridge.js.map +1 -0
- package/dist/src/ars/contracts.d.ts +55 -0
- package/dist/src/ars/contracts.js +2 -0
- package/dist/src/ars/contracts.js.map +1 -0
- package/dist/src/ars/panel-plan.d.ts +4 -0
- package/dist/src/ars/panel-plan.js +11 -0
- package/dist/src/ars/panel-plan.js.map +1 -0
- package/dist/src/ars/pi-panel-executor.d.ts +30 -0
- package/dist/src/ars/pi-panel-executor.js +140 -0
- package/dist/src/ars/pi-panel-executor.js.map +1 -0
- package/dist/src/ars/profile.d.ts +36 -0
- package/dist/src/ars/profile.js +119 -0
- package/dist/src/ars/profile.js.map +1 -0
- package/dist/src/ars/re-review.d.ts +22 -0
- package/dist/src/ars/re-review.js +172 -0
- package/dist/src/ars/re-review.js.map +1 -0
- package/dist/src/branding.d.ts +2 -4
- package/dist/src/branding.js +3 -5
- package/dist/src/branding.js.map +1 -1
- package/dist/src/bundled-tools.d.ts +3 -0
- package/dist/src/bundled-tools.js +21 -0
- package/dist/src/bundled-tools.js.map +1 -0
- package/dist/src/chat.js +6 -5
- package/dist/src/chat.js.map +1 -1
- package/dist/src/cli.js +6 -3
- package/dist/src/cli.js.map +1 -1
- package/dist/src/creation/contracts.d.ts +41 -0
- package/dist/src/creation/contracts.js +2 -0
- package/dist/src/creation/contracts.js.map +1 -0
- package/dist/src/creation/service.d.ts +7 -0
- package/dist/src/creation/service.js +208 -0
- package/dist/src/creation/service.js.map +1 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/install/installer.js +32 -10
- package/dist/src/install/installer.js.map +1 -1
- package/dist/src/orchestration/bundled-personas.d.ts +16 -0
- package/dist/src/orchestration/bundled-personas.js +101 -0
- package/dist/src/orchestration/bundled-personas.js.map +1 -0
- package/dist/src/orchestration/effects.d.ts +8 -0
- package/dist/src/orchestration/effects.js +39 -0
- package/dist/src/orchestration/effects.js.map +1 -0
- package/dist/src/orchestration/personas.d.ts +16 -0
- package/dist/src/orchestration/personas.js +64 -0
- package/dist/src/orchestration/personas.js.map +1 -0
- package/dist/src/orchestration/pi-executor.d.ts +9 -4
- package/dist/src/orchestration/pi-executor.js +55 -22
- package/dist/src/orchestration/pi-executor.js.map +1 -1
- package/dist/src/orchestration/research-agents.d.ts +3 -7
- package/dist/src/orchestration/research-agents.js +5 -69
- package/dist/src/orchestration/research-agents.js.map +1 -1
- package/dist/src/panel/server.js +19 -4
- package/dist/src/panel/server.js.map +1 -1
- package/dist/src/project/paths.d.ts +3 -0
- package/dist/src/project/paths.js +7 -0
- package/dist/src/project/paths.js.map +1 -1
- package/dist/src/rules/user-rules.d.ts +8 -0
- package/dist/src/rules/user-rules.js +36 -0
- package/dist/src/rules/user-rules.js.map +1 -0
- package/dist/src/skills/contracts.d.ts +4 -4
- package/dist/src/skills/recommended.js +1 -1
- package/dist/src/skills/registry.js +49 -28
- package/dist/src/skills/registry.js.map +1 -1
- package/dist/src/style/cli-ui.d.ts +14 -0
- package/dist/src/style/cli-ui.js +45 -1
- package/dist/src/style/cli-ui.js.map +1 -1
- package/dist/src/tui/skill-manager.js +1 -1
- package/dist/src/tui/skill-manager.js.map +1 -1
- package/dist/src/updates/update.js +9 -3
- package/dist/src/updates/update.js.map +1 -1
- package/package.json +15 -3
- package/scripts/rebrand-pi.mjs +6 -0
- package/skills/recommended/catalog.json +2 -11
- package/vendor/ars/.claude/CLAUDE.md +371 -0
- package/vendor/ars/.command-invariants.toml +24 -0
- package/vendor/ars/CITATION.cff +35 -0
- package/vendor/ars/LICENSE +417 -0
- package/vendor/ars/MODE_REGISTRY.md +76 -0
- package/vendor/ars/NOTICE.md +26 -0
- package/vendor/ars/POSITIONING.md +99 -0
- package/vendor/ars/PSYCLAW_SOURCE.json +10 -0
- package/vendor/ars/README.md +751 -0
- package/vendor/ars/SECURITY.md +52 -0
- package/vendor/ars/THIRD_PARTY.md +70 -0
- package/vendor/ars/academic-paper/SKILL.md +542 -0
- package/vendor/ars/academic-paper/agents/abstract_bilingual_agent.md +171 -0
- package/vendor/ars/academic-paper/agents/argument_builder_agent.md +276 -0
- package/vendor/ars/academic-paper/agents/citation_compliance_agent.md +422 -0
- package/vendor/ars/academic-paper/agents/draft_writer_agent.md +656 -0
- package/vendor/ars/academic-paper/agents/formatter_agent.md +999 -0
- package/vendor/ars/academic-paper/agents/intake_agent.md +393 -0
- package/vendor/ars/academic-paper/agents/literature_strategist_agent.md +626 -0
- package/vendor/ars/academic-paper/agents/peer_reviewer_agent.md +516 -0
- package/vendor/ars/academic-paper/agents/revision_coach_agent.md +334 -0
- package/vendor/ars/academic-paper/agents/socratic_mentor_agent.md +527 -0
- package/vendor/ars/academic-paper/agents/structure_architect_agent.md +401 -0
- package/vendor/ars/academic-paper/agents/visualization_agent.md +441 -0
- package/vendor/ars/academic-paper/examples/chinese_paper_example.md +278 -0
- package/vendor/ars/academic-paper/examples/clinical_citation_verification_checklist.md +95 -0
- package/vendor/ars/academic-paper/examples/clinical_epistemic_status_example.md +100 -0
- package/vendor/ars/academic-paper/examples/commitment_ledger_example.md +147 -0
- package/vendor/ars/academic-paper/examples/imrad_hei_example.md +234 -0
- package/vendor/ars/academic-paper/examples/literature_review_example.md +260 -0
- package/vendor/ars/academic-paper/examples/plan_mode_guided_writing.md +600 -0
- package/vendor/ars/academic-paper/examples/revision_mode_example.md +344 -0
- package/vendor/ars/academic-paper/examples/revision_recovery_example.md +506 -0
- package/vendor/ars/academic-paper/examples/version_family_reconciliation_example.md +89 -0
- package/vendor/ars/academic-paper/references/abstract_writing_guide.md +169 -0
- package/vendor/ars/academic-paper/references/academic_writing_style.md +188 -0
- package/vendor/ars/academic-paper/references/anti_leakage_protocol.md +83 -0
- package/vendor/ars/academic-paper/references/apa7_chinese_citation_guide.md +364 -0
- package/vendor/ars/academic-paper/references/apa7_extended_guide.md +198 -0
- package/vendor/ars/academic-paper/references/changelog.md +11 -0
- package/vendor/ars/academic-paper/references/citation_format_switcher.md +228 -0
- package/vendor/ars/academic-paper/references/committee_correspondence_protocol.md +158 -0
- package/vendor/ars/academic-paper/references/credit_authorship_guide.md +308 -0
- package/vendor/ars/academic-paper/references/disclosure_mode_protocol.md +478 -0
- package/vendor/ars/academic-paper/references/domain_evidence_profiles.md +38 -0
- package/vendor/ars/academic-paper/references/failure_paths.md +349 -0
- package/vendor/ars/academic-paper/references/funding_statement_guide.md +319 -0
- package/vendor/ars/academic-paper/references/hei_domain_glossary.md +169 -0
- package/vendor/ars/academic-paper/references/intro_title_rhetoric_guide.md +114 -0
- package/vendor/ars/academic-paper/references/journal_submission_guide.md +249 -0
- package/vendor/ars/academic-paper/references/latex_template_reference.md +378 -0
- package/vendor/ars/academic-paper/references/mode_selection_guide.md +378 -0
- package/vendor/ars/academic-paper/references/paper_structure_patterns.md +330 -0
- package/vendor/ars/academic-paper/references/plan_mode_protocol.md +112 -0
- package/vendor/ars/academic-paper/references/policy_anchor_disclosure_protocol.md +200 -0
- package/vendor/ars/academic-paper/references/policy_anchor_table.md +157 -0
- package/vendor/ars/academic-paper/references/revision_patch_protocol.md +173 -0
- package/vendor/ars/academic-paper/references/statistical_visualization_standards.md +750 -0
- package/vendor/ars/academic-paper/references/venue_disclosure_policies.md +259 -0
- package/vendor/ars/academic-paper/references/vlm_figure_verification.md +126 -0
- package/vendor/ars/academic-paper/references/workflow_phase_details.md +135 -0
- package/vendor/ars/academic-paper/references/writing_judgment_framework.md +59 -0
- package/vendor/ars/academic-paper/references/writing_quality_check.md +173 -0
- package/vendor/ars/academic-paper/templates/bilingual_abstract_template.md +78 -0
- package/vendor/ars/academic-paper/templates/case_study_template.md +129 -0
- package/vendor/ars/academic-paper/templates/conference_paper_template.md +108 -0
- package/vendor/ars/academic-paper/templates/credit_statement_template.md +132 -0
- package/vendor/ars/academic-paper/templates/funding_statement_template.md +290 -0
- package/vendor/ars/academic-paper/templates/imrad_template.md +183 -0
- package/vendor/ars/academic-paper/templates/latex_article_template.tex +199 -0
- package/vendor/ars/academic-paper/templates/literature_review_template.md +135 -0
- package/vendor/ars/academic-paper/templates/policy_brief_template.md +139 -0
- package/vendor/ars/academic-paper/templates/revision_tracking_template.md +199 -0
- package/vendor/ars/academic-paper/templates/theoretical_paper_template.md +119 -0
- package/vendor/ars/academic-paper-reviewer/SKILL.md +491 -0
- package/vendor/ars/academic-paper-reviewer/agents/devils_advocate_reviewer_agent.md +443 -0
- package/vendor/ars/academic-paper-reviewer/agents/domain_reviewer_agent.md +412 -0
- package/vendor/ars/academic-paper-reviewer/agents/editorial_synthesizer_agent.md +478 -0
- package/vendor/ars/academic-paper-reviewer/agents/eic_agent.md +339 -0
- package/vendor/ars/academic-paper-reviewer/agents/field_analyst_agent.md +221 -0
- package/vendor/ars/academic-paper-reviewer/agents/methodology_reviewer_agent.md +449 -0
- package/vendor/ars/academic-paper-reviewer/agents/perspective_reviewer_agent.md +427 -0
- package/vendor/ars/academic-paper-reviewer/examples/hei_paper_review_example.md +391 -0
- package/vendor/ars/academic-paper-reviewer/examples/interdisciplinary_review_example.md +299 -0
- package/vendor/ars/academic-paper-reviewer/examples/subclaim_decomposition_example.md +80 -0
- package/vendor/ars/academic-paper-reviewer/references/calibration_mode_protocol.md +256 -0
- package/vendor/ars/academic-paper-reviewer/references/changelog.md +10 -0
- package/vendor/ars/academic-paper-reviewer/references/editorial_decision_standards.md +236 -0
- package/vendor/ars/academic-paper-reviewer/references/guided_mode_protocol.md +34 -0
- package/vendor/ars/academic-paper-reviewer/references/integration_guide.md +15 -0
- package/vendor/ars/academic-paper-reviewer/references/quality_rubrics.md +84 -0
- package/vendor/ars/academic-paper-reviewer/references/re_review_mode_protocol.md +340 -0
- package/vendor/ars/academic-paper-reviewer/references/review_criteria_framework.md +98 -0
- package/vendor/ars/academic-paper-reviewer/references/review_panel_provenance_protocol.md +197 -0
- package/vendor/ars/academic-paper-reviewer/references/review_quality_thinking.md +58 -0
- package/vendor/ars/academic-paper-reviewer/references/reviewer_sprint_prompt_source.md +324 -0
- package/vendor/ars/academic-paper-reviewer/references/sprint_contract_protocol.md +296 -0
- package/vendor/ars/academic-paper-reviewer/references/statistical_reporting_standards.md +505 -0
- package/vendor/ars/academic-paper-reviewer/references/top_journals_by_field.md +206 -0
- package/vendor/ars/academic-paper-reviewer/templates/editorial_decision_template.md +235 -0
- package/vendor/ars/academic-paper-reviewer/templates/peer_review_report_template.md +305 -0
- package/vendor/ars/academic-paper-reviewer/templates/revision_response_template.md +248 -0
- package/vendor/ars/academic-pipeline/SKILL.md +736 -0
- package/vendor/ars/academic-pipeline/agents/claim_ref_alignment_audit_agent.md +382 -0
- package/vendor/ars/academic-pipeline/agents/collaboration_depth_agent.md +164 -0
- package/vendor/ars/academic-pipeline/agents/integrity_verification_agent.md +870 -0
- package/vendor/ars/academic-pipeline/agents/pipeline_orchestrator_agent.md +1379 -0
- package/vendor/ars/academic-pipeline/agents/state_tracker_agent.md +622 -0
- package/vendor/ars/academic-pipeline/examples/full_pipeline_example.md +482 -0
- package/vendor/ars/academic-pipeline/examples/integrity_failure_recovery.md +389 -0
- package/vendor/ars/academic-pipeline/examples/mid_entry_example.md +414 -0
- package/vendor/ars/academic-pipeline/references/adapters/.gitkeep +0 -0
- package/vendor/ars/academic-pipeline/references/adapters/overview.md +153 -0
- package/vendor/ars/academic-pipeline/references/ai_research_failure_modes.md +185 -0
- package/vendor/ars/academic-pipeline/references/changelog.md +14 -0
- package/vendor/ars/academic-pipeline/references/claim_audit_calibration_protocol.md +175 -0
- package/vendor/ars/academic-pipeline/references/claim_verification_protocol.md +282 -0
- package/vendor/ars/academic-pipeline/references/external_review_protocol.md +131 -0
- package/vendor/ars/academic-pipeline/references/integrity_review_protocol.md +110 -0
- package/vendor/ars/academic-pipeline/references/literature_corpus_consumers.md +193 -0
- package/vendor/ars/academic-pipeline/references/mode_advisor.md +135 -0
- package/vendor/ars/academic-pipeline/references/passport_as_reset_boundary.md +132 -0
- package/vendor/ars/academic-pipeline/references/pipeline_state_machine.md +405 -0
- package/vendor/ars/academic-pipeline/references/plagiarism_detection_protocol.md +239 -0
- package/vendor/ars/academic-pipeline/references/process_summary_protocol.md +209 -0
- package/vendor/ars/academic-pipeline/references/progress_dashboard_template.md +38 -0
- package/vendor/ars/academic-pipeline/references/reinforcement_content.md +15 -0
- package/vendor/ars/academic-pipeline/references/reproducibility_audit.md +55 -0
- package/vendor/ars/academic-pipeline/references/score_trajectory_protocol.md +78 -0
- package/vendor/ars/academic-pipeline/references/team_collaboration_protocol.md +261 -0
- package/vendor/ars/academic-pipeline/references/two_stage_review_protocol.md +27 -0
- package/vendor/ars/academic-pipeline/templates/pipeline_status_template.md +146 -0
- package/vendor/ars/agents/report_compiler_agent.md +341 -0
- package/vendor/ars/agents/research_architect_agent.md +298 -0
- package/vendor/ars/agents/synthesis_agent.md +356 -0
- package/vendor/ars/commands/ars-3w.md +10 -0
- package/vendor/ars/commands/ars-abstract.md +10 -0
- package/vendor/ars/commands/ars-cache-invalidate.md +20 -0
- package/vendor/ars/commands/ars-citation-check.md +10 -0
- package/vendor/ars/commands/ars-disclosure.md +10 -0
- package/vendor/ars/commands/ars-format-convert.md +10 -0
- package/vendor/ars/commands/ars-full.md +9 -0
- package/vendor/ars/commands/ars-lit-review.md +12 -0
- package/vendor/ars/commands/ars-mark-read.md +18 -0
- package/vendor/ars/commands/ars-outline.md +10 -0
- package/vendor/ars/commands/ars-plan.md +10 -0
- package/vendor/ars/commands/ars-rebuttal-audit.md +12 -0
- package/vendor/ars/commands/ars-reviewer.md +9 -0
- package/vendor/ars/commands/ars-revision-coach.md +9 -0
- package/vendor/ars/commands/ars-revision.md +10 -0
- package/vendor/ars/commands/ars-unmark-read.md +16 -0
- package/vendor/ars/deep-research/SKILL.md +600 -0
- package/vendor/ars/deep-research/agents/bibliography_agent.md +473 -0
- package/vendor/ars/deep-research/agents/devils_advocate_agent.md +192 -0
- package/vendor/ars/deep-research/agents/editor_in_chief_agent.md +167 -0
- package/vendor/ars/deep-research/agents/ethics_review_agent.md +267 -0
- package/vendor/ars/deep-research/agents/meta_analysis_agent.md +325 -0
- package/vendor/ars/deep-research/agents/monitoring_agent.md +209 -0
- package/vendor/ars/deep-research/agents/report_compiler_agent.md +341 -0
- package/vendor/ars/deep-research/agents/research_architect_agent.md +298 -0
- package/vendor/ars/deep-research/agents/research_question_agent.md +216 -0
- package/vendor/ars/deep-research/agents/risk_of_bias_agent.md +231 -0
- package/vendor/ars/deep-research/agents/socratic_mentor_agent.md +764 -0
- package/vendor/ars/deep-research/agents/source_verification_agent.md +219 -0
- package/vendor/ars/deep-research/agents/synthesis_agent.md +356 -0
- package/vendor/ars/deep-research/agents/timeline_extraction_agent.md +99 -0
- package/vendor/ars/deep-research/examples/exploratory_research.md +157 -0
- package/vendor/ars/deep-research/examples/fact_check_mode.md +173 -0
- package/vendor/ars/deep-research/examples/handoff_to_paper.md +318 -0
- package/vendor/ars/deep-research/examples/idea_diversity_coverage_gap_advisory.md +64 -0
- package/vendor/ars/deep-research/examples/policy_analysis.md +161 -0
- package/vendor/ars/deep-research/examples/review_mode.md +253 -0
- package/vendor/ars/deep-research/examples/socratic_guided_research.md +331 -0
- package/vendor/ars/deep-research/examples/systematic_review.md +133 -0
- package/vendor/ars/deep-research/references/apa7_style_guide.md +162 -0
- package/vendor/ars/deep-research/references/argumentation_reasoning_framework.md +68 -0
- package/vendor/ars/deep-research/references/arxiv_api_protocol.md +76 -0
- package/vendor/ars/deep-research/references/changelog.md +22 -0
- package/vendor/ars/deep-research/references/chinese_literature_api_protocol.md +317 -0
- package/vendor/ars/deep-research/references/cross_agent_quality_definitions.md +14 -0
- package/vendor/ars/deep-research/references/crossref_api_protocol.md +84 -0
- package/vendor/ars/deep-research/references/equator_reporting_guidelines.md +482 -0
- package/vendor/ars/deep-research/references/ethics_checklist.md +282 -0
- package/vendor/ars/deep-research/references/failure_paths.md +355 -0
- package/vendor/ars/deep-research/references/interdisciplinary_bridges.md +292 -0
- package/vendor/ars/deep-research/references/irb_decision_tree.md +315 -0
- package/vendor/ars/deep-research/references/literature_monitoring_strategies.md +263 -0
- package/vendor/ars/deep-research/references/logical_fallacies.md +192 -0
- package/vendor/ars/deep-research/references/methodology_patterns.md +462 -0
- package/vendor/ars/deep-research/references/mode_selection_guide.md +331 -0
- package/vendor/ars/deep-research/references/openalex_api_protocol.md +82 -0
- package/vendor/ars/deep-research/references/preregistration_guide.md +324 -0
- package/vendor/ars/deep-research/references/semantic_scholar_api_protocol.md +107 -0
- package/vendor/ars/deep-research/references/socratic_mode_protocol.md +99 -0
- package/vendor/ars/deep-research/references/socratic_questioning_framework.md +232 -0
- package/vendor/ars/deep-research/references/source_quality_hierarchy.md +188 -0
- package/vendor/ars/deep-research/references/systematic_review_protocol.md +95 -0
- package/vendor/ars/deep-research/references/systematic_review_toolkit.md +353 -0
- package/vendor/ars/deep-research/templates/evidence_assessment_template.md +127 -0
- package/vendor/ars/deep-research/templates/literature_matrix_template.md +85 -0
- package/vendor/ars/deep-research/templates/preregistration_template.md +318 -0
- package/vendor/ars/deep-research/templates/prisma_protocol_template.md +248 -0
- package/vendor/ars/deep-research/templates/prisma_report_template.md +415 -0
- package/vendor/ars/deep-research/templates/research_brief_template.md +93 -0
- package/vendor/ars/package.json +24 -0
- package/vendor/ars/pi/README.md +161 -0
- package/vendor/ars/pi/package.json +26 -0
- package/vendor/ars/pi/wrapper.js +193 -0
- package/vendor/ars/pi/wrapper.test.mjs +201 -0
- package/vendor/ars/pyproject.toml +2 -0
- package/vendor/ars/requirements-pdf-content-classifier.txt +5 -0
- package/vendor/ars/scripts/_block_parser.py +396 -0
- package/vendor/ars/scripts/_ci_pytest_manifest.toml +661 -0
- package/vendor/ars/scripts/_claim_audit_constants.py +268 -0
- package/vendor/ars/scripts/_e4_evidence.py +110 -0
- package/vendor/ars/scripts/_eval_threshold_gate.py +73 -0
- package/vendor/ars/scripts/_markdown_lint_util.py +224 -0
- package/vendor/ars/scripts/_next_verified_at_ms.py +176 -0
- package/vendor/ars/scripts/_passport_yaml.py +53 -0
- package/vendor/ars/scripts/_skill_lint.py +254 -0
- package/vendor/ars/scripts/_text_similarity.py +141 -0
- package/vendor/ars/scripts/adapters/README.md +89 -0
- package/vendor/ars/scripts/adapters/_common.py +209 -0
- package/vendor/ars/scripts/adapters/examples/folder_scan/expected_passport.yaml +25 -0
- package/vendor/ars/scripts/adapters/examples/folder_scan/expected_rejection_log.yaml +18 -0
- package/vendor/ars/scripts/adapters/examples/folder_scan/input_fixture/Chen2024_AIAssessment.pdf +0 -0
- package/vendor/ars/scripts/adapters/examples/folder_scan/input_fixture/Wang_2023_formative_feedback.pdf +0 -0
- package/vendor/ars/scripts/adapters/examples/folder_scan/input_fixture/paper1.pdf +0 -0
- package/vendor/ars/scripts/adapters/examples/folder_scan/input_fixture//344/270/255/346/226/207/346/252/224/345/220/215_2024.pdf +0 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/expected_passport.yaml +40 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/expected_rejection_log.yaml +13 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/.gitkeep +0 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/.obsidian/app.json +1 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/_templates/tmpl.md +7 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/chen2024ai.md +13 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/invalid.md +1 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/wang2023formative.md +10 -0
- package/vendor/ars/scripts/adapters/examples/zotero/expected_passport.yaml +34 -0
- package/vendor/ars/scripts/adapters/examples/zotero/expected_rejection_log.yaml +34 -0
- package/vendor/ars/scripts/adapters/examples/zotero/input_fixture/.gitkeep +0 -0
- package/vendor/ars/scripts/adapters/examples/zotero/input_fixture/export.json +43 -0
- package/vendor/ars/scripts/adapters/folder_scan.py +214 -0
- package/vendor/ars/scripts/adapters/obsidian.py +336 -0
- package/vendor/ars/scripts/adapters/tests/.gitkeep +0 -0
- package/vendor/ars/scripts/adapters/tests/conftest.py +77 -0
- package/vendor/ars/scripts/adapters/tests/test_check_corpus_consumer_protocol.py +632 -0
- package/vendor/ars/scripts/adapters/tests/test_check_literature_corpus_schema.py +631 -0
- package/vendor/ars/scripts/adapters/tests/test_common.py +365 -0
- package/vendor/ars/scripts/adapters/tests/test_conftest.py +96 -0
- package/vendor/ars/scripts/adapters/tests/test_folder_scan.py +260 -0
- package/vendor/ars/scripts/adapters/tests/test_literature_corpus_entry_schema.py +745 -0
- package/vendor/ars/scripts/adapters/tests/test_obsidian.py +357 -0
- package/vendor/ars/scripts/adapters/tests/test_rejection_log_schema.py +271 -0
- package/vendor/ars/scripts/adapters/tests/test_sync_adapter_docs.py +88 -0
- package/vendor/ars/scripts/adapters/tests/test_zotero.py +454 -0
- package/vendor/ars/scripts/adapters/zotero.py +318 -0
- package/vendor/ars/scripts/adjudication_activity.py +1592 -0
- package/vendor/ars/scripts/announce-ars-loaded.sh +144 -0
- package/vendor/ars/scripts/ars_anchorize_draft.py +170 -0
- package/vendor/ars/scripts/ars_apply_revision_patch.py +912 -0
- package/vendor/ars/scripts/ars_cache_invalidate.py +40 -0
- package/vendor/ars/scripts/ars_mark_read.py +521 -0
- package/vendor/ars/scripts/ars_phase_scope_manifest.json +33 -0
- package/vendor/ars/scripts/ars_update_check.sh +215 -0
- package/vendor/ars/scripts/ars_write_scope_guard.py +506 -0
- package/vendor/ars/scripts/arxiv_client.py +222 -0
- package/vendor/ars/scripts/audit_snapshot.py +572 -0
- package/vendor/ars/scripts/bibliographic_integrity_signals.py +800 -0
- package/vendor/ars/scripts/bootstrap_timeline_yaml.py +146 -0
- package/vendor/ars/scripts/build_claim_standing_candidate_ledger.py +1238 -0
- package/vendor/ars/scripts/build_claim_standing_query_plan.py +643 -0
- package/vendor/ars/scripts/build_content_coverage_advisory.py +1205 -0
- package/vendor/ars/scripts/build_cross_document_consistency_advisory.py +2332 -0
- package/vendor/ars/scripts/build_review_pathway_rule_trace.py +830 -0
- package/vendor/ars/scripts/build_submission_packet_manifest.py +2310 -0
- package/vendor/ars/scripts/check_215_field_norm.py +173 -0
- package/vendor/ars/scripts/check_216_surface_form.py +250 -0
- package/vendor/ars/scripts/check_268_nested_commitment_ledger.py +180 -0
- package/vendor/ars/scripts/check_390_revision_patch_discipline.py +296 -0
- package/vendor/ars/scripts/check_392_citation_verification_intake.py +126 -0
- package/vendor/ars/scripts/check_394_submission_policy.py +178 -0
- package/vendor/ars/scripts/check_439_format_profile.py +307 -0
- package/vendor/ars/scripts/check_619_disclosure_closeout.py +237 -0
- package/vendor/ars/scripts/check_630_codex_subscription_transport.py +456 -0
- package/vendor/ars/scripts/check_669_review_pathway_rule_trace.py +662 -0
- package/vendor/ars/scripts/check_670_revision_roadmap_integration.py +518 -0
- package/vendor/ars/scripts/check_673_adjudication_activity.py +684 -0
- package/vendor/ars/scripts/check_684_review_criteria_binding.py +557 -0
- package/vendor/ars/scripts/check_agents_mirror_sync.py +115 -0
- package/vendor/ars/scripts/check_audit_artifact_consistency.py +2313 -0
- package/vendor/ars/scripts/check_benchmark_report.py +79 -0
- package/vendor/ars/scripts/check_bibliographic_integrity_signals.py +831 -0
- package/vendor/ars/scripts/check_calibration_tiers.py +235 -0
- package/vendor/ars/scripts/check_changelog_covers_merges.py +289 -0
- package/vendor/ars/scripts/check_ci_pytest_manifest.py +204 -0
- package/vendor/ars/scripts/check_claim_audit_consistency.py +1664 -0
- package/vendor/ars/scripts/check_claim_standing_candidate_ledger_integration.py +500 -0
- package/vendor/ars/scripts/check_claim_standing_freshness.py +253 -0
- package/vendor/ars/scripts/check_claim_standing_transmissions.py +449 -0
- package/vendor/ars/scripts/check_collaboration_depth_rubric.py +180 -0
- package/vendor/ars/scripts/check_command_frontmatter_name.py +116 -0
- package/vendor/ars/scripts/check_committee_correspondence.py +333 -0
- package/vendor/ars/scripts/check_compliance_report.py +108 -0
- package/vendor/ars/scripts/check_content_coverage_advisory_integration.py +796 -0
- package/vendor/ars/scripts/check_control_availability.py +172 -0
- package/vendor/ars/scripts/check_corpus_consumer_protocol.py +404 -0
- package/vendor/ars/scripts/check_cross_document_consistency_advisory_integration.py +1191 -0
- package/vendor/ars/scripts/check_cross_model_handoff_contract.py +234 -0
- package/vendor/ars/scripts/check_cross_model_verification_sync.py +261 -0
- package/vendor/ars/scripts/check_data_access_level.py +131 -0
- package/vendor/ars/scripts/check_data_flows.py +252 -0
- package/vendor/ars/scripts/check_decision_contract.py +464 -0
- package/vendor/ars/scripts/check_degradation_registry.py +326 -0
- package/vendor/ars/scripts/check_distribution_surface_claims.py +226 -0
- package/vendor/ars/scripts/check_domain_evidence_profile.py +538 -0
- package/vendor/ars/scripts/check_e4_promotion.py +195 -0
- package/vendor/ars/scripts/check_evals_gold_set.py +279 -0
- package/vendor/ars/scripts/check_evidence_row_integration.py +396 -0
- package/vendor/ars/scripts/check_experiment_provenance.py +117 -0
- package/vendor/ars/scripts/check_field_norm_severity.py +144 -0
- package/vendor/ars/scripts/check_firm_rules_sync.py +375 -0
- package/vendor/ars/scripts/check_heldout_measurement_report.py +1179 -0
- package/vendor/ars/scripts/check_human_subjects_output_contract.py +139 -0
- package/vendor/ars/scripts/check_human_subjects_reference_migration.py +844 -0
- package/vendor/ars/scripts/check_indirect_prompt_injection_no_call.py +328 -0
- package/vendor/ars/scripts/check_instruction_data_boundary.py +236 -0
- package/vendor/ars/scripts/check_judge_prompt_version.py +125 -0
- package/vendor/ars/scripts/check_literature_corpus_schema.py +402 -0
- package/vendor/ars/scripts/check_model_tiering.py +223 -0
- package/vendor/ars/scripts/check_panel_synthesis.py +1331 -0
- package/vendor/ars/scripts/check_passport_reset_contract.py +214 -0
- package/vendor/ars/scripts/check_pattern_eval_manifest.py +422 -0
- package/vendor/ars/scripts/check_persuasion_invariance_fixtures.py +637 -0
- package/vendor/ars/scripts/check_phase_conformance.py +2180 -0
- package/vendor/ars/scripts/check_pipeline_boundary_semantics.py +600 -0
- package/vendor/ars/scripts/check_pipeline_integrity.py +340 -0
- package/vendor/ars/scripts/check_policy_anchor_protocol.py +159 -0
- package/vendor/ars/scripts/check_policy_anchor_table.py +286 -0
- package/vendor/ars/scripts/check_preprint_venues_consistency.py +123 -0
- package/vendor/ars/scripts/check_prisma_trAIce_freshness.py +84 -0
- package/vendor/ars/scripts/check_promotion_bakeoff_preregistration.py +1303 -0
- package/vendor/ars/scripts/check_ranking_lift.py +323 -0
- package/vendor/ars/scripts/check_re_review_synthesis.py +2719 -0
- package/vendor/ars/scripts/check_receipt_enum_sync.py +203 -0
- package/vendor/ars/scripts/check_repro_lock.py +85 -0
- package/vendor/ars/scripts/check_review_pathway_output.py +276 -0
- package/vendor/ars/scripts/check_reviewer_data_fences.py +224 -0
- package/vendor/ars/scripts/check_reviewer_finding_contract.py +783 -0
- package/vendor/ars/scripts/check_reviewer_role_label.py +447 -0
- package/vendor/ars/scripts/check_reviewer_scoring_honesty.py +292 -0
- package/vendor/ars/scripts/check_reviewer_sprint_prompt_sync.py +409 -0
- package/vendor/ars/scripts/check_revision_claim_drift_suite_v2.py +1622 -0
- package/vendor/ars/scripts/check_revision_token_conservation.py +263 -0
- package/vendor/ars/scripts/check_risk_register.py +280 -0
- package/vendor/ars/scripts/check_role_scoped_contract.py +702 -0
- package/vendor/ars/scripts/check_rq_framing_patterns.py +184 -0
- package/vendor/ars/scripts/check_rubric_weight_consistency.py +32 -0
- package/vendor/ars/scripts/check_seeded_defect_fixtures.py +425 -0
- package/vendor/ars/scripts/check_setup_cross_model_parity.py +139 -0
- package/vendor/ars/scripts/check_spec_consistency.py +1249 -0
- package/vendor/ars/scripts/check_sprint_contract.py +371 -0
- package/vendor/ars/scripts/check_stage_capability_matrix.py +784 -0
- package/vendor/ars/scripts/check_submission_packet_manifest_integration.py +358 -0
- package/vendor/ars/scripts/check_surface_form_parity.py +445 -0
- package/vendor/ars/scripts/check_task_type.py +22 -0
- package/vendor/ars/scripts/check_tools_allowlist.py +538 -0
- package/vendor/ars/scripts/check_tortured_phrase_screening_integration.py +1974 -0
- package/vendor/ars/scripts/check_v3_10_134_write_scope.py +286 -0
- package/vendor/ars/scripts/check_v3_10_policy.py +656 -0
- package/vendor/ars/scripts/check_v3_6_6_ab_manifest.py +364 -0
- package/vendor/ars/scripts/check_v3_6_7_pattern_protection.py +1366 -0
- package/vendor/ars/scripts/check_v3_6_8_audit_scope_block.py +464 -0
- package/vendor/ars/scripts/check_v3_6_8_cite_provenance_pipeline.py +231 -0
- package/vendor/ars/scripts/check_v3_6_8_frontmatter_trust_schema.py +248 -0
- package/vendor/ars/scripts/check_v3_6_8_mark_read_commands.py +79 -0
- package/vendor/ars/scripts/check_v3_6_8_pattern_protection.py +941 -0
- package/vendor/ars/scripts/check_v3_7_3_three_layer_citation.py +318 -0
- package/vendor/ars/scripts/check_v3_8_annotation_literal_sync.py +228 -0
- package/vendor/ars/scripts/check_v3_9_0_triangulation.py +366 -0
- package/vendor/ars/scripts/check_v3_9_2_phase_boundary.py +270 -0
- package/vendor/ars/scripts/check_v3_9_4_temporal_verification.py +139 -0
- package/vendor/ars/scripts/check_venue_disclosure_policies.py +63 -0
- package/vendor/ars/scripts/check_version_consistency.py +826 -0
- package/vendor/ars/scripts/check_workflow_classification.py +223 -0
- package/vendor/ars/scripts/chinese_literature_client.py +1938 -0
- package/vendor/ars/scripts/citation_verification_summary.py +85 -0
- package/vendor/ars/scripts/claim_audit_calibration.py +517 -0
- package/vendor/ars/scripts/claim_audit_finalizer.py +456 -0
- package/vendor/ars/scripts/claim_audit_pipeline.py +1594 -0
- package/vendor/ars/scripts/claim_registry_coverage.py +493 -0
- package/vendor/ars/scripts/claim_standing_discovery.py +784 -0
- package/vendor/ars/scripts/claim_standing_stance_runner.py +758 -0
- package/vendor/ars/scripts/claim_standing_stance_scorer.py +239 -0
- package/vendor/ars/scripts/claim_strength_drift_disposition.py +666 -0
- package/vendor/ars/scripts/contamination_signals.py +689 -0
- package/vendor/ars/scripts/corpus_consumer_manifest.json +19 -0
- package/vendor/ars/scripts/cross_model_codex_transport.py +1374 -0
- package/vendor/ars/scripts/cross_model_codex_verify.sh +6 -0
- package/vendor/ars/scripts/cross_model_handoff.py +359 -0
- package/vendor/ars/scripts/cross_model_smoke_test.sh +183 -0
- package/vendor/ars/scripts/cross_model_smoke_test_codex.sh +35 -0
- package/vendor/ars/scripts/cross_model_verification/gemini_is_grounded.jq +45 -0
- package/vendor/ars/scripts/cross_model_verification/gemini_sources.jq +45 -0
- package/vendor/ars/scripts/cross_model_verification/normalize_compat_verdict.py +57 -0
- package/vendor/ars/scripts/cross_model_verification/openai_has_completed_web_search.jq +15 -0
- package/vendor/ars/scripts/cross_model_verification/openai_sources.jq +17 -0
- package/vendor/ars/scripts/cross_model_verification/openai_text.jq +11 -0
- package/vendor/ars/scripts/crossref_client.py +225 -0
- package/vendor/ars/scripts/dispatch_e4_panel.py +2731 -0
- package/vendor/ars/scripts/evidence_rows.py +2043 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/author_stage3.json +32 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/author_stage3_input.json +27 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/author_stage3_prime.json +32 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/author_stage3_prime_input.json +27 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/compliance_override.json +50 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/compliance_override_action.json +14 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/compliance_pass.json +44 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/explicit_user_request_log.json +26 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/mandatory_checkpoint_log.json +116 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/README.md +56 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a1_pass_with_p1/2026-04-30T15-22-04Z-d8f3.audit_artifact_entry.json +24 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a1_pass_with_p1/2026-04-30T15-22-04Z-d8f3.jsonl +4 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a1_pass_with_p1/2026-04-30T15-22-04Z-d8f3.meta.json +43 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a1_pass_with_p1/2026-04-30T15-22-04Z-d8f3.verdict.yaml +19 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a7_orphan_completion/2026-04-30T15-22-04Z-d8f3.jsonl +3 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/persisted_minor/2026-04-30T15-22-04Z-d8f3.audit_artifact_entry.json +26 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/persisted_minor/2026-04-30T15-22-04Z-d8f3.jsonl +4 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/persisted_minor/2026-04-30T15-22-04Z-d8f3.meta.json +43 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/persisted_minor/2026-04-30T15-22-04Z-d8f3.verdict.yaml +19 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/proposal_pass/2026-04-30T15-22-04Z-d8f3.audit_artifact_entry.json +24 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/proposal_pass/2026-04-30T15-22-04Z-d8f3.jsonl +4 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/proposal_pass/2026-04-30T15-22-04Z-d8f3.meta.json +43 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/proposal_pass/2026-04-30T15-22-04Z-d8f3.verdict.yaml +12 -0
- package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/retraction.json +46 -0
- package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/retraction_check_attestation.json +44 -0
- package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/tortured_phrase.json +44 -0
- package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/tortured_phrase_v1_2_abstract_missing.json +107 -0
- package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/tortured_phrase_v1_2_detected.json +124 -0
- package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/expected_outcomes.json +77 -0
- package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/manifest.yaml +37 -0
- package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/tuples/001-valid-doi-test.json +20 -0
- package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/tuples/002-valid-arxiv-test.json +19 -0
- package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/tuples/003-fabricated-test.json +20 -0
- package/vendor/ars/scripts/fixtures/claim_audit_calibration/gold_set.json +344 -0
- package/vendor/ars/scripts/fixtures/claim_standing_candidate_ledger/query_plan.json +108 -0
- package/vendor/ars/scripts/fixtures/claim_standing_candidate_ledger/retrieval_input.json +179 -0
- package/vendor/ars/scripts/fixtures/committee_correspondence/16fd83f6aec7/concern_tracker.json +129 -0
- package/vendor/ars/scripts/fixtures/committee_correspondence/16fd83f6aec7/response_skeleton.md +19 -0
- package/vendor/ars/scripts/fixtures/committee_correspondence/16fd83f6aec7/source_letter.txt +9 -0
- package/vendor/ars/scripts/fixtures/content_coverage_advisory/base_draft.json +48 -0
- package/vendor/ars/scripts/fixtures/content_coverage_advisory/base_inventory.json +38 -0
- package/vendor/ars/scripts/fixtures/content_coverage_advisory/packet/consent.txt +1 -0
- package/vendor/ars/scripts/fixtures/content_coverage_advisory/session_sources.json +3 -0
- package/vendor/ars/scripts/fixtures/cross_document_consistency/README.md +6 -0
- package/vendor/ars/scripts/fixtures/cross_document_consistency/accepted_draft.md +35 -0
- package/vendor/ars/scripts/fixtures/cross_document_consistency/cases.json +75 -0
- package/vendor/ars/scripts/fixtures/cross_document_consistency/preregistration.md +5 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/forbidden_event.jsonl +4 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/grounded_verified.jsonl +3 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/malformed.jsonl +3 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/missing_search.jsonl +2 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/multiple_finals.jsonl +4 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/not_found.jsonl +3 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/unbound_source.jsonl +3 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/wrong_search_shape.jsonl +3 -0
- package/vendor/ars/scripts/fixtures/evidence_rows/phase_e_inputs.json +114 -0
- package/vendor/ars/scripts/fixtures/evidence_rows/session_sources.json +5 -0
- package/vendor/ars/scripts/fixtures/human_subjects_authority/cross-border-us-tw-gdpr.json +71 -0
- package/vendor/ars/scripts/fixtures/human_subjects_authority/gdpr-member-state-unresolved.json +62 -0
- package/vendor/ars/scripts/fixtures/human_subjects_authority/missing-data-axis.json +45 -0
- package/vendor/ars/scripts/fixtures/human_subjects_authority/no-profile.json +33 -0
- package/vendor/ars/scripts/fixtures/human_subjects_authority/tw-gdpr-two-axis.json +74 -0
- package/vendor/ars/scripts/fixtures/human_subjects_authority/us-gdpr-two-axis.json +74 -0
- package/vendor/ars/scripts/fixtures/review_pathway_rule_trace/lint-near-misses.json +72 -0
- package/vendor/ars/scripts/fixtures/review_pathway_rule_trace/no-profile-request.json +18 -0
- package/vendor/ars/scripts/fixtures/review_pathway_rule_trace/tw-candidates-request.json +63 -0
- package/vendor/ars/scripts/fixtures/review_pathway_rule_trace/us-candidates-request.json +77 -0
- package/vendor/ars/scripts/fixtures/review_target_context/exact-declaration.json +24 -0
- package/vendor/ars/scripts/fixtures/review_target_context/field-general-declaration.json +24 -0
- package/vendor/ars/scripts/fixtures/review_target_context/msr-2027-technical-full-declaration.json +24 -0
- package/vendor/ars/scripts/fixtures/review_target_context/synthetic-registry.json +92 -0
- package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/README.md +21 -0
- package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/subject_context_attested_only.json +55 -0
- package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/subject_context_machine_supported.json +49 -0
- package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/subject_context_not_isolated.json +56 -0
- package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/subject_context_unknown.json +49 -0
- package/vendor/ars/scripts/fixtures/submission_package/clean/paper.md +16 -0
- package/vendor/ars/scripts/fixtures/submission_package/clean/references.bib +13 -0
- package/vendor/ars/scripts/fixtures/submission_package/fallback_authoryear/paper.md +11 -0
- package/vendor/ars/scripts/fixtures/submission_package/fallback_authoryear/references.bib +13 -0
- package/vendor/ars/scripts/fixtures/submission_package/fallback_latex/paper.tex +9 -0
- package/vendor/ars/scripts/fixtures/submission_package/fallback_latex/references.bib +13 -0
- package/vendor/ars/scripts/fixtures/submission_package/marker_no_join/paper.md +7 -0
- package/vendor/ars/scripts/fixtures/submission_package/orphan_intext/paper.md +8 -0
- package/vendor/ars/scripts/fixtures/submission_package/orphan_intext/references.bib +6 -0
- package/vendor/ars/scripts/fixtures/submission_package/passports/corpus_only.yaml +9 -0
- package/vendor/ars/scripts/fixtures/submission_package/passports/summary_join.yaml +16 -0
- package/vendor/ars/scripts/fixtures/submission_package/profiles/full.yaml +15 -0
- package/vendor/ars/scripts/fixtures/submission_package/profiles/tight.yaml +15 -0
- package/vendor/ars/scripts/fixtures/submission_package/summary_join/paper.md +7 -0
- package/vendor/ars/scripts/fixtures/submission_package/uncited_reference/paper.md +9 -0
- package/vendor/ars/scripts/fixtures/submission_package/uncited_reference/references.bib +13 -0
- package/vendor/ars/scripts/fixtures/submission_package/venue_clean/paper.md +26 -0
- package/vendor/ars/scripts/fixtures/submission_package/venue_clean/references.bib +13 -0
- package/vendor/ars/scripts/fixtures/submission_package/venue_violations/paper.md +20 -0
- package/vendor/ars/scripts/fixtures/submission_package/venue_violations/references.bib +13 -0
- package/vendor/ars/scripts/fixtures/submission_packet_manifest/base_inventory.json +101 -0
- package/vendor/ars/scripts/fixtures/submission_packet_manifest/packet/consent-materials.txt +3 -0
- package/vendor/ars/scripts/fixtures/submission_packet_manifest/packet/training-certificate.txt +2 -0
- package/vendor/ars/scripts/fixtures/submission_packet_manifest/packet/tw-consent-materials.txt +3 -0
- package/vendor/ars/scripts/fixtures/tortured_phrase_screening/corpus_input.yaml +30 -0
- package/vendor/ars/scripts/fixtures/tortured_phrase_screening/own_draft.md +36 -0
- package/vendor/ars/scripts/fixtures/tortured_phrase_screening/own_draft.tex +21 -0
- package/vendor/ars/scripts/fixtures/tortured_phrase_screening/seed_expectations.json +218 -0
- package/vendor/ars/scripts/fixtures/tortured_phrase_screening/snapshot.json +164 -0
- package/vendor/ars/scripts/fixtures/tortured_phrase_screening/snapshot_manifest.json +29 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/README.md +55 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/arxiv/empty_feed.xml +10 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/arxiv/error_5xx.html +7 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/arxiv/id_hit.xml +26 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/README.md +69 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/cnki_landing_page.html +13 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/error_5xx.html +2 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coordinate_ambiguous.json +16 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coordinate_hit.json +16 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coordinate_zero.json +14 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coverage_hit.json +15 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coverage_zero.json +13 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_hit.json +43 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_issn_mismatch.json +31 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_no_doi.json +31 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_unknown_ra.json +34 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_year_mismatch.json +31 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/handle_absent.json +4 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/handle_exists.json +16 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/handle_internal_error.json +4 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/istic_csl_hit.json +25 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/istic_csl_other_title.json +18 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/ra_cnki.json +6 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/ra_crossref.json +6 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/ra_istic.json +6 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/ra_unknown_prefix.json +6 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/crossref/doi_hit.json +24 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/crossref/error_5xx.html +7 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/crossref/title_search_miss.json +15 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/openalex/doi_hit.json +29 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/openalex/error_5xx.json +4 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/openalex/title_search_miss.json +11 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/semantic_scholar/doi_hit.json +14 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/semantic_scholar/error_5xx.json +3 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/semantic_scholar/title_search_miss.json +5 -0
- package/vendor/ars/scripts/human_read_attestation_resolver.py +467 -0
- package/vendor/ars/scripts/ideation_diversity_assignment_gate.py +430 -0
- package/vendor/ars/scripts/inquiry_branch_ledger.py +2540 -0
- package/vendor/ars/scripts/legacy/ars_apply_revision_patch_v1_0.py +715 -0
- package/vendor/ars/scripts/legacy/check_re_review_synthesis_v1_0.py +2215 -0
- package/vendor/ars/scripts/migrate_literature_corpus_to_v3_10.py +223 -0
- package/vendor/ars/scripts/migrate_literature_corpus_to_v3_7_3.py +277 -0
- package/vendor/ars/scripts/migrate_literature_corpus_to_v3_9_0.py +304 -0
- package/vendor/ars/scripts/model_tiering_manifest.json +46 -0
- package/vendor/ars/scripts/openalex_client.py +232 -0
- package/vendor/ars/scripts/parse_audit_verdict.py +802 -0
- package/vendor/ars/scripts/pdf_content_classifier_worker.py +176 -0
- package/vendor/ars/scripts/pdf_read_preflight.py +1455 -0
- package/vendor/ars/scripts/policy_anchor_disclosure_referee.py +354 -0
- package/vendor/ars/scripts/recompute_receipts.py +1414 -0
- package/vendor/ars/scripts/render_claim_standing_view.py +374 -0
- package/vendor/ars/scripts/render_eval_comment.py +130 -0
- package/vendor/ars/scripts/render_harness_retirement_issue.py +167 -0
- package/vendor/ars/scripts/repro_lock_validation.py +90 -0
- package/vendor/ars/scripts/research_workflow_profile.py +1079 -0
- package/vendor/ars/scripts/resolve_human_subjects_authority.py +1158 -0
- package/vendor/ars/scripts/resolve_review_target_context.py +683 -0
- package/vendor/ars/scripts/resume_e4_record.py +509 -0
- package/vendor/ars/scripts/retraction_status.py +484 -0
- package/vendor/ars/scripts/review_criteria_binding.py +889 -0
- package/vendor/ars/scripts/review_panel_provenance.py +744 -0
- package/vendor/ars/scripts/revision_roadmap.py +1967 -0
- package/vendor/ars/scripts/run_ci_pytest_manifest.py +116 -0
- package/vendor/ars/scripts/run_codex_audit.sh +1191 -0
- package/vendor/ars/scripts/run_evals.py +513 -0
- package/vendor/ars/scripts/run_ideation_diversity_no_call.py +3505 -0
- package/vendor/ars/scripts/run_indirect_prompt_injection_no_call.py +3330 -0
- package/vendor/ars/scripts/run_indirect_prompt_injection_probe.py +399 -0
- package/vendor/ars/scripts/run_review_criteria_constructive_value.py +1895 -0
- package/vendor/ars/scripts/run_role_topology_utility_dry_run.py +606 -0
- package/vendor/ars/scripts/score_review_criteria_constructive_value.py +617 -0
- package/vendor/ars/scripts/semantic_scholar_client.py +291 -0
- package/vendor/ars/scripts/slr_lineage.py +59 -0
- package/vendor/ars/scripts/sync_adapter_docs.py +118 -0
- package/vendor/ars/scripts/temporal_integrity_audit.py +840 -0
- package/vendor/ars/scripts/test_431_exact_or_bust.py +253 -0
- package/vendor/ars/scripts/test__eval_threshold_gate.py +125 -0
- package/vendor/ars/scripts/test__markdown_lint_util.py +129 -0
- package/vendor/ars/scripts/test__next_verified_at_ms.py +256 -0
- package/vendor/ars/scripts/test_adjacent_framing_probe_lint.py +171 -0
- package/vendor/ars/scripts/test_adjudication_activity.py +1515 -0
- package/vendor/ars/scripts/test_ars_anchorize_draft.py +178 -0
- package/vendor/ars/scripts/test_ars_apply_revision_patch.py +1335 -0
- package/vendor/ars/scripts/test_ars_cache_invalidate.py +51 -0
- package/vendor/ars/scripts/test_ars_mark_read.py +910 -0
- package/vendor/ars/scripts/test_ars_update_check.py +816 -0
- package/vendor/ars/scripts/test_ars_write_scope_guard.py +790 -0
- package/vendor/ars/scripts/test_arxiv_client.py +374 -0
- package/vendor/ars/scripts/test_audit_schemas.py +560 -0
- package/vendor/ars/scripts/test_audit_snapshot_render_section_0.py +105 -0
- package/vendor/ars/scripts/test_block_parser.py +259 -0
- package/vendor/ars/scripts/test_bootstrap_timeline_yaml.py +148 -0
- package/vendor/ars/scripts/test_build_claim_standing_candidate_ledger.py +1203 -0
- package/vendor/ars/scripts/test_build_claim_standing_query_plan.py +791 -0
- package/vendor/ars/scripts/test_build_submission_packet_manifest.py +2644 -0
- package/vendor/ars/scripts/test_check_215_field_norm.py +238 -0
- package/vendor/ars/scripts/test_check_216_surface_form.py +341 -0
- package/vendor/ars/scripts/test_check_268_nested_commitment_ledger.py +194 -0
- package/vendor/ars/scripts/test_check_390_revision_patch_discipline.py +279 -0
- package/vendor/ars/scripts/test_check_392_citation_verification_intake.py +144 -0
- package/vendor/ars/scripts/test_check_394_submission_policy.py +200 -0
- package/vendor/ars/scripts/test_check_439_format_profile.py +252 -0
- package/vendor/ars/scripts/test_check_619_disclosure_closeout.py +158 -0
- package/vendor/ars/scripts/test_check_630_codex_subscription_transport.py +245 -0
- package/vendor/ars/scripts/test_check_669_review_pathway_rule_trace.py +304 -0
- package/vendor/ars/scripts/test_check_670_revision_roadmap_integration.py +260 -0
- package/vendor/ars/scripts/test_check_673_adjudication_activity.py +367 -0
- package/vendor/ars/scripts/test_check_684_review_criteria_binding.py +274 -0
- package/vendor/ars/scripts/test_check_agents_mirror_sync.py +137 -0
- package/vendor/ars/scripts/test_check_audit_artifact_consistency.py +2133 -0
- package/vendor/ars/scripts/test_check_benchmark_report.py +117 -0
- package/vendor/ars/scripts/test_check_bibliographic_integrity_signals.py +609 -0
- package/vendor/ars/scripts/test_check_calibration_tiers.py +376 -0
- package/vendor/ars/scripts/test_check_changelog_covers_merges.py +509 -0
- package/vendor/ars/scripts/test_check_ci_pytest_manifest.py +425 -0
- package/vendor/ars/scripts/test_check_claim_standing_candidate_ledger_integration.py +256 -0
- package/vendor/ars/scripts/test_check_claim_standing_freshness.py +277 -0
- package/vendor/ars/scripts/test_check_collaboration_depth_rubric.py +239 -0
- package/vendor/ars/scripts/test_check_command_frontmatter_name.py +178 -0
- package/vendor/ars/scripts/test_check_committee_correspondence.py +298 -0
- package/vendor/ars/scripts/test_check_compliance_report.py +381 -0
- package/vendor/ars/scripts/test_check_content_coverage_advisory_integration.py +308 -0
- package/vendor/ars/scripts/test_check_control_availability.py +361 -0
- package/vendor/ars/scripts/test_check_cross_document_consistency_advisory_integration.py +698 -0
- package/vendor/ars/scripts/test_check_cross_model_handoff_contract.py +301 -0
- package/vendor/ars/scripts/test_check_cross_model_verification_sync.py +203 -0
- package/vendor/ars/scripts/test_check_data_access_level.py +227 -0
- package/vendor/ars/scripts/test_check_data_flows.py +382 -0
- package/vendor/ars/scripts/test_check_decision_contract.py +387 -0
- package/vendor/ars/scripts/test_check_degradation_registry.py +270 -0
- package/vendor/ars/scripts/test_check_distribution_surface_claims.py +225 -0
- package/vendor/ars/scripts/test_check_domain_evidence_profile.py +439 -0
- package/vendor/ars/scripts/test_check_e4_promotion.py +163 -0
- package/vendor/ars/scripts/test_check_evals_gold_set.py +312 -0
- package/vendor/ars/scripts/test_check_evidence_row_integration.py +187 -0
- package/vendor/ars/scripts/test_check_field_norm_severity.py +173 -0
- package/vendor/ars/scripts/test_check_firm_rules_sync.py +342 -0
- package/vendor/ars/scripts/test_check_heldout_measurement_report.py +1508 -0
- package/vendor/ars/scripts/test_check_human_subjects_output_contract.py +129 -0
- package/vendor/ars/scripts/test_check_human_subjects_reference_migration.py +756 -0
- package/vendor/ars/scripts/test_check_instruction_data_boundary.py +204 -0
- package/vendor/ars/scripts/test_check_judge_prompt_version.py +90 -0
- package/vendor/ars/scripts/test_check_model_tiering.py +236 -0
- package/vendor/ars/scripts/test_check_panel_synthesis.py +1658 -0
- package/vendor/ars/scripts/test_check_passport_reset_contract.py +249 -0
- package/vendor/ars/scripts/test_check_pattern_eval_manifest.py +381 -0
- package/vendor/ars/scripts/test_check_persuasion_invariance_fixtures.py +591 -0
- package/vendor/ars/scripts/test_check_phase_conformance.py +4366 -0
- package/vendor/ars/scripts/test_check_pipeline_boundary_semantics.py +931 -0
- package/vendor/ars/scripts/test_check_pipeline_integrity.py +243 -0
- package/vendor/ars/scripts/test_check_policy_anchor_protocol.py +236 -0
- package/vendor/ars/scripts/test_check_policy_anchor_table.py +295 -0
- package/vendor/ars/scripts/test_check_prisma_trAIce_freshness.py +68 -0
- package/vendor/ars/scripts/test_check_promotion_bakeoff_preregistration.py +799 -0
- package/vendor/ars/scripts/test_check_ranking_lift.py +377 -0
- package/vendor/ars/scripts/test_check_re_review_synthesis.py +3398 -0
- package/vendor/ars/scripts/test_check_receipt_enum_sync.py +176 -0
- package/vendor/ars/scripts/test_check_repro_lock.py +107 -0
- package/vendor/ars/scripts/test_check_reviewer_data_fences.py +334 -0
- package/vendor/ars/scripts/test_check_reviewer_finding_contract.py +1107 -0
- package/vendor/ars/scripts/test_check_reviewer_role_label.py +491 -0
- package/vendor/ars/scripts/test_check_reviewer_scoring_honesty.py +222 -0
- package/vendor/ars/scripts/test_check_reviewer_sprint_prompt_sync.py +373 -0
- package/vendor/ars/scripts/test_check_revision_claim_drift_suite_v2.py +1925 -0
- package/vendor/ars/scripts/test_check_revision_token_conservation.py +398 -0
- package/vendor/ars/scripts/test_check_risk_register.py +336 -0
- package/vendor/ars/scripts/test_check_role_scoped_contract.py +1104 -0
- package/vendor/ars/scripts/test_check_rq_framing_patterns.py +110 -0
- package/vendor/ars/scripts/test_check_rubric_weight_consistency.py +32 -0
- package/vendor/ars/scripts/test_check_seeded_defect_fixtures.py +392 -0
- package/vendor/ars/scripts/test_check_setup_cross_model_parity.py +121 -0
- package/vendor/ars/scripts/test_check_spec_consistency.py +1081 -0
- package/vendor/ars/scripts/test_check_sprint_contract.py +458 -0
- package/vendor/ars/scripts/test_check_stage_capability_matrix.py +698 -0
- package/vendor/ars/scripts/test_check_submission_packet_manifest_integration.py +177 -0
- package/vendor/ars/scripts/test_check_surface_form_parity.py +417 -0
- package/vendor/ars/scripts/test_check_task_type.py +116 -0
- package/vendor/ars/scripts/test_check_tools_allowlist.py +835 -0
- package/vendor/ars/scripts/test_check_tortured_phrase_screening_integration.py +1306 -0
- package/vendor/ars/scripts/test_check_v3_10_134_write_scope.py +251 -0
- package/vendor/ars/scripts/test_check_v3_10_policy.py +547 -0
- package/vendor/ars/scripts/test_check_v3_6_7_pattern_protection.py +960 -0
- package/vendor/ars/scripts/test_check_v3_6_8_audit_scope_block.py +1000 -0
- package/vendor/ars/scripts/test_check_v3_6_8_cite_provenance_pipeline.py +454 -0
- package/vendor/ars/scripts/test_check_v3_6_8_frontmatter_trust_schema.py +581 -0
- package/vendor/ars/scripts/test_check_v3_6_8_mark_read_commands.py +120 -0
- package/vendor/ars/scripts/test_check_v3_6_8_pattern_protection.py +1138 -0
- package/vendor/ars/scripts/test_check_v3_7_3_three_layer_citation.py +566 -0
- package/vendor/ars/scripts/test_check_v3_8_annotation_literal_sync.py +262 -0
- package/vendor/ars/scripts/test_check_v3_9_0_triangulation.py +321 -0
- package/vendor/ars/scripts/test_check_v3_9_2_phase_boundary.py +190 -0
- package/vendor/ars/scripts/test_check_v3_9_4_temporal_verification.py +471 -0
- package/vendor/ars/scripts/test_check_version_consistency.py +1462 -0
- package/vendor/ars/scripts/test_check_workflow_classification.py +225 -0
- package/vendor/ars/scripts/test_chinese_literature_client.py +1889 -0
- package/vendor/ars/scripts/test_citation_existence_policy.py +480 -0
- package/vendor/ars/scripts/test_citation_verification_summary.py +342 -0
- package/vendor/ars/scripts/test_claim_audit_calibration.py +882 -0
- package/vendor/ars/scripts/test_claim_audit_finalizer.py +979 -0
- package/vendor/ars/scripts/test_claim_audit_pipeline.py +2398 -0
- package/vendor/ars/scripts/test_claim_audit_schema.py +1778 -0
- package/vendor/ars/scripts/test_claim_intent_manifest.py +666 -0
- package/vendor/ars/scripts/test_claim_registry_coverage.py +246 -0
- package/vendor/ars/scripts/test_claim_standing_discovery.py +579 -0
- package/vendor/ars/scripts/test_claim_standing_pipeline_wiring.py +290 -0
- package/vendor/ars/scripts/test_claim_standing_stance_assets.py +399 -0
- package/vendor/ars/scripts/test_claim_standing_stance_contracts.py +383 -0
- package/vendor/ars/scripts/test_claim_standing_stance_runner.py +349 -0
- package/vendor/ars/scripts/test_claim_standing_transmissions.py +605 -0
- package/vendor/ars/scripts/test_claim_strength_drift_disposition.py +517 -0
- package/vendor/ars/scripts/test_claim_verification_coverage_contract.py +104 -0
- package/vendor/ars/scripts/test_contamination_signals.py +1086 -0
- package/vendor/ars/scripts/test_content_coverage_advisory.py +1767 -0
- package/vendor/ars/scripts/test_cross_document_consistency_advisory.py +1270 -0
- package/vendor/ars/scripts/test_cross_model_codex_transport.py +1152 -0
- package/vendor/ars/scripts/test_cross_model_handoff.py +571 -0
- package/vendor/ars/scripts/test_cross_model_verification_guards.py +792 -0
- package/vendor/ars/scripts/test_crossref_client.py +393 -0
- package/vendor/ars/scripts/test_dispatch_e4_panel.py +4235 -0
- package/vendor/ars/scripts/test_e2e_claim_audit.py +540 -0
- package/vendor/ars/scripts/test_eval_harness_workflow.py +140 -0
- package/vendor/ars/scripts/test_evals_citation_extraction.py +150 -0
- package/vendor/ars/scripts/test_evals_lift_report_schema.py +108 -0
- package/vendor/ars/scripts/test_evidence_rows.py +2593 -0
- package/vendor/ars/scripts/test_experiment_provenance.py +915 -0
- package/vendor/ars/scripts/test_human_read_attestation_resolver.py +477 -0
- package/vendor/ars/scripts/test_ideation_diversity_assignment_gate.py +615 -0
- package/vendor/ars/scripts/test_indirect_prompt_injection_behavior_probe.py +250 -0
- package/vendor/ars/scripts/test_inquiry_branch_ledger.py +2296 -0
- package/vendor/ars/scripts/test_migrate_literature_corpus_to_v3_10.py +248 -0
- package/vendor/ars/scripts/test_migrate_literature_corpus_to_v3_7_3.py +545 -0
- package/vendor/ars/scripts/test_migrate_literature_corpus_to_v3_9_0.py +497 -0
- package/vendor/ars/scripts/test_normalize_compat_verdict.py +149 -0
- package/vendor/ars/scripts/test_openalex_client.py +490 -0
- package/vendor/ars/scripts/test_passport_yaml.py +104 -0
- package/vendor/ars/scripts/test_pattern_eval_runtime.py +1295 -0
- package/vendor/ars/scripts/test_pdf_read_preflight.py +1943 -0
- package/vendor/ars/scripts/test_policy_anchor_disclosure.py +666 -0
- package/vendor/ars/scripts/test_reading_probe_lint.py +218 -0
- package/vendor/ars/scripts/test_recompute_receipts.py +778 -0
- package/vendor/ars/scripts/test_render_claim_standing_view.py +192 -0
- package/vendor/ars/scripts/test_render_eval_comment.py +162 -0
- package/vendor/ars/scripts/test_render_harness_retirement_issue.py +110 -0
- package/vendor/ars/scripts/test_repro_lock_validation_drift.py +100 -0
- package/vendor/ars/scripts/test_research_workflow_profile.py +734 -0
- package/vendor/ars/scripts/test_resolve_human_subjects_authority.py +1219 -0
- package/vendor/ars/scripts/test_resolve_review_target_context.py +703 -0
- package/vendor/ars/scripts/test_resume_e4_record.py +315 -0
- package/vendor/ars/scripts/test_retraction_status.py +456 -0
- package/vendor/ars/scripts/test_review_criteria_binding.py +629 -0
- package/vendor/ars/scripts/test_review_panel_provenance.py +565 -0
- package/vendor/ars/scripts/test_review_pathway_rule_trace.py +821 -0
- package/vendor/ars/scripts/test_revision_roadmap.py +1255 -0
- package/vendor/ars/scripts/test_run_ci_pytest_manifest.py +186 -0
- package/vendor/ars/scripts/test_run_codex_audit_e2e.py +369 -0
- package/vendor/ars/scripts/test_run_evals.py +430 -0
- package/vendor/ars/scripts/test_run_guard_launcher.py +500 -0
- package/vendor/ars/scripts/test_run_ideation_diversity_no_call.py +1833 -0
- package/vendor/ars/scripts/test_run_indirect_prompt_injection_no_call.py +1889 -0
- package/vendor/ars/scripts/test_run_review_criteria_constructive_value.py +586 -0
- package/vendor/ars/scripts/test_run_role_topology_utility_dry_run.py +428 -0
- package/vendor/ars/scripts/test_score_review_criteria_constructive_value.py +340 -0
- package/vendor/ars/scripts/test_semantic_scholar_client.py +554 -0
- package/vendor/ars/scripts/test_slr_lineage_emission.py +230 -0
- package/vendor/ars/scripts/test_socratic_rq_non_generation_contract.py +173 -0
- package/vendor/ars/scripts/test_temporal_integrity_audit.py +438 -0
- package/vendor/ars/scripts/test_text_similarity.py +95 -0
- package/vendor/ars/scripts/test_title_fuzzy_false_positive.py +111 -0
- package/vendor/ars/scripts/test_tortured_phrase_screening.py +2959 -0
- package/vendor/ars/scripts/test_transport_fixture_citation_gate.py +338 -0
- package/vendor/ars/scripts/test_uncited_assertion.py +558 -0
- package/vendor/ars/scripts/test_v3_6_7_phase_6_6.py +1279 -0
- package/vendor/ars/scripts/test_validate_compliance_fixtures.py +36 -0
- package/vendor/ars/scripts/test_validate_ideation_diversity_assets.py +230 -0
- package/vendor/ars/scripts/test_venue_disclosure_contract.py +755 -0
- package/vendor/ars/scripts/test_verification_cache.py +280 -0
- package/vendor/ars/scripts/test_verification_gate.py +461 -0
- package/vendor/ars/scripts/test_verify_passport_cli.py +123 -0
- package/vendor/ars/scripts/test_verify_submission_package.py +1407 -0
- package/vendor/ars/scripts/test_version_records_schema.py +211 -0
- package/vendor/ars/scripts/tortured_phrase_screening.py +3502 -0
- package/vendor/ars/scripts/uncited_assertion_detector.py +254 -0
- package/vendor/ars/scripts/v3_6_7_inversion_manifest.json +9 -0
- package/vendor/ars/scripts/v3_6_8_inversion_manifest.json +10 -0
- package/vendor/ars/scripts/validate_claim_standing_stance_assets.py +249 -0
- package/vendor/ars/scripts/validate_compliance_fixtures.py +56 -0
- package/vendor/ars/scripts/validate_ideation_diversity_assets.py +303 -0
- package/vendor/ars/scripts/venue_disclosure_contract_harness.py +837 -0
- package/vendor/ars/scripts/verification_cache.py +276 -0
- package/vendor/ars/scripts/verification_gate/__init__.py +345 -0
- package/vendor/ars/scripts/verify_passport.py +133 -0
- package/vendor/ars/scripts/verify_submission_package.py +1657 -0
- package/vendor/ars/shared/agents/compliance_agent.md +136 -0
- package/vendor/ars/shared/artifact_reproducibility_pattern.md +173 -0
- package/vendor/ars/shared/benchmark_report.schema.json +81 -0
- package/vendor/ars/shared/benchmark_report_pattern.md +180 -0
- package/vendor/ars/shared/bibliographic_integrity_signals.md +142 -0
- package/vendor/ars/shared/collaboration_depth_rubric.md +154 -0
- package/vendor/ars/shared/compliance_checkpoint_protocol.md +162 -0
- package/vendor/ars/shared/compliance_report.schema.json +187 -0
- package/vendor/ars/shared/contracts/README.md +938 -0
- package/vendor/ars/shared/contracts/activity/adjudication_activity_input.schema.json +555 -0
- package/vendor/ars/shared/contracts/activity/adjudication_activity_store.schema.json +560 -0
- package/vendor/ars/shared/contracts/audit/audit_jsonl.schema.json +128 -0
- package/vendor/ars/shared/contracts/audit/audit_sidecar.schema.json +169 -0
- package/vendor/ars/shared/contracts/audit/audit_verdict.schema.json +133 -0
- package/vendor/ars/shared/contracts/audit/cross_document_consistency_advisory.schema.json +480 -0
- package/vendor/ars/shared/contracts/audit/cross_document_consistency_advisory_draft.schema.json +564 -0
- package/vendor/ars/shared/contracts/audit/cross_document_source_manifest.schema.json +202 -0
- package/vendor/ars/shared/contracts/audit/tortured_phrase_advisory.schema.json +1362 -0
- package/vendor/ars/shared/contracts/audit/tortured_phrase_snapshot.schema.json +208 -0
- package/vendor/ars/shared/contracts/audit/tortured_phrase_snapshot_manifest.schema.json +335 -0
- package/vendor/ars/shared/contracts/capability/stage_capability_matrix.json +434 -0
- package/vendor/ars/shared/contracts/claim_standing/candidate_ledger.schema.json +705 -0
- package/vendor/ars/shared/contracts/claim_standing/query_plan.schema.json +389 -0
- package/vendor/ars/shared/contracts/claim_standing/query_plan_v1_1.schema.json +782 -0
- package/vendor/ars/shared/contracts/claim_standing/retrieval_input.schema.json +440 -0
- package/vendor/ars/shared/contracts/claim_standing/stance_record.schema.json +460 -0
- package/vendor/ars/shared/contracts/claim_standing/transmission_ledger.schema.json +282 -0
- package/vendor/ars/shared/contracts/cross_model/codex_citation_receipt.schema.json +157 -0
- package/vendor/ars/shared/contracts/cross_model/codex_citation_request.schema.json +23 -0
- package/vendor/ars/shared/contracts/cross_model/promotion_bakeoff_sealed_commitment.schema.json +55 -0
- package/vendor/ars/shared/contracts/cross_model/promotion_bakeoff_sealed_reveal.schema.json +50 -0
- package/vendor/ars/shared/contracts/degradation_registry.json +428 -0
- package/vendor/ars/shared/contracts/evaluator/full.json +126 -0
- package/vendor/ars/shared/contracts/evidence/claim_registry.schema.json +50 -0
- package/vendor/ars/shared/contracts/evidence/claim_registry_coverage_report.schema.json +79 -0
- package/vendor/ars/shared/contracts/evidence/evidence_row.schema.json +504 -0
- package/vendor/ars/shared/contracts/evidence/evidence_row_v1_1.schema.json +364 -0
- package/vendor/ars/shared/contracts/evidence/evidence_row_v1_2.schema.json +714 -0
- package/vendor/ars/shared/contracts/evidence/evidence_row_v1_3.schema.json +524 -0
- package/vendor/ars/shared/contracts/human_subjects/authority_profile_registry.schema.json +497 -0
- package/vendor/ars/shared/contracts/human_subjects/committee_correspondence.schema.json +253 -0
- package/vendor/ars/shared/contracts/human_subjects/content_coverage_advisory.schema.json +620 -0
- package/vendor/ars/shared/contracts/human_subjects/irb_context_record.schema.json +329 -0
- package/vendor/ars/shared/contracts/human_subjects/resolved_authority_context.schema.json +347 -0
- package/vendor/ars/shared/contracts/human_subjects/review_pathway_rule_trace.schema.json +265 -0
- package/vendor/ars/shared/contracts/human_subjects/review_pathway_trace_request.schema.json +127 -0
- package/vendor/ars/shared/contracts/human_subjects/submission_packet_inventory.schema.json +240 -0
- package/vendor/ars/shared/contracts/human_subjects/submission_packet_manifest.schema.json +999 -0
- package/vendor/ars/shared/contracts/passport/audit_artifact_entry.schema.json +266 -0
- package/vendor/ars/shared/contracts/passport/bibliographic_integrity_signal.schema.json +1676 -0
- package/vendor/ars/shared/contracts/passport/citation_provenance.schema.json +107 -0
- package/vendor/ars/shared/contracts/passport/citation_verification_summary.schema.json +164 -0
- package/vendor/ars/shared/contracts/passport/claim_audit_result.schema.json +124 -0
- package/vendor/ars/shared/contracts/passport/claim_drift.schema.json +58 -0
- package/vendor/ars/shared/contracts/passport/claim_intent_manifest.schema.json +107 -0
- package/vendor/ars/shared/contracts/passport/constraint_violation.schema.json +65 -0
- package/vendor/ars/shared/contracts/passport/experiment_alignment_result.schema.json +69 -0
- package/vendor/ars/shared/contracts/passport/experiment_provenance_entry.schema.json +169 -0
- package/vendor/ars/shared/contracts/passport/human_read_log.schema.json +86 -0
- package/vendor/ars/shared/contracts/passport/inquiry_ledger_ref.schema.json +22 -0
- package/vendor/ars/shared/contracts/passport/literature_corpus_entry.schema.json +650 -0
- package/vendor/ars/shared/contracts/passport/preregistration_artifact.schema.json +132 -0
- package/vendor/ars/shared/contracts/passport/rejection_log.schema.json +89 -0
- package/vendor/ars/shared/contracts/passport/reset_ledger_entry.schema.json +158 -0
- package/vendor/ars/shared/contracts/passport/temporal_audit_results.schema.json +208 -0
- package/vendor/ars/shared/contracts/passport/terminal_policies.schema.json +50 -0
- package/vendor/ars/shared/contracts/passport/timeline.schema.json +102 -0
- package/vendor/ars/shared/contracts/passport/uncited_assertion.schema.json +56 -0
- package/vendor/ars/shared/contracts/passport/uncited_audit_failure.schema.json +72 -0
- package/vendor/ars/shared/contracts/passport/user_attested_read_resolution.schema.json +87 -0
- package/vendor/ars/shared/contracts/passport/version_records.schema.json +138 -0
- package/vendor/ars/shared/contracts/patch/block_manifest.schema.json +45 -0
- package/vendor/ars/shared/contracts/patch/legacy/v1_0/revision_patch.schema.json +110 -0
- package/vendor/ars/shared/contracts/patch/revision_patch.schema.json +250 -0
- package/vendor/ars/shared/contracts/pdf/pdf_content_classifier_diagnostic.schema.json +39 -0
- package/vendor/ars/shared/contracts/pdf/pdf_content_classifier_worker.schema.json +88 -0
- package/vendor/ars/shared/contracts/pdf/pdf_read_preflight.schema.json +227 -0
- package/vendor/ars/shared/contracts/re_review/input_manifest.schema.json +161 -0
- package/vendor/ars/shared/contracts/re_review/legacy/v1_0/input_manifest.schema.json +134 -0
- package/vendor/ars/shared/contracts/re_review/legacy/v1_0/precommitment.schema.json +193 -0
- package/vendor/ars/shared/contracts/re_review/legacy/v1_0/traceability.schema.json +841 -0
- package/vendor/ars/shared/contracts/re_review/legacy/v1_0/verdict_record.schema.json +244 -0
- package/vendor/ars/shared/contracts/re_review/precommitment.schema.json +193 -0
- package/vendor/ars/shared/contracts/re_review/traceability.schema.json +916 -0
- package/vendor/ars/shared/contracts/re_review/verdict_record.schema.json +245 -0
- package/vendor/ars/shared/contracts/research_workflow/inquiry_branch_ledger.schema.json +449 -0
- package/vendor/ars/shared/contracts/research_workflow/research_workflow_profile.schema.json +222 -0
- package/vendor/ars/shared/contracts/research_workflow/research_workflow_profile_selection_receipt.schema.json +111 -0
- package/vendor/ars/shared/contracts/review_target/constructive_review_findings.schema.json +172 -0
- package/vendor/ars/shared/contracts/review_target/criteria_registry.schema.json +97 -0
- package/vendor/ars/shared/contracts/review_target/review_criteria_binding_manifest.schema.json +235 -0
- package/vendor/ars/shared/contracts/review_target/review_criteria_source_receipt.schema.json +158 -0
- package/vendor/ars/shared/contracts/review_target/review_target_context.schema.json +106 -0
- package/vendor/ars/shared/contracts/review_target/review_target_declaration.schema.json +118 -0
- package/vendor/ars/shared/contracts/reviewer/full.json +114 -0
- package/vendor/ars/shared/contracts/reviewer/methodology_focus.json +75 -0
- package/vendor/ars/shared/contracts/reviewer/review_panel_provenance.schema.json +263 -0
- package/vendor/ars/shared/contracts/reviewer/review_panel_provenance_carrier.schema.json +122 -0
- package/vendor/ars/shared/contracts/reviewer/review_panel_provenance_input.schema.json +120 -0
- package/vendor/ars/shared/contracts/revision/author_adjudication.schema.json +251 -0
- package/vendor/ars/shared/contracts/revision/author_adjudication_input.schema.json +25 -0
- package/vendor/ars/shared/contracts/revision/claim_strength_drift_disposition.schema.json +97 -0
- package/vendor/ars/shared/contracts/revision/claim_strength_drift_disposition_input.schema.json +80 -0
- package/vendor/ars/shared/contracts/revision/claim_strength_drift_findings.schema.json +139 -0
- package/vendor/ars/shared/contracts/revision/claim_surface_manifest.schema.json +99 -0
- package/vendor/ars/shared/contracts/revision/integrity_correction_authorization.schema.json +140 -0
- package/vendor/ars/shared/contracts/revision/integrity_correction_authorization_input.schema.json +28 -0
- package/vendor/ars/shared/contracts/revision/integrity_correction_list.schema.json +48 -0
- package/vendor/ars/shared/contracts/revision/integrity_pass_receipt.schema.json +16 -0
- package/vendor/ars/shared/contracts/revision/revision_evidence_bundle.schema.json +134 -0
- package/vendor/ars/shared/contracts/revision/revision_roadmap.schema.json +334 -0
- package/vendor/ars/shared/contracts/submission/format_profile.example.yaml +33 -0
- package/vendor/ars/shared/contracts/submission/format_profile.schema.json +102 -0
- package/vendor/ars/shared/contracts/submission/submission_verification_report.schema.json +233 -0
- package/vendor/ars/shared/contracts/submission/venue_profile.schema.json +114 -0
- package/vendor/ars/shared/contracts/writer/full.json +87 -0
- package/vendor/ars/shared/cross_model_verification.md +714 -0
- package/vendor/ars/shared/evals_lift_report.schema.json +141 -0
- package/vendor/ars/shared/ground_truth_isolation_pattern.md +275 -0
- package/vendor/ars/shared/handoff_schemas.md +1209 -0
- package/vendor/ars/shared/human_subjects_authority_registry.json +1278 -0
- package/vendor/ars/shared/mode_spectrum.md +57 -0
- package/vendor/ars/shared/model_tiering.md +83 -0
- package/vendor/ars/shared/policy_data/nature_policy.md +56 -0
- package/vendor/ars/shared/prisma_trAIce_protocol.md +157 -0
- package/vendor/ars/shared/raise_framework.md +129 -0
- package/vendor/ars/shared/references/authority_content_coverage_advisory_protocol.md +275 -0
- package/vendor/ars/shared/references/claim_standing_candidate_ledger_protocol.md +66 -0
- package/vendor/ars/shared/references/claim_strength_ladder.md +93 -0
- package/vendor/ars/shared/references/cross_document_consistency_advisory_protocol.md +263 -0
- package/vendor/ars/shared/references/evidence_row_protocol.md +260 -0
- package/vendor/ars/shared/references/firm_rules.md +90 -0
- package/vendor/ars/shared/references/human_subjects_authority_protocol.md +274 -0
- package/vendor/ars/shared/references/intent_clarification_protocol.md +168 -0
- package/vendor/ars/shared/references/irb_terminology_glossary.md +229 -0
- package/vendor/ars/shared/references/protected_hedging_phrases.md +118 -0
- package/vendor/ars/shared/references/psychometric_terminology_glossary.md +109 -0
- package/vendor/ars/shared/references/review_criteria_consumer_protocol.md +238 -0
- package/vendor/ars/shared/references/review_pathway_rule_trace_protocol.md +166 -0
- package/vendor/ars/shared/references/submission_packet_manifest_protocol.md +292 -0
- package/vendor/ars/shared/references/word_count_conventions.md +124 -0
- package/vendor/ars/shared/research_workflow_profiles/field_general.json +1 -0
- package/vendor/ars/shared/review_criteria_registry.json +207 -0
- package/vendor/ars/shared/review_criteria_sources/msr-2027-technical-papers.2026-08-24.json +46 -0
- package/vendor/ars/shared/review_criteria_sources/sigsoft-empirical-standards.2026-08-24.json +31 -0
- package/vendor/ars/shared/sprint_contract.schema.json +482 -0
- package/vendor/ars/shared/style_calibration_protocol.md +151 -0
- package/vendor/ars/shared/templates/codex_audit_multifile_template.md +263 -0
- package/vendor/ars/tools/release-discipline/.toolkit-version +1 -0
- package/vendor/ars/tools/release-discipline/README.md +4 -0
- package/vendor/ars/tools/release-discipline/scripts/_release_doc_alignment_schema.py +1011 -0
- package/vendor/ars/tools/release-discipline/scripts/check_command_invariants.py +497 -0
- package/vendor/ars/tools/release-discipline/scripts/check_release_doc_alignment.py +263 -0
- package/vendor/ars/tools/release-discipline/scripts/sync-toolkit.sh +147 -0
- package/vendor/windows/NOTICE.md +12 -0
- package/vendor/windows/arm64/fd.exe +0 -0
- package/vendor/windows/arm64/licenses/fd/LICENSE-APACHE +201 -0
- package/vendor/windows/arm64/licenses/fd/LICENSE-MIT +21 -0
- package/vendor/windows/arm64/licenses/ripgrep/COPYING +3 -0
- package/vendor/windows/arm64/licenses/ripgrep/LICENSE-MIT +21 -0
- package/vendor/windows/arm64/licenses/ripgrep/UNLICENSE +24 -0
- package/vendor/windows/arm64/rg.exe +0 -0
- package/vendor/windows/x64/fd.exe +0 -0
- package/vendor/windows/x64/licenses/fd/LICENSE-APACHE +201 -0
- package/vendor/windows/x64/licenses/fd/LICENSE-MIT +21 -0
- package/vendor/windows/x64/licenses/ripgrep/COPYING +3 -0
- package/vendor/windows/x64/licenses/ripgrep/LICENSE-MIT +21 -0
- package/vendor/windows/x64/licenses/ripgrep/UNLICENSE +24 -0
- package/vendor/windows/x64/rg.exe +0 -0
|
@@ -0,0 +1,1967 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Validate and replay the #670 revision-authority contract.
|
|
3
|
+
|
|
4
|
+
The runtime is hermetic. It opens only explicitly named local artifacts, never
|
|
5
|
+
calls a model or network service, never reads an ambient clock, and never
|
|
6
|
+
supplies an author choice. Reviewer-owned roadmap bytes, explicit author-choice
|
|
7
|
+
bytes, registered claim surfaces, patch bytes, reports, and draft-chain bytes
|
|
8
|
+
remain separate and are joined only through exact SHA-256 bindings.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import copy
|
|
14
|
+
import hashlib
|
|
15
|
+
import json
|
|
16
|
+
import math
|
|
17
|
+
import os
|
|
18
|
+
import re
|
|
19
|
+
import stat
|
|
20
|
+
import sys
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Any, Iterable
|
|
24
|
+
|
|
25
|
+
import jsonschema
|
|
26
|
+
from referencing import Registry, Resource
|
|
27
|
+
|
|
28
|
+
if __package__ in (None, ""): # pragma: no cover - direct CLI invocation
|
|
29
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
30
|
+
|
|
31
|
+
from scripts._block_parser import (
|
|
32
|
+
BlockParseError,
|
|
33
|
+
ParsedDocument,
|
|
34
|
+
atomic_write_bytes,
|
|
35
|
+
base_draft_hash,
|
|
36
|
+
parse_document,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
40
|
+
REVISION_CONTRACTS = REPO_ROOT / "shared" / "contracts" / "revision"
|
|
41
|
+
ROADMAP_SCHEMA_PATH = REVISION_CONTRACTS / "revision_roadmap.schema.json"
|
|
42
|
+
AUTHOR_SCHEMA_PATH = REVISION_CONTRACTS / "author_adjudication.schema.json"
|
|
43
|
+
AUTHOR_INPUT_SCHEMA_PATH = REVISION_CONTRACTS / "author_adjudication_input.schema.json"
|
|
44
|
+
CLAIM_SURFACE_SCHEMA_PATH = REVISION_CONTRACTS / "claim_surface_manifest.schema.json"
|
|
45
|
+
BUNDLE_SCHEMA_PATH = REVISION_CONTRACTS / "revision_evidence_bundle.schema.json"
|
|
46
|
+
INTEGRITY_RECEIPT_SCHEMA_PATH = REVISION_CONTRACTS / "integrity_pass_receipt.schema.json"
|
|
47
|
+
INTEGRITY_LIST_SCHEMA_PATH = REVISION_CONTRACTS / "integrity_correction_list.schema.json"
|
|
48
|
+
INTEGRITY_AUTH_SCHEMA_PATH = (
|
|
49
|
+
REVISION_CONTRACTS / "integrity_correction_authorization.schema.json"
|
|
50
|
+
)
|
|
51
|
+
INTEGRITY_AUTH_INPUT_SCHEMA_PATH = (
|
|
52
|
+
REVISION_CONTRACTS / "integrity_correction_authorization_input.schema.json"
|
|
53
|
+
)
|
|
54
|
+
REVISION_SCHEMA_PATHS = (
|
|
55
|
+
ROADMAP_SCHEMA_PATH,
|
|
56
|
+
AUTHOR_SCHEMA_PATH,
|
|
57
|
+
AUTHOR_INPUT_SCHEMA_PATH,
|
|
58
|
+
CLAIM_SURFACE_SCHEMA_PATH,
|
|
59
|
+
BUNDLE_SCHEMA_PATH,
|
|
60
|
+
INTEGRITY_RECEIPT_SCHEMA_PATH,
|
|
61
|
+
INTEGRITY_LIST_SCHEMA_PATH,
|
|
62
|
+
INTEGRITY_AUTH_SCHEMA_PATH,
|
|
63
|
+
INTEGRITY_AUTH_INPUT_SCHEMA_PATH,
|
|
64
|
+
)
|
|
65
|
+
BLOCK_MANIFEST_SCHEMA_PATH = (
|
|
66
|
+
REPO_ROOT / "shared" / "contracts" / "patch" / "block_manifest.schema.json"
|
|
67
|
+
)
|
|
68
|
+
CLAIM_INTENT_SCHEMA_PATH = (
|
|
69
|
+
REPO_ROOT / "shared" / "contracts" / "passport" / "claim_intent_manifest.schema.json"
|
|
70
|
+
)
|
|
71
|
+
PATCH_SCHEMA_PATH = REPO_ROOT / "shared" / "contracts" / "patch" / "revision_patch.schema.json"
|
|
72
|
+
|
|
73
|
+
CURRENT_ROADMAP_VERSION = "revision-roadmap/1.0"
|
|
74
|
+
CURRENT_AUTHOR_VERSION = "author-adjudication/1.0"
|
|
75
|
+
CURRENT_PATCH_VERSION = "1.1"
|
|
76
|
+
CURRENT_REPORT_VERSION = "1.3"
|
|
77
|
+
OBLIGATION_CLASSES = ("must_fix", "should_fix", "consider")
|
|
78
|
+
DECLINED_TRIAGE = ("wont_address", "not_on_point")
|
|
79
|
+
OP_ORDER = {"replace_block": 0, "insert_after": 1, "delete_block": 2}
|
|
80
|
+
SEAT_ORDER = {"EIC": 0, "R1": 1, "R2": 2, "R3": 3, "DA": 4}
|
|
81
|
+
CHANNEL_ORDER = {"finding": 0, "question": 1, "editorial": 2}
|
|
82
|
+
MAX_ARTIFACT_BYTES = 64 * 1024 * 1024
|
|
83
|
+
|
|
84
|
+
_TIME_UNIT_RE = re.compile(r"\b(?:hours?|hrs?|days?|weeks?|months?)\b", re.IGNORECASE)
|
|
85
|
+
_WORK_RANK_RE = re.compile(
|
|
86
|
+
r"\b(?:priority|rank)\s*(?:number\s*)?[123]\b|"
|
|
87
|
+
r"\bp[123]\s+work\b|\branked\s+work\b|\bwork\s+rank\b|"
|
|
88
|
+
r"\bhighest\s+priority\b|\bdo\b.{0,80}\bfirst\b|"
|
|
89
|
+
r"\bfirst\s+(?:address|revise|complete|do)\b",
|
|
90
|
+
re.IGNORECASE,
|
|
91
|
+
)
|
|
92
|
+
_PREDICTION_LANGUAGE_RE = re.compile(
|
|
93
|
+
r"\b(?:odds|probabilit(?:y|ies)|chance|likelihood)\b|"
|
|
94
|
+
r"\b(?:will|would|shall|certain(?:ly)?|guaranteed\s+to)\s+"
|
|
95
|
+
r"(?:be\s+)?(?:accept(?:ed)?|reject(?:ed)?)\b|"
|
|
96
|
+
r"\b(?:accepted|rejected)\b",
|
|
97
|
+
re.IGNORECASE,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class ContractError(ValueError):
|
|
102
|
+
"""Closed validation failure collection; callers fail before writing."""
|
|
103
|
+
|
|
104
|
+
def __init__(self, failures: list[str]):
|
|
105
|
+
self.failures = failures
|
|
106
|
+
super().__init__("; ".join(failures))
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def bytes_hash(value: bytes) -> str:
|
|
110
|
+
return hashlib.sha256(value).hexdigest()
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _reject_non_jcs_numbers(value: Any, path: str = "$") -> None:
|
|
114
|
+
if isinstance(value, float):
|
|
115
|
+
raise ContractError([f"{path}: floating-point values are outside this contract's JCS value domain"])
|
|
116
|
+
if isinstance(value, dict):
|
|
117
|
+
for key, child in value.items():
|
|
118
|
+
_reject_non_jcs_numbers(child, f"{path}.{key}")
|
|
119
|
+
elif isinstance(value, list):
|
|
120
|
+
for index, child in enumerate(value):
|
|
121
|
+
_reject_non_jcs_numbers(child, f"{path}[{index}]")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def canonical_bytes(value: Any) -> bytes:
|
|
125
|
+
"""Canonical UTF-8 JSON for the contract's string/int/bool/null domain."""
|
|
126
|
+
_reject_non_jcs_numbers(value)
|
|
127
|
+
return json.dumps(
|
|
128
|
+
value, sort_keys=True, separators=(",", ":"), ensure_ascii=False, allow_nan=False
|
|
129
|
+
).encode("utf-8")
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def canonical_hash(value: Any) -> str:
|
|
133
|
+
return bytes_hash(canonical_bytes(value))
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def author_decision_projection(adjudication: dict) -> dict:
|
|
137
|
+
"""Exact author-owned state used for the stable JCS audit digest."""
|
|
138
|
+
return {
|
|
139
|
+
"author_events": copy.deepcopy(adjudication.get("author_events")),
|
|
140
|
+
"display_order": copy.deepcopy(adjudication.get("display_order")),
|
|
141
|
+
"author_adjudications": copy.deepcopy(adjudication.get("author_adjudications")),
|
|
142
|
+
"collateral_authorizations": copy.deepcopy(
|
|
143
|
+
adjudication.get("collateral_authorizations")
|
|
144
|
+
),
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def author_decision_digest(adjudication: dict) -> str:
|
|
149
|
+
return canonical_hash(author_decision_projection(adjudication))
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def source_finding_projection(roadmap: dict) -> list[dict]:
|
|
153
|
+
"""Project transported reviewer data only; never author/view authority."""
|
|
154
|
+
fields = (
|
|
155
|
+
"id",
|
|
156
|
+
"source_refs",
|
|
157
|
+
"description",
|
|
158
|
+
"reviewer",
|
|
159
|
+
"sub_claim_ids",
|
|
160
|
+
"severity",
|
|
161
|
+
"severity_source",
|
|
162
|
+
"evidence_anchor",
|
|
163
|
+
"confidence",
|
|
164
|
+
"competence_basis",
|
|
165
|
+
"confidence_source",
|
|
166
|
+
"corroborating_sources",
|
|
167
|
+
"source_kind",
|
|
168
|
+
)
|
|
169
|
+
return [
|
|
170
|
+
{field: copy.deepcopy(item[field]) for field in fields if field in item}
|
|
171
|
+
for item in roadmap.get("items", [])
|
|
172
|
+
]
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _load_schema(path: Path) -> dict:
|
|
176
|
+
return json.loads(path.read_text(encoding="utf-8"))
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _schema_validator(schema_path: Path) -> jsonschema.Draft202012Validator:
|
|
180
|
+
schema = _load_schema(schema_path)
|
|
181
|
+
registry = Registry()
|
|
182
|
+
for path in REVISION_SCHEMA_PATHS:
|
|
183
|
+
candidate = _load_schema(path)
|
|
184
|
+
if "$id" in candidate:
|
|
185
|
+
registry = registry.with_resource(
|
|
186
|
+
candidate["$id"], Resource.from_contents(candidate)
|
|
187
|
+
)
|
|
188
|
+
return jsonschema.Draft202012Validator(schema, registry=registry)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _schema_failures(value: Any, schema_path: Path, label: str) -> list[str]:
|
|
192
|
+
errors = sorted(
|
|
193
|
+
_schema_validator(schema_path).iter_errors(value),
|
|
194
|
+
key=lambda error: [str(part) for part in error.absolute_path],
|
|
195
|
+
)
|
|
196
|
+
failures: list[str] = []
|
|
197
|
+
for error in errors:
|
|
198
|
+
path = "/".join(str(part) for part in error.absolute_path) or "(root)"
|
|
199
|
+
failures.append(f"{label} schema {path}: {error.message}")
|
|
200
|
+
return failures
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _json_from_raw(raw: bytes, label: str) -> dict:
|
|
204
|
+
def unique_object(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
|
|
205
|
+
value: dict[str, Any] = {}
|
|
206
|
+
for key, child in pairs:
|
|
207
|
+
if key in value:
|
|
208
|
+
raise ValueError(f"duplicate object key {key!r}")
|
|
209
|
+
value[key] = child
|
|
210
|
+
return value
|
|
211
|
+
|
|
212
|
+
def reject_constant(token: str) -> None:
|
|
213
|
+
raise ValueError(f"non-finite JSON constant {token!r}")
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
value = json.loads(
|
|
217
|
+
raw.decode("utf-8"),
|
|
218
|
+
object_pairs_hook=unique_object,
|
|
219
|
+
parse_constant=reject_constant,
|
|
220
|
+
)
|
|
221
|
+
except (UnicodeDecodeError, json.JSONDecodeError, ValueError) as exc:
|
|
222
|
+
raise ContractError([f"{label}: invalid UTF-8 JSON: {exc}"]) from exc
|
|
223
|
+
if not isinstance(value, dict):
|
|
224
|
+
raise ContractError([f"{label}: top level must be an object"])
|
|
225
|
+
return value
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _read_path_once(path: Path, label: str) -> bytes:
|
|
229
|
+
flags = os.O_RDONLY
|
|
230
|
+
if hasattr(os, "O_NOFOLLOW"):
|
|
231
|
+
flags |= os.O_NOFOLLOW
|
|
232
|
+
try:
|
|
233
|
+
fd = os.open(path, flags)
|
|
234
|
+
except OSError as exc:
|
|
235
|
+
raise ContractError([f"{label}: cannot open regular non-symlink file {path}: {exc}"]) from exc
|
|
236
|
+
try:
|
|
237
|
+
before = os.fstat(fd)
|
|
238
|
+
if not stat.S_ISREG(before.st_mode):
|
|
239
|
+
raise ContractError([f"{label}: artifact is not a regular file"])
|
|
240
|
+
chunks: list[bytes] = []
|
|
241
|
+
total = 0
|
|
242
|
+
while True:
|
|
243
|
+
chunk = os.read(fd, min(1024 * 1024, MAX_ARTIFACT_BYTES + 1 - total))
|
|
244
|
+
if not chunk:
|
|
245
|
+
break
|
|
246
|
+
chunks.append(chunk)
|
|
247
|
+
total += len(chunk)
|
|
248
|
+
if total > MAX_ARTIFACT_BYTES:
|
|
249
|
+
raise ContractError([f"{label}: artifact exceeds {MAX_ARTIFACT_BYTES} bytes"])
|
|
250
|
+
after = os.fstat(fd)
|
|
251
|
+
fingerprint_before = (before.st_dev, before.st_ino, before.st_size, before.st_mtime_ns)
|
|
252
|
+
fingerprint_after = (after.st_dev, after.st_ino, after.st_size, after.st_mtime_ns)
|
|
253
|
+
if fingerprint_before != fingerprint_after or total != after.st_size:
|
|
254
|
+
raise ContractError([f"{label}: artifact changed while it was being read"])
|
|
255
|
+
return b"".join(chunks)
|
|
256
|
+
finally:
|
|
257
|
+
os.close(fd)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def load_json_path(path: Path, label: str) -> tuple[dict, bytes]:
|
|
261
|
+
raw = _read_path_once(path, label)
|
|
262
|
+
return _json_from_raw(raw, label), raw
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@dataclass(frozen=True)
|
|
266
|
+
class LoadedArtifact:
|
|
267
|
+
relative_path: str
|
|
268
|
+
raw: bytes
|
|
269
|
+
|
|
270
|
+
def json(self, label: str) -> dict:
|
|
271
|
+
return _json_from_raw(self.raw, label)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
class ArtifactStore:
|
|
275
|
+
"""Containment-safe, no-symlink, hash-checked, read-once bundle store."""
|
|
276
|
+
|
|
277
|
+
def __init__(self, root: Path):
|
|
278
|
+
try:
|
|
279
|
+
self.root = root.resolve(strict=True)
|
|
280
|
+
except OSError as exc:
|
|
281
|
+
raise ContractError([f"bundle root does not exist: {root}"]) from exc
|
|
282
|
+
if not self.root.is_dir():
|
|
283
|
+
raise ContractError([f"bundle root is not a directory: {root}"])
|
|
284
|
+
self._cache: dict[str, LoadedArtifact] = {}
|
|
285
|
+
self._declared_hashes: dict[str, str] = {}
|
|
286
|
+
|
|
287
|
+
@staticmethod
|
|
288
|
+
def _parts(relative: str, label: str) -> list[str]:
|
|
289
|
+
if "\\" in relative:
|
|
290
|
+
raise ContractError([f"bundle {label}: backslash path separators are forbidden"])
|
|
291
|
+
parts = relative.split("/")
|
|
292
|
+
if not parts or any(part in ("", ".", "..") for part in parts):
|
|
293
|
+
raise ContractError([f"bundle {label}: path is not a normalized relative path"])
|
|
294
|
+
if relative.startswith("/"):
|
|
295
|
+
raise ContractError([f"bundle {label}: absolute path is forbidden"])
|
|
296
|
+
return parts
|
|
297
|
+
|
|
298
|
+
def _open_relative(self, relative: str, label: str) -> bytes:
|
|
299
|
+
parts = self._parts(relative, label)
|
|
300
|
+
dir_flags = os.O_RDONLY
|
|
301
|
+
if hasattr(os, "O_DIRECTORY"):
|
|
302
|
+
dir_flags |= os.O_DIRECTORY
|
|
303
|
+
if hasattr(os, "O_NOFOLLOW"):
|
|
304
|
+
dir_flags |= os.O_NOFOLLOW
|
|
305
|
+
file_flags = os.O_RDONLY
|
|
306
|
+
if hasattr(os, "O_NOFOLLOW"):
|
|
307
|
+
file_flags |= os.O_NOFOLLOW
|
|
308
|
+
try:
|
|
309
|
+
current_fd = os.open(self.root, dir_flags)
|
|
310
|
+
except OSError as exc: # pragma: no cover - root was validated
|
|
311
|
+
raise ContractError([f"bundle {label}: cannot open bundle root: {exc}"]) from exc
|
|
312
|
+
file_fd: int | None = None
|
|
313
|
+
try:
|
|
314
|
+
for part in parts[:-1]:
|
|
315
|
+
next_fd = os.open(part, dir_flags, dir_fd=current_fd)
|
|
316
|
+
os.close(current_fd)
|
|
317
|
+
current_fd = next_fd
|
|
318
|
+
file_fd = os.open(parts[-1], file_flags, dir_fd=current_fd)
|
|
319
|
+
before = os.fstat(file_fd)
|
|
320
|
+
if not stat.S_ISREG(before.st_mode):
|
|
321
|
+
raise ContractError([f"bundle {label}: artifact is not a regular file"])
|
|
322
|
+
chunks: list[bytes] = []
|
|
323
|
+
total = 0
|
|
324
|
+
while True:
|
|
325
|
+
chunk = os.read(file_fd, min(1024 * 1024, MAX_ARTIFACT_BYTES + 1 - total))
|
|
326
|
+
if not chunk:
|
|
327
|
+
break
|
|
328
|
+
chunks.append(chunk)
|
|
329
|
+
total += len(chunk)
|
|
330
|
+
if total > MAX_ARTIFACT_BYTES:
|
|
331
|
+
raise ContractError(
|
|
332
|
+
[f"bundle {label}: artifact exceeds {MAX_ARTIFACT_BYTES} bytes"]
|
|
333
|
+
)
|
|
334
|
+
after = os.fstat(file_fd)
|
|
335
|
+
before_fp = (before.st_dev, before.st_ino, before.st_size, before.st_mtime_ns)
|
|
336
|
+
after_fp = (after.st_dev, after.st_ino, after.st_size, after.st_mtime_ns)
|
|
337
|
+
if before_fp != after_fp or total != after.st_size:
|
|
338
|
+
raise ContractError([f"bundle {label}: artifact changed while read"])
|
|
339
|
+
return b"".join(chunks)
|
|
340
|
+
except OSError as exc:
|
|
341
|
+
raise ContractError(
|
|
342
|
+
[f"bundle {label}: cannot open regular no-symlink artifact {relative}: {exc}"]
|
|
343
|
+
) from exc
|
|
344
|
+
finally:
|
|
345
|
+
if file_fd is not None:
|
|
346
|
+
os.close(file_fd)
|
|
347
|
+
os.close(current_fd)
|
|
348
|
+
|
|
349
|
+
def read(self, entry: dict, label: str) -> LoadedArtifact:
|
|
350
|
+
relative = entry["path"]
|
|
351
|
+
expected = entry["sha256"]
|
|
352
|
+
prior_hash = self._declared_hashes.get(relative)
|
|
353
|
+
if prior_hash is not None and prior_hash != expected:
|
|
354
|
+
raise ContractError(
|
|
355
|
+
[f"bundle {label}: one path is declared with conflicting sha256 values"]
|
|
356
|
+
)
|
|
357
|
+
self._declared_hashes[relative] = expected
|
|
358
|
+
if relative in self._cache:
|
|
359
|
+
return self._cache[relative]
|
|
360
|
+
raw = self._open_relative(relative, label)
|
|
361
|
+
actual = bytes_hash(raw)
|
|
362
|
+
if actual != expected:
|
|
363
|
+
raise ContractError(
|
|
364
|
+
[f"bundle {label}: sha256 mismatch (expected {expected}, actual {actual})"]
|
|
365
|
+
)
|
|
366
|
+
artifact = LoadedArtifact(relative, raw)
|
|
367
|
+
self._cache[relative] = artifact
|
|
368
|
+
return artifact
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def _parse_base(base_raw: bytes, label: str = "base draft") -> tuple[str, ParsedDocument]:
|
|
372
|
+
try:
|
|
373
|
+
text = base_raw.decode("utf-8")
|
|
374
|
+
except UnicodeDecodeError as exc:
|
|
375
|
+
raise ContractError([f"{label}: invalid UTF-8: {exc}"]) from exc
|
|
376
|
+
try:
|
|
377
|
+
parsed = parse_document(text)
|
|
378
|
+
except BlockParseError as exc:
|
|
379
|
+
raise ContractError([f"{label}: block parse rejected [{exc.kind}]: {exc}"]) from exc
|
|
380
|
+
return text, parsed
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def validate_block_manifest(manifest: dict, manifest_raw: bytes, base_raw: bytes) -> ParsedDocument:
|
|
384
|
+
failures = _schema_failures(manifest, BLOCK_MANIFEST_SCHEMA_PATH, "block manifest")
|
|
385
|
+
parsed: ParsedDocument | None = None
|
|
386
|
+
try:
|
|
387
|
+
_text, parsed = _parse_base(base_raw)
|
|
388
|
+
except ContractError as exc:
|
|
389
|
+
failures.extend(exc.failures)
|
|
390
|
+
if failures:
|
|
391
|
+
raise ContractError(failures)
|
|
392
|
+
assert parsed is not None # established by the failure gate above
|
|
393
|
+
expected_base = base_draft_hash(base_raw)
|
|
394
|
+
if manifest["base_draft_hash"] != expected_base:
|
|
395
|
+
failures.append("block manifest base_draft_hash does not match exact base bytes")
|
|
396
|
+
expected_blocks = [
|
|
397
|
+
{"block_id": block.block_id, "old_hash": block.norm_hash}
|
|
398
|
+
for block in parsed.blocks
|
|
399
|
+
]
|
|
400
|
+
actual_blocks = [
|
|
401
|
+
{"block_id": row["block_id"], "old_hash": row["old_hash"]}
|
|
402
|
+
for row in manifest["blocks"]
|
|
403
|
+
]
|
|
404
|
+
if actual_blocks != expected_blocks:
|
|
405
|
+
failures.append("block manifest block_id/old_hash sequence does not match parsed base")
|
|
406
|
+
if failures:
|
|
407
|
+
raise ContractError(failures)
|
|
408
|
+
return parsed
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def _source_key(ref: dict) -> tuple[int, int, int, int]:
|
|
412
|
+
return (
|
|
413
|
+
SEAT_ORDER[ref["seat"]],
|
|
414
|
+
ref["ordinal"],
|
|
415
|
+
ref["subclaim_ordinal"],
|
|
416
|
+
CHANNEL_ORDER[ref["channel"]],
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def _target_key(target: dict) -> tuple[int, str, tuple[int, ...]]:
|
|
421
|
+
block_id = target["block_id"]
|
|
422
|
+
if block_id == "DOC-BODY-START":
|
|
423
|
+
block_order = -1
|
|
424
|
+
else:
|
|
425
|
+
block_order = int(block_id[1:])
|
|
426
|
+
return (
|
|
427
|
+
block_order,
|
|
428
|
+
block_id,
|
|
429
|
+
tuple(OP_ORDER[op] for op in target["allowed_operations"]),
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def _target_map(targets: Iterable[dict]) -> dict[str, set[str]]:
|
|
434
|
+
return {target["block_id"]: set(target["allowed_operations"]) for target in targets}
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def _validate_target_list(
|
|
438
|
+
targets: list[dict],
|
|
439
|
+
*,
|
|
440
|
+
label: str,
|
|
441
|
+
valid_block_ids: set[str] | None,
|
|
442
|
+
failures: list[str],
|
|
443
|
+
) -> None:
|
|
444
|
+
block_ids = [target["block_id"] for target in targets]
|
|
445
|
+
if len(block_ids) != len(set(block_ids)):
|
|
446
|
+
failures.append(f"{label}: each block_id may appear only once")
|
|
447
|
+
for target in targets:
|
|
448
|
+
operations = target["allowed_operations"]
|
|
449
|
+
if operations != sorted(operations, key=OP_ORDER.__getitem__):
|
|
450
|
+
failures.append(f"{label}: allowed_operations must use canonical operation order")
|
|
451
|
+
if valid_block_ids is not None and target["block_id"] not in valid_block_ids:
|
|
452
|
+
failures.append(f"{label}: block {target['block_id']} does not exist in the base")
|
|
453
|
+
if targets != sorted(targets, key=_target_key):
|
|
454
|
+
failures.append(f"{label}: target rows must use canonical block/operation order")
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def _has_forbidden_work_language(text: str) -> bool:
|
|
458
|
+
folded = " " + " ".join(text.lower().split()) + " "
|
|
459
|
+
if _WORK_RANK_RE.search(folded):
|
|
460
|
+
return True
|
|
461
|
+
return _TIME_UNIT_RE.search(folded) is not None
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def _has_forbidden_prediction_language(text: str) -> bool:
|
|
465
|
+
return _PREDICTION_LANGUAGE_RE.search(" ".join(text.split())) is not None
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
def validate_roadmap(
|
|
469
|
+
roadmap: dict,
|
|
470
|
+
*,
|
|
471
|
+
roadmap_raw: bytes | None = None,
|
|
472
|
+
base_raw: bytes | None = None,
|
|
473
|
+
block_manifest: dict | None = None,
|
|
474
|
+
block_manifest_raw: bytes | None = None,
|
|
475
|
+
) -> None:
|
|
476
|
+
failures = _schema_failures(roadmap, ROADMAP_SCHEMA_PATH, "roadmap")
|
|
477
|
+
if failures:
|
|
478
|
+
raise ContractError(failures)
|
|
479
|
+
|
|
480
|
+
parsed: ParsedDocument | None = None
|
|
481
|
+
if base_raw is not None:
|
|
482
|
+
if roadmap["base_draft_sha256"] != bytes_hash(base_raw):
|
|
483
|
+
failures.append("roadmap base_draft_sha256 does not match exact base bytes")
|
|
484
|
+
try:
|
|
485
|
+
_text, parsed = _parse_base(base_raw)
|
|
486
|
+
except ContractError as exc:
|
|
487
|
+
failures.extend(exc.failures)
|
|
488
|
+
if block_manifest_raw is not None:
|
|
489
|
+
if roadmap["block_manifest_sha256"] != bytes_hash(block_manifest_raw):
|
|
490
|
+
failures.append("roadmap block_manifest_sha256 does not match exact manifest bytes")
|
|
491
|
+
if block_manifest is None or base_raw is None:
|
|
492
|
+
failures.append("roadmap block-manifest replay requires both manifest JSON and base bytes")
|
|
493
|
+
else:
|
|
494
|
+
try:
|
|
495
|
+
parsed = validate_block_manifest(block_manifest, block_manifest_raw, base_raw)
|
|
496
|
+
except ContractError as exc:
|
|
497
|
+
failures.extend(exc.failures)
|
|
498
|
+
|
|
499
|
+
items = roadmap["items"]
|
|
500
|
+
item_ids = [item["id"] for item in items]
|
|
501
|
+
if len(item_ids) != len(set(item_ids)):
|
|
502
|
+
failures.append("roadmap items: duplicate id")
|
|
503
|
+
if roadmap["total_items"] != len(items):
|
|
504
|
+
failures.append("roadmap total_items does not equal items length")
|
|
505
|
+
counts = {name: 0 for name in OBLIGATION_CLASSES}
|
|
506
|
+
all_source_keys: list[tuple[int, int, int, int]] = []
|
|
507
|
+
valid_blocks = None
|
|
508
|
+
if parsed is not None:
|
|
509
|
+
valid_blocks = {block.block_id for block in parsed.blocks if block.block_id}
|
|
510
|
+
valid_blocks.add("DOC-BODY-START")
|
|
511
|
+
for item in items:
|
|
512
|
+
counts[item["obligation_class"]] += 1
|
|
513
|
+
refs = item["source_refs"]
|
|
514
|
+
keys = [_source_key(ref) for ref in refs]
|
|
515
|
+
if keys != sorted(keys):
|
|
516
|
+
failures.append(f"roadmap item {item['id']}: source_refs must be in immutable source order")
|
|
517
|
+
all_source_keys.extend(keys)
|
|
518
|
+
for field in ("suggested_action", "verification_criteria"):
|
|
519
|
+
if _has_forbidden_work_language(item[field]):
|
|
520
|
+
failures.append(
|
|
521
|
+
f"roadmap item {item['id']} {field}: work-rank or time-estimate language is forbidden"
|
|
522
|
+
)
|
|
523
|
+
if _has_forbidden_prediction_language(item[field]):
|
|
524
|
+
failures.append(
|
|
525
|
+
f"roadmap item {item['id']} {field}: acceptance-prediction language is forbidden"
|
|
526
|
+
)
|
|
527
|
+
if _has_forbidden_work_language(item["cost_scope"]["locator"]):
|
|
528
|
+
failures.append(
|
|
529
|
+
f"roadmap item {item['id']} cost_scope.locator: describe a surface, not a work rank/time estimate"
|
|
530
|
+
)
|
|
531
|
+
if _has_forbidden_prediction_language(item["cost_scope"]["locator"]):
|
|
532
|
+
failures.append(
|
|
533
|
+
f"roadmap item {item['id']} cost_scope.locator: acceptance-prediction language is forbidden"
|
|
534
|
+
)
|
|
535
|
+
consequence_locator = item["consequence_if_unaddressed"]["target"]["locator"]
|
|
536
|
+
if _has_forbidden_work_language(consequence_locator):
|
|
537
|
+
failures.append(
|
|
538
|
+
f"roadmap item {item['id']} consequence target: use a locator, not a work rank/time estimate"
|
|
539
|
+
)
|
|
540
|
+
if _has_forbidden_prediction_language(consequence_locator):
|
|
541
|
+
failures.append(
|
|
542
|
+
f"roadmap item {item['id']} consequence target: acceptance-prediction language is forbidden"
|
|
543
|
+
)
|
|
544
|
+
_validate_target_list(
|
|
545
|
+
item["proposed_targets"],
|
|
546
|
+
label=f"roadmap item {item['id']} proposed_targets",
|
|
547
|
+
valid_block_ids=valid_blocks,
|
|
548
|
+
failures=failures,
|
|
549
|
+
)
|
|
550
|
+
if len(all_source_keys) != len(set(all_source_keys)):
|
|
551
|
+
failures.append("roadmap source_refs: each immutable source position must be unique")
|
|
552
|
+
expected_order = sorted(items, key=lambda item: (_source_key(item["source_refs"][0]), item["id"]))
|
|
553
|
+
if items != expected_order:
|
|
554
|
+
failures.append("roadmap items must use deterministic primary-source order")
|
|
555
|
+
if roadmap["obligation_counts"] != counts:
|
|
556
|
+
failures.append("roadmap obligation_counts does not recompute from obligation_class")
|
|
557
|
+
if failures:
|
|
558
|
+
raise ContractError(failures)
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
def validate_claim_surface_manifest(
|
|
562
|
+
claim_surface: dict,
|
|
563
|
+
*,
|
|
564
|
+
claim_surface_raw: bytes,
|
|
565
|
+
roadmap: dict,
|
|
566
|
+
roadmap_raw: bytes,
|
|
567
|
+
base_raw: bytes,
|
|
568
|
+
artifact_store: ArtifactStore,
|
|
569
|
+
) -> dict[str, dict]:
|
|
570
|
+
failures = _schema_failures(
|
|
571
|
+
claim_surface, CLAIM_SURFACE_SCHEMA_PATH, "claim surface manifest"
|
|
572
|
+
)
|
|
573
|
+
if failures:
|
|
574
|
+
raise ContractError(failures)
|
|
575
|
+
if claim_surface["roadmap_sha256"] != bytes_hash(roadmap_raw):
|
|
576
|
+
failures.append("claim surface roadmap_sha256 does not match exact roadmap bytes")
|
|
577
|
+
if claim_surface["base_draft_sha256"] != bytes_hash(base_raw):
|
|
578
|
+
failures.append("claim surface base_draft_sha256 does not match exact base bytes")
|
|
579
|
+
if claim_surface["revision_round"] != roadmap["revision_round"]:
|
|
580
|
+
failures.append("claim surface revision_round does not match roadmap")
|
|
581
|
+
|
|
582
|
+
text, parsed = _parse_base(base_raw)
|
|
583
|
+
blocks = parsed.block_by_id()
|
|
584
|
+
source_ids: set[str] = set()
|
|
585
|
+
claims: dict[tuple[str, str], dict] = {}
|
|
586
|
+
for index, source in enumerate(claim_surface["claim_intent_sources"]):
|
|
587
|
+
manifest_id = source["scoped_manifest_id"]
|
|
588
|
+
if manifest_id in source_ids:
|
|
589
|
+
failures.append(f"claim intent sources: duplicate scoped_manifest_id {manifest_id}")
|
|
590
|
+
continue
|
|
591
|
+
source_ids.add(manifest_id)
|
|
592
|
+
try:
|
|
593
|
+
artifact = artifact_store.read(
|
|
594
|
+
source["artifact"], f"claim_intent_sources[{index}]"
|
|
595
|
+
)
|
|
596
|
+
manifest = artifact.json(f"claim intent source {manifest_id}")
|
|
597
|
+
failures.extend(
|
|
598
|
+
_schema_failures(manifest, CLAIM_INTENT_SCHEMA_PATH, f"claim intent {manifest_id}")
|
|
599
|
+
)
|
|
600
|
+
if manifest.get("manifest_id") != manifest_id:
|
|
601
|
+
failures.append(
|
|
602
|
+
f"claim intent source {manifest_id}: artifact manifest_id differs"
|
|
603
|
+
)
|
|
604
|
+
seen_claim_ids: set[str] = set()
|
|
605
|
+
for claim in manifest.get("claims", []):
|
|
606
|
+
claim_id = claim.get("claim_id")
|
|
607
|
+
if claim_id in seen_claim_ids:
|
|
608
|
+
failures.append(
|
|
609
|
+
f"claim intent source {manifest_id}: duplicate claim_id {claim_id}"
|
|
610
|
+
)
|
|
611
|
+
seen_claim_ids.add(claim_id)
|
|
612
|
+
claims[(manifest_id, claim_id)] = claim
|
|
613
|
+
except ContractError as exc:
|
|
614
|
+
failures.extend(exc.failures)
|
|
615
|
+
|
|
616
|
+
surfaces_by_id: dict[str, dict] = {}
|
|
617
|
+
referenced_sources: set[str] = set()
|
|
618
|
+
byte_ranges: list[tuple[int, int, str]] = []
|
|
619
|
+
block_text_counts: dict[tuple[str, str], int] = {}
|
|
620
|
+
for surface in claim_surface["surfaces"]:
|
|
621
|
+
surface_id = surface["surface_id"]
|
|
622
|
+
if surface_id in surfaces_by_id:
|
|
623
|
+
failures.append(f"claim surfaces: duplicate surface_id {surface_id}")
|
|
624
|
+
surfaces_by_id[surface_id] = surface
|
|
625
|
+
key = (surface["scoped_manifest_id"], surface["claim_id"])
|
|
626
|
+
referenced_sources.add(key[0])
|
|
627
|
+
claim = claims.get(key)
|
|
628
|
+
if claim is None:
|
|
629
|
+
failures.append(
|
|
630
|
+
f"claim surface {surface_id}: ({key[0]}, {key[1]}) does not resolve"
|
|
631
|
+
)
|
|
632
|
+
elif bytes_hash(claim["claim_text"].encode("utf-8")) != surface["intent_claim_text_sha256"]:
|
|
633
|
+
failures.append(
|
|
634
|
+
f"claim surface {surface_id}: intent_claim_text_sha256 does not match source claim"
|
|
635
|
+
)
|
|
636
|
+
elif surface["original_text"] != claim["claim_text"]:
|
|
637
|
+
failures.append(
|
|
638
|
+
f"claim surface {surface_id}: original_text must equal the referenced ClaimIntent claim_text exactly"
|
|
639
|
+
)
|
|
640
|
+
original_raw = surface["original_text"].encode("utf-8")
|
|
641
|
+
if bytes_hash(original_raw) != surface["original_text_sha256"]:
|
|
642
|
+
failures.append(f"claim surface {surface_id}: original_text_sha256 mismatch")
|
|
643
|
+
start, end = surface["utf8_start"], surface["utf8_end"]
|
|
644
|
+
if not (start < end <= len(base_raw)) or base_raw[start:end] != original_raw:
|
|
645
|
+
failures.append(f"claim surface {surface_id}: UTF-8 span does not select exact original_text")
|
|
646
|
+
block = blocks.get(surface["block_id"])
|
|
647
|
+
if block is None:
|
|
648
|
+
failures.append(f"claim surface {surface_id}: block does not exist")
|
|
649
|
+
else:
|
|
650
|
+
block_start = len(text[: block.span[0]].encode("utf-8"))
|
|
651
|
+
block_end = len(text[: block.span[1]].encode("utf-8"))
|
|
652
|
+
if not (block_start <= start < end <= block_end):
|
|
653
|
+
failures.append(f"claim surface {surface_id}: UTF-8 span escapes declared block")
|
|
654
|
+
count_key = (surface["block_id"], surface["original_text"])
|
|
655
|
+
# Use the exact raw block slice. Normalization is appropriate for
|
|
656
|
+
# block hashes, but a registered claim surface is an absolute
|
|
657
|
+
# UTF-8 byte witness and must replay against the original bytes.
|
|
658
|
+
count = text[block.span[0] : block.span[1]].count(surface["original_text"])
|
|
659
|
+
block_text_counts[count_key] = count
|
|
660
|
+
if count != 1:
|
|
661
|
+
failures.append(
|
|
662
|
+
f"claim surface {surface_id}: original_text must occur exactly once in its block"
|
|
663
|
+
)
|
|
664
|
+
byte_ranges.append((start, end, surface_id))
|
|
665
|
+
if referenced_sources != source_ids:
|
|
666
|
+
failures.append(
|
|
667
|
+
"claim intent sources must equal exactly the manifests referenced by surfaces"
|
|
668
|
+
)
|
|
669
|
+
byte_ranges.sort()
|
|
670
|
+
for prior, current in zip(byte_ranges, byte_ranges[1:]):
|
|
671
|
+
if current[0] < prior[1]:
|
|
672
|
+
failures.append(
|
|
673
|
+
f"claim surfaces {prior[2]} and {current[2]} overlap in the base draft"
|
|
674
|
+
)
|
|
675
|
+
if failures:
|
|
676
|
+
raise ContractError(failures)
|
|
677
|
+
return surfaces_by_id
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
def _claim_auth_projection(value: dict) -> dict:
|
|
681
|
+
fields = (
|
|
682
|
+
"authorization_id",
|
|
683
|
+
"surface_id",
|
|
684
|
+
"scoped_manifest_id",
|
|
685
|
+
"claim_id",
|
|
686
|
+
"block_id",
|
|
687
|
+
"original_text_sha256",
|
|
688
|
+
"replacement_text_sha256",
|
|
689
|
+
"from_rung",
|
|
690
|
+
"to_rung",
|
|
691
|
+
"direction",
|
|
692
|
+
)
|
|
693
|
+
return {field: value[field] for field in fields}
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
def validate_author_adjudication(
|
|
697
|
+
adjudication: dict,
|
|
698
|
+
*,
|
|
699
|
+
adjudication_raw: bytes,
|
|
700
|
+
roadmap: dict,
|
|
701
|
+
roadmap_raw: bytes,
|
|
702
|
+
claim_surface: dict,
|
|
703
|
+
claim_surface_raw: bytes,
|
|
704
|
+
base_raw: bytes,
|
|
705
|
+
surfaces_by_id: dict[str, dict],
|
|
706
|
+
) -> dict:
|
|
707
|
+
failures = _schema_failures(adjudication, AUTHOR_SCHEMA_PATH, "author adjudication")
|
|
708
|
+
if failures:
|
|
709
|
+
raise ContractError(failures)
|
|
710
|
+
if adjudication["roadmap_sha256"] != bytes_hash(roadmap_raw):
|
|
711
|
+
failures.append("author adjudication roadmap_sha256 does not match exact roadmap bytes")
|
|
712
|
+
if adjudication["base_draft_sha256"] != bytes_hash(base_raw):
|
|
713
|
+
failures.append("author adjudication base_draft_sha256 does not match exact base bytes")
|
|
714
|
+
if adjudication["claim_surface_manifest_sha256"] != bytes_hash(claim_surface_raw):
|
|
715
|
+
failures.append(
|
|
716
|
+
"author adjudication claim_surface_manifest_sha256 does not match exact bytes"
|
|
717
|
+
)
|
|
718
|
+
if adjudication["revision_round"] != roadmap["revision_round"]:
|
|
719
|
+
failures.append("author adjudication revision_round does not match roadmap")
|
|
720
|
+
|
|
721
|
+
event_ids = [event["event_id"] for event in adjudication["author_events"]]
|
|
722
|
+
if len(event_ids) != len(set(event_ids)):
|
|
723
|
+
failures.append("author adjudication author_events: duplicate event_id")
|
|
724
|
+
event_set = set(event_ids)
|
|
725
|
+
if adjudication["display_order"]["author_event_id"] not in event_set:
|
|
726
|
+
failures.append("author adjudication display_order author_event_id does not resolve")
|
|
727
|
+
|
|
728
|
+
roadmap_items = {item["id"]: item for item in roadmap["items"]}
|
|
729
|
+
roadmap_ids = list(roadmap_items)
|
|
730
|
+
display_ids = adjudication["display_order"]["item_ids"]
|
|
731
|
+
if len(display_ids) != len(set(display_ids)) or set(display_ids) != set(roadmap_ids):
|
|
732
|
+
failures.append("author display_order.item_ids must be a full unique roadmap permutation")
|
|
733
|
+
if (
|
|
734
|
+
adjudication["display_order"]["mode"] == "source_traceability"
|
|
735
|
+
and display_ids != roadmap_ids
|
|
736
|
+
):
|
|
737
|
+
failures.append("source_traceability author view must equal immutable roadmap order")
|
|
738
|
+
|
|
739
|
+
records: dict[str, dict] = {}
|
|
740
|
+
claim_auths: dict[str, tuple[str, dict]] = {}
|
|
741
|
+
claim_auth_surface_ids: dict[str, str] = {}
|
|
742
|
+
for record in adjudication["author_adjudications"]:
|
|
743
|
+
item_id = record["item_id"]
|
|
744
|
+
if item_id in records:
|
|
745
|
+
failures.append(f"author adjudications: duplicate item_id {item_id}")
|
|
746
|
+
records[item_id] = record
|
|
747
|
+
item = roadmap_items.get(item_id)
|
|
748
|
+
if item is None:
|
|
749
|
+
failures.append(f"author adjudication item {item_id} does not resolve")
|
|
750
|
+
continue
|
|
751
|
+
if record["author_event_id"] not in event_set:
|
|
752
|
+
failures.append(f"author adjudication {item_id}: author_event_id does not resolve")
|
|
753
|
+
if record["author_triage"] == "will_address" and "author_reason" in record:
|
|
754
|
+
failures.append(
|
|
755
|
+
f"author adjudication {item_id}: will_address must not carry author_reason"
|
|
756
|
+
)
|
|
757
|
+
_validate_target_list(
|
|
758
|
+
record["authorized_targets"],
|
|
759
|
+
label=f"author adjudication {item_id} authorized_targets",
|
|
760
|
+
valid_block_ids=None,
|
|
761
|
+
failures=failures,
|
|
762
|
+
)
|
|
763
|
+
proposed = _target_map(item["proposed_targets"])
|
|
764
|
+
for target in record["authorized_targets"]:
|
|
765
|
+
proposed_ops = proposed.get(target["block_id"])
|
|
766
|
+
if proposed_ops is None or not set(target["allowed_operations"]).issubset(proposed_ops):
|
|
767
|
+
failures.append(
|
|
768
|
+
f"author adjudication {item_id}: authorized target exceeds reviewer-proposed scope"
|
|
769
|
+
)
|
|
770
|
+
authorized = _target_map(record["authorized_targets"])
|
|
771
|
+
for authorization in record["claim_strength_authorizations"]:
|
|
772
|
+
auth_id = authorization["authorization_id"]
|
|
773
|
+
if auth_id in claim_auths:
|
|
774
|
+
failures.append(f"claim authorizations: duplicate authorization_id {auth_id}")
|
|
775
|
+
claim_auths[auth_id] = (item_id, authorization)
|
|
776
|
+
surface_id = authorization["surface_id"]
|
|
777
|
+
prior_auth_id = claim_auth_surface_ids.get(surface_id)
|
|
778
|
+
if prior_auth_id is not None:
|
|
779
|
+
failures.append(
|
|
780
|
+
f"claim authorizations: surface_id {surface_id} is authorized more than once "
|
|
781
|
+
f"({prior_auth_id}, {auth_id})"
|
|
782
|
+
)
|
|
783
|
+
else:
|
|
784
|
+
claim_auth_surface_ids[surface_id] = auth_id
|
|
785
|
+
if authorization["author_event_id"] not in event_set:
|
|
786
|
+
failures.append(f"claim authorization {auth_id}: author_event_id does not resolve")
|
|
787
|
+
surface = surfaces_by_id.get(authorization["surface_id"])
|
|
788
|
+
if surface is None:
|
|
789
|
+
failures.append(f"claim authorization {auth_id}: surface_id does not resolve")
|
|
790
|
+
else:
|
|
791
|
+
for field in (
|
|
792
|
+
"scoped_manifest_id",
|
|
793
|
+
"claim_id",
|
|
794
|
+
"block_id",
|
|
795
|
+
"original_text_sha256",
|
|
796
|
+
):
|
|
797
|
+
if authorization[field] != surface[field]:
|
|
798
|
+
failures.append(
|
|
799
|
+
f"claim authorization {auth_id}: {field} differs from registered surface"
|
|
800
|
+
)
|
|
801
|
+
if authorization["from_rung"] != surface["current_rung"]:
|
|
802
|
+
failures.append(
|
|
803
|
+
f"claim authorization {auth_id}: from_rung differs from registered current_rung"
|
|
804
|
+
)
|
|
805
|
+
if authorization["from_rung"] == authorization["to_rung"]:
|
|
806
|
+
failures.append(f"claim authorization {auth_id}: from_rung and to_rung must differ")
|
|
807
|
+
replacement = authorization["replacement_text"].encode("utf-8")
|
|
808
|
+
if bytes_hash(replacement) != authorization["replacement_text_sha256"]:
|
|
809
|
+
failures.append(f"claim authorization {auth_id}: replacement_text_sha256 mismatch")
|
|
810
|
+
compatible_ops = authorized.get(authorization["block_id"], set())
|
|
811
|
+
needed_op = "delete_block" if authorization["replacement_text"] == "" else "replace_block"
|
|
812
|
+
if needed_op not in compatible_ops:
|
|
813
|
+
failures.append(
|
|
814
|
+
f"claim authorization {auth_id}: authorized target lacks compatible {needed_op}"
|
|
815
|
+
)
|
|
816
|
+
if set(records) != set(roadmap_items):
|
|
817
|
+
failures.append(
|
|
818
|
+
"complete author adjudication must contain exactly one record per roadmap item"
|
|
819
|
+
)
|
|
820
|
+
|
|
821
|
+
collateral: dict[str, dict] = {}
|
|
822
|
+
for authorization in adjudication["collateral_authorizations"]:
|
|
823
|
+
auth_id = authorization["authorization_id"]
|
|
824
|
+
if auth_id in collateral:
|
|
825
|
+
failures.append(f"collateral authorizations: duplicate authorization_id {auth_id}")
|
|
826
|
+
collateral[auth_id] = authorization
|
|
827
|
+
if authorization["author_event_id"] not in event_set:
|
|
828
|
+
failures.append(f"collateral authorization {auth_id}: author_event_id does not resolve")
|
|
829
|
+
accepted = records.get(authorization["authorizing_item_id"])
|
|
830
|
+
declined = records.get(authorization["constrained_item_id"])
|
|
831
|
+
if accepted is None or accepted["author_triage"] != "will_address":
|
|
832
|
+
failures.append(
|
|
833
|
+
f"collateral authorization {auth_id}: authorizing_item_id must be will_address"
|
|
834
|
+
)
|
|
835
|
+
if declined is None or declined["author_triage"] not in DECLINED_TRIAGE:
|
|
836
|
+
failures.append(
|
|
837
|
+
f"collateral authorization {auth_id}: constrained_item_id must be declined"
|
|
838
|
+
)
|
|
839
|
+
if authorization["authorizing_item_id"] == authorization["constrained_item_id"]:
|
|
840
|
+
failures.append(f"collateral authorization {auth_id}: item ids must differ")
|
|
841
|
+
if accepted is not None:
|
|
842
|
+
accepted_ops = _target_map(accepted["authorized_targets"]).get(
|
|
843
|
+
authorization["block_id"], set()
|
|
844
|
+
)
|
|
845
|
+
if authorization["operation"] not in accepted_ops:
|
|
846
|
+
failures.append(
|
|
847
|
+
f"collateral authorization {auth_id}: accepted item does not authorize exact target/op"
|
|
848
|
+
)
|
|
849
|
+
constrained_item = roadmap_items.get(authorization["constrained_item_id"])
|
|
850
|
+
if constrained_item is not None:
|
|
851
|
+
constrained_blocks = _target_map(constrained_item["proposed_targets"])
|
|
852
|
+
if authorization["block_id"] not in constrained_blocks:
|
|
853
|
+
failures.append(
|
|
854
|
+
f"collateral authorization {auth_id}: block is outside declined item's no-touch scope"
|
|
855
|
+
)
|
|
856
|
+
if failures:
|
|
857
|
+
raise ContractError(failures)
|
|
858
|
+
return {
|
|
859
|
+
"records": records,
|
|
860
|
+
"claim_authorizations": claim_auths,
|
|
861
|
+
"collateral_authorizations": collateral,
|
|
862
|
+
"author_decision_digest": author_decision_digest(adjudication),
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
def build_author_adjudication(
|
|
867
|
+
choice_input: dict,
|
|
868
|
+
*,
|
|
869
|
+
roadmap: dict,
|
|
870
|
+
roadmap_raw: bytes,
|
|
871
|
+
claim_surface: dict,
|
|
872
|
+
claim_surface_raw: bytes,
|
|
873
|
+
base_raw: bytes,
|
|
874
|
+
surfaces_by_id: dict[str, dict],
|
|
875
|
+
) -> dict:
|
|
876
|
+
failures = _schema_failures(choice_input, AUTHOR_INPUT_SCHEMA_PATH, "author choice input")
|
|
877
|
+
if failures:
|
|
878
|
+
raise ContractError(failures)
|
|
879
|
+
adjudication = {
|
|
880
|
+
"schema_version": CURRENT_AUTHOR_VERSION,
|
|
881
|
+
"revision_round": roadmap["revision_round"],
|
|
882
|
+
"roadmap_sha256": bytes_hash(roadmap_raw),
|
|
883
|
+
"base_draft_sha256": bytes_hash(base_raw),
|
|
884
|
+
"claim_surface_manifest_sha256": bytes_hash(claim_surface_raw),
|
|
885
|
+
"adjudication_status": "complete",
|
|
886
|
+
"author_events": copy.deepcopy(choice_input["author_events"]),
|
|
887
|
+
"display_order": copy.deepcopy(choice_input["display_order"]),
|
|
888
|
+
"author_adjudications": copy.deepcopy(choice_input["author_adjudications"]),
|
|
889
|
+
"collateral_authorizations": copy.deepcopy(
|
|
890
|
+
choice_input["collateral_authorizations"]
|
|
891
|
+
),
|
|
892
|
+
}
|
|
893
|
+
raw = canonical_bytes(adjudication)
|
|
894
|
+
validate_author_adjudication(
|
|
895
|
+
adjudication,
|
|
896
|
+
adjudication_raw=raw,
|
|
897
|
+
roadmap=roadmap,
|
|
898
|
+
roadmap_raw=roadmap_raw,
|
|
899
|
+
claim_surface=claim_surface,
|
|
900
|
+
claim_surface_raw=claim_surface_raw,
|
|
901
|
+
base_raw=base_raw,
|
|
902
|
+
surfaces_by_id=surfaces_by_id,
|
|
903
|
+
)
|
|
904
|
+
return adjudication
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
def _op_authorized(record: dict, op: dict) -> bool:
|
|
908
|
+
return op["op"] in _target_map(record["authorized_targets"]).get(op["block_id"], set())
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
def validate_review_patch_authorization(
|
|
912
|
+
patch: dict,
|
|
913
|
+
*,
|
|
914
|
+
base_raw: bytes,
|
|
915
|
+
roadmap: dict,
|
|
916
|
+
roadmap_raw: bytes,
|
|
917
|
+
adjudication: dict,
|
|
918
|
+
adjudication_raw: bytes,
|
|
919
|
+
claim_surface: dict,
|
|
920
|
+
claim_surface_raw: bytes,
|
|
921
|
+
surfaces_by_id: dict[str, dict],
|
|
922
|
+
) -> dict:
|
|
923
|
+
failures = _schema_failures(patch, PATCH_SCHEMA_PATH, "review patch")
|
|
924
|
+
if failures:
|
|
925
|
+
raise ContractError(failures)
|
|
926
|
+
if patch.get("patch_format_version") != CURRENT_PATCH_VERSION:
|
|
927
|
+
failures.append(f"patch_format_version must be {CURRENT_PATCH_VERSION} for writes")
|
|
928
|
+
if patch.get("authorization_context") != "review_roadmap":
|
|
929
|
+
failures.append("review patch authorization_context must be review_roadmap")
|
|
930
|
+
expected_bindings = {
|
|
931
|
+
"roadmap_sha256": bytes_hash(roadmap_raw),
|
|
932
|
+
"author_adjudication_sha256": bytes_hash(adjudication_raw),
|
|
933
|
+
"author_decision_digest": author_decision_digest(adjudication),
|
|
934
|
+
"claim_surface_manifest_sha256": bytes_hash(claim_surface_raw),
|
|
935
|
+
}
|
|
936
|
+
for field, expected in expected_bindings.items():
|
|
937
|
+
if patch.get(field) != expected:
|
|
938
|
+
failures.append(f"review patch {field} does not match bound artifact")
|
|
939
|
+
if patch.get("revision_round") != roadmap["revision_round"]:
|
|
940
|
+
failures.append("review patch revision_round does not match roadmap")
|
|
941
|
+
if patch.get("base_draft_hash") != base_draft_hash(base_raw):
|
|
942
|
+
failures.append("review patch base_draft_hash does not match exact base bytes")
|
|
943
|
+
|
|
944
|
+
author_state = validate_author_adjudication(
|
|
945
|
+
adjudication,
|
|
946
|
+
adjudication_raw=adjudication_raw,
|
|
947
|
+
roadmap=roadmap,
|
|
948
|
+
roadmap_raw=roadmap_raw,
|
|
949
|
+
claim_surface=claim_surface,
|
|
950
|
+
claim_surface_raw=claim_surface_raw,
|
|
951
|
+
base_raw=base_raw,
|
|
952
|
+
surfaces_by_id=surfaces_by_id,
|
|
953
|
+
)
|
|
954
|
+
records = author_state["records"]
|
|
955
|
+
claim_auths = author_state["claim_authorizations"]
|
|
956
|
+
collateral = author_state["collateral_authorizations"]
|
|
957
|
+
roadmap_items = {item["id"]: item for item in roadmap["items"]}
|
|
958
|
+
declined_by_block: dict[str, set[str]] = {}
|
|
959
|
+
for item_id, record in records.items():
|
|
960
|
+
if record["author_triage"] in DECLINED_TRIAGE:
|
|
961
|
+
for target in roadmap_items[item_id]["proposed_targets"]:
|
|
962
|
+
declined_by_block.setdefault(target["block_id"], set()).add(item_id)
|
|
963
|
+
surfaces_by_block: dict[str, list[dict]] = {}
|
|
964
|
+
for surface in surfaces_by_id.values():
|
|
965
|
+
surfaces_by_block.setdefault(surface["block_id"], []).append(surface)
|
|
966
|
+
|
|
967
|
+
used_claim_auths: set[str] = set()
|
|
968
|
+
used_collateral: set[str] = set()
|
|
969
|
+
protected_surfaces_checked = 0
|
|
970
|
+
for index, op in enumerate(patch.get("ops", [])):
|
|
971
|
+
cited = op.get("roadmap_item_ids", [])
|
|
972
|
+
if len(cited) != len(set(cited)):
|
|
973
|
+
failures.append(f"patch op {index}: duplicate roadmap_item_ids")
|
|
974
|
+
for item_id in cited:
|
|
975
|
+
record = records.get(item_id)
|
|
976
|
+
if record is None:
|
|
977
|
+
failures.append(f"patch op {index}: roadmap item {item_id} does not resolve")
|
|
978
|
+
elif record["author_triage"] != "will_address":
|
|
979
|
+
failures.append(f"patch op {index}: declined item {item_id} cannot authorize work")
|
|
980
|
+
elif not _op_authorized(record, op):
|
|
981
|
+
failures.append(
|
|
982
|
+
f"patch op {index}: target/op is outside accepted item {item_id}'s exact scope"
|
|
983
|
+
)
|
|
984
|
+
|
|
985
|
+
op_claim_auths: dict[str, dict] = {}
|
|
986
|
+
for move in op.get("claim_strength_changes", []):
|
|
987
|
+
auth_id = move["authorization_id"]
|
|
988
|
+
if auth_id in used_claim_auths:
|
|
989
|
+
failures.append(f"patch op {index}: claim authorization {auth_id} is reused")
|
|
990
|
+
used_claim_auths.add(auth_id)
|
|
991
|
+
target = claim_auths.get(auth_id)
|
|
992
|
+
if target is None:
|
|
993
|
+
failures.append(f"patch op {index}: claim authorization {auth_id} does not resolve")
|
|
994
|
+
continue
|
|
995
|
+
owner_item, authorization = target
|
|
996
|
+
if owner_item not in cited:
|
|
997
|
+
failures.append(
|
|
998
|
+
f"patch op {index}: claim authorization {auth_id} belongs to uncited item {owner_item}"
|
|
999
|
+
)
|
|
1000
|
+
if _claim_auth_projection(move) != _claim_auth_projection(authorization):
|
|
1001
|
+
failures.append(
|
|
1002
|
+
f"patch op {index}: claim move {auth_id} differs from exact author authorization"
|
|
1003
|
+
)
|
|
1004
|
+
if authorization["block_id"] != op["block_id"]:
|
|
1005
|
+
failures.append(f"patch op {index}: claim authorization {auth_id} targets another block")
|
|
1006
|
+
op_claim_auths[authorization["surface_id"]] = authorization
|
|
1007
|
+
|
|
1008
|
+
cited_collateral = op.get("collateral_authorization_ids", [])
|
|
1009
|
+
if len(cited_collateral) != len(set(cited_collateral)):
|
|
1010
|
+
failures.append(f"patch op {index}: duplicate collateral authorization ids")
|
|
1011
|
+
covered_declined: set[str] = set()
|
|
1012
|
+
for auth_id in cited_collateral:
|
|
1013
|
+
if auth_id in used_collateral:
|
|
1014
|
+
failures.append(f"patch op {index}: collateral authorization {auth_id} is reused")
|
|
1015
|
+
used_collateral.add(auth_id)
|
|
1016
|
+
authorization = collateral.get(auth_id)
|
|
1017
|
+
if authorization is None:
|
|
1018
|
+
failures.append(f"patch op {index}: collateral authorization {auth_id} does not resolve")
|
|
1019
|
+
continue
|
|
1020
|
+
if authorization["authorizing_item_id"] not in cited:
|
|
1021
|
+
failures.append(
|
|
1022
|
+
f"patch op {index}: collateral {auth_id} belongs to an uncited accepted item"
|
|
1023
|
+
)
|
|
1024
|
+
if (
|
|
1025
|
+
authorization["block_id"] != op["block_id"]
|
|
1026
|
+
or authorization["operation"] != op["op"]
|
|
1027
|
+
):
|
|
1028
|
+
failures.append(f"patch op {index}: collateral {auth_id} does not match exact target/op")
|
|
1029
|
+
covered_declined.add(authorization["constrained_item_id"])
|
|
1030
|
+
required_declined = declined_by_block.get(op["block_id"], set())
|
|
1031
|
+
if covered_declined != required_declined:
|
|
1032
|
+
missing = sorted(required_declined - covered_declined)
|
|
1033
|
+
extra = sorted(covered_declined - required_declined)
|
|
1034
|
+
failures.append(
|
|
1035
|
+
f"patch op {index}: declined no-touch coverage mismatch (missing {missing}, extra {extra})"
|
|
1036
|
+
)
|
|
1037
|
+
|
|
1038
|
+
touched_surfaces = surfaces_by_block.get(op["block_id"], [])
|
|
1039
|
+
touched_surface_ids = {surface["surface_id"] for surface in touched_surfaces}
|
|
1040
|
+
if set(op_claim_auths) - touched_surface_ids:
|
|
1041
|
+
failures.append(f"patch op {index}: claim authorization cites a surface outside target block")
|
|
1042
|
+
for surface in touched_surfaces:
|
|
1043
|
+
protected_surfaces_checked += 1
|
|
1044
|
+
authorization = op_claim_auths.get(surface["surface_id"])
|
|
1045
|
+
original = surface["original_text"]
|
|
1046
|
+
if op["op"] == "insert_after":
|
|
1047
|
+
if authorization is not None:
|
|
1048
|
+
failures.append(
|
|
1049
|
+
f"patch op {index}: insert_after cannot rewrite registered surface {surface['surface_id']}"
|
|
1050
|
+
)
|
|
1051
|
+
continue
|
|
1052
|
+
if op["op"] == "delete_block":
|
|
1053
|
+
if authorization is None or authorization["replacement_text"] != "":
|
|
1054
|
+
failures.append(
|
|
1055
|
+
f"patch op {index}: deleting registered surface {surface['surface_id']} requires exact empty replacement authorization"
|
|
1056
|
+
)
|
|
1057
|
+
continue
|
|
1058
|
+
new_text = op["new_text"]
|
|
1059
|
+
if authorization is None:
|
|
1060
|
+
if new_text.count(original) != 1:
|
|
1061
|
+
failures.append(
|
|
1062
|
+
f"patch op {index}: registered surface {surface['surface_id']} must remain exact or use authorization"
|
|
1063
|
+
)
|
|
1064
|
+
else:
|
|
1065
|
+
replacement = authorization["replacement_text"]
|
|
1066
|
+
if replacement == original:
|
|
1067
|
+
failures.append(
|
|
1068
|
+
f"patch op {index}: authorized claim replacement must differ from original bytes"
|
|
1069
|
+
)
|
|
1070
|
+
if original in new_text or new_text.count(replacement) != 1:
|
|
1071
|
+
failures.append(
|
|
1072
|
+
f"patch op {index}: claim authorization for {surface['surface_id']} must replace exact original once with exact approved bytes"
|
|
1073
|
+
)
|
|
1074
|
+
if failures:
|
|
1075
|
+
raise ContractError(failures)
|
|
1076
|
+
return {
|
|
1077
|
+
"status": "pass",
|
|
1078
|
+
**expected_bindings,
|
|
1079
|
+
"registered_claim_surfaces_checked": protected_surfaces_checked,
|
|
1080
|
+
"unregistered_claim_drift_review_required": True,
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
|
|
1084
|
+
def validate_integrity_correction_list(
|
|
1085
|
+
issue_list: dict,
|
|
1086
|
+
*,
|
|
1087
|
+
issue_list_raw: bytes,
|
|
1088
|
+
base_raw: bytes,
|
|
1089
|
+
) -> dict[str, dict]:
|
|
1090
|
+
failures = _schema_failures(issue_list, INTEGRITY_LIST_SCHEMA_PATH, "integrity correction list")
|
|
1091
|
+
if failures:
|
|
1092
|
+
raise ContractError(failures)
|
|
1093
|
+
if issue_list["base_draft_sha256"] != bytes_hash(base_raw):
|
|
1094
|
+
failures.append("integrity correction list base_draft_sha256 does not match base")
|
|
1095
|
+
_text, parsed = _parse_base(base_raw)
|
|
1096
|
+
valid_blocks = {block.block_id for block in parsed.blocks if block.block_id}
|
|
1097
|
+
valid_blocks.add("DOC-BODY-START")
|
|
1098
|
+
issues: dict[str, dict] = {}
|
|
1099
|
+
for issue in issue_list["issues"]:
|
|
1100
|
+
issue_id = issue["correction_id"]
|
|
1101
|
+
if issue_id in issues:
|
|
1102
|
+
failures.append(f"integrity correction list: duplicate correction_id {issue_id}")
|
|
1103
|
+
issues[issue_id] = issue
|
|
1104
|
+
_validate_target_list(
|
|
1105
|
+
issue["proposed_targets"],
|
|
1106
|
+
label=f"integrity correction {issue_id} proposed_targets",
|
|
1107
|
+
valid_block_ids=valid_blocks,
|
|
1108
|
+
failures=failures,
|
|
1109
|
+
)
|
|
1110
|
+
if failures:
|
|
1111
|
+
raise ContractError(failures)
|
|
1112
|
+
return issues
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
def validate_integrity_authorization(
|
|
1116
|
+
authorization: dict,
|
|
1117
|
+
*,
|
|
1118
|
+
authorization_raw: bytes,
|
|
1119
|
+
issue_list: dict,
|
|
1120
|
+
issue_list_raw: bytes,
|
|
1121
|
+
patch: dict,
|
|
1122
|
+
patch_raw: bytes,
|
|
1123
|
+
base_raw: bytes,
|
|
1124
|
+
) -> dict:
|
|
1125
|
+
"""Replay explicit author approval of one exact integrity patch."""
|
|
1126
|
+
failures = _schema_failures(
|
|
1127
|
+
authorization,
|
|
1128
|
+
INTEGRITY_AUTH_SCHEMA_PATH,
|
|
1129
|
+
"integrity correction authorization",
|
|
1130
|
+
)
|
|
1131
|
+
if failures:
|
|
1132
|
+
raise ContractError(failures)
|
|
1133
|
+
issues = validate_integrity_correction_list(
|
|
1134
|
+
issue_list,
|
|
1135
|
+
issue_list_raw=issue_list_raw,
|
|
1136
|
+
base_raw=base_raw,
|
|
1137
|
+
)
|
|
1138
|
+
patch_failures = _schema_failures(patch, PATCH_SCHEMA_PATH, "integrity patch")
|
|
1139
|
+
failures.extend(patch_failures)
|
|
1140
|
+
if authorization["revision_round"] != issue_list["revision_round"]:
|
|
1141
|
+
failures.append("integrity authorization revision_round does not match issue list")
|
|
1142
|
+
if authorization["base_draft_sha256"] != bytes_hash(base_raw):
|
|
1143
|
+
failures.append("integrity authorization base_draft_sha256 does not match base")
|
|
1144
|
+
if authorization["issue_list_sha256"] != bytes_hash(issue_list_raw):
|
|
1145
|
+
failures.append("integrity authorization issue_list_sha256 does not match exact bytes")
|
|
1146
|
+
if authorization["revision_patch_sha256"] != bytes_hash(patch_raw):
|
|
1147
|
+
failures.append("integrity authorization revision_patch_sha256 does not match exact patch bytes")
|
|
1148
|
+
if patch.get("authorization_context") != "integrity_correction":
|
|
1149
|
+
failures.append("integrity authorization requires an integrity_correction patch")
|
|
1150
|
+
if patch.get("issue_list_sha256") != bytes_hash(issue_list_raw):
|
|
1151
|
+
failures.append("integrity patch issue_list_sha256 does not match exact issue-list bytes")
|
|
1152
|
+
if patch.get("base_draft_hash") != base_draft_hash(base_raw):
|
|
1153
|
+
failures.append("integrity patch base_draft_hash does not match exact base bytes")
|
|
1154
|
+
if patch.get("revision_round") != issue_list["revision_round"]:
|
|
1155
|
+
failures.append("integrity patch revision_round does not match issue list")
|
|
1156
|
+
|
|
1157
|
+
event_ids = [event["event_id"] for event in authorization["author_events"]]
|
|
1158
|
+
if len(event_ids) != len(set(event_ids)):
|
|
1159
|
+
failures.append("integrity authorization author_events: duplicate event_id")
|
|
1160
|
+
event_set = set(event_ids)
|
|
1161
|
+
decisions: dict[str, dict] = {}
|
|
1162
|
+
for decision in authorization["author_decisions"]:
|
|
1163
|
+
correction_id = decision["correction_id"]
|
|
1164
|
+
if correction_id in decisions:
|
|
1165
|
+
failures.append(
|
|
1166
|
+
f"integrity authorization: duplicate correction_id {correction_id}"
|
|
1167
|
+
)
|
|
1168
|
+
decisions[correction_id] = decision
|
|
1169
|
+
issue = issues.get(correction_id)
|
|
1170
|
+
if issue is None:
|
|
1171
|
+
failures.append(
|
|
1172
|
+
f"integrity authorization correction_id {correction_id} does not resolve"
|
|
1173
|
+
)
|
|
1174
|
+
continue
|
|
1175
|
+
if decision["author_event_id"] not in event_set:
|
|
1176
|
+
failures.append(
|
|
1177
|
+
f"integrity authorization {correction_id}: author_event_id does not resolve"
|
|
1178
|
+
)
|
|
1179
|
+
_validate_target_list(
|
|
1180
|
+
decision["authorized_targets"],
|
|
1181
|
+
label=f"integrity authorization {correction_id} authorized_targets",
|
|
1182
|
+
valid_block_ids=None,
|
|
1183
|
+
failures=failures,
|
|
1184
|
+
)
|
|
1185
|
+
proposed = _target_map(issue["proposed_targets"])
|
|
1186
|
+
for target in decision["authorized_targets"]:
|
|
1187
|
+
proposed_ops = proposed.get(target["block_id"])
|
|
1188
|
+
if proposed_ops is None or not set(target["allowed_operations"]).issubset(
|
|
1189
|
+
proposed_ops
|
|
1190
|
+
):
|
|
1191
|
+
failures.append(
|
|
1192
|
+
f"integrity authorization {correction_id}: authorized target exceeds proposed scope"
|
|
1193
|
+
)
|
|
1194
|
+
if set(decisions) != set(issues):
|
|
1195
|
+
failures.append(
|
|
1196
|
+
"integrity authorization must contain exactly one author decision per correction"
|
|
1197
|
+
)
|
|
1198
|
+
if failures:
|
|
1199
|
+
raise ContractError(failures)
|
|
1200
|
+
return {
|
|
1201
|
+
"decisions": decisions,
|
|
1202
|
+
"integrity_authorization_sha256": bytes_hash(authorization_raw),
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
|
|
1206
|
+
def build_integrity_authorization(
|
|
1207
|
+
choice_input: dict,
|
|
1208
|
+
*,
|
|
1209
|
+
issue_list: dict,
|
|
1210
|
+
issue_list_raw: bytes,
|
|
1211
|
+
patch: dict,
|
|
1212
|
+
patch_raw: bytes,
|
|
1213
|
+
base_raw: bytes,
|
|
1214
|
+
) -> dict:
|
|
1215
|
+
failures = _schema_failures(
|
|
1216
|
+
choice_input,
|
|
1217
|
+
INTEGRITY_AUTH_INPUT_SCHEMA_PATH,
|
|
1218
|
+
"integrity correction authorization input",
|
|
1219
|
+
)
|
|
1220
|
+
if failures:
|
|
1221
|
+
raise ContractError(failures)
|
|
1222
|
+
if choice_input["revision_patch_sha256"] != bytes_hash(patch_raw):
|
|
1223
|
+
raise ContractError(
|
|
1224
|
+
[
|
|
1225
|
+
"integrity authorization input revision_patch_sha256 does not match exact proposed patch bytes"
|
|
1226
|
+
]
|
|
1227
|
+
)
|
|
1228
|
+
authorization = {
|
|
1229
|
+
"schema_version": "integrity-correction-authorization/1.0",
|
|
1230
|
+
"revision_round": issue_list["revision_round"],
|
|
1231
|
+
"base_draft_sha256": bytes_hash(base_raw),
|
|
1232
|
+
"issue_list_sha256": bytes_hash(issue_list_raw),
|
|
1233
|
+
"revision_patch_sha256": choice_input["revision_patch_sha256"],
|
|
1234
|
+
"author_events": copy.deepcopy(choice_input["author_events"]),
|
|
1235
|
+
"author_decisions": copy.deepcopy(choice_input["author_decisions"]),
|
|
1236
|
+
}
|
|
1237
|
+
validate_integrity_authorization(
|
|
1238
|
+
authorization,
|
|
1239
|
+
authorization_raw=canonical_bytes(authorization) + b"\n",
|
|
1240
|
+
issue_list=issue_list,
|
|
1241
|
+
issue_list_raw=issue_list_raw,
|
|
1242
|
+
patch=patch,
|
|
1243
|
+
patch_raw=patch_raw,
|
|
1244
|
+
base_raw=base_raw,
|
|
1245
|
+
)
|
|
1246
|
+
return authorization
|
|
1247
|
+
|
|
1248
|
+
|
|
1249
|
+
def validate_integrity_patch_authorization(
|
|
1250
|
+
patch: dict,
|
|
1251
|
+
*,
|
|
1252
|
+
patch_raw: bytes,
|
|
1253
|
+
base_raw: bytes,
|
|
1254
|
+
issue_list: dict,
|
|
1255
|
+
issue_list_raw: bytes,
|
|
1256
|
+
integrity_authorization: dict,
|
|
1257
|
+
integrity_authorization_raw: bytes,
|
|
1258
|
+
) -> dict:
|
|
1259
|
+
failures = _schema_failures(patch, PATCH_SCHEMA_PATH, "integrity patch")
|
|
1260
|
+
if failures:
|
|
1261
|
+
raise ContractError(failures)
|
|
1262
|
+
if patch.get("patch_format_version") != CURRENT_PATCH_VERSION:
|
|
1263
|
+
failures.append(f"integrity patch_format_version must be {CURRENT_PATCH_VERSION}")
|
|
1264
|
+
if patch.get("authorization_context") != "integrity_correction":
|
|
1265
|
+
failures.append("integrity patch authorization_context must be integrity_correction")
|
|
1266
|
+
if patch.get("issue_list_sha256") != bytes_hash(issue_list_raw):
|
|
1267
|
+
failures.append("integrity patch issue_list_sha256 does not match exact issue-list bytes")
|
|
1268
|
+
if patch.get("base_draft_hash") != base_draft_hash(base_raw):
|
|
1269
|
+
failures.append("integrity patch base_draft_hash does not match exact base bytes")
|
|
1270
|
+
if patch.get("revision_round") != issue_list["revision_round"]:
|
|
1271
|
+
failures.append("integrity patch revision_round does not match issue list")
|
|
1272
|
+
authorization_state = validate_integrity_authorization(
|
|
1273
|
+
integrity_authorization,
|
|
1274
|
+
authorization_raw=integrity_authorization_raw,
|
|
1275
|
+
issue_list=issue_list,
|
|
1276
|
+
issue_list_raw=issue_list_raw,
|
|
1277
|
+
patch=patch,
|
|
1278
|
+
patch_raw=patch_raw,
|
|
1279
|
+
base_raw=base_raw,
|
|
1280
|
+
)
|
|
1281
|
+
decisions = authorization_state["decisions"]
|
|
1282
|
+
for index, op in enumerate(patch.get("ops", [])):
|
|
1283
|
+
if op.get("claim_strength_changes"):
|
|
1284
|
+
failures.append(f"integrity patch op {index}: claim-strength changes are forbidden")
|
|
1285
|
+
if op.get("collateral_authorization_ids"):
|
|
1286
|
+
failures.append(f"integrity patch op {index}: collateral ids are forbidden")
|
|
1287
|
+
cited = op.get("roadmap_item_ids", [])
|
|
1288
|
+
if len(cited) != len(set(cited)):
|
|
1289
|
+
failures.append(f"integrity patch op {index}: duplicate correction ids")
|
|
1290
|
+
for correction_id in cited:
|
|
1291
|
+
decision = decisions.get(correction_id)
|
|
1292
|
+
if decision is None:
|
|
1293
|
+
failures.append(
|
|
1294
|
+
f"integrity patch op {index}: correction id {correction_id} does not resolve"
|
|
1295
|
+
)
|
|
1296
|
+
elif decision["decision"] != "authorize":
|
|
1297
|
+
failures.append(
|
|
1298
|
+
f"integrity patch op {index}: correction {correction_id} was stop_without_write"
|
|
1299
|
+
)
|
|
1300
|
+
elif op["op"] not in _target_map(decision["authorized_targets"]).get(
|
|
1301
|
+
op["block_id"], set()
|
|
1302
|
+
):
|
|
1303
|
+
failures.append(
|
|
1304
|
+
f"integrity patch op {index}: target/op exceeds correction {correction_id} scope"
|
|
1305
|
+
)
|
|
1306
|
+
if failures:
|
|
1307
|
+
raise ContractError(failures)
|
|
1308
|
+
return {
|
|
1309
|
+
"status": "pass",
|
|
1310
|
+
"authorization_kind": "explicit_author_exact_integrity_patch",
|
|
1311
|
+
"issue_list_sha256": bytes_hash(issue_list_raw),
|
|
1312
|
+
"integrity_authorization_sha256": bytes_hash(integrity_authorization_raw),
|
|
1313
|
+
"revision_patch_sha256": bytes_hash(patch_raw),
|
|
1314
|
+
"unregistered_claim_drift_review_required": True,
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
|
|
1318
|
+
def _validate_apply_report(
|
|
1319
|
+
report: dict,
|
|
1320
|
+
*,
|
|
1321
|
+
patch: dict,
|
|
1322
|
+
patch_raw: bytes,
|
|
1323
|
+
pre_raw: bytes,
|
|
1324
|
+
post_raw: bytes,
|
|
1325
|
+
witness: dict,
|
|
1326
|
+
label: str,
|
|
1327
|
+
) -> list[str]:
|
|
1328
|
+
failures: list[str] = []
|
|
1329
|
+
expected = {
|
|
1330
|
+
"report_format_version": CURRENT_REPORT_VERSION,
|
|
1331
|
+
"mode": "patch",
|
|
1332
|
+
"base_draft_hash": base_draft_hash(pre_raw),
|
|
1333
|
+
"output_draft_hash": base_draft_hash(post_raw),
|
|
1334
|
+
"patch_digest": bytes_hash(patch_raw),
|
|
1335
|
+
"revision_round": patch["revision_round"],
|
|
1336
|
+
"authorization_witness": witness,
|
|
1337
|
+
}
|
|
1338
|
+
for field, value in expected.items():
|
|
1339
|
+
if report.get(field) != value:
|
|
1340
|
+
failures.append(f"{label}: {field} does not match replayed value")
|
|
1341
|
+
return failures
|
|
1342
|
+
|
|
1343
|
+
|
|
1344
|
+
def _replay_patch_and_report(
|
|
1345
|
+
*,
|
|
1346
|
+
patch: dict,
|
|
1347
|
+
pre_raw: bytes,
|
|
1348
|
+
post_raw: bytes,
|
|
1349
|
+
report: dict,
|
|
1350
|
+
label: str,
|
|
1351
|
+
) -> list[str]:
|
|
1352
|
+
"""Re-run the deterministic patch engine and recompute report mechanics.
|
|
1353
|
+
|
|
1354
|
+
Authorization replay alone proves that a patch was permitted; it does not
|
|
1355
|
+
prove that the declared post draft is what that patch produces. Bundle
|
|
1356
|
+
validation therefore runs the pure validate/apply functions in memory and
|
|
1357
|
+
compares both output bytes and every mechanically derived report field.
|
|
1358
|
+
"""
|
|
1359
|
+
from scripts.ars_apply_revision_patch import ( # local: avoids import cycle
|
|
1360
|
+
ApplyRejection,
|
|
1361
|
+
apply_patch as apply_patch_bytes,
|
|
1362
|
+
validate_patch,
|
|
1363
|
+
)
|
|
1364
|
+
|
|
1365
|
+
failures: list[str] = []
|
|
1366
|
+
structural = report.get("structural_flags")
|
|
1367
|
+
if not isinstance(structural, dict):
|
|
1368
|
+
return [f"{label}: structural_flags must be an object"]
|
|
1369
|
+
threshold = structural.get("touched_ratio_threshold")
|
|
1370
|
+
if threshold is not None and (
|
|
1371
|
+
isinstance(threshold, bool)
|
|
1372
|
+
or not isinstance(threshold, (int, float))
|
|
1373
|
+
or not math.isfinite(threshold)
|
|
1374
|
+
or not 0.0 <= threshold <= 1.0
|
|
1375
|
+
):
|
|
1376
|
+
return [f"{label}: touched_ratio_threshold must be null or finite in [0, 1]"]
|
|
1377
|
+
acknowledged = structural.get("acknowledged")
|
|
1378
|
+
if not isinstance(acknowledged, bool):
|
|
1379
|
+
return [f"{label}: structural_flags.acknowledged must be boolean"]
|
|
1380
|
+
|
|
1381
|
+
try:
|
|
1382
|
+
pre_text, parsed = _parse_base(pre_raw, f"{label} pre draft")
|
|
1383
|
+
analysis = validate_patch(
|
|
1384
|
+
patch,
|
|
1385
|
+
pre_raw,
|
|
1386
|
+
parsed,
|
|
1387
|
+
touched_ratio_threshold=threshold,
|
|
1388
|
+
)
|
|
1389
|
+
replayed_text, phase2 = apply_patch_bytes(pre_text, parsed, analysis)
|
|
1390
|
+
except ApplyRejection as exc:
|
|
1391
|
+
details = "; ".join(
|
|
1392
|
+
f"{row.get('kind')}: {row.get('message')}" for row in exc.failures
|
|
1393
|
+
)
|
|
1394
|
+
return [f"{label}: deterministic patch replay rejected ({details})"]
|
|
1395
|
+
except ContractError as exc:
|
|
1396
|
+
return [f"{label}: deterministic patch replay rejected ({'; '.join(exc.failures)})"]
|
|
1397
|
+
|
|
1398
|
+
replayed_raw = replayed_text.encode("utf-8")
|
|
1399
|
+
if replayed_raw != post_raw:
|
|
1400
|
+
failures.append(f"{label}: deterministic patch output bytes do not equal post_round_draft")
|
|
1401
|
+
|
|
1402
|
+
replayed_flags = copy.deepcopy(analysis["structural_flags"])
|
|
1403
|
+
replayed_flags["acknowledged"] = acknowledged
|
|
1404
|
+
if replayed_flags["any"] and not acknowledged:
|
|
1405
|
+
failures.append(
|
|
1406
|
+
f"{label}: structural patch could not have produced a report without acknowledgement"
|
|
1407
|
+
)
|
|
1408
|
+
counters_base = analysis["counters_base"]
|
|
1409
|
+
total = counters_base["blocks_total"]
|
|
1410
|
+
touched = counters_base["blocks_touched"]
|
|
1411
|
+
preserved = total - touched
|
|
1412
|
+
expected = {
|
|
1413
|
+
"authorization_context": patch["authorization_context"],
|
|
1414
|
+
"ops_applied": phase2["ops_applied"],
|
|
1415
|
+
"fresh_block_ids": phase2["fresh_block_ids"],
|
|
1416
|
+
"pure_move_pairs": phase2["pure_move_pairs"],
|
|
1417
|
+
"structural_flags": replayed_flags,
|
|
1418
|
+
"counters": {
|
|
1419
|
+
"blocks_total": total,
|
|
1420
|
+
"blocks_touched": touched,
|
|
1421
|
+
"blocks_preserved_byte_identical": preserved,
|
|
1422
|
+
"preserved_ratio": round(preserved / total, 4) if total else 0.0,
|
|
1423
|
+
},
|
|
1424
|
+
}
|
|
1425
|
+
for field, value in expected.items():
|
|
1426
|
+
if report.get(field) != value:
|
|
1427
|
+
failures.append(f"{label}: {field} does not match deterministic replay")
|
|
1428
|
+
return failures
|
|
1429
|
+
|
|
1430
|
+
|
|
1431
|
+
def validate_bundle(bundle: dict, *, root: Path) -> None:
|
|
1432
|
+
failures = _schema_failures(bundle, BUNDLE_SCHEMA_PATH, "bundle")
|
|
1433
|
+
if failures:
|
|
1434
|
+
raise ContractError(failures)
|
|
1435
|
+
store = ArtifactStore(root)
|
|
1436
|
+
try:
|
|
1437
|
+
start_draft = store.read(bundle["chain_start"]["draft"], "chain_start.draft")
|
|
1438
|
+
start_manifest_artifact = store.read(
|
|
1439
|
+
bundle["chain_start"]["block_manifest"], "chain_start.block_manifest"
|
|
1440
|
+
)
|
|
1441
|
+
start_manifest = start_manifest_artifact.json("chain-start block manifest")
|
|
1442
|
+
validate_block_manifest(start_manifest, start_manifest_artifact.raw, start_draft.raw)
|
|
1443
|
+
receipt_artifact = store.read(
|
|
1444
|
+
bundle["chain_start"]["integrity_pass_receipt"],
|
|
1445
|
+
"chain_start.integrity_pass_receipt",
|
|
1446
|
+
)
|
|
1447
|
+
receipt = receipt_artifact.json("chain-start integrity PASS receipt")
|
|
1448
|
+
failures.extend(
|
|
1449
|
+
_schema_failures(receipt, INTEGRITY_RECEIPT_SCHEMA_PATH, "integrity PASS receipt")
|
|
1450
|
+
)
|
|
1451
|
+
if receipt.get("checked_draft_sha256") != bytes_hash(start_draft.raw):
|
|
1452
|
+
failures.append("chain-start integrity receipt is not bound to chain-start draft")
|
|
1453
|
+
except ContractError as exc:
|
|
1454
|
+
failures.extend(exc.failures)
|
|
1455
|
+
raise ContractError(failures)
|
|
1456
|
+
|
|
1457
|
+
expected_round = bundle["chain_start"]["first_revision_round"]
|
|
1458
|
+
prior_post = start_draft
|
|
1459
|
+
for index, entry in enumerate(bundle["rounds"]):
|
|
1460
|
+
label = f"rounds[{index}]"
|
|
1461
|
+
try:
|
|
1462
|
+
if entry["revision_round"] != expected_round:
|
|
1463
|
+
raise ContractError(
|
|
1464
|
+
[f"bundle {label}: revision rounds must be continuous from chain start"]
|
|
1465
|
+
)
|
|
1466
|
+
expected_round += 1
|
|
1467
|
+
pre = store.read(entry["pre_round_draft"], f"{label}.pre_round_draft")
|
|
1468
|
+
if bytes_hash(pre.raw) != bytes_hash(prior_post.raw):
|
|
1469
|
+
raise ContractError([f"bundle {label}: pre draft does not equal prior post draft"])
|
|
1470
|
+
manifest_artifact = store.read(
|
|
1471
|
+
entry["pre_round_block_manifest"], f"{label}.pre_round_block_manifest"
|
|
1472
|
+
)
|
|
1473
|
+
manifest = manifest_artifact.json(f"bundle {label} block manifest")
|
|
1474
|
+
validate_block_manifest(manifest, manifest_artifact.raw, pre.raw)
|
|
1475
|
+
post = store.read(entry["post_round_draft"], f"{label}.post_round_draft")
|
|
1476
|
+
|
|
1477
|
+
if entry["kind"] in ("review_roadmap", "review_noop"):
|
|
1478
|
+
roadmap_artifact = store.read(
|
|
1479
|
+
entry["revision_roadmap"], f"{label}.revision_roadmap"
|
|
1480
|
+
)
|
|
1481
|
+
roadmap = roadmap_artifact.json(f"bundle {label} roadmap")
|
|
1482
|
+
validate_roadmap(
|
|
1483
|
+
roadmap,
|
|
1484
|
+
roadmap_raw=roadmap_artifact.raw,
|
|
1485
|
+
base_raw=pre.raw,
|
|
1486
|
+
block_manifest=manifest,
|
|
1487
|
+
block_manifest_raw=manifest_artifact.raw,
|
|
1488
|
+
)
|
|
1489
|
+
if roadmap["revision_round"] != entry["revision_round"]:
|
|
1490
|
+
raise ContractError([f"bundle {label}: roadmap revision_round mismatch"])
|
|
1491
|
+
claim_artifact = store.read(
|
|
1492
|
+
entry["claim_surface_manifest"], f"{label}.claim_surface_manifest"
|
|
1493
|
+
)
|
|
1494
|
+
claim_surface = claim_artifact.json(f"bundle {label} claim surface")
|
|
1495
|
+
surfaces = validate_claim_surface_manifest(
|
|
1496
|
+
claim_surface,
|
|
1497
|
+
claim_surface_raw=claim_artifact.raw,
|
|
1498
|
+
roadmap=roadmap,
|
|
1499
|
+
roadmap_raw=roadmap_artifact.raw,
|
|
1500
|
+
base_raw=pre.raw,
|
|
1501
|
+
artifact_store=store,
|
|
1502
|
+
)
|
|
1503
|
+
author_artifact = store.read(
|
|
1504
|
+
entry["author_adjudication"], f"{label}.author_adjudication"
|
|
1505
|
+
)
|
|
1506
|
+
adjudication = author_artifact.json(f"bundle {label} author adjudication")
|
|
1507
|
+
author_state = validate_author_adjudication(
|
|
1508
|
+
adjudication,
|
|
1509
|
+
adjudication_raw=author_artifact.raw,
|
|
1510
|
+
roadmap=roadmap,
|
|
1511
|
+
roadmap_raw=roadmap_artifact.raw,
|
|
1512
|
+
claim_surface=claim_surface,
|
|
1513
|
+
claim_surface_raw=claim_artifact.raw,
|
|
1514
|
+
base_raw=pre.raw,
|
|
1515
|
+
surfaces_by_id=surfaces,
|
|
1516
|
+
)
|
|
1517
|
+
if entry["kind"] == "review_noop":
|
|
1518
|
+
if any(
|
|
1519
|
+
record["author_triage"] == "will_address"
|
|
1520
|
+
for record in author_state["records"].values()
|
|
1521
|
+
):
|
|
1522
|
+
raise ContractError(
|
|
1523
|
+
[f"bundle {label}: review_noop requires zero will_address decisions"]
|
|
1524
|
+
)
|
|
1525
|
+
if pre.raw != post.raw:
|
|
1526
|
+
raise ContractError(
|
|
1527
|
+
[f"bundle {label}: review_noop pre/post draft bytes must be identical"]
|
|
1528
|
+
)
|
|
1529
|
+
else:
|
|
1530
|
+
patch_artifact = store.read(
|
|
1531
|
+
entry["revision_patch"], f"{label}.revision_patch"
|
|
1532
|
+
)
|
|
1533
|
+
patch = patch_artifact.json(f"bundle {label} patch")
|
|
1534
|
+
witness = validate_review_patch_authorization(
|
|
1535
|
+
patch,
|
|
1536
|
+
base_raw=pre.raw,
|
|
1537
|
+
roadmap=roadmap,
|
|
1538
|
+
roadmap_raw=roadmap_artifact.raw,
|
|
1539
|
+
adjudication=adjudication,
|
|
1540
|
+
adjudication_raw=author_artifact.raw,
|
|
1541
|
+
claim_surface=claim_surface,
|
|
1542
|
+
claim_surface_raw=claim_artifact.raw,
|
|
1543
|
+
surfaces_by_id=surfaces,
|
|
1544
|
+
)
|
|
1545
|
+
report_artifact = store.read(
|
|
1546
|
+
entry["apply_report"], f"{label}.apply_report"
|
|
1547
|
+
)
|
|
1548
|
+
report = report_artifact.json(f"bundle {label} apply report")
|
|
1549
|
+
failures.extend(
|
|
1550
|
+
_validate_apply_report(
|
|
1551
|
+
report,
|
|
1552
|
+
patch=patch,
|
|
1553
|
+
patch_raw=patch_artifact.raw,
|
|
1554
|
+
pre_raw=pre.raw,
|
|
1555
|
+
post_raw=post.raw,
|
|
1556
|
+
witness=witness,
|
|
1557
|
+
label=f"bundle {label} apply report",
|
|
1558
|
+
)
|
|
1559
|
+
)
|
|
1560
|
+
failures.extend(
|
|
1561
|
+
_replay_patch_and_report(
|
|
1562
|
+
patch=patch,
|
|
1563
|
+
pre_raw=pre.raw,
|
|
1564
|
+
post_raw=post.raw,
|
|
1565
|
+
report=report,
|
|
1566
|
+
label=f"bundle {label} apply replay",
|
|
1567
|
+
)
|
|
1568
|
+
)
|
|
1569
|
+
else:
|
|
1570
|
+
issue_artifact = store.read(entry["issue_list"], f"{label}.issue_list")
|
|
1571
|
+
issue_list = issue_artifact.json(f"bundle {label} integrity issue list")
|
|
1572
|
+
if issue_list.get("revision_round") != entry["revision_round"]:
|
|
1573
|
+
raise ContractError(
|
|
1574
|
+
[f"bundle {label}: integrity issue-list revision_round mismatch"]
|
|
1575
|
+
)
|
|
1576
|
+
patch_artifact = store.read(entry["revision_patch"], f"{label}.revision_patch")
|
|
1577
|
+
patch = patch_artifact.json(f"bundle {label} patch")
|
|
1578
|
+
integrity_authorization_artifact = store.read(
|
|
1579
|
+
entry["integrity_authorization"],
|
|
1580
|
+
f"{label}.integrity_authorization",
|
|
1581
|
+
)
|
|
1582
|
+
integrity_authorization = integrity_authorization_artifact.json(
|
|
1583
|
+
f"bundle {label} integrity authorization"
|
|
1584
|
+
)
|
|
1585
|
+
witness = validate_integrity_patch_authorization(
|
|
1586
|
+
patch,
|
|
1587
|
+
patch_raw=patch_artifact.raw,
|
|
1588
|
+
base_raw=pre.raw,
|
|
1589
|
+
issue_list=issue_list,
|
|
1590
|
+
issue_list_raw=issue_artifact.raw,
|
|
1591
|
+
integrity_authorization=integrity_authorization,
|
|
1592
|
+
integrity_authorization_raw=integrity_authorization_artifact.raw,
|
|
1593
|
+
)
|
|
1594
|
+
report_artifact = store.read(entry["apply_report"], f"{label}.apply_report")
|
|
1595
|
+
report = report_artifact.json(f"bundle {label} apply report")
|
|
1596
|
+
failures.extend(
|
|
1597
|
+
_validate_apply_report(
|
|
1598
|
+
report,
|
|
1599
|
+
patch=patch,
|
|
1600
|
+
patch_raw=patch_artifact.raw,
|
|
1601
|
+
pre_raw=pre.raw,
|
|
1602
|
+
post_raw=post.raw,
|
|
1603
|
+
witness=witness,
|
|
1604
|
+
label=f"bundle {label} apply report",
|
|
1605
|
+
)
|
|
1606
|
+
)
|
|
1607
|
+
failures.extend(
|
|
1608
|
+
_replay_patch_and_report(
|
|
1609
|
+
patch=patch,
|
|
1610
|
+
pre_raw=pre.raw,
|
|
1611
|
+
post_raw=post.raw,
|
|
1612
|
+
report=report,
|
|
1613
|
+
label=f"bundle {label} apply replay",
|
|
1614
|
+
)
|
|
1615
|
+
)
|
|
1616
|
+
prior_post = post
|
|
1617
|
+
except ContractError as exc:
|
|
1618
|
+
failures.extend(exc.failures)
|
|
1619
|
+
try:
|
|
1620
|
+
final = store.read(bundle["final_draft"], "final_draft")
|
|
1621
|
+
if final.raw != prior_post.raw:
|
|
1622
|
+
failures.append("bundle final_draft does not equal last round post draft")
|
|
1623
|
+
except ContractError as exc:
|
|
1624
|
+
failures.extend(exc.failures)
|
|
1625
|
+
if failures:
|
|
1626
|
+
raise ContractError(failures)
|
|
1627
|
+
|
|
1628
|
+
|
|
1629
|
+
_CONSEQUENCE_PHRASES = {
|
|
1630
|
+
"acceptance_criterion_unmet": "specified acceptance criterion remains unmet",
|
|
1631
|
+
"evidence_gap_remains": "identified evidence gap remains",
|
|
1632
|
+
"claim_scope_unsupported": "registered claim scope remains unsupported",
|
|
1633
|
+
"method_reproducibility_unresolved": "method reproducibility remains unresolved",
|
|
1634
|
+
"reporting_requirement_unmet": "specified reporting requirement remains unmet",
|
|
1635
|
+
"editorial_conformance_unmet": "editorial conformance requirement remains unmet",
|
|
1636
|
+
"interpretive_ambiguity_remains": "identified interpretive ambiguity remains",
|
|
1637
|
+
"reader_traceability_reduced": "reader traceability remains reduced",
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
|
|
1641
|
+
def _md(value: Any) -> str:
|
|
1642
|
+
return str(value).replace("\r", " ").replace("\n", " ").replace("|", "\\|")
|
|
1643
|
+
|
|
1644
|
+
|
|
1645
|
+
def _cost_label(value: dict) -> str:
|
|
1646
|
+
labels = {
|
|
1647
|
+
"sentence": "sentence",
|
|
1648
|
+
"section": "section",
|
|
1649
|
+
"re_analysis": "re-analysis",
|
|
1650
|
+
"new_data": "new data",
|
|
1651
|
+
"other": f"other ({value.get('surface_id', 'declared')})",
|
|
1652
|
+
}
|
|
1653
|
+
return f"{labels[value['kind']]} — {_md(value['locator'])}"
|
|
1654
|
+
|
|
1655
|
+
|
|
1656
|
+
def _render_target_rows(targets: list[dict]) -> list[str]:
|
|
1657
|
+
return [
|
|
1658
|
+
" - {block}: {operations}".format(
|
|
1659
|
+
block=_md(target["block_id"]),
|
|
1660
|
+
operations=", ".join(_md(op) for op in target["allowed_operations"]),
|
|
1661
|
+
)
|
|
1662
|
+
for target in targets
|
|
1663
|
+
]
|
|
1664
|
+
|
|
1665
|
+
|
|
1666
|
+
def render_markdown(
|
|
1667
|
+
roadmap: dict,
|
|
1668
|
+
adjudication: dict | None = None,
|
|
1669
|
+
*,
|
|
1670
|
+
adjudication_raw: bytes | None = None,
|
|
1671
|
+
roadmap_raw: bytes | None = None,
|
|
1672
|
+
claim_surface: dict | None = None,
|
|
1673
|
+
claim_surface_raw: bytes | None = None,
|
|
1674
|
+
base_raw: bytes | None = None,
|
|
1675
|
+
surfaces_by_id: dict[str, dict] | None = None,
|
|
1676
|
+
) -> str:
|
|
1677
|
+
validate_roadmap(roadmap)
|
|
1678
|
+
records: dict[str, dict] = {}
|
|
1679
|
+
if adjudication is None:
|
|
1680
|
+
display = {"mode": "source_traceability", "item_ids": [item["id"] for item in roadmap["items"]]}
|
|
1681
|
+
else:
|
|
1682
|
+
required_inputs = {
|
|
1683
|
+
"adjudication_raw": adjudication_raw,
|
|
1684
|
+
"roadmap_raw": roadmap_raw,
|
|
1685
|
+
"claim_surface": claim_surface,
|
|
1686
|
+
"claim_surface_raw": claim_surface_raw,
|
|
1687
|
+
"base_raw": base_raw,
|
|
1688
|
+
"surfaces_by_id": surfaces_by_id,
|
|
1689
|
+
}
|
|
1690
|
+
missing = [name for name, value in required_inputs.items() if value is None]
|
|
1691
|
+
if missing:
|
|
1692
|
+
raise ContractError(
|
|
1693
|
+
[f"renderer: exact author-sidecar replay inputs required ({', '.join(missing)})"]
|
|
1694
|
+
)
|
|
1695
|
+
author_state = validate_author_adjudication(
|
|
1696
|
+
adjudication,
|
|
1697
|
+
adjudication_raw=adjudication_raw,
|
|
1698
|
+
roadmap=roadmap,
|
|
1699
|
+
roadmap_raw=roadmap_raw,
|
|
1700
|
+
claim_surface=claim_surface,
|
|
1701
|
+
claim_surface_raw=claim_surface_raw,
|
|
1702
|
+
base_raw=base_raw,
|
|
1703
|
+
surfaces_by_id=surfaces_by_id,
|
|
1704
|
+
)
|
|
1705
|
+
records = author_state["records"]
|
|
1706
|
+
display = adjudication["display_order"]
|
|
1707
|
+
by_id = {item["id"]: item for item in roadmap["items"]}
|
|
1708
|
+
lines = [
|
|
1709
|
+
"# Revision Roadmap",
|
|
1710
|
+
"",
|
|
1711
|
+
"> View order is presentation-only and changes no obligation or revision authority.",
|
|
1712
|
+
"",
|
|
1713
|
+
f"- Editorial decision: {_md(roadmap['editorial_decision'])}",
|
|
1714
|
+
f"- Revision round: {roadmap['revision_round']}",
|
|
1715
|
+
f"- View: {_md(display['mode'])}",
|
|
1716
|
+
"",
|
|
1717
|
+
"| Ref | Obligation class | Severity | Cost scope | Consequence if unaddressed | Author triage | Author reason |",
|
|
1718
|
+
"|---|---|---|---|---|---|---|",
|
|
1719
|
+
]
|
|
1720
|
+
for item_id in display["item_ids"]:
|
|
1721
|
+
item = by_id[item_id]
|
|
1722
|
+
decision = records.get(item_id)
|
|
1723
|
+
triage = decision["author_triage"] if decision else "PENDING AUTHOR DECISION"
|
|
1724
|
+
reason = decision.get("author_reason", "—") if decision else "—"
|
|
1725
|
+
consequence = item["consequence_if_unaddressed"]
|
|
1726
|
+
target = consequence["target"]
|
|
1727
|
+
consequence_text = (
|
|
1728
|
+
f"{_CONSEQUENCE_PHRASES[consequence['code']]} at "
|
|
1729
|
+
f"{_md(target['kind'])} {_md(target['locator'])}"
|
|
1730
|
+
)
|
|
1731
|
+
lines.append(
|
|
1732
|
+
"| {ref} | {obligation} | {severity} | {cost} | {consequence} | {triage} | {reason} |".format(
|
|
1733
|
+
ref=_md(item_id),
|
|
1734
|
+
obligation=_md(item["obligation_class"]),
|
|
1735
|
+
severity=_md(item.get("severity", "not-applicable")),
|
|
1736
|
+
cost=_cost_label(item["cost_scope"]),
|
|
1737
|
+
consequence=consequence_text,
|
|
1738
|
+
triage=_md(triage),
|
|
1739
|
+
reason=_md(reason),
|
|
1740
|
+
)
|
|
1741
|
+
)
|
|
1742
|
+
lines.extend(
|
|
1743
|
+
[
|
|
1744
|
+
"",
|
|
1745
|
+
f"## {_md(item_id)} — {_md(item['description'])}",
|
|
1746
|
+
"",
|
|
1747
|
+
f"- Source reviewer(s): {_md(item['reviewer'])}",
|
|
1748
|
+
f"- Target section: {_md(item['target_section'])}",
|
|
1749
|
+
f"- Suggested action: {_md(item['suggested_action'])}",
|
|
1750
|
+
f"- Verification criteria: {_md(item['verification_criteria'])}",
|
|
1751
|
+
"- Proposed targets (proposal only; no write authority):",
|
|
1752
|
+
]
|
|
1753
|
+
)
|
|
1754
|
+
lines.extend(_render_target_rows(item["proposed_targets"]))
|
|
1755
|
+
if decision is None:
|
|
1756
|
+
lines.append("- Exact authorized targets: PENDING AUTHOR DECISION — no write authority")
|
|
1757
|
+
elif decision["authorized_targets"]:
|
|
1758
|
+
lines.append("- Exact authorized targets:")
|
|
1759
|
+
lines.extend(_render_target_rows(decision["authorized_targets"]))
|
|
1760
|
+
else:
|
|
1761
|
+
lines.append("- Exact authorized targets: none — no write authority")
|
|
1762
|
+
if decision and decision["claim_strength_authorizations"]:
|
|
1763
|
+
lines.append("- Exact registered claim-surface authorizations:")
|
|
1764
|
+
for authorization in decision["claim_strength_authorizations"]:
|
|
1765
|
+
lines.append(
|
|
1766
|
+
" - {aid}: {manifest}/{claim}/{surface}, {before} → {after} ({direction})".format(
|
|
1767
|
+
aid=_md(authorization["authorization_id"]),
|
|
1768
|
+
manifest=_md(authorization["scoped_manifest_id"]),
|
|
1769
|
+
claim=_md(authorization["claim_id"]),
|
|
1770
|
+
surface=_md(authorization["surface_id"]),
|
|
1771
|
+
before=_md(authorization["from_rung"]),
|
|
1772
|
+
after=_md(authorization["to_rung"]),
|
|
1773
|
+
direction=_md(authorization["direction"]),
|
|
1774
|
+
)
|
|
1775
|
+
)
|
|
1776
|
+
return "\n".join(lines) + "\n"
|
|
1777
|
+
|
|
1778
|
+
|
|
1779
|
+
def _standalone_store(root: Path) -> ArtifactStore:
|
|
1780
|
+
return ArtifactStore(root)
|
|
1781
|
+
|
|
1782
|
+
|
|
1783
|
+
def _load_core_inputs(args: argparse.Namespace) -> tuple[dict, bytes, bytes, dict, bytes]:
|
|
1784
|
+
roadmap, roadmap_raw = load_json_path(args.roadmap, "roadmap")
|
|
1785
|
+
base_raw = _read_path_once(args.base, "base draft")
|
|
1786
|
+
block_manifest, block_raw = load_json_path(args.block_manifest, "block manifest")
|
|
1787
|
+
validate_roadmap(
|
|
1788
|
+
roadmap,
|
|
1789
|
+
roadmap_raw=roadmap_raw,
|
|
1790
|
+
base_raw=base_raw,
|
|
1791
|
+
block_manifest=block_manifest,
|
|
1792
|
+
block_manifest_raw=block_raw,
|
|
1793
|
+
)
|
|
1794
|
+
return roadmap, roadmap_raw, base_raw, block_manifest, block_raw
|
|
1795
|
+
|
|
1796
|
+
|
|
1797
|
+
def main(argv: list[str] | None = None) -> int:
|
|
1798
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
1799
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
1800
|
+
|
|
1801
|
+
core_parent = argparse.ArgumentParser(add_help=False)
|
|
1802
|
+
core_parent.add_argument("roadmap", type=Path)
|
|
1803
|
+
core_parent.add_argument("--base", type=Path, required=True)
|
|
1804
|
+
core_parent.add_argument("--block-manifest", type=Path, required=True)
|
|
1805
|
+
|
|
1806
|
+
sub.add_parser("validate-roadmap", parents=[core_parent])
|
|
1807
|
+
|
|
1808
|
+
p_build = sub.add_parser("build-adjudication", parents=[core_parent])
|
|
1809
|
+
p_build.add_argument("--claim-surface", type=Path, required=True)
|
|
1810
|
+
p_build.add_argument("--author-choices", type=Path, required=True)
|
|
1811
|
+
p_build.add_argument("--artifact-root", type=Path, required=True)
|
|
1812
|
+
p_build.add_argument("--output", type=Path, required=True)
|
|
1813
|
+
|
|
1814
|
+
p_author = sub.add_parser("validate-adjudication", parents=[core_parent])
|
|
1815
|
+
p_author.add_argument("adjudication", type=Path)
|
|
1816
|
+
p_author.add_argument("--claim-surface", type=Path, required=True)
|
|
1817
|
+
p_author.add_argument("--artifact-root", type=Path, required=True)
|
|
1818
|
+
|
|
1819
|
+
p_render = sub.add_parser("render", parents=[core_parent])
|
|
1820
|
+
p_render.add_argument("--adjudication", type=Path)
|
|
1821
|
+
p_render.add_argument("--claim-surface", type=Path, required=True)
|
|
1822
|
+
p_render.add_argument("--artifact-root", type=Path, required=True)
|
|
1823
|
+
|
|
1824
|
+
integrity_parent = argparse.ArgumentParser(add_help=False)
|
|
1825
|
+
integrity_parent.add_argument("issue_list", type=Path)
|
|
1826
|
+
integrity_parent.add_argument("--base", type=Path, required=True)
|
|
1827
|
+
integrity_parent.add_argument("--patch", type=Path, required=True)
|
|
1828
|
+
|
|
1829
|
+
p_integrity_build = sub.add_parser(
|
|
1830
|
+
"build-integrity-authorization", parents=[integrity_parent]
|
|
1831
|
+
)
|
|
1832
|
+
p_integrity_build.add_argument("--author-choices", type=Path, required=True)
|
|
1833
|
+
p_integrity_build.add_argument("--output", type=Path, required=True)
|
|
1834
|
+
|
|
1835
|
+
p_integrity_validate = sub.add_parser(
|
|
1836
|
+
"validate-integrity-authorization", parents=[integrity_parent]
|
|
1837
|
+
)
|
|
1838
|
+
p_integrity_validate.add_argument("authorization", type=Path)
|
|
1839
|
+
|
|
1840
|
+
p_bundle = sub.add_parser("validate-bundle")
|
|
1841
|
+
p_bundle.add_argument("bundle", type=Path)
|
|
1842
|
+
p_bundle.add_argument("--root", type=Path)
|
|
1843
|
+
|
|
1844
|
+
args = parser.parse_args(argv)
|
|
1845
|
+
try:
|
|
1846
|
+
if args.command in (
|
|
1847
|
+
"build-integrity-authorization",
|
|
1848
|
+
"validate-integrity-authorization",
|
|
1849
|
+
):
|
|
1850
|
+
base_raw = _read_path_once(args.base, "base draft")
|
|
1851
|
+
issue_list, issue_list_raw = load_json_path(
|
|
1852
|
+
args.issue_list, "integrity correction list"
|
|
1853
|
+
)
|
|
1854
|
+
patch, patch_raw = load_json_path(args.patch, "integrity patch")
|
|
1855
|
+
if args.command == "build-integrity-authorization":
|
|
1856
|
+
if args.output.exists():
|
|
1857
|
+
raise ContractError(
|
|
1858
|
+
["build-integrity-authorization output already exists"]
|
|
1859
|
+
)
|
|
1860
|
+
choices, _choices_raw = load_json_path(
|
|
1861
|
+
args.author_choices,
|
|
1862
|
+
"integrity correction authorization input",
|
|
1863
|
+
)
|
|
1864
|
+
authorization = build_integrity_authorization(
|
|
1865
|
+
choices,
|
|
1866
|
+
issue_list=issue_list,
|
|
1867
|
+
issue_list_raw=issue_list_raw,
|
|
1868
|
+
patch=patch,
|
|
1869
|
+
patch_raw=patch_raw,
|
|
1870
|
+
base_raw=base_raw,
|
|
1871
|
+
)
|
|
1872
|
+
atomic_write_bytes(
|
|
1873
|
+
args.output, canonical_bytes(authorization) + b"\n"
|
|
1874
|
+
)
|
|
1875
|
+
print(f"integrity correction authorization built: {args.output}")
|
|
1876
|
+
else:
|
|
1877
|
+
authorization, authorization_raw = load_json_path(
|
|
1878
|
+
args.authorization, "integrity correction authorization"
|
|
1879
|
+
)
|
|
1880
|
+
validate_integrity_authorization(
|
|
1881
|
+
authorization,
|
|
1882
|
+
authorization_raw=authorization_raw,
|
|
1883
|
+
issue_list=issue_list,
|
|
1884
|
+
issue_list_raw=issue_list_raw,
|
|
1885
|
+
patch=patch,
|
|
1886
|
+
patch_raw=patch_raw,
|
|
1887
|
+
base_raw=base_raw,
|
|
1888
|
+
)
|
|
1889
|
+
print("integrity correction authorization ok")
|
|
1890
|
+
return 0
|
|
1891
|
+
if args.command == "validate-bundle":
|
|
1892
|
+
bundle, _raw = load_json_path(args.bundle, "bundle")
|
|
1893
|
+
validate_bundle(bundle, root=args.root or args.bundle.parent)
|
|
1894
|
+
print("revision evidence bundle ok")
|
|
1895
|
+
return 0
|
|
1896
|
+
|
|
1897
|
+
roadmap, roadmap_raw, base_raw, _manifest, _manifest_raw = _load_core_inputs(args)
|
|
1898
|
+
if args.command == "validate-roadmap":
|
|
1899
|
+
print("revision roadmap ok")
|
|
1900
|
+
else:
|
|
1901
|
+
claim_surface, claim_raw = load_json_path(args.claim_surface, "claim surface manifest")
|
|
1902
|
+
store = _standalone_store(args.artifact_root)
|
|
1903
|
+
surfaces = validate_claim_surface_manifest(
|
|
1904
|
+
claim_surface,
|
|
1905
|
+
claim_surface_raw=claim_raw,
|
|
1906
|
+
roadmap=roadmap,
|
|
1907
|
+
roadmap_raw=roadmap_raw,
|
|
1908
|
+
base_raw=base_raw,
|
|
1909
|
+
artifact_store=store,
|
|
1910
|
+
)
|
|
1911
|
+
if args.command == "render":
|
|
1912
|
+
author = None
|
|
1913
|
+
author_raw = None
|
|
1914
|
+
if args.adjudication is not None:
|
|
1915
|
+
author, author_raw = load_json_path(
|
|
1916
|
+
args.adjudication, "author adjudication"
|
|
1917
|
+
)
|
|
1918
|
+
sys.stdout.write(
|
|
1919
|
+
render_markdown(
|
|
1920
|
+
roadmap,
|
|
1921
|
+
author,
|
|
1922
|
+
adjudication_raw=author_raw,
|
|
1923
|
+
roadmap_raw=roadmap_raw,
|
|
1924
|
+
claim_surface=claim_surface,
|
|
1925
|
+
claim_surface_raw=claim_raw,
|
|
1926
|
+
base_raw=base_raw,
|
|
1927
|
+
surfaces_by_id=surfaces,
|
|
1928
|
+
)
|
|
1929
|
+
)
|
|
1930
|
+
elif args.command == "build-adjudication":
|
|
1931
|
+
if args.output.exists():
|
|
1932
|
+
raise ContractError(["build-adjudication output already exists"])
|
|
1933
|
+
choices, _choices_raw = load_json_path(args.author_choices, "author choice input")
|
|
1934
|
+
adjudication = build_author_adjudication(
|
|
1935
|
+
choices,
|
|
1936
|
+
roadmap=roadmap,
|
|
1937
|
+
roadmap_raw=roadmap_raw,
|
|
1938
|
+
claim_surface=claim_surface,
|
|
1939
|
+
claim_surface_raw=claim_raw,
|
|
1940
|
+
base_raw=base_raw,
|
|
1941
|
+
surfaces_by_id=surfaces,
|
|
1942
|
+
)
|
|
1943
|
+
atomic_write_bytes(args.output, canonical_bytes(adjudication) + b"\n")
|
|
1944
|
+
print(f"author adjudication built: {args.output}")
|
|
1945
|
+
else:
|
|
1946
|
+
author, author_raw = load_json_path(args.adjudication, "author adjudication")
|
|
1947
|
+
validate_author_adjudication(
|
|
1948
|
+
author,
|
|
1949
|
+
adjudication_raw=author_raw,
|
|
1950
|
+
roadmap=roadmap,
|
|
1951
|
+
roadmap_raw=roadmap_raw,
|
|
1952
|
+
claim_surface=claim_surface,
|
|
1953
|
+
claim_surface_raw=claim_raw,
|
|
1954
|
+
base_raw=base_raw,
|
|
1955
|
+
surfaces_by_id=surfaces,
|
|
1956
|
+
)
|
|
1957
|
+
print("author adjudication ok")
|
|
1958
|
+
except ContractError as exc:
|
|
1959
|
+
print("revision authority contract invalid", file=sys.stderr)
|
|
1960
|
+
for failure in exc.failures:
|
|
1961
|
+
print(f" - {failure}", file=sys.stderr)
|
|
1962
|
+
return 2
|
|
1963
|
+
return 0
|
|
1964
|
+
|
|
1965
|
+
|
|
1966
|
+
if __name__ == "__main__":
|
|
1967
|
+
raise SystemExit(main())
|