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,1407 @@
1
+ #!/usr/bin/env python3
2
+ """Tests for verify_submission_package — #394 Slice 1 (CLI skeleton + Family C).
3
+
4
+ Spec: docs/design/2026-06-10-394-submission-package-verifier-spec.md §3.3 / §5.1
5
+ / §7.3 / §8. Mutation discipline per repo convention: every check has a fixture
6
+ that fails it and a test proving the failure fires.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import shutil
12
+ import zipfile
13
+ from pathlib import Path
14
+
15
+ import jsonschema
16
+ import pytest
17
+ import yaml
18
+
19
+ from verify_submission_package import run
20
+
21
+ REPO_ROOT = Path(__file__).resolve().parent.parent
22
+ FIXTURES = REPO_ROOT / "scripts" / "fixtures" / "submission_package"
23
+ SCHEMA_PATH = (
24
+ REPO_ROOT / "shared" / "contracts" / "submission"
25
+ / "submission_verification_report.schema.json"
26
+ )
27
+ REPORT_BASENAME = "submission_verification_report.json"
28
+
29
+
30
+ def load_schema():
31
+ return json.loads(SCHEMA_PATH.read_text(encoding="utf-8"))
32
+
33
+
34
+ def run_dir(package_dir, extra_args=()):
35
+ """Run the CLI on a package dir; returns (exit_code, report_dict)."""
36
+ rc = run([str(package_dir), *extra_args])
37
+ report_path = package_dir / REPORT_BASENAME
38
+ report = (
39
+ json.loads(report_path.read_text(encoding="utf-8"))
40
+ if report_path.is_file() else None
41
+ )
42
+ return rc, report
43
+
44
+
45
+ def run_on(fixture_name, tmp_path, extra_args=()):
46
+ """Copy a fixture package into tmp and run the CLI on the copy.
47
+
48
+ Returns (exit_code, report_dict, package_dir). The copy keeps the repo
49
+ fixture pristine (the CLI writes its report into the package dir).
50
+ """
51
+ package_dir = tmp_path / fixture_name
52
+ shutil.copytree(FIXTURES / fixture_name, package_dir)
53
+ rc, report = run_dir(package_dir, extra_args)
54
+ return rc, report, package_dir
55
+
56
+
57
+ def checks_by_id(report):
58
+ return {c["id"]: c for c in report["checks"]}
59
+
60
+
61
+ # --- Round 1: clean package, joined marker path -----------------------------
62
+
63
+ def test_clean_package_family_c_passes(tmp_path):
64
+ # Without a venue profile the Family B checks are NOT-CHECKED (§3.2), so
65
+ # the honest exit code is 3 ("passed what was checkable", §8) — Family C
66
+ # itself is fully green.
67
+ rc, report, _ = run_on("clean", tmp_path)
68
+ assert rc == 3
69
+ by_id = checks_by_id(report)
70
+ assert by_id["C1"]["status"] == "pass"
71
+ assert by_id["C2"]["status"] == "pass"
72
+
73
+
74
+ def test_clean_package_is_deterministic_joined_marker(tmp_path):
75
+ _, report, _ = run_on("clean", tmp_path)
76
+ assert report["header"]["extraction_path"] == "joined_marker"
77
+ by_id = checks_by_id(report)
78
+ for cid in ("C1", "C2"):
79
+ assert by_id[cid]["family"] == "reference_integrity"
80
+ assert by_id[cid]["signal_class"] == "deterministic"
81
+ # strict_eligible is class-level: C1 promotable, C2 (warn-only) never —
82
+ # asserted in test_C2_is_never_strict_eligible.
83
+
84
+
85
+ # --- Slice 2: Family B venue limits ------------------------------------------
86
+
87
+ def test_no_venue_profile_family_b_not_checked(tmp_path):
88
+ # §3.2: without a venue profile every Family B check is
89
+ # NOT-CHECKED(no venue profile) — never guessed from the journal name
90
+ # (R-L3-2-D mirror). The checks stay visible (deterministic,
91
+ # strict-eligible) so the slice-4 fail-closed path has something to see.
92
+ rc, report, _ = run_on("clean", tmp_path)
93
+ assert rc == 3
94
+ by_id = checks_by_id(report)
95
+ for cid in ("B1", "B2", "B3", "B4", "B5"):
96
+ assert by_id[cid]["status"] == "not_checked"
97
+ assert "no venue profile" in by_id[cid]["detail"]
98
+ assert by_id[cid]["family"] == "venue_limits"
99
+ assert by_id[cid]["signal_class"] == "deterministic"
100
+ assert by_id[cid]["strict_eligible"] is True
101
+ assert report["header"]["not_checked_count"] == 5
102
+ jsonschema.validate(report, load_schema())
103
+
104
+
105
+ def test_clean_report_validates_against_schema(tmp_path):
106
+ _, report, _ = run_on("clean", tmp_path)
107
+ jsonschema.validate(report, load_schema())
108
+
109
+
110
+ def test_policy_slug_is_null_in_standalone_runs(tmp_path):
111
+ # §5.2/§5.3: the script never reads terminal_policies; the slug is stamped
112
+ # by the slice-4 orchestrator hook. A standalone run always emits null.
113
+ _, report, _ = run_on("clean", tmp_path)
114
+ assert report["header"]["policy_slug"] is None
115
+
116
+
117
+ def test_report_written_into_package_dir(tmp_path):
118
+ _, _, package_dir = run_on("clean", tmp_path)
119
+ assert (package_dir / REPORT_BASENAME).is_file()
120
+
121
+
122
+ def test_full_profile_all_family_b_pass(tmp_path):
123
+ # venue_clean satisfies every limit in profiles/full.yaml; with both
124
+ # families green the exit code is a true 0.
125
+ profile = FIXTURES / "profiles" / "full.yaml"
126
+ rc, report, _ = run_on("venue_clean", tmp_path,
127
+ extra_args=["--venue-profile", str(profile)])
128
+ assert rc == 0
129
+ by_id = checks_by_id(report)
130
+ for cid in ("B1", "B2", "B3", "B4", "B5", "C1", "C2"):
131
+ assert by_id[cid]["status"] == "pass", (cid, by_id[cid]["detail"])
132
+ # §3.2: the word-count method is declared in the report, never implied
133
+ # venue-exact.
134
+ assert "whitespace-split" in by_id["B1"]["detail"]
135
+ assert "body_only" in by_id["B1"]["detail"]
136
+ assert report["header"]["not_checked_count"] == 0
137
+ jsonschema.validate(report, load_schema())
138
+
139
+
140
+ def test_violated_profile_every_family_b_check_fails(tmp_path):
141
+ # Mutation discipline (§8): every Family B check has a fixture that fails
142
+ # it. venue_violations breaks all five limits in profiles/tight.yaml.
143
+ profile = FIXTURES / "profiles" / "tight.yaml"
144
+ rc, report, _ = run_on("venue_violations", tmp_path,
145
+ extra_args=["--venue-profile", str(profile)])
146
+ assert rc == 1
147
+ by_id = checks_by_id(report)
148
+ for cid in ("B1", "B2", "B3", "B4", "B5"):
149
+ assert by_id[cid]["status"] == "fail", (cid, by_id[cid]["detail"])
150
+ assert by_id[cid]["signal_class"] == "deterministic"
151
+ assert by_id[cid]["strict_eligible"] is True
152
+ assert "Data Availability" in by_id["B4"]["detail"]
153
+ # Family C stays green — the violations are venue limits, not integrity.
154
+ assert by_id["C1"]["status"] == "pass"
155
+ jsonschema.validate(report, load_schema())
156
+
157
+
158
+ def test_partial_profile_runs_what_it_can(tmp_path):
159
+ # §4: a partially-declared profile runs the checks it can and
160
+ # NOT-CHECKEDs the rest, each with the undeclared field named.
161
+ profile = tmp_path / "partial.yaml"
162
+ profile.write_text(
163
+ "word_limit: 200\ndeclared_by: scholar\n", encoding="utf-8")
164
+ rc, report, _ = run_on("venue_clean", tmp_path,
165
+ extra_args=["--venue-profile", str(profile)])
166
+ assert rc == 3
167
+ by_id = checks_by_id(report)
168
+ assert by_id["B1"]["status"] == "pass"
169
+ for cid, field in (("B2", "abstract_word_limit"),
170
+ ("B3", "keyword_range"),
171
+ ("B4", "required_sections"),
172
+ ("B5", "reference_limit")):
173
+ assert by_id[cid]["status"] == "not_checked"
174
+ assert f"{field} not declared" in by_id[cid]["detail"]
175
+
176
+
177
+ def test_word_count_tolerance_two_percent(tmp_path):
178
+ # §3.2: ±2% tolerance before fail (format-conversion noise). 101 words
179
+ # against a 100 limit passes; 103 fails.
180
+ profile = tmp_path / "profile.yaml"
181
+ profile.write_text(
182
+ "word_limit: 100\ndeclared_by: scholar\n", encoding="utf-8")
183
+ for n_words, expected in ((101, "pass"), (103, "fail")):
184
+ package = tmp_path / f"pkg{n_words}"
185
+ package.mkdir()
186
+ (package / "paper.md").write_text(
187
+ " ".join(["word"] * n_words) + "\n", encoding="utf-8")
188
+ run([str(package), "--venue-profile", str(profile)])
189
+ report = json.loads(
190
+ (package / REPORT_BASENAME).read_text(encoding="utf-8"))
191
+ assert checks_by_id(report)["B1"]["status"] == expected, n_words
192
+
193
+
194
+ def test_invalid_venue_profile_is_usage_error(tmp_path):
195
+ package = tmp_path / "pkg"
196
+ package.mkdir()
197
+ (package / "paper.md").write_text("# x\n", encoding="utf-8")
198
+ cases = (
199
+ "word_limit: 100\n", # no declared_by
200
+ "declared_by: tool\n", # wrong provenance
201
+ "declared_by: scholar\nword_count_scope: detexed\n", # bad enum
202
+ "declared_by: scholar\nkeyword_range: {min: 5, max: 2}\n", # min>max
203
+ "declared_by: scholar\nword_limit: -3\n", # bad int
204
+ )
205
+ for body in cases:
206
+ profile = tmp_path / "bad.yaml"
207
+ profile.write_text(body, encoding="utf-8")
208
+ assert run([str(package), "--venue-profile", str(profile)]) == 2, body
209
+
210
+
211
+ def test_missing_abstract_and_keywords_not_checked(tmp_path):
212
+ # Declared limits whose actuals cannot be located are NOT-CHECKED with the
213
+ # reason — never folded into pass (§1.4), never guessed.
214
+ profile = tmp_path / "profile.yaml"
215
+ profile.write_text(
216
+ "abstract_word_limit: 50\nkeyword_range: {min: 1, max: 5}\n"
217
+ "declared_by: scholar\n", encoding="utf-8")
218
+ rc, report, _ = run_on("clean", tmp_path,
219
+ extra_args=["--venue-profile", str(profile)])
220
+ by_id = checks_by_id(report)
221
+ assert by_id["B2"]["status"] == "not_checked"
222
+ assert "no abstract section" in by_id["B2"]["detail"]
223
+ assert by_id["B3"]["status"] == "not_checked"
224
+ assert "no keywords line" in by_id["B3"]["detail"]
225
+
226
+
227
+ def test_latex_manuscript_word_count_declares_detex(tmp_path):
228
+ # §10 item 4 (adjudicated at slice 2): LaTeX counting = naive detex +
229
+ # whitespace-split, the method is declared in the report, never promised
230
+ # venue-exact.
231
+ profile = tmp_path / "profile.yaml"
232
+ profile.write_text(
233
+ "word_limit: 5\ndeclared_by: scholar\n", encoding="utf-8")
234
+ rc, report, _ = run_on("fallback_latex", tmp_path,
235
+ extra_args=["--venue-profile", str(profile)])
236
+ by_id = checks_by_id(report)
237
+ assert by_id["B1"]["status"] == "fail"
238
+ assert "naive detex" in by_id["B1"]["detail"]
239
+ assert by_id["B1"]["location"] == "paper.tex"
240
+
241
+
242
+ def test_word_count_scope_all_counts_everything(tmp_path):
243
+ # codex P2: `all` must actually count everything (keywords line included);
244
+ # only body_only / body_plus_references exclude it. 10 body words +
245
+ # "**Keywords:** a, b" (3 tokens) against limit 10: body_only passes,
246
+ # all fails.
247
+ base = " ".join(["word"] * 10) + "\n\n**Keywords:** alpha, beta\n"
248
+ for scope, expected in (("body_only", "pass"), ("all", "fail")):
249
+ package = tmp_path / f"pkg_{scope}"
250
+ package.mkdir()
251
+ (package / "paper.md").write_text(base, encoding="utf-8")
252
+ profile = tmp_path / f"{scope}.yaml"
253
+ profile.write_text(
254
+ f"word_limit: 10\nword_count_scope: {scope}\n"
255
+ "declared_by: scholar\n", encoding="utf-8")
256
+ run([str(package), "--venue-profile", str(profile)])
257
+ report = json.loads(
258
+ (package / REPORT_BASENAME).read_text(encoding="utf-8"))
259
+ assert checks_by_id(report)["B1"]["status"] == expected, scope
260
+
261
+
262
+ def test_profile_validation_matches_schema_strictness(tmp_path):
263
+ # codex P2: the CLI gate must not be looser than
264
+ # venue_profile.schema.json — unknown fields (additionalProperties false)
265
+ # and booleans-as-integers are rejected.
266
+ package = tmp_path / "pkg"
267
+ package.mkdir()
268
+ (package / "paper.md").write_text("# x\n", encoding="utf-8")
269
+ cases = (
270
+ "declared_by: scholar\nword_limt: 100\n", # unknown field (typo)
271
+ "declared_by: scholar\nword_limit: true\n", # bool is not an int
272
+ "declared_by: scholar\nvenue_name: 42\n", # venue_name not a string
273
+ "declared_by: scholar\nkeyword_range: {min: -1, max: 2}\n", # min < 0
274
+ )
275
+ for body in cases:
276
+ profile = tmp_path / "bad.yaml"
277
+ profile.write_text(body, encoding="utf-8")
278
+ assert run([str(package), "--venue-profile", str(profile)]) == 2, body
279
+
280
+
281
+ def test_ambiguous_manuscript_not_checked(tmp_path):
282
+ # codex P2: with several non-canonical candidates the verifier must not
283
+ # silently pick the wordiest (it could be a response letter); it reports
284
+ # NOT-CHECKED(ambiguous manuscript). A canonical name (paper.* /
285
+ # manuscript.* / main.*) resolves the ambiguity.
286
+ profile = tmp_path / "profile.yaml"
287
+ profile.write_text(
288
+ "word_limit: 100\ndeclared_by: scholar\n", encoding="utf-8")
289
+ package = tmp_path / "pkg"
290
+ package.mkdir()
291
+ (package / "chapter_one.md").write_text("alpha " * 20, encoding="utf-8")
292
+ (package / "rejoinder.md").write_text("beta " * 30, encoding="utf-8")
293
+ run([str(package), "--venue-profile", str(profile)])
294
+ report = json.loads(
295
+ (package / REPORT_BASENAME).read_text(encoding="utf-8"))
296
+ b1 = checks_by_id(report)["B1"]
297
+ assert b1["status"] == "not_checked"
298
+ assert "ambiguous manuscript" in b1["detail"]
299
+
300
+ (package / "paper.md").write_text("gamma " * 10, encoding="utf-8")
301
+ run([str(package), "--venue-profile", str(profile)])
302
+ report = json.loads(
303
+ (package / REPORT_BASENAME).read_text(encoding="utf-8"))
304
+ b1 = checks_by_id(report)["B1"]
305
+ assert b1["status"] == "pass"
306
+ assert b1["location"] == "paper.md"
307
+
308
+
309
+ def test_abstract_tolerance_and_b5_no_reference_list(tmp_path):
310
+ # codex P3: pin the B2 ±2% tolerance and the B5
311
+ # declared-limit-but-no-reference-list branch.
312
+ profile = tmp_path / "profile.yaml"
313
+ profile.write_text(
314
+ "abstract_word_limit: 100\nreference_limit: 5\n"
315
+ "declared_by: scholar\n", encoding="utf-8")
316
+ for n_words, expected in ((101, "pass"), (103, "fail")):
317
+ package = tmp_path / f"pkg{n_words}"
318
+ package.mkdir()
319
+ (package / "paper.md").write_text(
320
+ "## Abstract\n\n" + " ".join(["word"] * n_words) + "\n",
321
+ encoding="utf-8")
322
+ run([str(package), "--venue-profile", str(profile)])
323
+ report = json.loads(
324
+ (package / REPORT_BASENAME).read_text(encoding="utf-8"))
325
+ by_id = checks_by_id(report)
326
+ assert by_id["B2"]["status"] == expected, n_words
327
+ assert by_id["B5"]["status"] == "not_checked"
328
+ assert "no machine-readable reference list" in by_id["B5"]["detail"]
329
+
330
+
331
+ def test_profile_with_no_manuscript_not_checked(tmp_path):
332
+ profile = tmp_path / "profile.yaml"
333
+ profile.write_text(
334
+ "word_limit: 100\ndeclared_by: scholar\n", encoding="utf-8")
335
+ package = tmp_path / "pkg"
336
+ package.mkdir()
337
+ (package / "figure.png").write_bytes(b"\x89PNG\r\n")
338
+ run([str(package), "--venue-profile", str(profile)])
339
+ report = json.loads(
340
+ (package / REPORT_BASENAME).read_text(encoding="utf-8"))
341
+ b1 = checks_by_id(report)["B1"]
342
+ assert b1["status"] == "not_checked"
343
+ assert "no manuscript found" in b1["detail"]
344
+
345
+
346
+ # --- Slice 3: Family A blind-review residue ----------------------------------
347
+
348
+ def test_family_a_not_applicable_without_trigger(tmp_path):
349
+ # §3.1: the residue scan runs only when the package contains an anonymized
350
+ # variant or the profile declares double-blind. Untriggered checks are
351
+ # not_applicable — visibly distinct from not_checked (they did not need to
352
+ # run), so a single-blind package is not condemned to exit 3 forever.
353
+ rc, report, _ = run_on("clean", tmp_path)
354
+ by_id = checks_by_id(report)
355
+ for cid in ("A1", "A2", "A3", "A4", "A5", "A6", "A7"):
356
+ assert by_id[cid]["status"] == "not_applicable", cid
357
+ assert "not triggered" in by_id[cid]["detail"]
358
+ assert by_id[cid]["family"] == "blind_review_residue"
359
+ # not_applicable is not incompleteness: it does not count as not_checked.
360
+ assert report["header"]["not_checked_count"] == 5 # the B checks only
361
+ jsonschema.validate(report, load_schema())
362
+
363
+
364
+ def test_declared_double_blind_without_variant_fails_A7(tmp_path):
365
+ # §3.1: a declared-double-blind package with NO anonymized variant is
366
+ # itself a fail — the most basic residue of all, the blind version is
367
+ # missing. A1-A6 have nothing to scan: not_checked.
368
+ profile = tmp_path / "double.yaml"
369
+ profile.write_text(
370
+ "blind_review: double\ndeclared_by: scholar\n", encoding="utf-8")
371
+ rc, report, _ = run_on("clean", tmp_path,
372
+ extra_args=["--venue-profile", str(profile)])
373
+ assert rc == 1
374
+ by_id = checks_by_id(report)
375
+ assert by_id["A7"]["status"] == "fail"
376
+ assert "anonymized manuscript variant" in by_id["A7"]["detail"]
377
+ assert by_id["A7"]["strict_eligible"] is True
378
+ for cid in ("A1", "A2", "A3", "A4", "A5", "A6"):
379
+ assert by_id[cid]["status"] == "not_checked", cid
380
+ assert "no anonymized variant" in by_id[cid]["detail"]
381
+
382
+
383
+ def test_anonymized_variant_triggers_family_a(tmp_path):
384
+ # Presence of an anonymized variant triggers the scan even without a
385
+ # profile (presence-or-declaration, §3.1). With an .md-only variant the
386
+ # PDF/DOCX metadata checks have no object: not_applicable.
387
+ package = tmp_path / "pkg"
388
+ package.mkdir()
389
+ (package / "paper.md").write_text(
390
+ "Body (Smith, 2024) <!--ref:smith2024-->.\n", encoding="utf-8")
391
+ shutil.copy(FIXTURES / "clean" / "references.bib",
392
+ package / "references.bib")
393
+ (package / "paper_anonymized.md").write_text(
394
+ "# T\n\nBody text without identity.\n", encoding="utf-8")
395
+ rc, report = run_dir(package)
396
+ by_id = checks_by_id(report)
397
+ assert by_id["A7"]["status"] == "pass"
398
+ for cid in ("A1", "A2", "A3"):
399
+ assert by_id[cid]["status"] == "not_applicable", cid
400
+ assert "no PDF" in by_id[cid]["detail"] or "no DOCX" in by_id[cid]["detail"]
401
+ jsonschema.validate(report, load_schema())
402
+
403
+
404
+ _DOCX_CORE_TMPL = (
405
+ '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
406
+ '<cp:coreProperties '
407
+ 'xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" '
408
+ 'xmlns:dc="http://purl.org/dc/elements/1.1/">'
409
+ "<dc:creator>{creator}</dc:creator>"
410
+ "<cp:lastModifiedBy>{last_modified_by}</cp:lastModifiedBy>"
411
+ "</cp:coreProperties>")
412
+ _DOCX_DOC_TMPL = (
413
+ '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
414
+ '<w:document '
415
+ 'xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">'
416
+ "<w:body><w:p><w:r><w:t>Blind body text.</w:t></w:r></w:p>{extra}</w:body>"
417
+ "</w:document>")
418
+
419
+
420
+ def make_docx(path, creator="", last_modified_by="", ins_author=None,
421
+ comment_author=None):
422
+ """Minimal raw-structure .docx (a zip with core.xml + document.xml [+
423
+ comments.xml]) — exactly the parts the residue scan reads (§1.3: the
424
+ deliverable is the raw file, not the rendered view)."""
425
+ extra = ""
426
+ if ins_author:
427
+ extra = (f'<w:ins w:id="1" w:author="{ins_author}">'
428
+ "<w:r><w:t>inserted</w:t></w:r></w:ins>")
429
+ with zipfile.ZipFile(path, "w") as z:
430
+ z.writestr("docProps/core.xml", _DOCX_CORE_TMPL.format(
431
+ creator=creator, last_modified_by=last_modified_by))
432
+ z.writestr("word/document.xml", _DOCX_DOC_TMPL.format(extra=extra))
433
+ if comment_author:
434
+ z.writestr(
435
+ "word/comments.xml",
436
+ '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
437
+ '<w:comments xmlns:w="http://schemas.openxmlformats.org/'
438
+ 'wordprocessingml/2006/main">'
439
+ f'<w:comment w:id="0" w:author="{comment_author}">'
440
+ "<w:p><w:r><w:t>note</w:t></w:r></w:p></w:comment>"
441
+ "</w:comments>")
442
+
443
+
444
+ def _blind_package(tmp_path, **docx_kwargs):
445
+ package = tmp_path / "pkg"
446
+ package.mkdir()
447
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
448
+ make_docx(package / "paper_anonymized.docx", **docx_kwargs)
449
+ rc, report = run_dir(package)
450
+ return checks_by_id(report)
451
+
452
+
453
+ def test_docx_metadata_author_residue_fails_A2(tmp_path):
454
+ # A2 (§3.1): docProps/core.xml creator / lastModifiedBy non-empty in the
455
+ # blind variant is a deterministic fact about the file — invisible to any
456
+ # rendered-view scan (§1.3).
457
+ by_id = _blind_package(tmp_path, creator="Jordan Smith")
458
+ assert by_id["A2"]["status"] == "fail"
459
+ assert "Jordan Smith" in by_id["A2"]["detail"]
460
+ assert by_id["A2"]["strict_eligible"] is True
461
+ assert by_id["A3"]["status"] == "pass"
462
+
463
+
464
+ def test_docx_clean_metadata_passes_A2_A3(tmp_path):
465
+ by_id = _blind_package(tmp_path)
466
+ assert by_id["A2"]["status"] == "pass"
467
+ assert by_id["A3"]["status"] == "pass"
468
+
469
+
470
+ def test_docx_tracked_change_author_fails_A3(tmp_path):
471
+ by_id = _blind_package(tmp_path, ins_author="J. Smith")
472
+ assert by_id["A3"]["status"] == "fail"
473
+ assert "J. Smith" in by_id["A3"]["detail"]
474
+
475
+
476
+ def test_docx_comment_author_fails_A3(tmp_path):
477
+ by_id = _blind_package(tmp_path, comment_author="Reviewer Zero")
478
+ assert by_id["A3"]["status"] == "fail"
479
+ assert "Reviewer Zero" in by_id["A3"]["detail"]
480
+
481
+
482
+ def test_corrupt_docx_not_checked(tmp_path):
483
+ # An unreadable artifact is incompleteness, never folded into pass (§1.4).
484
+ package = tmp_path / "pkg"
485
+ package.mkdir()
486
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
487
+ (package / "paper_anonymized.docx").write_bytes(b"not a zip")
488
+ _rc, report = run_dir(package)
489
+ by_id = checks_by_id(report)
490
+ for cid in ("A2", "A3"):
491
+ assert by_id[cid]["status"] == "not_checked"
492
+ assert "unreadable" in by_id[cid]["detail"]
493
+
494
+
495
+ def test_pdf_metadata_author_fails_A1(tmp_path):
496
+ pypdf = pytest.importorskip("pypdf")
497
+
498
+ package = tmp_path / "pkg"
499
+ package.mkdir()
500
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
501
+ writer = pypdf.PdfWriter()
502
+ writer.add_blank_page(width=72, height=72)
503
+ writer.add_metadata({"/Author": "Jordan Smith"})
504
+ with open(package / "paper_blind.pdf", "wb") as f:
505
+ writer.write(f)
506
+ _rc, report = run_dir(package)
507
+ a1 = checks_by_id(report)["A1"]
508
+ assert a1["status"] == "fail"
509
+ assert "Jordan Smith" in a1["detail"]
510
+ assert a1["strict_eligible"] is True
511
+
512
+
513
+ def test_pdf_parser_unavailable_is_not_checked(tmp_path, monkeypatch):
514
+ # §1.4/#349: a missing parser must surface as NOT-CHECKED, never read as
515
+ # covered. (The slice-4 strict mode turns this into
516
+ # VERIFICATION-INCOMPLETE.)
517
+ import verify_submission_package as v
518
+
519
+ monkeypatch.setattr(v, "pypdf", None)
520
+ package = tmp_path / "pkg"
521
+ package.mkdir()
522
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
523
+ (package / "paper_blind.pdf").write_bytes(b"%PDF-1.4\n%%EOF\n")
524
+ _rc, report = run_dir(package)
525
+ a1 = checks_by_id(report)["A1"]
526
+ assert a1["status"] == "not_checked"
527
+ assert "pypdf" in a1["detail"]
528
+
529
+
530
+ def test_A4_strict_only_when_profile_forbids_acknowledgments(tmp_path):
531
+ # §3.1 load-bearing: A4's SIGNAL is deterministic but the judgment is the
532
+ # scholar's — strict-eligible ONLY when the venue profile explicitly
533
+ # declares acknowledgments must be removed from the blind version.
534
+ def build(profile_body):
535
+ package = tmp_path / f"pkg{len(profile_body)}"
536
+ package.mkdir()
537
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
538
+ (package / "paper_anonymized.md").write_text(
539
+ "# Title\n\n## Acknowledgments\n\nWe thank our colleagues.\n",
540
+ encoding="utf-8")
541
+ profile = tmp_path / f"p{len(profile_body)}.yaml"
542
+ profile.write_text(profile_body, encoding="utf-8")
543
+ run([str(package), "--venue-profile", str(profile)])
544
+ return json.loads(
545
+ (package / REPORT_BASENAME).read_text(encoding="utf-8"))
546
+
547
+ base = "blind_review: double\ndeclared_by: scholar\n"
548
+ a4 = checks_by_id(build(base))["A4"]
549
+ assert a4["status"] == "fail"
550
+ assert a4["strict_eligible"] is False
551
+
552
+ a4 = checks_by_id(build(
553
+ base + "acknowledgments_forbidden_in_blind: true\n"))["A4"]
554
+ assert a4["status"] == "fail"
555
+ assert a4["strict_eligible"] is True
556
+
557
+
558
+ def test_A6_filename_leakage_from_original_metadata(tmp_path):
559
+ # §3.1 A6: author-name tokens harvested from the NON-anonymized artifact's
560
+ # metadata, matched against package filenames (heuristic — coincidental
561
+ # tokens can false-positive). The metadata-source original itself is not
562
+ # scanned (its identified name is expected).
563
+ package = tmp_path / "pkg"
564
+ package.mkdir()
565
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
566
+ make_docx(package / "paper.docx", creator="Jordan Smith")
567
+ make_docx(package / "paper_anonymized.docx")
568
+ (package / "smith_appendix.csv").write_text("x\n", encoding="utf-8")
569
+ _rc, report = run_dir(package)
570
+ a6 = checks_by_id(report)["A6"]
571
+ assert a6["status"] == "fail"
572
+ assert "smith_appendix.csv" in a6["detail"]
573
+ assert a6["signal_class"] == "heuristic"
574
+ assert a6["strict_eligible"] is False
575
+
576
+
577
+ def test_A6_without_original_metadata_not_checked(tmp_path):
578
+ package = tmp_path / "pkg"
579
+ package.mkdir()
580
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
581
+ (package / "paper_anonymized.md").write_text("Body.\n", encoding="utf-8")
582
+ _rc, report = run_dir(package)
583
+ a6 = checks_by_id(report)["A6"]
584
+ assert a6["status"] == "not_checked"
585
+ assert "no author" in a6["detail"]
586
+
587
+
588
+ def test_A5_zh_tw_self_citation_phrase(tmp_path):
589
+ # §10 item 1: the phrasing list must not be anglophone-only.
590
+ package = tmp_path / "pkg"
591
+ package.mkdir()
592
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
593
+ (package / "paper_anonymized.md").write_text(
594
+ "# 匿名稿\n\n如我們先前的研究所示,品保回饋迴圈存在斷點。\n",
595
+ encoding="utf-8")
596
+ _rc, report = run_dir(package)
597
+ a5 = checks_by_id(report)["A5"]
598
+ assert a5["status"] == "fail"
599
+ assert "我們先前的研究" in a5["detail"]
600
+
601
+
602
+ def test_A5_zh_tw_third_person_author_self_reference(tmp_path):
603
+ # zh-TW curation (#394 follow-up): third-person self-reference via
604
+ # 本文作者 — the bare 作者先前 would false-positive on 該作者先前
605
+ # (a cited third party's author), so the phrase is anchored on the
606
+ # 本文 prefix.
607
+ package = tmp_path / "pkg"
608
+ package.mkdir()
609
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
610
+ (package / "paper_anonymized.md").write_text(
611
+ "# 匿名稿\n\n本文作者先前已就品保回饋迴圈提出分析架構。\n",
612
+ encoding="utf-8")
613
+ _rc, report = run_dir(package)
614
+ a5 = checks_by_id(report)["A5"]
615
+ assert a5["status"] == "fail"
616
+ assert "本文作者先前" in a5["detail"]
617
+
618
+
619
+ def test_A5_other_authors_prior_work_not_flagged(tmp_path):
620
+ # 該作者先前 refers to a cited third party, not the manuscript's own
621
+ # authors — must stay clean (the reason the phrase list does not carry
622
+ # a bare 作者先前 entry).
623
+ package = tmp_path / "pkg"
624
+ package.mkdir()
625
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
626
+ (package / "paper_anonymized.md").write_text(
627
+ "# 匿名稿\n\n該作者先前的研究指出品保回饋迴圈存在斷點。\n",
628
+ encoding="utf-8")
629
+ _rc, report = run_dir(package)
630
+ a5 = checks_by_id(report)["A5"]
631
+ assert a5["status"] == "pass"
632
+
633
+
634
+ # --- codex slice-3 review round ----------------------------------------------
635
+
636
+ def test_A4_docx_only_variant_is_not_checked_not_applicable(tmp_path):
637
+ # codex P1: a DOCX-only blind variant means the acknowledgments scan
638
+ # SHOULD run but cannot (no text-form variant to read headings from) —
639
+ # that is not_checked honesty, never not_applicable masquerade.
640
+ package = tmp_path / "pkg"
641
+ package.mkdir()
642
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
643
+ make_docx(package / "paper_anonymized.docx")
644
+ _rc, report = run_dir(package)
645
+ a4 = checks_by_id(report)["A4"]
646
+ assert a4["status"] == "not_checked"
647
+ assert "text-form" in a4["detail"]
648
+
649
+
650
+ def test_A7_not_satisfied_by_blind_named_supplement(tmp_path):
651
+ # codex P1: a declared double-blind package whose only blind-named file is
652
+ # an ancillary CSV has NO blind manuscript variant — A7 must still fail.
653
+ package = tmp_path / "pkg"
654
+ package.mkdir()
655
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
656
+ (package / "blind_survey.csv").write_text("q,a\n", encoding="utf-8")
657
+ profile = tmp_path / "double.yaml"
658
+ profile.write_text(
659
+ "blind_review: double\ndeclared_by: scholar\n", encoding="utf-8")
660
+ rc = run([str(package), "--venue-profile", str(profile)])
661
+ report = json.loads(
662
+ (package / REPORT_BASENAME).read_text(encoding="utf-8"))
663
+ assert rc == 1
664
+ assert checks_by_id(report)["A7"]["status"] == "fail"
665
+
666
+
667
+ def test_untriggered_A4_is_never_strict_eligible(tmp_path):
668
+ # codex P1: A4's eligibility comes ONLY from the explicit profile
669
+ # declaration — including on the untriggered/not_applicable path.
670
+ _rc, report, _ = run_on("clean", tmp_path)
671
+ assert checks_by_id(report)["A4"]["strict_eligible"] is False
672
+
673
+
674
+ def test_A6_token_match_does_not_flag_substrings(tmp_path):
675
+ # codex P2: token-to-token matching — `Smith` must not flag
676
+ # `blacksmith_notes.md`.
677
+ package = tmp_path / "pkg"
678
+ package.mkdir()
679
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
680
+ make_docx(package / "paper.docx", creator="Jordan Smith")
681
+ make_docx(package / "paper_anonymized.docx")
682
+ (package / "blacksmith_notes.md").write_text("x\n", encoding="utf-8")
683
+ _rc, report = run_dir(package)
684
+ a6 = checks_by_id(report)["A6"]
685
+ assert a6["status"] == "pass", a6["detail"]
686
+
687
+
688
+ def test_oversized_docx_part_is_not_checked(tmp_path, monkeypatch):
689
+ # codex P2: unbounded zip reads are a zip-bomb exposure; oversized parts
690
+ # are reported as unreadable incompleteness, never scanned or passed.
691
+ import verify_submission_package as v
692
+
693
+ monkeypatch.setattr(v, "_MAX_XML_PART_BYTES", 64)
694
+ package = tmp_path / "pkg"
695
+ package.mkdir()
696
+ (package / "paper.md").write_text("Body.\n", encoding="utf-8")
697
+ make_docx(package / "paper_anonymized.docx",
698
+ creator="x" * 200) # inflates core.xml past the test cap
699
+ _rc, report = run_dir(package)
700
+ a2 = checks_by_id(report)["A2"]
701
+ assert a2["status"] == "not_checked"
702
+ assert "unreadable" in a2["detail"]
703
+
704
+
705
+ def test_profile_rejects_nonboolean_acknowledgments_forbidden_field(tmp_path):
706
+ package = tmp_path / "pkg"
707
+ package.mkdir()
708
+ (package / "paper.md").write_text("# x\n", encoding="utf-8")
709
+ profile = tmp_path / "p.yaml"
710
+ profile.write_text(
711
+ "declared_by: scholar\nacknowledgments_forbidden_in_blind: maybe\n",
712
+ encoding="utf-8")
713
+ assert run([str(package), "--venue-profile", str(profile)]) == 2
714
+
715
+
716
+ def test_schema_accepts_not_applicable():
717
+ # (Unknown statuses are rejected by test_schema_rejects_unknown_status.)
718
+ ok = _minimal_report(status="not_applicable")
719
+ jsonschema.validate(ok, load_schema())
720
+
721
+
722
+ def test_venue_profile_fixtures_validate_against_schema():
723
+ profile_schema = json.loads(
724
+ (REPO_ROOT / "shared" / "contracts" / "submission"
725
+ / "venue_profile.schema.json").read_text(encoding="utf-8"))
726
+ for name in ("full.yaml", "tight.yaml"):
727
+ profile = yaml.safe_load(
728
+ (FIXTURES / "profiles" / name).read_text(encoding="utf-8"))
729
+ jsonschema.validate(profile, profile_schema)
730
+
731
+
732
+ # --- Round 2: fail / warn / NOT-CHECKED paths + exit codes -------------------
733
+
734
+ def test_orphan_intext_citation_fails_C1_exit_1(tmp_path):
735
+ rc, report, _ = run_on("orphan_intext", tmp_path)
736
+ assert rc == 1
737
+ by_id = checks_by_id(report)
738
+ assert by_id["C1"]["status"] == "fail"
739
+ assert "ghost2024" in by_id["C1"]["detail"]
740
+ assert by_id["C1"]["location"] == "paper.md"
741
+ # The orphan is deterministic-classed on the joined marker path.
742
+ assert by_id["C1"]["signal_class"] == "deterministic"
743
+ assert by_id["C1"]["strict_eligible"] is True
744
+ jsonschema.validate(report, load_schema())
745
+
746
+
747
+ def test_uncited_reference_entry_warns_C2_exit_0(tmp_path):
748
+ # §3.3: uncited reference entry = warn (some venues allow further-reading
749
+ # entries) — advisory, never a fail exit (3 = Family B not checked).
750
+ rc, report, _ = run_on("uncited_reference", tmp_path)
751
+ assert rc == 3
752
+ by_id = checks_by_id(report)
753
+ assert by_id["C1"]["status"] == "pass"
754
+ assert by_id["C2"]["status"] == "warn"
755
+ assert "chenlee2023" in by_id["C2"]["detail"]
756
+
757
+
758
+ def test_markers_without_join_source_not_checked_exit_3(tmp_path):
759
+ # §3.3 + §8 join test: markers present, passport supplies a corpus (a
760
+ # reference list) but NO citation_verification_summary — never a guessed
761
+ # comparison.
762
+ passport = FIXTURES / "passports" / "corpus_only.yaml"
763
+ rc, report, _ = run_on("marker_no_join", tmp_path,
764
+ extra_args=["--passport", str(passport)])
765
+ assert rc == 3
766
+ by_id = checks_by_id(report)
767
+ for cid in ("C1", "C2"):
768
+ assert by_id[cid]["status"] == "not_checked"
769
+ assert "missing prose-reference join" in by_id[cid]["detail"]
770
+ assert report["header"]["not_checked_count"] == 7 # 2 C + 5 B (no profile)
771
+ assert report["header"]["extraction_path"] == "none"
772
+ jsonschema.validate(report, load_schema())
773
+
774
+
775
+ def test_join_map_resolves_the_no_join_case(tmp_path):
776
+ # The explicit scholar-supplied join map is a valid join source (§3.3) and
777
+ # joins the prose slug to the corpus citation_key.
778
+ passport = FIXTURES / "passports" / "corpus_only.yaml"
779
+ join = tmp_path / "join.yaml"
780
+ join.write_text("smith-feedback-2024: smith2024\n", encoding="utf-8")
781
+ rc, report, _ = run_on(
782
+ "marker_no_join", tmp_path,
783
+ extra_args=["--passport", str(passport), "--join-map", str(join)])
784
+ assert rc == 3 # Family C green; B not checked (no profile)
785
+ by_id = checks_by_id(report)
786
+ assert by_id["C1"]["status"] == "pass"
787
+ assert by_id["C2"]["status"] == "pass"
788
+ assert report["header"]["extraction_path"] == "joined_marker"
789
+
790
+
791
+ def test_missing_package_dir_is_usage_error(tmp_path):
792
+ assert run([str(tmp_path / "does-not-exist")]) == 2
793
+
794
+
795
+ def test_unparseable_passport_is_usage_error(tmp_path):
796
+
797
+ bad = tmp_path / "bad.yaml"
798
+ bad.write_text("just a string\n", encoding="utf-8")
799
+ package = tmp_path / "pkg"
800
+ package.mkdir()
801
+ (package / "paper.md").write_text("# x\n", encoding="utf-8")
802
+ assert run([str(package), "--passport", str(bad)]) == 2
803
+
804
+
805
+ # --- Round 3: fallback extraction, summary join, fingerprint -----------------
806
+
807
+ def test_fallback_latex_cite_extraction_is_heuristic_best_effort(tmp_path):
808
+ # §3.3: post-converted sources fall back to \cite{} extraction; the header
809
+ # downgrades to best-effort and the whole path is heuristic-classed
810
+ # (advisory-only) — even a true orphan fail is NOT strict-eligible.
811
+ rc, report, _ = run_on("fallback_latex", tmp_path)
812
+ assert rc == 1
813
+ assert report["header"]["extraction_path"] == "best_effort"
814
+ by_id = checks_by_id(report)
815
+ assert by_id["C1"]["status"] == "fail"
816
+ assert "ghost2024" in by_id["C1"]["detail"]
817
+ assert "smith2024" not in by_id["C1"]["detail"]
818
+ for cid in ("C1", "C2"):
819
+ assert by_id[cid]["signal_class"] == "heuristic"
820
+ assert by_id[cid]["strict_eligible"] is False
821
+ assert by_id["C2"]["status"] == "pass"
822
+ jsonschema.validate(report, load_schema())
823
+
824
+
825
+ def test_fallback_authoryear_extraction_matches_bib_metadata(tmp_path):
826
+ rc, report, _ = run_on("fallback_authoryear", tmp_path)
827
+ assert rc == 1
828
+ assert report["header"]["extraction_path"] == "best_effort"
829
+ by_id = checks_by_id(report)
830
+ # Only the unmatched (Nowhere, 2020) is an orphan; Smith (2024) narrative
831
+ # and (Chen & Lee, 2023) parenthetical both join to bib metadata.
832
+ assert by_id["C1"]["status"] == "fail"
833
+ assert "nowhere" in by_id["C1"]["detail"].lower()
834
+ assert "smith" not in by_id["C1"]["detail"].lower()
835
+ assert "chen" not in by_id["C1"]["detail"].lower()
836
+ # Both bib entries were cited, so C2 passes — and the references section
837
+ # itself was not scanned as in-text prose.
838
+ assert by_id["C2"]["status"] == "pass"
839
+ assert by_id["C1"]["signal_class"] == "heuristic"
840
+
841
+
842
+ def test_summary_join_consumes_real_prose_join(tmp_path):
843
+ # The prose slug (smith-feedback-2024) differs from the citation_key
844
+ # (smith2024): a pass proves the citation_verification_summary join was
845
+ # consumed, not an identity guess (§3.3).
846
+ passport = FIXTURES / "passports" / "summary_join.yaml"
847
+ rc, report, _ = run_on("summary_join", tmp_path,
848
+ extra_args=["--passport", str(passport)])
849
+ assert rc == 3 # Family C green; B not checked (no profile)
850
+ by_id = checks_by_id(report)
851
+ assert by_id["C1"]["status"] == "pass"
852
+ assert by_id["C2"]["status"] == "pass"
853
+ assert report["header"]["extraction_path"] == "joined_marker"
854
+ for cid in ("C1", "C2"):
855
+ assert by_id[cid]["signal_class"] == "deterministic"
856
+
857
+
858
+ def test_no_machine_readable_reference_list_not_checked(tmp_path):
859
+ package = tmp_path / "pkg"
860
+ package.mkdir()
861
+ (package / "paper.md").write_text(
862
+ "Smith (2024) said things.\n", encoding="utf-8")
863
+ rc = run([str(package)])
864
+ report = json.loads(
865
+ (package / REPORT_BASENAME).read_text(encoding="utf-8"))
866
+ assert rc == 3
867
+ by_id = checks_by_id(report)
868
+ for cid in ("C1", "C2"):
869
+ assert by_id[cid]["status"] == "not_checked"
870
+ assert "no machine-readable reference list" in by_id[cid]["detail"]
871
+
872
+
873
+ def test_fingerprint_follows_audit_snapshot_convention_excluding_report(tmp_path):
874
+ # §10 open item 3 (adjudicated at slice 1): `<relative-path>:<sha256>`
875
+ # lines, byte-sorted, trailing newline, fingerprint = sha256 of the
876
+ # manifest text; the report file itself is excluded. Pinned here by an
877
+ # independent reimplementation.
878
+ import hashlib
879
+
880
+ _, report, package_dir = run_on("clean", tmp_path)
881
+ lines = []
882
+ for p in sorted(package_dir.rglob("*")):
883
+ if not p.is_file() or p.name == REPORT_BASENAME:
884
+ continue
885
+ digest = hashlib.sha256(p.read_bytes()).hexdigest()
886
+ lines.append(f"{p.relative_to(package_dir).as_posix()}:{digest}")
887
+ lines.sort()
888
+ expected = hashlib.sha256(
889
+ ("\n".join(lines) + "\n").encode("utf-8")).hexdigest()
890
+ assert report["header"]["package_fingerprint"] == expected
891
+
892
+
893
+ def test_fingerprint_stable_across_reruns_with_report_present(tmp_path):
894
+ # Second run sees the first run's report inside the package dir; the
895
+ # exclusion keeps the fingerprint stable (freshness guard usable, §5.2).
896
+
897
+ _, first, package_dir = run_on("clean", tmp_path)
898
+ run([str(package_dir)])
899
+ second = json.loads(
900
+ (package_dir / REPORT_BASENAME).read_text(encoding="utf-8"))
901
+ assert (second["header"]["package_fingerprint"]
902
+ == first["header"]["package_fingerprint"])
903
+
904
+
905
+ # --- Codex review round: P1 partial-join identity guess + P2s ----------------
906
+
907
+ def test_partial_summary_join_never_falls_back_to_identity(tmp_path):
908
+ # P1: a marker slug ABSENT from the join source must never be compared via
909
+ # an identity guess — even (especially) when the slug coincidentally equals
910
+ # a citation_key in the reference list (§3.3 "never a guessed comparison").
911
+ package = tmp_path / "pkg"
912
+ package.mkdir()
913
+ (package / "paper.md").write_text(
914
+ "Joined (Smith, 2024) <!--ref:smith-feedback-2024-->.\n"
915
+ "Unjoined but key-shaped (Smith, 2024) <!--ref:smith2024-->.\n",
916
+ encoding="utf-8")
917
+ passport = FIXTURES / "passports" / "summary_join.yaml"
918
+ rc = run([str(package), "--passport", str(passport)])
919
+ report = json.loads(
920
+ (package / REPORT_BASENAME).read_text(encoding="utf-8"))
921
+ assert rc == 1
922
+ by_id = checks_by_id(report)
923
+ assert by_id["C1"]["status"] == "fail"
924
+ assert "no join entry" in by_id["C1"]["detail"]
925
+ assert "smith2024" in by_id["C1"]["detail"]
926
+
927
+
928
+ def test_C2_is_never_strict_eligible(tmp_path):
929
+ # P2: C2's worst outcome is warn, which is advisory-only and never
930
+ # policy-promotable (§5.3) — so the check itself is not strict-eligible,
931
+ # even on the deterministic path.
932
+ _, report, _ = run_on("clean", tmp_path)
933
+ by_id = checks_by_id(report)
934
+ assert by_id["C1"]["strict_eligible"] is True
935
+ assert by_id["C2"]["strict_eligible"] is False
936
+
937
+
938
+ def test_custom_report_out_inside_package_excluded_from_fingerprint(tmp_path):
939
+ # P2: a --report-out path inside the package must be excluded from the
940
+ # fingerprint like the default basename, or reruns self-reference.
941
+
942
+ package = tmp_path / "clean"
943
+ shutil.copytree(FIXTURES / "clean", package)
944
+ out = package / "custom_report.json"
945
+ run([str(package), "--report-out", str(out)])
946
+ first = json.loads(out.read_text(encoding="utf-8"))
947
+ run([str(package), "--report-out", str(out)])
948
+ second = json.loads(out.read_text(encoding="utf-8"))
949
+ assert (first["header"]["package_fingerprint"]
950
+ == second["header"]["package_fingerprint"])
951
+
952
+
953
+ def test_authoryear_fallback_tolerates_page_locators(tmp_path):
954
+ # P3: `Smith (2024, p. 12)` / `(Chen & Lee, 2023, pp. 45–67)` are common
955
+ # locator forms; missing them creates avoidable fallback false orphans.
956
+ package = tmp_path / "pkg"
957
+ package.mkdir()
958
+ (package / "paper.md").write_text(
959
+ "Smith (2024, p. 12) framed it; details follow "
960
+ "(Chen & Lee, 2023, pp. 45–67).\n", encoding="utf-8")
961
+ shutil.copy(FIXTURES / "fallback_authoryear" / "references.bib",
962
+ package / "references.bib")
963
+ rc = run([str(package)])
964
+ report = json.loads(
965
+ (package / REPORT_BASENAME).read_text(encoding="utf-8"))
966
+ by_id = checks_by_id(report)
967
+ assert rc == 3 # Family C green; B not checked (no profile)
968
+ assert by_id["C1"]["status"] == "pass"
969
+ assert by_id["C2"]["status"] == "pass"
970
+
971
+
972
+ def test_schema_rejects_warn_with_strict_eligible():
973
+ # P2: warn is advisory-only and never policy-promotable — tightened
974
+ # structurally like the heuristic exclusion.
975
+ bad = _minimal_report(status="warn", strict_eligible=True)
976
+ with pytest.raises(jsonschema.ValidationError):
977
+ jsonschema.validate(bad, load_schema())
978
+ ok = _minimal_report(status="warn", strict_eligible=False)
979
+ jsonschema.validate(ok, load_schema())
980
+
981
+
982
+ # --- Report schema structural contract --------------------------------------
983
+
984
+ def _minimal_report(**check_overrides):
985
+ check = {
986
+ "id": "C1",
987
+ "family": "reference_integrity",
988
+ "signal_class": "deterministic",
989
+ "strict_eligible": True,
990
+ "status": "pass",
991
+ "detail": "ok",
992
+ "location": None,
993
+ }
994
+ check.update(check_overrides)
995
+ return {
996
+ "header": {
997
+ "extraction_path": "joined_marker",
998
+ "not_checked_count": 0,
999
+ "package_fingerprint": "0" * 64,
1000
+ "inputs_fingerprint": "0" * 64,
1001
+ "policy_slug": None,
1002
+ },
1003
+ "checks": [check],
1004
+ }
1005
+
1006
+
1007
+ def test_schema_rejects_heuristic_strict_eligible():
1008
+ # §3.1/§6: heuristic checks are advisory-only STRUCTURALLY — the schema
1009
+ # itself forbids the promotion, not just the emitter.
1010
+ bad = _minimal_report(signal_class="heuristic", strict_eligible=True)
1011
+ with pytest.raises(jsonschema.ValidationError):
1012
+ jsonschema.validate(bad, load_schema())
1013
+ ok = _minimal_report(signal_class="heuristic", strict_eligible=False)
1014
+ jsonschema.validate(ok, load_schema())
1015
+
1016
+
1017
+ def test_schema_binds_check_id_prefix_to_family():
1018
+ # The id prefix encodes the family (spec §3 tables); the contract binds
1019
+ # them so a later-slice emitter cannot ship mismatched pairs.
1020
+ bad = _minimal_report(id="C1", family="blind_review_residue")
1021
+ with pytest.raises(jsonschema.ValidationError):
1022
+ jsonschema.validate(bad, load_schema())
1023
+ bad2 = _minimal_report(id="A1", family="reference_integrity")
1024
+ with pytest.raises(jsonschema.ValidationError):
1025
+ jsonschema.validate(bad2, load_schema())
1026
+
1027
+
1028
+ def test_schema_rejects_unknown_status():
1029
+ bad = _minimal_report(status="skipped")
1030
+ with pytest.raises(jsonschema.ValidationError):
1031
+ jsonschema.validate(bad, load_schema())
1032
+
1033
+
1034
+ # --- Slice 4: terminality (--policy / --check-freshness, spec §5.2/§5.3/§8) --
1035
+ #
1036
+ # Terminal signals are STDOUT TOKENS (TERMINAL-BLOCK / VERIFICATION-INCOMPLETE
1037
+ # / STALE-REPORT), never raw exit codes — exit 1 also carries nonterminal
1038
+ # advisory/heuristic fails (gate-1 P1). The evaluator keys on STATUS
1039
+ # (fail / not_checked), never on the strict_eligible bit alone, so
1040
+ # not_applicable can never compose into a block (slice-3 schema pin).
1041
+
1042
+ def _strict_run(fixture_name, tmp_path, capsys, extra_args=()):
1043
+ rc, report, package_dir = run_on(
1044
+ fixture_name, tmp_path,
1045
+ extra_args=["--policy", "strict", *extra_args])
1046
+ out = capsys.readouterr().out
1047
+ return rc, report, package_dir, out
1048
+
1049
+
1050
+ def test_strict_eligible_fail_blocks_with_token(tmp_path, capsys):
1051
+ # orphan_intext fails C1 on the joined marker path (deterministic class).
1052
+ rc, report, _, out = _strict_run("orphan_intext", tmp_path, capsys)
1053
+ assert rc == 1
1054
+ assert "TERMINAL-BLOCK policy=submission_package" in out
1055
+ assert report["header"]["policy_slug"] == "strict"
1056
+
1057
+
1058
+ def test_strict_heuristic_fail_never_promotes(tmp_path, capsys):
1059
+ # fallback_latex fails C1 on the FALLBACK path (heuristic class). Under
1060
+ # strict the heuristic fail must NEVER appear as a TERMINAL-BLOCK
1061
+ # (§3.1/§6, structural exclusion). The run exits 4, not 1: the
1062
+ # profileless Family B not_checked outranks the nonterminal fail —
1063
+ # itself evidence of the fail-closed precedence (a heuristic fail does
1064
+ # not short-circuit the incompleteness verdict the way a strict fail
1065
+ # would).
1066
+ rc, report, _, out = _strict_run("fallback_latex", tmp_path, capsys)
1067
+ by_id = checks_by_id(report)
1068
+ assert by_id["C1"]["status"] == "fail"
1069
+ assert by_id["C1"]["signal_class"] == "heuristic"
1070
+ assert "TERMINAL-BLOCK" not in out
1071
+ assert rc == 4 # VERIFICATION-INCOMPLETE from Family B, not the C1 fail
1072
+ assert "C1" not in next(
1073
+ l for l in out.splitlines() if "VERIFICATION-INCOMPLETE" in l)
1074
+
1075
+
1076
+ def test_evaluate_policy_unit_contract():
1077
+ # Unit pin of the evaluator's whole decision table: token + exit per
1078
+ # policy×status×strict_eligible combination, including precedence (a
1079
+ # strict fail outranks incomplete) and the not_applicable
1080
+ # never-composes rule. The advisory/strict divergence lives inside the
1081
+ # evaluator (it takes the resolved policy), so non-strict policies are
1082
+ # part of the table.
1083
+ from verify_submission_package import evaluate_policy
1084
+
1085
+ def report_of(*checks):
1086
+ return {"checks": [
1087
+ {"id": cid, "strict_eligible": se, "status": status}
1088
+ for cid, se, status in checks
1089
+ ]}
1090
+
1091
+ # Heuristic (strict_eligible=False) fail alone under strict: exit 1,
1092
+ # NO token.
1093
+ token, code = evaluate_policy(report_of(("A5", False, "fail"),
1094
+ ("C2", True, "pass")), "strict")
1095
+ assert token is None and code == 1
1096
+ # Strict-eligible fail under strict: token + exit 1.
1097
+ token, code = evaluate_policy(report_of(("B4", True, "fail")), "strict")
1098
+ assert code == 1 and "TERMINAL-BLOCK policy=submission_package" in token
1099
+ assert "B4" in token
1100
+ # The SAME report under advisory / under no policy: never a token —
1101
+ # the divergence is the evaluator's own contract, not a caller guard.
1102
+ for policy in ("advisory", None):
1103
+ token, code = evaluate_policy(report_of(("B4", True, "fail")), policy)
1104
+ assert token is None and code == 1
1105
+ # Strict-eligible not_checked under strict: incomplete token + exit 4.
1106
+ token, code = evaluate_policy(
1107
+ report_of(("B1", True, "not_checked")), "strict")
1108
+ assert code == 4 and "VERIFICATION-INCOMPLETE" in token
1109
+ # ... and under advisory: plain exit 3, no token.
1110
+ token, code = evaluate_policy(
1111
+ report_of(("B1", True, "not_checked")), "advisory")
1112
+ assert token is None and code == 3
1113
+ # Precedence: strict fail wins over incomplete (block now, the rerun
1114
+ # after remediation surfaces the rest).
1115
+ token, code = evaluate_policy(report_of(("B4", True, "fail"),
1116
+ ("B1", True, "not_checked")),
1117
+ "strict")
1118
+ assert code == 1 and "TERMINAL-BLOCK" in token
1119
+ # not_applicable never composes into anything (slice-3 schema pin),
1120
+ # heuristic not_checked doesn't either.
1121
+ token, code = evaluate_policy(report_of(("A1", True, "not_applicable"),
1122
+ ("A5", False, "not_checked"),
1123
+ ("C2", True, "pass")), "strict")
1124
+ assert token is None and code == 3
1125
+ # All green under strict: clean 0.
1126
+ token, code = evaluate_policy(report_of(("C1", True, "pass")), "strict")
1127
+ assert token is None and code == 0
1128
+
1129
+
1130
+ def test_strict_eligible_not_checked_is_verification_incomplete(
1131
+ tmp_path, capsys):
1132
+ # venue_clean without a profile: Family B is strict-eligible not_checked
1133
+ # → fail-closed exit 4 + token (§5.2: a missing input must not silently
1134
+ # waive the class the scholar opted into blocking on).
1135
+ rc, report, _, out = _strict_run("venue_clean", tmp_path, capsys)
1136
+ assert rc == 4
1137
+ assert "VERIFICATION-INCOMPLETE" in out
1138
+ assert "TERMINAL-BLOCK" not in out
1139
+ assert report["header"]["policy_slug"] == "strict"
1140
+
1141
+
1142
+ def test_advisory_same_not_checked_stays_exit_3(tmp_path, capsys):
1143
+ # Explicit advisory: byte-identical slice-3 behavior except the stamp.
1144
+ rc, report, _, = run_on("venue_clean", tmp_path,
1145
+ extra_args=["--policy", "advisory"])
1146
+ out = capsys.readouterr().out
1147
+ assert rc == 3
1148
+ assert "VERIFICATION-INCOMPLETE" not in out
1149
+ assert "TERMINAL-BLOCK" not in out
1150
+ assert report["header"]["policy_slug"] == "advisory"
1151
+
1152
+
1153
+ def test_no_policy_flag_stamps_null(tmp_path):
1154
+ # Standalone unevaluated run: argparse default is None (never "default
1155
+ # advisory" — gate-1 P1), the stamp stays null.
1156
+ _, report, _ = run_on("venue_clean", tmp_path)
1157
+ assert report["header"]["policy_slug"] is None
1158
+
1159
+
1160
+ def test_strict_not_applicable_never_blocks(tmp_path, capsys):
1161
+ # clean has no anonymized variant and no blind_review declaration: Family
1162
+ # A is not_applicable (untriggered). Under strict that must NOT read as
1163
+ # incomplete or block — the evaluator keys on status, and not_applicable
1164
+ # is neither fail nor not_checked. (Family B absent-profile not_checked
1165
+ # still yields exit 4 here, proving the discrimination is per-status.)
1166
+ rc, report, _, out = _strict_run("clean", tmp_path, capsys)
1167
+ by_id = checks_by_id(report)
1168
+ assert by_id["A1"]["status"] == "not_applicable"
1169
+ assert rc == 4 # from Family B not_checked, NOT from Family A
1170
+ assert "VERIFICATION-INCOMPLETE" in out
1171
+ token_line = next(l for l in out.splitlines()
1172
+ if "VERIFICATION-INCOMPLETE" in l)
1173
+ for aid in (f"A{i}" for i in range(1, 8)):
1174
+ assert aid not in token_line
1175
+
1176
+
1177
+ def test_strict_full_profile_clean_package_exits_0(tmp_path, capsys):
1178
+ # The strict happy path: everything checked, everything green.
1179
+ profile = FIXTURES / "profiles" / "full.yaml"
1180
+ rc, report, _, out = _strict_run(
1181
+ "venue_clean", tmp_path, capsys,
1182
+ extra_args=["--venue-profile", str(profile)])
1183
+ assert rc == 0
1184
+ assert "TERMINAL-BLOCK" not in out
1185
+ assert "VERIFICATION-INCOMPLETE" not in out
1186
+ assert report["header"]["policy_slug"] == "strict"
1187
+
1188
+
1189
+ # --- Slice 4: freshness guard (--check-freshness, §5.2) ----------------------
1190
+
1191
+ def _fresh_args(policy="advisory"):
1192
+ return ["--check-freshness", "--policy", policy]
1193
+
1194
+
1195
+ def test_freshness_mutated_package_is_stale(tmp_path, capsys):
1196
+ _, _, package_dir = run_on("venue_clean", tmp_path,
1197
+ extra_args=["--policy", "advisory"])
1198
+ manuscript = next(p for p in package_dir.iterdir()
1199
+ if p.suffix == ".md" and p.name != "provenance_summary.md")
1200
+ manuscript.write_text(
1201
+ manuscript.read_text(encoding="utf-8") + "\nDrifted.\n",
1202
+ encoding="utf-8")
1203
+ capsys.readouterr()
1204
+ rc = run([str(package_dir), *_fresh_args()])
1205
+ out = capsys.readouterr().out
1206
+ assert rc == 5
1207
+ assert "STALE-REPORT" in out
1208
+
1209
+
1210
+ def test_freshness_policy_mismatch_is_stale(tmp_path, capsys):
1211
+ # Report stamped advisory, orchestrator now wants strict: stale, rerun.
1212
+ _, _, package_dir = run_on("venue_clean", tmp_path,
1213
+ extra_args=["--policy", "advisory"])
1214
+ capsys.readouterr()
1215
+ rc = run([str(package_dir), *_fresh_args(policy="strict")])
1216
+ out = capsys.readouterr().out
1217
+ assert rc == 5
1218
+ assert "STALE-REPORT" in out
1219
+
1220
+
1221
+ def test_freshness_null_stamped_report_never_fresh(tmp_path, capsys):
1222
+ # A standalone (unevaluated, policy_slug=null) report never satisfies
1223
+ # pipeline freshness — gate-1 P1 (null must not impersonate advisory).
1224
+ # The reason token is pinned: null_policy_slug ("you handed the pipeline
1225
+ # a standalone report") is a different remediation from policy_mismatch
1226
+ # ("the policy changed since stamping") — without the dedicated branch
1227
+ # the null case would collapse into the mismatch reason.
1228
+ _, _, package_dir = run_on("venue_clean", tmp_path) # no --policy
1229
+ capsys.readouterr()
1230
+ rc = run([str(package_dir), *_fresh_args()])
1231
+ out = capsys.readouterr().out
1232
+ assert rc == 5
1233
+ assert "STALE-REPORT reason=null_policy_slug" in out
1234
+
1235
+
1236
+ def test_freshness_missing_report_is_stale(tmp_path, capsys):
1237
+ package_dir = tmp_path / "pkg"
1238
+ package_dir.mkdir()
1239
+ (package_dir / "paper.md").write_text("Body.\n", encoding="utf-8")
1240
+ rc = run([str(package_dir), *_fresh_args()])
1241
+ out = capsys.readouterr().out
1242
+ assert rc == 5
1243
+ assert "STALE-REPORT" in out
1244
+
1245
+
1246
+ def test_freshness_requires_policy(tmp_path, capsys):
1247
+ # --check-freshness without --policy is a usage error (exit 2): freshness
1248
+ # is always relative to an expected policy, never free-floating.
1249
+ _, _, package_dir = run_on("venue_clean", tmp_path,
1250
+ extra_args=["--policy", "advisory"])
1251
+ capsys.readouterr()
1252
+ rc = run([str(package_dir), "--check-freshness"])
1253
+ err = capsys.readouterr().err
1254
+ assert rc == 2
1255
+ assert "policy" in err.lower()
1256
+
1257
+
1258
+ def test_freshness_does_not_rerun_checks(tmp_path, capsys):
1259
+ # Freshness must not rewrite the report: mtime-stable bytes.
1260
+ _, _, package_dir = run_on("venue_clean", tmp_path,
1261
+ extra_args=["--policy", "advisory"])
1262
+ report_path = package_dir / REPORT_BASENAME
1263
+ before = report_path.read_bytes()
1264
+ capsys.readouterr()
1265
+ run([str(package_dir), *_fresh_args()])
1266
+ assert report_path.read_bytes() == before
1267
+
1268
+
1269
+ def test_provenance_summary_outside_fingerprint(tmp_path, capsys):
1270
+ # gate-1 P1 self-staleness: provenance_summary.md is the pipeline's own
1271
+ # advisory carrier (D4 appends to it AFTER the report is stamped) — it is
1272
+ # excluded from the fingerprint, so mutating it does NOT stale the report.
1273
+ package_dir = tmp_path / "venue_clean"
1274
+ shutil.copytree(FIXTURES / "venue_clean", package_dir)
1275
+ (package_dir / "provenance_summary.md").write_text(
1276
+ "# Provenance\n", encoding="utf-8")
1277
+ rc, _ = run_dir(package_dir, extra_args=["--policy", "advisory"])
1278
+ (package_dir / "provenance_summary.md").write_text(
1279
+ "# Provenance\n\n## Submission Package Advisories\n\n- B2: ...\n",
1280
+ encoding="utf-8")
1281
+ capsys.readouterr()
1282
+ rc = run([str(package_dir), *_fresh_args()])
1283
+ out = capsys.readouterr().out
1284
+ # Fresh (no STALE token); the exit code is the re-emitted underlying
1285
+ # verdict — 3 here (profileless Family B not_checked), NOT a stale 5.
1286
+ assert rc == 3
1287
+ assert "STALE-REPORT" not in out
1288
+ assert "report fresh" in out
1289
+
1290
+
1291
+ def test_advisory_run_is_byte_equivalent_for_package_files(tmp_path):
1292
+ # §11 byte-equivalence: an explicit-advisory run mutates NOTHING in the
1293
+ # package except adding the report file.
1294
+ package_dir = tmp_path / "venue_clean"
1295
+ shutil.copytree(FIXTURES / "venue_clean", package_dir)
1296
+ before = {
1297
+ p.relative_to(package_dir).as_posix(): p.read_bytes()
1298
+ for p in package_dir.rglob("*") if p.is_file()
1299
+ }
1300
+ profile = FIXTURES / "profiles" / "full.yaml"
1301
+ run_dir(package_dir, extra_args=["--policy", "advisory",
1302
+ "--venue-profile", str(profile)])
1303
+ after = {
1304
+ p.relative_to(package_dir).as_posix(): p.read_bytes()
1305
+ for p in package_dir.rglob("*") if p.is_file()
1306
+ }
1307
+ assert set(after) - set(before) == {REPORT_BASENAME}
1308
+ for rel, content in before.items():
1309
+ assert after[rel] == content, f"{rel} mutated by an advisory run"
1310
+
1311
+
1312
+ # --- Slice 4 gate-2 review round: freshness re-emit + external inputs -------
1313
+
1314
+ def test_freshness_fresh_strict_report_reemits_terminal_token(
1315
+ tmp_path, capsys):
1316
+ # Gate-2 P1: freshness alone means "the report is trustworthy", not "the
1317
+ # package passed". A fresh strict report that recorded a blocking fail
1318
+ # must re-emit its terminal verdict on reuse — otherwise the verdict
1319
+ # silently evaporates on resume and the orchestrator (gating on tokens)
1320
+ # reads the reuse as a pass.
1321
+ _, _, package_dir = run_on("orphan_intext", tmp_path,
1322
+ extra_args=["--policy", "strict"])
1323
+ capsys.readouterr()
1324
+ rc = run([str(package_dir), "--check-freshness", "--policy", "strict"])
1325
+ out = capsys.readouterr().out
1326
+ assert rc == 1
1327
+ assert "report fresh" in out
1328
+ assert "TERMINAL-BLOCK policy=submission_package" in out
1329
+
1330
+
1331
+ def test_freshness_fresh_advisory_report_reemits_underlying_code(
1332
+ tmp_path, capsys):
1333
+ # Same contract on the advisory side: a fresh advisory report with
1334
+ # not_checked rows re-emits exit 3, not a flat 0.
1335
+ _, _, package_dir = run_on("venue_clean", tmp_path,
1336
+ extra_args=["--policy", "advisory"])
1337
+ capsys.readouterr()
1338
+ rc = run([str(package_dir), *_fresh_args()])
1339
+ out = capsys.readouterr().out
1340
+ assert rc == 3
1341
+ assert "report fresh" in out
1342
+ assert "STALE-REPORT" not in out
1343
+
1344
+
1345
+ def test_freshness_changed_venue_profile_is_stale(tmp_path, capsys):
1346
+ # Gate-2 P1: Family B verdicts depend on the venue profile — a report
1347
+ # produced under one profile must never read as fresh under another
1348
+ # (a lenient-profile report would otherwise waive a stricter profile's
1349
+ # limits without any check ever running against them).
1350
+ full = FIXTURES / "profiles" / "full.yaml"
1351
+ tight = FIXTURES / "profiles" / "tight.yaml"
1352
+ _, _, package_dir = run_on(
1353
+ "venue_clean", tmp_path,
1354
+ extra_args=["--policy", "advisory", "--venue-profile", str(full)])
1355
+ capsys.readouterr()
1356
+ rc = run([str(package_dir), "--check-freshness", "--policy", "advisory",
1357
+ "--venue-profile", str(tight)])
1358
+ out = capsys.readouterr().out
1359
+ assert rc == 5
1360
+ assert "STALE-REPORT reason=inputs_mismatch" in out
1361
+
1362
+
1363
+ def test_freshness_same_venue_profile_stays_fresh(tmp_path, capsys):
1364
+ full = FIXTURES / "profiles" / "full.yaml"
1365
+ _, _, package_dir = run_on(
1366
+ "venue_clean", tmp_path,
1367
+ extra_args=["--policy", "advisory", "--venue-profile", str(full)])
1368
+ capsys.readouterr()
1369
+ rc = run([str(package_dir), "--check-freshness", "--policy", "advisory",
1370
+ "--venue-profile", str(full)])
1371
+ out = capsys.readouterr().out
1372
+ assert rc == 0
1373
+ assert "report fresh" in out
1374
+
1375
+
1376
+ def test_freshness_dropped_input_is_stale(tmp_path, capsys):
1377
+ # Running with a profile, then checking freshness WITHOUT one, is an
1378
+ # inputs change (declared → absent) and must be stale.
1379
+ full = FIXTURES / "profiles" / "full.yaml"
1380
+ _, _, package_dir = run_on(
1381
+ "venue_clean", tmp_path,
1382
+ extra_args=["--policy", "advisory", "--venue-profile", str(full)])
1383
+ capsys.readouterr()
1384
+ rc = run([str(package_dir), *_fresh_args()])
1385
+ out = capsys.readouterr().out
1386
+ assert rc == 5
1387
+ assert "STALE-REPORT reason=inputs_mismatch" in out
1388
+
1389
+
1390
+ def test_freshness_thinned_roster_is_stale(tmp_path, capsys):
1391
+ # Final-round review P2: the report file is excluded from the package
1392
+ # fingerprint, so a hand-edited report with checks thinned out (here:
1393
+ # emptied) would otherwise read as fresh and re-evaluate to a clean
1394
+ # exit — the roster guard build_report enforces at write time must
1395
+ # hold on reuse too.
1396
+ _, _, package_dir = run_on("orphan_intext", tmp_path,
1397
+ extra_args=["--policy", "strict"])
1398
+ report_path = package_dir / REPORT_BASENAME
1399
+ doctored = json.loads(report_path.read_text(encoding="utf-8"))
1400
+ doctored["checks"] = []
1401
+ report_path.write_text(json.dumps(doctored), encoding="utf-8")
1402
+ capsys.readouterr()
1403
+ rc = run([str(package_dir), "--check-freshness", "--policy", "strict"])
1404
+ out = capsys.readouterr().out
1405
+ assert rc == 5
1406
+ assert "STALE-REPORT reason=roster_mismatch" in out
1407
+ assert "report fresh" not in out