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.
- package/README.md +11 -5
- package/dist/apps/panel/index.html +2 -2
- package/dist/src/adapters/pi/extension.js +225 -92
- package/dist/src/adapters/pi/extension.js.map +1 -1
- package/dist/src/agents/import.js +44 -32
- package/dist/src/agents/import.js.map +1 -1
- package/dist/src/analysis/hooks.d.ts +1 -0
- package/dist/src/analysis/hooks.js +20 -1
- package/dist/src/analysis/hooks.js.map +1 -1
- package/dist/src/ars/bridge.d.ts +20 -0
- package/dist/src/ars/bridge.js +132 -0
- package/dist/src/ars/bridge.js.map +1 -0
- package/dist/src/ars/contracts.d.ts +55 -0
- package/dist/src/ars/contracts.js +2 -0
- package/dist/src/ars/contracts.js.map +1 -0
- package/dist/src/ars/panel-plan.d.ts +4 -0
- package/dist/src/ars/panel-plan.js +11 -0
- package/dist/src/ars/panel-plan.js.map +1 -0
- package/dist/src/ars/pi-panel-executor.d.ts +30 -0
- package/dist/src/ars/pi-panel-executor.js +140 -0
- package/dist/src/ars/pi-panel-executor.js.map +1 -0
- package/dist/src/ars/profile.d.ts +36 -0
- package/dist/src/ars/profile.js +119 -0
- package/dist/src/ars/profile.js.map +1 -0
- package/dist/src/ars/re-review.d.ts +22 -0
- package/dist/src/ars/re-review.js +172 -0
- package/dist/src/ars/re-review.js.map +1 -0
- package/dist/src/branding.d.ts +2 -4
- package/dist/src/branding.js +3 -5
- package/dist/src/branding.js.map +1 -1
- package/dist/src/bundled-tools.d.ts +3 -0
- package/dist/src/bundled-tools.js +21 -0
- package/dist/src/bundled-tools.js.map +1 -0
- package/dist/src/chat.js +6 -5
- package/dist/src/chat.js.map +1 -1
- package/dist/src/creation/contracts.d.ts +38 -0
- package/dist/src/creation/contracts.js +2 -0
- package/dist/src/creation/contracts.js.map +1 -0
- package/dist/src/creation/service.d.ts +7 -0
- package/dist/src/creation/service.js +196 -0
- package/dist/src/creation/service.js.map +1 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.js +10 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/install/installer.js +32 -10
- package/dist/src/install/installer.js.map +1 -1
- package/dist/src/orchestration/personas.d.ts +15 -0
- package/dist/src/orchestration/personas.js +51 -0
- package/dist/src/orchestration/personas.js.map +1 -0
- package/dist/src/orchestration/pi-executor.d.ts +1 -0
- package/dist/src/orchestration/pi-executor.js +1 -1
- package/dist/src/orchestration/pi-executor.js.map +1 -1
- package/dist/src/panel/extension.js +29 -8
- package/dist/src/panel/extension.js.map +1 -1
- package/dist/src/panel/server.js +14 -5
- package/dist/src/panel/server.js.map +1 -1
- package/dist/src/project/paths.d.ts +3 -0
- package/dist/src/project/paths.js +7 -0
- package/dist/src/project/paths.js.map +1 -1
- package/dist/src/rules/user-rules.d.ts +8 -0
- package/dist/src/rules/user-rules.js +36 -0
- package/dist/src/rules/user-rules.js.map +1 -0
- package/dist/src/skills/contracts.d.ts +4 -4
- package/dist/src/skills/recommended.js +1 -1
- package/dist/src/skills/registry.js +49 -28
- package/dist/src/skills/registry.js.map +1 -1
- package/dist/src/style/cli-ui.js +0 -1
- package/dist/src/style/cli-ui.js.map +1 -1
- package/package.json +14 -3
- package/scripts/rebrand-pi.mjs +6 -0
- package/skills/recommended/catalog.json +2 -11
- package/vendor/ars/.claude/CLAUDE.md +371 -0
- package/vendor/ars/.command-invariants.toml +24 -0
- package/vendor/ars/CITATION.cff +35 -0
- package/vendor/ars/LICENSE +417 -0
- package/vendor/ars/MODE_REGISTRY.md +76 -0
- package/vendor/ars/NOTICE.md +26 -0
- package/vendor/ars/POSITIONING.md +99 -0
- package/vendor/ars/PSYCLAW_SOURCE.json +10 -0
- package/vendor/ars/README.md +751 -0
- package/vendor/ars/SECURITY.md +52 -0
- package/vendor/ars/THIRD_PARTY.md +70 -0
- package/vendor/ars/academic-paper/SKILL.md +542 -0
- package/vendor/ars/academic-paper/agents/abstract_bilingual_agent.md +171 -0
- package/vendor/ars/academic-paper/agents/argument_builder_agent.md +276 -0
- package/vendor/ars/academic-paper/agents/citation_compliance_agent.md +422 -0
- package/vendor/ars/academic-paper/agents/draft_writer_agent.md +656 -0
- package/vendor/ars/academic-paper/agents/formatter_agent.md +999 -0
- package/vendor/ars/academic-paper/agents/intake_agent.md +393 -0
- package/vendor/ars/academic-paper/agents/literature_strategist_agent.md +626 -0
- package/vendor/ars/academic-paper/agents/peer_reviewer_agent.md +516 -0
- package/vendor/ars/academic-paper/agents/revision_coach_agent.md +334 -0
- package/vendor/ars/academic-paper/agents/socratic_mentor_agent.md +527 -0
- package/vendor/ars/academic-paper/agents/structure_architect_agent.md +401 -0
- package/vendor/ars/academic-paper/agents/visualization_agent.md +441 -0
- package/vendor/ars/academic-paper/examples/chinese_paper_example.md +278 -0
- package/vendor/ars/academic-paper/examples/clinical_citation_verification_checklist.md +95 -0
- package/vendor/ars/academic-paper/examples/clinical_epistemic_status_example.md +100 -0
- package/vendor/ars/academic-paper/examples/commitment_ledger_example.md +147 -0
- package/vendor/ars/academic-paper/examples/imrad_hei_example.md +234 -0
- package/vendor/ars/academic-paper/examples/literature_review_example.md +260 -0
- package/vendor/ars/academic-paper/examples/plan_mode_guided_writing.md +600 -0
- package/vendor/ars/academic-paper/examples/revision_mode_example.md +344 -0
- package/vendor/ars/academic-paper/examples/revision_recovery_example.md +506 -0
- package/vendor/ars/academic-paper/examples/version_family_reconciliation_example.md +89 -0
- package/vendor/ars/academic-paper/references/abstract_writing_guide.md +169 -0
- package/vendor/ars/academic-paper/references/academic_writing_style.md +188 -0
- package/vendor/ars/academic-paper/references/anti_leakage_protocol.md +83 -0
- package/vendor/ars/academic-paper/references/apa7_chinese_citation_guide.md +364 -0
- package/vendor/ars/academic-paper/references/apa7_extended_guide.md +198 -0
- package/vendor/ars/academic-paper/references/changelog.md +11 -0
- package/vendor/ars/academic-paper/references/citation_format_switcher.md +228 -0
- package/vendor/ars/academic-paper/references/committee_correspondence_protocol.md +158 -0
- package/vendor/ars/academic-paper/references/credit_authorship_guide.md +308 -0
- package/vendor/ars/academic-paper/references/disclosure_mode_protocol.md +478 -0
- package/vendor/ars/academic-paper/references/domain_evidence_profiles.md +38 -0
- package/vendor/ars/academic-paper/references/failure_paths.md +349 -0
- package/vendor/ars/academic-paper/references/funding_statement_guide.md +319 -0
- package/vendor/ars/academic-paper/references/hei_domain_glossary.md +169 -0
- package/vendor/ars/academic-paper/references/intro_title_rhetoric_guide.md +114 -0
- package/vendor/ars/academic-paper/references/journal_submission_guide.md +249 -0
- package/vendor/ars/academic-paper/references/latex_template_reference.md +378 -0
- package/vendor/ars/academic-paper/references/mode_selection_guide.md +378 -0
- package/vendor/ars/academic-paper/references/paper_structure_patterns.md +330 -0
- package/vendor/ars/academic-paper/references/plan_mode_protocol.md +112 -0
- package/vendor/ars/academic-paper/references/policy_anchor_disclosure_protocol.md +200 -0
- package/vendor/ars/academic-paper/references/policy_anchor_table.md +157 -0
- package/vendor/ars/academic-paper/references/revision_patch_protocol.md +173 -0
- package/vendor/ars/academic-paper/references/statistical_visualization_standards.md +750 -0
- package/vendor/ars/academic-paper/references/venue_disclosure_policies.md +259 -0
- package/vendor/ars/academic-paper/references/vlm_figure_verification.md +126 -0
- package/vendor/ars/academic-paper/references/workflow_phase_details.md +135 -0
- package/vendor/ars/academic-paper/references/writing_judgment_framework.md +59 -0
- package/vendor/ars/academic-paper/references/writing_quality_check.md +173 -0
- package/vendor/ars/academic-paper/templates/bilingual_abstract_template.md +78 -0
- package/vendor/ars/academic-paper/templates/case_study_template.md +129 -0
- package/vendor/ars/academic-paper/templates/conference_paper_template.md +108 -0
- package/vendor/ars/academic-paper/templates/credit_statement_template.md +132 -0
- package/vendor/ars/academic-paper/templates/funding_statement_template.md +290 -0
- package/vendor/ars/academic-paper/templates/imrad_template.md +183 -0
- package/vendor/ars/academic-paper/templates/latex_article_template.tex +199 -0
- package/vendor/ars/academic-paper/templates/literature_review_template.md +135 -0
- package/vendor/ars/academic-paper/templates/policy_brief_template.md +139 -0
- package/vendor/ars/academic-paper/templates/revision_tracking_template.md +199 -0
- package/vendor/ars/academic-paper/templates/theoretical_paper_template.md +119 -0
- package/vendor/ars/academic-paper-reviewer/SKILL.md +491 -0
- package/vendor/ars/academic-paper-reviewer/agents/devils_advocate_reviewer_agent.md +443 -0
- package/vendor/ars/academic-paper-reviewer/agents/domain_reviewer_agent.md +412 -0
- package/vendor/ars/academic-paper-reviewer/agents/editorial_synthesizer_agent.md +478 -0
- package/vendor/ars/academic-paper-reviewer/agents/eic_agent.md +339 -0
- package/vendor/ars/academic-paper-reviewer/agents/field_analyst_agent.md +221 -0
- package/vendor/ars/academic-paper-reviewer/agents/methodology_reviewer_agent.md +449 -0
- package/vendor/ars/academic-paper-reviewer/agents/perspective_reviewer_agent.md +427 -0
- package/vendor/ars/academic-paper-reviewer/examples/hei_paper_review_example.md +391 -0
- package/vendor/ars/academic-paper-reviewer/examples/interdisciplinary_review_example.md +299 -0
- package/vendor/ars/academic-paper-reviewer/examples/subclaim_decomposition_example.md +80 -0
- package/vendor/ars/academic-paper-reviewer/references/calibration_mode_protocol.md +256 -0
- package/vendor/ars/academic-paper-reviewer/references/changelog.md +10 -0
- package/vendor/ars/academic-paper-reviewer/references/editorial_decision_standards.md +236 -0
- package/vendor/ars/academic-paper-reviewer/references/guided_mode_protocol.md +34 -0
- package/vendor/ars/academic-paper-reviewer/references/integration_guide.md +15 -0
- package/vendor/ars/academic-paper-reviewer/references/quality_rubrics.md +84 -0
- package/vendor/ars/academic-paper-reviewer/references/re_review_mode_protocol.md +340 -0
- package/vendor/ars/academic-paper-reviewer/references/review_criteria_framework.md +98 -0
- package/vendor/ars/academic-paper-reviewer/references/review_panel_provenance_protocol.md +197 -0
- package/vendor/ars/academic-paper-reviewer/references/review_quality_thinking.md +58 -0
- package/vendor/ars/academic-paper-reviewer/references/reviewer_sprint_prompt_source.md +324 -0
- package/vendor/ars/academic-paper-reviewer/references/sprint_contract_protocol.md +296 -0
- package/vendor/ars/academic-paper-reviewer/references/statistical_reporting_standards.md +505 -0
- package/vendor/ars/academic-paper-reviewer/references/top_journals_by_field.md +206 -0
- package/vendor/ars/academic-paper-reviewer/templates/editorial_decision_template.md +235 -0
- package/vendor/ars/academic-paper-reviewer/templates/peer_review_report_template.md +305 -0
- package/vendor/ars/academic-paper-reviewer/templates/revision_response_template.md +248 -0
- package/vendor/ars/academic-pipeline/SKILL.md +736 -0
- package/vendor/ars/academic-pipeline/agents/claim_ref_alignment_audit_agent.md +382 -0
- package/vendor/ars/academic-pipeline/agents/collaboration_depth_agent.md +164 -0
- package/vendor/ars/academic-pipeline/agents/integrity_verification_agent.md +870 -0
- package/vendor/ars/academic-pipeline/agents/pipeline_orchestrator_agent.md +1379 -0
- package/vendor/ars/academic-pipeline/agents/state_tracker_agent.md +622 -0
- package/vendor/ars/academic-pipeline/examples/full_pipeline_example.md +482 -0
- package/vendor/ars/academic-pipeline/examples/integrity_failure_recovery.md +389 -0
- package/vendor/ars/academic-pipeline/examples/mid_entry_example.md +414 -0
- package/vendor/ars/academic-pipeline/references/adapters/.gitkeep +0 -0
- package/vendor/ars/academic-pipeline/references/adapters/overview.md +153 -0
- package/vendor/ars/academic-pipeline/references/ai_research_failure_modes.md +185 -0
- package/vendor/ars/academic-pipeline/references/changelog.md +14 -0
- package/vendor/ars/academic-pipeline/references/claim_audit_calibration_protocol.md +175 -0
- package/vendor/ars/academic-pipeline/references/claim_verification_protocol.md +282 -0
- package/vendor/ars/academic-pipeline/references/external_review_protocol.md +131 -0
- package/vendor/ars/academic-pipeline/references/integrity_review_protocol.md +110 -0
- package/vendor/ars/academic-pipeline/references/literature_corpus_consumers.md +193 -0
- package/vendor/ars/academic-pipeline/references/mode_advisor.md +135 -0
- package/vendor/ars/academic-pipeline/references/passport_as_reset_boundary.md +132 -0
- package/vendor/ars/academic-pipeline/references/pipeline_state_machine.md +405 -0
- package/vendor/ars/academic-pipeline/references/plagiarism_detection_protocol.md +239 -0
- package/vendor/ars/academic-pipeline/references/process_summary_protocol.md +209 -0
- package/vendor/ars/academic-pipeline/references/progress_dashboard_template.md +38 -0
- package/vendor/ars/academic-pipeline/references/reinforcement_content.md +15 -0
- package/vendor/ars/academic-pipeline/references/reproducibility_audit.md +55 -0
- package/vendor/ars/academic-pipeline/references/score_trajectory_protocol.md +78 -0
- package/vendor/ars/academic-pipeline/references/team_collaboration_protocol.md +261 -0
- package/vendor/ars/academic-pipeline/references/two_stage_review_protocol.md +27 -0
- package/vendor/ars/academic-pipeline/templates/pipeline_status_template.md +146 -0
- package/vendor/ars/agents/report_compiler_agent.md +341 -0
- package/vendor/ars/agents/research_architect_agent.md +298 -0
- package/vendor/ars/agents/synthesis_agent.md +356 -0
- package/vendor/ars/commands/ars-3w.md +10 -0
- package/vendor/ars/commands/ars-abstract.md +10 -0
- package/vendor/ars/commands/ars-cache-invalidate.md +20 -0
- package/vendor/ars/commands/ars-citation-check.md +10 -0
- package/vendor/ars/commands/ars-disclosure.md +10 -0
- package/vendor/ars/commands/ars-format-convert.md +10 -0
- package/vendor/ars/commands/ars-full.md +9 -0
- package/vendor/ars/commands/ars-lit-review.md +12 -0
- package/vendor/ars/commands/ars-mark-read.md +18 -0
- package/vendor/ars/commands/ars-outline.md +10 -0
- package/vendor/ars/commands/ars-plan.md +10 -0
- package/vendor/ars/commands/ars-rebuttal-audit.md +12 -0
- package/vendor/ars/commands/ars-reviewer.md +9 -0
- package/vendor/ars/commands/ars-revision-coach.md +9 -0
- package/vendor/ars/commands/ars-revision.md +10 -0
- package/vendor/ars/commands/ars-unmark-read.md +16 -0
- package/vendor/ars/deep-research/SKILL.md +600 -0
- package/vendor/ars/deep-research/agents/bibliography_agent.md +473 -0
- package/vendor/ars/deep-research/agents/devils_advocate_agent.md +192 -0
- package/vendor/ars/deep-research/agents/editor_in_chief_agent.md +167 -0
- package/vendor/ars/deep-research/agents/ethics_review_agent.md +267 -0
- package/vendor/ars/deep-research/agents/meta_analysis_agent.md +325 -0
- package/vendor/ars/deep-research/agents/monitoring_agent.md +209 -0
- package/vendor/ars/deep-research/agents/report_compiler_agent.md +341 -0
- package/vendor/ars/deep-research/agents/research_architect_agent.md +298 -0
- package/vendor/ars/deep-research/agents/research_question_agent.md +216 -0
- package/vendor/ars/deep-research/agents/risk_of_bias_agent.md +231 -0
- package/vendor/ars/deep-research/agents/socratic_mentor_agent.md +764 -0
- package/vendor/ars/deep-research/agents/source_verification_agent.md +219 -0
- package/vendor/ars/deep-research/agents/synthesis_agent.md +356 -0
- package/vendor/ars/deep-research/agents/timeline_extraction_agent.md +99 -0
- package/vendor/ars/deep-research/examples/exploratory_research.md +157 -0
- package/vendor/ars/deep-research/examples/fact_check_mode.md +173 -0
- package/vendor/ars/deep-research/examples/handoff_to_paper.md +318 -0
- package/vendor/ars/deep-research/examples/idea_diversity_coverage_gap_advisory.md +64 -0
- package/vendor/ars/deep-research/examples/policy_analysis.md +161 -0
- package/vendor/ars/deep-research/examples/review_mode.md +253 -0
- package/vendor/ars/deep-research/examples/socratic_guided_research.md +331 -0
- package/vendor/ars/deep-research/examples/systematic_review.md +133 -0
- package/vendor/ars/deep-research/references/apa7_style_guide.md +162 -0
- package/vendor/ars/deep-research/references/argumentation_reasoning_framework.md +68 -0
- package/vendor/ars/deep-research/references/arxiv_api_protocol.md +76 -0
- package/vendor/ars/deep-research/references/changelog.md +22 -0
- package/vendor/ars/deep-research/references/chinese_literature_api_protocol.md +317 -0
- package/vendor/ars/deep-research/references/cross_agent_quality_definitions.md +14 -0
- package/vendor/ars/deep-research/references/crossref_api_protocol.md +84 -0
- package/vendor/ars/deep-research/references/equator_reporting_guidelines.md +482 -0
- package/vendor/ars/deep-research/references/ethics_checklist.md +282 -0
- package/vendor/ars/deep-research/references/failure_paths.md +355 -0
- package/vendor/ars/deep-research/references/interdisciplinary_bridges.md +292 -0
- package/vendor/ars/deep-research/references/irb_decision_tree.md +315 -0
- package/vendor/ars/deep-research/references/literature_monitoring_strategies.md +263 -0
- package/vendor/ars/deep-research/references/logical_fallacies.md +192 -0
- package/vendor/ars/deep-research/references/methodology_patterns.md +462 -0
- package/vendor/ars/deep-research/references/mode_selection_guide.md +331 -0
- package/vendor/ars/deep-research/references/openalex_api_protocol.md +82 -0
- package/vendor/ars/deep-research/references/preregistration_guide.md +324 -0
- package/vendor/ars/deep-research/references/semantic_scholar_api_protocol.md +107 -0
- package/vendor/ars/deep-research/references/socratic_mode_protocol.md +99 -0
- package/vendor/ars/deep-research/references/socratic_questioning_framework.md +232 -0
- package/vendor/ars/deep-research/references/source_quality_hierarchy.md +188 -0
- package/vendor/ars/deep-research/references/systematic_review_protocol.md +95 -0
- package/vendor/ars/deep-research/references/systematic_review_toolkit.md +353 -0
- package/vendor/ars/deep-research/templates/evidence_assessment_template.md +127 -0
- package/vendor/ars/deep-research/templates/literature_matrix_template.md +85 -0
- package/vendor/ars/deep-research/templates/preregistration_template.md +318 -0
- package/vendor/ars/deep-research/templates/prisma_protocol_template.md +248 -0
- package/vendor/ars/deep-research/templates/prisma_report_template.md +415 -0
- package/vendor/ars/deep-research/templates/research_brief_template.md +93 -0
- package/vendor/ars/package.json +24 -0
- package/vendor/ars/pi/README.md +161 -0
- package/vendor/ars/pi/package.json +26 -0
- package/vendor/ars/pi/wrapper.js +193 -0
- package/vendor/ars/pi/wrapper.test.mjs +201 -0
- package/vendor/ars/pyproject.toml +2 -0
- package/vendor/ars/requirements-pdf-content-classifier.txt +5 -0
- package/vendor/ars/scripts/_block_parser.py +396 -0
- package/vendor/ars/scripts/_ci_pytest_manifest.toml +661 -0
- package/vendor/ars/scripts/_claim_audit_constants.py +268 -0
- package/vendor/ars/scripts/_e4_evidence.py +110 -0
- package/vendor/ars/scripts/_eval_threshold_gate.py +73 -0
- package/vendor/ars/scripts/_markdown_lint_util.py +224 -0
- package/vendor/ars/scripts/_next_verified_at_ms.py +176 -0
- package/vendor/ars/scripts/_passport_yaml.py +53 -0
- package/vendor/ars/scripts/_skill_lint.py +254 -0
- package/vendor/ars/scripts/_text_similarity.py +141 -0
- package/vendor/ars/scripts/adapters/README.md +89 -0
- package/vendor/ars/scripts/adapters/_common.py +209 -0
- package/vendor/ars/scripts/adapters/examples/folder_scan/expected_passport.yaml +25 -0
- package/vendor/ars/scripts/adapters/examples/folder_scan/expected_rejection_log.yaml +18 -0
- package/vendor/ars/scripts/adapters/examples/folder_scan/input_fixture/Chen2024_AIAssessment.pdf +0 -0
- package/vendor/ars/scripts/adapters/examples/folder_scan/input_fixture/Wang_2023_formative_feedback.pdf +0 -0
- package/vendor/ars/scripts/adapters/examples/folder_scan/input_fixture/paper1.pdf +0 -0
- package/vendor/ars/scripts/adapters/examples/folder_scan/input_fixture//344/270/255/346/226/207/346/252/224/345/220/215_2024.pdf +0 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/expected_passport.yaml +40 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/expected_rejection_log.yaml +13 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/.gitkeep +0 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/.obsidian/app.json +1 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/_templates/tmpl.md +7 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/chen2024ai.md +13 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/invalid.md +1 -0
- package/vendor/ars/scripts/adapters/examples/obsidian/input_fixture/vault/wang2023formative.md +10 -0
- package/vendor/ars/scripts/adapters/examples/zotero/expected_passport.yaml +34 -0
- package/vendor/ars/scripts/adapters/examples/zotero/expected_rejection_log.yaml +34 -0
- package/vendor/ars/scripts/adapters/examples/zotero/input_fixture/.gitkeep +0 -0
- package/vendor/ars/scripts/adapters/examples/zotero/input_fixture/export.json +43 -0
- package/vendor/ars/scripts/adapters/folder_scan.py +214 -0
- package/vendor/ars/scripts/adapters/obsidian.py +336 -0
- package/vendor/ars/scripts/adapters/tests/.gitkeep +0 -0
- package/vendor/ars/scripts/adapters/tests/conftest.py +77 -0
- package/vendor/ars/scripts/adapters/tests/test_check_corpus_consumer_protocol.py +632 -0
- package/vendor/ars/scripts/adapters/tests/test_check_literature_corpus_schema.py +631 -0
- package/vendor/ars/scripts/adapters/tests/test_common.py +365 -0
- package/vendor/ars/scripts/adapters/tests/test_conftest.py +96 -0
- package/vendor/ars/scripts/adapters/tests/test_folder_scan.py +260 -0
- package/vendor/ars/scripts/adapters/tests/test_literature_corpus_entry_schema.py +745 -0
- package/vendor/ars/scripts/adapters/tests/test_obsidian.py +357 -0
- package/vendor/ars/scripts/adapters/tests/test_rejection_log_schema.py +271 -0
- package/vendor/ars/scripts/adapters/tests/test_sync_adapter_docs.py +88 -0
- package/vendor/ars/scripts/adapters/tests/test_zotero.py +454 -0
- package/vendor/ars/scripts/adapters/zotero.py +318 -0
- package/vendor/ars/scripts/adjudication_activity.py +1592 -0
- package/vendor/ars/scripts/announce-ars-loaded.sh +144 -0
- package/vendor/ars/scripts/ars_anchorize_draft.py +170 -0
- package/vendor/ars/scripts/ars_apply_revision_patch.py +912 -0
- package/vendor/ars/scripts/ars_cache_invalidate.py +40 -0
- package/vendor/ars/scripts/ars_mark_read.py +521 -0
- package/vendor/ars/scripts/ars_phase_scope_manifest.json +33 -0
- package/vendor/ars/scripts/ars_update_check.sh +215 -0
- package/vendor/ars/scripts/ars_write_scope_guard.py +506 -0
- package/vendor/ars/scripts/arxiv_client.py +222 -0
- package/vendor/ars/scripts/audit_snapshot.py +572 -0
- package/vendor/ars/scripts/bibliographic_integrity_signals.py +800 -0
- package/vendor/ars/scripts/bootstrap_timeline_yaml.py +146 -0
- package/vendor/ars/scripts/build_claim_standing_candidate_ledger.py +1238 -0
- package/vendor/ars/scripts/build_claim_standing_query_plan.py +643 -0
- package/vendor/ars/scripts/build_content_coverage_advisory.py +1205 -0
- package/vendor/ars/scripts/build_cross_document_consistency_advisory.py +2332 -0
- package/vendor/ars/scripts/build_review_pathway_rule_trace.py +830 -0
- package/vendor/ars/scripts/build_submission_packet_manifest.py +2310 -0
- package/vendor/ars/scripts/check_215_field_norm.py +173 -0
- package/vendor/ars/scripts/check_216_surface_form.py +250 -0
- package/vendor/ars/scripts/check_268_nested_commitment_ledger.py +180 -0
- package/vendor/ars/scripts/check_390_revision_patch_discipline.py +296 -0
- package/vendor/ars/scripts/check_392_citation_verification_intake.py +126 -0
- package/vendor/ars/scripts/check_394_submission_policy.py +178 -0
- package/vendor/ars/scripts/check_439_format_profile.py +307 -0
- package/vendor/ars/scripts/check_619_disclosure_closeout.py +237 -0
- package/vendor/ars/scripts/check_630_codex_subscription_transport.py +456 -0
- package/vendor/ars/scripts/check_669_review_pathway_rule_trace.py +662 -0
- package/vendor/ars/scripts/check_670_revision_roadmap_integration.py +518 -0
- package/vendor/ars/scripts/check_673_adjudication_activity.py +684 -0
- package/vendor/ars/scripts/check_684_review_criteria_binding.py +557 -0
- package/vendor/ars/scripts/check_agents_mirror_sync.py +115 -0
- package/vendor/ars/scripts/check_audit_artifact_consistency.py +2313 -0
- package/vendor/ars/scripts/check_benchmark_report.py +79 -0
- package/vendor/ars/scripts/check_bibliographic_integrity_signals.py +831 -0
- package/vendor/ars/scripts/check_calibration_tiers.py +235 -0
- package/vendor/ars/scripts/check_changelog_covers_merges.py +289 -0
- package/vendor/ars/scripts/check_ci_pytest_manifest.py +204 -0
- package/vendor/ars/scripts/check_claim_audit_consistency.py +1664 -0
- package/vendor/ars/scripts/check_claim_standing_candidate_ledger_integration.py +500 -0
- package/vendor/ars/scripts/check_claim_standing_freshness.py +253 -0
- package/vendor/ars/scripts/check_claim_standing_transmissions.py +449 -0
- package/vendor/ars/scripts/check_collaboration_depth_rubric.py +180 -0
- package/vendor/ars/scripts/check_command_frontmatter_name.py +116 -0
- package/vendor/ars/scripts/check_committee_correspondence.py +333 -0
- package/vendor/ars/scripts/check_compliance_report.py +108 -0
- package/vendor/ars/scripts/check_content_coverage_advisory_integration.py +796 -0
- package/vendor/ars/scripts/check_control_availability.py +172 -0
- package/vendor/ars/scripts/check_corpus_consumer_protocol.py +404 -0
- package/vendor/ars/scripts/check_cross_document_consistency_advisory_integration.py +1191 -0
- package/vendor/ars/scripts/check_cross_model_handoff_contract.py +234 -0
- package/vendor/ars/scripts/check_cross_model_verification_sync.py +261 -0
- package/vendor/ars/scripts/check_data_access_level.py +131 -0
- package/vendor/ars/scripts/check_data_flows.py +252 -0
- package/vendor/ars/scripts/check_decision_contract.py +464 -0
- package/vendor/ars/scripts/check_degradation_registry.py +326 -0
- package/vendor/ars/scripts/check_distribution_surface_claims.py +226 -0
- package/vendor/ars/scripts/check_domain_evidence_profile.py +538 -0
- package/vendor/ars/scripts/check_e4_promotion.py +195 -0
- package/vendor/ars/scripts/check_evals_gold_set.py +279 -0
- package/vendor/ars/scripts/check_evidence_row_integration.py +396 -0
- package/vendor/ars/scripts/check_experiment_provenance.py +117 -0
- package/vendor/ars/scripts/check_field_norm_severity.py +144 -0
- package/vendor/ars/scripts/check_firm_rules_sync.py +375 -0
- package/vendor/ars/scripts/check_heldout_measurement_report.py +1179 -0
- package/vendor/ars/scripts/check_human_subjects_output_contract.py +139 -0
- package/vendor/ars/scripts/check_human_subjects_reference_migration.py +844 -0
- package/vendor/ars/scripts/check_indirect_prompt_injection_no_call.py +328 -0
- package/vendor/ars/scripts/check_instruction_data_boundary.py +236 -0
- package/vendor/ars/scripts/check_judge_prompt_version.py +125 -0
- package/vendor/ars/scripts/check_literature_corpus_schema.py +402 -0
- package/vendor/ars/scripts/check_model_tiering.py +223 -0
- package/vendor/ars/scripts/check_panel_synthesis.py +1331 -0
- package/vendor/ars/scripts/check_passport_reset_contract.py +214 -0
- package/vendor/ars/scripts/check_pattern_eval_manifest.py +422 -0
- package/vendor/ars/scripts/check_persuasion_invariance_fixtures.py +637 -0
- package/vendor/ars/scripts/check_phase_conformance.py +2180 -0
- package/vendor/ars/scripts/check_pipeline_boundary_semantics.py +600 -0
- package/vendor/ars/scripts/check_pipeline_integrity.py +340 -0
- package/vendor/ars/scripts/check_policy_anchor_protocol.py +159 -0
- package/vendor/ars/scripts/check_policy_anchor_table.py +286 -0
- package/vendor/ars/scripts/check_preprint_venues_consistency.py +123 -0
- package/vendor/ars/scripts/check_prisma_trAIce_freshness.py +84 -0
- package/vendor/ars/scripts/check_promotion_bakeoff_preregistration.py +1303 -0
- package/vendor/ars/scripts/check_ranking_lift.py +323 -0
- package/vendor/ars/scripts/check_re_review_synthesis.py +2719 -0
- package/vendor/ars/scripts/check_receipt_enum_sync.py +203 -0
- package/vendor/ars/scripts/check_repro_lock.py +85 -0
- package/vendor/ars/scripts/check_review_pathway_output.py +276 -0
- package/vendor/ars/scripts/check_reviewer_data_fences.py +224 -0
- package/vendor/ars/scripts/check_reviewer_finding_contract.py +783 -0
- package/vendor/ars/scripts/check_reviewer_role_label.py +447 -0
- package/vendor/ars/scripts/check_reviewer_scoring_honesty.py +292 -0
- package/vendor/ars/scripts/check_reviewer_sprint_prompt_sync.py +409 -0
- package/vendor/ars/scripts/check_revision_claim_drift_suite_v2.py +1622 -0
- package/vendor/ars/scripts/check_revision_token_conservation.py +263 -0
- package/vendor/ars/scripts/check_risk_register.py +280 -0
- package/vendor/ars/scripts/check_role_scoped_contract.py +702 -0
- package/vendor/ars/scripts/check_rq_framing_patterns.py +184 -0
- package/vendor/ars/scripts/check_rubric_weight_consistency.py +32 -0
- package/vendor/ars/scripts/check_seeded_defect_fixtures.py +425 -0
- package/vendor/ars/scripts/check_setup_cross_model_parity.py +139 -0
- package/vendor/ars/scripts/check_spec_consistency.py +1249 -0
- package/vendor/ars/scripts/check_sprint_contract.py +371 -0
- package/vendor/ars/scripts/check_stage_capability_matrix.py +784 -0
- package/vendor/ars/scripts/check_submission_packet_manifest_integration.py +358 -0
- package/vendor/ars/scripts/check_surface_form_parity.py +445 -0
- package/vendor/ars/scripts/check_task_type.py +22 -0
- package/vendor/ars/scripts/check_tools_allowlist.py +538 -0
- package/vendor/ars/scripts/check_tortured_phrase_screening_integration.py +1974 -0
- package/vendor/ars/scripts/check_v3_10_134_write_scope.py +286 -0
- package/vendor/ars/scripts/check_v3_10_policy.py +656 -0
- package/vendor/ars/scripts/check_v3_6_6_ab_manifest.py +364 -0
- package/vendor/ars/scripts/check_v3_6_7_pattern_protection.py +1366 -0
- package/vendor/ars/scripts/check_v3_6_8_audit_scope_block.py +464 -0
- package/vendor/ars/scripts/check_v3_6_8_cite_provenance_pipeline.py +231 -0
- package/vendor/ars/scripts/check_v3_6_8_frontmatter_trust_schema.py +248 -0
- package/vendor/ars/scripts/check_v3_6_8_mark_read_commands.py +79 -0
- package/vendor/ars/scripts/check_v3_6_8_pattern_protection.py +941 -0
- package/vendor/ars/scripts/check_v3_7_3_three_layer_citation.py +318 -0
- package/vendor/ars/scripts/check_v3_8_annotation_literal_sync.py +228 -0
- package/vendor/ars/scripts/check_v3_9_0_triangulation.py +366 -0
- package/vendor/ars/scripts/check_v3_9_2_phase_boundary.py +270 -0
- package/vendor/ars/scripts/check_v3_9_4_temporal_verification.py +139 -0
- package/vendor/ars/scripts/check_venue_disclosure_policies.py +63 -0
- package/vendor/ars/scripts/check_version_consistency.py +826 -0
- package/vendor/ars/scripts/check_workflow_classification.py +223 -0
- package/vendor/ars/scripts/chinese_literature_client.py +1938 -0
- package/vendor/ars/scripts/citation_verification_summary.py +85 -0
- package/vendor/ars/scripts/claim_audit_calibration.py +517 -0
- package/vendor/ars/scripts/claim_audit_finalizer.py +456 -0
- package/vendor/ars/scripts/claim_audit_pipeline.py +1594 -0
- package/vendor/ars/scripts/claim_registry_coverage.py +493 -0
- package/vendor/ars/scripts/claim_standing_discovery.py +784 -0
- package/vendor/ars/scripts/claim_standing_stance_runner.py +758 -0
- package/vendor/ars/scripts/claim_standing_stance_scorer.py +239 -0
- package/vendor/ars/scripts/claim_strength_drift_disposition.py +666 -0
- package/vendor/ars/scripts/contamination_signals.py +689 -0
- package/vendor/ars/scripts/corpus_consumer_manifest.json +19 -0
- package/vendor/ars/scripts/cross_model_codex_transport.py +1374 -0
- package/vendor/ars/scripts/cross_model_codex_verify.sh +6 -0
- package/vendor/ars/scripts/cross_model_handoff.py +359 -0
- package/vendor/ars/scripts/cross_model_smoke_test.sh +183 -0
- package/vendor/ars/scripts/cross_model_smoke_test_codex.sh +35 -0
- package/vendor/ars/scripts/cross_model_verification/gemini_is_grounded.jq +45 -0
- package/vendor/ars/scripts/cross_model_verification/gemini_sources.jq +45 -0
- package/vendor/ars/scripts/cross_model_verification/normalize_compat_verdict.py +57 -0
- package/vendor/ars/scripts/cross_model_verification/openai_has_completed_web_search.jq +15 -0
- package/vendor/ars/scripts/cross_model_verification/openai_sources.jq +17 -0
- package/vendor/ars/scripts/cross_model_verification/openai_text.jq +11 -0
- package/vendor/ars/scripts/crossref_client.py +225 -0
- package/vendor/ars/scripts/dispatch_e4_panel.py +2731 -0
- package/vendor/ars/scripts/evidence_rows.py +2043 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/author_stage3.json +32 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/author_stage3_input.json +27 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/author_stage3_prime.json +32 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/author_stage3_prime_input.json +27 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/compliance_override.json +50 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/compliance_override_action.json +14 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/compliance_pass.json +44 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/explicit_user_request_log.json +26 -0
- package/vendor/ars/scripts/fixtures/adjudication_activity/mandatory_checkpoint_log.json +116 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/README.md +56 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a1_pass_with_p1/2026-04-30T15-22-04Z-d8f3.audit_artifact_entry.json +24 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a1_pass_with_p1/2026-04-30T15-22-04Z-d8f3.jsonl +4 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a1_pass_with_p1/2026-04-30T15-22-04Z-d8f3.meta.json +43 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a1_pass_with_p1/2026-04-30T15-22-04Z-d8f3.verdict.yaml +19 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/negative/a7_orphan_completion/2026-04-30T15-22-04Z-d8f3.jsonl +3 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/persisted_minor/2026-04-30T15-22-04Z-d8f3.audit_artifact_entry.json +26 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/persisted_minor/2026-04-30T15-22-04Z-d8f3.jsonl +4 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/persisted_minor/2026-04-30T15-22-04Z-d8f3.meta.json +43 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/persisted_minor/2026-04-30T15-22-04Z-d8f3.verdict.yaml +19 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/proposal_pass/2026-04-30T15-22-04Z-d8f3.audit_artifact_entry.json +24 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/proposal_pass/2026-04-30T15-22-04Z-d8f3.jsonl +4 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/proposal_pass/2026-04-30T15-22-04Z-d8f3.meta.json +43 -0
- package/vendor/ars/scripts/fixtures/audit_artifact_consistency/positive/proposal_pass/2026-04-30T15-22-04Z-d8f3.verdict.yaml +12 -0
- package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/retraction.json +46 -0
- package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/retraction_check_attestation.json +44 -0
- package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/tortured_phrase.json +44 -0
- package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/tortured_phrase_v1_2_abstract_missing.json +107 -0
- package/vendor/ars/scripts/fixtures/bibliographic_integrity_signals/tortured_phrase_v1_2_detected.json +124 -0
- package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/expected_outcomes.json +77 -0
- package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/manifest.yaml +37 -0
- package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/tuples/001-valid-doi-test.json +20 -0
- package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/tuples/002-valid-arxiv-test.json +19 -0
- package/vendor/ars/scripts/fixtures/check_evals_gold_set/clean/tuples/003-fabricated-test.json +20 -0
- package/vendor/ars/scripts/fixtures/claim_audit_calibration/gold_set.json +344 -0
- package/vendor/ars/scripts/fixtures/claim_standing_candidate_ledger/query_plan.json +108 -0
- package/vendor/ars/scripts/fixtures/claim_standing_candidate_ledger/retrieval_input.json +179 -0
- package/vendor/ars/scripts/fixtures/committee_correspondence/16fd83f6aec7/concern_tracker.json +129 -0
- package/vendor/ars/scripts/fixtures/committee_correspondence/16fd83f6aec7/response_skeleton.md +19 -0
- package/vendor/ars/scripts/fixtures/committee_correspondence/16fd83f6aec7/source_letter.txt +9 -0
- package/vendor/ars/scripts/fixtures/content_coverage_advisory/base_draft.json +48 -0
- package/vendor/ars/scripts/fixtures/content_coverage_advisory/base_inventory.json +38 -0
- package/vendor/ars/scripts/fixtures/content_coverage_advisory/packet/consent.txt +1 -0
- package/vendor/ars/scripts/fixtures/content_coverage_advisory/session_sources.json +3 -0
- package/vendor/ars/scripts/fixtures/cross_document_consistency/README.md +6 -0
- package/vendor/ars/scripts/fixtures/cross_document_consistency/accepted_draft.md +35 -0
- package/vendor/ars/scripts/fixtures/cross_document_consistency/cases.json +75 -0
- package/vendor/ars/scripts/fixtures/cross_document_consistency/preregistration.md +5 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/forbidden_event.jsonl +4 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/grounded_verified.jsonl +3 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/malformed.jsonl +3 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/missing_search.jsonl +2 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/multiple_finals.jsonl +4 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/not_found.jsonl +3 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/unbound_source.jsonl +3 -0
- package/vendor/ars/scripts/fixtures/cross_model_codex_transport/wrong_search_shape.jsonl +3 -0
- package/vendor/ars/scripts/fixtures/evidence_rows/phase_e_inputs.json +114 -0
- package/vendor/ars/scripts/fixtures/evidence_rows/session_sources.json +5 -0
- package/vendor/ars/scripts/fixtures/human_subjects_authority/cross-border-us-tw-gdpr.json +71 -0
- package/vendor/ars/scripts/fixtures/human_subjects_authority/gdpr-member-state-unresolved.json +62 -0
- package/vendor/ars/scripts/fixtures/human_subjects_authority/missing-data-axis.json +45 -0
- package/vendor/ars/scripts/fixtures/human_subjects_authority/no-profile.json +33 -0
- package/vendor/ars/scripts/fixtures/human_subjects_authority/tw-gdpr-two-axis.json +74 -0
- package/vendor/ars/scripts/fixtures/human_subjects_authority/us-gdpr-two-axis.json +74 -0
- package/vendor/ars/scripts/fixtures/review_pathway_rule_trace/lint-near-misses.json +72 -0
- package/vendor/ars/scripts/fixtures/review_pathway_rule_trace/no-profile-request.json +18 -0
- package/vendor/ars/scripts/fixtures/review_pathway_rule_trace/tw-candidates-request.json +63 -0
- package/vendor/ars/scripts/fixtures/review_pathway_rule_trace/us-candidates-request.json +77 -0
- package/vendor/ars/scripts/fixtures/review_target_context/exact-declaration.json +24 -0
- package/vendor/ars/scripts/fixtures/review_target_context/field-general-declaration.json +24 -0
- package/vendor/ars/scripts/fixtures/review_target_context/msr-2027-technical-full-declaration.json +24 -0
- package/vendor/ars/scripts/fixtures/review_target_context/synthetic-registry.json +92 -0
- package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/README.md +21 -0
- package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/subject_context_attested_only.json +55 -0
- package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/subject_context_machine_supported.json +49 -0
- package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/subject_context_not_isolated.json +56 -0
- package/vendor/ars/scripts/fixtures/revision_claim_drift_v2/subject_context_unknown.json +49 -0
- package/vendor/ars/scripts/fixtures/submission_package/clean/paper.md +16 -0
- package/vendor/ars/scripts/fixtures/submission_package/clean/references.bib +13 -0
- package/vendor/ars/scripts/fixtures/submission_package/fallback_authoryear/paper.md +11 -0
- package/vendor/ars/scripts/fixtures/submission_package/fallback_authoryear/references.bib +13 -0
- package/vendor/ars/scripts/fixtures/submission_package/fallback_latex/paper.tex +9 -0
- package/vendor/ars/scripts/fixtures/submission_package/fallback_latex/references.bib +13 -0
- package/vendor/ars/scripts/fixtures/submission_package/marker_no_join/paper.md +7 -0
- package/vendor/ars/scripts/fixtures/submission_package/orphan_intext/paper.md +8 -0
- package/vendor/ars/scripts/fixtures/submission_package/orphan_intext/references.bib +6 -0
- package/vendor/ars/scripts/fixtures/submission_package/passports/corpus_only.yaml +9 -0
- package/vendor/ars/scripts/fixtures/submission_package/passports/summary_join.yaml +16 -0
- package/vendor/ars/scripts/fixtures/submission_package/profiles/full.yaml +15 -0
- package/vendor/ars/scripts/fixtures/submission_package/profiles/tight.yaml +15 -0
- package/vendor/ars/scripts/fixtures/submission_package/summary_join/paper.md +7 -0
- package/vendor/ars/scripts/fixtures/submission_package/uncited_reference/paper.md +9 -0
- package/vendor/ars/scripts/fixtures/submission_package/uncited_reference/references.bib +13 -0
- package/vendor/ars/scripts/fixtures/submission_package/venue_clean/paper.md +26 -0
- package/vendor/ars/scripts/fixtures/submission_package/venue_clean/references.bib +13 -0
- package/vendor/ars/scripts/fixtures/submission_package/venue_violations/paper.md +20 -0
- package/vendor/ars/scripts/fixtures/submission_package/venue_violations/references.bib +13 -0
- package/vendor/ars/scripts/fixtures/submission_packet_manifest/base_inventory.json +101 -0
- package/vendor/ars/scripts/fixtures/submission_packet_manifest/packet/consent-materials.txt +3 -0
- package/vendor/ars/scripts/fixtures/submission_packet_manifest/packet/training-certificate.txt +2 -0
- package/vendor/ars/scripts/fixtures/submission_packet_manifest/packet/tw-consent-materials.txt +3 -0
- package/vendor/ars/scripts/fixtures/tortured_phrase_screening/corpus_input.yaml +30 -0
- package/vendor/ars/scripts/fixtures/tortured_phrase_screening/own_draft.md +36 -0
- package/vendor/ars/scripts/fixtures/tortured_phrase_screening/own_draft.tex +21 -0
- package/vendor/ars/scripts/fixtures/tortured_phrase_screening/seed_expectations.json +218 -0
- package/vendor/ars/scripts/fixtures/tortured_phrase_screening/snapshot.json +164 -0
- package/vendor/ars/scripts/fixtures/tortured_phrase_screening/snapshot_manifest.json +29 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/README.md +55 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/arxiv/empty_feed.xml +10 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/arxiv/error_5xx.html +7 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/arxiv/id_hit.xml +26 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/README.md +69 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/cnki_landing_page.html +13 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/error_5xx.html +2 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coordinate_ambiguous.json +16 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coordinate_hit.json +16 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coordinate_zero.json +14 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coverage_hit.json +15 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esearch_coverage_zero.json +13 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_hit.json +43 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_issn_mismatch.json +31 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_no_doi.json +31 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_unknown_ra.json +34 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/esummary_year_mismatch.json +31 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/handle_absent.json +4 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/handle_exists.json +16 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/handle_internal_error.json +4 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/istic_csl_hit.json +25 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/istic_csl_other_title.json +18 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/ra_cnki.json +6 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/ra_crossref.json +6 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/ra_istic.json +6 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/chinese_literature/ra_unknown_prefix.json +6 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/crossref/doi_hit.json +24 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/crossref/error_5xx.html +7 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/crossref/title_search_miss.json +15 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/openalex/doi_hit.json +29 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/openalex/error_5xx.json +4 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/openalex/title_search_miss.json +11 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/semantic_scholar/doi_hit.json +14 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/semantic_scholar/error_5xx.json +3 -0
- package/vendor/ars/scripts/fixtures/transport_bodies/semantic_scholar/title_search_miss.json +5 -0
- package/vendor/ars/scripts/human_read_attestation_resolver.py +467 -0
- package/vendor/ars/scripts/ideation_diversity_assignment_gate.py +430 -0
- package/vendor/ars/scripts/inquiry_branch_ledger.py +2540 -0
- package/vendor/ars/scripts/legacy/ars_apply_revision_patch_v1_0.py +715 -0
- package/vendor/ars/scripts/legacy/check_re_review_synthesis_v1_0.py +2215 -0
- package/vendor/ars/scripts/migrate_literature_corpus_to_v3_10.py +223 -0
- package/vendor/ars/scripts/migrate_literature_corpus_to_v3_7_3.py +277 -0
- package/vendor/ars/scripts/migrate_literature_corpus_to_v3_9_0.py +304 -0
- package/vendor/ars/scripts/model_tiering_manifest.json +46 -0
- package/vendor/ars/scripts/openalex_client.py +232 -0
- package/vendor/ars/scripts/parse_audit_verdict.py +802 -0
- package/vendor/ars/scripts/pdf_content_classifier_worker.py +176 -0
- package/vendor/ars/scripts/pdf_read_preflight.py +1455 -0
- package/vendor/ars/scripts/policy_anchor_disclosure_referee.py +354 -0
- package/vendor/ars/scripts/recompute_receipts.py +1414 -0
- package/vendor/ars/scripts/render_claim_standing_view.py +374 -0
- package/vendor/ars/scripts/render_eval_comment.py +130 -0
- package/vendor/ars/scripts/render_harness_retirement_issue.py +167 -0
- package/vendor/ars/scripts/repro_lock_validation.py +90 -0
- package/vendor/ars/scripts/research_workflow_profile.py +1079 -0
- package/vendor/ars/scripts/resolve_human_subjects_authority.py +1158 -0
- package/vendor/ars/scripts/resolve_review_target_context.py +683 -0
- package/vendor/ars/scripts/resume_e4_record.py +509 -0
- package/vendor/ars/scripts/retraction_status.py +484 -0
- package/vendor/ars/scripts/review_criteria_binding.py +889 -0
- package/vendor/ars/scripts/review_panel_provenance.py +744 -0
- package/vendor/ars/scripts/revision_roadmap.py +1967 -0
- package/vendor/ars/scripts/run_ci_pytest_manifest.py +116 -0
- package/vendor/ars/scripts/run_codex_audit.sh +1191 -0
- package/vendor/ars/scripts/run_evals.py +513 -0
- package/vendor/ars/scripts/run_ideation_diversity_no_call.py +3505 -0
- package/vendor/ars/scripts/run_indirect_prompt_injection_no_call.py +3330 -0
- package/vendor/ars/scripts/run_indirect_prompt_injection_probe.py +399 -0
- package/vendor/ars/scripts/run_review_criteria_constructive_value.py +1895 -0
- package/vendor/ars/scripts/run_role_topology_utility_dry_run.py +606 -0
- package/vendor/ars/scripts/score_review_criteria_constructive_value.py +617 -0
- package/vendor/ars/scripts/semantic_scholar_client.py +291 -0
- package/vendor/ars/scripts/slr_lineage.py +59 -0
- package/vendor/ars/scripts/sync_adapter_docs.py +118 -0
- package/vendor/ars/scripts/temporal_integrity_audit.py +840 -0
- package/vendor/ars/scripts/test_431_exact_or_bust.py +253 -0
- package/vendor/ars/scripts/test__eval_threshold_gate.py +125 -0
- package/vendor/ars/scripts/test__markdown_lint_util.py +129 -0
- package/vendor/ars/scripts/test__next_verified_at_ms.py +256 -0
- package/vendor/ars/scripts/test_adjacent_framing_probe_lint.py +171 -0
- package/vendor/ars/scripts/test_adjudication_activity.py +1515 -0
- package/vendor/ars/scripts/test_ars_anchorize_draft.py +178 -0
- package/vendor/ars/scripts/test_ars_apply_revision_patch.py +1335 -0
- package/vendor/ars/scripts/test_ars_cache_invalidate.py +51 -0
- package/vendor/ars/scripts/test_ars_mark_read.py +910 -0
- package/vendor/ars/scripts/test_ars_update_check.py +816 -0
- package/vendor/ars/scripts/test_ars_write_scope_guard.py +790 -0
- package/vendor/ars/scripts/test_arxiv_client.py +374 -0
- package/vendor/ars/scripts/test_audit_schemas.py +560 -0
- package/vendor/ars/scripts/test_audit_snapshot_render_section_0.py +105 -0
- package/vendor/ars/scripts/test_block_parser.py +259 -0
- package/vendor/ars/scripts/test_bootstrap_timeline_yaml.py +148 -0
- package/vendor/ars/scripts/test_build_claim_standing_candidate_ledger.py +1203 -0
- package/vendor/ars/scripts/test_build_claim_standing_query_plan.py +791 -0
- package/vendor/ars/scripts/test_build_submission_packet_manifest.py +2644 -0
- package/vendor/ars/scripts/test_check_215_field_norm.py +238 -0
- package/vendor/ars/scripts/test_check_216_surface_form.py +341 -0
- package/vendor/ars/scripts/test_check_268_nested_commitment_ledger.py +194 -0
- package/vendor/ars/scripts/test_check_390_revision_patch_discipline.py +279 -0
- package/vendor/ars/scripts/test_check_392_citation_verification_intake.py +144 -0
- package/vendor/ars/scripts/test_check_394_submission_policy.py +200 -0
- package/vendor/ars/scripts/test_check_439_format_profile.py +252 -0
- package/vendor/ars/scripts/test_check_619_disclosure_closeout.py +158 -0
- package/vendor/ars/scripts/test_check_630_codex_subscription_transport.py +245 -0
- package/vendor/ars/scripts/test_check_669_review_pathway_rule_trace.py +304 -0
- package/vendor/ars/scripts/test_check_670_revision_roadmap_integration.py +260 -0
- package/vendor/ars/scripts/test_check_673_adjudication_activity.py +367 -0
- package/vendor/ars/scripts/test_check_684_review_criteria_binding.py +274 -0
- package/vendor/ars/scripts/test_check_agents_mirror_sync.py +137 -0
- package/vendor/ars/scripts/test_check_audit_artifact_consistency.py +2133 -0
- package/vendor/ars/scripts/test_check_benchmark_report.py +117 -0
- package/vendor/ars/scripts/test_check_bibliographic_integrity_signals.py +609 -0
- package/vendor/ars/scripts/test_check_calibration_tiers.py +376 -0
- package/vendor/ars/scripts/test_check_changelog_covers_merges.py +509 -0
- package/vendor/ars/scripts/test_check_ci_pytest_manifest.py +425 -0
- package/vendor/ars/scripts/test_check_claim_standing_candidate_ledger_integration.py +256 -0
- package/vendor/ars/scripts/test_check_claim_standing_freshness.py +277 -0
- package/vendor/ars/scripts/test_check_collaboration_depth_rubric.py +239 -0
- package/vendor/ars/scripts/test_check_command_frontmatter_name.py +178 -0
- package/vendor/ars/scripts/test_check_committee_correspondence.py +298 -0
- package/vendor/ars/scripts/test_check_compliance_report.py +381 -0
- package/vendor/ars/scripts/test_check_content_coverage_advisory_integration.py +308 -0
- package/vendor/ars/scripts/test_check_control_availability.py +361 -0
- package/vendor/ars/scripts/test_check_cross_document_consistency_advisory_integration.py +698 -0
- package/vendor/ars/scripts/test_check_cross_model_handoff_contract.py +301 -0
- package/vendor/ars/scripts/test_check_cross_model_verification_sync.py +203 -0
- package/vendor/ars/scripts/test_check_data_access_level.py +227 -0
- package/vendor/ars/scripts/test_check_data_flows.py +382 -0
- package/vendor/ars/scripts/test_check_decision_contract.py +387 -0
- package/vendor/ars/scripts/test_check_degradation_registry.py +270 -0
- package/vendor/ars/scripts/test_check_distribution_surface_claims.py +225 -0
- package/vendor/ars/scripts/test_check_domain_evidence_profile.py +439 -0
- package/vendor/ars/scripts/test_check_e4_promotion.py +163 -0
- package/vendor/ars/scripts/test_check_evals_gold_set.py +312 -0
- package/vendor/ars/scripts/test_check_evidence_row_integration.py +187 -0
- package/vendor/ars/scripts/test_check_field_norm_severity.py +173 -0
- package/vendor/ars/scripts/test_check_firm_rules_sync.py +342 -0
- package/vendor/ars/scripts/test_check_heldout_measurement_report.py +1508 -0
- package/vendor/ars/scripts/test_check_human_subjects_output_contract.py +129 -0
- package/vendor/ars/scripts/test_check_human_subjects_reference_migration.py +756 -0
- package/vendor/ars/scripts/test_check_instruction_data_boundary.py +204 -0
- package/vendor/ars/scripts/test_check_judge_prompt_version.py +90 -0
- package/vendor/ars/scripts/test_check_model_tiering.py +236 -0
- package/vendor/ars/scripts/test_check_panel_synthesis.py +1658 -0
- package/vendor/ars/scripts/test_check_passport_reset_contract.py +249 -0
- package/vendor/ars/scripts/test_check_pattern_eval_manifest.py +381 -0
- package/vendor/ars/scripts/test_check_persuasion_invariance_fixtures.py +591 -0
- package/vendor/ars/scripts/test_check_phase_conformance.py +4366 -0
- package/vendor/ars/scripts/test_check_pipeline_boundary_semantics.py +931 -0
- package/vendor/ars/scripts/test_check_pipeline_integrity.py +243 -0
- package/vendor/ars/scripts/test_check_policy_anchor_protocol.py +236 -0
- package/vendor/ars/scripts/test_check_policy_anchor_table.py +295 -0
- package/vendor/ars/scripts/test_check_prisma_trAIce_freshness.py +68 -0
- package/vendor/ars/scripts/test_check_promotion_bakeoff_preregistration.py +799 -0
- package/vendor/ars/scripts/test_check_ranking_lift.py +377 -0
- package/vendor/ars/scripts/test_check_re_review_synthesis.py +3398 -0
- package/vendor/ars/scripts/test_check_receipt_enum_sync.py +176 -0
- package/vendor/ars/scripts/test_check_repro_lock.py +107 -0
- package/vendor/ars/scripts/test_check_reviewer_data_fences.py +334 -0
- package/vendor/ars/scripts/test_check_reviewer_finding_contract.py +1107 -0
- package/vendor/ars/scripts/test_check_reviewer_role_label.py +491 -0
- package/vendor/ars/scripts/test_check_reviewer_scoring_honesty.py +222 -0
- package/vendor/ars/scripts/test_check_reviewer_sprint_prompt_sync.py +373 -0
- package/vendor/ars/scripts/test_check_revision_claim_drift_suite_v2.py +1925 -0
- package/vendor/ars/scripts/test_check_revision_token_conservation.py +398 -0
- package/vendor/ars/scripts/test_check_risk_register.py +336 -0
- package/vendor/ars/scripts/test_check_role_scoped_contract.py +1104 -0
- package/vendor/ars/scripts/test_check_rq_framing_patterns.py +110 -0
- package/vendor/ars/scripts/test_check_rubric_weight_consistency.py +32 -0
- package/vendor/ars/scripts/test_check_seeded_defect_fixtures.py +392 -0
- package/vendor/ars/scripts/test_check_setup_cross_model_parity.py +121 -0
- package/vendor/ars/scripts/test_check_spec_consistency.py +1081 -0
- package/vendor/ars/scripts/test_check_sprint_contract.py +458 -0
- package/vendor/ars/scripts/test_check_stage_capability_matrix.py +698 -0
- package/vendor/ars/scripts/test_check_submission_packet_manifest_integration.py +177 -0
- package/vendor/ars/scripts/test_check_surface_form_parity.py +417 -0
- package/vendor/ars/scripts/test_check_task_type.py +116 -0
- package/vendor/ars/scripts/test_check_tools_allowlist.py +835 -0
- package/vendor/ars/scripts/test_check_tortured_phrase_screening_integration.py +1306 -0
- package/vendor/ars/scripts/test_check_v3_10_134_write_scope.py +251 -0
- package/vendor/ars/scripts/test_check_v3_10_policy.py +547 -0
- package/vendor/ars/scripts/test_check_v3_6_7_pattern_protection.py +960 -0
- package/vendor/ars/scripts/test_check_v3_6_8_audit_scope_block.py +1000 -0
- package/vendor/ars/scripts/test_check_v3_6_8_cite_provenance_pipeline.py +454 -0
- package/vendor/ars/scripts/test_check_v3_6_8_frontmatter_trust_schema.py +581 -0
- package/vendor/ars/scripts/test_check_v3_6_8_mark_read_commands.py +120 -0
- package/vendor/ars/scripts/test_check_v3_6_8_pattern_protection.py +1138 -0
- package/vendor/ars/scripts/test_check_v3_7_3_three_layer_citation.py +566 -0
- package/vendor/ars/scripts/test_check_v3_8_annotation_literal_sync.py +262 -0
- package/vendor/ars/scripts/test_check_v3_9_0_triangulation.py +321 -0
- package/vendor/ars/scripts/test_check_v3_9_2_phase_boundary.py +190 -0
- package/vendor/ars/scripts/test_check_v3_9_4_temporal_verification.py +471 -0
- package/vendor/ars/scripts/test_check_version_consistency.py +1462 -0
- package/vendor/ars/scripts/test_check_workflow_classification.py +225 -0
- package/vendor/ars/scripts/test_chinese_literature_client.py +1889 -0
- package/vendor/ars/scripts/test_citation_existence_policy.py +480 -0
- package/vendor/ars/scripts/test_citation_verification_summary.py +342 -0
- package/vendor/ars/scripts/test_claim_audit_calibration.py +882 -0
- package/vendor/ars/scripts/test_claim_audit_finalizer.py +979 -0
- package/vendor/ars/scripts/test_claim_audit_pipeline.py +2398 -0
- package/vendor/ars/scripts/test_claim_audit_schema.py +1778 -0
- package/vendor/ars/scripts/test_claim_intent_manifest.py +666 -0
- package/vendor/ars/scripts/test_claim_registry_coverage.py +246 -0
- package/vendor/ars/scripts/test_claim_standing_discovery.py +579 -0
- package/vendor/ars/scripts/test_claim_standing_pipeline_wiring.py +290 -0
- package/vendor/ars/scripts/test_claim_standing_stance_assets.py +399 -0
- package/vendor/ars/scripts/test_claim_standing_stance_contracts.py +383 -0
- package/vendor/ars/scripts/test_claim_standing_stance_runner.py +349 -0
- package/vendor/ars/scripts/test_claim_standing_transmissions.py +605 -0
- package/vendor/ars/scripts/test_claim_strength_drift_disposition.py +517 -0
- package/vendor/ars/scripts/test_claim_verification_coverage_contract.py +104 -0
- package/vendor/ars/scripts/test_contamination_signals.py +1086 -0
- package/vendor/ars/scripts/test_content_coverage_advisory.py +1767 -0
- package/vendor/ars/scripts/test_cross_document_consistency_advisory.py +1270 -0
- package/vendor/ars/scripts/test_cross_model_codex_transport.py +1152 -0
- package/vendor/ars/scripts/test_cross_model_handoff.py +571 -0
- package/vendor/ars/scripts/test_cross_model_verification_guards.py +792 -0
- package/vendor/ars/scripts/test_crossref_client.py +393 -0
- package/vendor/ars/scripts/test_dispatch_e4_panel.py +4235 -0
- package/vendor/ars/scripts/test_e2e_claim_audit.py +540 -0
- package/vendor/ars/scripts/test_eval_harness_workflow.py +140 -0
- package/vendor/ars/scripts/test_evals_citation_extraction.py +150 -0
- package/vendor/ars/scripts/test_evals_lift_report_schema.py +108 -0
- package/vendor/ars/scripts/test_evidence_rows.py +2593 -0
- package/vendor/ars/scripts/test_experiment_provenance.py +915 -0
- package/vendor/ars/scripts/test_human_read_attestation_resolver.py +477 -0
- package/vendor/ars/scripts/test_ideation_diversity_assignment_gate.py +615 -0
- package/vendor/ars/scripts/test_indirect_prompt_injection_behavior_probe.py +250 -0
- package/vendor/ars/scripts/test_inquiry_branch_ledger.py +2296 -0
- package/vendor/ars/scripts/test_migrate_literature_corpus_to_v3_10.py +248 -0
- package/vendor/ars/scripts/test_migrate_literature_corpus_to_v3_7_3.py +545 -0
- package/vendor/ars/scripts/test_migrate_literature_corpus_to_v3_9_0.py +497 -0
- package/vendor/ars/scripts/test_normalize_compat_verdict.py +149 -0
- package/vendor/ars/scripts/test_openalex_client.py +490 -0
- package/vendor/ars/scripts/test_passport_yaml.py +104 -0
- package/vendor/ars/scripts/test_pattern_eval_runtime.py +1295 -0
- package/vendor/ars/scripts/test_pdf_read_preflight.py +1943 -0
- package/vendor/ars/scripts/test_policy_anchor_disclosure.py +666 -0
- package/vendor/ars/scripts/test_reading_probe_lint.py +218 -0
- package/vendor/ars/scripts/test_recompute_receipts.py +778 -0
- package/vendor/ars/scripts/test_render_claim_standing_view.py +192 -0
- package/vendor/ars/scripts/test_render_eval_comment.py +162 -0
- package/vendor/ars/scripts/test_render_harness_retirement_issue.py +110 -0
- package/vendor/ars/scripts/test_repro_lock_validation_drift.py +100 -0
- package/vendor/ars/scripts/test_research_workflow_profile.py +734 -0
- package/vendor/ars/scripts/test_resolve_human_subjects_authority.py +1219 -0
- package/vendor/ars/scripts/test_resolve_review_target_context.py +703 -0
- package/vendor/ars/scripts/test_resume_e4_record.py +315 -0
- package/vendor/ars/scripts/test_retraction_status.py +456 -0
- package/vendor/ars/scripts/test_review_criteria_binding.py +629 -0
- package/vendor/ars/scripts/test_review_panel_provenance.py +565 -0
- package/vendor/ars/scripts/test_review_pathway_rule_trace.py +821 -0
- package/vendor/ars/scripts/test_revision_roadmap.py +1255 -0
- package/vendor/ars/scripts/test_run_ci_pytest_manifest.py +186 -0
- package/vendor/ars/scripts/test_run_codex_audit_e2e.py +369 -0
- package/vendor/ars/scripts/test_run_evals.py +430 -0
- package/vendor/ars/scripts/test_run_guard_launcher.py +500 -0
- package/vendor/ars/scripts/test_run_ideation_diversity_no_call.py +1833 -0
- package/vendor/ars/scripts/test_run_indirect_prompt_injection_no_call.py +1889 -0
- package/vendor/ars/scripts/test_run_review_criteria_constructive_value.py +586 -0
- package/vendor/ars/scripts/test_run_role_topology_utility_dry_run.py +428 -0
- package/vendor/ars/scripts/test_score_review_criteria_constructive_value.py +340 -0
- package/vendor/ars/scripts/test_semantic_scholar_client.py +554 -0
- package/vendor/ars/scripts/test_slr_lineage_emission.py +230 -0
- package/vendor/ars/scripts/test_socratic_rq_non_generation_contract.py +173 -0
- package/vendor/ars/scripts/test_temporal_integrity_audit.py +438 -0
- package/vendor/ars/scripts/test_text_similarity.py +95 -0
- package/vendor/ars/scripts/test_title_fuzzy_false_positive.py +111 -0
- package/vendor/ars/scripts/test_tortured_phrase_screening.py +2959 -0
- package/vendor/ars/scripts/test_transport_fixture_citation_gate.py +338 -0
- package/vendor/ars/scripts/test_uncited_assertion.py +558 -0
- package/vendor/ars/scripts/test_v3_6_7_phase_6_6.py +1279 -0
- package/vendor/ars/scripts/test_validate_compliance_fixtures.py +36 -0
- package/vendor/ars/scripts/test_validate_ideation_diversity_assets.py +230 -0
- package/vendor/ars/scripts/test_venue_disclosure_contract.py +755 -0
- package/vendor/ars/scripts/test_verification_cache.py +280 -0
- package/vendor/ars/scripts/test_verification_gate.py +461 -0
- package/vendor/ars/scripts/test_verify_passport_cli.py +123 -0
- package/vendor/ars/scripts/test_verify_submission_package.py +1407 -0
- package/vendor/ars/scripts/test_version_records_schema.py +211 -0
- package/vendor/ars/scripts/tortured_phrase_screening.py +3502 -0
- package/vendor/ars/scripts/uncited_assertion_detector.py +254 -0
- package/vendor/ars/scripts/v3_6_7_inversion_manifest.json +9 -0
- package/vendor/ars/scripts/v3_6_8_inversion_manifest.json +10 -0
- package/vendor/ars/scripts/validate_claim_standing_stance_assets.py +249 -0
- package/vendor/ars/scripts/validate_compliance_fixtures.py +56 -0
- package/vendor/ars/scripts/validate_ideation_diversity_assets.py +303 -0
- package/vendor/ars/scripts/venue_disclosure_contract_harness.py +837 -0
- package/vendor/ars/scripts/verification_cache.py +276 -0
- package/vendor/ars/scripts/verification_gate/__init__.py +345 -0
- package/vendor/ars/scripts/verify_passport.py +133 -0
- package/vendor/ars/scripts/verify_submission_package.py +1657 -0
- package/vendor/ars/shared/agents/compliance_agent.md +136 -0
- package/vendor/ars/shared/artifact_reproducibility_pattern.md +173 -0
- package/vendor/ars/shared/benchmark_report.schema.json +81 -0
- package/vendor/ars/shared/benchmark_report_pattern.md +180 -0
- package/vendor/ars/shared/bibliographic_integrity_signals.md +142 -0
- package/vendor/ars/shared/collaboration_depth_rubric.md +154 -0
- package/vendor/ars/shared/compliance_checkpoint_protocol.md +162 -0
- package/vendor/ars/shared/compliance_report.schema.json +187 -0
- package/vendor/ars/shared/contracts/README.md +938 -0
- package/vendor/ars/shared/contracts/activity/adjudication_activity_input.schema.json +555 -0
- package/vendor/ars/shared/contracts/activity/adjudication_activity_store.schema.json +560 -0
- package/vendor/ars/shared/contracts/audit/audit_jsonl.schema.json +128 -0
- package/vendor/ars/shared/contracts/audit/audit_sidecar.schema.json +169 -0
- package/vendor/ars/shared/contracts/audit/audit_verdict.schema.json +133 -0
- package/vendor/ars/shared/contracts/audit/cross_document_consistency_advisory.schema.json +480 -0
- package/vendor/ars/shared/contracts/audit/cross_document_consistency_advisory_draft.schema.json +564 -0
- package/vendor/ars/shared/contracts/audit/cross_document_source_manifest.schema.json +202 -0
- package/vendor/ars/shared/contracts/audit/tortured_phrase_advisory.schema.json +1362 -0
- package/vendor/ars/shared/contracts/audit/tortured_phrase_snapshot.schema.json +208 -0
- package/vendor/ars/shared/contracts/audit/tortured_phrase_snapshot_manifest.schema.json +335 -0
- package/vendor/ars/shared/contracts/capability/stage_capability_matrix.json +434 -0
- package/vendor/ars/shared/contracts/claim_standing/candidate_ledger.schema.json +705 -0
- package/vendor/ars/shared/contracts/claim_standing/query_plan.schema.json +389 -0
- package/vendor/ars/shared/contracts/claim_standing/query_plan_v1_1.schema.json +782 -0
- package/vendor/ars/shared/contracts/claim_standing/retrieval_input.schema.json +440 -0
- package/vendor/ars/shared/contracts/claim_standing/stance_record.schema.json +460 -0
- package/vendor/ars/shared/contracts/claim_standing/transmission_ledger.schema.json +282 -0
- package/vendor/ars/shared/contracts/cross_model/codex_citation_receipt.schema.json +157 -0
- package/vendor/ars/shared/contracts/cross_model/codex_citation_request.schema.json +23 -0
- package/vendor/ars/shared/contracts/cross_model/promotion_bakeoff_sealed_commitment.schema.json +55 -0
- package/vendor/ars/shared/contracts/cross_model/promotion_bakeoff_sealed_reveal.schema.json +50 -0
- package/vendor/ars/shared/contracts/degradation_registry.json +428 -0
- package/vendor/ars/shared/contracts/evaluator/full.json +126 -0
- package/vendor/ars/shared/contracts/evidence/claim_registry.schema.json +50 -0
- package/vendor/ars/shared/contracts/evidence/claim_registry_coverage_report.schema.json +79 -0
- package/vendor/ars/shared/contracts/evidence/evidence_row.schema.json +504 -0
- package/vendor/ars/shared/contracts/evidence/evidence_row_v1_1.schema.json +364 -0
- package/vendor/ars/shared/contracts/evidence/evidence_row_v1_2.schema.json +714 -0
- package/vendor/ars/shared/contracts/evidence/evidence_row_v1_3.schema.json +524 -0
- package/vendor/ars/shared/contracts/human_subjects/authority_profile_registry.schema.json +497 -0
- package/vendor/ars/shared/contracts/human_subjects/committee_correspondence.schema.json +253 -0
- package/vendor/ars/shared/contracts/human_subjects/content_coverage_advisory.schema.json +620 -0
- package/vendor/ars/shared/contracts/human_subjects/irb_context_record.schema.json +329 -0
- package/vendor/ars/shared/contracts/human_subjects/resolved_authority_context.schema.json +347 -0
- package/vendor/ars/shared/contracts/human_subjects/review_pathway_rule_trace.schema.json +265 -0
- package/vendor/ars/shared/contracts/human_subjects/review_pathway_trace_request.schema.json +127 -0
- package/vendor/ars/shared/contracts/human_subjects/submission_packet_inventory.schema.json +240 -0
- package/vendor/ars/shared/contracts/human_subjects/submission_packet_manifest.schema.json +999 -0
- package/vendor/ars/shared/contracts/passport/audit_artifact_entry.schema.json +266 -0
- package/vendor/ars/shared/contracts/passport/bibliographic_integrity_signal.schema.json +1676 -0
- package/vendor/ars/shared/contracts/passport/citation_provenance.schema.json +107 -0
- package/vendor/ars/shared/contracts/passport/citation_verification_summary.schema.json +164 -0
- package/vendor/ars/shared/contracts/passport/claim_audit_result.schema.json +124 -0
- package/vendor/ars/shared/contracts/passport/claim_drift.schema.json +58 -0
- package/vendor/ars/shared/contracts/passport/claim_intent_manifest.schema.json +107 -0
- package/vendor/ars/shared/contracts/passport/constraint_violation.schema.json +65 -0
- package/vendor/ars/shared/contracts/passport/experiment_alignment_result.schema.json +69 -0
- package/vendor/ars/shared/contracts/passport/experiment_provenance_entry.schema.json +169 -0
- package/vendor/ars/shared/contracts/passport/human_read_log.schema.json +86 -0
- package/vendor/ars/shared/contracts/passport/inquiry_ledger_ref.schema.json +22 -0
- package/vendor/ars/shared/contracts/passport/literature_corpus_entry.schema.json +650 -0
- package/vendor/ars/shared/contracts/passport/preregistration_artifact.schema.json +132 -0
- package/vendor/ars/shared/contracts/passport/rejection_log.schema.json +89 -0
- package/vendor/ars/shared/contracts/passport/reset_ledger_entry.schema.json +158 -0
- package/vendor/ars/shared/contracts/passport/temporal_audit_results.schema.json +208 -0
- package/vendor/ars/shared/contracts/passport/terminal_policies.schema.json +50 -0
- package/vendor/ars/shared/contracts/passport/timeline.schema.json +102 -0
- package/vendor/ars/shared/contracts/passport/uncited_assertion.schema.json +56 -0
- package/vendor/ars/shared/contracts/passport/uncited_audit_failure.schema.json +72 -0
- package/vendor/ars/shared/contracts/passport/user_attested_read_resolution.schema.json +87 -0
- package/vendor/ars/shared/contracts/passport/version_records.schema.json +138 -0
- package/vendor/ars/shared/contracts/patch/block_manifest.schema.json +45 -0
- package/vendor/ars/shared/contracts/patch/legacy/v1_0/revision_patch.schema.json +110 -0
- package/vendor/ars/shared/contracts/patch/revision_patch.schema.json +250 -0
- package/vendor/ars/shared/contracts/pdf/pdf_content_classifier_diagnostic.schema.json +39 -0
- package/vendor/ars/shared/contracts/pdf/pdf_content_classifier_worker.schema.json +88 -0
- package/vendor/ars/shared/contracts/pdf/pdf_read_preflight.schema.json +227 -0
- package/vendor/ars/shared/contracts/re_review/input_manifest.schema.json +161 -0
- package/vendor/ars/shared/contracts/re_review/legacy/v1_0/input_manifest.schema.json +134 -0
- package/vendor/ars/shared/contracts/re_review/legacy/v1_0/precommitment.schema.json +193 -0
- package/vendor/ars/shared/contracts/re_review/legacy/v1_0/traceability.schema.json +841 -0
- package/vendor/ars/shared/contracts/re_review/legacy/v1_0/verdict_record.schema.json +244 -0
- package/vendor/ars/shared/contracts/re_review/precommitment.schema.json +193 -0
- package/vendor/ars/shared/contracts/re_review/traceability.schema.json +916 -0
- package/vendor/ars/shared/contracts/re_review/verdict_record.schema.json +245 -0
- package/vendor/ars/shared/contracts/research_workflow/inquiry_branch_ledger.schema.json +449 -0
- package/vendor/ars/shared/contracts/research_workflow/research_workflow_profile.schema.json +222 -0
- package/vendor/ars/shared/contracts/research_workflow/research_workflow_profile_selection_receipt.schema.json +111 -0
- package/vendor/ars/shared/contracts/review_target/constructive_review_findings.schema.json +172 -0
- package/vendor/ars/shared/contracts/review_target/criteria_registry.schema.json +97 -0
- package/vendor/ars/shared/contracts/review_target/review_criteria_binding_manifest.schema.json +235 -0
- package/vendor/ars/shared/contracts/review_target/review_criteria_source_receipt.schema.json +158 -0
- package/vendor/ars/shared/contracts/review_target/review_target_context.schema.json +106 -0
- package/vendor/ars/shared/contracts/review_target/review_target_declaration.schema.json +118 -0
- package/vendor/ars/shared/contracts/reviewer/full.json +114 -0
- package/vendor/ars/shared/contracts/reviewer/methodology_focus.json +75 -0
- package/vendor/ars/shared/contracts/reviewer/review_panel_provenance.schema.json +263 -0
- package/vendor/ars/shared/contracts/reviewer/review_panel_provenance_carrier.schema.json +122 -0
- package/vendor/ars/shared/contracts/reviewer/review_panel_provenance_input.schema.json +120 -0
- package/vendor/ars/shared/contracts/revision/author_adjudication.schema.json +251 -0
- package/vendor/ars/shared/contracts/revision/author_adjudication_input.schema.json +25 -0
- package/vendor/ars/shared/contracts/revision/claim_strength_drift_disposition.schema.json +97 -0
- package/vendor/ars/shared/contracts/revision/claim_strength_drift_disposition_input.schema.json +80 -0
- package/vendor/ars/shared/contracts/revision/claim_strength_drift_findings.schema.json +139 -0
- package/vendor/ars/shared/contracts/revision/claim_surface_manifest.schema.json +99 -0
- package/vendor/ars/shared/contracts/revision/integrity_correction_authorization.schema.json +140 -0
- package/vendor/ars/shared/contracts/revision/integrity_correction_authorization_input.schema.json +28 -0
- package/vendor/ars/shared/contracts/revision/integrity_correction_list.schema.json +48 -0
- package/vendor/ars/shared/contracts/revision/integrity_pass_receipt.schema.json +16 -0
- package/vendor/ars/shared/contracts/revision/revision_evidence_bundle.schema.json +134 -0
- package/vendor/ars/shared/contracts/revision/revision_roadmap.schema.json +334 -0
- package/vendor/ars/shared/contracts/submission/format_profile.example.yaml +33 -0
- package/vendor/ars/shared/contracts/submission/format_profile.schema.json +102 -0
- package/vendor/ars/shared/contracts/submission/submission_verification_report.schema.json +233 -0
- package/vendor/ars/shared/contracts/submission/venue_profile.schema.json +114 -0
- package/vendor/ars/shared/contracts/writer/full.json +87 -0
- package/vendor/ars/shared/cross_model_verification.md +714 -0
- package/vendor/ars/shared/evals_lift_report.schema.json +141 -0
- package/vendor/ars/shared/ground_truth_isolation_pattern.md +275 -0
- package/vendor/ars/shared/handoff_schemas.md +1209 -0
- package/vendor/ars/shared/human_subjects_authority_registry.json +1278 -0
- package/vendor/ars/shared/mode_spectrum.md +57 -0
- package/vendor/ars/shared/model_tiering.md +83 -0
- package/vendor/ars/shared/policy_data/nature_policy.md +56 -0
- package/vendor/ars/shared/prisma_trAIce_protocol.md +157 -0
- package/vendor/ars/shared/raise_framework.md +129 -0
- package/vendor/ars/shared/references/authority_content_coverage_advisory_protocol.md +275 -0
- package/vendor/ars/shared/references/claim_standing_candidate_ledger_protocol.md +66 -0
- package/vendor/ars/shared/references/claim_strength_ladder.md +93 -0
- package/vendor/ars/shared/references/cross_document_consistency_advisory_protocol.md +263 -0
- package/vendor/ars/shared/references/evidence_row_protocol.md +260 -0
- package/vendor/ars/shared/references/firm_rules.md +90 -0
- package/vendor/ars/shared/references/human_subjects_authority_protocol.md +274 -0
- package/vendor/ars/shared/references/intent_clarification_protocol.md +168 -0
- package/vendor/ars/shared/references/irb_terminology_glossary.md +229 -0
- package/vendor/ars/shared/references/protected_hedging_phrases.md +118 -0
- package/vendor/ars/shared/references/psychometric_terminology_glossary.md +109 -0
- package/vendor/ars/shared/references/review_criteria_consumer_protocol.md +238 -0
- package/vendor/ars/shared/references/review_pathway_rule_trace_protocol.md +166 -0
- package/vendor/ars/shared/references/submission_packet_manifest_protocol.md +292 -0
- package/vendor/ars/shared/references/word_count_conventions.md +124 -0
- package/vendor/ars/shared/research_workflow_profiles/field_general.json +1 -0
- package/vendor/ars/shared/review_criteria_registry.json +207 -0
- package/vendor/ars/shared/review_criteria_sources/msr-2027-technical-papers.2026-08-24.json +46 -0
- package/vendor/ars/shared/review_criteria_sources/sigsoft-empirical-standards.2026-08-24.json +31 -0
- package/vendor/ars/shared/sprint_contract.schema.json +482 -0
- package/vendor/ars/shared/style_calibration_protocol.md +151 -0
- package/vendor/ars/shared/templates/codex_audit_multifile_template.md +263 -0
- package/vendor/ars/tools/release-discipline/.toolkit-version +1 -0
- package/vendor/ars/tools/release-discipline/README.md +4 -0
- package/vendor/ars/tools/release-discipline/scripts/_release_doc_alignment_schema.py +1011 -0
- package/vendor/ars/tools/release-discipline/scripts/check_command_invariants.py +497 -0
- package/vendor/ars/tools/release-discipline/scripts/check_release_doc_alignment.py +263 -0
- package/vendor/ars/tools/release-discipline/scripts/sync-toolkit.sh +147 -0
- package/vendor/windows/NOTICE.md +12 -0
- package/vendor/windows/arm64/fd.exe +0 -0
- package/vendor/windows/arm64/licenses/fd/LICENSE-APACHE +201 -0
- package/vendor/windows/arm64/licenses/fd/LICENSE-MIT +21 -0
- package/vendor/windows/arm64/licenses/ripgrep/COPYING +3 -0
- package/vendor/windows/arm64/licenses/ripgrep/LICENSE-MIT +21 -0
- package/vendor/windows/arm64/licenses/ripgrep/UNLICENSE +24 -0
- package/vendor/windows/arm64/rg.exe +0 -0
- package/vendor/windows/x64/fd.exe +0 -0
- package/vendor/windows/x64/licenses/fd/LICENSE-APACHE +201 -0
- package/vendor/windows/x64/licenses/fd/LICENSE-MIT +21 -0
- package/vendor/windows/x64/licenses/ripgrep/COPYING +3 -0
- package/vendor/windows/x64/licenses/ripgrep/LICENSE-MIT +21 -0
- package/vendor/windows/x64/licenses/ripgrep/UNLICENSE +24 -0
- package/vendor/windows/x64/rg.exe +0 -0
|
@@ -0,0 +1,1592 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Deterministic, advisory-only cross-run adjudication activity recorder.
|
|
3
|
+
|
|
4
|
+
The runtime intentionally has no default paths, clock, network, model, judge,
|
|
5
|
+
directory scan, or environment-variable inputs. All authority comes from an
|
|
6
|
+
explicit terminal state, its sealed five-family inventory, and hash-bound
|
|
7
|
+
artifacts beneath an explicit artifact root.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import copy
|
|
14
|
+
import errno
|
|
15
|
+
import fcntl
|
|
16
|
+
import hashlib
|
|
17
|
+
import json
|
|
18
|
+
import os
|
|
19
|
+
import re
|
|
20
|
+
import stat
|
|
21
|
+
import sys
|
|
22
|
+
import tempfile
|
|
23
|
+
from contextlib import contextmanager
|
|
24
|
+
from pathlib import Path, PurePosixPath
|
|
25
|
+
from typing import Any, Iterator, Sequence
|
|
26
|
+
|
|
27
|
+
from jsonschema import Draft202012Validator, FormatChecker
|
|
28
|
+
from referencing import Registry, Resource
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
32
|
+
INPUT_SCHEMA_PATH = REPO_ROOT / "shared/contracts/activity/adjudication_activity_input.schema.json"
|
|
33
|
+
STORE_SCHEMA_PATH = REPO_ROOT / "shared/contracts/activity/adjudication_activity_store.schema.json"
|
|
34
|
+
COMPLIANCE_SCHEMA_PATH = REPO_ROOT / "shared/compliance_report.schema.json"
|
|
35
|
+
REVISION_CONTRACTS = REPO_ROOT / "shared/contracts/revision"
|
|
36
|
+
REREVIEW_CONTRACTS = REPO_ROOT / "shared/contracts/re_review"
|
|
37
|
+
|
|
38
|
+
INPUT_VERSION = "adjudication-activity-input/1.0"
|
|
39
|
+
STORE_VERSION = "adjudication-activity-store/1.0"
|
|
40
|
+
SOURCE_FAMILIES = (
|
|
41
|
+
"revision_author_adjudication",
|
|
42
|
+
"compliance_report",
|
|
43
|
+
"re_review_traceability",
|
|
44
|
+
"explicit_user_request",
|
|
45
|
+
"mandatory_checkpoint_response",
|
|
46
|
+
)
|
|
47
|
+
STAGES = (
|
|
48
|
+
"pipeline_stage_1", "pipeline_stage_2", "pipeline_stage_2_5",
|
|
49
|
+
"pipeline_stage_3", "pipeline_stage_3_prime", "pipeline_stage_4",
|
|
50
|
+
"pipeline_stage_4_prime", "pipeline_stage_4_5", "pipeline_stage_5",
|
|
51
|
+
"pipeline_stage_6",
|
|
52
|
+
)
|
|
53
|
+
RAW_TO_STAGE = {
|
|
54
|
+
"1": STAGES[0], "2": STAGES[1], "2.5": STAGES[2], "3": STAGES[3],
|
|
55
|
+
"3p": STAGES[4], "4": STAGES[5], "4p": STAGES[6], "4.5": STAGES[7],
|
|
56
|
+
"5": STAGES[8], "6": STAGES[9],
|
|
57
|
+
}
|
|
58
|
+
STAGE_TO_RAW = {value: key for key, value in RAW_TO_STAGE.items()}
|
|
59
|
+
STATUS_VALUES = {"pending", "in_progress", "completed", "skipped", "blocked"}
|
|
60
|
+
REASON_UNAVAILABLE = {
|
|
61
|
+
"source_not_provided", "source_unreadable", "source_invalid",
|
|
62
|
+
"capture_not_supported",
|
|
63
|
+
}
|
|
64
|
+
ROLE_ORDER = {
|
|
65
|
+
"revision_author_adjudication": ("author_adjudication_input", "author_adjudication"),
|
|
66
|
+
"compliance_report": ("compliance_report", "compliance_override_action_receipt"),
|
|
67
|
+
"re_review_traceability": ("input_manifest", "precommitment", "verdict_record", "traceability"),
|
|
68
|
+
"explicit_user_request": ("explicit_user_request_log",),
|
|
69
|
+
"mandatory_checkpoint_response": ("mandatory_checkpoint_response_log",),
|
|
70
|
+
}
|
|
71
|
+
OVERTURN_TYPES = {
|
|
72
|
+
"author_triage_not_on_point", "compliance_block_override",
|
|
73
|
+
"re_review_verdict_changed",
|
|
74
|
+
}
|
|
75
|
+
MAX_INPUT = 1 << 20
|
|
76
|
+
MAX_ARTIFACT = 8 << 20
|
|
77
|
+
MAX_ARTIFACT_TOTAL = 64 << 20
|
|
78
|
+
MAX_STORE = 16 << 20
|
|
79
|
+
MAX_EVENTS_RUN = 4096
|
|
80
|
+
MAX_EVENTS_STORE = 100000
|
|
81
|
+
MAX_RUNS = 10000
|
|
82
|
+
LIMITATION = "This records explicit adjudication activity only. It cannot determine correctness, attentiveness, engagement, or whether human ownership is real; genuine agreement and non-review can produce the same history."
|
|
83
|
+
ADVISORY = "This series is advisory only; it never gates, blocks, scores, or changes any verdict."
|
|
84
|
+
COVERAGE = "Coverage: only successfully retained records in this explicitly selected store are shown; runs without this store selection or whose append failed are not represented."
|
|
85
|
+
DATA_MINIMIZATION = {
|
|
86
|
+
"raw_prose_embedded": False,
|
|
87
|
+
"user_identity_embedded": False,
|
|
88
|
+
"absolute_paths_embedded": False,
|
|
89
|
+
}
|
|
90
|
+
HEX_RE = re.compile(r"^[0-9a-f]{64}$")
|
|
91
|
+
ID_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$")
|
|
92
|
+
GROUP_RE = re.compile(r"^SOURCE-GROUP-[A-Za-z0-9][A-Za-z0-9._-]{0,95}$")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class ActivityError(Exception):
|
|
96
|
+
"""Bounded public failure with a closed CLI error code."""
|
|
97
|
+
|
|
98
|
+
def __init__(self, code: str, detail: str):
|
|
99
|
+
super().__init__(detail)
|
|
100
|
+
self.code = code
|
|
101
|
+
self.detail = detail[:500]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
EXIT_BY_CODE = {
|
|
105
|
+
"USAGE": 2, "PATH": 3, "INPUT": 3, "SOURCE": 3, "STORE": 4,
|
|
106
|
+
"CONFLICT": 5, "CAP": 5, "DELETE_CONFIRMATION": 6,
|
|
107
|
+
"LOCK": 7, "WRITE": 7,
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _pairs(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
|
|
112
|
+
result: dict[str, Any] = {}
|
|
113
|
+
for key, value in pairs:
|
|
114
|
+
if key in result:
|
|
115
|
+
raise ValueError("duplicate object key")
|
|
116
|
+
result[key] = value
|
|
117
|
+
return result
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _reject_number(token: str) -> None:
|
|
121
|
+
raise ValueError(f"forbidden JSON number {token}")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def strict_json(raw: bytes, *, code: str) -> Any:
|
|
125
|
+
if raw.startswith(b"\xef\xbb\xbf"):
|
|
126
|
+
raise ActivityError(code, "UTF-8 BOM is forbidden")
|
|
127
|
+
try:
|
|
128
|
+
value = json.loads(
|
|
129
|
+
raw.decode("utf-8"), object_pairs_hook=_pairs,
|
|
130
|
+
parse_float=_reject_number, parse_constant=_reject_number,
|
|
131
|
+
)
|
|
132
|
+
except (UnicodeDecodeError, json.JSONDecodeError, ValueError) as exc:
|
|
133
|
+
raise ActivityError(code, f"invalid strict JSON: {exc.__class__.__name__}") from None
|
|
134
|
+
_canonical_domain(value, code=code)
|
|
135
|
+
return value
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _canonical_domain(value: Any, *, code: str, depth: int = 0) -> None:
|
|
139
|
+
if depth > 256:
|
|
140
|
+
raise ActivityError(code, "JSON nesting exceeds contract bound")
|
|
141
|
+
if isinstance(value, str):
|
|
142
|
+
if any(0xD800 <= ord(char) <= 0xDFFF for char in value):
|
|
143
|
+
raise ActivityError(code, "lone UTF-16 surrogate is forbidden")
|
|
144
|
+
return
|
|
145
|
+
if value is None or isinstance(value, bool):
|
|
146
|
+
return
|
|
147
|
+
if isinstance(value, int) and not isinstance(value, bool):
|
|
148
|
+
return
|
|
149
|
+
if isinstance(value, list):
|
|
150
|
+
for child in value:
|
|
151
|
+
_canonical_domain(child, code=code, depth=depth + 1)
|
|
152
|
+
return
|
|
153
|
+
if isinstance(value, dict):
|
|
154
|
+
for key, child in value.items():
|
|
155
|
+
if not isinstance(key, str) or not key.isascii():
|
|
156
|
+
raise ActivityError(code, "contract object keys must be ASCII")
|
|
157
|
+
_canonical_domain(child, code=code, depth=depth + 1)
|
|
158
|
+
return
|
|
159
|
+
raise ActivityError(code, "floats and non-contract JSON values are forbidden")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def canonical_bytes(value: Any, *, code: str = "INPUT") -> bytes:
|
|
163
|
+
_canonical_domain(value, code=code)
|
|
164
|
+
return json.dumps(
|
|
165
|
+
value, sort_keys=True, separators=(",", ":"), ensure_ascii=False,
|
|
166
|
+
allow_nan=False,
|
|
167
|
+
).encode("utf-8")
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _digest(domain: bytes, value: Any) -> str:
|
|
171
|
+
return hashlib.sha256(domain + canonical_bytes(value)).hexdigest()
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def interaction_sha256(run_id: str, interaction_id: str) -> str:
|
|
175
|
+
return _digest(
|
|
176
|
+
b"ars.adjudication-activity.interaction/1.0\0",
|
|
177
|
+
{"run_id": run_id, "interaction_id": interaction_id},
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _load_schema(path: Path) -> dict[str, Any]:
|
|
182
|
+
value = strict_json(path.read_bytes(), code="SOURCE")
|
|
183
|
+
if not isinstance(value, dict):
|
|
184
|
+
raise ActivityError("SOURCE", "schema root is not an object")
|
|
185
|
+
return value
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _validator(path: Path, *, revision_registry: bool = False) -> Draft202012Validator:
|
|
189
|
+
schema = _load_schema(path)
|
|
190
|
+
registry = Registry()
|
|
191
|
+
if revision_registry:
|
|
192
|
+
for candidate_path in (
|
|
193
|
+
REVISION_CONTRACTS / "author_adjudication.schema.json",
|
|
194
|
+
REVISION_CONTRACTS / "author_adjudication_input.schema.json",
|
|
195
|
+
):
|
|
196
|
+
candidate = _load_schema(candidate_path)
|
|
197
|
+
if "$id" in candidate:
|
|
198
|
+
registry = registry.with_resource(candidate["$id"], Resource.from_contents(candidate))
|
|
199
|
+
return Draft202012Validator(schema, registry=registry, format_checker=FormatChecker())
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _schema_validate(value: Any, path: Path, *, code: str, revision_registry: bool = False) -> None:
|
|
203
|
+
errors = sorted(
|
|
204
|
+
_validator(path, revision_registry=revision_registry).iter_errors(value),
|
|
205
|
+
key=lambda error: tuple(str(part) for part in error.absolute_path),
|
|
206
|
+
)
|
|
207
|
+
if errors:
|
|
208
|
+
raise ActivityError(code, f"schema validation failed at {list(errors[0].absolute_path)!r}")
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _read_limited_identity(path: Path, limit: int, *, code: str) -> tuple[bytes, tuple[int, int, int]]:
|
|
212
|
+
try:
|
|
213
|
+
fd = os.open(path, os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0))
|
|
214
|
+
try:
|
|
215
|
+
info = os.fstat(fd)
|
|
216
|
+
if not stat.S_ISREG(info.st_mode) or info.st_nlink != 1:
|
|
217
|
+
raise ActivityError("PATH", "selected path is not a single-linked regular file")
|
|
218
|
+
identity = (info.st_dev, info.st_ino, info.st_size)
|
|
219
|
+
if info.st_size > limit:
|
|
220
|
+
raise ActivityError("CAP", "file exceeds hard byte cap")
|
|
221
|
+
chunks: list[bytes] = []
|
|
222
|
+
size = 0
|
|
223
|
+
while True:
|
|
224
|
+
chunk = os.read(fd, min(1024 * 1024, limit + 1 - size))
|
|
225
|
+
if not chunk:
|
|
226
|
+
break
|
|
227
|
+
chunks.append(chunk)
|
|
228
|
+
size += len(chunk)
|
|
229
|
+
if size > limit:
|
|
230
|
+
raise ActivityError("CAP", "file exceeds hard byte cap")
|
|
231
|
+
after = os.fstat(fd)
|
|
232
|
+
if (after.st_dev, after.st_ino, after.st_size) != identity or size != info.st_size:
|
|
233
|
+
raise ActivityError(code, "file changed while being read")
|
|
234
|
+
return b"".join(chunks), identity
|
|
235
|
+
finally:
|
|
236
|
+
os.close(fd)
|
|
237
|
+
except ActivityError:
|
|
238
|
+
raise
|
|
239
|
+
except OSError as exc:
|
|
240
|
+
raise ActivityError(code, f"file read failed: {exc.__class__.__name__}") from None
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _read_limited(path: Path, limit: int, *, code: str) -> bytes:
|
|
244
|
+
return _read_limited_identity(path, limit, code=code)[0]
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _path_identity(path: Path) -> tuple[int, int, int]:
|
|
248
|
+
try:
|
|
249
|
+
info = path.lstat()
|
|
250
|
+
except OSError as exc:
|
|
251
|
+
raise ActivityError("WRITE", f"target identity check failed: {exc.__class__.__name__}") from None
|
|
252
|
+
return info.st_dev, info.st_ino, info.st_size
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def _assert_identity(path: Path, expected: tuple[int, int, int]) -> None:
|
|
256
|
+
if _path_identity(path) != expected:
|
|
257
|
+
raise ActivityError("CONFLICT", "target changed after validated read")
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def _relative_binding(root: Path, path: Path) -> str:
|
|
261
|
+
try:
|
|
262
|
+
root_real = root.resolve(strict=True)
|
|
263
|
+
path_real = path.resolve(strict=True)
|
|
264
|
+
relative = path_real.relative_to(root_real).as_posix()
|
|
265
|
+
except (OSError, ValueError):
|
|
266
|
+
raise ActivityError("PATH", "path is not contained beneath artifact root") from None
|
|
267
|
+
_safe_relative(root, relative)
|
|
268
|
+
return relative
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def _safe_relative(root: Path, relative: str) -> Path:
|
|
272
|
+
if not isinstance(relative, str) or not relative or len(relative) > 512:
|
|
273
|
+
raise ActivityError("PATH", "invalid relative artifact path")
|
|
274
|
+
pure = PurePosixPath(relative)
|
|
275
|
+
if pure.is_absolute() or "\\" in relative or relative.endswith("/"):
|
|
276
|
+
raise ActivityError("PATH", "unsafe relative artifact path")
|
|
277
|
+
if re.match(r"^[A-Za-z]:/", relative) or any(part in {"", ".", ".."} for part in pure.parts):
|
|
278
|
+
raise ActivityError("PATH", "unsafe relative artifact path")
|
|
279
|
+
if any(ord(char) < 32 or ord(char) == 127 for char in relative):
|
|
280
|
+
raise ActivityError("PATH", "unsafe relative artifact path")
|
|
281
|
+
try:
|
|
282
|
+
root_info = root.lstat()
|
|
283
|
+
if stat.S_ISLNK(root_info.st_mode) or not stat.S_ISDIR(root_info.st_mode):
|
|
284
|
+
raise ActivityError("PATH", "artifact root must be a non-symlink directory")
|
|
285
|
+
cursor = root
|
|
286
|
+
for part in pure.parts:
|
|
287
|
+
cursor = cursor / part
|
|
288
|
+
info = cursor.lstat()
|
|
289
|
+
if stat.S_ISLNK(info.st_mode):
|
|
290
|
+
raise ActivityError("PATH", "symlink artifact path is forbidden")
|
|
291
|
+
resolved = cursor.resolve(strict=True)
|
|
292
|
+
resolved.relative_to(root.resolve(strict=True))
|
|
293
|
+
if not stat.S_ISREG(cursor.stat().st_mode):
|
|
294
|
+
raise ActivityError("PATH", "artifact must be a regular file")
|
|
295
|
+
return cursor
|
|
296
|
+
except ActivityError:
|
|
297
|
+
raise
|
|
298
|
+
except (OSError, ValueError):
|
|
299
|
+
raise ActivityError("PATH", "artifact path cannot be safely resolved") from None
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _read_artifact_relative(root: Path, relative: str, limit: int) -> bytes:
|
|
303
|
+
"""Descriptor-relative no-follow traversal prevents parent-component swaps."""
|
|
304
|
+
if not isinstance(relative, str) or not relative or len(relative) > 512:
|
|
305
|
+
raise ActivityError("PATH", "invalid relative artifact path")
|
|
306
|
+
pure = PurePosixPath(relative)
|
|
307
|
+
if (
|
|
308
|
+
pure.is_absolute() or "\\" in relative or relative.endswith("/")
|
|
309
|
+
or re.match(r"^[A-Za-z]:/", relative)
|
|
310
|
+
or any(part in {"", ".", ".."} for part in pure.parts)
|
|
311
|
+
or any(ord(char) < 32 or ord(char) == 127 for char in relative)
|
|
312
|
+
):
|
|
313
|
+
raise ActivityError("PATH", "unsafe relative artifact path")
|
|
314
|
+
directory_flags = os.O_RDONLY | getattr(os, "O_DIRECTORY", 0) | getattr(os, "O_NOFOLLOW", 0)
|
|
315
|
+
opened: list[int] = []
|
|
316
|
+
try:
|
|
317
|
+
directory_fd = os.open(root, directory_flags)
|
|
318
|
+
opened.append(directory_fd)
|
|
319
|
+
for part in pure.parts[:-1]:
|
|
320
|
+
directory_fd = os.open(part, directory_flags, dir_fd=directory_fd)
|
|
321
|
+
opened.append(directory_fd)
|
|
322
|
+
fd = os.open(
|
|
323
|
+
pure.parts[-1], os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0),
|
|
324
|
+
dir_fd=directory_fd,
|
|
325
|
+
)
|
|
326
|
+
opened.append(fd)
|
|
327
|
+
info = os.fstat(fd)
|
|
328
|
+
identity = (info.st_dev, info.st_ino, info.st_size)
|
|
329
|
+
if not stat.S_ISREG(info.st_mode) or info.st_nlink != 1:
|
|
330
|
+
raise ActivityError("PATH", "artifact must be a single-linked regular file")
|
|
331
|
+
if info.st_size > limit:
|
|
332
|
+
raise ActivityError("CAP", "artifact exceeds hard byte cap")
|
|
333
|
+
chunks: list[bytes] = []
|
|
334
|
+
size = 0
|
|
335
|
+
while True:
|
|
336
|
+
chunk = os.read(fd, min(1024 * 1024, limit + 1 - size))
|
|
337
|
+
if not chunk:
|
|
338
|
+
break
|
|
339
|
+
chunks.append(chunk)
|
|
340
|
+
size += len(chunk)
|
|
341
|
+
if size > limit:
|
|
342
|
+
raise ActivityError("CAP", "artifact exceeds hard byte cap")
|
|
343
|
+
after = os.fstat(fd)
|
|
344
|
+
if (after.st_dev, after.st_ino, after.st_size) != identity or size != info.st_size:
|
|
345
|
+
raise ActivityError("SOURCE", "artifact changed while being read")
|
|
346
|
+
return b"".join(chunks)
|
|
347
|
+
except ActivityError:
|
|
348
|
+
raise
|
|
349
|
+
except OSError as exc:
|
|
350
|
+
if exc.errno == errno.ELOOP:
|
|
351
|
+
raise ActivityError("PATH", "symlink artifact path is forbidden") from None
|
|
352
|
+
raise ActivityError("PATH", f"artifact traversal failed: {exc.__class__.__name__}") from None
|
|
353
|
+
finally:
|
|
354
|
+
for opened_fd in reversed(opened):
|
|
355
|
+
os.close(opened_fd)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
@contextmanager
|
|
359
|
+
def _store_lock(path: Path, *, exclusive: bool) -> Iterator[None]:
|
|
360
|
+
lock_path = path.with_name(path.name + ".lock")
|
|
361
|
+
try:
|
|
362
|
+
fd = os.open(lock_path, os.O_RDWR | os.O_CREAT | getattr(os, "O_NOFOLLOW", 0), 0o600)
|
|
363
|
+
info = os.fstat(fd)
|
|
364
|
+
if not stat.S_ISREG(info.st_mode) or info.st_nlink != 1 or info.st_size != 0:
|
|
365
|
+
raise ActivityError("LOCK", "lock metadata is not an empty single-linked regular file")
|
|
366
|
+
operation = (fcntl.LOCK_EX if exclusive else fcntl.LOCK_SH) | fcntl.LOCK_NB
|
|
367
|
+
fcntl.flock(fd, operation)
|
|
368
|
+
except ActivityError:
|
|
369
|
+
if "fd" in locals():
|
|
370
|
+
os.close(fd)
|
|
371
|
+
raise
|
|
372
|
+
except OSError as exc:
|
|
373
|
+
if "fd" in locals():
|
|
374
|
+
os.close(fd)
|
|
375
|
+
raise ActivityError("LOCK", f"lock acquisition failed: {exc.__class__.__name__}") from None
|
|
376
|
+
try:
|
|
377
|
+
yield
|
|
378
|
+
finally:
|
|
379
|
+
fcntl.flock(fd, fcntl.LOCK_UN)
|
|
380
|
+
os.close(fd)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def _write_all(fd: int, raw: bytes) -> None:
|
|
384
|
+
view = memoryview(raw)
|
|
385
|
+
while view:
|
|
386
|
+
written = os.write(fd, view)
|
|
387
|
+
if written <= 0:
|
|
388
|
+
raise OSError("write made no progress")
|
|
389
|
+
view = view[written:]
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def _atomic_replace(path: Path, raw: bytes, *, expected_identity: tuple[int, int, int] | None = None) -> None:
|
|
393
|
+
path.parent.mkdir(parents=False, exist_ok=True)
|
|
394
|
+
temporary: str | None = None
|
|
395
|
+
try:
|
|
396
|
+
fd, temporary = tempfile.mkstemp(prefix=f".{path.name}.", dir=path.parent)
|
|
397
|
+
try:
|
|
398
|
+
os.fchmod(fd, 0o600)
|
|
399
|
+
_write_all(fd, raw)
|
|
400
|
+
os.fsync(fd)
|
|
401
|
+
finally:
|
|
402
|
+
os.close(fd)
|
|
403
|
+
if os.stat(temporary).st_size != len(raw):
|
|
404
|
+
raise OSError("temporary file size mismatch")
|
|
405
|
+
if expected_identity is not None:
|
|
406
|
+
_assert_identity(path, expected_identity)
|
|
407
|
+
os.replace(temporary, path)
|
|
408
|
+
temporary = None
|
|
409
|
+
directory_fd = os.open(path.parent, os.O_RDONLY)
|
|
410
|
+
try:
|
|
411
|
+
os.fsync(directory_fd)
|
|
412
|
+
finally:
|
|
413
|
+
os.close(directory_fd)
|
|
414
|
+
except OSError as exc:
|
|
415
|
+
raise ActivityError("WRITE", f"atomic write failed: {exc.__class__.__name__}") from None
|
|
416
|
+
finally:
|
|
417
|
+
if temporary is not None:
|
|
418
|
+
try:
|
|
419
|
+
os.unlink(temporary)
|
|
420
|
+
except OSError:
|
|
421
|
+
pass
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def _atomic_create(path: Path, raw: bytes) -> None:
|
|
425
|
+
if path.exists() or path.is_symlink():
|
|
426
|
+
raise ActivityError("CONFLICT", "output path already exists")
|
|
427
|
+
temporary: str | None = None
|
|
428
|
+
try:
|
|
429
|
+
fd, temporary = tempfile.mkstemp(prefix=f".{path.name}.", dir=path.parent)
|
|
430
|
+
try:
|
|
431
|
+
os.fchmod(fd, 0o600)
|
|
432
|
+
_write_all(fd, raw)
|
|
433
|
+
os.fsync(fd)
|
|
434
|
+
finally:
|
|
435
|
+
os.close(fd)
|
|
436
|
+
if os.stat(temporary).st_size != len(raw):
|
|
437
|
+
raise OSError("temporary file size mismatch")
|
|
438
|
+
os.link(temporary, path)
|
|
439
|
+
os.unlink(temporary)
|
|
440
|
+
temporary = None
|
|
441
|
+
directory_fd = os.open(path.parent, os.O_RDONLY)
|
|
442
|
+
try:
|
|
443
|
+
os.fsync(directory_fd)
|
|
444
|
+
finally:
|
|
445
|
+
os.close(directory_fd)
|
|
446
|
+
except FileExistsError:
|
|
447
|
+
raise ActivityError("CONFLICT", "output path already exists") from None
|
|
448
|
+
except OSError as exc:
|
|
449
|
+
raise ActivityError("WRITE", f"atomic create failed: {exc.__class__.__name__}") from None
|
|
450
|
+
finally:
|
|
451
|
+
if temporary:
|
|
452
|
+
try:
|
|
453
|
+
os.unlink(temporary)
|
|
454
|
+
except OSError:
|
|
455
|
+
pass
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def _state_replay(state: dict[str, Any]) -> tuple[str, str, str, str]:
|
|
459
|
+
if not isinstance(state, dict) or not ID_RE.fullmatch(str(state.get("run_id", ""))):
|
|
460
|
+
raise ActivityError("INPUT", "terminal state lacks a valid stable run_id")
|
|
461
|
+
pipeline_state = state.get("pipeline_state")
|
|
462
|
+
if pipeline_state not in {"completed", "aborted"}:
|
|
463
|
+
raise ActivityError("INPUT", "pipeline state is not eligible terminal state")
|
|
464
|
+
raw_stage = str(state.get("current_stage", ""))
|
|
465
|
+
stage = RAW_TO_STAGE.get(raw_stage)
|
|
466
|
+
stages = state.get("stages")
|
|
467
|
+
if stage is None or not isinstance(stages, dict) or not isinstance(stages.get(raw_stage), dict):
|
|
468
|
+
raise ActivityError("INPUT", "current stage cannot be strictly replayed")
|
|
469
|
+
status = stages[raw_stage].get("status")
|
|
470
|
+
if status not in STATUS_VALUES:
|
|
471
|
+
raise ActivityError("INPUT", "current stage status is outside the closed vocabulary")
|
|
472
|
+
if pipeline_state == "completed" and not (raw_stage == "6" and status in {"completed", "skipped"}):
|
|
473
|
+
raise ActivityError("INPUT", "completed state must replay Stage 6 completed or skipped")
|
|
474
|
+
return state["run_id"], pipeline_state, stage, status
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def _terminal_receipt(state: dict[str, Any], state_raw: bytes, relative_path: str) -> dict[str, Any]:
|
|
478
|
+
run_id, pipeline_state, stage, status = _state_replay(state)
|
|
479
|
+
return {
|
|
480
|
+
"artifact_id": "pipeline-state-terminal-receipt",
|
|
481
|
+
"relative_path": relative_path,
|
|
482
|
+
"sha256": hashlib.sha256(state_raw).hexdigest(),
|
|
483
|
+
"run_id": run_id,
|
|
484
|
+
"pipeline_state": pipeline_state,
|
|
485
|
+
"current_stage": stage,
|
|
486
|
+
"current_stage_status": status,
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def _validate_source_rows(rows: Any, *, pending: bool = False) -> None:
|
|
491
|
+
if not isinstance(rows, list) or len(rows) != 5:
|
|
492
|
+
raise ActivityError("SOURCE", "source inventory must contain exactly five rows")
|
|
493
|
+
for index, (row, family) in enumerate(zip(rows, SOURCE_FAMILIES)):
|
|
494
|
+
if not isinstance(row, dict) or row.get("source_family") != family:
|
|
495
|
+
raise ActivityError("SOURCE", f"source family order mismatch at row {index}")
|
|
496
|
+
if set(row) != {"source_family", "capture_state", "reason_code", "artifacts"}:
|
|
497
|
+
raise ActivityError("SOURCE", "source row has unknown or missing fields")
|
|
498
|
+
state = row.get("capture_state")
|
|
499
|
+
reason = row.get("reason_code")
|
|
500
|
+
artifacts = row.get("artifacts")
|
|
501
|
+
if not isinstance(artifacts, list) or len(artifacts) > 64:
|
|
502
|
+
raise ActivityError("SOURCE", "invalid source artifact list")
|
|
503
|
+
if state == "captured":
|
|
504
|
+
if reason is not None or not artifacts:
|
|
505
|
+
raise ActivityError("SOURCE", "captured source requires artifacts and null reason")
|
|
506
|
+
elif state == "not_applicable":
|
|
507
|
+
if reason != "not_applicable_for_run" or artifacts:
|
|
508
|
+
raise ActivityError("SOURCE", "not-applicable source shape is invalid")
|
|
509
|
+
elif state == "unavailable":
|
|
510
|
+
if reason not in REASON_UNAVAILABLE or artifacts:
|
|
511
|
+
raise ActivityError("SOURCE", "unavailable source shape is invalid")
|
|
512
|
+
else:
|
|
513
|
+
raise ActivityError("SOURCE", "unknown capture state")
|
|
514
|
+
for artifact in artifacts:
|
|
515
|
+
expected = {
|
|
516
|
+
"artifact_id", "artifact_role", "artifact_group_id",
|
|
517
|
+
"artifact_group_stage", "relative_path",
|
|
518
|
+
}
|
|
519
|
+
if not pending:
|
|
520
|
+
expected.add("sha256")
|
|
521
|
+
if not isinstance(artifact, dict) or set(artifact) != expected:
|
|
522
|
+
raise ActivityError("SOURCE", "artifact binding has unknown or missing fields")
|
|
523
|
+
if not isinstance(artifact.get("artifact_id"), str) or not ID_RE.fullmatch(artifact["artifact_id"]):
|
|
524
|
+
raise ActivityError("SOURCE", "artifact id is outside the closed identifier grammar")
|
|
525
|
+
if artifact.get("artifact_role") not in ROLE_ORDER[family]:
|
|
526
|
+
raise ActivityError("SOURCE", "artifact role is outside the source-family vocabulary")
|
|
527
|
+
if not isinstance(artifact.get("artifact_group_id"), str) or not GROUP_RE.fullmatch(artifact["artifact_group_id"]):
|
|
528
|
+
raise ActivityError("SOURCE", "artifact group id is invalid")
|
|
529
|
+
group_stage = artifact.get("artifact_group_stage")
|
|
530
|
+
if family == SOURCE_FAMILIES[0]:
|
|
531
|
+
if group_stage not in {"pipeline_stage_3", "pipeline_stage_3_prime"}:
|
|
532
|
+
raise ActivityError("SOURCE", "author artifact group stage is invalid")
|
|
533
|
+
elif group_stage is not None:
|
|
534
|
+
raise ActivityError("SOURCE", "non-author artifact group stage must be null")
|
|
535
|
+
relative_path = artifact.get("relative_path")
|
|
536
|
+
if not isinstance(relative_path, str):
|
|
537
|
+
raise ActivityError("SOURCE", "artifact relative path must be a string")
|
|
538
|
+
if not pending and (not isinstance(artifact.get("sha256"), str) or not HEX_RE.fullmatch(artifact["sha256"])):
|
|
539
|
+
raise ActivityError("SOURCE", "artifact hash is invalid")
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
def _group_artifacts(row: dict[str, Any]) -> list[list[dict[str, Any]]]:
|
|
543
|
+
family = row["source_family"]
|
|
544
|
+
artifacts = row["artifacts"]
|
|
545
|
+
groups: list[list[dict[str, Any]]] = []
|
|
546
|
+
seen_ids: set[str] = set()
|
|
547
|
+
cursor = 0
|
|
548
|
+
while cursor < len(artifacts):
|
|
549
|
+
group_id = artifacts[cursor].get("artifact_group_id")
|
|
550
|
+
if not isinstance(group_id, str) or not GROUP_RE.fullmatch(group_id) or group_id in seen_ids:
|
|
551
|
+
raise ActivityError("SOURCE", "invalid or repeated artifact group id")
|
|
552
|
+
seen_ids.add(group_id)
|
|
553
|
+
group: list[dict[str, Any]] = []
|
|
554
|
+
while cursor < len(artifacts) and artifacts[cursor].get("artifact_group_id") == group_id:
|
|
555
|
+
group.append(artifacts[cursor])
|
|
556
|
+
cursor += 1
|
|
557
|
+
groups.append(group)
|
|
558
|
+
if row["capture_state"] != "captured":
|
|
559
|
+
return groups
|
|
560
|
+
expected_roles = ROLE_ORDER[family]
|
|
561
|
+
if family == "revision_author_adjudication":
|
|
562
|
+
if len(groups) not in {1, 2}:
|
|
563
|
+
raise ActivityError("SOURCE", "author family requires one or two groups")
|
|
564
|
+
expected_stages = ["pipeline_stage_3", "pipeline_stage_3_prime"] if len(groups) == 2 else None
|
|
565
|
+
for index, group in enumerate(groups):
|
|
566
|
+
if tuple(item.get("artifact_role") for item in group) != expected_roles:
|
|
567
|
+
raise ActivityError("SOURCE", "author group role order is invalid")
|
|
568
|
+
stages = {item.get("artifact_group_stage") for item in group}
|
|
569
|
+
if len(stages) != 1 or next(iter(stages)) not in {"pipeline_stage_3", "pipeline_stage_3_prime"}:
|
|
570
|
+
raise ActivityError("SOURCE", "author group stage is invalid")
|
|
571
|
+
if expected_stages and next(iter(stages)) != expected_stages[index]:
|
|
572
|
+
raise ActivityError("SOURCE", "author group stage order is invalid")
|
|
573
|
+
elif family == "compliance_report":
|
|
574
|
+
if not 1 <= len(groups) <= 16:
|
|
575
|
+
raise ActivityError("SOURCE", "compliance family requires 1..16 groups")
|
|
576
|
+
for group in groups:
|
|
577
|
+
roles = tuple(item.get("artifact_role") for item in group)
|
|
578
|
+
if roles not in {(expected_roles[0],), expected_roles}:
|
|
579
|
+
raise ActivityError("SOURCE", "compliance group role set/order is invalid")
|
|
580
|
+
if any(item.get("artifact_group_stage") is not None for item in group):
|
|
581
|
+
raise ActivityError("SOURCE", "non-author artifact stage must be null")
|
|
582
|
+
else:
|
|
583
|
+
if len(groups) != 1 or tuple(item.get("artifact_role") for item in groups[0]) != expected_roles:
|
|
584
|
+
raise ActivityError("SOURCE", "captured family has invalid exact group roles")
|
|
585
|
+
if any(item.get("artifact_group_stage") is not None for item in groups[0]):
|
|
586
|
+
raise ActivityError("SOURCE", "non-author artifact stage must be null")
|
|
587
|
+
return groups
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
def seal_terminal_inventory(state_path: str | Path, artifact_root: str | Path, pending_bindings: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
591
|
+
"""Post-terminal best-effort helper: hash explicit pending rows and seal them.
|
|
592
|
+
|
|
593
|
+
``pending_bindings`` is authority supplied by the state tracker's sole
|
|
594
|
+
writer. It contains no hashes. This helper performs no discovery.
|
|
595
|
+
"""
|
|
596
|
+
state_file = Path(state_path)
|
|
597
|
+
root = Path(artifact_root)
|
|
598
|
+
_validate_source_rows(pending_bindings, pending=True)
|
|
599
|
+
with _store_lock(state_file, exclusive=True):
|
|
600
|
+
state_raw, state_identity = _read_limited_identity(state_file, MAX_STORE, code="INPUT")
|
|
601
|
+
state = strict_json(state_raw, code="INPUT")
|
|
602
|
+
_state_replay(state)
|
|
603
|
+
sealed_rows = copy.deepcopy(pending_bindings)
|
|
604
|
+
total = 0
|
|
605
|
+
for row in sealed_rows:
|
|
606
|
+
_group_artifacts(row)
|
|
607
|
+
for artifact in row["artifacts"]:
|
|
608
|
+
raw = _read_artifact_relative(root, artifact["relative_path"], MAX_ARTIFACT)
|
|
609
|
+
total += len(raw)
|
|
610
|
+
if total > MAX_ARTIFACT_TOTAL:
|
|
611
|
+
raise ActivityError("CAP", "referenced artifacts exceed per-run byte cap")
|
|
612
|
+
artifact["sha256"] = hashlib.sha256(raw).hexdigest()
|
|
613
|
+
_validate_source_rows(sealed_rows)
|
|
614
|
+
candidate = copy.deepcopy(state)
|
|
615
|
+
existing = candidate.get("adjudication_activity_sources")
|
|
616
|
+
if existing is not None and existing != sealed_rows:
|
|
617
|
+
raise ActivityError("CONFLICT", "terminal source inventory is already sealed differently")
|
|
618
|
+
if existing == sealed_rows:
|
|
619
|
+
return sealed_rows
|
|
620
|
+
candidate["adjudication_activity_sources"] = sealed_rows
|
|
621
|
+
_atomic_replace(
|
|
622
|
+
state_file, canonical_bytes(candidate) + b"\n",
|
|
623
|
+
expected_identity=state_identity,
|
|
624
|
+
)
|
|
625
|
+
return sealed_rows
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
def author_source_record(adjudication: dict[str, Any], event: dict[str, Any], digest: str) -> dict[str, Any]:
|
|
629
|
+
return {
|
|
630
|
+
"item_id": adjudication["item_id"],
|
|
631
|
+
"author_event_id": adjudication["author_event_id"],
|
|
632
|
+
"author_triage": adjudication["author_triage"],
|
|
633
|
+
"input_sha256": event["input_sha256"],
|
|
634
|
+
"interaction_sha256": digest,
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
def compliance_source_record(
|
|
639
|
+
group_id: str, stage: str, blockers: list[str], report_hash: str,
|
|
640
|
+
receipt_hash: str, receipt: dict[str, Any],
|
|
641
|
+
) -> dict[str, Any]:
|
|
642
|
+
return {
|
|
643
|
+
"artifact_group_id": group_id,
|
|
644
|
+
"stage": stage,
|
|
645
|
+
"blocking_contributor_ids": blockers,
|
|
646
|
+
"report_sha256": report_hash,
|
|
647
|
+
"action_receipt_sha256": receipt_hash,
|
|
648
|
+
"interaction_id": receipt["interaction_id"],
|
|
649
|
+
"interaction_sha256": receipt["interaction_sha256"],
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
def re_review_source_record(
|
|
654
|
+
round_id: str, dissent_id: str, item_id: str, reapplication_id: str,
|
|
655
|
+
adjustment: dict[str, Any], traceability_hash: str,
|
|
656
|
+
) -> dict[str, Any]:
|
|
657
|
+
return {
|
|
658
|
+
"round_id": round_id,
|
|
659
|
+
"dissent_id": dissent_id,
|
|
660
|
+
"item_id": item_id,
|
|
661
|
+
"reapplication_id": reapplication_id,
|
|
662
|
+
"adjustment_id": adjustment["adjustment_id"],
|
|
663
|
+
"from_verdict": adjustment["from_verdict"],
|
|
664
|
+
"to_verdict": adjustment["to_verdict"],
|
|
665
|
+
"traceability_sha256": traceability_hash,
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
def explicit_source_record(record: dict[str, Any]) -> dict[str, Any]:
|
|
670
|
+
return {key: record[key] for key in (
|
|
671
|
+
"request_id", "actor_role", "source", "action", "stage", "finding_id",
|
|
672
|
+
"interaction_id", "interaction_sha256",
|
|
673
|
+
)}
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
def mandatory_source_record(record: dict[str, Any]) -> dict[str, Any]:
|
|
677
|
+
return {key: record[key] for key in (
|
|
678
|
+
"response_id", "checkpoint_id", "checkpoint_type", "actor_role", "source",
|
|
679
|
+
"stage", "disposition", "interaction_id", "interaction_sha256",
|
|
680
|
+
)}
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
def _event(
|
|
684
|
+
run_id: str, family: str, event_type: str, stage: str, disposition: str,
|
|
685
|
+
interaction: str | None, source_record: dict[str, Any],
|
|
686
|
+
) -> dict[str, Any]:
|
|
687
|
+
source_hash = _digest(
|
|
688
|
+
b"ars.adjudication-activity.source-event/1.0\0",
|
|
689
|
+
{"source_family": family, "source_record": source_record},
|
|
690
|
+
)
|
|
691
|
+
payload = {
|
|
692
|
+
"run_id": run_id, "source_family": family, "event_type": event_type,
|
|
693
|
+
"stage": stage, "disposition": disposition,
|
|
694
|
+
"interaction_sha256": interaction, "source_event_sha256": source_hash,
|
|
695
|
+
}
|
|
696
|
+
return {
|
|
697
|
+
"event_id": "ACTIVITY-EVENT-" + _digest(b"ars.adjudication-activity.event-id/1.0\0", payload),
|
|
698
|
+
"event_type": event_type, "stage": stage, "disposition": disposition,
|
|
699
|
+
"interaction_sha256": interaction, "source_event_sha256": source_hash,
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
def _load_artifact(root: Path, binding: dict[str, Any], total: list[int]) -> tuple[dict[str, Any], bytes]:
|
|
704
|
+
raw = _read_artifact_relative(root, binding["relative_path"], MAX_ARTIFACT)
|
|
705
|
+
total[0] += len(raw)
|
|
706
|
+
if total[0] > MAX_ARTIFACT_TOTAL:
|
|
707
|
+
raise ActivityError("CAP", "referenced artifacts exceed per-run byte cap")
|
|
708
|
+
if hashlib.sha256(raw).hexdigest() != binding["sha256"]:
|
|
709
|
+
raise ActivityError("SOURCE", "artifact raw-byte hash mismatch")
|
|
710
|
+
value = strict_json(raw, code="SOURCE")
|
|
711
|
+
if not isinstance(value, dict):
|
|
712
|
+
raise ActivityError("SOURCE", "source artifact root must be an object")
|
|
713
|
+
return value, raw
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
def _author_events(run_id: str, stage: str, group: list[dict[str, Any]], root: Path, total: list[int]) -> list[dict[str, Any]]:
|
|
717
|
+
input_value, _ = _load_artifact(root, group[0], total)
|
|
718
|
+
output_value, _ = _load_artifact(root, group[1], total)
|
|
719
|
+
_schema_validate(input_value, REVISION_CONTRACTS / "author_adjudication_input.schema.json", code="SOURCE", revision_registry=True)
|
|
720
|
+
_schema_validate(output_value, REVISION_CONTRACTS / "author_adjudication.schema.json", code="SOURCE", revision_registry=True)
|
|
721
|
+
projection_keys = ("author_events", "author_adjudications", "display_order", "collateral_authorizations")
|
|
722
|
+
if any(input_value[key] != output_value[key] for key in projection_keys):
|
|
723
|
+
raise ActivityError("SOURCE", "author input/output projection mismatch")
|
|
724
|
+
event_by_id: dict[str, dict[str, Any]] = {}
|
|
725
|
+
for source_event in output_value["author_events"]:
|
|
726
|
+
event_id = source_event["event_id"]
|
|
727
|
+
if event_id in event_by_id:
|
|
728
|
+
raise ActivityError("SOURCE", "duplicate author event id")
|
|
729
|
+
event_by_id[event_id] = source_event
|
|
730
|
+
derived: list[dict[str, Any]] = []
|
|
731
|
+
for adjudication in output_value["author_adjudications"]:
|
|
732
|
+
event_id = adjudication["author_event_id"]
|
|
733
|
+
if event_id not in event_by_id:
|
|
734
|
+
raise ActivityError("SOURCE", "author adjudication event id is unresolved")
|
|
735
|
+
triage = adjudication["author_triage"]
|
|
736
|
+
if triage == "will_address":
|
|
737
|
+
continue
|
|
738
|
+
digest = interaction_sha256(run_id, event_id)
|
|
739
|
+
event_type, disposition = (
|
|
740
|
+
("author_triage_wont_address", "wont_address") if triage == "wont_address"
|
|
741
|
+
else ("author_triage_not_on_point", "not_on_point")
|
|
742
|
+
)
|
|
743
|
+
derived.append(_event(
|
|
744
|
+
run_id, SOURCE_FAMILIES[0], event_type, stage, disposition, digest,
|
|
745
|
+
author_source_record(adjudication, event_by_id[event_id], digest),
|
|
746
|
+
))
|
|
747
|
+
return derived
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
def _receipt_shape(value: dict[str, Any], keys: set[str], version: str) -> None:
|
|
751
|
+
if set(value) != keys or value.get("schema_version") != version:
|
|
752
|
+
raise ActivityError("SOURCE", "closed action receipt shape/version is invalid")
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
def _blocking_contributors(report: dict[str, Any]) -> list[str]:
|
|
756
|
+
if report.get("mode") != "systematic_review":
|
|
757
|
+
return []
|
|
758
|
+
result: set[str] = set()
|
|
759
|
+
prisma = report.get("prisma_trAIce")
|
|
760
|
+
if isinstance(prisma, dict) and prisma.get("block_decision") == "block":
|
|
761
|
+
failed = prisma["by_tier"]["mandatory"]["fail"]
|
|
762
|
+
if len(failed) != len(set(failed)):
|
|
763
|
+
raise ActivityError("SOURCE", "PRISMA blocking contributor ids must be unique")
|
|
764
|
+
result.update(failed)
|
|
765
|
+
raise_part = report.get("raise")
|
|
766
|
+
if isinstance(raise_part, dict) and raise_part.get("block_decision") == "block":
|
|
767
|
+
result.update(name for name, status_value in raise_part["principles"].items() if status_value == "fail")
|
|
768
|
+
return sorted(result)
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
def _compliance_events(run_id: str, groups: list[list[dict[str, Any]]], root: Path, total: list[int]) -> list[dict[str, Any]]:
|
|
772
|
+
derived: list[dict[str, Any]] = []
|
|
773
|
+
expected_ordinal = {"pipeline_stage_2_5": 1, "pipeline_stage_4_5": 1}
|
|
774
|
+
receipt_ids: set[str] = set()
|
|
775
|
+
receipt_keys = {
|
|
776
|
+
"schema_version", "receipt_id", "run_id", "actor_role", "source", "action",
|
|
777
|
+
"stage", "scope", "report_sha256", "override_ordinal", "interaction_id",
|
|
778
|
+
"interaction_sha256",
|
|
779
|
+
}
|
|
780
|
+
for group in groups:
|
|
781
|
+
report, _ = _load_artifact(root, group[0], total)
|
|
782
|
+
_schema_validate(report, COMPLIANCE_SCHEMA_PATH, code="SOURCE")
|
|
783
|
+
has_override = "user_override" in report
|
|
784
|
+
if not has_override and len(group) == 1:
|
|
785
|
+
continue
|
|
786
|
+
if not has_override or len(group) != 2:
|
|
787
|
+
raise ActivityError("SOURCE", "compliance action receipt pairing is invalid")
|
|
788
|
+
receipt, _ = _load_artifact(root, group[1], total)
|
|
789
|
+
_receipt_shape(receipt, receipt_keys, "adjudication-compliance-override-action/1.0")
|
|
790
|
+
receipt_id = receipt.get("receipt_id")
|
|
791
|
+
interaction_id = receipt.get("interaction_id")
|
|
792
|
+
scope = receipt.get("scope")
|
|
793
|
+
ordinal = receipt.get("override_ordinal")
|
|
794
|
+
if (
|
|
795
|
+
not isinstance(receipt_id, str) or not ID_RE.fullmatch(receipt_id)
|
|
796
|
+
or not isinstance(interaction_id, str) or not ID_RE.fullmatch(interaction_id)
|
|
797
|
+
or not isinstance(scope, list) or not scope
|
|
798
|
+
or any(not isinstance(item, str) or not ID_RE.fullmatch(item) for item in scope)
|
|
799
|
+
or len(scope) != len(set(scope))
|
|
800
|
+
or not isinstance(ordinal, int) or isinstance(ordinal, bool) or ordinal < 1
|
|
801
|
+
or not isinstance(receipt.get("report_sha256"), str)
|
|
802
|
+
or not HEX_RE.fullmatch(receipt["report_sha256"])
|
|
803
|
+
or not isinstance(receipt.get("interaction_sha256"), str)
|
|
804
|
+
or not HEX_RE.fullmatch(receipt["interaction_sha256"])
|
|
805
|
+
):
|
|
806
|
+
raise ActivityError("SOURCE", "compliance action receipt field types are invalid")
|
|
807
|
+
blockers = _blocking_contributors(report)
|
|
808
|
+
report_stage = {"2.5": "pipeline_stage_2_5", "4.5": "pipeline_stage_4_5"}.get(report.get("stage"))
|
|
809
|
+
override = report["user_override"]
|
|
810
|
+
valid = (
|
|
811
|
+
report.get("overall_decision") == "block"
|
|
812
|
+
and report.get("user_action_required") is True
|
|
813
|
+
and bool(blockers)
|
|
814
|
+
and override.get("decision") is True
|
|
815
|
+
and report_stage == receipt.get("stage")
|
|
816
|
+
and receipt.get("run_id") == run_id
|
|
817
|
+
and receipt.get("actor_role") == "user"
|
|
818
|
+
and receipt.get("source") == "explicit_session_user_action"
|
|
819
|
+
and receipt.get("action") == "acknowledge_compliance_limitation"
|
|
820
|
+
and receipt.get("report_sha256") == group[0]["sha256"]
|
|
821
|
+
)
|
|
822
|
+
scopes = (override.get("scope"), receipt.get("scope"))
|
|
823
|
+
for candidate_scope in scopes:
|
|
824
|
+
if (
|
|
825
|
+
not isinstance(candidate_scope, list)
|
|
826
|
+
or any(not isinstance(item, str) for item in candidate_scope)
|
|
827
|
+
or len(candidate_scope) != len(set(candidate_scope))
|
|
828
|
+
or set(candidate_scope) != set(blockers)
|
|
829
|
+
):
|
|
830
|
+
valid = False
|
|
831
|
+
stage = receipt.get("stage")
|
|
832
|
+
if stage not in expected_ordinal or ordinal != expected_ordinal.get(stage):
|
|
833
|
+
valid = False
|
|
834
|
+
else:
|
|
835
|
+
expected_ordinal[stage] += 1
|
|
836
|
+
rationale = override.get("rationale")
|
|
837
|
+
if ordinal == 2 and (not isinstance(rationale, str) or not rationale):
|
|
838
|
+
valid = False
|
|
839
|
+
if isinstance(ordinal, int) and ordinal >= 3 and (not isinstance(rationale, str) or len(rationale) < 100):
|
|
840
|
+
valid = False
|
|
841
|
+
if receipt_id in receipt_ids:
|
|
842
|
+
valid = False
|
|
843
|
+
else:
|
|
844
|
+
receipt_ids.add(receipt_id)
|
|
845
|
+
expected_digest = interaction_sha256(run_id, interaction_id)
|
|
846
|
+
if receipt.get("interaction_sha256") != expected_digest:
|
|
847
|
+
valid = False
|
|
848
|
+
if not valid:
|
|
849
|
+
raise ActivityError("SOURCE", "qualifying compliance override replay failed")
|
|
850
|
+
source = compliance_source_record(
|
|
851
|
+
group[0]["artifact_group_id"], stage, blockers, group[0]["sha256"],
|
|
852
|
+
group[1]["sha256"], receipt,
|
|
853
|
+
)
|
|
854
|
+
derived.append(_event(
|
|
855
|
+
run_id, SOURCE_FAMILIES[1], "compliance_block_override", stage,
|
|
856
|
+
"block_overridden", expected_digest, source,
|
|
857
|
+
))
|
|
858
|
+
return derived
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
def _rereview_events(run_id: str, group: list[dict[str, Any]], root: Path, total: list[int]) -> list[dict[str, Any]]:
|
|
862
|
+
names = ("input_manifest", "precommitment", "verdict_record", "traceability")
|
|
863
|
+
values: dict[str, dict[str, Any]] = {}
|
|
864
|
+
for name, binding in zip(names, group):
|
|
865
|
+
value, _ = _load_artifact(root, binding, total)
|
|
866
|
+
_schema_validate(value, REREVIEW_CONTRACTS / f"{name}.schema.json", code="SOURCE")
|
|
867
|
+
values[name] = value
|
|
868
|
+
round_ids = {values[name].get("round_id") for name in names}
|
|
869
|
+
if len(round_ids) != 1:
|
|
870
|
+
raise ActivityError("SOURCE", "re-review round ids do not agree")
|
|
871
|
+
if values["precommitment"].get("input_manifest_hash") != hashlib.sha256(canonical_bytes(values["input_manifest"])).hexdigest():
|
|
872
|
+
raise ActivityError("SOURCE", "re-review input/precommitment hash chain mismatch")
|
|
873
|
+
if values["verdict_record"].get("precommitment_hash") != hashlib.sha256(canonical_bytes(values["precommitment"])).hexdigest():
|
|
874
|
+
raise ActivityError("SOURCE", "re-review precommitment/verdict hash chain mismatch")
|
|
875
|
+
if values["traceability"].get("verdict_record_hash") != hashlib.sha256(canonical_bytes(values["verdict_record"])).hexdigest():
|
|
876
|
+
raise ActivityError("SOURCE", "re-review verdict/traceability hash chain mismatch")
|
|
877
|
+
verdict = values["verdict_record"]
|
|
878
|
+
trace = values["traceability"]
|
|
879
|
+
dissent_item: dict[str, str] = {}
|
|
880
|
+
for dissent in verdict["dissents"]:
|
|
881
|
+
if dissent["dissent_id"] in dissent_item:
|
|
882
|
+
raise ActivityError("SOURCE", "duplicate re-review dissent id")
|
|
883
|
+
dissent_item[dissent["dissent_id"]] = dissent["item_id"]
|
|
884
|
+
adjudications_by_id: dict[str, dict[str, Any]] = {}
|
|
885
|
+
for item in trace["dissent_adjudications"]:
|
|
886
|
+
if item["dissent_id"] in adjudications_by_id:
|
|
887
|
+
raise ActivityError("SOURCE", "duplicate dissent adjudication id")
|
|
888
|
+
adjudications_by_id[item["dissent_id"]] = item
|
|
889
|
+
qualifying_dissents = {
|
|
890
|
+
dissent_id: item for dissent_id, item in adjudications_by_id.items()
|
|
891
|
+
if item["adjudicator"] == "user" and item["outcome"] == "original_upheld"
|
|
892
|
+
}
|
|
893
|
+
reapp_by_id: dict[str, dict[str, Any]] = {}
|
|
894
|
+
for item in trace["reapplications"]:
|
|
895
|
+
if item["reapplication_id"] in reapp_by_id:
|
|
896
|
+
raise ActivityError("SOURCE", "duplicate reapplication id")
|
|
897
|
+
reapp_by_id[item["reapplication_id"]] = item
|
|
898
|
+
superseded_by: dict[str, str] = {}
|
|
899
|
+
for item in trace["reapplications"]:
|
|
900
|
+
previous = item.get("supersedes_reapplication_id")
|
|
901
|
+
if previous is not None:
|
|
902
|
+
previous_item = reapp_by_id.get(previous)
|
|
903
|
+
if previous_item is None or previous_item["item_id"] != item["item_id"] or previous in superseded_by:
|
|
904
|
+
raise ActivityError("SOURCE", "invalid reapplication supersession")
|
|
905
|
+
superseded_by[previous] = item["reapplication_id"]
|
|
906
|
+
for item in trace["reapplications"]:
|
|
907
|
+
seen: set[str] = set()
|
|
908
|
+
cursor: dict[str, Any] | None = item
|
|
909
|
+
while cursor is not None:
|
|
910
|
+
cursor_id = cursor["reapplication_id"]
|
|
911
|
+
if cursor_id in seen:
|
|
912
|
+
raise ActivityError("SOURCE", "reapplication supersession cycle")
|
|
913
|
+
seen.add(cursor_id)
|
|
914
|
+
previous = cursor.get("supersedes_reapplication_id")
|
|
915
|
+
cursor = reapp_by_id.get(previous) if previous is not None else None
|
|
916
|
+
current_reapps = [item for item in trace["reapplications"] if item["reapplication_id"] not in superseded_by]
|
|
917
|
+
for reapp in trace["reapplications"]:
|
|
918
|
+
for answer_ref in reapp["answer_refs"]:
|
|
919
|
+
if answer_ref.startswith("adjudication:"):
|
|
920
|
+
dissent_id = answer_ref.split(":", 1)[1]
|
|
921
|
+
adjudication = adjudications_by_id.get(dissent_id)
|
|
922
|
+
if (
|
|
923
|
+
adjudication is None
|
|
924
|
+
or adjudication["outcome"] != "original_upheld"
|
|
925
|
+
or dissent_item.get(dissent_id) != reapp["item_id"]
|
|
926
|
+
):
|
|
927
|
+
raise ActivityError("SOURCE", "reapplication adjudication ref is unresolved or cross-item")
|
|
928
|
+
for dissent_id, adjudication in adjudications_by_id.items():
|
|
929
|
+
if adjudication["outcome"] == "original_upheld":
|
|
930
|
+
holders = [
|
|
931
|
+
reapp for reapp in current_reapps
|
|
932
|
+
if f"adjudication:{dissent_id}" in reapp["answer_refs"]
|
|
933
|
+
]
|
|
934
|
+
if len(holders) != 1:
|
|
935
|
+
raise ActivityError("SOURCE", "original-upheld dissent requires exactly one current reapplication")
|
|
936
|
+
if (
|
|
937
|
+
holders[0]["reapplied_verdict"] == "CANNOT_VERIFY"
|
|
938
|
+
or holders[0]["reapplied_verdict"] == holders[0]["pre_reapplication_verdict"]
|
|
939
|
+
):
|
|
940
|
+
raise ActivityError("SOURCE", "original-upheld current reapplication must prove a verdict change")
|
|
941
|
+
adjustments_by_item: dict[str, list[dict[str, Any]]] = {}
|
|
942
|
+
global_adjustment_ids: set[str] = set()
|
|
943
|
+
for adjustment in trace["adjustments"]:
|
|
944
|
+
if adjustment["adjustment_id"] in global_adjustment_ids:
|
|
945
|
+
raise ActivityError("SOURCE", "duplicate adjustment id")
|
|
946
|
+
global_adjustment_ids.add(adjustment["adjustment_id"])
|
|
947
|
+
adjustments_by_item.setdefault(adjustment["item_id"], []).append(adjustment)
|
|
948
|
+
row_by_item: dict[str, dict[str, Any]] = {}
|
|
949
|
+
for row in trace["rows"]:
|
|
950
|
+
if row["item_id"] in row_by_item:
|
|
951
|
+
raise ActivityError("SOURCE", "duplicate traceability row item id")
|
|
952
|
+
row_by_item[row["item_id"]] = row
|
|
953
|
+
adjustments_by_source: dict[str, list[dict[str, Any]]] = {}
|
|
954
|
+
for adjustment in trace["adjustments"]:
|
|
955
|
+
source_ref = adjustment.get("source_ref")
|
|
956
|
+
if source_ref is not None:
|
|
957
|
+
if source_ref.startswith("reapplication:") and source_ref.split(":", 1)[1] not in reapp_by_id:
|
|
958
|
+
raise ActivityError("SOURCE", "adjustment source_ref names an unknown reapplication")
|
|
959
|
+
adjustments_by_source.setdefault(source_ref, []).append(adjustment)
|
|
960
|
+
for reapp in trace["reapplications"]:
|
|
961
|
+
derived = adjustments_by_source.get(f"reapplication:{reapp['reapplication_id']}", [])
|
|
962
|
+
changing = (
|
|
963
|
+
reapp["reapplied_verdict"] != "CANNOT_VERIFY"
|
|
964
|
+
and reapp["reapplied_verdict"] != reapp["pre_reapplication_verdict"]
|
|
965
|
+
)
|
|
966
|
+
if not changing:
|
|
967
|
+
if derived:
|
|
968
|
+
raise ActivityError("SOURCE", "non-changing/CANNOT reapplication has a derived adjustment")
|
|
969
|
+
continue
|
|
970
|
+
if len(derived) != 1:
|
|
971
|
+
raise ActivityError("SOURCE", "verdict-changing reapplication requires exactly one derived adjustment")
|
|
972
|
+
adjustment = derived[0]
|
|
973
|
+
if (
|
|
974
|
+
adjustment["item_id"] != reapp["item_id"]
|
|
975
|
+
or adjustment["basis"] != "cross_model_adjudication"
|
|
976
|
+
or adjustment["from_verdict"] != reapp["pre_reapplication_verdict"]
|
|
977
|
+
or adjustment["to_verdict"] != reapp["reapplied_verdict"]
|
|
978
|
+
or adjustment["rationale"] != reapp["rationale"]
|
|
979
|
+
or adjustment.get("residual_gap") != reapp.get("residual_gap")
|
|
980
|
+
or adjustment.get("evidence_anchor") != reapp.get("evidence_anchor")
|
|
981
|
+
):
|
|
982
|
+
raise ActivityError("SOURCE", "derived adjustment does not mirror its reapplication")
|
|
983
|
+
candidates: list[tuple[int, dict[str, Any], str, str]] = []
|
|
984
|
+
counted_adjustments: set[str] = set()
|
|
985
|
+
for dissent_id in qualifying_dissents:
|
|
986
|
+
item_id = dissent_item.get(dissent_id)
|
|
987
|
+
if item_id is None:
|
|
988
|
+
raise ActivityError("SOURCE", "adjudicated dissent does not resolve to verdict dissent")
|
|
989
|
+
reapps = [item for item in current_reapps if item["item_id"] == item_id and f"adjudication:{dissent_id}" in item["answer_refs"]]
|
|
990
|
+
if len(reapps) != 1:
|
|
991
|
+
raise ActivityError("SOURCE", "dissent must resolve to one current reapplication")
|
|
992
|
+
if (
|
|
993
|
+
reapps[0]["reapplied_verdict"] == "CANNOT_VERIFY"
|
|
994
|
+
or reapps[0]["reapplied_verdict"] == reapps[0]["pre_reapplication_verdict"]
|
|
995
|
+
):
|
|
996
|
+
raise ActivityError("SOURCE", "original-upheld current reapplication must prove a verdict change")
|
|
997
|
+
records = adjustments_by_item.get(item_id, [])
|
|
998
|
+
by_id = {item["adjustment_id"]: item for item in records}
|
|
999
|
+
if len(by_id) != len(records):
|
|
1000
|
+
raise ActivityError("SOURCE", "duplicate adjustment id")
|
|
1001
|
+
followers: dict[str, dict[str, Any]] = {}
|
|
1002
|
+
heads: list[dict[str, Any]] = []
|
|
1003
|
+
for adjustment in records:
|
|
1004
|
+
previous = adjustment.get("supersedes_adjustment_id")
|
|
1005
|
+
if previous is None:
|
|
1006
|
+
heads.append(adjustment)
|
|
1007
|
+
elif previous not in by_id or previous in followers:
|
|
1008
|
+
raise ActivityError("SOURCE", "forked or orphan adjustment chain")
|
|
1009
|
+
else:
|
|
1010
|
+
followers[previous] = adjustment
|
|
1011
|
+
if len(heads) != 1:
|
|
1012
|
+
raise ActivityError("SOURCE", "adjustment chain must have exactly one head")
|
|
1013
|
+
chain = [heads[0]]
|
|
1014
|
+
while chain[-1]["adjustment_id"] in followers:
|
|
1015
|
+
next_item = followers[chain[-1]["adjustment_id"]]
|
|
1016
|
+
if next_item["from_verdict"] != chain[-1]["to_verdict"]:
|
|
1017
|
+
raise ActivityError("SOURCE", "adjustment chain verdict join mismatch")
|
|
1018
|
+
chain.append(next_item)
|
|
1019
|
+
if len(chain) != len(records):
|
|
1020
|
+
raise ActivityError("SOURCE", "adjustment chain contains a cycle or disconnected record")
|
|
1021
|
+
row = row_by_item.get(item_id)
|
|
1022
|
+
if not row or row.get("adjustment_id") != chain[-1]["adjustment_id"] or row.get("final_verdict") != chain[-1]["to_verdict"]:
|
|
1023
|
+
raise ActivityError("SOURCE", "final row does not bind adjustment chain tail")
|
|
1024
|
+
reapp = reapps[0]
|
|
1025
|
+
for adjustment in chain:
|
|
1026
|
+
if (
|
|
1027
|
+
adjustment["basis"] == "cross_model_adjudication"
|
|
1028
|
+
and adjustment.get("source_ref") == f"reapplication:{reapp['reapplication_id']}"
|
|
1029
|
+
and adjustment["from_verdict"] != adjustment["to_verdict"]
|
|
1030
|
+
):
|
|
1031
|
+
if adjustment["adjustment_id"] in counted_adjustments:
|
|
1032
|
+
raise ActivityError("SOURCE", "one adjustment cannot produce multiple activity events")
|
|
1033
|
+
counted_adjustments.add(adjustment["adjustment_id"])
|
|
1034
|
+
numeric = int(adjustment["adjustment_id"].split("-", 1)[1])
|
|
1035
|
+
candidates.append((numeric, adjustment, dissent_id, reapp["reapplication_id"]))
|
|
1036
|
+
trace_hash = group[3]["sha256"]
|
|
1037
|
+
return [
|
|
1038
|
+
_event(
|
|
1039
|
+
run_id, SOURCE_FAMILIES[2], "re_review_verdict_changed",
|
|
1040
|
+
"pipeline_stage_3_prime", "verdict_changed", None,
|
|
1041
|
+
re_review_source_record(
|
|
1042
|
+
values["input_manifest"]["round_id"], dissent_id,
|
|
1043
|
+
adjustment["item_id"], reapplication_id, adjustment, trace_hash,
|
|
1044
|
+
),
|
|
1045
|
+
)
|
|
1046
|
+
for _, adjustment, dissent_id, reapplication_id in sorted(candidates, key=lambda item: item[0])
|
|
1047
|
+
]
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
def _validate_action_log(value: dict[str, Any], *, run_id: str, mandatory: bool) -> list[dict[str, Any]]:
|
|
1051
|
+
version = "adjudication-mandatory-checkpoint-log/1.0" if mandatory else "adjudication-explicit-user-request-log/1.0"
|
|
1052
|
+
if set(value) != {"schema_version", "run_id", "records"} or value.get("schema_version") != version or value.get("run_id") != run_id:
|
|
1053
|
+
raise ActivityError("SOURCE", "action log root is invalid")
|
|
1054
|
+
records = value.get("records")
|
|
1055
|
+
if not isinstance(records, list) or len(records) > MAX_EVENTS_RUN:
|
|
1056
|
+
raise ActivityError("SOURCE", "action log record list is invalid")
|
|
1057
|
+
ids: set[str] = set()
|
|
1058
|
+
for record in records:
|
|
1059
|
+
common = {"actor_role", "source", "stage", "interaction_id", "interaction_sha256"}
|
|
1060
|
+
expected = common | (
|
|
1061
|
+
{"response_id", "checkpoint_id", "checkpoint_type", "disposition"}
|
|
1062
|
+
if mandatory else {"request_id", "action", "finding_id"}
|
|
1063
|
+
)
|
|
1064
|
+
if not isinstance(record, dict) or set(record) != expected:
|
|
1065
|
+
raise ActivityError("SOURCE", "action log record closed shape is invalid")
|
|
1066
|
+
record_id = record["response_id" if mandatory else "request_id"]
|
|
1067
|
+
if not isinstance(record_id, str) or not ID_RE.fullmatch(record_id) or record_id in ids:
|
|
1068
|
+
raise ActivityError("SOURCE", "action log record id is invalid or repeated")
|
|
1069
|
+
ids.add(record_id)
|
|
1070
|
+
identifier_fields = (
|
|
1071
|
+
("checkpoint_id", "interaction_id")
|
|
1072
|
+
if mandatory else ("finding_id", "interaction_id")
|
|
1073
|
+
)
|
|
1074
|
+
if any(
|
|
1075
|
+
not isinstance(record.get(field), str) or not ID_RE.fullmatch(record[field])
|
|
1076
|
+
for field in identifier_fields
|
|
1077
|
+
):
|
|
1078
|
+
raise ActivityError("SOURCE", "action log identifier is outside the closed grammar")
|
|
1079
|
+
if record.get("actor_role") != "user" or record.get("source") != "explicit_session_user_action" or record.get("stage") not in STAGES:
|
|
1080
|
+
raise ActivityError("SOURCE", "action log authority/stage is invalid")
|
|
1081
|
+
interaction_id = record.get("interaction_id")
|
|
1082
|
+
if not isinstance(interaction_id, str) or not ID_RE.fullmatch(interaction_id) or record.get("interaction_sha256") != interaction_sha256(run_id, interaction_id):
|
|
1083
|
+
raise ActivityError("SOURCE", "action log interaction digest is invalid")
|
|
1084
|
+
if mandatory:
|
|
1085
|
+
if record.get("checkpoint_type") != "MANDATORY" or record.get("disposition") not in {"proceed", "skip", "pause", "adjust", "view_progress", "redo", "abort"}:
|
|
1086
|
+
raise ActivityError("SOURCE", "mandatory checkpoint record is invalid")
|
|
1087
|
+
elif record.get("action") not in {"justify_finding", "redo_finding"}:
|
|
1088
|
+
raise ActivityError("SOURCE", "explicit request action is invalid")
|
|
1089
|
+
return records
|
|
1090
|
+
|
|
1091
|
+
|
|
1092
|
+
def _log_events(run_id: str, family: str, group: list[dict[str, Any]], root: Path, total: list[int]) -> tuple[list[dict[str, Any]], int]:
|
|
1093
|
+
value, _ = _load_artifact(root, group[0], total)
|
|
1094
|
+
mandatory = family == SOURCE_FAMILIES[4]
|
|
1095
|
+
records = _validate_action_log(value, run_id=run_id, mandatory=mandatory)
|
|
1096
|
+
result: list[dict[str, Any]] = []
|
|
1097
|
+
for record in records:
|
|
1098
|
+
if mandatory:
|
|
1099
|
+
source_disposition = record["disposition"]
|
|
1100
|
+
if source_disposition == "proceed":
|
|
1101
|
+
continue
|
|
1102
|
+
disposition = "skip_refused" if source_disposition == "skip" else source_disposition
|
|
1103
|
+
result.append(_event(
|
|
1104
|
+
run_id, family, "mandatory_checkpoint_non_proceed", record["stage"],
|
|
1105
|
+
disposition, record["interaction_sha256"], mandatory_source_record(record),
|
|
1106
|
+
))
|
|
1107
|
+
else:
|
|
1108
|
+
event_type, disposition = (
|
|
1109
|
+
("finding_justification_requested", "justification_requested")
|
|
1110
|
+
if record["action"] == "justify_finding"
|
|
1111
|
+
else ("finding_redo_requested", "redo_requested")
|
|
1112
|
+
)
|
|
1113
|
+
result.append(_event(
|
|
1114
|
+
run_id, family, event_type, record["stage"], disposition,
|
|
1115
|
+
record["interaction_sha256"], explicit_source_record(record),
|
|
1116
|
+
))
|
|
1117
|
+
return result, len(records)
|
|
1118
|
+
|
|
1119
|
+
|
|
1120
|
+
def _validate_manifest_authority(manifest: dict[str, Any], root: Path) -> tuple[dict[str, Any], bytes]:
|
|
1121
|
+
_schema_validate(manifest, INPUT_SCHEMA_PATH, code="INPUT")
|
|
1122
|
+
terminal = manifest["terminal_receipt"]
|
|
1123
|
+
state_raw = _read_artifact_relative(root, terminal["relative_path"], MAX_STORE)
|
|
1124
|
+
if hashlib.sha256(state_raw).hexdigest() != terminal["sha256"]:
|
|
1125
|
+
raise ActivityError("INPUT", "terminal receipt raw-byte hash mismatch")
|
|
1126
|
+
state = strict_json(state_raw, code="INPUT")
|
|
1127
|
+
run_id, pipeline_state, stage, status = _state_replay(state)
|
|
1128
|
+
exact = {
|
|
1129
|
+
"artifact_id": "pipeline-state-terminal-receipt",
|
|
1130
|
+
"relative_path": terminal["relative_path"],
|
|
1131
|
+
"sha256": hashlib.sha256(state_raw).hexdigest(),
|
|
1132
|
+
"run_id": run_id, "pipeline_state": pipeline_state,
|
|
1133
|
+
"current_stage": stage, "current_stage_status": status,
|
|
1134
|
+
}
|
|
1135
|
+
if terminal != exact:
|
|
1136
|
+
raise ActivityError("INPUT", "terminal receipt projection does not exactly replay")
|
|
1137
|
+
if manifest["run_id"] != run_id or manifest["terminal_state"] != pipeline_state or manifest["terminal_stage"] != stage:
|
|
1138
|
+
raise ActivityError("INPUT", "input root does not match terminal state authority")
|
|
1139
|
+
inventory = state.get("adjudication_activity_sources")
|
|
1140
|
+
if inventory != manifest["sources"]:
|
|
1141
|
+
raise ActivityError("INPUT", "input sources differ from sealed terminal inventory")
|
|
1142
|
+
_validate_source_rows(inventory)
|
|
1143
|
+
for row in inventory:
|
|
1144
|
+
_group_artifacts(row)
|
|
1145
|
+
if row["source_family"] == SOURCE_FAMILIES[0] and row["capture_state"] == "captured":
|
|
1146
|
+
for group in _group_artifacts(row):
|
|
1147
|
+
raw_stage = STAGE_TO_RAW[group[0]["artifact_group_stage"]]
|
|
1148
|
+
stage_row = state.get("stages", {}).get(raw_stage)
|
|
1149
|
+
if not isinstance(stage_row, dict) or stage_row.get("status") != "completed":
|
|
1150
|
+
raise ActivityError("INPUT", "author source stage is not completed in terminal state")
|
|
1151
|
+
return state, state_raw
|
|
1152
|
+
|
|
1153
|
+
|
|
1154
|
+
def _extract_run(manifest: dict[str, Any], root: Path, sequence: int) -> dict[str, Any]:
|
|
1155
|
+
_, _ = _validate_manifest_authority(manifest, root)
|
|
1156
|
+
run_id = manifest["run_id"]
|
|
1157
|
+
total = [0]
|
|
1158
|
+
source_rows: list[dict[str, Any]] = []
|
|
1159
|
+
all_events: list[list[dict[str, Any]]] = []
|
|
1160
|
+
action_log_record_count = 0
|
|
1161
|
+
for row in manifest["sources"]:
|
|
1162
|
+
groups = _group_artifacts(row)
|
|
1163
|
+
events: list[dict[str, Any]] = []
|
|
1164
|
+
if row["capture_state"] == "captured":
|
|
1165
|
+
family = row["source_family"]
|
|
1166
|
+
if family == SOURCE_FAMILIES[0]:
|
|
1167
|
+
for group in groups:
|
|
1168
|
+
events.extend(_author_events(run_id, group[0]["artifact_group_stage"], group, root, total))
|
|
1169
|
+
elif family == SOURCE_FAMILIES[1]:
|
|
1170
|
+
events = _compliance_events(run_id, groups, root, total)
|
|
1171
|
+
elif family == SOURCE_FAMILIES[2]:
|
|
1172
|
+
events = _rereview_events(run_id, groups[0], root, total)
|
|
1173
|
+
else:
|
|
1174
|
+
events, source_record_count = _log_events(run_id, family, groups[0], root, total)
|
|
1175
|
+
action_log_record_count += source_record_count
|
|
1176
|
+
if action_log_record_count > MAX_EVENTS_RUN:
|
|
1177
|
+
raise ActivityError("CAP", "combined action-log records exceed per-run cap")
|
|
1178
|
+
all_events.append(events)
|
|
1179
|
+
source_rows.append({
|
|
1180
|
+
"source_family": row["source_family"],
|
|
1181
|
+
"capture_state": row["capture_state"],
|
|
1182
|
+
"reason_code": row["reason_code"],
|
|
1183
|
+
"artifact_sha256s": [item["sha256"] for item in row["artifacts"]],
|
|
1184
|
+
"events": events,
|
|
1185
|
+
})
|
|
1186
|
+
winner: dict[str, int] = {}
|
|
1187
|
+
for family_index, events in enumerate(all_events):
|
|
1188
|
+
for event in events:
|
|
1189
|
+
digest = event["interaction_sha256"]
|
|
1190
|
+
if digest is not None and digest not in winner:
|
|
1191
|
+
winner[digest] = family_index
|
|
1192
|
+
for family_index, source in enumerate(source_rows):
|
|
1193
|
+
source["events"] = [
|
|
1194
|
+
event for event in source["events"]
|
|
1195
|
+
if event["interaction_sha256"] is None or winner[event["interaction_sha256"]] == family_index
|
|
1196
|
+
]
|
|
1197
|
+
event_count = sum(len(row["events"]) for row in source_rows)
|
|
1198
|
+
if event_count > MAX_EVENTS_RUN:
|
|
1199
|
+
raise ActivityError("CAP", "derived events exceed per-run cap")
|
|
1200
|
+
record: dict[str, Any] = {
|
|
1201
|
+
"append_sequence": sequence,
|
|
1202
|
+
"run_id": run_id,
|
|
1203
|
+
"terminal_state": manifest["terminal_state"],
|
|
1204
|
+
"terminal_stage": manifest["terminal_stage"],
|
|
1205
|
+
"terminal_receipt_sha256": manifest["terminal_receipt"]["sha256"],
|
|
1206
|
+
"input_receipt_sha256": _digest(b"ars.adjudication-activity.input/1.0\0", manifest),
|
|
1207
|
+
"record_sha256": "",
|
|
1208
|
+
"sealed": True,
|
|
1209
|
+
"sources": source_rows,
|
|
1210
|
+
}
|
|
1211
|
+
preimage = {key: value for key, value in record.items() if key != "record_sha256"}
|
|
1212
|
+
record["record_sha256"] = _digest(b"ars.adjudication-activity.run/1.0\0", preimage)
|
|
1213
|
+
return record
|
|
1214
|
+
|
|
1215
|
+
|
|
1216
|
+
def _empty_store(store_id: str) -> dict[str, Any]:
|
|
1217
|
+
return {
|
|
1218
|
+
"schema_version": STORE_VERSION, "store_id": store_id,
|
|
1219
|
+
"revision": 0, "next_sequence": 1, "runs": [],
|
|
1220
|
+
"data_minimization": copy.deepcopy(DATA_MINIMIZATION),
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
|
|
1224
|
+
def _validate_store(value: Any) -> dict[str, Any]:
|
|
1225
|
+
if not isinstance(value, dict):
|
|
1226
|
+
raise ActivityError("STORE", "store root must be an object")
|
|
1227
|
+
_schema_validate(value, STORE_SCHEMA_PATH, code="STORE")
|
|
1228
|
+
runs = value["runs"]
|
|
1229
|
+
if len(runs) > MAX_RUNS:
|
|
1230
|
+
raise ActivityError("CAP", "retained runs exceed hard cap")
|
|
1231
|
+
sequences: list[int] = []
|
|
1232
|
+
identities: dict[str, set[Any]] = {
|
|
1233
|
+
"run": set(), "input": set(), "record": set(), "event": set(),
|
|
1234
|
+
}
|
|
1235
|
+
total_events = 0
|
|
1236
|
+
for run in runs:
|
|
1237
|
+
sequences.append(run["append_sequence"])
|
|
1238
|
+
checks = (("run", run["run_id"]), ("input", run["input_receipt_sha256"]), ("record", run["record_sha256"]))
|
|
1239
|
+
for kind, identity in checks:
|
|
1240
|
+
if identity in identities[kind]:
|
|
1241
|
+
raise ActivityError("STORE", f"duplicate {kind} identity")
|
|
1242
|
+
identities[kind].add(identity)
|
|
1243
|
+
preimage = {key: item for key, item in run.items() if key != "record_sha256"}
|
|
1244
|
+
if run["record_sha256"] != _digest(b"ars.adjudication-activity.run/1.0\0", preimage):
|
|
1245
|
+
raise ActivityError("STORE", "run record digest mismatch")
|
|
1246
|
+
if [row["source_family"] for row in run["sources"]] != list(SOURCE_FAMILIES):
|
|
1247
|
+
raise ActivityError("STORE", "stored source family order mismatch")
|
|
1248
|
+
captured_counts = (
|
|
1249
|
+
{2, 4}, set(range(1, 33)), {4}, {1}, {1},
|
|
1250
|
+
)
|
|
1251
|
+
cross_family: dict[str, int] = {}
|
|
1252
|
+
for family_index, row in enumerate(run["sources"]):
|
|
1253
|
+
artifact_count = len(row["artifact_sha256s"])
|
|
1254
|
+
if row["capture_state"] == "captured" and artifact_count not in captured_counts[family_index]:
|
|
1255
|
+
raise ActivityError("STORE", "captured source artifact count violates family contract")
|
|
1256
|
+
if row["capture_state"] != "captured" and artifact_count != 0:
|
|
1257
|
+
raise ActivityError("STORE", "non-captured source retains artifact hashes")
|
|
1258
|
+
for event in row["events"]:
|
|
1259
|
+
if event["event_id"] in identities["event"]:
|
|
1260
|
+
raise ActivityError("STORE", "duplicate event id")
|
|
1261
|
+
identities["event"].add(event["event_id"])
|
|
1262
|
+
digest = event["interaction_sha256"]
|
|
1263
|
+
if digest is not None and digest in cross_family and cross_family[digest] != family_index:
|
|
1264
|
+
raise ActivityError("STORE", "cross-family causal duplicate remains in store")
|
|
1265
|
+
if digest is not None:
|
|
1266
|
+
cross_family[digest] = family_index
|
|
1267
|
+
payload = {
|
|
1268
|
+
"run_id": run["run_id"], "source_family": row["source_family"],
|
|
1269
|
+
"event_type": event["event_type"], "stage": event["stage"],
|
|
1270
|
+
"disposition": event["disposition"],
|
|
1271
|
+
"interaction_sha256": digest,
|
|
1272
|
+
"source_event_sha256": event["source_event_sha256"],
|
|
1273
|
+
}
|
|
1274
|
+
expected_id = "ACTIVITY-EVENT-" + _digest(b"ars.adjudication-activity.event-id/1.0\0", payload)
|
|
1275
|
+
if event["event_id"] != expected_id:
|
|
1276
|
+
raise ActivityError("STORE", "event id digest mismatch")
|
|
1277
|
+
total_events += 1
|
|
1278
|
+
if sequences != sorted(sequences) or len(sequences) != len(set(sequences)):
|
|
1279
|
+
raise ActivityError("STORE", "append sequences are not strictly increasing")
|
|
1280
|
+
if sequences and value["next_sequence"] <= sequences[-1]:
|
|
1281
|
+
raise ActivityError("STORE", "next_sequence does not exceed retained sequences")
|
|
1282
|
+
if value["revision"] < len(runs):
|
|
1283
|
+
raise ActivityError("STORE", "revision cannot be below retained append count")
|
|
1284
|
+
if value["revision"] < value["next_sequence"] - 1:
|
|
1285
|
+
raise ActivityError("STORE", "revision cannot be below allocated append sequences")
|
|
1286
|
+
if total_events > MAX_EVENTS_STORE:
|
|
1287
|
+
raise ActivityError("CAP", "store event count exceeds hard cap")
|
|
1288
|
+
return value
|
|
1289
|
+
|
|
1290
|
+
|
|
1291
|
+
def _read_store(path: Path) -> tuple[dict[str, Any], bytes, tuple[int, int, int]]:
|
|
1292
|
+
raw, identity = _read_limited_identity(path, MAX_STORE, code="STORE")
|
|
1293
|
+
value = strict_json(raw, code="STORE")
|
|
1294
|
+
if raw != canonical_bytes(value, code="STORE") + b"\n":
|
|
1295
|
+
raise ActivityError("STORE", "store bytes are not canonical JSON plus one LF")
|
|
1296
|
+
return _validate_store(value), raw, identity
|
|
1297
|
+
|
|
1298
|
+
|
|
1299
|
+
def _store_bytes(value: dict[str, Any]) -> bytes:
|
|
1300
|
+
_validate_store(value)
|
|
1301
|
+
raw = canonical_bytes(value, code="STORE") + b"\n"
|
|
1302
|
+
if len(raw) > MAX_STORE:
|
|
1303
|
+
raise ActivityError("CAP", "persisted store exceeds hard byte cap")
|
|
1304
|
+
return raw
|
|
1305
|
+
|
|
1306
|
+
|
|
1307
|
+
def _json_id(value: str) -> str:
|
|
1308
|
+
return json.dumps(value, ensure_ascii=False, separators=(",", ":"))
|
|
1309
|
+
|
|
1310
|
+
|
|
1311
|
+
def _cmd_init(args: argparse.Namespace) -> str:
|
|
1312
|
+
path = Path(args.store)
|
|
1313
|
+
with _store_lock(path, exclusive=True):
|
|
1314
|
+
if path.exists() or path.is_symlink():
|
|
1315
|
+
raise ActivityError("CONFLICT", "store path already exists")
|
|
1316
|
+
store = _empty_store(args.store_id)
|
|
1317
|
+
_schema_validate(store, STORE_SCHEMA_PATH, code="STORE")
|
|
1318
|
+
_atomic_create(path, _store_bytes(store))
|
|
1319
|
+
return f"[ARS-ADJUDICATION-ACTIVITY] initialized store_id={_json_id(args.store_id)}; revision=0; next_sequence=1"
|
|
1320
|
+
|
|
1321
|
+
|
|
1322
|
+
def _cmd_build(args: argparse.Namespace) -> str:
|
|
1323
|
+
state_path, root = Path(args.state), Path(args.artifact_root)
|
|
1324
|
+
state_raw = _read_limited(state_path, MAX_STORE, code="INPUT")
|
|
1325
|
+
state = strict_json(state_raw, code="INPUT")
|
|
1326
|
+
run_id, pipeline_state, stage, _ = _state_replay(state)
|
|
1327
|
+
inventory = state.get("adjudication_activity_sources")
|
|
1328
|
+
_validate_source_rows(inventory)
|
|
1329
|
+
relative = _relative_binding(root, state_path)
|
|
1330
|
+
manifest = {
|
|
1331
|
+
"schema_version": INPUT_VERSION, "store_id": args.store_id,
|
|
1332
|
+
"run_id": run_id, "terminal_state": pipeline_state,
|
|
1333
|
+
"terminal_stage": stage,
|
|
1334
|
+
"terminal_receipt": _terminal_receipt(state, state_raw, relative),
|
|
1335
|
+
"sources": copy.deepcopy(inventory),
|
|
1336
|
+
"data_minimization": copy.deepcopy(DATA_MINIMIZATION),
|
|
1337
|
+
}
|
|
1338
|
+
_validate_manifest_authority(manifest, root)
|
|
1339
|
+
# Full extraction here proves every projected artifact before publishing input.
|
|
1340
|
+
_extract_run(manifest, root, 1)
|
|
1341
|
+
_atomic_create(Path(args.output), canonical_bytes(manifest) + b"\n")
|
|
1342
|
+
return f"[ARS-ADJUDICATION-ACTIVITY] built_input run_id={_json_id(run_id)}; source_count=5"
|
|
1343
|
+
|
|
1344
|
+
|
|
1345
|
+
def _load_manifest(path: Path) -> dict[str, Any]:
|
|
1346
|
+
raw = _read_limited(path, MAX_INPUT, code="INPUT")
|
|
1347
|
+
value = strict_json(raw, code="INPUT")
|
|
1348
|
+
if not isinstance(value, dict):
|
|
1349
|
+
raise ActivityError("INPUT", "input manifest root must be an object")
|
|
1350
|
+
_schema_validate(value, INPUT_SCHEMA_PATH, code="INPUT")
|
|
1351
|
+
return value
|
|
1352
|
+
|
|
1353
|
+
|
|
1354
|
+
def _cmd_append(args: argparse.Namespace) -> str:
|
|
1355
|
+
manifest = _load_manifest(Path(args.input))
|
|
1356
|
+
root, path = Path(args.artifact_root), Path(args.store)
|
|
1357
|
+
receipt = _digest(b"ars.adjudication-activity.input/1.0\0", manifest)
|
|
1358
|
+
with _store_lock(path, exclusive=True):
|
|
1359
|
+
if path.exists() or path.is_symlink():
|
|
1360
|
+
store, _, store_identity = _read_store(path)
|
|
1361
|
+
if store["store_id"] != manifest["store_id"]:
|
|
1362
|
+
raise ActivityError("CONFLICT", "store id differs from input store id")
|
|
1363
|
+
else:
|
|
1364
|
+
store = _empty_store(manifest["store_id"])
|
|
1365
|
+
store_identity = None
|
|
1366
|
+
for retained in store["runs"]:
|
|
1367
|
+
if retained["run_id"] == manifest["run_id"]:
|
|
1368
|
+
if retained["input_receipt_sha256"] == receipt:
|
|
1369
|
+
return (
|
|
1370
|
+
f"[ARS-ADJUDICATION-ACTIVITY] already_appended run_id={_json_id(retained['run_id'])}; "
|
|
1371
|
+
f"append_sequence={retained['append_sequence']}; revision={store['revision']}"
|
|
1372
|
+
)
|
|
1373
|
+
raise ActivityError("CONFLICT", "run id is retained with a different input receipt")
|
|
1374
|
+
if retained["input_receipt_sha256"] == receipt:
|
|
1375
|
+
raise ActivityError("CONFLICT", "input receipt is retained under a different run id")
|
|
1376
|
+
if len(store["runs"]) >= MAX_RUNS:
|
|
1377
|
+
raise ActivityError("CAP", "retained run cap reached")
|
|
1378
|
+
# Source and terminal replay occurs only for a genuinely new identity.
|
|
1379
|
+
record = _extract_run(manifest, root, store["next_sequence"])
|
|
1380
|
+
candidate = copy.deepcopy(store)
|
|
1381
|
+
candidate["runs"].append(record)
|
|
1382
|
+
candidate["next_sequence"] += 1
|
|
1383
|
+
candidate["revision"] += 1
|
|
1384
|
+
raw = _store_bytes(candidate)
|
|
1385
|
+
if store_identity is not None:
|
|
1386
|
+
_atomic_replace(path, raw, expected_identity=store_identity)
|
|
1387
|
+
else:
|
|
1388
|
+
_atomic_create(path, raw)
|
|
1389
|
+
return (
|
|
1390
|
+
f"[ARS-ADJUDICATION-ACTIVITY] appended run_id={_json_id(record['run_id'])}; "
|
|
1391
|
+
f"append_sequence={record['append_sequence']}; revision={candidate['revision']}"
|
|
1392
|
+
)
|
|
1393
|
+
|
|
1394
|
+
|
|
1395
|
+
def _render(store: dict[str, Any], window: int) -> str:
|
|
1396
|
+
selected = store["runs"][-window:]
|
|
1397
|
+
count = sum(len(source["events"]) for run in selected for source in run["sources"])
|
|
1398
|
+
overturn = sum(
|
|
1399
|
+
event["event_type"] in OVERTURN_TYPES
|
|
1400
|
+
for run in selected for source in run["sources"] for event in source["events"]
|
|
1401
|
+
)
|
|
1402
|
+
unavailable_runs = sum(any(source["capture_state"] == "unavailable" for source in run["sources"]) for run in selected)
|
|
1403
|
+
lines: list[str] = []
|
|
1404
|
+
if len(selected) < 2:
|
|
1405
|
+
lines.append(
|
|
1406
|
+
f"[ARS-ADJUDICATION-ACTIVITY INSUFFICIENT_HISTORY] selected_retained_eligible_run_count={len(selected)}; "
|
|
1407
|
+
f"minimum_required=2; requested_window={window}."
|
|
1408
|
+
)
|
|
1409
|
+
lines.append(
|
|
1410
|
+
f"[ARS-ADJUDICATION-ACTIVITY COUNTS] adjudication_count={count} (denominator: {len(selected)} retained eligible terminal run records); "
|
|
1411
|
+
f"overturn_count={overturn} (denominator: {count} recorded adjudications); unavailable_run_count={unavailable_runs} "
|
|
1412
|
+
f"(denominator: {len(selected)} retained eligible terminal run records)."
|
|
1413
|
+
)
|
|
1414
|
+
else:
|
|
1415
|
+
lines.append(
|
|
1416
|
+
f"[ARS-ADJUDICATION-ACTIVITY] selected_retained_eligible_run_count={len(selected)}; requested_window={window}; "
|
|
1417
|
+
f"adjudication_count={count} (denominator: {len(selected)} retained eligible terminal run records); "
|
|
1418
|
+
f"overturn_count={overturn} (denominator: {count} recorded adjudications); unavailable_run_count={unavailable_runs} "
|
|
1419
|
+
f"(denominator: {len(selected)} retained eligible terminal run records)."
|
|
1420
|
+
)
|
|
1421
|
+
for run in selected:
|
|
1422
|
+
run_count = sum(len(source["events"]) for source in run["sources"])
|
|
1423
|
+
run_overturn = sum(event["event_type"] in OVERTURN_TYPES for source in run["sources"] for event in source["events"])
|
|
1424
|
+
unavailable = sum(source["capture_state"] == "unavailable" for source in run["sources"])
|
|
1425
|
+
lines.append(
|
|
1426
|
+
f"sequence={run['append_sequence']}; run_id={_json_id(run['run_id'])}; terminal_state={run['terminal_state']}; "
|
|
1427
|
+
f"adjudication_count={run_count} (denominator: 1 retained eligible terminal run record); "
|
|
1428
|
+
f"overturn_count={run_overturn} (denominator: {run_count} recorded adjudications); "
|
|
1429
|
+
f"unavailable_source_count={unavailable} (denominator: 5 source families)."
|
|
1430
|
+
)
|
|
1431
|
+
lines.extend((COVERAGE, LIMITATION, ADVISORY))
|
|
1432
|
+
return "\n".join(lines)
|
|
1433
|
+
|
|
1434
|
+
|
|
1435
|
+
def _cmd_render(args: argparse.Namespace) -> str:
|
|
1436
|
+
path = Path(args.store)
|
|
1437
|
+
with _store_lock(path, exclusive=False):
|
|
1438
|
+
store, _, _ = _read_store(path)
|
|
1439
|
+
return _render(store, args.window)
|
|
1440
|
+
|
|
1441
|
+
|
|
1442
|
+
def _cmd_validate(args: argparse.Namespace) -> str:
|
|
1443
|
+
path = Path(args.store)
|
|
1444
|
+
with _store_lock(path, exclusive=False):
|
|
1445
|
+
store, _, _ = _read_store(path)
|
|
1446
|
+
return (
|
|
1447
|
+
f"[ARS-ADJUDICATION-ACTIVITY] valid store_id={_json_id(store['store_id'])}; "
|
|
1448
|
+
f"retained_runs={len(store['runs'])}; revision={store['revision']}; next_sequence={store['next_sequence']}"
|
|
1449
|
+
)
|
|
1450
|
+
|
|
1451
|
+
|
|
1452
|
+
def _confirmation(store_id: str, expected_hash: str, raw: bytes) -> None:
|
|
1453
|
+
if not HEX_RE.fullmatch(expected_hash) or hashlib.sha256(raw).hexdigest() != expected_hash:
|
|
1454
|
+
raise ActivityError("DELETE_CONFIRMATION", "store raw-byte hash confirmation mismatch")
|
|
1455
|
+
if store_id is None:
|
|
1456
|
+
raise ActivityError("DELETE_CONFIRMATION", "store id confirmation is required")
|
|
1457
|
+
|
|
1458
|
+
|
|
1459
|
+
def _cmd_delete_runs(args: argparse.Namespace) -> str:
|
|
1460
|
+
path = Path(args.store)
|
|
1461
|
+
with _store_lock(path, exclusive=True):
|
|
1462
|
+
store, raw, store_identity = _read_store(path)
|
|
1463
|
+
_confirmation(args.store_id, args.expect_store_sha256, raw)
|
|
1464
|
+
if store["store_id"] != args.store_id:
|
|
1465
|
+
raise ActivityError("DELETE_CONFIRMATION", "store id confirmation mismatch")
|
|
1466
|
+
if args.run_id:
|
|
1467
|
+
if len(args.run_id) != len(set(args.run_id)):
|
|
1468
|
+
raise ActivityError("DELETE_CONFIRMATION", "run id deletion set has duplicates")
|
|
1469
|
+
wanted = set(args.run_id)
|
|
1470
|
+
existing = {run["run_id"] for run in store["runs"]}
|
|
1471
|
+
if not wanted or not wanted <= existing:
|
|
1472
|
+
raise ActivityError("DELETE_CONFIRMATION", "run id deletion target mismatch")
|
|
1473
|
+
survivors = [run for run in store["runs"] if run["run_id"] not in wanted]
|
|
1474
|
+
else:
|
|
1475
|
+
try:
|
|
1476
|
+
first_text, last_text = args.sequence_range.split(":", 1)
|
|
1477
|
+
first, last = int(first_text), int(last_text)
|
|
1478
|
+
except (AttributeError, ValueError):
|
|
1479
|
+
raise ActivityError("DELETE_CONFIRMATION", "invalid sequence range") from None
|
|
1480
|
+
if first < 1 or first > last:
|
|
1481
|
+
raise ActivityError("DELETE_CONFIRMATION", "invalid sequence range")
|
|
1482
|
+
selected = {run["append_sequence"] for run in store["runs"] if first <= run["append_sequence"] <= last}
|
|
1483
|
+
if not selected:
|
|
1484
|
+
raise ActivityError("DELETE_CONFIRMATION", "sequence range selects no retained run")
|
|
1485
|
+
survivors = [run for run in store["runs"] if run["append_sequence"] not in selected]
|
|
1486
|
+
deleted = len(store["runs"]) - len(survivors)
|
|
1487
|
+
candidate = copy.deepcopy(store)
|
|
1488
|
+
candidate["runs"] = survivors
|
|
1489
|
+
candidate["revision"] += 1
|
|
1490
|
+
_atomic_replace(path, _store_bytes(candidate), expected_identity=store_identity)
|
|
1491
|
+
return f"[ARS-ADJUDICATION-ACTIVITY] deleted_runs={deleted}; revision={candidate['revision']}; next_sequence={candidate['next_sequence']}"
|
|
1492
|
+
|
|
1493
|
+
|
|
1494
|
+
def _cmd_delete_store(args: argparse.Namespace) -> str:
|
|
1495
|
+
if args.confirm != "DELETE-ADJUDICATION-ACTIVITY-STORE":
|
|
1496
|
+
raise ActivityError("DELETE_CONFIRMATION", "whole-store confirmation token mismatch")
|
|
1497
|
+
path = Path(args.store)
|
|
1498
|
+
with _store_lock(path, exclusive=True):
|
|
1499
|
+
raw, store_identity = _read_limited_identity(path, MAX_STORE, code="STORE")
|
|
1500
|
+
_confirmation(args.store_id, args.expect_store_sha256, raw)
|
|
1501
|
+
try:
|
|
1502
|
+
parsed = strict_json(raw, code="STORE")
|
|
1503
|
+
if raw != canonical_bytes(parsed, code="STORE") + b"\n":
|
|
1504
|
+
raise ActivityError("STORE", "store bytes are noncanonical")
|
|
1505
|
+
store = _validate_store(parsed)
|
|
1506
|
+
except ActivityError:
|
|
1507
|
+
store = None
|
|
1508
|
+
if store is not None and store["store_id"] != args.store_id:
|
|
1509
|
+
raise ActivityError("DELETE_CONFIRMATION", "store id confirmation mismatch")
|
|
1510
|
+
try:
|
|
1511
|
+
_assert_identity(path, store_identity)
|
|
1512
|
+
os.unlink(path)
|
|
1513
|
+
directory_fd = os.open(path.parent, os.O_RDONLY)
|
|
1514
|
+
try:
|
|
1515
|
+
os.fsync(directory_fd)
|
|
1516
|
+
finally:
|
|
1517
|
+
os.close(directory_fd)
|
|
1518
|
+
except OSError as exc:
|
|
1519
|
+
raise ActivityError("WRITE", f"store deletion failed: {exc.__class__.__name__}") from None
|
|
1520
|
+
return "[ARS-ADJUDICATION-ACTIVITY] deleted_store=true"
|
|
1521
|
+
|
|
1522
|
+
|
|
1523
|
+
class _Parser(argparse.ArgumentParser):
|
|
1524
|
+
def error(self, message: str) -> None:
|
|
1525
|
+
raise ActivityError("USAGE", message)
|
|
1526
|
+
|
|
1527
|
+
|
|
1528
|
+
def build_cli_parser() -> argparse.ArgumentParser:
|
|
1529
|
+
parser = _Parser(prog="adjudication_activity.py")
|
|
1530
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
1531
|
+
|
|
1532
|
+
init_parser = subparsers.add_parser("init-store")
|
|
1533
|
+
init_parser.add_argument("--store", required=True)
|
|
1534
|
+
init_parser.add_argument("--store-id", required=True)
|
|
1535
|
+
init_parser.set_defaults(handler=_cmd_init)
|
|
1536
|
+
|
|
1537
|
+
build_parser = subparsers.add_parser("build-input")
|
|
1538
|
+
build_parser.add_argument("--state", required=True)
|
|
1539
|
+
build_parser.add_argument("--artifact-root", required=True)
|
|
1540
|
+
build_parser.add_argument("--store-id", required=True)
|
|
1541
|
+
build_parser.add_argument("--output", required=True)
|
|
1542
|
+
build_parser.set_defaults(handler=_cmd_build)
|
|
1543
|
+
|
|
1544
|
+
append_parser = subparsers.add_parser("append-run")
|
|
1545
|
+
append_parser.add_argument("--store", required=True)
|
|
1546
|
+
append_parser.add_argument("--artifact-root", required=True)
|
|
1547
|
+
append_parser.add_argument("--input", required=True)
|
|
1548
|
+
append_parser.set_defaults(handler=_cmd_append)
|
|
1549
|
+
|
|
1550
|
+
render_parser = subparsers.add_parser("render")
|
|
1551
|
+
render_parser.add_argument("--store", required=True)
|
|
1552
|
+
render_parser.add_argument("--window", type=int, default=10)
|
|
1553
|
+
render_parser.set_defaults(handler=_cmd_render)
|
|
1554
|
+
|
|
1555
|
+
validate_parser = subparsers.add_parser("validate")
|
|
1556
|
+
validate_parser.add_argument("--store", required=True)
|
|
1557
|
+
validate_parser.set_defaults(handler=_cmd_validate)
|
|
1558
|
+
|
|
1559
|
+
delete_runs_parser = subparsers.add_parser("delete-runs")
|
|
1560
|
+
delete_runs_parser.add_argument("--store", required=True)
|
|
1561
|
+
delete_runs_parser.add_argument("--store-id", required=True)
|
|
1562
|
+
delete_runs_parser.add_argument("--expect-store-sha256", required=True)
|
|
1563
|
+
selection = delete_runs_parser.add_mutually_exclusive_group(required=True)
|
|
1564
|
+
selection.add_argument("--run-id", action="append")
|
|
1565
|
+
selection.add_argument("--sequence-range")
|
|
1566
|
+
delete_runs_parser.set_defaults(handler=_cmd_delete_runs)
|
|
1567
|
+
|
|
1568
|
+
delete_store_parser = subparsers.add_parser("delete-store")
|
|
1569
|
+
delete_store_parser.add_argument("--store", required=True)
|
|
1570
|
+
delete_store_parser.add_argument("--store-id", required=True)
|
|
1571
|
+
delete_store_parser.add_argument("--expect-store-sha256", required=True)
|
|
1572
|
+
delete_store_parser.add_argument("--confirm", required=True)
|
|
1573
|
+
delete_store_parser.set_defaults(handler=_cmd_delete_store)
|
|
1574
|
+
return parser
|
|
1575
|
+
|
|
1576
|
+
|
|
1577
|
+
def main(argv: Sequence[str] | None = None) -> int:
|
|
1578
|
+
try:
|
|
1579
|
+
args = build_cli_parser().parse_args(argv)
|
|
1580
|
+
if getattr(args, "window", 10) not in range(2, 51):
|
|
1581
|
+
raise ActivityError("USAGE", "window must be in the closed range 2..50")
|
|
1582
|
+
output = args.handler(args)
|
|
1583
|
+
if output:
|
|
1584
|
+
print(output)
|
|
1585
|
+
return 0
|
|
1586
|
+
except ActivityError as exc:
|
|
1587
|
+
print(f"[ARS-ADJUDICATION-ACTIVITY ERROR:{exc.code}] {exc.detail}", file=sys.stderr)
|
|
1588
|
+
return EXIT_BY_CODE[exc.code]
|
|
1589
|
+
|
|
1590
|
+
|
|
1591
|
+
if __name__ == "__main__":
|
|
1592
|
+
raise SystemExit(main())
|