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,1594 @@
1
+ """claim_audit_pipeline — Python implementation of the §4 Step 1-6 pipeline.
2
+
3
+ This module is the executable face of `claim_ref_alignment_audit_agent.md`.
4
+ The agent prompt narrates the pipeline contract; this module runs it
5
+ under test so cross-field invariants and emission routing can be pinned
6
+ without dispatching the agent to a live model.
7
+
8
+ Retrieval and judge invocation are dependency-injected (`retrieve_fn` /
9
+ `judge_fn`) so tests can drive every error and decision path — paywall,
10
+ audit_tool_failure, not_found, SUPPORTED, UNSUPPORTED with each
11
+ defect_stage hint, VIOLATED. Production callers wire these to real
12
+ retrieval/judge clients in their own dispatch layer.
13
+
14
+ The full spec is in
15
+ docs/design/2026-05-15-issue-103-claim-alignment-audit-spec.md §4-§5.
16
+ """
17
+ from __future__ import annotations
18
+
19
+ import hashlib
20
+ import json
21
+ import sys
22
+ from pathlib import Path
23
+ from typing import Any, Callable
24
+
25
+ # Allow both CLI invocations (`python3 scripts/claim_audit_pipeline.py`) AND
26
+ # package-style invocations (`python -m unittest scripts.test_*`) to resolve
27
+ # the shared constants module via the same import.
28
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
29
+ from _claim_audit_constants import ( # noqa: E402
30
+ DRIFT_RULE_VERSION,
31
+ INV6_RATIONALE_PREFIX,
32
+ JUDGE_PROMPT_SHA256,
33
+ RE_NC_CONSTRAINT,
34
+ SAMPLING_STRATEGY,
35
+ SENTINEL_MANIFEST_ID,
36
+ UAF_RULE_VERSION,
37
+ UNCITED_RULE_VERSION,
38
+ is_emittable_partial_breakdown,
39
+ )
40
+
41
+ # Permitted UNSUPPORTED defect_stages for non-constraint paths (§3.1 matrix).
42
+ _UNSUPPORTED_NON_CONSTRAINT_DEFECTS = {
43
+ "source_description",
44
+ "metadata",
45
+ "citation_anchor",
46
+ "synthesis_overclaim",
47
+ }
48
+
49
+ # Permitted AMBIGUOUS defect_stages (§3.1 matrix).
50
+ _AMBIGUOUS_DEFECTS = {"source_description", "citation_anchor", "synthesis_overclaim", None}
51
+
52
+
53
+ # ---------------------------------------------------------------------------
54
+ # Cache helpers.
55
+ # ---------------------------------------------------------------------------
56
+
57
+
58
+ def _stable_json(value: Any) -> str:
59
+ """JCS-style canonicalization sufficient for cache-key hashing."""
60
+ return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
61
+
62
+
63
+ def _hash_text(text: str | None) -> str:
64
+ return hashlib.sha256((text or "").encode("utf-8")).hexdigest()
65
+
66
+
67
+ # claim_audit_result.rationale schema maxLength (#355 P2#3). A judge/retrieval
68
+ # failure detail that embeds the offending payload's repr must fit here, or the
69
+ # "clean inconclusive" fallback row it produces is itself schema-invalid. Every
70
+ # JudgeInvocationError / RetrievalInvocationError detail ends up in a row's
71
+ # rationale via `f"{fault_class}: {detail}"`, so the bound lives in those
72
+ # exceptions' constructors (single choke point) rather than at each raise site.
73
+ _RATIONALE_MAX_LEN = 2000
74
+ _RATIONALE_TRUNC_MARK = "…[truncated]"
75
+ # Widest fault-class prefix across both exception families ("retrieval_network_error: ").
76
+ _WIDEST_FAULT_PREFIX = "retrieval_network_error: "
77
+
78
+ # #512 PDF read-integrity rationale tag. Appended (never prepended — INV-6/INV-14
79
+ # startswith contracts stay intact) to a completed manual_pdf page-anchor row whose
80
+ # preflight sidecar is missing or non-PASS. The finalizer keys its advisory
81
+ # annotation on this exact substring; keep in lockstep with
82
+ # claim_audit_finalizer.PDF_READ_INTEGRITY_TAG.
83
+ PDF_READ_INTEGRITY_TAG = "[pdf_read_integrity_unverified]"
84
+
85
+
86
+ def _tag_pdf_read_integrity(entry: dict[str, Any]) -> None:
87
+ """#512: mark a manual_pdf page-anchor row whose preflight did not vouch.
88
+
89
+ Applied at the single Step-6 emission point AFTER cache resolution, so a cache
90
+ hit cannot bypass it (the tag is run-context, never written into the judge
91
+ cache body). Idempotent; respects the rationale maxLength budget."""
92
+ rationale = entry.get("rationale") or ""
93
+ if PDF_READ_INTEGRITY_TAG in rationale:
94
+ return
95
+ if rationale:
96
+ clamped = _clamp_to_rationale_budget(
97
+ rationale, reserved=len(PDF_READ_INTEGRITY_TAG) + 1
98
+ )
99
+ entry["rationale"] = f"{clamped} {PDF_READ_INTEGRITY_TAG}"
100
+ else:
101
+ entry["rationale"] = PDF_READ_INTEGRITY_TAG
102
+
103
+
104
+ def _clamp_to_rationale_budget(text: str, *, reserved: int) -> str:
105
+ """Clamp `text` so that `reserved + len(result)` fits the rationale maxLength.
106
+
107
+ Single length-budgeting choke point for every untrusted string that lands in
108
+ a row's `rationale` (#355 P2#3 / #360). `reserved` is the number of chars the
109
+ caller will prepend before this text reaches the rationale field:
110
+
111
+ - Failure paths emit ``f"{fault_class}: {detail}"`` → reserved = widest
112
+ fault-class prefix width, so the worst-case composed rationale still fits.
113
+ - Success paths copy a judge's own `rationale` verbatim onto the row → no
114
+ prefix → reserved = 0.
115
+
116
+ Truncation preserves the diagnostic head (which says WHAT the string is) and
117
+ marks the dropped tail, so a short string that already fits passes through
118
+ byte-for-byte.
119
+ """
120
+ budget = _RATIONALE_MAX_LEN - reserved
121
+ if len(text) <= budget:
122
+ return text
123
+ keep = budget - len(_RATIONALE_TRUNC_MARK)
124
+ return text[:keep] + _RATIONALE_TRUNC_MARK
125
+
126
+
127
+ def _bounded_failure_detail(message: str) -> str:
128
+ """Clamp a failure detail so ``f"{fault_class}: {detail}"`` fits the maxLength.
129
+
130
+ A malformed payload's repr embedded in `message` (a >1000-char
131
+ sub_claim_text, an over-decomposed breakdown, a giant non-string
132
+ judgment/method) can push the detail past the rationale maxLength, making the
133
+ fallback row schema-invalid (#355 P2#3). Budgets against the widest
134
+ fault-class prefix so the composed rationale fits for every fault class.
135
+ """
136
+ return _clamp_to_rationale_budget(message, reserved=len(_WIDEST_FAULT_PREFIX))
137
+
138
+
139
+ def _bounded_judge_rationale(rationale: Any) -> str:
140
+ """Clamp a judge-supplied `rationale` copied verbatim onto a SUCCESS-path row.
141
+
142
+ The judge is an LLM with no pre-emission length guarantee; an over-long
143
+ `rationale` makes a *clean* completed / constraint_violation row
144
+ schema-invalid (#360 — the success-path parallel to the #359 fallback fix).
145
+ No fault-class prefix is prepended on the success path, so reserved = 0.
146
+
147
+ `_validate_judge_dict` only checks that the `rationale` key is present, not
148
+ that its value is a string — a JSON-null (or otherwise non-string) rationale
149
+ passes that gate. Return "" for a non-string value so each caller's existing
150
+ fallback (`... or "(no rationale provided)"` / the constraint default) takes
151
+ over, rather than calling len() on it and aborting the audit run.
152
+ """
153
+ if not isinstance(rationale, str):
154
+ return ""
155
+ return _clamp_to_rationale_budget(rationale, reserved=0)
156
+
157
+
158
+ def _active_constraints_for_claim(
159
+ *,
160
+ scoped_manifest_id: str,
161
+ claim_id: str,
162
+ claim_by_mc_id: dict[tuple[str, str], dict[str, Any]],
163
+ mncs_by_manifest_id: dict[str, list[dict[str, Any]]],
164
+ ) -> list[dict[str, Any]]:
165
+ """Return the manifest-scoped + claim-scoped negative-constraint set for a citation.
166
+
167
+ Reads from pre-built indexes (built once per audit run in
168
+ `run_audit_pipeline`) instead of rescanning the manifest tree per
169
+ citation — at realistic workloads (~150 citations × ~100 manifest
170
+ claims) that saves ~30k Python ops per run with no behavioral delta.
171
+ """
172
+ constraints: list[dict[str, Any]] = []
173
+ for mnc in mncs_by_manifest_id.get(scoped_manifest_id, []):
174
+ constraints.append({"constraint_id": mnc["constraint_id"], "rule": mnc["rule"], "scope": "MNC"})
175
+ claim = claim_by_mc_id.get((scoped_manifest_id, claim_id))
176
+ if claim is not None:
177
+ for nc in claim.get("negative_constraints", []) or []:
178
+ constraints.append(
179
+ {"constraint_id": nc["constraint_id"], "rule": nc["rule"], "scope": "NC"}
180
+ )
181
+ constraints.sort(key=lambda c: c["constraint_id"])
182
+ return constraints
183
+
184
+
185
+ def _cache_key(
186
+ *,
187
+ claim_text: str,
188
+ ref_slug: str,
189
+ anchor_kind: str,
190
+ anchor_value: str,
191
+ retrieved_excerpt: str | None,
192
+ active_constraints: list[dict[str, Any]],
193
+ judge_model: str,
194
+ prompt_version: str,
195
+ ) -> str:
196
+ payload = {
197
+ "claim_text_hash": _hash_text(claim_text),
198
+ "ref_slug": ref_slug,
199
+ "anchor_kind": anchor_kind,
200
+ "anchor_value_hash": _hash_text(anchor_value),
201
+ "retrieved_excerpt_hash": _hash_text(retrieved_excerpt),
202
+ "active_constraints_hash": _hash_text(
203
+ _stable_json([{"constraint_id": c["constraint_id"], "rule": c["rule"]} for c in active_constraints])
204
+ ),
205
+ "judge_model": judge_model,
206
+ # #361: a judge-prompt revision partitions the keyspace — a verdict
207
+ # cached under one prompt is never served against new prompt logic.
208
+ # judge_model and prompt_version stay separate components (independent
209
+ # axes of judge behavior).
210
+ "prompt_version": prompt_version,
211
+ }
212
+ return hashlib.sha256(_stable_json(payload).encode("utf-8")).hexdigest()
213
+
214
+
215
+ # ---------------------------------------------------------------------------
216
+ # Judge + retrieval invocation — wraps callables so transient failures become
217
+ # INV-14 audit_tool_failure rows instead of aborting the audit. Spec §4 step 2
218
+ # + INV-14 + Step 13 R1+R2 codex findings (transient errors on either external
219
+ # call must surface as MED-WARN advisory rows).
220
+ # ---------------------------------------------------------------------------
221
+
222
+ # Legal judge verdicts per path. claim_audit_result schema enum + constraint-side
223
+ # verdicts (VIOLATED / NOT_VIOLATED). Cited and uncited paths route different
224
+ # subsets — passing path-specific allow-lists into `_invoke_judge` rejects an
225
+ # off-path verdict at the invocation boundary instead of letting it propagate
226
+ # into _judge_result_entry where the ValueError would abort the audit
227
+ # (Step 13 R3 codex P2 #2).
228
+ _CITED_PATH_JUDGMENTS: frozenset[str] = frozenset(
229
+ {"SUPPORTED", "UNSUPPORTED", "AMBIGUOUS", "PARTIAL", "VIOLATED"}
230
+ )
231
+ # PARTIAL is a cited-path-only verdict (a reference can support some sub-claims
232
+ # but not others). The uncited path has no reference to be partial against, so
233
+ # it stays the constraint VIOLATED/NOT_VIOLATED binary (#213).
234
+ _UNCITED_PATH_JUDGMENTS: frozenset[str] = frozenset({"VIOLATED", "NOT_VIOLATED"})
235
+
236
+
237
+ class _AuditInvocationError(Exception):
238
+ """Base for audit-tool invocation failures (judge / retrieval).
239
+
240
+ Carries an INV-14 fault-class tag + detail. The detail is bounded so the
241
+ `f"{fault_class}: {detail}"` rationale it becomes fits the claim_audit_result
242
+ schema maxLength (#355 P2#3) — every subclass's detail flows to a row
243
+ rationale, so the bound lives here (single choke point).
244
+ """
245
+
246
+ def __init__(self, fault_class: str, detail: str) -> None:
247
+ detail = _bounded_failure_detail(detail)
248
+ super().__init__(f"{fault_class}: {detail}")
249
+ self.fault_class = fault_class
250
+ self.detail = detail
251
+
252
+
253
+ class JudgeInvocationError(_AuditInvocationError):
254
+ """Raised by `_invoke_judge` when judge_fn fails or returns malformed output.
255
+
256
+ Carries the INV-14 fault-class tag + detail so the caller can emit a
257
+ `RETRIEVAL_FAILED + inconclusive + not_applicable + audit_tool_failure`
258
+ row per spec §4 step 2 + INV-14 instead of letting the exception abort the
259
+ audit pass.
260
+ """
261
+
262
+
263
+ class RetrievalInvocationError(_AuditInvocationError):
264
+ """Raised by `_invoke_retrieve` when retrieve_fn fails or returns malformed output.
265
+
266
+ Mirrors JudgeInvocationError but tags faults with the INV-14 retrieval_*
267
+ family (retrieval_api_error / retrieval_timeout / retrieval_network_error)
268
+ so a transient retrieval outage surfaces as audit_tool_failure rather than
269
+ aborting the audit pass (Step 13 R2 codex P2 finding).
270
+ """
271
+
272
+
273
+ def _validate_judge_dict(
274
+ result: Any,
275
+ *,
276
+ allowed_judgments: frozenset[str],
277
+ active_constraint_ids: frozenset[str],
278
+ source: str = "judge_fn",
279
+ ) -> dict[str, Any]:
280
+ """Validate a judge-output dict (fresh or cache-hit).
281
+
282
+ Raises `JudgeInvocationError` with the appropriate fault-class tag for any
283
+ shape violation. Pulled out of `_invoke_judge` so cache hits can reuse the
284
+ same validation surface — without it a malformed cache entry would crash
285
+ `_judge_result_entry` and abort the audit (Step 13 R3 codex P2 #4).
286
+
287
+ Validation surface:
288
+ - non-dict → judge_parse_error
289
+ - missing `judgment` or `rationale` → judge_parse_error
290
+ - judgment not in `allowed_judgments` → judge_parse_error
291
+ - VIOLATED without non-blank string id → judge_parse_error
292
+ - VIOLATED id not in `active_constraint_ids`→ judge_parse_error
293
+ (Step 13 R3 codex P2 #1 — prevents formatter gate-refuse on a
294
+ hallucinated constraint the author never declared)
295
+ """
296
+ if not isinstance(result, dict):
297
+ raise JudgeInvocationError(
298
+ "judge_parse_error",
299
+ f"{source} returned {type(result).__name__}, expected dict",
300
+ )
301
+ if "judgment" not in result or "rationale" not in result:
302
+ raise JudgeInvocationError(
303
+ "judge_parse_error",
304
+ f"{source} returned dict missing required key(s); got keys={sorted(result)}",
305
+ )
306
+ judgment = result.get("judgment")
307
+ # Step 13 R8 codex P2-3: guard isinstance(str) before set membership so a
308
+ # malformed return like {"judgment": [1, 2], ...} surfaces as a clean
309
+ # judge_parse_error instead of bubbling TypeError("unhashable type") out
310
+ # past the translation boundary and aborting the audit.
311
+ if not isinstance(judgment, str):
312
+ raise JudgeInvocationError(
313
+ "judge_parse_error",
314
+ f"{source} returned non-string judgment={judgment!r} (type={type(judgment).__name__}); expected one of {sorted(allowed_judgments)}",
315
+ )
316
+ if judgment not in allowed_judgments:
317
+ raise JudgeInvocationError(
318
+ "judge_parse_error",
319
+ f"{source} returned judgment={judgment!r}; expected one of {sorted(allowed_judgments)} on this path",
320
+ )
321
+ if judgment == "VIOLATED":
322
+ vcid = result.get("violated_constraint_id")
323
+ if not isinstance(vcid, str) or not vcid.strip():
324
+ raise JudgeInvocationError(
325
+ "judge_parse_error",
326
+ f"{source} returned VIOLATED without a valid violated_constraint_id (got {vcid!r}); INV-7 requires non-null id",
327
+ )
328
+ if vcid not in active_constraint_ids:
329
+ raise JudgeInvocationError(
330
+ "judge_parse_error",
331
+ f"{source} returned VIOLATED with violated_constraint_id={vcid!r} outside the active constraint set {sorted(active_constraint_ids)}; rejecting hallucinated id (Step 13 R3 codex P2 #1)",
332
+ )
333
+ if judgment == "PARTIAL":
334
+ # #213: a PARTIAL MUST carry a well-formed true-partial sub_claim_breakdown.
335
+ # A malformed PARTIAL is a judge-output parse failure — routing it through
336
+ # judge_parse_error yields the existing (RETRIEVAL_FAILED, inconclusive,
337
+ # not_applicable, audit_tool_failure) row, never a silent bare UNSUPPORTED
338
+ # (which would recreate the invisible-trap failure). The malformed-PARTIAL
339
+ # path has no new matrix triple; it reuses the judge_parse_error contract.
340
+ # is_emittable_*: true-partial mix AND every item schema-shaped (non-empty
341
+ # sub_claim_text + valid sub_verdict). The item-shape half is required
342
+ # because _judge_result_entry copies items onto a *completed* row; a
343
+ # mix-valid-but-malformed item (e.g. missing sub_claim_text) would emit a
344
+ # schema-invalid row instead of taking the judge_parse_error path
345
+ # (ship-gate round-2 finding).
346
+ if not is_emittable_partial_breakdown(result.get("sub_claim_breakdown")):
347
+ raise JudgeInvocationError(
348
+ "judge_parse_error",
349
+ f"{source} returned PARTIAL without an emittable true-partial sub_claim_breakdown "
350
+ f"(>=2 schema-shaped items, >=1 SUPPORTED AND >=1 non-SUPPORTED, each with a "
351
+ f"non-empty sub_claim_text); got {result.get('sub_claim_breakdown')!r}",
352
+ )
353
+ return result
354
+
355
+
356
+ def _invoke_judge(
357
+ judge_fn: Callable[..., dict[str, Any]],
358
+ *,
359
+ allowed_judgments: frozenset[str],
360
+ active_constraint_ids: frozenset[str],
361
+ **call_kwargs: Any,
362
+ ) -> dict[str, Any]:
363
+ """Invoke `judge_fn` and translate transient failures + malformed output into INV-14 tags.
364
+
365
+ Exception → fault class mapping:
366
+ - TimeoutError → judge_timeout
367
+ - json.JSONDecodeError / ValueError → judge_parse_error
368
+ - any other Exception → judge_api_error
369
+
370
+ Return-value validation delegates to `_validate_judge_dict` so cache hits
371
+ reuse the same surface (Step 13 R3 codex P2 #4).
372
+
373
+ `allowed_judgments` is path-specific: cited path passes
374
+ `_CITED_PATH_JUDGMENTS`, uncited (constraint) path passes
375
+ `_UNCITED_PATH_JUDGMENTS`. RETRIEVAL_FAILED / NOT_VIOLATED on the cited
376
+ path is rejected here instead of crashing in `_judge_result_entry`
377
+ (Step 13 R3 codex P2 #2).
378
+
379
+ `active_constraint_ids` carries the in-scope MNC/NC ids for this call
380
+ so a VIOLATED with a hallucinated id is rejected at the boundary
381
+ (Step 13 R3 codex P2 #1).
382
+
383
+ Does NOT swallow `SystemExit` / `KeyboardInterrupt`.
384
+ """
385
+ try:
386
+ result = judge_fn(**call_kwargs)
387
+ except TimeoutError as exc:
388
+ raise JudgeInvocationError("judge_timeout", str(exc) or "judge timed out") from exc
389
+ except (json.JSONDecodeError, ValueError) as exc:
390
+ raise JudgeInvocationError("judge_parse_error", str(exc) or "judge returned malformed payload") from exc
391
+ except Exception as exc: # noqa: BLE001 — translation boundary; the source class is captured
392
+ raise JudgeInvocationError("judge_api_error", f"{type(exc).__name__}: {exc}") from exc
393
+
394
+ return _validate_judge_dict(
395
+ result,
396
+ allowed_judgments=allowed_judgments,
397
+ active_constraint_ids=active_constraint_ids,
398
+ source="judge_fn",
399
+ )
400
+
401
+
402
+ def _invoke_retrieve(
403
+ retrieve_fn: Callable[[dict[str, Any]], dict[str, Any]],
404
+ citation: dict[str, Any],
405
+ ) -> dict[str, Any]:
406
+ """Invoke `retrieve_fn` and translate transient failures + malformed output into INV-14 retrieval_* tags.
407
+
408
+ Exception → fault class mapping (mirrors `_invoke_judge`):
409
+ - TimeoutError → retrieval_timeout
410
+ - OSError / ConnectionError → retrieval_network_error
411
+ - json.JSONDecodeError / ValueError → retrieval_api_error
412
+ - any other Exception → retrieval_api_error
413
+
414
+ Return-value validation:
415
+ - non-dict → retrieval_api_error
416
+ - missing `ref_retrieval_method` key → retrieval_api_error
417
+ - unknown `ref_retrieval_method` value → retrieval_api_error
418
+
419
+ Returns the retrieval dict on success; raises RetrievalInvocationError
420
+ otherwise so the caller can map it to an audit_tool_failure row.
421
+ """
422
+ try:
423
+ result = retrieve_fn(citation)
424
+ except TimeoutError as exc:
425
+ raise RetrievalInvocationError("retrieval_timeout", str(exc) or "retrieve_fn timed out") from exc
426
+ except (ConnectionError, OSError) as exc:
427
+ raise RetrievalInvocationError(
428
+ "retrieval_network_error",
429
+ f"{type(exc).__name__}: {exc}" if str(exc) else type(exc).__name__,
430
+ ) from exc
431
+ except (json.JSONDecodeError, ValueError) as exc:
432
+ raise RetrievalInvocationError(
433
+ "retrieval_api_error",
434
+ str(exc) or "retrieve_fn returned malformed payload",
435
+ ) from exc
436
+ except Exception as exc: # noqa: BLE001 — translation boundary
437
+ raise RetrievalInvocationError("retrieval_api_error", f"{type(exc).__name__}: {exc}") from exc
438
+
439
+ if not isinstance(result, dict):
440
+ raise RetrievalInvocationError(
441
+ "retrieval_api_error",
442
+ f"retrieve_fn returned {type(result).__name__}, expected dict",
443
+ )
444
+ method = result.get("ref_retrieval_method")
445
+ if method is None:
446
+ raise RetrievalInvocationError(
447
+ "retrieval_api_error",
448
+ f"retrieve_fn return missing ref_retrieval_method; got keys={sorted(result)}",
449
+ )
450
+ # Step 13 R8 codex P2-4: guard isinstance(str) before set membership so a
451
+ # malformed return like {"ref_retrieval_method": [...], ...} surfaces as a
452
+ # clean retrieval_api_error instead of bubbling TypeError("unhashable type")
453
+ # out past the translation boundary and aborting the audit (symmetric to
454
+ # P2-3 on the judge side).
455
+ if not isinstance(method, str):
456
+ raise RetrievalInvocationError(
457
+ "retrieval_api_error",
458
+ f"retrieve_fn returned non-string ref_retrieval_method={method!r} (type={type(method).__name__})",
459
+ )
460
+ if method not in {"api", "manual_pdf", "failed", "not_found", "audit_tool_failure"}:
461
+ raise RetrievalInvocationError(
462
+ "retrieval_api_error",
463
+ f"retrieve_fn returned unknown ref_retrieval_method={method!r}",
464
+ )
465
+ # Step 13 R3 codex P2 #3: a successful retrieval pathway MUST carry a
466
+ # non-empty excerpt — otherwise the judge would be invoked with
467
+ # `retrieved_excerpt=None`/empty and could mark a claim SUPPORTED with no
468
+ # source text. Map this shape violation to retrieval_api_error so it
469
+ # surfaces as audit_tool_failure instead of silently degrading the audit.
470
+ if method in {"api", "manual_pdf"}:
471
+ excerpt = result.get("retrieved_excerpt")
472
+ if not isinstance(excerpt, str) or not excerpt.strip():
473
+ raise RetrievalInvocationError(
474
+ "retrieval_api_error",
475
+ f"retrieve_fn returned ref_retrieval_method={method!r} with empty/missing retrieved_excerpt; successful retrievals must carry source text",
476
+ )
477
+ return result
478
+
479
+
480
+ # ---------------------------------------------------------------------------
481
+ # Emission helpers — each builds one entry dict.
482
+ # ---------------------------------------------------------------------------
483
+
484
+
485
+ def _anchorless_entry(citation: dict[str, Any], *, audit_run_id: str, now_iso: str, judge_model: str) -> dict[str, Any]:
486
+ """§4 Step 1: anchor=none short-circuits to RETRIEVAL_FAILED+inconclusive+not_applicable+not_attempted.
487
+
488
+ INV-6 sentinel: anchor_kind=none MUST carry anchor_value="" (empty sentinel
489
+ per claim_audit_result.schema.json). We pin the empty string here rather
490
+ than passing through citation.anchor_value — a stale residual anchor like
491
+ "123" on an anchor_kind=none row violates the schema contract.
492
+ """
493
+ return {
494
+ "claim_id": citation["claim_id"],
495
+ "scoped_manifest_id": citation.get("scoped_manifest_id", SENTINEL_MANIFEST_ID),
496
+ "claim_text": citation["claim_text"],
497
+ "ref_slug": citation["ref_slug"],
498
+ "anchor_kind": "none",
499
+ "anchor_value": "",
500
+ "judgment": "RETRIEVAL_FAILED",
501
+ "audit_status": "inconclusive",
502
+ "defect_stage": "not_applicable",
503
+ "rationale": (
504
+ f"{INV6_RATIONALE_PREFIX}: cited claim {citation['claim_id']} carries anchor=none; "
505
+ "v3.7.3 finalizer should have gate-refused upstream — defense-in-depth row."
506
+ ),
507
+ "judge_model": judge_model,
508
+ "judge_run_at": now_iso,
509
+ "ref_retrieval_method": "not_attempted",
510
+ "upstream_owner_agent": citation.get("upstream_owner_agent"),
511
+ "audit_run_id": audit_run_id,
512
+ }
513
+
514
+
515
+ def _retrieval_failure_entry(
516
+ citation: dict[str, Any],
517
+ *,
518
+ method: str,
519
+ audit_run_id: str,
520
+ now_iso: str,
521
+ judge_model: str,
522
+ fault_class: str | None = None,
523
+ ) -> dict[str, Any]:
524
+ """§4 Step 2: retrieval-side failure routes that skip the judge."""
525
+ if method == "failed":
526
+ # D2 paywall — LOW-WARN advisory; INV-10.
527
+ entry = {
528
+ "judgment": "RETRIEVAL_FAILED",
529
+ "audit_status": "inconclusive",
530
+ "defect_stage": "not_applicable",
531
+ "rationale": "Reference full text not retrievable (paywall / license-restricted access).",
532
+ }
533
+ elif method == "not_found":
534
+ # Fabricated reference — HIGH-WARN; INV-12.
535
+ entry = {
536
+ "judgment": "RETRIEVAL_FAILED",
537
+ "audit_status": "completed",
538
+ "defect_stage": "retrieval_existence",
539
+ "rationale": "Retrieval API reports the cited reference does not exist (suspected fabrication).",
540
+ }
541
+ elif method == "audit_tool_failure":
542
+ # Transient infrastructure outage — MED-WARN; INV-14.
543
+ tag = fault_class or "retrieval_api_error"
544
+ entry = {
545
+ "judgment": "RETRIEVAL_FAILED",
546
+ "audit_status": "inconclusive",
547
+ "defect_stage": "not_applicable",
548
+ "rationale": f"{tag}: transient audit-infrastructure failure during retrieval; retry on next pipeline pass.",
549
+ }
550
+ else: # pragma: no cover — should be unreachable given Step 2 caller dispatch
551
+ raise ValueError(f"_retrieval_failure_entry called with non-failure method={method!r}")
552
+
553
+ return {
554
+ "claim_id": citation["claim_id"],
555
+ "scoped_manifest_id": citation.get("scoped_manifest_id", SENTINEL_MANIFEST_ID),
556
+ "claim_text": citation["claim_text"],
557
+ "ref_slug": citation["ref_slug"],
558
+ "anchor_kind": citation["anchor_kind"],
559
+ "anchor_value": citation.get("anchor_value", ""),
560
+ "judgment": entry["judgment"],
561
+ "audit_status": entry["audit_status"],
562
+ "defect_stage": entry["defect_stage"],
563
+ "rationale": entry["rationale"],
564
+ "judge_model": judge_model,
565
+ "judge_run_at": now_iso,
566
+ "ref_retrieval_method": method,
567
+ "upstream_owner_agent": citation.get("upstream_owner_agent"),
568
+ "audit_run_id": audit_run_id,
569
+ }
570
+
571
+
572
+ def _judge_result_entry(
573
+ citation: dict[str, Any],
574
+ *,
575
+ judge_result: dict[str, Any],
576
+ ref_retrieval_method: str,
577
+ audit_run_id: str,
578
+ now_iso: str,
579
+ judge_model: str,
580
+ ) -> dict[str, Any]:
581
+ """§4 Steps 5-6: route judge verdict to the right (judgment, defect_stage) row."""
582
+ verdict = judge_result["judgment"]
583
+ # #360: a judge is an LLM with no length guarantee; clamp its rationale to
584
+ # the schema maxLength before it lands on the completed row (success path).
585
+ rationale = _bounded_judge_rationale(judge_result.get("rationale", ""))
586
+
587
+ if verdict == "SUPPORTED":
588
+ judgment, defect_stage, violated_id = "SUPPORTED", None, None
589
+ elif verdict == "AMBIGUOUS":
590
+ hint = judge_result.get("defect_stage_hint")
591
+ if hint not in _AMBIGUOUS_DEFECTS:
592
+ hint = None # AMBIGUOUS+disallowed defect → coerce to null (INV-3 protection)
593
+ judgment, defect_stage, violated_id = "AMBIGUOUS", hint, None
594
+ elif verdict == "UNSUPPORTED":
595
+ hint = judge_result.get("defect_stage_hint") or "source_description"
596
+ if hint not in _UNSUPPORTED_NON_CONSTRAINT_DEFECTS:
597
+ hint = "source_description"
598
+ judgment, defect_stage, violated_id = "UNSUPPORTED", hint, None
599
+ elif verdict == "VIOLATED":
600
+ # Cited constraint violation — INV-7/INV-8 path.
601
+ judgment = "UNSUPPORTED"
602
+ defect_stage = "negative_constraint_violation"
603
+ violated_id = judge_result.get("violated_constraint_id")
604
+ elif verdict == "PARTIAL":
605
+ # #213 B1 normalization: a prompt-verdict PARTIAL becomes
606
+ # judgment=UNSUPPORTED, defect_stage=source_description, carrying the
607
+ # sub_claim_breakdown[] (the machine-readable partial signal). Routing
608
+ # to UNSUPPORTED puts the unsupported sub-claim through the same
609
+ # gate-refuse path a fully-unsupported claim takes. The breakdown shape
610
+ # was validated true-partial in _validate_judge_dict, so INV-19 holds on
611
+ # the emitted completed row.
612
+ judgment = "UNSUPPORTED"
613
+ defect_stage = "source_description"
614
+ violated_id = None
615
+ else:
616
+ raise ValueError(f"unknown judge verdict: {verdict!r}")
617
+
618
+ entry: dict[str, Any] = {
619
+ "claim_id": citation["claim_id"],
620
+ "scoped_manifest_id": citation.get("scoped_manifest_id", SENTINEL_MANIFEST_ID),
621
+ "claim_text": citation["claim_text"],
622
+ "ref_slug": citation["ref_slug"],
623
+ "anchor_kind": citation["anchor_kind"],
624
+ "anchor_value": citation.get("anchor_value", ""),
625
+ "judgment": judgment,
626
+ "audit_status": "completed",
627
+ "defect_stage": defect_stage,
628
+ "rationale": rationale or "(no rationale provided)",
629
+ "judge_model": judge_model,
630
+ "judge_run_at": now_iso,
631
+ "ref_retrieval_method": ref_retrieval_method,
632
+ "upstream_owner_agent": citation.get("upstream_owner_agent"),
633
+ "audit_run_id": audit_run_id,
634
+ }
635
+ if violated_id is not None:
636
+ entry["violated_constraint_id"] = violated_id
637
+ if verdict == "PARTIAL":
638
+ # Carry the decomposition onto the emitted row. Normalize each item to
639
+ # the schema item shape (sub_claim_text, sub_verdict, optional
640
+ # evidence_pointer), dropping any extra keys the judge added so the
641
+ # additionalProperties:false item schema holds. Presence of this field
642
+ # is the machine-readable partial-support signal (#213).
643
+ entry["sub_claim_breakdown"] = [
644
+ {
645
+ "sub_claim_text": item.get("sub_claim_text"),
646
+ "sub_verdict": item.get("sub_verdict"),
647
+ **(
648
+ {"evidence_pointer": item["evidence_pointer"]}
649
+ if "evidence_pointer" in item
650
+ else {}
651
+ ),
652
+ }
653
+ for item in judge_result["sub_claim_breakdown"]
654
+ if isinstance(item, dict)
655
+ ]
656
+ return entry
657
+
658
+
659
+ def _uncited_audit_failure_entry(
660
+ *,
661
+ sentence: dict[str, Any],
662
+ scoped_manifest_id: str,
663
+ manifest_claim_id: str | None,
664
+ fault_class: str,
665
+ detail: str,
666
+ finding_id: str,
667
+ judge_model: str,
668
+ now_iso: str,
669
+ ) -> dict[str, Any]:
670
+ """§3.6 (v3.8.2 / #118): uncited sentence × manifest pair where the
671
+ constraint judge raised JudgeInvocationError. Mirrors INV-14 row on the
672
+ cited path but rides in the uncited_audit_failures[] aggregate because
673
+ claim_audit_result.ref_slug is required."""
674
+ rationale = f"{fault_class}: {detail}" if detail else f"{fault_class}:"
675
+ return {
676
+ "finding_id": finding_id,
677
+ "claim_text": sentence["sentence_text"],
678
+ "section_path": sentence.get("section_path", ""),
679
+ "scoped_manifest_id": scoped_manifest_id,
680
+ "manifest_claim_id": manifest_claim_id,
681
+ "fault_class": fault_class,
682
+ "rationale": rationale,
683
+ "judge_model": judge_model,
684
+ "judge_run_at": now_iso,
685
+ "rule_version": UAF_RULE_VERSION,
686
+ "upstream_owner_agent": sentence.get("upstream_owner_agent"),
687
+ }
688
+
689
+
690
+ def _constraint_violation_entry(
691
+ *,
692
+ sentence: dict[str, Any],
693
+ judge_result: dict[str, Any],
694
+ scoped_manifest_id: str,
695
+ finding_id: str,
696
+ judge_model: str,
697
+ now_iso: str,
698
+ ) -> dict[str, Any]:
699
+ """§3.5 / §5 stream (d): uncited claim with VIOLATED judge verdict."""
700
+ violated_id = judge_result.get("violated_constraint_id")
701
+ manifest_claim_id = None
702
+ if violated_id:
703
+ nc_match = RE_NC_CONSTRAINT.match(violated_id)
704
+ if nc_match:
705
+ manifest_claim_id = f"C-{nc_match.group(1)}"
706
+ return {
707
+ "finding_id": finding_id,
708
+ "claim_text": sentence["sentence_text"],
709
+ "section_path": sentence.get("section_path", ""),
710
+ "violated_constraint_id": violated_id,
711
+ "scoped_manifest_id": scoped_manifest_id,
712
+ "manifest_claim_id": manifest_claim_id,
713
+ "judge_verdict": "VIOLATED",
714
+ # #360: clamp the judge-supplied rationale (success path) to maxLength;
715
+ # `or` default catches a missing/null/empty rationale (schema minLength=1).
716
+ "rationale": _bounded_judge_rationale(judge_result.get("rationale"))
717
+ or "Constraint violated by uncited claim.",
718
+ "judge_model": judge_model,
719
+ "judge_run_at": now_iso,
720
+ "rule_version": DRIFT_RULE_VERSION,
721
+ "upstream_owner_agent": sentence.get("upstream_owner_agent"),
722
+ }
723
+
724
+
725
+ def _uncited_assertion_entry(
726
+ *,
727
+ sentence: dict[str, Any],
728
+ finding_id: str,
729
+ now_iso: str,
730
+ trigger_tokens: list[str] | None = None,
731
+ ) -> dict[str, Any]:
732
+ # Resolve trigger_tokens with strict semantics: prefer the explicit
733
+ # keyword arg, fall back to the sentence dict, and raise if both are
734
+ # absent. The prior `["uncited"]` sentinel passed U-INV-2 minItems=1
735
+ # but carried no semantic content — callers who skipped the detector
736
+ # silently emitted meaningless tokens into the passport. Raise instead
737
+ # so the contract is enforced at write-time, not discovered at audit-
738
+ # read-time (per codex R1 P1-4).
739
+ tokens = trigger_tokens or sentence.get("trigger_tokens")
740
+ if not tokens:
741
+ raise ValueError(
742
+ f"_uncited_assertion_entry: finding_id={finding_id!r} has no "
743
+ "trigger_tokens. Caller must pre-process draft sentences "
744
+ "through detect_uncited_assertions (or supply trigger_tokens "
745
+ "explicitly); the schema's U-INV-2 minItems=1 invariant is "
746
+ "an audit-quality contract, not a placeholder slot."
747
+ )
748
+ manifest_claim_id = sentence.get("manifest_claim_id")
749
+ # Step 7 codex R1 CO-3 / U-INV-4 pair rule: scoped_manifest_id is the
750
+ # disambiguator for a specific manifest claim. When no claim_id is bound
751
+ # (the uncited sentence is in scope for a manifest-level MNC but is NOT
752
+ # itself a manifest claim — runtime contract for stream-d uncited
753
+ # constraint-violation routing), the uncited_assertion row MUST drop the
754
+ # manifest scope. The companion constraint_violations[] row owns the
755
+ # manifest pointer in that case; carrying scope on both rows would fail
756
+ # U-INV-4 (manifest_claim_id null ↔ scoped_manifest_id null).
757
+ scoped_manifest_id = (
758
+ sentence.get("scoped_manifest_id") if manifest_claim_id is not None else None
759
+ )
760
+ return {
761
+ "finding_id": finding_id,
762
+ "sentence_text": sentence["sentence_text"],
763
+ "section_path": sentence.get("section_path", ""),
764
+ "trigger_tokens": tokens,
765
+ "detected_at": now_iso,
766
+ "rule_version": UNCITED_RULE_VERSION,
767
+ "upstream_owner_agent": sentence.get("upstream_owner_agent"),
768
+ "manifest_claim_id": manifest_claim_id,
769
+ "scoped_manifest_id": scoped_manifest_id,
770
+ }
771
+
772
+
773
+ def _claim_drift_entry(
774
+ *,
775
+ drift_kind: str,
776
+ claim_text: str,
777
+ finding_id: str,
778
+ now_iso: str,
779
+ manifest_claim_id: str | None = None,
780
+ scoped_manifest_id: str | None = None,
781
+ section_path: str | None = None,
782
+ ) -> dict[str, Any]:
783
+ entry = {
784
+ "finding_id": finding_id,
785
+ "drift_kind": drift_kind,
786
+ "claim_text": claim_text,
787
+ "detected_at": now_iso,
788
+ "rule_version": DRIFT_RULE_VERSION,
789
+ "manifest_claim_id": manifest_claim_id,
790
+ "scoped_manifest_id": scoped_manifest_id,
791
+ "section_path": section_path,
792
+ }
793
+ return entry
794
+
795
+
796
+ # ---------------------------------------------------------------------------
797
+ # Sampling helper.
798
+ # ---------------------------------------------------------------------------
799
+
800
+
801
+ def _stratified_bucket_indices(total: int, cap: int) -> list[int]:
802
+ """Pick `cap` indices in [0, total) via stratified buckets in document order.
803
+
804
+ Divides [0, total) into `cap` equal-ish buckets and picks the first index of
805
+ each bucket. The result is strictly ascending and has length min(cap, total).
806
+
807
+ Why two-stage fill: a naive `int(i * width)` for `width = total / cap`
808
+ silently collapses adjacent picks when `total/cap < 2` (e.g. N=101,
809
+ cap=100 → `int(99 * 1.01) == int(100 * 1.0)`-class duplicates after
810
+ dedup). The S-INV-1 invariant ties `audited_count` to `len(audited_indices)`
811
+ so a silent dedup would shrink audited_count below cap with no surface.
812
+ We dedup first, then fill the remaining slots from un-picked indices in
813
+ ascending document order — keeping the bucket-first-pick bias for spread
814
+ while honoring the contract that `audited_count == min(cap, N)` whenever
815
+ that is achievable.
816
+ """
817
+ if total <= 0 or cap <= 0:
818
+ return []
819
+ k = min(cap, total)
820
+ width = total / k
821
+ picks: set[int] = set()
822
+ for i in range(k):
823
+ picks.add(int(i * width))
824
+ # Fill missing slots from un-picked indices in ascending order so the
825
+ # final result is exactly k strictly-ascending unique picks whenever
826
+ # k ≤ total (which is guaranteed by `k = min(cap, total)`).
827
+ if len(picks) < k:
828
+ for j in range(total):
829
+ if j not in picks:
830
+ picks.add(j)
831
+ if len(picks) == k:
832
+ break
833
+ return sorted(picks)
834
+
835
+
836
+ # ---------------------------------------------------------------------------
837
+ # Drift detection (manifest set-diff).
838
+ # ---------------------------------------------------------------------------
839
+
840
+
841
+ def _detect_drifts(
842
+ *,
843
+ manifests: list[dict[str, Any]],
844
+ emitted_citations: list[dict[str, Any]],
845
+ uncited_sentence_texts: set[str],
846
+ constraint_absorbed_claim_ids: set[tuple[str, str]],
847
+ constraint_absorbed_manifest_scopes: set[str],
848
+ now_iso: str,
849
+ next_finding_id: Callable[[], str],
850
+ ) -> list[dict[str, Any]]:
851
+ """§4 step 5 manifest set-diff producing claim_drift entries.
852
+
853
+ Precedence:
854
+ - T-P8 + Step 13 R5 codex P3: constraint-violation absorbs drift in
855
+ **full** for the violating manifest. `constraint_absorbed_claim_ids`
856
+ captures (manifest, declared-claim-id) pairs; `constraint_absorbed_manifest_scopes`
857
+ captures the manifest_id itself so a same-manifest citation with a
858
+ drifted (non-manifest) claim_id is also suppressed — preserves the
859
+ "absorbed in full" spec promise. A violation in manifest A does NOT
860
+ silence drift in manifest B.
861
+ - T-P10 / D-INV-4: uncited sentence takes precedence over drift — no
862
+ drift entry whose claim_text matches an uncited sentence_text.
863
+
864
+ MANIFEST-MISSING fallback (Step 13 R5 codex P2 #2): when no manifest
865
+ carries any claims, there's no pre-commitment baseline to drift FROM —
866
+ every emitted citation would be classified EMITTED_NOT_INTENDED, layering
867
+ spurious LOW-WARN noise on top of the MANIFEST-MISSING advisory the
868
+ formatter already surfaces. Short-circuit and return no drifts so the
869
+ fallback run remains audit-only.
870
+ """
871
+ has_baseline = any((m.get("claims") or []) for m in manifests)
872
+ if not has_baseline:
873
+ return []
874
+ drifts: list[dict[str, Any]] = []
875
+
876
+ # Index emitted citations by (scoped_manifest_id, claim_id) — these are
877
+ # the "supported" set candidates the prose actually produced. Use
878
+ # .get(SENTINEL_MANIFEST_ID) so MANIFEST-MISSING callers that omit
879
+ # scoped_manifest_id still build a coherent emitted_pairs set per the
880
+ # sentinel fallback contract (Step 13 R4 codex P2 #3).
881
+ emitted_pairs: set[tuple[str, str]] = {
882
+ (c.get("scoped_manifest_id", SENTINEL_MANIFEST_ID), c.get("claim_id", ""))
883
+ for c in emitted_citations
884
+ }
885
+ emitted_texts = {c.get("claim_text", "") for c in emitted_citations}
886
+
887
+ # INTENDED_NOT_EMITTED — manifest claims missing from emitted set.
888
+ # D6 defines Emitted as a set of claim_text values; the dropped-claim side
889
+ # MUST mirror that. A stale or re-numbered claim_id where the claim_text
890
+ # still appears in the draft would otherwise show up as INTENDED_NOT_EMITTED
891
+ # even though the prose carries the claim — a false drift signal
892
+ # (Step 13 R2 codex P2 finding).
893
+ for m in manifests:
894
+ mid = m.get("manifest_id")
895
+ # If this manifest had any constraint violation, absorb ALL of its
896
+ # drift — Step 13 R5 codex P3. The (mid, cid) pair-level absorption
897
+ # below is preserved for backwards compat, but the scope-level skip
898
+ # is the load-bearing rule per "absorbed in full".
899
+ if mid in constraint_absorbed_manifest_scopes:
900
+ continue
901
+ for claim in m.get("claims", []) or []:
902
+ cid = claim.get("claim_id")
903
+ claim_text = claim.get("claim_text", "")
904
+ if (mid, cid) in emitted_pairs:
905
+ continue
906
+ if claim_text and claim_text in emitted_texts:
907
+ # The draft carries the claim under a different claim_id (e.g.
908
+ # claim_id was re-numbered between manifest emission and prose).
909
+ # D6 set-of-text semantics — not a drop.
910
+ continue
911
+ if (mid, cid) in constraint_absorbed_claim_ids:
912
+ continue
913
+ if claim_text in uncited_sentence_texts:
914
+ # Step 7 codex R1 CO-1 / D-INV-4 cross-aggregate exclusivity:
915
+ # when a manifest claim appears as an uncited sentence in the
916
+ # draft, the uncited_assertion row takes priority. Emitting an
917
+ # INTENDED_NOT_EMITTED drift alongside would fail the D-INV-4
918
+ # consistency lint (one finding per sentence across both
919
+ # aggregates). Mirrors the EMITTED_NOT_INTENDED skip in the
920
+ # loop below.
921
+ continue
922
+ drifts.append(
923
+ _claim_drift_entry(
924
+ drift_kind="INTENDED_NOT_EMITTED",
925
+ claim_text=claim_text,
926
+ finding_id=next_finding_id(),
927
+ now_iso=now_iso,
928
+ manifest_claim_id=cid,
929
+ scoped_manifest_id=mid,
930
+ section_path=None,
931
+ )
932
+ )
933
+
934
+ # EMITTED_NOT_INTENDED — emitted citations whose claim_text is not in any
935
+ # manifest's claim_text set. D6 defines Emitted as a SET of claim_text
936
+ # values, so a drifted claim that carries multiple citations (e.g. one
937
+ # sentence with two ref markers) MUST emit ONE drift row, not one per
938
+ # citation. We dedupe by claim_text here while keeping the first
939
+ # encountered section_path as the representative (Step 13 R1 codex P2).
940
+ all_manifest_texts: set[str] = set()
941
+ for m in manifests:
942
+ for claim in m.get("claims", []) or []:
943
+ text = claim.get("claim_text")
944
+ if text:
945
+ all_manifest_texts.add(text)
946
+
947
+ seen_drift_texts: set[str] = set()
948
+ for c in emitted_citations:
949
+ text = c.get("claim_text", "")
950
+ if text in all_manifest_texts:
951
+ continue
952
+ c_scope = c.get("scoped_manifest_id", SENTINEL_MANIFEST_ID)
953
+ c_claim_id = c.get("claim_id", "")
954
+ if c_scope in constraint_absorbed_manifest_scopes:
955
+ # Step 13 R5 codex P3 — manifest scope absorbed in full when any
956
+ # citation in it violated a negative constraint. Suppresses
957
+ # same-manifest drift for emitted citations whose claim_id was
958
+ # NOT in the manifest's declared claim set.
959
+ continue
960
+ if (c_scope, c_claim_id) in constraint_absorbed_claim_ids:
961
+ continue
962
+ if text in uncited_sentence_texts:
963
+ # Precedence rule 3 / D-INV-4 — uncited takes priority.
964
+ continue
965
+ if text in seen_drift_texts:
966
+ # D6 set semantics — one drift row per drifted claim_text.
967
+ continue
968
+ seen_drift_texts.add(text)
969
+ drifts.append(
970
+ _claim_drift_entry(
971
+ drift_kind="EMITTED_NOT_INTENDED",
972
+ claim_text=text,
973
+ finding_id=next_finding_id(),
974
+ now_iso=now_iso,
975
+ manifest_claim_id=None,
976
+ scoped_manifest_id=None,
977
+ section_path=c.get("section_path", "unknown"),
978
+ )
979
+ )
980
+
981
+ return drifts
982
+
983
+
984
+ # ---------------------------------------------------------------------------
985
+ # Public entry point.
986
+ # ---------------------------------------------------------------------------
987
+
988
+
989
+ def run_audit_pipeline(
990
+ *,
991
+ citations: list[dict[str, Any]],
992
+ manifests: list[dict[str, Any]],
993
+ # Reserved for the production retrieval-driver wiring per spec §4 step 2.
994
+ # The current implementation injects retrieval via `retrieve_fn` so the
995
+ # corpus is read inside that callback; keeping the parameter on the
996
+ # signature lets the orchestrator pass corpus through without changing
997
+ # the public API when the production retrieve_fn lands.
998
+ corpus: list[dict[str, Any]] | None = None,
999
+ config: dict[str, Any],
1000
+ retrieve_fn: Callable[[dict[str, Any]], dict[str, Any]],
1001
+ judge_fn: Callable[..., dict[str, Any]],
1002
+ audit_run_id: str,
1003
+ now_iso: str,
1004
+ cache: dict[str, Any] | None = None,
1005
+ uncited_sentences: list[dict[str, Any]] | None = None,
1006
+ all_uncited_sentences: list[dict[str, Any]] | None = None,
1007
+ pdf_preflight_sidecars: dict[str, dict[str, Any]] | None = None,
1008
+ ) -> dict[str, list[dict[str, Any]]]:
1009
+ """Run §4 Step 1-6 + manifest set-diff over caller-supplied inputs.
1010
+
1011
+ Two uncited streams (Step 13 R4 codex P1 #2):
1012
+
1013
+ - `uncited_sentences`: D4-c detector positives — output of
1014
+ `detect_uncited_assertions` (sentences matching the quantifier /
1015
+ empirical-trigger filter). Drives `uncited_assertions[]` LOW-WARN
1016
+ advisory emission only.
1017
+ - `all_uncited_sentences`: the full uncited sentence set (every draft
1018
+ sentence with no in-text citation marker). Drives stream (d) —
1019
+ constraint judging for `constraint_violations[]` HIGH-WARN. The full
1020
+ set is needed because a manifest negative constraint like "No causal
1021
+ language" can be violated by a sentence ("The program caused
1022
+ improvement") that the D4-c detector filters OUT (no quantifier, no
1023
+ empirical trigger token). Routing constraint judging through the
1024
+ D4-c-filtered subset silently drops those HIGH-WARN cases.
1025
+
1026
+ When `all_uncited_sentences` is omitted, it defaults to
1027
+ `uncited_sentences` (legacy callers preserved — but a warning band:
1028
+ those callers miss the R4 P1 expansion and should pass both).
1029
+
1030
+ The uncited token-rule detector
1031
+ (`scripts/uncited_assertion_detector.py`, §"Uncited-assertion detector
1032
+ (D4-c)" in claim_ref_alignment_audit_agent.md) is NOT invoked here.
1033
+ Callers pre-process the full uncited set through
1034
+ `detect_uncited_assertions` to get `uncited_sentences`; pass the raw
1035
+ full set as `all_uncited_sentences`. `scripts/test_e2e_claim_audit.py`
1036
+ exercises the full detector → pipeline → finalizer chain end-to-end.
1037
+
1038
+ Sentence-dict shape:
1039
+ - `uncited_sentences[]`: `sentence_text` + `section_path` +
1040
+ `trigger_tokens` (non-empty per U-INV-2). D4-c output guarantees
1041
+ these fields.
1042
+ - `all_uncited_sentences[]`: `sentence_text` + `section_path` only.
1043
+ Constraint judging does not consult `trigger_tokens`.
1044
+
1045
+ `pdf_preflight_sidecars` (#512): optional map of `ref_slug` →
1046
+ `pdf_read_preflight/1` sidecar dict (see `scripts/pdf_read_preflight.py`).
1047
+ `None` (default) = the caller has not wired the preflight layer — legacy
1048
+ byte-equivalent behavior, no tagging. When provided (even empty), every
1049
+ completed `manual_pdf` row with `anchor_kind == "page"` whose sidecar is
1050
+ missing or non-`PASS` gets `PDF_READ_INTEGRITY_TAG` appended to its
1051
+ rationale at the Step-6 emission point, cache hit or not. Additionally,
1052
+ page-anchor citations handed to `retrieve_fn` carry a
1053
+ `pdf_preflight_verdict` key (`PASS`/`FAIL`/`UNAVAILABLE`/`MISSING`):
1054
+ retrieve_fn implementations SHOULD locate the passage by content rather
1055
+ than by the page scope when the verdict is not `PASS` — the judge must
1056
+ never be fed a passage selected by an untrusted page number. Sidecar
1057
+ freshness is the CALLER's contract: this function does no file I/O, so
1058
+ the orchestrator re-hashes each PDF against its sidecar `sha256` before
1059
+ dispatch and re-runs the preflight on mismatch (a stale `PASS` from a
1060
+ replaced file must not license the new bytes).
1061
+
1062
+ Returns:
1063
+ dict with six aggregate arrays keyed by passport-aggregate name:
1064
+ claim_audit_results, uncited_assertions, claim_drifts,
1065
+ constraint_violations, audit_sampling_summaries, plus
1066
+ claim_intent_manifests (echoed for downstream consumption).
1067
+
1068
+ Raises:
1069
+ ValueError: when config validation fails (e.g. max_claims_per_paper <= 0).
1070
+ """
1071
+ # Intentional no-op: `corpus` is reserved for the production retrieval-driver
1072
+ # wiring (spec §4 step 2). Mark as read so static analysers (ruff ARG002,
1073
+ # mypy strict unused-arg) do not flag the forward-compat parameter.
1074
+ _ = corpus
1075
+
1076
+ # ---- Config sanity ----
1077
+ cap = config.get("max_claims_per_paper", 100)
1078
+ if not isinstance(cap, int) or cap <= 0:
1079
+ raise ValueError(
1080
+ f"max_claims_per_paper must be positive integer; got {cap!r} "
1081
+ "(spec §4 step 3 + S-INV-2 / T-P11 cap=0 rejected)"
1082
+ )
1083
+ judge_model = config.get("judge_model", "gpt-5.5-xhigh")
1084
+ # #361: prompt_version is a judge-cache-key component. Absent key → default
1085
+ # to JUDGE_PROMPT_SHA256, the prompt's own fingerprint and the SINGLE SOURCE
1086
+ # OF TRUTH for cache invalidation: check_judge_prompt_version.py keeps this
1087
+ # hash in lockstep with the judge-prompt text, so any prompt edit changes the
1088
+ # hash and AUTOMATICALLY invalidates stale entries (the human-readable
1089
+ # JUDGE_PROMPT_VERSION label is decoupled and must NOT gate the cache).
1090
+ # Present-but-None → the caller declares the prompt version UNKNOWN; fail
1091
+ # CLOSED by binding a run-local component (audit_run_id is per-run unique) so
1092
+ # a stale entry is never served across an unknown-version boundary — cross-run
1093
+ # hits are disabled, but within-run dedup for repeated citations still holds.
1094
+ prompt_version = config.get("judge_prompt_version", JUDGE_PROMPT_SHA256)
1095
+ if prompt_version is None:
1096
+ prompt_version = f"__unknown__:{audit_run_id}"
1097
+
1098
+ # Build the three lookup indexes once per run. Used by per-citation
1099
+ # constraint resolution + manifest-level absorption + drift detection.
1100
+ manifests_by_id: dict[str, dict[str, Any]] = {
1101
+ m["manifest_id"]: m for m in manifests if m.get("manifest_id")
1102
+ }
1103
+ claim_by_mc_id: dict[tuple[str, str], dict[str, Any]] = {
1104
+ (m["manifest_id"], claim["claim_id"]): claim
1105
+ for m in manifests
1106
+ if m.get("manifest_id")
1107
+ for claim in (m.get("claims") or [])
1108
+ if claim.get("claim_id")
1109
+ }
1110
+ mncs_by_manifest_id: dict[str, list[dict[str, Any]]] = {
1111
+ m["manifest_id"]: list(m.get("manifest_negative_constraints") or [])
1112
+ for m in manifests
1113
+ if m.get("manifest_id")
1114
+ }
1115
+ cache = cache if cache is not None else {}
1116
+ uncited_sentences = uncited_sentences or []
1117
+ # Step 13 R4 codex P1 #2: constraint judging needs the FULL uncited set,
1118
+ # not the D4-c-filtered subset. When the caller omits the full set we
1119
+ # fall back to the D4-c subset for backwards compatibility — but that
1120
+ # path silently drops constraint violations on sentences outside D4-c
1121
+ # trigger tokens. New callers should pass both.
1122
+ all_uncited_sentences = (
1123
+ all_uncited_sentences if all_uncited_sentences is not None else list(uncited_sentences)
1124
+ )
1125
+
1126
+ # ---- Sampling decision ----
1127
+ total = len(citations)
1128
+ if total > cap:
1129
+ sampled_indices = _stratified_bucket_indices(total, cap)
1130
+ audited_citations = [citations[i] for i in sampled_indices]
1131
+ sampling_summaries = [
1132
+ {
1133
+ "audit_run_id": audit_run_id,
1134
+ "max_claims_per_paper": cap,
1135
+ "total_citation_count": total,
1136
+ "audited_count": len(sampled_indices),
1137
+ "audited_indices": sampled_indices,
1138
+ "sampling_strategy": SAMPLING_STRATEGY,
1139
+ "emitted_at": now_iso,
1140
+ }
1141
+ ]
1142
+ else:
1143
+ audited_citations = list(citations)
1144
+ sampling_summaries = []
1145
+
1146
+ # ---- Per-citation §4 Step 1-6 ----
1147
+ claim_audit_results: list[dict[str, Any]] = []
1148
+ constraint_violations: list[dict[str, Any]] = []
1149
+ constraint_absorbed_claim_ids: set[tuple[str, str]] = set()
1150
+ # Step 13 R5 codex P3: track manifest_id scopes whose drift is absorbed
1151
+ # "in full". A constraint violation in manifest M suppresses ALL of M's
1152
+ # drift — declared claims (by id), the violating citation's pair (which
1153
+ # may itself be drifted), AND any other emitted citation in M with a
1154
+ # non-manifest claim_id.
1155
+ constraint_absorbed_manifest_scopes: set[str] = set()
1156
+
1157
+ def _written_scope_for(citation: dict[str, Any]) -> str:
1158
+ """Return the scoped_manifest_id that goes onto the claim_audit_result row.
1159
+
1160
+ Step 7 codex R1 CO-2: a drifted-cited citation's `claim_id` is not in
1161
+ any manifest, but the citation still arrives with the active
1162
+ `scoped_manifest_id` for runtime constraint resolution (so global MNCs
1163
+ still apply per M-INV-3). The row written to the passport, however,
1164
+ MUST carry the sentinel manifest id whenever the (scope, claim_id)
1165
+ pair is not present in the manifest index — otherwise INV-15 dangling
1166
+ check rejects the passport. Runtime constraint lookup stays untouched
1167
+ (it reads citation.scoped_manifest_id directly); only the persisted
1168
+ row is normalized.
1169
+ """
1170
+ runtime_scope = citation.get("scoped_manifest_id", SENTINEL_MANIFEST_ID)
1171
+ cid = citation.get("claim_id")
1172
+ if runtime_scope == SENTINEL_MANIFEST_ID:
1173
+ return SENTINEL_MANIFEST_ID
1174
+ if (runtime_scope, cid) in claim_by_mc_id:
1175
+ return runtime_scope
1176
+ return SENTINEL_MANIFEST_ID
1177
+
1178
+ for citation in audited_citations:
1179
+ anchor_kind = citation.get("anchor_kind")
1180
+ scoped_manifest_id = citation.get("scoped_manifest_id", SENTINEL_MANIFEST_ID)
1181
+ claim_id = citation.get("claim_id")
1182
+ written_scope = _written_scope_for(citation)
1183
+
1184
+ # Step 1 — anchor=none firm-rule short-circuit.
1185
+ if anchor_kind == "none":
1186
+ entry = _anchorless_entry(
1187
+ citation,
1188
+ audit_run_id=audit_run_id,
1189
+ now_iso=now_iso,
1190
+ judge_model=judge_model,
1191
+ )
1192
+ entry["scoped_manifest_id"] = written_scope
1193
+ claim_audit_results.append(entry)
1194
+ continue
1195
+
1196
+ # Step 2 — retrieval. Wrap in `_invoke_retrieve` so transient failures
1197
+ # surface as INV-14 retrieval_* audit_tool_failure rows instead of
1198
+ # aborting the pass (Step 13 R2 codex P2 finding, symmetric to the
1199
+ # R1 _invoke_judge wrapper).
1200
+ # #512 r2: when the preflight layer is wired, page-anchor citations carry
1201
+ # the sidecar verdict INTO retrieval so implementations can locate the
1202
+ # passage by content instead of the untrusted page scope BEFORE the judge
1203
+ # sees it — tagging after the fact cannot fix a judge that already read
1204
+ # the wrong passage. Copy-on-write; API-path retrieve_fns ignore the key.
1205
+ retrieval_citation = citation
1206
+ if pdf_preflight_sidecars is not None and anchor_kind == "page":
1207
+ _sc = pdf_preflight_sidecars.get(citation["ref_slug"])
1208
+ retrieval_citation = dict(citation)
1209
+ retrieval_citation["pdf_preflight_verdict"] = (
1210
+ _sc.get("verdict") if _sc else "MISSING"
1211
+ )
1212
+ try:
1213
+ retrieval = _invoke_retrieve(retrieve_fn, retrieval_citation)
1214
+ except RetrievalInvocationError as ret_err:
1215
+ entry = _retrieval_failure_entry(
1216
+ citation,
1217
+ method="audit_tool_failure",
1218
+ audit_run_id=audit_run_id,
1219
+ now_iso=now_iso,
1220
+ judge_model=judge_model,
1221
+ fault_class=ret_err.fault_class,
1222
+ )
1223
+ entry["rationale"] = f"{ret_err.fault_class}: {ret_err.detail}"
1224
+ entry["scoped_manifest_id"] = written_scope
1225
+ claim_audit_results.append(entry)
1226
+ continue
1227
+ method = retrieval["ref_retrieval_method"]
1228
+ excerpt = retrieval.get("retrieved_excerpt")
1229
+
1230
+ if method in {"failed", "not_found", "audit_tool_failure"}:
1231
+ entry = _retrieval_failure_entry(
1232
+ citation,
1233
+ method=method,
1234
+ audit_run_id=audit_run_id,
1235
+ now_iso=now_iso,
1236
+ judge_model=judge_model,
1237
+ fault_class=retrieval.get("fault_class"),
1238
+ )
1239
+ entry["scoped_manifest_id"] = written_scope
1240
+ claim_audit_results.append(entry)
1241
+ continue
1242
+
1243
+ if method not in {"api", "manual_pdf"}:
1244
+ raise ValueError(f"unexpected ref_retrieval_method: {method!r}")
1245
+
1246
+ # Step 3 — cache lookup. Active constraints scoped by (manifest, claim).
1247
+ active_constraints = _active_constraints_for_claim(
1248
+ scoped_manifest_id=scoped_manifest_id,
1249
+ claim_id=claim_id,
1250
+ claim_by_mc_id=claim_by_mc_id,
1251
+ mncs_by_manifest_id=mncs_by_manifest_id,
1252
+ )
1253
+ key = _cache_key(
1254
+ claim_text=citation["claim_text"],
1255
+ ref_slug=citation["ref_slug"],
1256
+ anchor_kind=anchor_kind,
1257
+ anchor_value=citation.get("anchor_value", ""),
1258
+ retrieved_excerpt=excerpt,
1259
+ active_constraints=active_constraints,
1260
+ judge_model=judge_model,
1261
+ prompt_version=prompt_version,
1262
+ )
1263
+ # In-scope constraint ids for this call. Both fresh judge invocations
1264
+ # AND cache hits validate VIOLATED ids against this set so a
1265
+ # hallucinated id never reaches `_judge_result_entry` (Step 13 R3
1266
+ # codex P2 #1).
1267
+ active_ids: frozenset[str] = frozenset(
1268
+ c["constraint_id"] for c in active_constraints if c.get("constraint_id")
1269
+ )
1270
+
1271
+ cached = cache.get(key)
1272
+ try:
1273
+ if cached is not None:
1274
+ # Step 13 R3 codex P2 #4: cache may carry a corrupted/partial
1275
+ # dict from a prior session. Re-validate every hit through the
1276
+ # same surface as fresh invocations so a stale entry surfaces
1277
+ # as cache_corruption instead of crashing in
1278
+ # `_judge_result_entry`.
1279
+ judge_result = _validate_judge_dict(
1280
+ cached,
1281
+ allowed_judgments=_CITED_PATH_JUDGMENTS,
1282
+ active_constraint_ids=active_ids,
1283
+ source="cache",
1284
+ )
1285
+ else:
1286
+ # Step 4-5 — passage location is implicit (excerpt is the
1287
+ # located passage); invoke judge. Wrap in `_invoke_judge` so
1288
+ # transient failures surface as INV-14 `audit_tool_failure`
1289
+ # rows instead of aborting the audit (Step 13 R1 codex).
1290
+ judge_result = _invoke_judge(
1291
+ judge_fn,
1292
+ allowed_judgments=_CITED_PATH_JUDGMENTS,
1293
+ active_constraint_ids=active_ids,
1294
+ claim_text=citation["claim_text"],
1295
+ retrieved_excerpt=excerpt,
1296
+ anchor_kind=anchor_kind,
1297
+ anchor_value=citation.get("anchor_value", ""),
1298
+ active_constraints=active_constraints,
1299
+ judge_model=judge_model,
1300
+ )
1301
+ cache[key] = judge_result
1302
+ except JudgeInvocationError as judge_err:
1303
+ # Cache-hit validation failures map to cache_corruption per INV-14.
1304
+ fault_class = "cache_corruption" if cached is not None else judge_err.fault_class
1305
+ entry = _retrieval_failure_entry(
1306
+ citation,
1307
+ method="audit_tool_failure",
1308
+ audit_run_id=audit_run_id,
1309
+ now_iso=now_iso,
1310
+ judge_model=judge_model,
1311
+ fault_class=fault_class,
1312
+ )
1313
+ entry["rationale"] = f"{fault_class}: {judge_err.detail}"
1314
+ entry["scoped_manifest_id"] = written_scope
1315
+ claim_audit_results.append(entry)
1316
+ continue
1317
+
1318
+ # Step 6 — defect_stage routing + emission.
1319
+ entry = _judge_result_entry(
1320
+ citation,
1321
+ judge_result=judge_result,
1322
+ ref_retrieval_method=method,
1323
+ audit_run_id=audit_run_id,
1324
+ now_iso=now_iso,
1325
+ judge_model=judge_model,
1326
+ )
1327
+ entry["scoped_manifest_id"] = written_scope
1328
+ # #512 PDF read-integrity precondition, executable path. Sits AFTER cache
1329
+ # resolution so hits and fresh invocations are tagged identically (codex
1330
+ # #512 P1: a cache hit must not bypass the check). `None` = caller has not
1331
+ # wired the preflight layer → byte-equivalent legacy behavior; a provided
1332
+ # dict (even empty) means the orchestrator ran the layer, so a missing or
1333
+ # non-PASS sidecar for a manual_pdf page-anchor row is tagged.
1334
+ if (
1335
+ pdf_preflight_sidecars is not None
1336
+ and method == "manual_pdf"
1337
+ and anchor_kind == "page"
1338
+ ):
1339
+ sidecar = pdf_preflight_sidecars.get(citation["ref_slug"])
1340
+ if not (sidecar and sidecar.get("verdict") == "PASS"):
1341
+ _tag_pdf_read_integrity(entry)
1342
+ claim_audit_results.append(entry)
1343
+
1344
+ # Precedence rule 1: cited constraint violation absorbs the drift signal.
1345
+ # Spec §6 lint rule 6 + §7.2 T-P8: when a citation in this manifest
1346
+ # judges VIOLATED, that manifest's drift findings are absorbed in
1347
+ # full — the constraint violation has already surfaced the L3
1348
+ # faithfulness failure at HIGH-WARN, so layering LOW-WARN drift
1349
+ # noise on top of it just reports the same paper-level problem twice.
1350
+ # Absorption is manifest-scoped (not global) so VIOLATED in
1351
+ # manifest A does NOT silence legitimate drift signal in manifest B.
1352
+ if entry["defect_stage"] == "negative_constraint_violation":
1353
+ manifest = manifests_by_id.get(scoped_manifest_id)
1354
+ if manifest is not None:
1355
+ for claim in manifest.get("claims", []) or []:
1356
+ cid_in_manifest = claim.get("claim_id")
1357
+ if cid_in_manifest:
1358
+ constraint_absorbed_claim_ids.add(
1359
+ (scoped_manifest_id, cid_in_manifest)
1360
+ )
1361
+ # Also absorb the emitted citation's own (manifest, claim) pair
1362
+ # so a drifted-yet-violated citation does not produce a
1363
+ # companion EMITTED_NOT_INTENDED row.
1364
+ constraint_absorbed_claim_ids.add((scoped_manifest_id, claim_id))
1365
+ # Step 13 R5 codex P3 — record the full manifest scope so any
1366
+ # other emitted citation in M with a drifted claim_id is also
1367
+ # absorbed by the drift detector.
1368
+ constraint_absorbed_manifest_scopes.add(scoped_manifest_id)
1369
+
1370
+ # ---- Stream (d): uncited constraint judging over FULL uncited set ----
1371
+ # Step 13 R4 codex P1 #2: constraint judging MUST see every uncited
1372
+ # sentence (not just D4-c detector positives). An MNC like "No causal
1373
+ # language" can be violated by an uncited sentence that the D4-c filter
1374
+ # drops (no quantifier, no empirical trigger token), so routing
1375
+ # constraint judging through the LOW-WARN advisory loop below would
1376
+ # silently miss HIGH-WARN cases. We run constraint judging here on
1377
+ # `all_uncited_sentences` and emit LOW-WARN uncited_assertion rows
1378
+ # separately on `uncited_sentences` (the D4-c subset).
1379
+ #
1380
+ # Step 13 R6 codex P1: the documented Stage 4 draft sentence shape carries
1381
+ # only `sentence_text` / `section_path` / optional `adjacent_text` — NOT
1382
+ # a sentence-level `scoped_manifest_id`. Pre-fix this loop required the
1383
+ # caller to populate scope on every sentence; absent that, the
1384
+ # constraint judge was skipped and the HIGH-WARN-CONSTRAINT-VIOLATION-UNCITED
1385
+ # gate was a no-op for orchestrator callers following the contract.
1386
+ # The runtime now derives a default scope set per sentence: if the caller
1387
+ # provides `scoped_manifest_id` on the sentence dict, only that manifest's
1388
+ # MNCs apply; otherwise the pipeline applies EVERY manifest's MNCs
1389
+ # (uncited sentences have no claim-level binding, so manifest-scoped
1390
+ # MNCs reach them universally per spec §3.5 D4-c stream (d) semantics).
1391
+ # Per-manifest constraint sets — MNCs (manifest-wide) PLUS, when the
1392
+ # sentence carries a `manifest_claim_id`, that claim's NC-C entries.
1393
+ # NC-C (claim-level) is the R7 codex P1 gap: spec §3.5 D4-c stream (d)
1394
+ # covers BOTH MNC and NC-C for uncited violations, but the R6 closure
1395
+ # only wired MNCs. We resolve NC-C from claim_by_mc_id at call time
1396
+ # when the sentence binds a claim_id.
1397
+ #
1398
+ # Step 13 R7 codex P2 also applies here: when MNC ids collide across
1399
+ # manifests (two manifests both have "MNC-1"), passing a flat list to
1400
+ # one judge call makes the returned `violated_constraint_id` ambiguous
1401
+ # — we'd have to first-match-wins which mis-attributes the row to the
1402
+ # wrong manifest. Solution: run the judge ONCE PER MANIFEST, with that
1403
+ # manifest's MNC + NC-C set. Each return is unambiguous by construction;
1404
+ # cost is N judge calls per sentence (cf. cited path where each
1405
+ # citation already takes one judge call).
1406
+ manifest_mncs_by_id: dict[str, list[dict[str, Any]]] = {}
1407
+ for m in manifests:
1408
+ mid = m.get("manifest_id")
1409
+ if not mid:
1410
+ continue
1411
+ mncs_for_mid: list[dict[str, Any]] = []
1412
+ for mnc in m.get("manifest_negative_constraints") or []:
1413
+ if mnc.get("constraint_id"):
1414
+ mncs_for_mid.append(
1415
+ {"constraint_id": mnc["constraint_id"], "rule": mnc["rule"], "scope": "MNC"}
1416
+ )
1417
+ manifest_mncs_by_id[mid] = mncs_for_mid
1418
+
1419
+ constraint_violation_texts: set[str] = set()
1420
+ cv_counter = 1
1421
+ # v3.8.2 / #118 — uncited_audit_failures[] aggregate for JudgeInvocationError
1422
+ # on the uncited constraint-judging path. Mirrors INV-14 audit_tool_failure
1423
+ # on the cited path. Pre-v3.8.2 the failure was silently substituted as
1424
+ # NOT_VIOLATED, suppressing HIGH-WARN constraint checks; the UAF aggregate
1425
+ # surfaces the operational signal at MED-WARN advisory tier without
1426
+ # dropping audit coverage (option 4 — re-raise and abort — was rejected
1427
+ # for that exact coverage reason). See spec §3.6.
1428
+ uncited_audit_failures: list[dict[str, Any]] = []
1429
+ uaf_counter = 1
1430
+ for sentence in all_uncited_sentences:
1431
+ scoped_manifest_id_for_sentence = sentence.get("scoped_manifest_id")
1432
+ sentence_claim_id = sentence.get("manifest_claim_id")
1433
+
1434
+ # Decide which manifests this sentence is constraint-judged against.
1435
+ # Caller-pinned scope → that one manifest. Otherwise every manifest.
1436
+ if scoped_manifest_id_for_sentence:
1437
+ target_manifest_ids = [scoped_manifest_id_for_sentence] if scoped_manifest_id_for_sentence in manifest_mncs_by_id else []
1438
+ else:
1439
+ target_manifest_ids = list(manifest_mncs_by_id.keys())
1440
+
1441
+ if not target_manifest_ids:
1442
+ continue
1443
+
1444
+ # One judge call per (sentence, manifest) pair so MNC id collisions
1445
+ # across manifests cannot misattribute the violation (R7 codex P2).
1446
+ sentence_violation_recorded = False
1447
+ for mid in target_manifest_ids:
1448
+ per_manifest_constraints: list[dict[str, Any]] = list(manifest_mncs_by_id[mid])
1449
+ # R7 codex P1: also include NC-C for this manifest's bound claim.
1450
+ # v3.8.2 / #118 codex P2-2 + R2 P2-1: only set the UAF row's
1451
+ # manifest_claim_id when THIS manifest actually owns the claim
1452
+ # binding AND at least one NC constraint was added. When sentence
1453
+ # carries a sentence_claim_id but the current manifest doesn't
1454
+ # have that claim_id, OR the claim exists but has no NC entries
1455
+ # (so the failed judge call was MNC-only), the UAF row's
1456
+ # manifest_claim_id MUST stay null — the failure is MNC-only at
1457
+ # that point and a non-null binding would mislabel downstream
1458
+ # consumers about which constraint set the outage hit.
1459
+ uaf_manifest_claim_id: str | None = None
1460
+ if sentence_claim_id:
1461
+ claim = claim_by_mc_id.get((mid, sentence_claim_id))
1462
+ if claim is not None:
1463
+ for nc in claim.get("negative_constraints") or []:
1464
+ cid = nc.get("constraint_id")
1465
+ if cid:
1466
+ per_manifest_constraints.append(
1467
+ {"constraint_id": cid, "rule": nc["rule"], "scope": "NC"}
1468
+ )
1469
+ # Only mark NC-C binding when at least one NC
1470
+ # constraint actually entered the judge call.
1471
+ uaf_manifest_claim_id = sentence_claim_id
1472
+
1473
+ if not per_manifest_constraints:
1474
+ continue
1475
+
1476
+ applicable_ids: frozenset[str] = frozenset(
1477
+ c["constraint_id"] for c in per_manifest_constraints if c.get("constraint_id")
1478
+ )
1479
+ # Wrap in `_invoke_judge` so transient failures don't abort the
1480
+ # uncited stream. v3.8.2 / #118 — JudgeInvocationError now routes
1481
+ # to an uncited_audit_failures[] row (MED-WARN advisory, gate
1482
+ # passes) instead of synthesising a NOT_VIOLATED verdict. The
1483
+ # synthesis substitution shipped pre-v3.8.2 was silently
1484
+ # suppressing HIGH-WARN constraint checks on transient judge
1485
+ # outage — see spec §3.6 + §4 step 9 fourth bullet for routing,
1486
+ # and the design memo at docs/superpowers/plans/2026-05-17-issue-118-*
1487
+ # for the option 1-4 trade-off analysis.
1488
+ try:
1489
+ judge_result = _invoke_judge(
1490
+ judge_fn,
1491
+ allowed_judgments=_UNCITED_PATH_JUDGMENTS,
1492
+ active_constraint_ids=applicable_ids,
1493
+ claim_text=sentence["sentence_text"],
1494
+ retrieved_excerpt=None,
1495
+ anchor_kind=None,
1496
+ anchor_value=None,
1497
+ active_constraints=per_manifest_constraints,
1498
+ judge_model=judge_model,
1499
+ )
1500
+ except JudgeInvocationError as judge_err:
1501
+ uncited_audit_failures.append(
1502
+ _uncited_audit_failure_entry(
1503
+ sentence=sentence,
1504
+ scoped_manifest_id=mid,
1505
+ manifest_claim_id=uaf_manifest_claim_id,
1506
+ fault_class=judge_err.fault_class,
1507
+ detail=judge_err.detail,
1508
+ finding_id=f"UAF-{uaf_counter:03d}",
1509
+ judge_model=judge_model,
1510
+ now_iso=now_iso,
1511
+ )
1512
+ )
1513
+ uaf_counter += 1
1514
+ continue # no fake NOT_VIOLATED, no CV row, skip to next manifest
1515
+ if judge_result.get("judgment") == "VIOLATED":
1516
+ constraint_violations.append(
1517
+ _constraint_violation_entry(
1518
+ sentence=sentence,
1519
+ judge_result=judge_result,
1520
+ scoped_manifest_id=mid,
1521
+ finding_id=f"CV-{cv_counter:03d}",
1522
+ judge_model=judge_model,
1523
+ now_iso=now_iso,
1524
+ )
1525
+ )
1526
+ cv_counter += 1
1527
+ sentence_violation_recorded = True
1528
+
1529
+ if sentence_violation_recorded:
1530
+ constraint_violation_texts.add(sentence["sentence_text"])
1531
+
1532
+ # ---- Step 6 stream (uncited_assertion LOW-WARN advisory) ----
1533
+ # D4-c detector positives only — uncited_sentences is the filtered set.
1534
+ uncited_assertions: list[dict[str, Any]] = []
1535
+ uncited_sentence_texts: set[str] = set()
1536
+ ua_counter = 1
1537
+
1538
+ for sentence in uncited_sentences:
1539
+ uncited_sentence_texts.add(sentence["sentence_text"])
1540
+ # Always emit uncited_assertion (LOW-WARN advisory). CV-INV-4
1541
+ # explicitly permits a sentence to appear in both uncited_assertions[]
1542
+ # and constraint_violations[] simultaneously.
1543
+ uncited_assertions.append(
1544
+ _uncited_assertion_entry(
1545
+ sentence=sentence,
1546
+ finding_id=f"UA-{ua_counter:03d}",
1547
+ now_iso=now_iso,
1548
+ )
1549
+ )
1550
+ ua_counter += 1
1551
+
1552
+ # Also surface uncited_sentence_texts for any constraint-violation
1553
+ # sentence text that wasn't a D4-c positive but did violate an MNC.
1554
+ # The drift detector reads `uncited_sentence_texts` to apply the
1555
+ # D-INV-4 uncited-takes-precedence rule; without including CV-text
1556
+ # entries here, a sentence outside D4-c but matching a manifest claim
1557
+ # would produce both a constraint_violation row AND a drift row,
1558
+ # violating D-INV-4.
1559
+ uncited_sentence_texts.update(constraint_violation_texts)
1560
+
1561
+ # ---- Manifest set-diff drift detection ----
1562
+ cd_counter = 1
1563
+
1564
+ def _next_cd() -> str:
1565
+ nonlocal cd_counter
1566
+ out = f"CD-{cd_counter:03d}"
1567
+ cd_counter += 1
1568
+ return out
1569
+
1570
+ # Step 7 codex R1 CO-4: drift detection's emitted-side index MUST use
1571
+ # the FULL citation list, not the sampled subset. Sampling caps judge
1572
+ # invocations (spec §4 step 3) — it does NOT shrink the prose visible to
1573
+ # the manifest set-diff. Passing audited_citations here made every
1574
+ # unsampled-but-present citation look dropped from manifest, producing
1575
+ # false INTENDED_NOT_EMITTED rows in proportion to (total - cap).
1576
+ claim_drifts = _detect_drifts(
1577
+ manifests=manifests,
1578
+ emitted_citations=citations,
1579
+ uncited_sentence_texts=uncited_sentence_texts,
1580
+ constraint_absorbed_claim_ids=constraint_absorbed_claim_ids,
1581
+ constraint_absorbed_manifest_scopes=constraint_absorbed_manifest_scopes,
1582
+ now_iso=now_iso,
1583
+ next_finding_id=_next_cd,
1584
+ )
1585
+
1586
+ return {
1587
+ "claim_intent_manifests": manifests,
1588
+ "claim_audit_results": claim_audit_results,
1589
+ "uncited_assertions": uncited_assertions,
1590
+ "claim_drifts": claim_drifts,
1591
+ "constraint_violations": constraint_violations,
1592
+ "audit_sampling_summaries": sampling_summaries,
1593
+ "uncited_audit_failures": uncited_audit_failures,
1594
+ }