rig-create 0.0.0-stage → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +169 -2
- package/docs/CHECKS.md +1682 -0
- package/docs/COLLECTIONS.md +337 -0
- package/docs/CRAFT.md +277 -0
- package/docs/INTERVIEW.md +886 -0
- package/docs/LESSONS.md +172 -0
- package/docs/PROJECT.md +2657 -0
- package/docs/SOURCE.md +225 -0
- package/package.json +44 -4
- package/src/agent-bounce.ts +27 -0
- package/src/agent-guide.ts +237 -0
- package/src/amend.ts +193 -0
- package/src/applied-review.ts +104 -0
- package/src/ask-coverage.ts +69 -0
- package/src/assemble-answers.ts +53 -0
- package/src/cg-gates.ts +211 -0
- package/src/check-reads.ts +106 -0
- package/src/check.ts +1059 -0
- package/src/checkpoint-evidence-writer.ts +125 -0
- package/src/checkpoint-evidence.ts +152 -0
- package/src/choice-writers.ts +271 -0
- package/src/choices.ts +378 -0
- package/src/cli.ts +371 -0
- package/src/collection-answer.ts +136 -0
- package/src/collection-binding-reader.ts +496 -0
- package/src/collection-binding.ts +478 -0
- package/src/collection.ts +348 -0
- package/src/config-inputs.ts +155 -0
- package/src/config-lost.ts +135 -0
- package/src/correction-writers.ts +207 -0
- package/src/corrections.ts +685 -0
- package/src/diff-classes.ts +219 -0
- package/src/diff-map.ts +248 -0
- package/src/direction-citation.ts +13 -0
- package/src/direction-writers.ts +119 -0
- package/src/direction.ts +266 -0
- package/src/drafts.ts +363 -0
- package/src/feedback.ts +744 -0
- package/src/figure-mask.ts +143 -0
- package/src/fix-ledger.ts +355 -0
- package/src/init.ts +265 -0
- package/src/inputs.ts +160 -0
- package/src/intake.ts +158 -0
- package/src/interview.ts +53 -0
- package/src/invariants.ts +132 -0
- package/src/job-acts.ts +80 -0
- package/src/job-advance.ts +65 -0
- package/src/job-close.ts +226 -0
- package/src/job-host.ts +529 -0
- package/src/job-outbox.ts +383 -0
- package/src/job-publication.ts +701 -0
- package/src/job-runtime.ts +99 -0
- package/src/job-writer.ts +123 -0
- package/src/meshes-bust.ts +63 -0
- package/src/next.ts +1506 -0
- package/src/overrides.ts +42 -0
- package/src/package-upgrades.ts +32 -0
- package/src/packages-upgrade-check.ts +6 -0
- package/src/packages-upgrade.ts +168 -0
- package/src/parts-act.ts +96 -0
- package/src/parts-check.ts +242 -0
- package/src/parts-review.ts +196 -0
- package/src/parts-sections.ts +98 -0
- package/src/parts-verdict-record.ts +265 -0
- package/src/parts-verdict.ts +33 -0
- package/src/pause.ts +118 -0
- package/src/pins-check.ts +619 -0
- package/src/pins.ts +17 -0
- package/src/plan-bar-amendments.ts +54 -0
- package/src/plan-history.ts +147 -0
- package/src/plan-writers.ts +202 -0
- package/src/plate-receipt.ts +110 -0
- package/src/pre-interview.ts +302 -0
- package/src/prepared-inputs.ts +113 -0
- package/src/progress-writers.ts +181 -0
- package/src/provenance.ts +301 -0
- package/src/record-direction-target.ts +26 -0
- package/src/record-input.ts +18 -0
- package/src/refusal-baseline.ts +55 -0
- package/src/refusal.ts +30 -0
- package/src/reopen-lapses.ts +80 -0
- package/src/reopen.ts +144 -0
- package/src/republish.ts +93 -0
- package/src/restart.ts +141 -0
- package/src/review-act-runtime.ts +16 -0
- package/src/review-act.ts +592 -0
- package/src/review-package.ts +524 -0
- package/src/review-read.ts +238 -0
- package/src/review.ts +432 -0
- package/src/rig-version-date.ts +22 -0
- package/src/rig-version.ts +1047 -0
- package/src/run-record.ts +232 -0
- package/src/scene-authority.ts +410 -0
- package/src/scene-writers.ts +144 -0
- package/src/scene.ts +284 -0
- package/src/setup-painting.ts +46 -0
- package/src/signable.ts +65 -0
- package/src/signoff-answers.ts +76 -0
- package/src/signoff-checkpoint-act.ts +95 -0
- package/src/signoff-target.ts +127 -0
- package/src/signoff.ts +331 -0
- package/src/split-captions.ts +154 -0
- package/src/stage-progress.ts +379 -0
- package/src/stages.ts +148 -0
- package/src/step-hash.ts +19 -0
- package/src/structure-snapshot.ts +109 -0
- package/src/structure.ts +166 -0
- package/src/templates.ts +16 -0
- package/src/waypoints.ts +163 -0
- package/templates/agent-guide.md +108 -0
- package/templates/collection-agent-guide.md +72 -0
- package/templates/collection.json +252 -0
- package/templates/example-chain/AGENTS.md +134 -0
- package/templates/example-chain/CLAUDE.md +3 -0
- package/templates/example-chain/README.md +13 -0
- package/templates/example-chain/chain.json +2869 -0
- package/templates/example-chain/checkpoints/0a-interview-options/AGENTS.md +134 -0
- package/templates/example-chain/checkpoints/0a-interview-options/CLAUDE.md +3 -0
- package/templates/example-chain/checkpoints/0a-interview-options/evidence/.gitkeep +0 -0
- package/templates/example-chain/checkpoints/0a-interview-options/evidence/approval.txt +1 -0
- package/templates/example-chain/checkpoints/0a-interview-options/evidence/interview/rig_type.json +59 -0
- package/templates/example-chain/checkpoints/0a-interview-options/evidence/split-config.json +1 -0
- package/templates/example-chain/checkpoints/0a-interview-options/inputs/painting.png +0 -0
- package/templates/example-chain/checkpoints/0a-interview-options/inputs/references/.gitkeep +0 -0
- package/templates/example-chain/checkpoints/0a-interview-options/package.json +9 -0
- package/templates/example-chain/checkpoints/0a-interview-options/project.json +295 -0
- package/templates/example-chain/checkpoints/0a-interview-options.json +127 -0
- package/templates/example-chain/checkpoints/0b-plan-pending/AGENTS.md +134 -0
- package/templates/example-chain/checkpoints/0b-plan-pending/CLAUDE.md +3 -0
- package/templates/example-chain/checkpoints/0b-plan-pending/evidence/.gitkeep +0 -0
- package/templates/example-chain/checkpoints/0b-plan-pending/evidence/approval.txt +1 -0
- package/templates/example-chain/checkpoints/0b-plan-pending/evidence/interview/assemble.json +309 -0
- package/templates/example-chain/checkpoints/0b-plan-pending/evidence/interview/reference.json +59 -0
- package/templates/example-chain/checkpoints/0b-plan-pending/evidence/interview/rig_type.json +59 -0
- package/templates/example-chain/checkpoints/0b-plan-pending/evidence/interview/seethrough.json +186 -0
- package/templates/example-chain/checkpoints/0b-plan-pending/evidence/split-config.json +1 -0
- package/templates/example-chain/checkpoints/0b-plan-pending/inputs/painting.png +0 -0
- package/templates/example-chain/checkpoints/0b-plan-pending/inputs/references/.gitkeep +0 -0
- package/templates/example-chain/checkpoints/0b-plan-pending/package.json +9 -0
- package/templates/example-chain/checkpoints/0b-plan-pending/project.json +685 -0
- package/templates/example-chain/checkpoints/0b-plan-pending.json +81 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/AGENTS.md +134 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/CLAUDE.md +3 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/evidence/.gitkeep +0 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/evidence/approval.txt +1 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/evidence/interview/assemble.json +309 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/evidence/interview/reference.json +59 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/evidence/interview/rig_type.json +59 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/evidence/interview/seethrough.json +186 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/evidence/parts-check.json +127 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/evidence/split-config.json +1 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/inputs/painting.png +0 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/inputs/references/.gitkeep +0 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/package.json +9 -0
- package/templates/example-chain/checkpoints/1-parts-verdict/project.json +955 -0
- package/templates/example-chain/checkpoints/1-parts-verdict.json +204 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/AGENTS.md +134 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/CLAUDE.md +3 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/evidence/.gitkeep +0 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/evidence/approval.txt +1 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/evidence/diff-components.json +34 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/evidence/interview/assemble.json +309 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/evidence/interview/bones.json +190 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/evidence/interview/reference.json +59 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/evidence/interview/rig_type.json +59 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/evidence/interview/seethrough.json +186 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/evidence/parts-check.json +127 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/evidence/parts-review.json +88 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/evidence/review-reads/a12dea02d32508acc99386f894af76a14f1c85f45f804db2aa6b4dea5297973f.json +59 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/evidence/split-config.json +1 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/evidence/structure.json +30 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/inputs/painting.png +0 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/inputs/references/.gitkeep +0 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/package.json +9 -0
- package/templates/example-chain/checkpoints/2-rigging-answers/project.json +1198 -0
- package/templates/example-chain/checkpoints/2-rigging-answers.json +254 -0
- package/templates/example-chain/checkpoints/3-rig-review/AGENTS.md +134 -0
- package/templates/example-chain/checkpoints/3-rig-review/CLAUDE.md +3 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/.gitkeep +0 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/approval.txt +1 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/diff-components.json +34 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/assemble.json +309 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/bones.json +190 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/constraints.json +272 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/meshes.json +190 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/motion.json +272 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/reference.json +59 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/rig_type.json +59 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/interview/seethrough.json +186 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/parts-check.json +127 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/parts-review.json +88 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/review-reads/a12dea02d32508acc99386f894af76a14f1c85f45f804db2aa6b4dea5297973f.json +59 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/setup.png +0 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/split-config.json +1 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/structure.json +30 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/v1/config.json +88 -0
- package/templates/example-chain/checkpoints/3-rig-review/evidence/v1/interview-requirements.json +8 -0
- package/templates/example-chain/checkpoints/3-rig-review/inputs/painting.png +0 -0
- package/templates/example-chain/checkpoints/3-rig-review/inputs/references/.gitkeep +0 -0
- package/templates/example-chain/checkpoints/3-rig-review/package.json +9 -0
- package/templates/example-chain/checkpoints/3-rig-review/project.json +1909 -0
- package/templates/example-chain/checkpoints/3-rig-review.json +424 -0
- package/templates/example-chain/checkpoints/4-direction-post/AGENTS.md +134 -0
- package/templates/example-chain/checkpoints/4-direction-post/CLAUDE.md +3 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/.gitkeep +0 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/approval.txt +1 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/diff-components.json +34 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/assemble.json +309 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/bones.json +190 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/camera_depth.json +102 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/constraints.json +272 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/meshes.json +190 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/motion.json +272 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/post_composition.json +122 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/post_timing.json +102 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/reference.json +59 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/rig_type.json +59 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/interview/seethrough.json +186 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/parts-check.json +127 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/parts-review.json +88 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/review-reads/a12dea02d32508acc99386f894af76a14f1c85f45f804db2aa6b4dea5297973f.json +59 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/setup.png +0 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/split-config.json +1 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/structure.json +30 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/v1/config.json +88 -0
- package/templates/example-chain/checkpoints/4-direction-post/evidence/v1/interview-requirements.json +8 -0
- package/templates/example-chain/checkpoints/4-direction-post/inputs/painting.png +0 -0
- package/templates/example-chain/checkpoints/4-direction-post/inputs/references/.gitkeep +0 -0
- package/templates/example-chain/checkpoints/4-direction-post/package.json +9 -0
- package/templates/example-chain/checkpoints/4-direction-post/project.json +2302 -0
- package/templates/example-chain/checkpoints/4-direction-post.json +456 -0
- package/templates/example-chain/evidence/.gitkeep +0 -0
- package/templates/example-chain/evidence/approval.txt +1 -0
- package/templates/example-chain/evidence/captions.json +101 -0
- package/templates/example-chain/evidence/diff-components.json +34 -0
- package/templates/example-chain/evidence/direction/v2.json +74 -0
- package/templates/example-chain/evidence/direction-input.json +74 -0
- package/templates/example-chain/evidence/interview/assemble.json +309 -0
- package/templates/example-chain/evidence/interview/bones.json +190 -0
- package/templates/example-chain/evidence/interview/camera_depth.json +102 -0
- package/templates/example-chain/evidence/interview/constraints.json +272 -0
- package/templates/example-chain/evidence/interview/meshes.json +190 -0
- package/templates/example-chain/evidence/interview/motion.json +272 -0
- package/templates/example-chain/evidence/interview/post_composition.json +122 -0
- package/templates/example-chain/evidence/interview/post_timing.json +102 -0
- package/templates/example-chain/evidence/interview/reference.json +59 -0
- package/templates/example-chain/evidence/interview/rig_type.json +59 -0
- package/templates/example-chain/evidence/interview/seethrough.json +186 -0
- package/templates/example-chain/evidence/parts-check.json +127 -0
- package/templates/example-chain/evidence/parts-review.json +88 -0
- package/templates/example-chain/evidence/review-reads/a12dea02d32508acc99386f894af76a14f1c85f45f804db2aa6b4dea5297973f.json +59 -0
- package/templates/example-chain/evidence/scene/s1.json +65 -0
- package/templates/example-chain/evidence/scene-citations.json +9 -0
- package/templates/example-chain/evidence/setup.png +0 -0
- package/templates/example-chain/evidence/split-config.json +1 -0
- package/templates/example-chain/evidence/structure.json +30 -0
- package/templates/example-chain/evidence/v1/config.json +88 -0
- package/templates/example-chain/evidence/v1/interview-requirements.json +8 -0
- package/templates/example-chain/inputs/background.png +0 -0
- package/templates/example-chain/inputs/painting.png +0 -0
- package/templates/example-chain/inputs/references/.gitkeep +0 -0
- package/templates/example-chain/package.json +9 -0
- package/templates/example-chain/project.json +2593 -0
- package/templates/example-diff/diff-components.json +71 -0
- package/templates/example-diff/recomposite_rig.png +0 -0
- package/templates/example-direction/approval.txt +1 -0
- package/templates/example-direction/derived/review/v1/out/check/build/rectangle.png +0 -0
- package/templates/example-direction/derived/review/v1/out/check/build/run.json +40 -0
- package/templates/example-direction/derived/review/v1/out/check/build/skeleton.atlas +8 -0
- package/templates/example-direction/derived/review/v1/out/check/build/skeleton.json +73 -0
- package/templates/example-direction/derived/review/v1/out/check/build/skeleton.model.json +195 -0
- package/templates/example-direction/evidence/direction/v2.json +69 -0
- package/templates/example-direction/evidence/direction/v3.json +59 -0
- package/templates/example-direction/evidence/images/rectangle.png +0 -0
- package/templates/example-direction/evidence/input.json +69 -0
- package/templates/example-direction/evidence/motion.json +33 -0
- package/templates/example-direction/evidence/patch.json +23 -0
- package/templates/example-direction/evidence/rig-config.json +55 -0
- package/templates/example-direction/evidence/still.png +0 -0
- package/templates/example-direction/project.json +372 -0
- package/templates/example-direction/reasoning.txt +1 -0
- package/templates/example-direction/words.txt +1 -0
- package/templates/example-draft/README.md +28 -0
- package/templates/example-draft/config.json +71 -0
- package/templates/example-draft/derived/drafts/lantern/config.json +71 -0
- package/templates/example-draft/derived/drafts/lantern/input/painting_in_rig.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/input/parts/background.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/input/parts/eye_l.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/input/parts/eye_r.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/input/parts/face.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/input/parts/lantern.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/input/parts/torso.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/input/parts.json +188 -0
- package/templates/example-draft/derived/drafts/lantern/input/recomposite_rig.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/interview-requirements.json +8 -0
- package/templates/example-draft/derived/drafts/lantern/out/check/build/run.json +40 -0
- package/templates/example-draft/derived/drafts/lantern/out/check/build/skeleton.atlas +28 -0
- package/templates/example-draft/derived/drafts/lantern/out/check/build/skeleton.json +193 -0
- package/templates/example-draft/derived/drafts/lantern/out/check/build/skeleton.model.json +483 -0
- package/templates/example-draft/derived/drafts/lantern/out/check/build/skeleton.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/out/images/background.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/out/images/eye_l.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/out/images/eye_r.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/out/images/face.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/out/images/lantern.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/out/images/torso.png +0 -0
- package/templates/example-draft/derived/drafts/lantern/out/mesh_report.json +1 -0
- package/templates/example-draft/derived/drafts/lantern/out/motion.json +137 -0
- package/templates/example-draft/derived/drafts/lantern/out/rig.json +102 -0
- package/templates/example-draft/derived/drafts/lantern/out/run.json +52 -0
- package/templates/example-draft/derived/parts/rig/painting_in_rig.png +0 -0
- package/templates/example-draft/derived/parts/rig/parts/background.png +0 -0
- package/templates/example-draft/derived/parts/rig/parts/eye_l.png +0 -0
- package/templates/example-draft/derived/parts/rig/parts/eye_r.png +0 -0
- package/templates/example-draft/derived/parts/rig/parts/face.png +0 -0
- package/templates/example-draft/derived/parts/rig/parts/lantern.png +0 -0
- package/templates/example-draft/derived/parts/rig/parts/torso.png +0 -0
- package/templates/example-draft/derived/parts/rig/parts.json +188 -0
- package/templates/example-draft/derived/parts/rig/recomposite_rig.png +0 -0
- package/templates/example-draft/derived/review/v1/config.json +71 -0
- package/templates/example-draft/derived/review/v1/interview-requirements.json +8 -0
- package/templates/example-draft/derived/review/v1/out/check/build/run.json +40 -0
- package/templates/example-draft/derived/review/v1/out/check/build/skeleton.atlas +28 -0
- package/templates/example-draft/derived/review/v1/out/check/build/skeleton.json +193 -0
- package/templates/example-draft/derived/review/v1/out/check/build/skeleton.model.json +483 -0
- package/templates/example-draft/derived/review/v1/out/check/build/skeleton.png +0 -0
- package/templates/example-draft/derived/review/v1/out/parts/background.png +0 -0
- package/templates/example-draft/derived/review/v1/out/parts/eye_l.png +0 -0
- package/templates/example-draft/derived/review/v1/out/parts/eye_r.png +0 -0
- package/templates/example-draft/derived/review/v1/out/parts/face.png +0 -0
- package/templates/example-draft/derived/review/v1/out/parts/lantern.png +0 -0
- package/templates/example-draft/derived/review/v1/out/parts/torso.png +0 -0
- package/templates/example-draft/derived/review/v1/out/parts.json +188 -0
- package/templates/example-draft/derived/review/v1/out/rig/images/background.png +0 -0
- package/templates/example-draft/derived/review/v1/out/rig/images/eye_l.png +0 -0
- package/templates/example-draft/derived/review/v1/out/rig/images/eye_r.png +0 -0
- package/templates/example-draft/derived/review/v1/out/rig/images/face.png +0 -0
- package/templates/example-draft/derived/review/v1/out/rig/images/lantern.png +0 -0
- package/templates/example-draft/derived/review/v1/out/rig/images/torso.png +0 -0
- package/templates/example-draft/derived/review/v1/out/rig/mesh_report.json +1 -0
- package/templates/example-draft/derived/review/v1/out/rig/motion.json +137 -0
- package/templates/example-draft/derived/review/v1/out/rig/rig.json +102 -0
- package/templates/example-draft/derived/review/v1/out/rig/run.json +52 -0
- package/templates/example-draft/derived/review/v2/config.json +71 -0
- package/templates/example-draft/derived/review/v2/interview-requirements.json +8 -0
- package/templates/example-draft/derived/review/v2/out/check/build/run.json +40 -0
- package/templates/example-draft/derived/review/v2/out/check/build/skeleton.atlas +28 -0
- package/templates/example-draft/derived/review/v2/out/check/build/skeleton.json +193 -0
- package/templates/example-draft/derived/review/v2/out/check/build/skeleton.model.json +483 -0
- package/templates/example-draft/derived/review/v2/out/check/build/skeleton.png +0 -0
- package/templates/example-draft/derived/review/v2/out/parts/background.png +0 -0
- package/templates/example-draft/derived/review/v2/out/parts/eye_l.png +0 -0
- package/templates/example-draft/derived/review/v2/out/parts/eye_r.png +0 -0
- package/templates/example-draft/derived/review/v2/out/parts/face.png +0 -0
- package/templates/example-draft/derived/review/v2/out/parts/lantern.png +0 -0
- package/templates/example-draft/derived/review/v2/out/parts/torso.png +0 -0
- package/templates/example-draft/derived/review/v2/out/parts.json +188 -0
- package/templates/example-draft/derived/review/v2/out/rig/images/background.png +0 -0
- package/templates/example-draft/derived/review/v2/out/rig/images/eye_l.png +0 -0
- package/templates/example-draft/derived/review/v2/out/rig/images/eye_r.png +0 -0
- package/templates/example-draft/derived/review/v2/out/rig/images/face.png +0 -0
- package/templates/example-draft/derived/review/v2/out/rig/images/lantern.png +0 -0
- package/templates/example-draft/derived/review/v2/out/rig/images/torso.png +0 -0
- package/templates/example-draft/derived/review/v2/out/rig/mesh_report.json +1 -0
- package/templates/example-draft/derived/review/v2/out/rig/motion.json +137 -0
- package/templates/example-draft/derived/review/v2/out/rig/rig.json +102 -0
- package/templates/example-draft/derived/review/v2/out/rig/run.json +52 -0
- package/templates/example-draft/evidence/diff-components.json +71 -0
- package/templates/example-draft/evidence/direction/v4.json +64 -0
- package/templates/example-draft/evidence/direction-input-v4.json +64 -0
- package/templates/example-draft/evidence/fix-ledger/lantern.json +17 -0
- package/templates/example-draft/evidence/parts-check.json +127 -0
- package/templates/example-draft/evidence/parts-review.json +88 -0
- package/templates/example-draft/evidence/review-reads/4ed0507381809746443021554e012032be5b5f8417da0f2e525e9b6df16e9f05.json +59 -0
- package/templates/example-draft/evidence/scene/s1.json +65 -0
- package/templates/example-draft/evidence/scene-background.png +0 -0
- package/templates/example-draft/evidence/scene-citations.json +9 -0
- package/templates/example-draft/evidence/structure-decisions.json +9 -0
- package/templates/example-draft/evidence/v1/interview-config.json +71 -0
- package/templates/example-draft/evidence/v1/interview-requirements.json +8 -0
- package/templates/example-draft/evidence/v1/review-config.json +71 -0
- package/templates/example-draft/evidence/v2/interview-config.json +71 -0
- package/templates/example-draft/evidence/v2/interview-requirements.json +8 -0
- package/templates/example-draft/evidence/v2/review-config.json +71 -0
- package/templates/example-draft/input/painting_in_rig.png +0 -0
- package/templates/example-draft/input/parts/background.png +0 -0
- package/templates/example-draft/input/parts/eye_l.png +0 -0
- package/templates/example-draft/input/parts/eye_r.png +0 -0
- package/templates/example-draft/input/parts/face.png +0 -0
- package/templates/example-draft/input/parts/lantern.png +0 -0
- package/templates/example-draft/input/parts/torso.png +0 -0
- package/templates/example-draft/input/parts.json +188 -0
- package/templates/example-draft/input/recomposite_rig.png +0 -0
- package/templates/example-draft/inputs/painting.png +0 -0
- package/templates/example-draft/interview-requirements.json +8 -0
- package/templates/example-draft/out/check/build/run.json +40 -0
- package/templates/example-draft/out/check/build/skeleton.atlas +28 -0
- package/templates/example-draft/out/check/build/skeleton.json +193 -0
- package/templates/example-draft/out/check/build/skeleton.model.json +483 -0
- package/templates/example-draft/out/check/build/skeleton.png +0 -0
- package/templates/example-draft/out/images/background.png +0 -0
- package/templates/example-draft/out/images/eye_l.png +0 -0
- package/templates/example-draft/out/images/eye_r.png +0 -0
- package/templates/example-draft/out/images/face.png +0 -0
- package/templates/example-draft/out/images/lantern.png +0 -0
- package/templates/example-draft/out/images/torso.png +0 -0
- package/templates/example-draft/out/mesh_report.json +1 -0
- package/templates/example-draft/out/motion.json +137 -0
- package/templates/example-draft/out/rig.json +102 -0
- package/templates/example-draft/out/run.json +52 -0
- package/templates/example-draft/outputs/v1/out/check/build/run.json +40 -0
- package/templates/example-draft/outputs/v1/out/check/build/skeleton.atlas +28 -0
- package/templates/example-draft/outputs/v1/out/check/build/skeleton.json +193 -0
- package/templates/example-draft/outputs/v1/out/check/build/skeleton.model.json +483 -0
- package/templates/example-draft/outputs/v1/out/check/build/skeleton.png +0 -0
- package/templates/example-draft/outputs/v1/out/painting_in_rig.png +0 -0
- package/templates/example-draft/outputs/v1/out/parts/background.png +0 -0
- package/templates/example-draft/outputs/v1/out/parts/eye_l.png +0 -0
- package/templates/example-draft/outputs/v1/out/parts/eye_r.png +0 -0
- package/templates/example-draft/outputs/v1/out/parts/face.png +0 -0
- package/templates/example-draft/outputs/v1/out/parts/lantern.png +0 -0
- package/templates/example-draft/outputs/v1/out/parts/torso.png +0 -0
- package/templates/example-draft/outputs/v1/out/parts.json +188 -0
- package/templates/example-draft/outputs/v1/out/rig/images/background.png +0 -0
- package/templates/example-draft/outputs/v1/out/rig/images/eye_l.png +0 -0
- package/templates/example-draft/outputs/v1/out/rig/images/eye_r.png +0 -0
- package/templates/example-draft/outputs/v1/out/rig/images/face.png +0 -0
- package/templates/example-draft/outputs/v1/out/rig/images/lantern.png +0 -0
- package/templates/example-draft/outputs/v1/out/rig/images/torso.png +0 -0
- package/templates/example-draft/outputs/v1/out/rig/mesh_report.json +1 -0
- package/templates/example-draft/outputs/v1/out/rig/motion.json +137 -0
- package/templates/example-draft/outputs/v1/out/rig/rig.json +102 -0
- package/templates/example-draft/outputs/v1/out/rig/run.json +52 -0
- package/templates/example-draft/outputs/v2/out/check/build/run.json +40 -0
- package/templates/example-draft/outputs/v2/out/check/build/skeleton.atlas +28 -0
- package/templates/example-draft/outputs/v2/out/check/build/skeleton.json +193 -0
- package/templates/example-draft/outputs/v2/out/check/build/skeleton.model.json +483 -0
- package/templates/example-draft/outputs/v2/out/check/build/skeleton.png +0 -0
- package/templates/example-draft/outputs/v2/out/painting_in_rig.png +0 -0
- package/templates/example-draft/outputs/v2/out/parts/background.png +0 -0
- package/templates/example-draft/outputs/v2/out/parts/eye_l.png +0 -0
- package/templates/example-draft/outputs/v2/out/parts/eye_r.png +0 -0
- package/templates/example-draft/outputs/v2/out/parts/face.png +0 -0
- package/templates/example-draft/outputs/v2/out/parts/lantern.png +0 -0
- package/templates/example-draft/outputs/v2/out/parts/torso.png +0 -0
- package/templates/example-draft/outputs/v2/out/parts.json +188 -0
- package/templates/example-draft/outputs/v2/out/rig/images/background.png +0 -0
- package/templates/example-draft/outputs/v2/out/rig/images/eye_l.png +0 -0
- package/templates/example-draft/outputs/v2/out/rig/images/eye_r.png +0 -0
- package/templates/example-draft/outputs/v2/out/rig/images/face.png +0 -0
- package/templates/example-draft/outputs/v2/out/rig/images/lantern.png +0 -0
- package/templates/example-draft/outputs/v2/out/rig/images/torso.png +0 -0
- package/templates/example-draft/outputs/v2/out/rig/mesh_report.json +1 -0
- package/templates/example-draft/outputs/v2/out/rig/motion.json +137 -0
- package/templates/example-draft/outputs/v2/out/rig/rig.json +102 -0
- package/templates/example-draft/outputs/v2/out/rig/run.json +52 -0
- package/templates/example-interview-choice.json +1068 -0
- package/templates/example-interview-options/constraint.json +376 -0
- package/templates/example-interview-options/example-assemble.json +376 -0
- package/templates/example-interview-options/example-bones.json +190 -0
- package/templates/example-interview-options/example-camera-depth.json +99 -0
- package/templates/example-interview-options/example-constraints.json +272 -0
- package/templates/example-interview-options/example-meshes.json +190 -0
- package/templates/example-interview-options/example-motion.json +272 -0
- package/templates/example-interview-options/example-picks.json +15 -0
- package/templates/example-interview-options/example-post-composition.json +110 -0
- package/templates/example-interview-options/example-post-timing.json +105 -0
- package/templates/example-interview-options/example-reference.json +63 -0
- package/templates/example-interview-options/example-rig-type.json +63 -0
- package/templates/example-interview-options/example-seethrough.json +190 -0
- package/templates/example-interview-options/fullscreen.json +63 -0
- package/templates/example-interview-options/other-explicit.json +63 -0
- package/templates/example-interview-options/other-pending.json +63 -0
- package/templates/example-interview-options/other-picks.json +16 -0
- package/templates/example-interview.md +213 -0
- package/templates/example-invariants/invariants.json +1339 -0
- package/templates/example-prepared/prepared.svg +1 -0
- package/templates/example-prepared/source.svg +1 -0
- package/templates/example-project.json +4259 -0
- package/templates/example-remesh/AGENTS.md +134 -0
- package/templates/example-remesh/CLAUDE.md +3 -0
- package/templates/example-remesh/evidence/.gitkeep +0 -0
- package/templates/example-remesh/evidence/approval.txt +1 -0
- package/templates/example-remesh/evidence/captions.json +101 -0
- package/templates/example-remesh/evidence/diff-components.json +34 -0
- package/templates/example-remesh/evidence/direction/v4.json +74 -0
- package/templates/example-remesh/evidence/direction/v5.json +74 -0
- package/templates/example-remesh/evidence/direction-input-v4.json +74 -0
- package/templates/example-remesh/evidence/direction-input-v5.json +74 -0
- package/templates/example-remesh/evidence/interview/assemble.json +309 -0
- package/templates/example-remesh/evidence/interview/bones.json +190 -0
- package/templates/example-remesh/evidence/interview/camera_depth.json +103 -0
- package/templates/example-remesh/evidence/interview/constraints.json +272 -0
- package/templates/example-remesh/evidence/interview/meshes.json +190 -0
- package/templates/example-remesh/evidence/interview/motion.json +272 -0
- package/templates/example-remesh/evidence/interview/post_composition.json +123 -0
- package/templates/example-remesh/evidence/interview/post_timing.json +103 -0
- package/templates/example-remesh/evidence/interview/reference.json +59 -0
- package/templates/example-remesh/evidence/interview/rig_type.json +59 -0
- package/templates/example-remesh/evidence/interview/seethrough.json +186 -0
- package/templates/example-remesh/evidence/parts-check.json +127 -0
- package/templates/example-remesh/evidence/parts-review.json +88 -0
- package/templates/example-remesh/evidence/reopen.txt +1 -0
- package/templates/example-remesh/evidence/review-reads/6a17db694db96f1b6049a61a017e0c8e66757b982b8851e0187e561cfcf9af68.json +59 -0
- package/templates/example-remesh/evidence/scene/s1.json +69 -0
- package/templates/example-remesh/evidence/scene-citations.json +9 -0
- package/templates/example-remesh/evidence/setup.png +0 -0
- package/templates/example-remesh/evidence/split-config.json +1 -0
- package/templates/example-remesh/evidence/structure.json +30 -0
- package/templates/example-remesh/evidence/v1/registration/at-source.json +44 -0
- package/templates/example-remesh/evidence/v1/registration/citations.json +68 -0
- package/templates/example-remesh/evidence/v1/registration/compile-report.json +368 -0
- package/templates/example-remesh/evidence/v1/registration/config-source.json +88 -0
- package/templates/example-remesh/evidence/v1/registration/config.json +88 -0
- package/templates/example-remesh/evidence/v1/registration/interview-requirements.json +8 -0
- package/templates/example-remesh/evidence/v1/registration/package-lock.json +11 -0
- package/templates/example-remesh/evidence/v1/registration/path-adapter.json +1 -0
- package/templates/example-remesh/evidence/v1/registration/rigc-run-1.json +44 -0
- package/templates/example-remesh/evidence/v2/registration/at-source.json +44 -0
- package/templates/example-remesh/evidence/v2/registration/citations.json +68 -0
- package/templates/example-remesh/evidence/v2/registration/compile-report.json +368 -0
- package/templates/example-remesh/evidence/v2/registration/config-source.json +88 -0
- package/templates/example-remesh/evidence/v2/registration/config.json +88 -0
- package/templates/example-remesh/evidence/v2/registration/interview-requirements.json +8 -0
- package/templates/example-remesh/evidence/v2/registration/package-lock.json +11 -0
- package/templates/example-remesh/evidence/v2/registration/path-adapter.json +1 -0
- package/templates/example-remesh/evidence/v2/registration/rigc-run-1.json +44 -0
- package/templates/example-remesh/evidence/v3/registration/at-source.json +44 -0
- package/templates/example-remesh/evidence/v3/registration/citations.json +68 -0
- package/templates/example-remesh/evidence/v3/registration/compile-report.json +368 -0
- package/templates/example-remesh/evidence/v3/registration/config-source.json +88 -0
- package/templates/example-remesh/evidence/v3/registration/config.json +88 -0
- package/templates/example-remesh/evidence/v3/registration/interview-requirements.json +8 -0
- package/templates/example-remesh/evidence/v3/registration/package-lock.json +11 -0
- package/templates/example-remesh/evidence/v3/registration/path-adapter.json +1 -0
- package/templates/example-remesh/evidence/v3/registration/rigc-run-1.json +44 -0
- package/templates/example-remesh/inputs/background.png +0 -0
- package/templates/example-remesh/inputs/painting.png +0 -0
- package/templates/example-remesh/inputs/references/.gitkeep +0 -0
- package/templates/example-remesh/package.json +9 -0
- package/templates/example-remesh/project.json +3916 -0
- package/templates/example-reopened/project.json +4568 -0
- package/templates/example-review/config.json +1 -0
- package/templates/example-review/out/check/build/skeleton.model.json +1 -0
- package/templates/example-review/out/parts/piece.svg +1 -0
- package/templates/example-review/out/parts.json +1 -0
- package/templates/example-review/out/rig/mesh_report.json +1 -0
- package/templates/example-review/out/rig/motion.json +1 -0
- package/templates/example-review/out/rig/rig.json +1 -0
- package/templates/example-split/captions.json +357 -0
- package/templates/example-split/config.json +215 -0
- package/templates/legacy-example-project.json +1071 -0
- package/templates/project.json +199 -0
- package/templates/shared/conventions.json +23 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/** Bind producer run records (rig-run/1 and rigc-run/1) by raw SHA-256 and spec shape without re-running or recomputing producer measurements. */
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { readFileSync } from './check-reads.ts';
|
|
4
|
+
import { isAbsolute, win32 } from 'node:path';
|
|
5
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
6
|
+
import { asArray, isObject, type Finding } from './check.ts';
|
|
7
|
+
import { literalFile } from './choices.ts';
|
|
8
|
+
import { structurePathIsIgnored } from './structure.ts';
|
|
9
|
+
import type { Json, JsonObject } from './templates.ts';
|
|
10
|
+
|
|
11
|
+
export const RUN_RECORD_SINCE = '2026-11-08T00:00:00Z';
|
|
12
|
+
export const RUN_SPECS = ['rig-run/1', 'rigc-run/1'] as const;
|
|
13
|
+
export type RunSpec = (typeof RUN_SPECS)[number];
|
|
14
|
+
export const RIGC_INPUT_ROLES = ['rig', 'motion', 'manifest', 'cuts'] as const;
|
|
15
|
+
export const RIGC_REQUIRED_ROLES = ['rig', 'motion'] as const;
|
|
16
|
+
|
|
17
|
+
const TOP_KEYS: Record<RunSpec, readonly string[]> = {
|
|
18
|
+
'rig-run/1': ['spec', 'package', 'command', 'started_at', 'finished_at', 'config', 'outputs'],
|
|
19
|
+
'rigc-run/1': ['spec', 'package', 'command', 'started_at', 'finished_at', 'inputs', 'outputs'],
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const sha = (bytes: Buffer): string => createHash('sha256').update(bytes).digest('hex');
|
|
23
|
+
const absolute = (path: string): boolean => isAbsolute(path) || win32.isAbsolute(path);
|
|
24
|
+
const literal = (path: string): boolean => !!path && !absolute(path) && !path.includes('\\') && !path.includes(':') && path.split('/').every(p => p !== '' && p !== '.' && p !== '..');
|
|
25
|
+
const relativeRunPath = (path: Json | undefined): path is string =>
|
|
26
|
+
typeof path === 'string' && path.length > 0 && !absolute(path) && !path.startsWith('~') && !path.includes('\\') && !path.includes(':')
|
|
27
|
+
&& path.split('/').every(segment => segment !== '' && segment !== '.');
|
|
28
|
+
const hex64 = (value: Json | undefined): value is string => typeof value === 'string' && /^[a-f0-9]{64}$/.test(value);
|
|
29
|
+
const runTimestamp = (value: Json | undefined): value is string =>
|
|
30
|
+
typeof value === 'string' && /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$/.test(value)
|
|
31
|
+
&& Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
|
|
32
|
+
|
|
33
|
+
export class RunRecordError extends Error {
|
|
34
|
+
constructor(readonly code: string, readonly path: string, readonly why: string) {
|
|
35
|
+
super(`${path}: ${why}; retain the producer run.json with --run-record and register a new rig version`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function fail(code: string, path: string, why: string): never {
|
|
40
|
+
throw new RunRecordError(code, path, why);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function isRunSpec(value: Json | undefined): value is RunSpec {
|
|
44
|
+
return value === 'rig-run/1' || value === 'rigc-run/1';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function validateRunRecord(bytes: Buffer, path: string): { spec: RunSpec; record: JsonObject } {
|
|
48
|
+
let parsed: Json;
|
|
49
|
+
try { parsed = JSON.parse(bytes.toString('utf8')) as Json; }
|
|
50
|
+
catch { fail('RUN_RECORD_MALFORMED', path, 'expected valid UTF-8 JSON'); }
|
|
51
|
+
if (!isObject(parsed)) fail('RUN_RECORD_MALFORMED', path, 'expected a JSON object');
|
|
52
|
+
if (!isRunSpec(parsed.spec)) {
|
|
53
|
+
fail('RUN_RECORD_SPEC_UNKNOWN', `${path}.spec`, `unknown producer run spec ${JSON.stringify(parsed.spec ?? null)}; expected rig-run/1 or rigc-run/1`);
|
|
54
|
+
}
|
|
55
|
+
const spec = parsed.spec;
|
|
56
|
+
if (!isDeepStrictEqual(Object.keys(parsed), [...TOP_KEYS[spec]])) {
|
|
57
|
+
fail('RUN_RECORD_MALFORMED', path, `keys must be in published ${spec} order (${TOP_KEYS[spec].join(', ')})`);
|
|
58
|
+
}
|
|
59
|
+
const pkg = parsed.package;
|
|
60
|
+
if (!isObject(pkg) || !isDeepStrictEqual(Object.keys(pkg), ['name', 'version'])) {
|
|
61
|
+
fail('RUN_RECORD_MALFORMED', `${path}.package`, 'package must have keys name, version in that order');
|
|
62
|
+
}
|
|
63
|
+
const expectedNames = spec === 'rig-run/1' ? ['@rig-c/parts'] : ['@rig-c/core', 'rig-c'];
|
|
64
|
+
if (!expectedNames.includes(String(pkg.name)) || typeof pkg.version !== 'string' || !pkg.version.trim()) {
|
|
65
|
+
fail('RUN_RECORD_MALFORMED', `${path}.package`, `expected package.name ${expectedNames.map(name => JSON.stringify(name)).join(' or ')} and a nonempty version`);
|
|
66
|
+
}
|
|
67
|
+
if (spec === 'rig-run/1' ? (parsed.command !== 'rig' && parsed.command !== 'assemble') : parsed.command !== 'build') {
|
|
68
|
+
fail('RUN_RECORD_MALFORMED', `${path}.command`, `invalid ${spec} command ${JSON.stringify(parsed.command ?? null)}`);
|
|
69
|
+
}
|
|
70
|
+
if (!runTimestamp(parsed.started_at)) fail('RUN_RECORD_MALFORMED', `${path}.started_at`, 'expected a UTC ISO-8601 millisecond timestamp ending in Z');
|
|
71
|
+
if (!runTimestamp(parsed.finished_at)) fail('RUN_RECORD_MALFORMED', `${path}.finished_at`, 'expected a UTC ISO-8601 millisecond timestamp ending in Z');
|
|
72
|
+
|
|
73
|
+
if (spec === 'rig-run/1') {
|
|
74
|
+
const config = parsed.config;
|
|
75
|
+
if (!isObject(config) || !isDeepStrictEqual(Object.keys(config), ['path', 'sha256']) || !relativeRunPath(config.path) || !hex64(config.sha256)) {
|
|
76
|
+
fail('RUN_RECORD_MALFORMED', `${path}.config`, 'config must have relative path and 64-hex sha256 in that order');
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
const inputs = parsed.inputs;
|
|
80
|
+
if (!Array.isArray(inputs)) fail('RUN_RECORD_MALFORMED', `${path}.inputs`, 'inputs must be an array');
|
|
81
|
+
const seenRoles = new Set<string>();
|
|
82
|
+
let prevRoleOrder = -1;
|
|
83
|
+
let prevPath = '';
|
|
84
|
+
for (const [i, item] of inputs.entries()) {
|
|
85
|
+
const itemPath = `${path}.inputs[${i}]`;
|
|
86
|
+
if (!isObject(item)) fail('RUN_RECORD_MALFORMED', itemPath, 'input entry must be an object');
|
|
87
|
+
if (typeof item.role !== 'string' || !RIGC_INPUT_ROLES.includes(item.role as (typeof RIGC_INPUT_ROLES)[number])) {
|
|
88
|
+
fail('RUN_RECORD_ROLE_INVALID', `${itemPath}.role`, `unknown input role ${JSON.stringify(item.role ?? null)}; expected one of ${RIGC_INPUT_ROLES.join(', ')}`);
|
|
89
|
+
}
|
|
90
|
+
if (!isDeepStrictEqual(Object.keys(item), ['role', 'path', 'sha256']) || !relativeRunPath(item.path) || !hex64(item.sha256)) {
|
|
91
|
+
fail('RUN_RECORD_MALFORMED', itemPath, 'input entry must have keys role, path, sha256 in that order with a relative path and 64-hex sha256');
|
|
92
|
+
}
|
|
93
|
+
const roleOrder = RIGC_INPUT_ROLES.indexOf(item.role as (typeof RIGC_INPUT_ROLES)[number]);
|
|
94
|
+
if (roleOrder < prevRoleOrder) {
|
|
95
|
+
fail('RUN_RECORD_ROLE_INVALID', `${itemPath}.role`, `input roles must sort in fixed order (${RIGC_INPUT_ROLES.join(', ')})`);
|
|
96
|
+
}
|
|
97
|
+
if (roleOrder === prevRoleOrder && !(prevPath < item.path)) {
|
|
98
|
+
fail('RUN_RECORD_MALFORMED', `${itemPath}.path`, 'inputs with the same role must sort by path in UTF-16 code-unit order');
|
|
99
|
+
}
|
|
100
|
+
seenRoles.add(item.role);
|
|
101
|
+
prevRoleOrder = roleOrder;
|
|
102
|
+
prevPath = item.path;
|
|
103
|
+
}
|
|
104
|
+
for (const required of RIGC_REQUIRED_ROLES) {
|
|
105
|
+
if (!seenRoles.has(required)) {
|
|
106
|
+
fail('RUN_RECORD_ROLE_INVALID', `${path}.inputs`, `rigc-run/1 requires input role ${required}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const outputs = parsed.outputs;
|
|
112
|
+
if (!Array.isArray(outputs) || outputs.length === 0) {
|
|
113
|
+
fail('RUN_RECORD_MALFORMED', `${path}.outputs`, 'outputs must be a nonempty array');
|
|
114
|
+
}
|
|
115
|
+
let prevOutputPath = '';
|
|
116
|
+
for (const [i, out] of outputs.entries()) {
|
|
117
|
+
const outPath = `${path}.outputs[${i}]`;
|
|
118
|
+
if (!isObject(out) || !isDeepStrictEqual(Object.keys(out), ['path', 'sha256']) || !relativeRunPath(out.path) || !hex64(out.sha256)) {
|
|
119
|
+
fail('RUN_RECORD_MALFORMED', outPath, 'output entry must have keys path, sha256 in that order with a relative path and 64-hex sha256');
|
|
120
|
+
}
|
|
121
|
+
if (i > 0 && !(prevOutputPath < out.path)) {
|
|
122
|
+
fail('RUN_RECORD_MALFORMED', `${outPath}.path`, 'outputs must sort by path in UTF-16 code-unit order');
|
|
123
|
+
}
|
|
124
|
+
prevOutputPath = out.path;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return { spec, record: parsed };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function checkRegisteredRuns(
|
|
131
|
+
dir: string,
|
|
132
|
+
versionPath: string,
|
|
133
|
+
record: JsonObject,
|
|
134
|
+
refusals: Finding[],
|
|
135
|
+
warnings: Finding[],
|
|
136
|
+
): Set<string> {
|
|
137
|
+
const runPaths = new Set<string>();
|
|
138
|
+
const runsPath = `${versionPath}.registration.runs`;
|
|
139
|
+
if (record.runs === undefined) {
|
|
140
|
+
const finding: Finding = {
|
|
141
|
+
code: 'RUN_RECORD_REQUIRED',
|
|
142
|
+
path: runsPath,
|
|
143
|
+
message: `${runsPath}: version registered from the npm lock alone; retain producer run.json records with --run-record and register a new rig version`,
|
|
144
|
+
};
|
|
145
|
+
const at = Date.parse(String(record.at));
|
|
146
|
+
if (Number.isFinite(at) && at < Date.parse(RUN_RECORD_SINCE)) warnings.push(finding);
|
|
147
|
+
else refusals.push(finding);
|
|
148
|
+
return runPaths;
|
|
149
|
+
}
|
|
150
|
+
if (!Array.isArray(record.runs) || record.runs.length === 0) {
|
|
151
|
+
refusals.push({
|
|
152
|
+
code: 'RUN_RECORD_MALFORMED',
|
|
153
|
+
path: runsPath,
|
|
154
|
+
message: `${runsPath}: expected a nonempty list of bound producer run records; retain the producer run.json with --run-record and register a new rig version`,
|
|
155
|
+
});
|
|
156
|
+
return runPaths;
|
|
157
|
+
}
|
|
158
|
+
const files = asArray(record.files);
|
|
159
|
+
const seenSpecs = new Set<string>();
|
|
160
|
+
for (const [i, entry] of record.runs.entries()) {
|
|
161
|
+
const entryPath = `${runsPath}[${i}]`;
|
|
162
|
+
if (isObject(entry) && isObject(entry.source) && typeof entry.source.path === 'string') {
|
|
163
|
+
runPaths.add(entry.source.path);
|
|
164
|
+
}
|
|
165
|
+
if (!isObject(entry) || !('spec' in entry) || !('source' in entry) || Object.keys(entry).length !== 2) {
|
|
166
|
+
refusals.push({
|
|
167
|
+
code: 'RUN_RECORD_MALFORMED',
|
|
168
|
+
path: entryPath,
|
|
169
|
+
message: `${entryPath}: expected { spec, source }; restore the retained registration inputs or register a new rig version`,
|
|
170
|
+
});
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (!isRunSpec(entry.spec)) {
|
|
174
|
+
refusals.push({
|
|
175
|
+
code: 'RUN_RECORD_SPEC_UNKNOWN',
|
|
176
|
+
path: `${entryPath}.spec`,
|
|
177
|
+
message: `${entryPath}.spec: unknown producer run spec ${JSON.stringify(entry.spec ?? null)}; retain a rig-run/1 or rigc-run/1 run.json and register a new rig version`,
|
|
178
|
+
});
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (seenSpecs.has(entry.spec)) {
|
|
182
|
+
refusals.push({
|
|
183
|
+
code: 'RUN_RECORD_MALFORMED',
|
|
184
|
+
path: `${entryPath}.spec`,
|
|
185
|
+
message: `${entryPath}.spec: duplicate run record for spec ${entry.spec}; supply at most one --run-record per spec and register a new rig version`,
|
|
186
|
+
});
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
seenSpecs.add(entry.spec);
|
|
190
|
+
const source = entry.source;
|
|
191
|
+
let bytes: Buffer;
|
|
192
|
+
try {
|
|
193
|
+
if (!isObject(source) || typeof source.path !== 'string' || !literal(source.path)
|
|
194
|
+
|| !hex64(source.sha256) || (source.bytes !== undefined && (typeof source.bytes !== 'number' || !Number.isSafeInteger(source.bytes) || source.bytes < 0))) {
|
|
195
|
+
throw Error('expected literal retained path, sha256 and byte count');
|
|
196
|
+
}
|
|
197
|
+
if (structurePathIsIgnored(dir, source.path)) throw Error('run record is under an ignored root');
|
|
198
|
+
const file = literalFile(dir, source.path);
|
|
199
|
+
bytes = readFileSync(file);
|
|
200
|
+
if (sha(bytes) !== source.sha256 || (typeof source.bytes === 'number' && bytes.length !== source.bytes)) {
|
|
201
|
+
throw Error(`${source.path} bytes differ from bound sha256`);
|
|
202
|
+
}
|
|
203
|
+
if (!files.some(f => isObject(f) && f.path === source.path && f.sha256 === source.sha256)) {
|
|
204
|
+
throw Error(`${source.path} is absent from registration.files or its sha256 disagrees`);
|
|
205
|
+
}
|
|
206
|
+
} catch (error) {
|
|
207
|
+
refusals.push({
|
|
208
|
+
code: 'RUN_RECORD_HASH_MISMATCH',
|
|
209
|
+
path: `${entryPath}.source`,
|
|
210
|
+
message: `${entryPath}.source: ${error instanceof Error ? error.message : String(error)}; restore the retained registration inputs or register a new rig version`,
|
|
211
|
+
});
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
const validated = validateRunRecord(bytes, entryPath);
|
|
216
|
+
if (validated.spec !== entry.spec) {
|
|
217
|
+
fail('RUN_RECORD_MALFORMED', `${entryPath}.spec`, `declared spec ${entry.spec} disagrees with retained record spec ${validated.spec}`);
|
|
218
|
+
}
|
|
219
|
+
} catch (error) {
|
|
220
|
+
if (error instanceof RunRecordError) {
|
|
221
|
+
refusals.push({ code: error.code, path: error.path, message: error.message });
|
|
222
|
+
} else {
|
|
223
|
+
refusals.push({
|
|
224
|
+
code: 'RUN_RECORD_MALFORMED',
|
|
225
|
+
path: entryPath,
|
|
226
|
+
message: `${entryPath}: ${error instanceof Error ? error.message : String(error)}; restore the retained registration inputs or register a new rig version`,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return runPaths;
|
|
232
|
+
}
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/** Agent scene authority: every agent-authored scene derives from a recorded post_composition choice or decided delegation. */
|
|
2
|
+
import { isDeepStrictEqual as equal } from 'node:util';
|
|
3
|
+
import { asArray, collectItems, isObject, loadCollection, type Ctx, type Finding } from './check.ts';
|
|
4
|
+
import { CHOICE_SPEC, OPTIONS_SPEC, choiceVerbatim, assembleFragments, optionFile, selection } from './choices.ts';
|
|
5
|
+
import { closed } from './direction.ts';
|
|
6
|
+
import { checkPlateReceipt } from './plate-receipt.ts';
|
|
7
|
+
import { answersOf } from './provenance.ts';
|
|
8
|
+
import { sceneBytes, sceneFail } from './scene.ts';
|
|
9
|
+
import type { Json, JsonObject } from './templates.ts';
|
|
10
|
+
|
|
11
|
+
export const SCENE_CHOICE_MISSING = 'SCENE_CHOICE_MISSING';
|
|
12
|
+
export const SCENE_CHOICE_MISMATCH = 'SCENE_CHOICE_MISMATCH';
|
|
13
|
+
|
|
14
|
+
const MISSING_REMEDY =
|
|
15
|
+
'record a post_composition choice in the Review tool (or complete its delegated agent_decision) whose value.scene binds {background:{path,rect:{x,y,width,height}},foreground?:{path,rect:{x,y,width,height}}} and run scene write';
|
|
16
|
+
const MISMATCH_REMEDY =
|
|
17
|
+
'match the exact roles, paths and rects from the cited post_composition choice in the Review tool (or record a new post_composition choice in the Review tool) and run scene write';
|
|
18
|
+
|
|
19
|
+
const text = (value: unknown): value is string => typeof value === 'string' && value.trim().length > 0;
|
|
20
|
+
const finite = (value: unknown): value is number => typeof value === 'number' && Number.isFinite(value);
|
|
21
|
+
const pathShape = (value: unknown): value is string =>
|
|
22
|
+
text(value) &&
|
|
23
|
+
!value.startsWith('/') &&
|
|
24
|
+
!value.includes('\\') &&
|
|
25
|
+
!/^[A-Za-z]:/.test(value) &&
|
|
26
|
+
value.split('/').every(part => part !== '' && part !== '.' && part !== '..');
|
|
27
|
+
const boxShape = (value: unknown): value is JsonObject =>
|
|
28
|
+
closed(value, ['x', 'y', 'width', 'height']) && Object.values(value).every(v => typeof v === 'number');
|
|
29
|
+
|
|
30
|
+
export const sceneAuthor = (value: unknown): value is string =>
|
|
31
|
+
value === 'agent' || (text(value) && value.toLowerCase() !== 'agent');
|
|
32
|
+
|
|
33
|
+
export interface AgentRoleSpec {
|
|
34
|
+
path: string;
|
|
35
|
+
rect: JsonObject;
|
|
36
|
+
}
|
|
37
|
+
export interface AgentSceneSpec {
|
|
38
|
+
background: AgentRoleSpec;
|
|
39
|
+
foreground?: AgentRoleSpec;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parseRoleSpec(role: 'background' | 'foreground', raw: Json | undefined, valuePath: string): AgentRoleSpec {
|
|
43
|
+
const rolePath = `${valuePath}.scene.${role}`;
|
|
44
|
+
if (!isObject(raw)) {
|
|
45
|
+
sceneFail(SCENE_CHOICE_MISSING, rolePath, `post_composition value.scene.${role} must be a closed {path,rect} object`, MISSING_REMEDY);
|
|
46
|
+
}
|
|
47
|
+
if (!('path' in raw) || raw.path === undefined) {
|
|
48
|
+
sceneFail(SCENE_CHOICE_MISSING, `${rolePath}.path`, `post_composition value.scene.${role} must declare a project-relative path`, MISSING_REMEDY);
|
|
49
|
+
}
|
|
50
|
+
if (!('rect' in raw) || raw.rect === undefined) {
|
|
51
|
+
sceneFail(SCENE_CHOICE_MISSING, `${rolePath}.rect`, `post_composition value.scene.${role} must declare rect:{x,y,width,height}`, MISSING_REMEDY);
|
|
52
|
+
}
|
|
53
|
+
if (!closed(raw, ['path', 'rect'])) {
|
|
54
|
+
sceneFail(SCENE_CHOICE_MISSING, rolePath, `post_composition value.scene.${role} allows only path and rect`, MISSING_REMEDY);
|
|
55
|
+
}
|
|
56
|
+
if (!pathShape(raw.path)) {
|
|
57
|
+
sceneFail(SCENE_CHOICE_MISSING, `${rolePath}.path`, `post_composition value.scene.${role}.path must be a literal project-relative path`, MISSING_REMEDY);
|
|
58
|
+
}
|
|
59
|
+
const rect = raw.rect;
|
|
60
|
+
if (!boxShape(rect) || !Object.values(rect).every(finite) || Number(rect.width) <= 0 || Number(rect.height) <= 0) {
|
|
61
|
+
sceneFail(SCENE_CHOICE_MISSING, `${rolePath}.rect`, `post_composition value.scene.${role}.rect must be a finite positive {x,y,width,height} box`, MISSING_REMEDY);
|
|
62
|
+
}
|
|
63
|
+
return { path: raw.path, rect };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function parseAgentSceneValue(value: Json | undefined, valuePath: string): AgentSceneSpec {
|
|
67
|
+
if (!isObject(value) || !isObject(value.scene)) {
|
|
68
|
+
sceneFail(
|
|
69
|
+
SCENE_CHOICE_MISSING,
|
|
70
|
+
`${valuePath}.scene`,
|
|
71
|
+
'post_composition choice value must declare scene:{background:{path,rect},foreground?:{path,rect}}',
|
|
72
|
+
MISSING_REMEDY,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
const scene = value.scene;
|
|
76
|
+
if (!('background' in scene) || scene.background === undefined) {
|
|
77
|
+
sceneFail(SCENE_CHOICE_MISSING, `${valuePath}.scene.background`, 'post_composition value.scene must declare background:{path,rect}', MISSING_REMEDY);
|
|
78
|
+
}
|
|
79
|
+
if (!closed(scene, ['background'], ['foreground'])) {
|
|
80
|
+
sceneFail(SCENE_CHOICE_MISSING, `${valuePath}.scene`, 'post_composition value.scene allows only background and optional foreground', MISSING_REMEDY);
|
|
81
|
+
}
|
|
82
|
+
const background = parseRoleSpec('background', scene.background, valuePath);
|
|
83
|
+
const foreground = scene.foreground === undefined ? undefined : parseRoleSpec('foreground', scene.foreground, valuePath);
|
|
84
|
+
return { background, ...(foreground ? { foreground } : {}) };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function matchesCitationSurface(answer: JsonObject, citation: JsonObject): boolean {
|
|
88
|
+
if (citation.delegated === true) {
|
|
89
|
+
return (
|
|
90
|
+
answer.delegated === true ||
|
|
91
|
+
asArray(answer.asks).some(ask => isObject(ask) && ask.id === 'post_composition' && ask.state === 'delegated') ||
|
|
92
|
+
isObject(answer.agent_decision)
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (typeof citation.quote === 'string' && citation.quote.trim().length > 0) {
|
|
96
|
+
return (
|
|
97
|
+
(typeof answer.verbatim === 'string' && answer.verbatim.includes(citation.quote)) ||
|
|
98
|
+
asArray(answer.additions).some(add => isObject(add) && typeof add.verbatim === 'string' && add.verbatim.includes(String(citation.quote)))
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function resolveAnswerValue(
|
|
105
|
+
dir: string,
|
|
106
|
+
itemPath: string,
|
|
107
|
+
answer: JsonObject,
|
|
108
|
+
citation: JsonObject,
|
|
109
|
+
snapshots?: Map<string, Buffer>,
|
|
110
|
+
): { value: Json | undefined; valuePath: string } {
|
|
111
|
+
if (!isObject(answer.choice) || answer.choice.spec !== CHOICE_SPEC) {
|
|
112
|
+
sceneFail(
|
|
113
|
+
SCENE_CHOICE_MISSING,
|
|
114
|
+
`${itemPath}.choice`,
|
|
115
|
+
'agent scene assembly requires a recorded Review interview-choice@1 on post_composition',
|
|
116
|
+
MISSING_REMEDY,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
if (!isObject(answer.choice.set) || typeof answer.choice.set.path !== 'string') {
|
|
120
|
+
sceneFail(SCENE_CHOICE_MISSING, `${itemPath}.choice.set`, 'post_composition choice requires a retained option set binding', MISSING_REMEDY);
|
|
121
|
+
}
|
|
122
|
+
if (snapshots) sceneBytes(dir, answer.choice.set.path, 'SCENE_CITATION_MISSING', snapshots);
|
|
123
|
+
let set: JsonObject;
|
|
124
|
+
try {
|
|
125
|
+
set = optionFile(dir, answer.choice.set).set;
|
|
126
|
+
} catch {
|
|
127
|
+
return sceneFail(SCENE_CHOICE_MISSING, `${itemPath}.choice.set`, 'post_composition option set is missing or changed', MISSING_REMEDY);
|
|
128
|
+
}
|
|
129
|
+
let selected: ReturnType<typeof selection>;
|
|
130
|
+
try {
|
|
131
|
+
if (set.schema !== OPTIONS_SPEC || set.question !== 'post_composition' || !text(answer.by) || answer.by.toLowerCase() === 'agent'
|
|
132
|
+
|| !text(answer.at) || !Number.isFinite(Date.parse(answer.at))) throw Error('invalid human choice identity');
|
|
133
|
+
selected = selection(set, answer.choice);
|
|
134
|
+
if (answer.delegated !== selected.delegated || !equal(answer.asks, selected.asks)
|
|
135
|
+
|| answer.verbatim !== choiceVerbatim(asArray(answer.choice.picks).filter(isObject), answer.choice.note)) throw Error('choice projection differs');
|
|
136
|
+
} catch {
|
|
137
|
+
return sceneFail(SCENE_CHOICE_MISSING, `${itemPath}.choice`, 'post_composition choice does not match its retained option set', MISSING_REMEDY);
|
|
138
|
+
}
|
|
139
|
+
if (citation.delegated === true) {
|
|
140
|
+
if (!selected.delegated || !selected.autos.includes('post_composition')) {
|
|
141
|
+
sceneFail(SCENE_CHOICE_MISSING, `${itemPath}.choice`, 'cited post_composition choice did not delegate post_composition', MISSING_REMEDY);
|
|
142
|
+
}
|
|
143
|
+
const decision = answer.agent_decision;
|
|
144
|
+
if (
|
|
145
|
+
!isObject(decision) ||
|
|
146
|
+
decision.by !== 'agent' ||
|
|
147
|
+
!text(decision.at) ||
|
|
148
|
+
!Number.isFinite(Date.parse(decision.at)) ||
|
|
149
|
+
!text(decision.reasoning) ||
|
|
150
|
+
decision.value === undefined ||
|
|
151
|
+
decision.value === null ||
|
|
152
|
+
!Array.isArray(decision.fragments)
|
|
153
|
+
) {
|
|
154
|
+
sceneFail(
|
|
155
|
+
SCENE_CHOICE_MISSING,
|
|
156
|
+
`${itemPath}.agent_decision`,
|
|
157
|
+
'complete the delegated post_composition agent_decision before assembling an agent scene',
|
|
158
|
+
MISSING_REMEDY,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
const frag = decision.fragments.filter(isObject).find(entry => entry.ask === 'post_composition');
|
|
162
|
+
if (!frag || frag.fragment === undefined) {
|
|
163
|
+
sceneFail(
|
|
164
|
+
SCENE_CHOICE_MISSING,
|
|
165
|
+
`${itemPath}.agent_decision.fragments`,
|
|
166
|
+
'delegated post_composition decision must supply a post_composition fragment',
|
|
167
|
+
MISSING_REMEDY,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
const rule = isObject(set.assembly) && typeof set.assembly.rule === 'string' ? set.assembly.rule : 'single';
|
|
171
|
+
let assembled: Json;
|
|
172
|
+
try {
|
|
173
|
+
assembled = assembleFragments(rule, [frag.fragment]);
|
|
174
|
+
} catch {
|
|
175
|
+
return sceneFail(SCENE_CHOICE_MISSING, `${itemPath}.agent_decision.value`, 'delegated post_composition fragment cannot be assembled', MISSING_REMEDY);
|
|
176
|
+
}
|
|
177
|
+
if (!equal(decision.value, assembled)) {
|
|
178
|
+
sceneFail(
|
|
179
|
+
SCENE_CHOICE_MISSING,
|
|
180
|
+
`${itemPath}.agent_decision.value`,
|
|
181
|
+
'delegated post_composition decision value differs from its assembled fragment',
|
|
182
|
+
MISSING_REMEDY,
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
return { value: decision.value, valuePath: `${itemPath}.agent_decision.value` };
|
|
186
|
+
}
|
|
187
|
+
if (selected.delegated || selected.pending.length > 0 || selected.value === undefined || selected.value === null || !equal(answer.value, selected.value)) {
|
|
188
|
+
sceneFail(
|
|
189
|
+
SCENE_CHOICE_MISSING,
|
|
190
|
+
`${itemPath}.value`,
|
|
191
|
+
'post_composition choice must have a resolved non-pending value from the retained option set',
|
|
192
|
+
MISSING_REMEDY,
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
if (typeof answer.verbatim !== 'string' || !answer.verbatim.includes(String(citation.quote))) {
|
|
196
|
+
sceneFail(
|
|
197
|
+
SCENE_CHOICE_MISSING,
|
|
198
|
+
`${itemPath}.verbatim`,
|
|
199
|
+
'agent scene citation quote must match the recorded Review choice verbatim',
|
|
200
|
+
MISSING_REMEDY,
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
return { value: answer.value, valuePath: `${itemPath}.value` };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function assertPlatesMatchSpec(plates: JsonObject[], spec: AgentSceneSpec): void {
|
|
207
|
+
const bgIndex = plates.findIndex(plate => plate.role === 'background');
|
|
208
|
+
const bgPlate = plates[bgIndex]!;
|
|
209
|
+
if (bgPlate.path !== spec.background.path) {
|
|
210
|
+
sceneFail(
|
|
211
|
+
SCENE_CHOICE_MISMATCH,
|
|
212
|
+
`scene.plates[${bgIndex}].path`,
|
|
213
|
+
'background plate path differs from post_composition value.scene.background.path',
|
|
214
|
+
MISMATCH_REMEDY,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
if (!equal(bgPlate.rect, spec.background.rect)) {
|
|
218
|
+
sceneFail(
|
|
219
|
+
SCENE_CHOICE_MISMATCH,
|
|
220
|
+
`scene.plates[${bgIndex}].rect`,
|
|
221
|
+
'background plate rect differs from post_composition value.scene.background.rect',
|
|
222
|
+
MISMATCH_REMEDY,
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
const fgIndex = plates.findIndex(plate => plate.role === 'foreground');
|
|
226
|
+
const fgPlate = fgIndex >= 0 ? plates[fgIndex] : undefined;
|
|
227
|
+
if (spec.foreground !== undefined && !fgPlate) {
|
|
228
|
+
sceneFail(
|
|
229
|
+
SCENE_CHOICE_MISMATCH,
|
|
230
|
+
'scene.plates',
|
|
231
|
+
'post_composition value.scene declares a foreground plate that is absent from scene.plates',
|
|
232
|
+
MISMATCH_REMEDY,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
if (spec.foreground === undefined && fgPlate) {
|
|
236
|
+
sceneFail(
|
|
237
|
+
SCENE_CHOICE_MISMATCH,
|
|
238
|
+
`scene.plates[${fgIndex}]`,
|
|
239
|
+
'scene declares a foreground plate not present in post_composition value.scene',
|
|
240
|
+
MISMATCH_REMEDY,
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
if (spec.foreground !== undefined && fgPlate) {
|
|
244
|
+
if (fgPlate.path !== spec.foreground.path) {
|
|
245
|
+
sceneFail(
|
|
246
|
+
SCENE_CHOICE_MISMATCH,
|
|
247
|
+
`scene.plates[${fgIndex}].path`,
|
|
248
|
+
'foreground plate path differs from post_composition value.scene.foreground.path',
|
|
249
|
+
MISMATCH_REMEDY,
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
if (!equal(fgPlate.rect, spec.foreground.rect)) {
|
|
253
|
+
sceneFail(
|
|
254
|
+
SCENE_CHOICE_MISMATCH,
|
|
255
|
+
`scene.plates[${fgIndex}].rect`,
|
|
256
|
+
'foreground plate rect differs from post_composition value.scene.foreground.rect',
|
|
257
|
+
MISMATCH_REMEDY,
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** Resolve the cited post_composition scene spec for an agent scene write before falling back to any stage rect. */
|
|
264
|
+
export function resolveAgentCitationSpec(
|
|
265
|
+
dir: string,
|
|
266
|
+
project: JsonObject,
|
|
267
|
+
citation: Json,
|
|
268
|
+
snapshots?: Map<string, Buffer>,
|
|
269
|
+
): AgentSceneSpec {
|
|
270
|
+
const collection = loadCollection(dir);
|
|
271
|
+
const items = collectItems(project, { collection });
|
|
272
|
+
const item = items.find(value => value.id === 'post_composition');
|
|
273
|
+
if (!item) sceneFail('SCENE_CITATION_MISSING', 'scene.plates[0].citation', 'cite a recorded post_composition answer or decided delegation');
|
|
274
|
+
if (
|
|
275
|
+
!isObject(citation) ||
|
|
276
|
+
!((closed(citation, ['guide', 'asks', 'quote']) && text(citation.quote)) ||
|
|
277
|
+
(closed(citation, ['guide', 'asks', 'delegated']) && citation.delegated === true)) ||
|
|
278
|
+
citation.guide !== 'post_composition' ||
|
|
279
|
+
!equal(citation.asks, ['post_composition'])
|
|
280
|
+
) {
|
|
281
|
+
sceneFail('SCENE_CITATION_MISSING', 'scene.plates[0].citation', 'cite post_composition with asks and a quote or delegated:true');
|
|
282
|
+
}
|
|
283
|
+
const currentAnswer =
|
|
284
|
+
item.state.state === 'user' || item.state.state === 'delegated'
|
|
285
|
+
? item.state.answer
|
|
286
|
+
: isObject(item.raw)
|
|
287
|
+
? item.raw
|
|
288
|
+
: null;
|
|
289
|
+
if (!currentAnswer) {
|
|
290
|
+
sceneFail('SCENE_CITATION_MISSING', 'scene.plates[0].citation', 'cite a recorded post_composition answer or decided delegation');
|
|
291
|
+
}
|
|
292
|
+
if (!matchesCitationSurface(currentAnswer, citation)) {
|
|
293
|
+
const ctx: Ctx = {
|
|
294
|
+
dir,
|
|
295
|
+
project,
|
|
296
|
+
collection,
|
|
297
|
+
items,
|
|
298
|
+
refusals: [],
|
|
299
|
+
warnings: [],
|
|
300
|
+
signoffs: [],
|
|
301
|
+
steps: [],
|
|
302
|
+
stage: String(project.stage),
|
|
303
|
+
effectiveStage: String(project.stage),
|
|
304
|
+
predatesPartsReview: null,
|
|
305
|
+
};
|
|
306
|
+
const historical = answersOf(item, ctx).some(answer => matchesCitationSurface(answer, citation));
|
|
307
|
+
if (historical) {
|
|
308
|
+
sceneFail(SCENE_CHOICE_MISMATCH, 'scene.plates[0].citation', 'agent scene must cite the current post_composition choice or decided delegation', MISMATCH_REMEDY);
|
|
309
|
+
}
|
|
310
|
+
sceneFail('SCENE_CITATION_MISSING', 'scene.plates[0].citation', 'cite a recorded post_composition answer or decided delegation');
|
|
311
|
+
}
|
|
312
|
+
const { value, valuePath } = resolveAnswerValue(dir, item.path, currentAnswer, citation, snapshots);
|
|
313
|
+
return parseAgentSceneValue(value, valuePath);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export function validateAgentSceneAuthority(
|
|
317
|
+
dir: string,
|
|
318
|
+
project: JsonObject,
|
|
319
|
+
doc: JsonObject,
|
|
320
|
+
ctx: Ctx,
|
|
321
|
+
snapshots?: Map<string, Buffer>,
|
|
322
|
+
current = false,
|
|
323
|
+
): void {
|
|
324
|
+
const plates = doc.plates as JsonObject[];
|
|
325
|
+
for (const [index, plate] of plates.entries()) {
|
|
326
|
+
const registration = plate.registered as JsonObject;
|
|
327
|
+
if (registration.kind === 'input') {
|
|
328
|
+
const match = /^inputs\[(\d+)\]$/.exec(String(registration.ref));
|
|
329
|
+
const entry = match ? asArray(project.inputs)[Number(match[1])] : undefined;
|
|
330
|
+
const bytes = sceneBytes(dir, String(plate.path), 'SCENE_PLATE_CHANGED', snapshots);
|
|
331
|
+
if (!isObject(entry) || entry.bytes !== bytes.length || !Number.isSafeInteger(entry.bytes)
|
|
332
|
+
|| !text(entry.origin) || !text(entry.at) || !Number.isFinite(Date.parse(entry.at))) {
|
|
333
|
+
sceneFail('SCENE_INPUT_RECEIPT_MISSING', `scene.plates[${index}].registered`,
|
|
334
|
+
'candidate lacks input-writer metadata {path,sha256,bytes,origin,at}',
|
|
335
|
+
'register a new source name with input add <path> --origin … and select it through the Review choice');
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (registration.kind === 'derived') {
|
|
339
|
+
const match = /^derived\[(\d+)\]$/.exec(String(registration.ref));
|
|
340
|
+
const entry = match ? asArray(project.derived)[Number(match[1])] : undefined;
|
|
341
|
+
if (!isObject(entry) || !isObject(entry.receipt) || typeof entry.receipt.path !== 'string') {
|
|
342
|
+
sceneFail('SCENE_PLATE_UNREGISTERED', `scene.plates[${index}].registered`, 'agent scene derived plate requires a bound rig-parts-plate-receipt/1 receipt');
|
|
343
|
+
}
|
|
344
|
+
if (snapshots) sceneBytes(dir, entry.receipt.path, 'SCENE_FILE_CHANGED', snapshots);
|
|
345
|
+
const receiptFindings: Finding[] = [];
|
|
346
|
+
checkPlateReceipt({ dir, refusals: receiptFindings }, entry, `derived[${match![1]}]`);
|
|
347
|
+
if (receiptFindings.length > 0) {
|
|
348
|
+
sceneFail('SCENE_PLATE_UNREGISTERED', `scene.plates[${index}].registered`, 'agent scene derived plate has an invalid rig-parts-plate-receipt/1 receipt');
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const item = ctx.items.find(value => value.id === 'post_composition');
|
|
353
|
+
if (!item) sceneFail('SCENE_CITATION_MISSING', 'scene.plates[0].citation', 'cite a recorded post_composition answer or decided delegation');
|
|
354
|
+
if (plates.length === 2) {
|
|
355
|
+
const first = plates[0]!.citation as JsonObject;
|
|
356
|
+
const second = plates[1]!.citation as JsonObject;
|
|
357
|
+
if (Boolean(first.delegated) !== Boolean(second.delegated)) {
|
|
358
|
+
sceneFail(
|
|
359
|
+
SCENE_CHOICE_MISMATCH,
|
|
360
|
+
'scene.plates[1].citation',
|
|
361
|
+
'background and foreground plates must cite the same post_composition choice or decided delegation',
|
|
362
|
+
MISMATCH_REMEDY,
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const allAnswers = answersOf(item, ctx);
|
|
367
|
+
const currentPool =
|
|
368
|
+
item.state.state === 'user' || item.state.state === 'delegated'
|
|
369
|
+
? [item.state.answer]
|
|
370
|
+
: isObject(item.raw)
|
|
371
|
+
? [item.raw]
|
|
372
|
+
: [];
|
|
373
|
+
const pool = current ? currentPool : allAnswers.length > 0 ? allAnswers : currentPool;
|
|
374
|
+
const matching = pool.filter(answer => plates.every(plate => matchesCitationSurface(answer, plate.citation as JsonObject)));
|
|
375
|
+
if (matching.length === 0) {
|
|
376
|
+
if (current && allAnswers.some(answer => plates.every(plate => matchesCitationSurface(answer, plate.citation as JsonObject)))) {
|
|
377
|
+
sceneFail(SCENE_CHOICE_MISMATCH, 'scene.plates[0].citation', 'agent scene must cite the current post_composition choice or decided delegation', MISMATCH_REMEDY);
|
|
378
|
+
}
|
|
379
|
+
if (plates.length === 2 && pool.some(a => matchesCitationSurface(a, plates[0]!.citation as JsonObject)) && pool.some(a => matchesCitationSurface(a, plates[1]!.citation as JsonObject))) {
|
|
380
|
+
sceneFail(
|
|
381
|
+
SCENE_CHOICE_MISMATCH,
|
|
382
|
+
'scene.plates[1].citation',
|
|
383
|
+
'background and foreground plates must cite the same post_composition choice or decided delegation',
|
|
384
|
+
MISMATCH_REMEDY,
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
sceneFail('SCENE_CITATION_MISSING', 'scene.plates[0].citation', 'cite a recorded post_composition answer or decided delegation');
|
|
388
|
+
}
|
|
389
|
+
const validSpecs: AgentSceneSpec[] = [];
|
|
390
|
+
let firstError: unknown;
|
|
391
|
+
for (const answer of matching) {
|
|
392
|
+
try {
|
|
393
|
+
const { value, valuePath } = resolveAnswerValue(dir, item.path, answer, plates[0]!.citation as JsonObject, snapshots);
|
|
394
|
+
validSpecs.push(parseAgentSceneValue(value, valuePath));
|
|
395
|
+
} catch (error) {
|
|
396
|
+
if (!firstError) firstError = error;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (validSpecs.length === 0) throw firstError;
|
|
400
|
+
let firstMismatch: unknown;
|
|
401
|
+
for (const spec of validSpecs) {
|
|
402
|
+
try {
|
|
403
|
+
assertPlatesMatchSpec(plates, spec);
|
|
404
|
+
return;
|
|
405
|
+
} catch (error) {
|
|
406
|
+
if (!firstMismatch) firstMismatch = error;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
throw firstMismatch;
|
|
410
|
+
}
|