psyclaw 0.27.22 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1048) hide show
  1. package/README.md +11 -5
  2. package/dist/apps/panel/index.html +2 -2
  3. package/dist/src/adapters/pi/extension.js +225 -92
  4. package/dist/src/adapters/pi/extension.js.map +1 -1
  5. package/dist/src/agents/import.js +44 -32
  6. package/dist/src/agents/import.js.map +1 -1
  7. package/dist/src/analysis/hooks.d.ts +1 -0
  8. package/dist/src/analysis/hooks.js +20 -1
  9. package/dist/src/analysis/hooks.js.map +1 -1
  10. package/dist/src/ars/bridge.d.ts +20 -0
  11. package/dist/src/ars/bridge.js +132 -0
  12. package/dist/src/ars/bridge.js.map +1 -0
  13. package/dist/src/ars/contracts.d.ts +55 -0
  14. package/dist/src/ars/contracts.js +2 -0
  15. package/dist/src/ars/contracts.js.map +1 -0
  16. package/dist/src/ars/panel-plan.d.ts +4 -0
  17. package/dist/src/ars/panel-plan.js +11 -0
  18. package/dist/src/ars/panel-plan.js.map +1 -0
  19. package/dist/src/ars/pi-panel-executor.d.ts +30 -0
  20. package/dist/src/ars/pi-panel-executor.js +140 -0
  21. package/dist/src/ars/pi-panel-executor.js.map +1 -0
  22. package/dist/src/ars/profile.d.ts +36 -0
  23. package/dist/src/ars/profile.js +119 -0
  24. package/dist/src/ars/profile.js.map +1 -0
  25. package/dist/src/ars/re-review.d.ts +22 -0
  26. package/dist/src/ars/re-review.js +172 -0
  27. package/dist/src/ars/re-review.js.map +1 -0
  28. package/dist/src/branding.d.ts +2 -4
  29. package/dist/src/branding.js +3 -5
  30. package/dist/src/branding.js.map +1 -1
  31. package/dist/src/bundled-tools.d.ts +3 -0
  32. package/dist/src/bundled-tools.js +21 -0
  33. package/dist/src/bundled-tools.js.map +1 -0
  34. package/dist/src/chat.js +6 -5
  35. package/dist/src/chat.js.map +1 -1
  36. package/dist/src/creation/contracts.d.ts +38 -0
  37. package/dist/src/creation/contracts.js +2 -0
  38. package/dist/src/creation/contracts.js.map +1 -0
  39. package/dist/src/creation/service.d.ts +7 -0
  40. package/dist/src/creation/service.js +196 -0
  41. package/dist/src/creation/service.js.map +1 -0
  42. package/dist/src/index.d.ts +10 -0
  43. package/dist/src/index.js +10 -0
  44. package/dist/src/index.js.map +1 -1
  45. package/dist/src/install/installer.js +32 -10
  46. package/dist/src/install/installer.js.map +1 -1
  47. package/dist/src/orchestration/personas.d.ts +15 -0
  48. package/dist/src/orchestration/personas.js +51 -0
  49. package/dist/src/orchestration/personas.js.map +1 -0
  50. package/dist/src/orchestration/pi-executor.d.ts +1 -0
  51. package/dist/src/orchestration/pi-executor.js +1 -1
  52. package/dist/src/orchestration/pi-executor.js.map +1 -1
  53. package/dist/src/panel/extension.js +29 -8
  54. package/dist/src/panel/extension.js.map +1 -1
  55. package/dist/src/panel/server.js +14 -5
  56. package/dist/src/panel/server.js.map +1 -1
  57. package/dist/src/project/paths.d.ts +3 -0
  58. package/dist/src/project/paths.js +7 -0
  59. package/dist/src/project/paths.js.map +1 -1
  60. package/dist/src/rules/user-rules.d.ts +8 -0
  61. package/dist/src/rules/user-rules.js +36 -0
  62. package/dist/src/rules/user-rules.js.map +1 -0
  63. package/dist/src/skills/contracts.d.ts +4 -4
  64. package/dist/src/skills/recommended.js +1 -1
  65. package/dist/src/skills/registry.js +49 -28
  66. package/dist/src/skills/registry.js.map +1 -1
  67. package/dist/src/style/cli-ui.js +0 -1
  68. package/dist/src/style/cli-ui.js.map +1 -1
  69. package/package.json +14 -3
  70. package/scripts/rebrand-pi.mjs +6 -0
  71. package/skills/recommended/catalog.json +2 -11
  72. package/vendor/ars/.claude/CLAUDE.md +371 -0
  73. package/vendor/ars/.command-invariants.toml +24 -0
  74. package/vendor/ars/CITATION.cff +35 -0
  75. package/vendor/ars/LICENSE +417 -0
  76. package/vendor/ars/MODE_REGISTRY.md +76 -0
  77. package/vendor/ars/NOTICE.md +26 -0
  78. package/vendor/ars/POSITIONING.md +99 -0
  79. package/vendor/ars/PSYCLAW_SOURCE.json +10 -0
  80. package/vendor/ars/README.md +751 -0
  81. package/vendor/ars/SECURITY.md +52 -0
  82. package/vendor/ars/THIRD_PARTY.md +70 -0
  83. package/vendor/ars/academic-paper/SKILL.md +542 -0
  84. package/vendor/ars/academic-paper/agents/abstract_bilingual_agent.md +171 -0
  85. package/vendor/ars/academic-paper/agents/argument_builder_agent.md +276 -0
  86. package/vendor/ars/academic-paper/agents/citation_compliance_agent.md +422 -0
  87. package/vendor/ars/academic-paper/agents/draft_writer_agent.md +656 -0
  88. package/vendor/ars/academic-paper/agents/formatter_agent.md +999 -0
  89. package/vendor/ars/academic-paper/agents/intake_agent.md +393 -0
  90. package/vendor/ars/academic-paper/agents/literature_strategist_agent.md +626 -0
  91. package/vendor/ars/academic-paper/agents/peer_reviewer_agent.md +516 -0
  92. package/vendor/ars/academic-paper/agents/revision_coach_agent.md +334 -0
  93. package/vendor/ars/academic-paper/agents/socratic_mentor_agent.md +527 -0
  94. package/vendor/ars/academic-paper/agents/structure_architect_agent.md +401 -0
  95. package/vendor/ars/academic-paper/agents/visualization_agent.md +441 -0
  96. package/vendor/ars/academic-paper/examples/chinese_paper_example.md +278 -0
  97. package/vendor/ars/academic-paper/examples/clinical_citation_verification_checklist.md +95 -0
  98. package/vendor/ars/academic-paper/examples/clinical_epistemic_status_example.md +100 -0
  99. package/vendor/ars/academic-paper/examples/commitment_ledger_example.md +147 -0
  100. package/vendor/ars/academic-paper/examples/imrad_hei_example.md +234 -0
  101. package/vendor/ars/academic-paper/examples/literature_review_example.md +260 -0
  102. package/vendor/ars/academic-paper/examples/plan_mode_guided_writing.md +600 -0
  103. package/vendor/ars/academic-paper/examples/revision_mode_example.md +344 -0
  104. package/vendor/ars/academic-paper/examples/revision_recovery_example.md +506 -0
  105. package/vendor/ars/academic-paper/examples/version_family_reconciliation_example.md +89 -0
  106. package/vendor/ars/academic-paper/references/abstract_writing_guide.md +169 -0
  107. package/vendor/ars/academic-paper/references/academic_writing_style.md +188 -0
  108. package/vendor/ars/academic-paper/references/anti_leakage_protocol.md +83 -0
  109. package/vendor/ars/academic-paper/references/apa7_chinese_citation_guide.md +364 -0
  110. package/vendor/ars/academic-paper/references/apa7_extended_guide.md +198 -0
  111. package/vendor/ars/academic-paper/references/changelog.md +11 -0
  112. package/vendor/ars/academic-paper/references/citation_format_switcher.md +228 -0
  113. package/vendor/ars/academic-paper/references/committee_correspondence_protocol.md +158 -0
  114. package/vendor/ars/academic-paper/references/credit_authorship_guide.md +308 -0
  115. package/vendor/ars/academic-paper/references/disclosure_mode_protocol.md +478 -0
  116. package/vendor/ars/academic-paper/references/domain_evidence_profiles.md +38 -0
  117. package/vendor/ars/academic-paper/references/failure_paths.md +349 -0
  118. package/vendor/ars/academic-paper/references/funding_statement_guide.md +319 -0
  119. package/vendor/ars/academic-paper/references/hei_domain_glossary.md +169 -0
  120. package/vendor/ars/academic-paper/references/intro_title_rhetoric_guide.md +114 -0
  121. package/vendor/ars/academic-paper/references/journal_submission_guide.md +249 -0
  122. package/vendor/ars/academic-paper/references/latex_template_reference.md +378 -0
  123. package/vendor/ars/academic-paper/references/mode_selection_guide.md +378 -0
  124. package/vendor/ars/academic-paper/references/paper_structure_patterns.md +330 -0
  125. package/vendor/ars/academic-paper/references/plan_mode_protocol.md +112 -0
  126. package/vendor/ars/academic-paper/references/policy_anchor_disclosure_protocol.md +200 -0
  127. package/vendor/ars/academic-paper/references/policy_anchor_table.md +157 -0
  128. package/vendor/ars/academic-paper/references/revision_patch_protocol.md +173 -0
  129. package/vendor/ars/academic-paper/references/statistical_visualization_standards.md +750 -0
  130. package/vendor/ars/academic-paper/references/venue_disclosure_policies.md +259 -0
  131. package/vendor/ars/academic-paper/references/vlm_figure_verification.md +126 -0
  132. package/vendor/ars/academic-paper/references/workflow_phase_details.md +135 -0
  133. package/vendor/ars/academic-paper/references/writing_judgment_framework.md +59 -0
  134. package/vendor/ars/academic-paper/references/writing_quality_check.md +173 -0
  135. package/vendor/ars/academic-paper/templates/bilingual_abstract_template.md +78 -0
  136. package/vendor/ars/academic-paper/templates/case_study_template.md +129 -0
  137. package/vendor/ars/academic-paper/templates/conference_paper_template.md +108 -0
  138. package/vendor/ars/academic-paper/templates/credit_statement_template.md +132 -0
  139. package/vendor/ars/academic-paper/templates/funding_statement_template.md +290 -0
  140. package/vendor/ars/academic-paper/templates/imrad_template.md +183 -0
  141. package/vendor/ars/academic-paper/templates/latex_article_template.tex +199 -0
  142. package/vendor/ars/academic-paper/templates/literature_review_template.md +135 -0
  143. package/vendor/ars/academic-paper/templates/policy_brief_template.md +139 -0
  144. package/vendor/ars/academic-paper/templates/revision_tracking_template.md +199 -0
  145. package/vendor/ars/academic-paper/templates/theoretical_paper_template.md +119 -0
  146. package/vendor/ars/academic-paper-reviewer/SKILL.md +491 -0
  147. package/vendor/ars/academic-paper-reviewer/agents/devils_advocate_reviewer_agent.md +443 -0
  148. package/vendor/ars/academic-paper-reviewer/agents/domain_reviewer_agent.md +412 -0
  149. package/vendor/ars/academic-paper-reviewer/agents/editorial_synthesizer_agent.md +478 -0
  150. package/vendor/ars/academic-paper-reviewer/agents/eic_agent.md +339 -0
  151. package/vendor/ars/academic-paper-reviewer/agents/field_analyst_agent.md +221 -0
  152. package/vendor/ars/academic-paper-reviewer/agents/methodology_reviewer_agent.md +449 -0
  153. package/vendor/ars/academic-paper-reviewer/agents/perspective_reviewer_agent.md +427 -0
  154. package/vendor/ars/academic-paper-reviewer/examples/hei_paper_review_example.md +391 -0
  155. package/vendor/ars/academic-paper-reviewer/examples/interdisciplinary_review_example.md +299 -0
  156. package/vendor/ars/academic-paper-reviewer/examples/subclaim_decomposition_example.md +80 -0
  157. package/vendor/ars/academic-paper-reviewer/references/calibration_mode_protocol.md +256 -0
  158. package/vendor/ars/academic-paper-reviewer/references/changelog.md +10 -0
  159. package/vendor/ars/academic-paper-reviewer/references/editorial_decision_standards.md +236 -0
  160. package/vendor/ars/academic-paper-reviewer/references/guided_mode_protocol.md +34 -0
  161. package/vendor/ars/academic-paper-reviewer/references/integration_guide.md +15 -0
  162. package/vendor/ars/academic-paper-reviewer/references/quality_rubrics.md +84 -0
  163. package/vendor/ars/academic-paper-reviewer/references/re_review_mode_protocol.md +340 -0
  164. package/vendor/ars/academic-paper-reviewer/references/review_criteria_framework.md +98 -0
  165. package/vendor/ars/academic-paper-reviewer/references/review_panel_provenance_protocol.md +197 -0
  166. package/vendor/ars/academic-paper-reviewer/references/review_quality_thinking.md +58 -0
  167. package/vendor/ars/academic-paper-reviewer/references/reviewer_sprint_prompt_source.md +324 -0
  168. package/vendor/ars/academic-paper-reviewer/references/sprint_contract_protocol.md +296 -0
  169. package/vendor/ars/academic-paper-reviewer/references/statistical_reporting_standards.md +505 -0
  170. package/vendor/ars/academic-paper-reviewer/references/top_journals_by_field.md +206 -0
  171. package/vendor/ars/academic-paper-reviewer/templates/editorial_decision_template.md +235 -0
  172. package/vendor/ars/academic-paper-reviewer/templates/peer_review_report_template.md +305 -0
  173. package/vendor/ars/academic-paper-reviewer/templates/revision_response_template.md +248 -0
  174. package/vendor/ars/academic-pipeline/SKILL.md +736 -0
  175. package/vendor/ars/academic-pipeline/agents/claim_ref_alignment_audit_agent.md +382 -0
  176. package/vendor/ars/academic-pipeline/agents/collaboration_depth_agent.md +164 -0
  177. package/vendor/ars/academic-pipeline/agents/integrity_verification_agent.md +870 -0
  178. package/vendor/ars/academic-pipeline/agents/pipeline_orchestrator_agent.md +1379 -0
  179. package/vendor/ars/academic-pipeline/agents/state_tracker_agent.md +622 -0
  180. package/vendor/ars/academic-pipeline/examples/full_pipeline_example.md +482 -0
  181. package/vendor/ars/academic-pipeline/examples/integrity_failure_recovery.md +389 -0
  182. package/vendor/ars/academic-pipeline/examples/mid_entry_example.md +414 -0
  183. package/vendor/ars/academic-pipeline/references/adapters/.gitkeep +0 -0
  184. package/vendor/ars/academic-pipeline/references/adapters/overview.md +153 -0
  185. package/vendor/ars/academic-pipeline/references/ai_research_failure_modes.md +185 -0
  186. package/vendor/ars/academic-pipeline/references/changelog.md +14 -0
  187. package/vendor/ars/academic-pipeline/references/claim_audit_calibration_protocol.md +175 -0
  188. package/vendor/ars/academic-pipeline/references/claim_verification_protocol.md +282 -0
  189. package/vendor/ars/academic-pipeline/references/external_review_protocol.md +131 -0
  190. package/vendor/ars/academic-pipeline/references/integrity_review_protocol.md +110 -0
  191. package/vendor/ars/academic-pipeline/references/literature_corpus_consumers.md +193 -0
  192. package/vendor/ars/academic-pipeline/references/mode_advisor.md +135 -0
  193. package/vendor/ars/academic-pipeline/references/passport_as_reset_boundary.md +132 -0
  194. package/vendor/ars/academic-pipeline/references/pipeline_state_machine.md +405 -0
  195. package/vendor/ars/academic-pipeline/references/plagiarism_detection_protocol.md +239 -0
  196. package/vendor/ars/academic-pipeline/references/process_summary_protocol.md +209 -0
  197. package/vendor/ars/academic-pipeline/references/progress_dashboard_template.md +38 -0
  198. package/vendor/ars/academic-pipeline/references/reinforcement_content.md +15 -0
  199. package/vendor/ars/academic-pipeline/references/reproducibility_audit.md +55 -0
  200. package/vendor/ars/academic-pipeline/references/score_trajectory_protocol.md +78 -0
  201. package/vendor/ars/academic-pipeline/references/team_collaboration_protocol.md +261 -0
  202. package/vendor/ars/academic-pipeline/references/two_stage_review_protocol.md +27 -0
  203. package/vendor/ars/academic-pipeline/templates/pipeline_status_template.md +146 -0
  204. package/vendor/ars/agents/report_compiler_agent.md +341 -0
  205. package/vendor/ars/agents/research_architect_agent.md +298 -0
  206. package/vendor/ars/agents/synthesis_agent.md +356 -0
  207. package/vendor/ars/commands/ars-3w.md +10 -0
  208. package/vendor/ars/commands/ars-abstract.md +10 -0
  209. package/vendor/ars/commands/ars-cache-invalidate.md +20 -0
  210. package/vendor/ars/commands/ars-citation-check.md +10 -0
  211. package/vendor/ars/commands/ars-disclosure.md +10 -0
  212. package/vendor/ars/commands/ars-format-convert.md +10 -0
  213. package/vendor/ars/commands/ars-full.md +9 -0
  214. package/vendor/ars/commands/ars-lit-review.md +12 -0
  215. package/vendor/ars/commands/ars-mark-read.md +18 -0
  216. package/vendor/ars/commands/ars-outline.md +10 -0
  217. package/vendor/ars/commands/ars-plan.md +10 -0
  218. package/vendor/ars/commands/ars-rebuttal-audit.md +12 -0
  219. package/vendor/ars/commands/ars-reviewer.md +9 -0
  220. package/vendor/ars/commands/ars-revision-coach.md +9 -0
  221. package/vendor/ars/commands/ars-revision.md +10 -0
  222. package/vendor/ars/commands/ars-unmark-read.md +16 -0
  223. package/vendor/ars/deep-research/SKILL.md +600 -0
  224. package/vendor/ars/deep-research/agents/bibliography_agent.md +473 -0
  225. package/vendor/ars/deep-research/agents/devils_advocate_agent.md +192 -0
  226. package/vendor/ars/deep-research/agents/editor_in_chief_agent.md +167 -0
  227. package/vendor/ars/deep-research/agents/ethics_review_agent.md +267 -0
  228. package/vendor/ars/deep-research/agents/meta_analysis_agent.md +325 -0
  229. package/vendor/ars/deep-research/agents/monitoring_agent.md +209 -0
  230. package/vendor/ars/deep-research/agents/report_compiler_agent.md +341 -0
  231. package/vendor/ars/deep-research/agents/research_architect_agent.md +298 -0
  232. package/vendor/ars/deep-research/agents/research_question_agent.md +216 -0
  233. package/vendor/ars/deep-research/agents/risk_of_bias_agent.md +231 -0
  234. package/vendor/ars/deep-research/agents/socratic_mentor_agent.md +764 -0
  235. package/vendor/ars/deep-research/agents/source_verification_agent.md +219 -0
  236. package/vendor/ars/deep-research/agents/synthesis_agent.md +356 -0
  237. package/vendor/ars/deep-research/agents/timeline_extraction_agent.md +99 -0
  238. package/vendor/ars/deep-research/examples/exploratory_research.md +157 -0
  239. package/vendor/ars/deep-research/examples/fact_check_mode.md +173 -0
  240. package/vendor/ars/deep-research/examples/handoff_to_paper.md +318 -0
  241. package/vendor/ars/deep-research/examples/idea_diversity_coverage_gap_advisory.md +64 -0
  242. package/vendor/ars/deep-research/examples/policy_analysis.md +161 -0
  243. package/vendor/ars/deep-research/examples/review_mode.md +253 -0
  244. package/vendor/ars/deep-research/examples/socratic_guided_research.md +331 -0
  245. package/vendor/ars/deep-research/examples/systematic_review.md +133 -0
  246. package/vendor/ars/deep-research/references/apa7_style_guide.md +162 -0
  247. package/vendor/ars/deep-research/references/argumentation_reasoning_framework.md +68 -0
  248. package/vendor/ars/deep-research/references/arxiv_api_protocol.md +76 -0
  249. package/vendor/ars/deep-research/references/changelog.md +22 -0
  250. package/vendor/ars/deep-research/references/chinese_literature_api_protocol.md +317 -0
  251. package/vendor/ars/deep-research/references/cross_agent_quality_definitions.md +14 -0
  252. package/vendor/ars/deep-research/references/crossref_api_protocol.md +84 -0
  253. package/vendor/ars/deep-research/references/equator_reporting_guidelines.md +482 -0
  254. package/vendor/ars/deep-research/references/ethics_checklist.md +282 -0
  255. package/vendor/ars/deep-research/references/failure_paths.md +355 -0
  256. package/vendor/ars/deep-research/references/interdisciplinary_bridges.md +292 -0
  257. package/vendor/ars/deep-research/references/irb_decision_tree.md +315 -0
  258. package/vendor/ars/deep-research/references/literature_monitoring_strategies.md +263 -0
  259. package/vendor/ars/deep-research/references/logical_fallacies.md +192 -0
  260. package/vendor/ars/deep-research/references/methodology_patterns.md +462 -0
  261. package/vendor/ars/deep-research/references/mode_selection_guide.md +331 -0
  262. package/vendor/ars/deep-research/references/openalex_api_protocol.md +82 -0
  263. package/vendor/ars/deep-research/references/preregistration_guide.md +324 -0
  264. package/vendor/ars/deep-research/references/semantic_scholar_api_protocol.md +107 -0
  265. package/vendor/ars/deep-research/references/socratic_mode_protocol.md +99 -0
  266. package/vendor/ars/deep-research/references/socratic_questioning_framework.md +232 -0
  267. package/vendor/ars/deep-research/references/source_quality_hierarchy.md +188 -0
  268. package/vendor/ars/deep-research/references/systematic_review_protocol.md +95 -0
  269. package/vendor/ars/deep-research/references/systematic_review_toolkit.md +353 -0
  270. package/vendor/ars/deep-research/templates/evidence_assessment_template.md +127 -0
  271. package/vendor/ars/deep-research/templates/literature_matrix_template.md +85 -0
  272. package/vendor/ars/deep-research/templates/preregistration_template.md +318 -0
  273. package/vendor/ars/deep-research/templates/prisma_protocol_template.md +248 -0
  274. package/vendor/ars/deep-research/templates/prisma_report_template.md +415 -0
  275. package/vendor/ars/deep-research/templates/research_brief_template.md +93 -0
  276. package/vendor/ars/package.json +24 -0
  277. package/vendor/ars/pi/README.md +161 -0
  278. package/vendor/ars/pi/package.json +26 -0
  279. package/vendor/ars/pi/wrapper.js +193 -0
  280. package/vendor/ars/pi/wrapper.test.mjs +201 -0
  281. package/vendor/ars/pyproject.toml +2 -0
  282. package/vendor/ars/requirements-pdf-content-classifier.txt +5 -0
  283. package/vendor/ars/scripts/_block_parser.py +396 -0
  284. package/vendor/ars/scripts/_ci_pytest_manifest.toml +661 -0
  285. package/vendor/ars/scripts/_claim_audit_constants.py +268 -0
  286. package/vendor/ars/scripts/_e4_evidence.py +110 -0
  287. package/vendor/ars/scripts/_eval_threshold_gate.py +73 -0
  288. package/vendor/ars/scripts/_markdown_lint_util.py +224 -0
  289. package/vendor/ars/scripts/_next_verified_at_ms.py +176 -0
  290. package/vendor/ars/scripts/_passport_yaml.py +53 -0
  291. package/vendor/ars/scripts/_skill_lint.py +254 -0
  292. package/vendor/ars/scripts/_text_similarity.py +141 -0
  293. package/vendor/ars/scripts/adapters/README.md +89 -0
  294. package/vendor/ars/scripts/adapters/_common.py +209 -0
  295. package/vendor/ars/scripts/adapters/examples/folder_scan/expected_passport.yaml +25 -0
  296. package/vendor/ars/scripts/adapters/examples/folder_scan/expected_rejection_log.yaml +18 -0
  297. package/vendor/ars/scripts/adapters/examples/folder_scan/input_fixture/Chen2024_AIAssessment.pdf +0 -0
  298. package/vendor/ars/scripts/adapters/examples/folder_scan/input_fixture/Wang_2023_formative_feedback.pdf +0 -0
  299. package/vendor/ars/scripts/adapters/examples/folder_scan/input_fixture/paper1.pdf +0 -0
  300. 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
  301. package/vendor/ars/scripts/adapters/examples/obsidian/expected_passport.yaml +40 -0
  302. package/vendor/ars/scripts/adapters/examples/obsidian/expected_rejection_log.yaml +13 -0
  303. package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/.gitkeep +0 -0
  304. package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/.obsidian/app.json +1 -0
  305. package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/_templates/tmpl.md +7 -0
  306. package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/chen2024ai.md +13 -0
  307. package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/invalid.md +1 -0
  308. package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/wang2023formative.md +10 -0
  309. package/vendor/ars/scripts/adapters/examples/zotero/expected_passport.yaml +34 -0
  310. package/vendor/ars/scripts/adapters/examples/zotero/expected_rejection_log.yaml +34 -0
  311. package/vendor/ars/scripts/adapters/examples/zotero/input_fixture/.gitkeep +0 -0
  312. package/vendor/ars/scripts/adapters/examples/zotero/input_fixture/export.json +43 -0
  313. package/vendor/ars/scripts/adapters/folder_scan.py +214 -0
  314. package/vendor/ars/scripts/adapters/obsidian.py +336 -0
  315. package/vendor/ars/scripts/adapters/tests/.gitkeep +0 -0
  316. package/vendor/ars/scripts/adapters/tests/conftest.py +77 -0
  317. package/vendor/ars/scripts/adapters/tests/test_check_corpus_consumer_protocol.py +632 -0
  318. package/vendor/ars/scripts/adapters/tests/test_check_literature_corpus_schema.py +631 -0
  319. package/vendor/ars/scripts/adapters/tests/test_common.py +365 -0
  320. package/vendor/ars/scripts/adapters/tests/test_conftest.py +96 -0
  321. package/vendor/ars/scripts/adapters/tests/test_folder_scan.py +260 -0
  322. package/vendor/ars/scripts/adapters/tests/test_literature_corpus_entry_schema.py +745 -0
  323. package/vendor/ars/scripts/adapters/tests/test_obsidian.py +357 -0
  324. package/vendor/ars/scripts/adapters/tests/test_rejection_log_schema.py +271 -0
  325. package/vendor/ars/scripts/adapters/tests/test_sync_adapter_docs.py +88 -0
  326. package/vendor/ars/scripts/adapters/tests/test_zotero.py +454 -0
  327. package/vendor/ars/scripts/adapters/zotero.py +318 -0
  328. package/vendor/ars/scripts/adjudication_activity.py +1592 -0
  329. package/vendor/ars/scripts/announce-ars-loaded.sh +144 -0
  330. package/vendor/ars/scripts/ars_anchorize_draft.py +170 -0
  331. package/vendor/ars/scripts/ars_apply_revision_patch.py +912 -0
  332. package/vendor/ars/scripts/ars_cache_invalidate.py +40 -0
  333. package/vendor/ars/scripts/ars_mark_read.py +521 -0
  334. package/vendor/ars/scripts/ars_phase_scope_manifest.json +33 -0
  335. package/vendor/ars/scripts/ars_update_check.sh +215 -0
  336. package/vendor/ars/scripts/ars_write_scope_guard.py +506 -0
  337. package/vendor/ars/scripts/arxiv_client.py +222 -0
  338. package/vendor/ars/scripts/audit_snapshot.py +572 -0
  339. package/vendor/ars/scripts/bibliographic_integrity_signals.py +800 -0
  340. package/vendor/ars/scripts/bootstrap_timeline_yaml.py +146 -0
  341. package/vendor/ars/scripts/build_claim_standing_candidate_ledger.py +1238 -0
  342. package/vendor/ars/scripts/build_claim_standing_query_plan.py +643 -0
  343. package/vendor/ars/scripts/build_content_coverage_advisory.py +1205 -0
  344. package/vendor/ars/scripts/build_cross_document_consistency_advisory.py +2332 -0
  345. package/vendor/ars/scripts/build_review_pathway_rule_trace.py +830 -0
  346. package/vendor/ars/scripts/build_submission_packet_manifest.py +2310 -0
  347. package/vendor/ars/scripts/check_215_field_norm.py +173 -0
  348. package/vendor/ars/scripts/check_216_surface_form.py +250 -0
  349. package/vendor/ars/scripts/check_268_nested_commitment_ledger.py +180 -0
  350. package/vendor/ars/scripts/check_390_revision_patch_discipline.py +296 -0
  351. package/vendor/ars/scripts/check_392_citation_verification_intake.py +126 -0
  352. package/vendor/ars/scripts/check_394_submission_policy.py +178 -0
  353. package/vendor/ars/scripts/check_439_format_profile.py +307 -0
  354. package/vendor/ars/scripts/check_619_disclosure_closeout.py +237 -0
  355. package/vendor/ars/scripts/check_630_codex_subscription_transport.py +456 -0
  356. package/vendor/ars/scripts/check_669_review_pathway_rule_trace.py +662 -0
  357. package/vendor/ars/scripts/check_670_revision_roadmap_integration.py +518 -0
  358. package/vendor/ars/scripts/check_673_adjudication_activity.py +684 -0
  359. package/vendor/ars/scripts/check_684_review_criteria_binding.py +557 -0
  360. package/vendor/ars/scripts/check_agents_mirror_sync.py +115 -0
  361. package/vendor/ars/scripts/check_audit_artifact_consistency.py +2313 -0
  362. package/vendor/ars/scripts/check_benchmark_report.py +79 -0
  363. package/vendor/ars/scripts/check_bibliographic_integrity_signals.py +831 -0
  364. package/vendor/ars/scripts/check_calibration_tiers.py +235 -0
  365. package/vendor/ars/scripts/check_changelog_covers_merges.py +289 -0
  366. package/vendor/ars/scripts/check_ci_pytest_manifest.py +204 -0
  367. package/vendor/ars/scripts/check_claim_audit_consistency.py +1664 -0
  368. package/vendor/ars/scripts/check_claim_standing_candidate_ledger_integration.py +500 -0
  369. package/vendor/ars/scripts/check_claim_standing_freshness.py +253 -0
  370. package/vendor/ars/scripts/check_claim_standing_transmissions.py +449 -0
  371. package/vendor/ars/scripts/check_collaboration_depth_rubric.py +180 -0
  372. package/vendor/ars/scripts/check_command_frontmatter_name.py +116 -0
  373. package/vendor/ars/scripts/check_committee_correspondence.py +333 -0
  374. package/vendor/ars/scripts/check_compliance_report.py +108 -0
  375. package/vendor/ars/scripts/check_content_coverage_advisory_integration.py +796 -0
  376. package/vendor/ars/scripts/check_control_availability.py +172 -0
  377. package/vendor/ars/scripts/check_corpus_consumer_protocol.py +404 -0
  378. package/vendor/ars/scripts/check_cross_document_consistency_advisory_integration.py +1191 -0
  379. package/vendor/ars/scripts/check_cross_model_handoff_contract.py +234 -0
  380. package/vendor/ars/scripts/check_cross_model_verification_sync.py +261 -0
  381. package/vendor/ars/scripts/check_data_access_level.py +131 -0
  382. package/vendor/ars/scripts/check_data_flows.py +252 -0
  383. package/vendor/ars/scripts/check_decision_contract.py +464 -0
  384. package/vendor/ars/scripts/check_degradation_registry.py +326 -0
  385. package/vendor/ars/scripts/check_distribution_surface_claims.py +226 -0
  386. package/vendor/ars/scripts/check_domain_evidence_profile.py +538 -0
  387. package/vendor/ars/scripts/check_e4_promotion.py +195 -0
  388. package/vendor/ars/scripts/check_evals_gold_set.py +279 -0
  389. package/vendor/ars/scripts/check_evidence_row_integration.py +396 -0
  390. package/vendor/ars/scripts/check_experiment_provenance.py +117 -0
  391. package/vendor/ars/scripts/check_field_norm_severity.py +144 -0
  392. package/vendor/ars/scripts/check_firm_rules_sync.py +375 -0
  393. package/vendor/ars/scripts/check_heldout_measurement_report.py +1179 -0
  394. package/vendor/ars/scripts/check_human_subjects_output_contract.py +139 -0
  395. package/vendor/ars/scripts/check_human_subjects_reference_migration.py +844 -0
  396. package/vendor/ars/scripts/check_indirect_prompt_injection_no_call.py +328 -0
  397. package/vendor/ars/scripts/check_instruction_data_boundary.py +236 -0
  398. package/vendor/ars/scripts/check_judge_prompt_version.py +125 -0
  399. package/vendor/ars/scripts/check_literature_corpus_schema.py +402 -0
  400. package/vendor/ars/scripts/check_model_tiering.py +223 -0
  401. package/vendor/ars/scripts/check_panel_synthesis.py +1331 -0
  402. package/vendor/ars/scripts/check_passport_reset_contract.py +214 -0
  403. package/vendor/ars/scripts/check_pattern_eval_manifest.py +422 -0
  404. package/vendor/ars/scripts/check_persuasion_invariance_fixtures.py +637 -0
  405. package/vendor/ars/scripts/check_phase_conformance.py +2180 -0
  406. package/vendor/ars/scripts/check_pipeline_boundary_semantics.py +600 -0
  407. package/vendor/ars/scripts/check_pipeline_integrity.py +340 -0
  408. package/vendor/ars/scripts/check_policy_anchor_protocol.py +159 -0
  409. package/vendor/ars/scripts/check_policy_anchor_table.py +286 -0
  410. package/vendor/ars/scripts/check_preprint_venues_consistency.py +123 -0
  411. package/vendor/ars/scripts/check_prisma_trAIce_freshness.py +84 -0
  412. package/vendor/ars/scripts/check_promotion_bakeoff_preregistration.py +1303 -0
  413. package/vendor/ars/scripts/check_ranking_lift.py +323 -0
  414. package/vendor/ars/scripts/check_re_review_synthesis.py +2719 -0
  415. package/vendor/ars/scripts/check_receipt_enum_sync.py +203 -0
  416. package/vendor/ars/scripts/check_repro_lock.py +85 -0
  417. package/vendor/ars/scripts/check_review_pathway_output.py +276 -0
  418. package/vendor/ars/scripts/check_reviewer_data_fences.py +224 -0
  419. package/vendor/ars/scripts/check_reviewer_finding_contract.py +783 -0
  420. package/vendor/ars/scripts/check_reviewer_role_label.py +447 -0
  421. package/vendor/ars/scripts/check_reviewer_scoring_honesty.py +292 -0
  422. package/vendor/ars/scripts/check_reviewer_sprint_prompt_sync.py +409 -0
  423. package/vendor/ars/scripts/check_revision_claim_drift_suite_v2.py +1622 -0
  424. package/vendor/ars/scripts/check_revision_token_conservation.py +263 -0
  425. package/vendor/ars/scripts/check_risk_register.py +280 -0
  426. package/vendor/ars/scripts/check_role_scoped_contract.py +702 -0
  427. package/vendor/ars/scripts/check_rq_framing_patterns.py +184 -0
  428. package/vendor/ars/scripts/check_rubric_weight_consistency.py +32 -0
  429. package/vendor/ars/scripts/check_seeded_defect_fixtures.py +425 -0
  430. package/vendor/ars/scripts/check_setup_cross_model_parity.py +139 -0
  431. package/vendor/ars/scripts/check_spec_consistency.py +1249 -0
  432. package/vendor/ars/scripts/check_sprint_contract.py +371 -0
  433. package/vendor/ars/scripts/check_stage_capability_matrix.py +784 -0
  434. package/vendor/ars/scripts/check_submission_packet_manifest_integration.py +358 -0
  435. package/vendor/ars/scripts/check_surface_form_parity.py +445 -0
  436. package/vendor/ars/scripts/check_task_type.py +22 -0
  437. package/vendor/ars/scripts/check_tools_allowlist.py +538 -0
  438. package/vendor/ars/scripts/check_tortured_phrase_screening_integration.py +1974 -0
  439. package/vendor/ars/scripts/check_v3_10_134_write_scope.py +286 -0
  440. package/vendor/ars/scripts/check_v3_10_policy.py +656 -0
  441. package/vendor/ars/scripts/check_v3_6_6_ab_manifest.py +364 -0
  442. package/vendor/ars/scripts/check_v3_6_7_pattern_protection.py +1366 -0
  443. package/vendor/ars/scripts/check_v3_6_8_audit_scope_block.py +464 -0
  444. package/vendor/ars/scripts/check_v3_6_8_cite_provenance_pipeline.py +231 -0
  445. package/vendor/ars/scripts/check_v3_6_8_frontmatter_trust_schema.py +248 -0
  446. package/vendor/ars/scripts/check_v3_6_8_mark_read_commands.py +79 -0
  447. package/vendor/ars/scripts/check_v3_6_8_pattern_protection.py +941 -0
  448. package/vendor/ars/scripts/check_v3_7_3_three_layer_citation.py +318 -0
  449. package/vendor/ars/scripts/check_v3_8_annotation_literal_sync.py +228 -0
  450. package/vendor/ars/scripts/check_v3_9_0_triangulation.py +366 -0
  451. package/vendor/ars/scripts/check_v3_9_2_phase_boundary.py +270 -0
  452. package/vendor/ars/scripts/check_v3_9_4_temporal_verification.py +139 -0
  453. package/vendor/ars/scripts/check_venue_disclosure_policies.py +63 -0
  454. package/vendor/ars/scripts/check_version_consistency.py +826 -0
  455. package/vendor/ars/scripts/check_workflow_classification.py +223 -0
  456. package/vendor/ars/scripts/chinese_literature_client.py +1938 -0
  457. package/vendor/ars/scripts/citation_verification_summary.py +85 -0
  458. package/vendor/ars/scripts/claim_audit_calibration.py +517 -0
  459. package/vendor/ars/scripts/claim_audit_finalizer.py +456 -0
  460. package/vendor/ars/scripts/claim_audit_pipeline.py +1594 -0
  461. package/vendor/ars/scripts/claim_registry_coverage.py +493 -0
  462. package/vendor/ars/scripts/claim_standing_discovery.py +784 -0
  463. package/vendor/ars/scripts/claim_standing_stance_runner.py +758 -0
  464. package/vendor/ars/scripts/claim_standing_stance_scorer.py +239 -0
  465. package/vendor/ars/scripts/claim_strength_drift_disposition.py +666 -0
  466. package/vendor/ars/scripts/contamination_signals.py +689 -0
  467. package/vendor/ars/scripts/corpus_consumer_manifest.json +19 -0
  468. package/vendor/ars/scripts/cross_model_codex_transport.py +1374 -0
  469. package/vendor/ars/scripts/cross_model_codex_verify.sh +6 -0
  470. package/vendor/ars/scripts/cross_model_handoff.py +359 -0
  471. package/vendor/ars/scripts/cross_model_smoke_test.sh +183 -0
  472. package/vendor/ars/scripts/cross_model_smoke_test_codex.sh +35 -0
  473. package/vendor/ars/scripts/cross_model_verification/gemini_is_grounded.jq +45 -0
  474. package/vendor/ars/scripts/cross_model_verification/gemini_sources.jq +45 -0
  475. package/vendor/ars/scripts/cross_model_verification/normalize_compat_verdict.py +57 -0
  476. package/vendor/ars/scripts/cross_model_verification/openai_has_completed_web_search.jq +15 -0
  477. package/vendor/ars/scripts/cross_model_verification/openai_sources.jq +17 -0
  478. package/vendor/ars/scripts/cross_model_verification/openai_text.jq +11 -0
  479. package/vendor/ars/scripts/crossref_client.py +225 -0
  480. package/vendor/ars/scripts/dispatch_e4_panel.py +2731 -0
  481. package/vendor/ars/scripts/evidence_rows.py +2043 -0
  482. package/vendor/ars/scripts/fixtures/adjudication_activity/author_stage3.json +32 -0
  483. package/vendor/ars/scripts/fixtures/adjudication_activity/author_stage3_input.json +27 -0
  484. package/vendor/ars/scripts/fixtures/adjudication_activity/author_stage3_prime.json +32 -0
  485. package/vendor/ars/scripts/fixtures/adjudication_activity/author_stage3_prime_input.json +27 -0
  486. package/vendor/ars/scripts/fixtures/adjudication_activity/compliance_override.json +50 -0
  487. package/vendor/ars/scripts/fixtures/adjudication_activity/compliance_override_action.json +14 -0
  488. package/vendor/ars/scripts/fixtures/adjudication_activity/compliance_pass.json +44 -0
  489. package/vendor/ars/scripts/fixtures/adjudication_activity/explicit_user_request_log.json +26 -0
  490. package/vendor/ars/scripts/fixtures/adjudication_activity/mandatory_checkpoint_log.json +116 -0
  491. package/vendor/ars/scripts/fixtures/audit_artifact_consistency/README.md +56 -0
  492. 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
  493. package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a1_pass_with_p1/2026-04-30T15-22-04Z-d8f3.jsonl +4 -0
  494. package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a1_pass_with_p1/2026-04-30T15-22-04Z-d8f3.meta.json +43 -0
  495. package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a1_pass_with_p1/2026-04-30T15-22-04Z-d8f3.verdict.yaml +19 -0
  496. package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a7_orphan_completion/2026-04-30T15-22-04Z-d8f3.jsonl +3 -0
  497. package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/persisted_minor/2026-04-30T15-22-04Z-d8f3.audit_artifact_entry.json +26 -0
  498. package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/persisted_minor/2026-04-30T15-22-04Z-d8f3.jsonl +4 -0
  499. package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/persisted_minor/2026-04-30T15-22-04Z-d8f3.meta.json +43 -0
  500. package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/persisted_minor/2026-04-30T15-22-04Z-d8f3.verdict.yaml +19 -0
  501. package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/proposal_pass/2026-04-30T15-22-04Z-d8f3.audit_artifact_entry.json +24 -0
  502. package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/proposal_pass/2026-04-30T15-22-04Z-d8f3.jsonl +4 -0
  503. package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/proposal_pass/2026-04-30T15-22-04Z-d8f3.meta.json +43 -0
  504. package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/proposal_pass/2026-04-30T15-22-04Z-d8f3.verdict.yaml +12 -0
  505. package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/retraction.json +46 -0
  506. package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/retraction_check_attestation.json +44 -0
  507. package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/tortured_phrase.json +44 -0
  508. package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/tortured_phrase_v1_2_abstract_missing.json +107 -0
  509. package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/tortured_phrase_v1_2_detected.json +124 -0
  510. package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/expected_outcomes.json +77 -0
  511. package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/manifest.yaml +37 -0
  512. package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/tuples/001-valid-doi-test.json +20 -0
  513. package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/tuples/002-valid-arxiv-test.json +19 -0
  514. package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/tuples/003-fabricated-test.json +20 -0
  515. package/vendor/ars/scripts/fixtures/claim_audit_calibration/gold_set.json +344 -0
  516. package/vendor/ars/scripts/fixtures/claim_standing_candidate_ledger/query_plan.json +108 -0
  517. package/vendor/ars/scripts/fixtures/claim_standing_candidate_ledger/retrieval_input.json +179 -0
  518. package/vendor/ars/scripts/fixtures/committee_correspondence/16fd83f6aec7/concern_tracker.json +129 -0
  519. package/vendor/ars/scripts/fixtures/committee_correspondence/16fd83f6aec7/response_skeleton.md +19 -0
  520. package/vendor/ars/scripts/fixtures/committee_correspondence/16fd83f6aec7/source_letter.txt +9 -0
  521. package/vendor/ars/scripts/fixtures/content_coverage_advisory/base_draft.json +48 -0
  522. package/vendor/ars/scripts/fixtures/content_coverage_advisory/base_inventory.json +38 -0
  523. package/vendor/ars/scripts/fixtures/content_coverage_advisory/packet/consent.txt +1 -0
  524. package/vendor/ars/scripts/fixtures/content_coverage_advisory/session_sources.json +3 -0
  525. package/vendor/ars/scripts/fixtures/cross_document_consistency/README.md +6 -0
  526. package/vendor/ars/scripts/fixtures/cross_document_consistency/accepted_draft.md +35 -0
  527. package/vendor/ars/scripts/fixtures/cross_document_consistency/cases.json +75 -0
  528. package/vendor/ars/scripts/fixtures/cross_document_consistency/preregistration.md +5 -0
  529. package/vendor/ars/scripts/fixtures/cross_model_codex_transport/forbidden_event.jsonl +4 -0
  530. package/vendor/ars/scripts/fixtures/cross_model_codex_transport/grounded_verified.jsonl +3 -0
  531. package/vendor/ars/scripts/fixtures/cross_model_codex_transport/malformed.jsonl +3 -0
  532. package/vendor/ars/scripts/fixtures/cross_model_codex_transport/missing_search.jsonl +2 -0
  533. package/vendor/ars/scripts/fixtures/cross_model_codex_transport/multiple_finals.jsonl +4 -0
  534. package/vendor/ars/scripts/fixtures/cross_model_codex_transport/not_found.jsonl +3 -0
  535. package/vendor/ars/scripts/fixtures/cross_model_codex_transport/unbound_source.jsonl +3 -0
  536. package/vendor/ars/scripts/fixtures/cross_model_codex_transport/wrong_search_shape.jsonl +3 -0
  537. package/vendor/ars/scripts/fixtures/evidence_rows/phase_e_inputs.json +114 -0
  538. package/vendor/ars/scripts/fixtures/evidence_rows/session_sources.json +5 -0
  539. package/vendor/ars/scripts/fixtures/human_subjects_authority/cross-border-us-tw-gdpr.json +71 -0
  540. package/vendor/ars/scripts/fixtures/human_subjects_authority/gdpr-member-state-unresolved.json +62 -0
  541. package/vendor/ars/scripts/fixtures/human_subjects_authority/missing-data-axis.json +45 -0
  542. package/vendor/ars/scripts/fixtures/human_subjects_authority/no-profile.json +33 -0
  543. package/vendor/ars/scripts/fixtures/human_subjects_authority/tw-gdpr-two-axis.json +74 -0
  544. package/vendor/ars/scripts/fixtures/human_subjects_authority/us-gdpr-two-axis.json +74 -0
  545. package/vendor/ars/scripts/fixtures/review_pathway_rule_trace/lint-near-misses.json +72 -0
  546. package/vendor/ars/scripts/fixtures/review_pathway_rule_trace/no-profile-request.json +18 -0
  547. package/vendor/ars/scripts/fixtures/review_pathway_rule_trace/tw-candidates-request.json +63 -0
  548. package/vendor/ars/scripts/fixtures/review_pathway_rule_trace/us-candidates-request.json +77 -0
  549. package/vendor/ars/scripts/fixtures/review_target_context/exact-declaration.json +24 -0
  550. package/vendor/ars/scripts/fixtures/review_target_context/field-general-declaration.json +24 -0
  551. package/vendor/ars/scripts/fixtures/review_target_context/msr-2027-technical-full-declaration.json +24 -0
  552. package/vendor/ars/scripts/fixtures/review_target_context/synthetic-registry.json +92 -0
  553. package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/README.md +21 -0
  554. package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/subject_context_attested_only.json +55 -0
  555. package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/subject_context_machine_supported.json +49 -0
  556. package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/subject_context_not_isolated.json +56 -0
  557. package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/subject_context_unknown.json +49 -0
  558. package/vendor/ars/scripts/fixtures/submission_package/clean/paper.md +16 -0
  559. package/vendor/ars/scripts/fixtures/submission_package/clean/references.bib +13 -0
  560. package/vendor/ars/scripts/fixtures/submission_package/fallback_authoryear/paper.md +11 -0
  561. package/vendor/ars/scripts/fixtures/submission_package/fallback_authoryear/references.bib +13 -0
  562. package/vendor/ars/scripts/fixtures/submission_package/fallback_latex/paper.tex +9 -0
  563. package/vendor/ars/scripts/fixtures/submission_package/fallback_latex/references.bib +13 -0
  564. package/vendor/ars/scripts/fixtures/submission_package/marker_no_join/paper.md +7 -0
  565. package/vendor/ars/scripts/fixtures/submission_package/orphan_intext/paper.md +8 -0
  566. package/vendor/ars/scripts/fixtures/submission_package/orphan_intext/references.bib +6 -0
  567. package/vendor/ars/scripts/fixtures/submission_package/passports/corpus_only.yaml +9 -0
  568. package/vendor/ars/scripts/fixtures/submission_package/passports/summary_join.yaml +16 -0
  569. package/vendor/ars/scripts/fixtures/submission_package/profiles/full.yaml +15 -0
  570. package/vendor/ars/scripts/fixtures/submission_package/profiles/tight.yaml +15 -0
  571. package/vendor/ars/scripts/fixtures/submission_package/summary_join/paper.md +7 -0
  572. package/vendor/ars/scripts/fixtures/submission_package/uncited_reference/paper.md +9 -0
  573. package/vendor/ars/scripts/fixtures/submission_package/uncited_reference/references.bib +13 -0
  574. package/vendor/ars/scripts/fixtures/submission_package/venue_clean/paper.md +26 -0
  575. package/vendor/ars/scripts/fixtures/submission_package/venue_clean/references.bib +13 -0
  576. package/vendor/ars/scripts/fixtures/submission_package/venue_violations/paper.md +20 -0
  577. package/vendor/ars/scripts/fixtures/submission_package/venue_violations/references.bib +13 -0
  578. package/vendor/ars/scripts/fixtures/submission_packet_manifest/base_inventory.json +101 -0
  579. package/vendor/ars/scripts/fixtures/submission_packet_manifest/packet/consent-materials.txt +3 -0
  580. package/vendor/ars/scripts/fixtures/submission_packet_manifest/packet/training-certificate.txt +2 -0
  581. package/vendor/ars/scripts/fixtures/submission_packet_manifest/packet/tw-consent-materials.txt +3 -0
  582. package/vendor/ars/scripts/fixtures/tortured_phrase_screening/corpus_input.yaml +30 -0
  583. package/vendor/ars/scripts/fixtures/tortured_phrase_screening/own_draft.md +36 -0
  584. package/vendor/ars/scripts/fixtures/tortured_phrase_screening/own_draft.tex +21 -0
  585. package/vendor/ars/scripts/fixtures/tortured_phrase_screening/seed_expectations.json +218 -0
  586. package/vendor/ars/scripts/fixtures/tortured_phrase_screening/snapshot.json +164 -0
  587. package/vendor/ars/scripts/fixtures/tortured_phrase_screening/snapshot_manifest.json +29 -0
  588. package/vendor/ars/scripts/fixtures/transport_bodies/README.md +55 -0
  589. package/vendor/ars/scripts/fixtures/transport_bodies/arxiv/empty_feed.xml +10 -0
  590. package/vendor/ars/scripts/fixtures/transport_bodies/arxiv/error_5xx.html +7 -0
  591. package/vendor/ars/scripts/fixtures/transport_bodies/arxiv/id_hit.xml +26 -0
  592. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/README.md +69 -0
  593. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/cnki_landing_page.html +13 -0
  594. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/error_5xx.html +2 -0
  595. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coordinate_ambiguous.json +16 -0
  596. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coordinate_hit.json +16 -0
  597. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coordinate_zero.json +14 -0
  598. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coverage_hit.json +15 -0
  599. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coverage_zero.json +13 -0
  600. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_hit.json +43 -0
  601. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_issn_mismatch.json +31 -0
  602. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_no_doi.json +31 -0
  603. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_unknown_ra.json +34 -0
  604. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_year_mismatch.json +31 -0
  605. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/handle_absent.json +4 -0
  606. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/handle_exists.json +16 -0
  607. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/handle_internal_error.json +4 -0
  608. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/istic_csl_hit.json +25 -0
  609. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/istic_csl_other_title.json +18 -0
  610. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/ra_cnki.json +6 -0
  611. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/ra_crossref.json +6 -0
  612. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/ra_istic.json +6 -0
  613. package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/ra_unknown_prefix.json +6 -0
  614. package/vendor/ars/scripts/fixtures/transport_bodies/crossref/doi_hit.json +24 -0
  615. package/vendor/ars/scripts/fixtures/transport_bodies/crossref/error_5xx.html +7 -0
  616. package/vendor/ars/scripts/fixtures/transport_bodies/crossref/title_search_miss.json +15 -0
  617. package/vendor/ars/scripts/fixtures/transport_bodies/openalex/doi_hit.json +29 -0
  618. package/vendor/ars/scripts/fixtures/transport_bodies/openalex/error_5xx.json +4 -0
  619. package/vendor/ars/scripts/fixtures/transport_bodies/openalex/title_search_miss.json +11 -0
  620. package/vendor/ars/scripts/fixtures/transport_bodies/semantic_scholar/doi_hit.json +14 -0
  621. package/vendor/ars/scripts/fixtures/transport_bodies/semantic_scholar/error_5xx.json +3 -0
  622. package/vendor/ars/scripts/fixtures/transport_bodies/semantic_scholar/title_search_miss.json +5 -0
  623. package/vendor/ars/scripts/human_read_attestation_resolver.py +467 -0
  624. package/vendor/ars/scripts/ideation_diversity_assignment_gate.py +430 -0
  625. package/vendor/ars/scripts/inquiry_branch_ledger.py +2540 -0
  626. package/vendor/ars/scripts/legacy/ars_apply_revision_patch_v1_0.py +715 -0
  627. package/vendor/ars/scripts/legacy/check_re_review_synthesis_v1_0.py +2215 -0
  628. package/vendor/ars/scripts/migrate_literature_corpus_to_v3_10.py +223 -0
  629. package/vendor/ars/scripts/migrate_literature_corpus_to_v3_7_3.py +277 -0
  630. package/vendor/ars/scripts/migrate_literature_corpus_to_v3_9_0.py +304 -0
  631. package/vendor/ars/scripts/model_tiering_manifest.json +46 -0
  632. package/vendor/ars/scripts/openalex_client.py +232 -0
  633. package/vendor/ars/scripts/parse_audit_verdict.py +802 -0
  634. package/vendor/ars/scripts/pdf_content_classifier_worker.py +176 -0
  635. package/vendor/ars/scripts/pdf_read_preflight.py +1455 -0
  636. package/vendor/ars/scripts/policy_anchor_disclosure_referee.py +354 -0
  637. package/vendor/ars/scripts/recompute_receipts.py +1414 -0
  638. package/vendor/ars/scripts/render_claim_standing_view.py +374 -0
  639. package/vendor/ars/scripts/render_eval_comment.py +130 -0
  640. package/vendor/ars/scripts/render_harness_retirement_issue.py +167 -0
  641. package/vendor/ars/scripts/repro_lock_validation.py +90 -0
  642. package/vendor/ars/scripts/research_workflow_profile.py +1079 -0
  643. package/vendor/ars/scripts/resolve_human_subjects_authority.py +1158 -0
  644. package/vendor/ars/scripts/resolve_review_target_context.py +683 -0
  645. package/vendor/ars/scripts/resume_e4_record.py +509 -0
  646. package/vendor/ars/scripts/retraction_status.py +484 -0
  647. package/vendor/ars/scripts/review_criteria_binding.py +889 -0
  648. package/vendor/ars/scripts/review_panel_provenance.py +744 -0
  649. package/vendor/ars/scripts/revision_roadmap.py +1967 -0
  650. package/vendor/ars/scripts/run_ci_pytest_manifest.py +116 -0
  651. package/vendor/ars/scripts/run_codex_audit.sh +1191 -0
  652. package/vendor/ars/scripts/run_evals.py +513 -0
  653. package/vendor/ars/scripts/run_ideation_diversity_no_call.py +3505 -0
  654. package/vendor/ars/scripts/run_indirect_prompt_injection_no_call.py +3330 -0
  655. package/vendor/ars/scripts/run_indirect_prompt_injection_probe.py +399 -0
  656. package/vendor/ars/scripts/run_review_criteria_constructive_value.py +1895 -0
  657. package/vendor/ars/scripts/run_role_topology_utility_dry_run.py +606 -0
  658. package/vendor/ars/scripts/score_review_criteria_constructive_value.py +617 -0
  659. package/vendor/ars/scripts/semantic_scholar_client.py +291 -0
  660. package/vendor/ars/scripts/slr_lineage.py +59 -0
  661. package/vendor/ars/scripts/sync_adapter_docs.py +118 -0
  662. package/vendor/ars/scripts/temporal_integrity_audit.py +840 -0
  663. package/vendor/ars/scripts/test_431_exact_or_bust.py +253 -0
  664. package/vendor/ars/scripts/test__eval_threshold_gate.py +125 -0
  665. package/vendor/ars/scripts/test__markdown_lint_util.py +129 -0
  666. package/vendor/ars/scripts/test__next_verified_at_ms.py +256 -0
  667. package/vendor/ars/scripts/test_adjacent_framing_probe_lint.py +171 -0
  668. package/vendor/ars/scripts/test_adjudication_activity.py +1515 -0
  669. package/vendor/ars/scripts/test_ars_anchorize_draft.py +178 -0
  670. package/vendor/ars/scripts/test_ars_apply_revision_patch.py +1335 -0
  671. package/vendor/ars/scripts/test_ars_cache_invalidate.py +51 -0
  672. package/vendor/ars/scripts/test_ars_mark_read.py +910 -0
  673. package/vendor/ars/scripts/test_ars_update_check.py +816 -0
  674. package/vendor/ars/scripts/test_ars_write_scope_guard.py +790 -0
  675. package/vendor/ars/scripts/test_arxiv_client.py +374 -0
  676. package/vendor/ars/scripts/test_audit_schemas.py +560 -0
  677. package/vendor/ars/scripts/test_audit_snapshot_render_section_0.py +105 -0
  678. package/vendor/ars/scripts/test_block_parser.py +259 -0
  679. package/vendor/ars/scripts/test_bootstrap_timeline_yaml.py +148 -0
  680. package/vendor/ars/scripts/test_build_claim_standing_candidate_ledger.py +1203 -0
  681. package/vendor/ars/scripts/test_build_claim_standing_query_plan.py +791 -0
  682. package/vendor/ars/scripts/test_build_submission_packet_manifest.py +2644 -0
  683. package/vendor/ars/scripts/test_check_215_field_norm.py +238 -0
  684. package/vendor/ars/scripts/test_check_216_surface_form.py +341 -0
  685. package/vendor/ars/scripts/test_check_268_nested_commitment_ledger.py +194 -0
  686. package/vendor/ars/scripts/test_check_390_revision_patch_discipline.py +279 -0
  687. package/vendor/ars/scripts/test_check_392_citation_verification_intake.py +144 -0
  688. package/vendor/ars/scripts/test_check_394_submission_policy.py +200 -0
  689. package/vendor/ars/scripts/test_check_439_format_profile.py +252 -0
  690. package/vendor/ars/scripts/test_check_619_disclosure_closeout.py +158 -0
  691. package/vendor/ars/scripts/test_check_630_codex_subscription_transport.py +245 -0
  692. package/vendor/ars/scripts/test_check_669_review_pathway_rule_trace.py +304 -0
  693. package/vendor/ars/scripts/test_check_670_revision_roadmap_integration.py +260 -0
  694. package/vendor/ars/scripts/test_check_673_adjudication_activity.py +367 -0
  695. package/vendor/ars/scripts/test_check_684_review_criteria_binding.py +274 -0
  696. package/vendor/ars/scripts/test_check_agents_mirror_sync.py +137 -0
  697. package/vendor/ars/scripts/test_check_audit_artifact_consistency.py +2133 -0
  698. package/vendor/ars/scripts/test_check_benchmark_report.py +117 -0
  699. package/vendor/ars/scripts/test_check_bibliographic_integrity_signals.py +609 -0
  700. package/vendor/ars/scripts/test_check_calibration_tiers.py +376 -0
  701. package/vendor/ars/scripts/test_check_changelog_covers_merges.py +509 -0
  702. package/vendor/ars/scripts/test_check_ci_pytest_manifest.py +425 -0
  703. package/vendor/ars/scripts/test_check_claim_standing_candidate_ledger_integration.py +256 -0
  704. package/vendor/ars/scripts/test_check_claim_standing_freshness.py +277 -0
  705. package/vendor/ars/scripts/test_check_collaboration_depth_rubric.py +239 -0
  706. package/vendor/ars/scripts/test_check_command_frontmatter_name.py +178 -0
  707. package/vendor/ars/scripts/test_check_committee_correspondence.py +298 -0
  708. package/vendor/ars/scripts/test_check_compliance_report.py +381 -0
  709. package/vendor/ars/scripts/test_check_content_coverage_advisory_integration.py +308 -0
  710. package/vendor/ars/scripts/test_check_control_availability.py +361 -0
  711. package/vendor/ars/scripts/test_check_cross_document_consistency_advisory_integration.py +698 -0
  712. package/vendor/ars/scripts/test_check_cross_model_handoff_contract.py +301 -0
  713. package/vendor/ars/scripts/test_check_cross_model_verification_sync.py +203 -0
  714. package/vendor/ars/scripts/test_check_data_access_level.py +227 -0
  715. package/vendor/ars/scripts/test_check_data_flows.py +382 -0
  716. package/vendor/ars/scripts/test_check_decision_contract.py +387 -0
  717. package/vendor/ars/scripts/test_check_degradation_registry.py +270 -0
  718. package/vendor/ars/scripts/test_check_distribution_surface_claims.py +225 -0
  719. package/vendor/ars/scripts/test_check_domain_evidence_profile.py +439 -0
  720. package/vendor/ars/scripts/test_check_e4_promotion.py +163 -0
  721. package/vendor/ars/scripts/test_check_evals_gold_set.py +312 -0
  722. package/vendor/ars/scripts/test_check_evidence_row_integration.py +187 -0
  723. package/vendor/ars/scripts/test_check_field_norm_severity.py +173 -0
  724. package/vendor/ars/scripts/test_check_firm_rules_sync.py +342 -0
  725. package/vendor/ars/scripts/test_check_heldout_measurement_report.py +1508 -0
  726. package/vendor/ars/scripts/test_check_human_subjects_output_contract.py +129 -0
  727. package/vendor/ars/scripts/test_check_human_subjects_reference_migration.py +756 -0
  728. package/vendor/ars/scripts/test_check_instruction_data_boundary.py +204 -0
  729. package/vendor/ars/scripts/test_check_judge_prompt_version.py +90 -0
  730. package/vendor/ars/scripts/test_check_model_tiering.py +236 -0
  731. package/vendor/ars/scripts/test_check_panel_synthesis.py +1658 -0
  732. package/vendor/ars/scripts/test_check_passport_reset_contract.py +249 -0
  733. package/vendor/ars/scripts/test_check_pattern_eval_manifest.py +381 -0
  734. package/vendor/ars/scripts/test_check_persuasion_invariance_fixtures.py +591 -0
  735. package/vendor/ars/scripts/test_check_phase_conformance.py +4366 -0
  736. package/vendor/ars/scripts/test_check_pipeline_boundary_semantics.py +931 -0
  737. package/vendor/ars/scripts/test_check_pipeline_integrity.py +243 -0
  738. package/vendor/ars/scripts/test_check_policy_anchor_protocol.py +236 -0
  739. package/vendor/ars/scripts/test_check_policy_anchor_table.py +295 -0
  740. package/vendor/ars/scripts/test_check_prisma_trAIce_freshness.py +68 -0
  741. package/vendor/ars/scripts/test_check_promotion_bakeoff_preregistration.py +799 -0
  742. package/vendor/ars/scripts/test_check_ranking_lift.py +377 -0
  743. package/vendor/ars/scripts/test_check_re_review_synthesis.py +3398 -0
  744. package/vendor/ars/scripts/test_check_receipt_enum_sync.py +176 -0
  745. package/vendor/ars/scripts/test_check_repro_lock.py +107 -0
  746. package/vendor/ars/scripts/test_check_reviewer_data_fences.py +334 -0
  747. package/vendor/ars/scripts/test_check_reviewer_finding_contract.py +1107 -0
  748. package/vendor/ars/scripts/test_check_reviewer_role_label.py +491 -0
  749. package/vendor/ars/scripts/test_check_reviewer_scoring_honesty.py +222 -0
  750. package/vendor/ars/scripts/test_check_reviewer_sprint_prompt_sync.py +373 -0
  751. package/vendor/ars/scripts/test_check_revision_claim_drift_suite_v2.py +1925 -0
  752. package/vendor/ars/scripts/test_check_revision_token_conservation.py +398 -0
  753. package/vendor/ars/scripts/test_check_risk_register.py +336 -0
  754. package/vendor/ars/scripts/test_check_role_scoped_contract.py +1104 -0
  755. package/vendor/ars/scripts/test_check_rq_framing_patterns.py +110 -0
  756. package/vendor/ars/scripts/test_check_rubric_weight_consistency.py +32 -0
  757. package/vendor/ars/scripts/test_check_seeded_defect_fixtures.py +392 -0
  758. package/vendor/ars/scripts/test_check_setup_cross_model_parity.py +121 -0
  759. package/vendor/ars/scripts/test_check_spec_consistency.py +1081 -0
  760. package/vendor/ars/scripts/test_check_sprint_contract.py +458 -0
  761. package/vendor/ars/scripts/test_check_stage_capability_matrix.py +698 -0
  762. package/vendor/ars/scripts/test_check_submission_packet_manifest_integration.py +177 -0
  763. package/vendor/ars/scripts/test_check_surface_form_parity.py +417 -0
  764. package/vendor/ars/scripts/test_check_task_type.py +116 -0
  765. package/vendor/ars/scripts/test_check_tools_allowlist.py +835 -0
  766. package/vendor/ars/scripts/test_check_tortured_phrase_screening_integration.py +1306 -0
  767. package/vendor/ars/scripts/test_check_v3_10_134_write_scope.py +251 -0
  768. package/vendor/ars/scripts/test_check_v3_10_policy.py +547 -0
  769. package/vendor/ars/scripts/test_check_v3_6_7_pattern_protection.py +960 -0
  770. package/vendor/ars/scripts/test_check_v3_6_8_audit_scope_block.py +1000 -0
  771. package/vendor/ars/scripts/test_check_v3_6_8_cite_provenance_pipeline.py +454 -0
  772. package/vendor/ars/scripts/test_check_v3_6_8_frontmatter_trust_schema.py +581 -0
  773. package/vendor/ars/scripts/test_check_v3_6_8_mark_read_commands.py +120 -0
  774. package/vendor/ars/scripts/test_check_v3_6_8_pattern_protection.py +1138 -0
  775. package/vendor/ars/scripts/test_check_v3_7_3_three_layer_citation.py +566 -0
  776. package/vendor/ars/scripts/test_check_v3_8_annotation_literal_sync.py +262 -0
  777. package/vendor/ars/scripts/test_check_v3_9_0_triangulation.py +321 -0
  778. package/vendor/ars/scripts/test_check_v3_9_2_phase_boundary.py +190 -0
  779. package/vendor/ars/scripts/test_check_v3_9_4_temporal_verification.py +471 -0
  780. package/vendor/ars/scripts/test_check_version_consistency.py +1462 -0
  781. package/vendor/ars/scripts/test_check_workflow_classification.py +225 -0
  782. package/vendor/ars/scripts/test_chinese_literature_client.py +1889 -0
  783. package/vendor/ars/scripts/test_citation_existence_policy.py +480 -0
  784. package/vendor/ars/scripts/test_citation_verification_summary.py +342 -0
  785. package/vendor/ars/scripts/test_claim_audit_calibration.py +882 -0
  786. package/vendor/ars/scripts/test_claim_audit_finalizer.py +979 -0
  787. package/vendor/ars/scripts/test_claim_audit_pipeline.py +2398 -0
  788. package/vendor/ars/scripts/test_claim_audit_schema.py +1778 -0
  789. package/vendor/ars/scripts/test_claim_intent_manifest.py +666 -0
  790. package/vendor/ars/scripts/test_claim_registry_coverage.py +246 -0
  791. package/vendor/ars/scripts/test_claim_standing_discovery.py +579 -0
  792. package/vendor/ars/scripts/test_claim_standing_pipeline_wiring.py +290 -0
  793. package/vendor/ars/scripts/test_claim_standing_stance_assets.py +399 -0
  794. package/vendor/ars/scripts/test_claim_standing_stance_contracts.py +383 -0
  795. package/vendor/ars/scripts/test_claim_standing_stance_runner.py +349 -0
  796. package/vendor/ars/scripts/test_claim_standing_transmissions.py +605 -0
  797. package/vendor/ars/scripts/test_claim_strength_drift_disposition.py +517 -0
  798. package/vendor/ars/scripts/test_claim_verification_coverage_contract.py +104 -0
  799. package/vendor/ars/scripts/test_contamination_signals.py +1086 -0
  800. package/vendor/ars/scripts/test_content_coverage_advisory.py +1767 -0
  801. package/vendor/ars/scripts/test_cross_document_consistency_advisory.py +1270 -0
  802. package/vendor/ars/scripts/test_cross_model_codex_transport.py +1152 -0
  803. package/vendor/ars/scripts/test_cross_model_handoff.py +571 -0
  804. package/vendor/ars/scripts/test_cross_model_verification_guards.py +792 -0
  805. package/vendor/ars/scripts/test_crossref_client.py +393 -0
  806. package/vendor/ars/scripts/test_dispatch_e4_panel.py +4235 -0
  807. package/vendor/ars/scripts/test_e2e_claim_audit.py +540 -0
  808. package/vendor/ars/scripts/test_eval_harness_workflow.py +140 -0
  809. package/vendor/ars/scripts/test_evals_citation_extraction.py +150 -0
  810. package/vendor/ars/scripts/test_evals_lift_report_schema.py +108 -0
  811. package/vendor/ars/scripts/test_evidence_rows.py +2593 -0
  812. package/vendor/ars/scripts/test_experiment_provenance.py +915 -0
  813. package/vendor/ars/scripts/test_human_read_attestation_resolver.py +477 -0
  814. package/vendor/ars/scripts/test_ideation_diversity_assignment_gate.py +615 -0
  815. package/vendor/ars/scripts/test_indirect_prompt_injection_behavior_probe.py +250 -0
  816. package/vendor/ars/scripts/test_inquiry_branch_ledger.py +2296 -0
  817. package/vendor/ars/scripts/test_migrate_literature_corpus_to_v3_10.py +248 -0
  818. package/vendor/ars/scripts/test_migrate_literature_corpus_to_v3_7_3.py +545 -0
  819. package/vendor/ars/scripts/test_migrate_literature_corpus_to_v3_9_0.py +497 -0
  820. package/vendor/ars/scripts/test_normalize_compat_verdict.py +149 -0
  821. package/vendor/ars/scripts/test_openalex_client.py +490 -0
  822. package/vendor/ars/scripts/test_passport_yaml.py +104 -0
  823. package/vendor/ars/scripts/test_pattern_eval_runtime.py +1295 -0
  824. package/vendor/ars/scripts/test_pdf_read_preflight.py +1943 -0
  825. package/vendor/ars/scripts/test_policy_anchor_disclosure.py +666 -0
  826. package/vendor/ars/scripts/test_reading_probe_lint.py +218 -0
  827. package/vendor/ars/scripts/test_recompute_receipts.py +778 -0
  828. package/vendor/ars/scripts/test_render_claim_standing_view.py +192 -0
  829. package/vendor/ars/scripts/test_render_eval_comment.py +162 -0
  830. package/vendor/ars/scripts/test_render_harness_retirement_issue.py +110 -0
  831. package/vendor/ars/scripts/test_repro_lock_validation_drift.py +100 -0
  832. package/vendor/ars/scripts/test_research_workflow_profile.py +734 -0
  833. package/vendor/ars/scripts/test_resolve_human_subjects_authority.py +1219 -0
  834. package/vendor/ars/scripts/test_resolve_review_target_context.py +703 -0
  835. package/vendor/ars/scripts/test_resume_e4_record.py +315 -0
  836. package/vendor/ars/scripts/test_retraction_status.py +456 -0
  837. package/vendor/ars/scripts/test_review_criteria_binding.py +629 -0
  838. package/vendor/ars/scripts/test_review_panel_provenance.py +565 -0
  839. package/vendor/ars/scripts/test_review_pathway_rule_trace.py +821 -0
  840. package/vendor/ars/scripts/test_revision_roadmap.py +1255 -0
  841. package/vendor/ars/scripts/test_run_ci_pytest_manifest.py +186 -0
  842. package/vendor/ars/scripts/test_run_codex_audit_e2e.py +369 -0
  843. package/vendor/ars/scripts/test_run_evals.py +430 -0
  844. package/vendor/ars/scripts/test_run_guard_launcher.py +500 -0
  845. package/vendor/ars/scripts/test_run_ideation_diversity_no_call.py +1833 -0
  846. package/vendor/ars/scripts/test_run_indirect_prompt_injection_no_call.py +1889 -0
  847. package/vendor/ars/scripts/test_run_review_criteria_constructive_value.py +586 -0
  848. package/vendor/ars/scripts/test_run_role_topology_utility_dry_run.py +428 -0
  849. package/vendor/ars/scripts/test_score_review_criteria_constructive_value.py +340 -0
  850. package/vendor/ars/scripts/test_semantic_scholar_client.py +554 -0
  851. package/vendor/ars/scripts/test_slr_lineage_emission.py +230 -0
  852. package/vendor/ars/scripts/test_socratic_rq_non_generation_contract.py +173 -0
  853. package/vendor/ars/scripts/test_temporal_integrity_audit.py +438 -0
  854. package/vendor/ars/scripts/test_text_similarity.py +95 -0
  855. package/vendor/ars/scripts/test_title_fuzzy_false_positive.py +111 -0
  856. package/vendor/ars/scripts/test_tortured_phrase_screening.py +2959 -0
  857. package/vendor/ars/scripts/test_transport_fixture_citation_gate.py +338 -0
  858. package/vendor/ars/scripts/test_uncited_assertion.py +558 -0
  859. package/vendor/ars/scripts/test_v3_6_7_phase_6_6.py +1279 -0
  860. package/vendor/ars/scripts/test_validate_compliance_fixtures.py +36 -0
  861. package/vendor/ars/scripts/test_validate_ideation_diversity_assets.py +230 -0
  862. package/vendor/ars/scripts/test_venue_disclosure_contract.py +755 -0
  863. package/vendor/ars/scripts/test_verification_cache.py +280 -0
  864. package/vendor/ars/scripts/test_verification_gate.py +461 -0
  865. package/vendor/ars/scripts/test_verify_passport_cli.py +123 -0
  866. package/vendor/ars/scripts/test_verify_submission_package.py +1407 -0
  867. package/vendor/ars/scripts/test_version_records_schema.py +211 -0
  868. package/vendor/ars/scripts/tortured_phrase_screening.py +3502 -0
  869. package/vendor/ars/scripts/uncited_assertion_detector.py +254 -0
  870. package/vendor/ars/scripts/v3_6_7_inversion_manifest.json +9 -0
  871. package/vendor/ars/scripts/v3_6_8_inversion_manifest.json +10 -0
  872. package/vendor/ars/scripts/validate_claim_standing_stance_assets.py +249 -0
  873. package/vendor/ars/scripts/validate_compliance_fixtures.py +56 -0
  874. package/vendor/ars/scripts/validate_ideation_diversity_assets.py +303 -0
  875. package/vendor/ars/scripts/venue_disclosure_contract_harness.py +837 -0
  876. package/vendor/ars/scripts/verification_cache.py +276 -0
  877. package/vendor/ars/scripts/verification_gate/__init__.py +345 -0
  878. package/vendor/ars/scripts/verify_passport.py +133 -0
  879. package/vendor/ars/scripts/verify_submission_package.py +1657 -0
  880. package/vendor/ars/shared/agents/compliance_agent.md +136 -0
  881. package/vendor/ars/shared/artifact_reproducibility_pattern.md +173 -0
  882. package/vendor/ars/shared/benchmark_report.schema.json +81 -0
  883. package/vendor/ars/shared/benchmark_report_pattern.md +180 -0
  884. package/vendor/ars/shared/bibliographic_integrity_signals.md +142 -0
  885. package/vendor/ars/shared/collaboration_depth_rubric.md +154 -0
  886. package/vendor/ars/shared/compliance_checkpoint_protocol.md +162 -0
  887. package/vendor/ars/shared/compliance_report.schema.json +187 -0
  888. package/vendor/ars/shared/contracts/README.md +938 -0
  889. package/vendor/ars/shared/contracts/activity/adjudication_activity_input.schema.json +555 -0
  890. package/vendor/ars/shared/contracts/activity/adjudication_activity_store.schema.json +560 -0
  891. package/vendor/ars/shared/contracts/audit/audit_jsonl.schema.json +128 -0
  892. package/vendor/ars/shared/contracts/audit/audit_sidecar.schema.json +169 -0
  893. package/vendor/ars/shared/contracts/audit/audit_verdict.schema.json +133 -0
  894. package/vendor/ars/shared/contracts/audit/cross_document_consistency_advisory.schema.json +480 -0
  895. package/vendor/ars/shared/contracts/audit/cross_document_consistency_advisory_draft.schema.json +564 -0
  896. package/vendor/ars/shared/contracts/audit/cross_document_source_manifest.schema.json +202 -0
  897. package/vendor/ars/shared/contracts/audit/tortured_phrase_advisory.schema.json +1362 -0
  898. package/vendor/ars/shared/contracts/audit/tortured_phrase_snapshot.schema.json +208 -0
  899. package/vendor/ars/shared/contracts/audit/tortured_phrase_snapshot_manifest.schema.json +335 -0
  900. package/vendor/ars/shared/contracts/capability/stage_capability_matrix.json +434 -0
  901. package/vendor/ars/shared/contracts/claim_standing/candidate_ledger.schema.json +705 -0
  902. package/vendor/ars/shared/contracts/claim_standing/query_plan.schema.json +389 -0
  903. package/vendor/ars/shared/contracts/claim_standing/query_plan_v1_1.schema.json +782 -0
  904. package/vendor/ars/shared/contracts/claim_standing/retrieval_input.schema.json +440 -0
  905. package/vendor/ars/shared/contracts/claim_standing/stance_record.schema.json +460 -0
  906. package/vendor/ars/shared/contracts/claim_standing/transmission_ledger.schema.json +282 -0
  907. package/vendor/ars/shared/contracts/cross_model/codex_citation_receipt.schema.json +157 -0
  908. package/vendor/ars/shared/contracts/cross_model/codex_citation_request.schema.json +23 -0
  909. package/vendor/ars/shared/contracts/cross_model/promotion_bakeoff_sealed_commitment.schema.json +55 -0
  910. package/vendor/ars/shared/contracts/cross_model/promotion_bakeoff_sealed_reveal.schema.json +50 -0
  911. package/vendor/ars/shared/contracts/degradation_registry.json +428 -0
  912. package/vendor/ars/shared/contracts/evaluator/full.json +126 -0
  913. package/vendor/ars/shared/contracts/evidence/claim_registry.schema.json +50 -0
  914. package/vendor/ars/shared/contracts/evidence/claim_registry_coverage_report.schema.json +79 -0
  915. package/vendor/ars/shared/contracts/evidence/evidence_row.schema.json +504 -0
  916. package/vendor/ars/shared/contracts/evidence/evidence_row_v1_1.schema.json +364 -0
  917. package/vendor/ars/shared/contracts/evidence/evidence_row_v1_2.schema.json +714 -0
  918. package/vendor/ars/shared/contracts/evidence/evidence_row_v1_3.schema.json +524 -0
  919. package/vendor/ars/shared/contracts/human_subjects/authority_profile_registry.schema.json +497 -0
  920. package/vendor/ars/shared/contracts/human_subjects/committee_correspondence.schema.json +253 -0
  921. package/vendor/ars/shared/contracts/human_subjects/content_coverage_advisory.schema.json +620 -0
  922. package/vendor/ars/shared/contracts/human_subjects/irb_context_record.schema.json +329 -0
  923. package/vendor/ars/shared/contracts/human_subjects/resolved_authority_context.schema.json +347 -0
  924. package/vendor/ars/shared/contracts/human_subjects/review_pathway_rule_trace.schema.json +265 -0
  925. package/vendor/ars/shared/contracts/human_subjects/review_pathway_trace_request.schema.json +127 -0
  926. package/vendor/ars/shared/contracts/human_subjects/submission_packet_inventory.schema.json +240 -0
  927. package/vendor/ars/shared/contracts/human_subjects/submission_packet_manifest.schema.json +999 -0
  928. package/vendor/ars/shared/contracts/passport/audit_artifact_entry.schema.json +266 -0
  929. package/vendor/ars/shared/contracts/passport/bibliographic_integrity_signal.schema.json +1676 -0
  930. package/vendor/ars/shared/contracts/passport/citation_provenance.schema.json +107 -0
  931. package/vendor/ars/shared/contracts/passport/citation_verification_summary.schema.json +164 -0
  932. package/vendor/ars/shared/contracts/passport/claim_audit_result.schema.json +124 -0
  933. package/vendor/ars/shared/contracts/passport/claim_drift.schema.json +58 -0
  934. package/vendor/ars/shared/contracts/passport/claim_intent_manifest.schema.json +107 -0
  935. package/vendor/ars/shared/contracts/passport/constraint_violation.schema.json +65 -0
  936. package/vendor/ars/shared/contracts/passport/experiment_alignment_result.schema.json +69 -0
  937. package/vendor/ars/shared/contracts/passport/experiment_provenance_entry.schema.json +169 -0
  938. package/vendor/ars/shared/contracts/passport/human_read_log.schema.json +86 -0
  939. package/vendor/ars/shared/contracts/passport/inquiry_ledger_ref.schema.json +22 -0
  940. package/vendor/ars/shared/contracts/passport/literature_corpus_entry.schema.json +650 -0
  941. package/vendor/ars/shared/contracts/passport/preregistration_artifact.schema.json +132 -0
  942. package/vendor/ars/shared/contracts/passport/rejection_log.schema.json +89 -0
  943. package/vendor/ars/shared/contracts/passport/reset_ledger_entry.schema.json +158 -0
  944. package/vendor/ars/shared/contracts/passport/temporal_audit_results.schema.json +208 -0
  945. package/vendor/ars/shared/contracts/passport/terminal_policies.schema.json +50 -0
  946. package/vendor/ars/shared/contracts/passport/timeline.schema.json +102 -0
  947. package/vendor/ars/shared/contracts/passport/uncited_assertion.schema.json +56 -0
  948. package/vendor/ars/shared/contracts/passport/uncited_audit_failure.schema.json +72 -0
  949. package/vendor/ars/shared/contracts/passport/user_attested_read_resolution.schema.json +87 -0
  950. package/vendor/ars/shared/contracts/passport/version_records.schema.json +138 -0
  951. package/vendor/ars/shared/contracts/patch/block_manifest.schema.json +45 -0
  952. package/vendor/ars/shared/contracts/patch/legacy/v1_0/revision_patch.schema.json +110 -0
  953. package/vendor/ars/shared/contracts/patch/revision_patch.schema.json +250 -0
  954. package/vendor/ars/shared/contracts/pdf/pdf_content_classifier_diagnostic.schema.json +39 -0
  955. package/vendor/ars/shared/contracts/pdf/pdf_content_classifier_worker.schema.json +88 -0
  956. package/vendor/ars/shared/contracts/pdf/pdf_read_preflight.schema.json +227 -0
  957. package/vendor/ars/shared/contracts/re_review/input_manifest.schema.json +161 -0
  958. package/vendor/ars/shared/contracts/re_review/legacy/v1_0/input_manifest.schema.json +134 -0
  959. package/vendor/ars/shared/contracts/re_review/legacy/v1_0/precommitment.schema.json +193 -0
  960. package/vendor/ars/shared/contracts/re_review/legacy/v1_0/traceability.schema.json +841 -0
  961. package/vendor/ars/shared/contracts/re_review/legacy/v1_0/verdict_record.schema.json +244 -0
  962. package/vendor/ars/shared/contracts/re_review/precommitment.schema.json +193 -0
  963. package/vendor/ars/shared/contracts/re_review/traceability.schema.json +916 -0
  964. package/vendor/ars/shared/contracts/re_review/verdict_record.schema.json +245 -0
  965. package/vendor/ars/shared/contracts/research_workflow/inquiry_branch_ledger.schema.json +449 -0
  966. package/vendor/ars/shared/contracts/research_workflow/research_workflow_profile.schema.json +222 -0
  967. package/vendor/ars/shared/contracts/research_workflow/research_workflow_profile_selection_receipt.schema.json +111 -0
  968. package/vendor/ars/shared/contracts/review_target/constructive_review_findings.schema.json +172 -0
  969. package/vendor/ars/shared/contracts/review_target/criteria_registry.schema.json +97 -0
  970. package/vendor/ars/shared/contracts/review_target/review_criteria_binding_manifest.schema.json +235 -0
  971. package/vendor/ars/shared/contracts/review_target/review_criteria_source_receipt.schema.json +158 -0
  972. package/vendor/ars/shared/contracts/review_target/review_target_context.schema.json +106 -0
  973. package/vendor/ars/shared/contracts/review_target/review_target_declaration.schema.json +118 -0
  974. package/vendor/ars/shared/contracts/reviewer/full.json +114 -0
  975. package/vendor/ars/shared/contracts/reviewer/methodology_focus.json +75 -0
  976. package/vendor/ars/shared/contracts/reviewer/review_panel_provenance.schema.json +263 -0
  977. package/vendor/ars/shared/contracts/reviewer/review_panel_provenance_carrier.schema.json +122 -0
  978. package/vendor/ars/shared/contracts/reviewer/review_panel_provenance_input.schema.json +120 -0
  979. package/vendor/ars/shared/contracts/revision/author_adjudication.schema.json +251 -0
  980. package/vendor/ars/shared/contracts/revision/author_adjudication_input.schema.json +25 -0
  981. package/vendor/ars/shared/contracts/revision/claim_strength_drift_disposition.schema.json +97 -0
  982. package/vendor/ars/shared/contracts/revision/claim_strength_drift_disposition_input.schema.json +80 -0
  983. package/vendor/ars/shared/contracts/revision/claim_strength_drift_findings.schema.json +139 -0
  984. package/vendor/ars/shared/contracts/revision/claim_surface_manifest.schema.json +99 -0
  985. package/vendor/ars/shared/contracts/revision/integrity_correction_authorization.schema.json +140 -0
  986. package/vendor/ars/shared/contracts/revision/integrity_correction_authorization_input.schema.json +28 -0
  987. package/vendor/ars/shared/contracts/revision/integrity_correction_list.schema.json +48 -0
  988. package/vendor/ars/shared/contracts/revision/integrity_pass_receipt.schema.json +16 -0
  989. package/vendor/ars/shared/contracts/revision/revision_evidence_bundle.schema.json +134 -0
  990. package/vendor/ars/shared/contracts/revision/revision_roadmap.schema.json +334 -0
  991. package/vendor/ars/shared/contracts/submission/format_profile.example.yaml +33 -0
  992. package/vendor/ars/shared/contracts/submission/format_profile.schema.json +102 -0
  993. package/vendor/ars/shared/contracts/submission/submission_verification_report.schema.json +233 -0
  994. package/vendor/ars/shared/contracts/submission/venue_profile.schema.json +114 -0
  995. package/vendor/ars/shared/contracts/writer/full.json +87 -0
  996. package/vendor/ars/shared/cross_model_verification.md +714 -0
  997. package/vendor/ars/shared/evals_lift_report.schema.json +141 -0
  998. package/vendor/ars/shared/ground_truth_isolation_pattern.md +275 -0
  999. package/vendor/ars/shared/handoff_schemas.md +1209 -0
  1000. package/vendor/ars/shared/human_subjects_authority_registry.json +1278 -0
  1001. package/vendor/ars/shared/mode_spectrum.md +57 -0
  1002. package/vendor/ars/shared/model_tiering.md +83 -0
  1003. package/vendor/ars/shared/policy_data/nature_policy.md +56 -0
  1004. package/vendor/ars/shared/prisma_trAIce_protocol.md +157 -0
  1005. package/vendor/ars/shared/raise_framework.md +129 -0
  1006. package/vendor/ars/shared/references/authority_content_coverage_advisory_protocol.md +275 -0
  1007. package/vendor/ars/shared/references/claim_standing_candidate_ledger_protocol.md +66 -0
  1008. package/vendor/ars/shared/references/claim_strength_ladder.md +93 -0
  1009. package/vendor/ars/shared/references/cross_document_consistency_advisory_protocol.md +263 -0
  1010. package/vendor/ars/shared/references/evidence_row_protocol.md +260 -0
  1011. package/vendor/ars/shared/references/firm_rules.md +90 -0
  1012. package/vendor/ars/shared/references/human_subjects_authority_protocol.md +274 -0
  1013. package/vendor/ars/shared/references/intent_clarification_protocol.md +168 -0
  1014. package/vendor/ars/shared/references/irb_terminology_glossary.md +229 -0
  1015. package/vendor/ars/shared/references/protected_hedging_phrases.md +118 -0
  1016. package/vendor/ars/shared/references/psychometric_terminology_glossary.md +109 -0
  1017. package/vendor/ars/shared/references/review_criteria_consumer_protocol.md +238 -0
  1018. package/vendor/ars/shared/references/review_pathway_rule_trace_protocol.md +166 -0
  1019. package/vendor/ars/shared/references/submission_packet_manifest_protocol.md +292 -0
  1020. package/vendor/ars/shared/references/word_count_conventions.md +124 -0
  1021. package/vendor/ars/shared/research_workflow_profiles/field_general.json +1 -0
  1022. package/vendor/ars/shared/review_criteria_registry.json +207 -0
  1023. package/vendor/ars/shared/review_criteria_sources/msr-2027-technical-papers.2026-08-24.json +46 -0
  1024. package/vendor/ars/shared/review_criteria_sources/sigsoft-empirical-standards.2026-08-24.json +31 -0
  1025. package/vendor/ars/shared/sprint_contract.schema.json +482 -0
  1026. package/vendor/ars/shared/style_calibration_protocol.md +151 -0
  1027. package/vendor/ars/shared/templates/codex_audit_multifile_template.md +263 -0
  1028. package/vendor/ars/tools/release-discipline/.toolkit-version +1 -0
  1029. package/vendor/ars/tools/release-discipline/README.md +4 -0
  1030. package/vendor/ars/tools/release-discipline/scripts/_release_doc_alignment_schema.py +1011 -0
  1031. package/vendor/ars/tools/release-discipline/scripts/check_command_invariants.py +497 -0
  1032. package/vendor/ars/tools/release-discipline/scripts/check_release_doc_alignment.py +263 -0
  1033. package/vendor/ars/tools/release-discipline/scripts/sync-toolkit.sh +147 -0
  1034. package/vendor/windows/NOTICE.md +12 -0
  1035. package/vendor/windows/arm64/fd.exe +0 -0
  1036. package/vendor/windows/arm64/licenses/fd/LICENSE-APACHE +201 -0
  1037. package/vendor/windows/arm64/licenses/fd/LICENSE-MIT +21 -0
  1038. package/vendor/windows/arm64/licenses/ripgrep/COPYING +3 -0
  1039. package/vendor/windows/arm64/licenses/ripgrep/LICENSE-MIT +21 -0
  1040. package/vendor/windows/arm64/licenses/ripgrep/UNLICENSE +24 -0
  1041. package/vendor/windows/arm64/rg.exe +0 -0
  1042. package/vendor/windows/x64/fd.exe +0 -0
  1043. package/vendor/windows/x64/licenses/fd/LICENSE-APACHE +201 -0
  1044. package/vendor/windows/x64/licenses/fd/LICENSE-MIT +21 -0
  1045. package/vendor/windows/x64/licenses/ripgrep/COPYING +3 -0
  1046. package/vendor/windows/x64/licenses/ripgrep/LICENSE-MIT +21 -0
  1047. package/vendor/windows/x64/licenses/ripgrep/UNLICENSE +24 -0
  1048. 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())