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,132 @@
|
|
|
1
|
+
/** Pure, conservative translation of current interview records; no producer or file reads. */
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import type { RigInvariants } from '@rig-c/core/rig';
|
|
4
|
+
import type { Json, JsonObject } from './templates.ts';
|
|
5
|
+
|
|
6
|
+
export const INVARIANTS_SPEC = 'rig-create/invariants@1';
|
|
7
|
+
export interface InvariantFrom { question: string; verbatim_sha256: string | null; }
|
|
8
|
+
export interface InvariantEntry {
|
|
9
|
+
invariant: RigInvariants;
|
|
10
|
+
from: InvariantFrom & { verbatim_sha256: string };
|
|
11
|
+
source_path: string;
|
|
12
|
+
value_path: string;
|
|
13
|
+
}
|
|
14
|
+
export interface InvariantGap {
|
|
15
|
+
gap: 'sentence_semantics' | 'vocabulary' | 'pending_answer' | 'pending_delegation' | 'pending_other' | 'inherited_answer' | 'not_applicable' | 'malformed_answer';
|
|
16
|
+
from: InvariantFrom;
|
|
17
|
+
source_path: string;
|
|
18
|
+
value_path: string;
|
|
19
|
+
sentence: string | null;
|
|
20
|
+
value: Json;
|
|
21
|
+
}
|
|
22
|
+
export interface InvariantsDocument {
|
|
23
|
+
spec: typeof INVARIANTS_SPEC;
|
|
24
|
+
/** Exact current records, including choice text, delegation reasons and additions; never history. */
|
|
25
|
+
sources: { question: string; path: string; record: Json }[];
|
|
26
|
+
entries: InvariantEntry[];
|
|
27
|
+
gaps: InvariantGap[];
|
|
28
|
+
}
|
|
29
|
+
const object = (v: Json | undefined): v is JsonObject => v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
30
|
+
const list = (v: Json | undefined): Json[] => Array.isArray(v) ? v : [];
|
|
31
|
+
const text = (v: Json | undefined): v is string => typeof v === 'string' && v.trim().length > 0;
|
|
32
|
+
const strings = (v: Json | undefined): v is string[] => Array.isArray(v) && v.length > 0 && v.every(text);
|
|
33
|
+
const keys = (v: JsonObject, allowed: string[]): boolean => Object.keys(v).every(k => allowed.includes(k));
|
|
34
|
+
const rows = (v: Json, predicate: (r: JsonObject) => boolean): boolean => Array.isArray(v) && v.length > 0 && v.every(r => object(r) && predicate(r));
|
|
35
|
+
const unique = (values: Json[]): boolean => new Set(values).size === values.length;
|
|
36
|
+
|
|
37
|
+
/** Only identically spelled, explicit structural readings qualify. No inference from part counts or prose. */
|
|
38
|
+
function structural(key: string, value: Json): RigInvariants | null {
|
|
39
|
+
let valid = false;
|
|
40
|
+
switch (key) {
|
|
41
|
+
case 'meshSlots': case 'meshTriangles': valid = typeof value === 'number' && Number.isSafeInteger(value) && value >= 0; break;
|
|
42
|
+
case 'axisBone': case 'massBone': valid = text(value); break;
|
|
43
|
+
case 'axes': valid = rows(value, r => keys(r, ['name', 'through', 'bones', 'tolerance']) && text(r.name)
|
|
44
|
+
&& strings(r.through) && r.through.length === 2 && unique(r.through) && strings(r.bones) && unique(r.bones)
|
|
45
|
+
&& typeof r.tolerance === 'number' && Number.isFinite(r.tolerance) && r.tolerance > 0 && r.tolerance < 90)
|
|
46
|
+
&& unique((value as JsonObject[]).map(r => r.name as Json)); break;
|
|
47
|
+
case 'detached': valid = rows(value, r => keys(r, ['bone', 'notUnder', 'why']) && text(r.bone) && text(r.notUnder) && (r.why === undefined || text(r.why))); break;
|
|
48
|
+
case 'deformMayFold': valid = rows(value, r => keys(r, ['slot', 'why']) && text(r.slot) && text(r.why))
|
|
49
|
+
&& unique((value as JsonObject[]).map(r => r.slot as Json)); break;
|
|
50
|
+
case 'consumerDrivenMix': valid = rows(value, r => keys(r, ['constraint', 'type', 'why']) && text(r.constraint) && (r.type === 'ik' || r.type === 'transform') && text(r.why))
|
|
51
|
+
&& unique((value as JsonObject[]).map(r => `${String(r.type)}:${String(r.constraint)}`)); break;
|
|
52
|
+
case 'idleDrivesMeshes': valid = object(value) && keys(value, ['why']) && text(value.why); break;
|
|
53
|
+
}
|
|
54
|
+
// Core resolves names and enforces the rig. Shape acceptance here is not a passed core check.
|
|
55
|
+
return valid ? { [key]: structuredClone(value) } as RigInvariants : null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function translateInvariants(project: JsonObject): InvariantsDocument {
|
|
59
|
+
const result: InvariantsDocument = { spec: INVARIANTS_SPEC, sources: [], entries: [], gaps: [] };
|
|
60
|
+
const visit = (question: string, path: string, raw: Json, addition = false): void => {
|
|
61
|
+
result.sources.push({ question, path, record: structuredClone(raw) });
|
|
62
|
+
const answer = object(raw) ? raw : {};
|
|
63
|
+
const sentence = typeof answer.verbatim === 'string' ? answer.verbatim : null;
|
|
64
|
+
const from: InvariantFrom = { question, verbatim_sha256: sentence === null ? null : createHash('sha256').update(sentence, 'utf8').digest('hex') };
|
|
65
|
+
const gap = (kind: InvariantGap['gap'], value_path: string, value: Json): void => {
|
|
66
|
+
result.gaps.push({ gap: kind, from: { ...from }, source_path: path, value_path, sentence, value: structuredClone(value) });
|
|
67
|
+
};
|
|
68
|
+
const leaves = (value: Json, at: string): void => {
|
|
69
|
+
if (Array.isArray(value) && value.length) value.forEach((v, i) => leaves(v, `${at}[${i}]`));
|
|
70
|
+
else if (object(value) && Object.keys(value).length) for (const [k, v] of Object.entries(value)) leaves(v, `${at}[${JSON.stringify(k)}]`);
|
|
71
|
+
else gap('vocabulary', at, value);
|
|
72
|
+
};
|
|
73
|
+
const reading = (value: Json, at: string): void => {
|
|
74
|
+
if (object(value)) {
|
|
75
|
+
if (!Object.keys(value).length) leaves(value, at);
|
|
76
|
+
for (const [k, v] of Object.entries(value)) {
|
|
77
|
+
const valuePath = `${at}[${JSON.stringify(k)}]`;
|
|
78
|
+
const invariant = sentence === null ? null : structural(k, v);
|
|
79
|
+
if (invariant !== null) result.entries.push({ invariant, from: { question, verbatim_sha256: from.verbatim_sha256 as string }, source_path: path, value_path: valuePath });
|
|
80
|
+
else leaves(v, valuePath);
|
|
81
|
+
}
|
|
82
|
+
} else leaves(value, at);
|
|
83
|
+
};
|
|
84
|
+
if (!object(raw)) gap(raw === null ? 'pending_answer' : 'malformed_answer', path, raw);
|
|
85
|
+
else if (answer.basis === 'inherited') gap('inherited_answer', path, raw);
|
|
86
|
+
else if (answer.not_applicable === true) gap('not_applicable', path, raw);
|
|
87
|
+
else {
|
|
88
|
+
// Retain ALL words, including concepts absent from value. This is an explicit semantic gap,
|
|
89
|
+
// not an NLP claim that the interpreter understood each sentence or verified agreement.
|
|
90
|
+
if (sentence !== null) gap('sentence_semantics', `${path}.verbatim`, sentence);
|
|
91
|
+
else gap('malformed_answer', path, raw);
|
|
92
|
+
if (!addition && answer.delegated !== true && answer.delegated !== false) gap('malformed_answer', path, raw);
|
|
93
|
+
if (answer.value !== undefined && (answer.delegated === false || addition)) {
|
|
94
|
+
// An Other-pending answer has value:null, but other picks/fragments are still retained below.
|
|
95
|
+
reading(answer.value, `${path}.value`);
|
|
96
|
+
}
|
|
97
|
+
const decision = object(answer.agent_decision) ? answer.agent_decision : null;
|
|
98
|
+
const decided = decision !== null && decision.value !== undefined && text(decision.reasoning);
|
|
99
|
+
if (decided) reading(decision.value as Json, `${path}.agent_decision.value`);
|
|
100
|
+
const asks = list(answer.asks).filter(object);
|
|
101
|
+
const delegated = asks.filter(a => a.state === 'delegated');
|
|
102
|
+
if (answer.delegated === true && !decided) gap('pending_delegation', `${path}.agent_decision`, answer.agent_decision ?? null);
|
|
103
|
+
else if (decision !== null && !decided && delegated.length === 0) gap('pending_delegation', `${path}.agent_decision`, decision);
|
|
104
|
+
for (const ask of delegated) {
|
|
105
|
+
const landed = decided && (!object(answer.choice) || list(decision?.fragments).some(f => object(f) && f.ask === ask.id && f.fragment !== undefined));
|
|
106
|
+
if (!landed) gap('pending_delegation', `${path}.asks[${String(ask.id)}]`, ask);
|
|
107
|
+
}
|
|
108
|
+
for (const ask of asks.filter(a => a.state === 'other-pending')) gap('pending_other', `${path}.asks[${String(ask.id)}]`, ask);
|
|
109
|
+
// Completed Other fragments are already in value. Only read picks while a pending
|
|
110
|
+
// Other suppresses that aggregate; no option-file reads or reassembly.
|
|
111
|
+
if (object(answer.choice)) list(answer.choice.picks).forEach((pick, i) => {
|
|
112
|
+
if (!object(pick)) return;
|
|
113
|
+
if (pick.other_text !== undefined) gap('sentence_semantics', `${path}.choice.picks[${i}].other_text`, pick.other_text);
|
|
114
|
+
if (asks.some(a => a.state === 'other-pending') && pick.other_fragment !== undefined) reading(pick.other_fragment, `${path}.choice.picks[${i}].other_fragment`);
|
|
115
|
+
});
|
|
116
|
+
if (answer.delegated === false && answer.value === undefined) gap('malformed_answer', `${path}.value`, null);
|
|
117
|
+
}
|
|
118
|
+
list(answer.additions).forEach((addition, i) => visit(question, `${path}.additions[${i}]`, addition, true));
|
|
119
|
+
};
|
|
120
|
+
const interview = object(project.interview) ? project.interview : {};
|
|
121
|
+
const collect = (records: Json[], prefix: string, field: string): void => {
|
|
122
|
+
records.forEach((record, i) => {
|
|
123
|
+
if (!object(record)) { visit(`${prefix}[${i}]`, `${prefix}[${i}]`, record); return; }
|
|
124
|
+
const question = typeof record.id === 'string' ? record.id : `${prefix}[${i}]`;
|
|
125
|
+
visit(question, `${prefix}[${question}].${field}`, record[field] ?? null);
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
collect(list(interview.framing), 'interview.framing', 'answer');
|
|
129
|
+
collect(list(interview.waypoints), 'interview.waypoints', 'guide');
|
|
130
|
+
collect(list(object(interview.post) ? interview.post.items : undefined), 'interview.post.items', 'guide');
|
|
131
|
+
return result;
|
|
132
|
+
}
|
package/src/job-acts.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** Writer routing for finalized acts. No event transport or automatic ingestion. */
|
|
2
|
+
import type { ActV3 } from '@rig-c/review/job-host';
|
|
3
|
+
import { asArray, isObject } from './check.ts';
|
|
4
|
+
import { stageOfStep } from './stages.ts';
|
|
5
|
+
import type { JsonObject } from './templates.ts';
|
|
6
|
+
|
|
7
|
+
export interface PendingJobAct {
|
|
8
|
+
actId: string;
|
|
9
|
+
kind: ActV3['kind'];
|
|
10
|
+
subject: string;
|
|
11
|
+
at: string;
|
|
12
|
+
args: string[] | null;
|
|
13
|
+
command: string | null;
|
|
14
|
+
unavailable?: { code: 'JOB_ACTS_WRITER_UNAVAILABLE'; message: string };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function shellWord(value: string): string {
|
|
18
|
+
return /^[A-Za-z0-9_./:-]+$/.test(value) ? value : `'${value.replaceAll("'", "'\\''")}'`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function pendingJobActs(project: JsonObject, acts: readonly ActV3[], root: string): PendingJobAct[] {
|
|
22
|
+
const ingested = new Set(asArray(project.review_acts).filter(isObject).map(row => JSON.stringify([row.jobId, row.actId])));
|
|
23
|
+
const signoffs = asArray(project.signoffs).filter(isObject);
|
|
24
|
+
const seen = new Set<string>();
|
|
25
|
+
return acts.flatMap(act => {
|
|
26
|
+
const key = JSON.stringify([act.jobId, act.actId]);
|
|
27
|
+
if (seen.has(key) || ingested.has(key) || signoffs.some(row => row.source === `review act ${act.jobId}/${act.actId}`)) return [];
|
|
28
|
+
seen.add(key);
|
|
29
|
+
let subject: string = act.kind;
|
|
30
|
+
let args: string[] | null = null;
|
|
31
|
+
switch (act.kind) {
|
|
32
|
+
case 'review-verdict': {
|
|
33
|
+
const selector = act.source.selector;
|
|
34
|
+
subject = act.value.stage;
|
|
35
|
+
if (selector && (selector.kind === 'rig' || selector.kind === 'post')
|
|
36
|
+
&& act.value.stage === (selector.kind === 'rig' ? 'rig-review' : 'direction-review')) {
|
|
37
|
+
subject = `${selector.kind} v${selector.version} / ${act.value.stage}`;
|
|
38
|
+
args = ['review', String(selector.version), root];
|
|
39
|
+
}
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
case 'parts-verdict': {
|
|
43
|
+
const selector = act.source.selector;
|
|
44
|
+
if (selector?.kind === 'draft') {
|
|
45
|
+
subject = `draft ${selector.id}`;
|
|
46
|
+
args = ['parts-review', root];
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case 'interview-picks':
|
|
51
|
+
subject = `question ${act.value.questionId}`;
|
|
52
|
+
args = ['interview-answer', act.value.questionId, root];
|
|
53
|
+
break;
|
|
54
|
+
case 'signoff':
|
|
55
|
+
subject = `stage ${act.value.stage}`;
|
|
56
|
+
args = ['signoff', act.value.stage, root];
|
|
57
|
+
break;
|
|
58
|
+
case 'checkpoint': {
|
|
59
|
+
const step = asArray(isObject(project.plan) ? project.plan.steps : undefined).filter(isObject).find(step => step.id === act.value.planStepId);
|
|
60
|
+
subject = `checkpoint ${act.value.planStepId}`;
|
|
61
|
+
if (step && (step.phase === 'rig' || step.phase === 'post')) {
|
|
62
|
+
const stage = stageOfStep(step.phase, String(step.id));
|
|
63
|
+
subject += ` / ${stage}`;
|
|
64
|
+
args = ['signoff', stage, root, '--checkpoint', act.value.planStepId];
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (args) args.push('--from-review', act.actId);
|
|
70
|
+
return [{ actId: act.actId, kind: act.kind, subject, at: act.at, args,
|
|
71
|
+
command: args ? ['rig-create', ...args].map(shellWord).join(' ') : null,
|
|
72
|
+
...(args ? {} : { unavailable: { code: 'JOB_ACTS_WRITER_UNAVAILABLE' as const,
|
|
73
|
+
message: `project.json: act ${act.actId} (${subject}) has no current writer target; restore its plan step or use a supported Review subject before ingestion` } }) }];
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function jobActsText(result: { acts: readonly PendingJobAct[] }): string {
|
|
78
|
+
if (!result.acts.length) return 'job: no finalized acts awaiting ingestion';
|
|
79
|
+
return result.acts.map(act => `${act.actId} ${act.kind} ${act.subject} at ${act.at}\n ${act.command ?? `${act.unavailable!.code}: ${act.unavailable!.message}`}`).join('\n');
|
|
80
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { existsSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { jobHash, jobPrivateRoot, readWriterBinding } from './job-outbox.ts';
|
|
4
|
+
import { publicationSelector } from './job-publication.ts';
|
|
5
|
+
import { acquireBoundJobWrite, prepareVersionIntent, publishCommittedVersion } from './job-writer.ts';
|
|
6
|
+
import { refuse } from './refusal.ts';
|
|
7
|
+
import { readVersions, type PostVersion, type RigVersion } from './review.ts';
|
|
8
|
+
import type { JsonObject } from './templates.ts';
|
|
9
|
+
|
|
10
|
+
export function isPublishAdvanceStage(stage: string): stage is 'rig-review' | 'direction-review' {
|
|
11
|
+
return stage === 'rig-review' || stage === 'direction-review';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function acquireAdvanceJobWrite(dir: string, stage: string): () => void {
|
|
15
|
+
return isPublishAdvanceStage(stage) ? acquireBoundJobWrite(dir) : () => {};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function currentAdvanceVersion(project: JsonObject, stage: 'rig-review' | 'direction-review'): number {
|
|
19
|
+
const versions = readVersions(project);
|
|
20
|
+
if (stage === 'rig-review') {
|
|
21
|
+
const current = versions.rigs.filter(r => r.live).reduce<RigVersion | null>((a, r) => (a === null || r.n > a.n ? r : a), null);
|
|
22
|
+
if (current === null) {
|
|
23
|
+
refuse('JOB_PUBLICATION_INVALID', 'versions: rig-review requires a live rig version to publish; record rig-create rig-version <n> before advancing');
|
|
24
|
+
}
|
|
25
|
+
return current.n;
|
|
26
|
+
}
|
|
27
|
+
const current = versions.posts.filter(p => p.live).reduce<PostVersion | null>((a, p) => (a === null || p.n > a.n ? p : a), null);
|
|
28
|
+
if (current === null) {
|
|
29
|
+
refuse('JOB_PUBLICATION_INVALID', 'versions: direction-review requires a live post version to publish; record rig-create direction write <n> before advancing');
|
|
30
|
+
}
|
|
31
|
+
return current.n;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function defaultWriteRecord(temp: string, target: string, bytes: Buffer): void {
|
|
35
|
+
writeFileSync(temp, bytes, { flag: 'wx' });
|
|
36
|
+
renameSync(temp, target);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function commitAdvance(
|
|
40
|
+
dir: string,
|
|
41
|
+
file: string,
|
|
42
|
+
project: JsonObject,
|
|
43
|
+
writeRecord: (temp: string, target: string, bytes: Buffer) => void = defaultWriteRecord,
|
|
44
|
+
): void {
|
|
45
|
+
const stage = String(project.stage);
|
|
46
|
+
const serialized = `${JSON.stringify(project, null, 2)}\n`;
|
|
47
|
+
if (!isPublishAdvanceStage(stage) || !readWriterBinding(dir)) {
|
|
48
|
+
writeFileSync(file, serialized);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const n = currentAdvanceVersion(project, stage);
|
|
52
|
+
publicationSelector(project, n);
|
|
53
|
+
const recordBytes = Buffer.from(serialized);
|
|
54
|
+
const publicationIntent = prepareVersionIntent(dir, recordBytes, n);
|
|
55
|
+
const temp = join(dir, `.project.json.advance-${process.pid}-${Date.now()}`);
|
|
56
|
+
try {
|
|
57
|
+
writeRecord(temp, file, recordBytes);
|
|
58
|
+
} finally {
|
|
59
|
+
rmSync(temp, { force: true });
|
|
60
|
+
if (publicationIntent && (!existsSync(file) || jobHash(readFileSync(file)) !== publicationIntent.recordHash)) {
|
|
61
|
+
rmSync(join(jobPrivateRoot(dir), 'outbox', `${publicationIntent.id}.json`), { force: true });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
publishCommittedVersion(dir, n);
|
|
65
|
+
}
|
package/src/job-close.ts
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { readFileSync, realpathSync, rmSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
4
|
+
import {
|
|
5
|
+
startJobHost,
|
|
6
|
+
type JobHostAttachFailure,
|
|
7
|
+
type JobHostOptions,
|
|
8
|
+
type JobHostReuseBinding,
|
|
9
|
+
type JobOwnerHost,
|
|
10
|
+
type JobPublicationReader,
|
|
11
|
+
} from '@rig-c/review/job-host';
|
|
12
|
+
import {
|
|
13
|
+
acquireJobLock,
|
|
14
|
+
JOB_BINDING_FILE,
|
|
15
|
+
pendingPublications,
|
|
16
|
+
readWriterBinding,
|
|
17
|
+
type JobIdentity,
|
|
18
|
+
type WriterBinding,
|
|
19
|
+
} from './job-outbox.ts';
|
|
20
|
+
import { refuse } from './refusal.ts';
|
|
21
|
+
|
|
22
|
+
function isAttachRefused(error: unknown): error is Extract<JobHostAttachFailure, { code: 'JOB_HOST_ATTACH_REFUSED' }> {
|
|
23
|
+
return typeof error === 'object' && error !== null
|
|
24
|
+
&& (error as { code?: unknown }).code === 'JOB_HOST_ATTACH_REFUSED'
|
|
25
|
+
&& typeof (error as { reason?: unknown }).reason === 'string'
|
|
26
|
+
&& typeof (error as { phase?: unknown }).phase === 'string';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isReuseMismatch(error: unknown): error is Extract<JobHostAttachFailure, { code: 'JOB_HOST_REUSE_MISMATCH' }> {
|
|
30
|
+
return typeof error === 'object' && error !== null
|
|
31
|
+
&& (error as { code?: unknown }).code === 'JOB_HOST_REUSE_MISMATCH'
|
|
32
|
+
&& typeof (error as { field?: unknown }).field === 'string'
|
|
33
|
+
&& 'expected' in error && 'actual' in error;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function closeReuseBinding(identity: JobIdentity): JobHostReuseBinding {
|
|
37
|
+
return {
|
|
38
|
+
root: identity.root,
|
|
39
|
+
stateDir: identity.stateDir,
|
|
40
|
+
fingerprint: identity.fingerprint,
|
|
41
|
+
reviewer: { id: identity.reviewer.id, role: identity.reviewer.role },
|
|
42
|
+
readerId: identity.readerId,
|
|
43
|
+
bindingId: identity.bindingId,
|
|
44
|
+
partsEnumeratorId: identity.partsEnumeratorId,
|
|
45
|
+
partsEnumeratorVersion: identity.enumeratorVersion,
|
|
46
|
+
apiSchema: identity.apiSchema as JobHostReuseBinding['apiSchema'],
|
|
47
|
+
actSchema: identity.actSchema as JobHostReuseBinding['actSchema'],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const failClosedCloseReadPublished: JobPublicationReader = async () => {
|
|
52
|
+
refuse('JOB_HOST_REUSE_MISMATCH', 'project.json: close attach must not invoke readPublished; reopen the live job at the current pin before publishing');
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export function failClosedCloseEnumerate(): never {
|
|
56
|
+
refuse('JOB_HOST_REUSE_MISMATCH', 'project.json: close attach must not invoke partsEnumerator.enumerate; reopen the live job at the current pin before publishing');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function failClosedCloseInstallBinding(): Promise<never> {
|
|
60
|
+
refuse('JOB_HOST_REUSE_MISMATCH', 'project.json: close attach must not install a writer binding');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function closeHostOptions(binding: WriterBinding): JobHostOptions {
|
|
64
|
+
const { identity } = binding;
|
|
65
|
+
return {
|
|
66
|
+
root: identity.root,
|
|
67
|
+
stateDir: identity.stateDir,
|
|
68
|
+
fingerprint: identity.fingerprint,
|
|
69
|
+
reviewer: { id: identity.reviewer.id, role: identity.reviewer.role },
|
|
70
|
+
readerId: identity.readerId,
|
|
71
|
+
readPublished: failClosedCloseReadPublished,
|
|
72
|
+
...(identity.publicationMode ? { publicationMode: identity.publicationMode, readRecordPublished: () => refuse('JOB_HOST_REUSE_MISMATCH', 'project.json: close attach must not invoke the record reader; reopen the live job before publishing') } : {}),
|
|
73
|
+
partsEnumeratorId: identity.partsEnumeratorId,
|
|
74
|
+
partsEnumerator: {
|
|
75
|
+
version: identity.enumeratorVersion,
|
|
76
|
+
enumerate: failClosedCloseEnumerate,
|
|
77
|
+
},
|
|
78
|
+
bindingId: identity.bindingId,
|
|
79
|
+
installWriterBinding: failClosedCloseInstallBinding,
|
|
80
|
+
reuseOnly: {
|
|
81
|
+
expected: {
|
|
82
|
+
jobId: binding.jobId,
|
|
83
|
+
origin: binding.origin,
|
|
84
|
+
listenerIncarnation: binding.listenerIncarnation,
|
|
85
|
+
binding: closeReuseBinding(identity),
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function assertStoredCloseBinding(root: string, binding: WriterBinding): void {
|
|
92
|
+
const identity = binding.identity as Partial<JobIdentity> | null | undefined;
|
|
93
|
+
if (
|
|
94
|
+
typeof identity !== 'object' || identity === null
|
|
95
|
+
|| typeof identity.root !== 'string'
|
|
96
|
+
|| typeof identity.stateDir !== 'string'
|
|
97
|
+
|| typeof identity.fingerprint !== 'string'
|
|
98
|
+
|| typeof identity.reviewer !== 'object' || identity.reviewer === null
|
|
99
|
+
|| typeof identity.reviewer.id !== 'string'
|
|
100
|
+
|| (identity.reviewer.role !== 'owner' && identity.reviewer.role !== 'delegate')
|
|
101
|
+
|| typeof identity.readerId !== 'string'
|
|
102
|
+
|| typeof identity.bindingId !== 'string'
|
|
103
|
+
|| typeof identity.partsEnumeratorId !== 'string'
|
|
104
|
+
|| typeof identity.apiSchema !== 'string'
|
|
105
|
+
|| typeof identity.actSchema !== 'string'
|
|
106
|
+
|| typeof identity.enumeratorVersion !== 'string'
|
|
107
|
+
) {
|
|
108
|
+
refuse('JOB_BINDING_INVALID', 'project.json: malformed private live-job binding; reopen the job through rig-create job open');
|
|
109
|
+
}
|
|
110
|
+
if (identity.root !== root) {
|
|
111
|
+
refuse('JOB_HOST_REUSE_MISMATCH', `project.json: root expected=${JSON.stringify(identity.root)} found=${JSON.stringify(root)}; restore the bound host configuration, then run rig-create job close`);
|
|
112
|
+
}
|
|
113
|
+
let project: { review_job?: unknown };
|
|
114
|
+
try {
|
|
115
|
+
const parsed: unknown = JSON.parse(readFileSync(join(root, 'project.json'), 'utf8'));
|
|
116
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) throw Error();
|
|
117
|
+
project = parsed as { review_job?: unknown };
|
|
118
|
+
} catch {
|
|
119
|
+
refuse('PROJECT_JSON_INVALID', 'project.json: project record is not a JSON object');
|
|
120
|
+
}
|
|
121
|
+
if (project.review_job !== undefined) {
|
|
122
|
+
if (
|
|
123
|
+
typeof project.review_job !== 'object' || project.review_job === null || Array.isArray(project.review_job)
|
|
124
|
+
|| typeof (project.review_job as { jobId?: unknown }).jobId !== 'string'
|
|
125
|
+
|| typeof (project.review_job as { origin?: unknown }).origin !== 'string'
|
|
126
|
+
) {
|
|
127
|
+
refuse('JOB_BINDING_INVALID', 'project.json: malformed review_job locator; reopen the job through rig-create job open');
|
|
128
|
+
}
|
|
129
|
+
const locator = project.review_job as { jobId: string; origin: string };
|
|
130
|
+
if (locator.jobId !== binding.jobId) {
|
|
131
|
+
refuse('JOB_HOST_REUSE_MISMATCH', `project.json: jobId expected=${JSON.stringify(locator.jobId)} found=${JSON.stringify(binding.jobId)}; restore the bound host configuration, then run rig-create job close`);
|
|
132
|
+
}
|
|
133
|
+
if (locator.origin !== binding.origin) {
|
|
134
|
+
refuse('JOB_HOST_REUSE_MISMATCH', `project.json: origin expected=${JSON.stringify(locator.origin)} found=${JSON.stringify(binding.origin)}; restore the bound host configuration, then run rig-create job close`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (!binding.listenerIncarnation) {
|
|
138
|
+
refuse('JOB_HOST_REUSE_MISMATCH', 'project.json: listenerIncarnation expected=a bound listener found=absent in the private binding; reopen the live job through rig-create job open, then run rig-create job close');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Close-only attachment boundary: uses the stored private binding's hook IDs and
|
|
144
|
+
* `enumeratorVersion` so a live host opened before a pin bump or reader ID bump can
|
|
145
|
+
* still be retired without weakening normal publication/reconcile/attach checks.
|
|
146
|
+
*/
|
|
147
|
+
export async function attachCreateJobForClose(
|
|
148
|
+
root: string,
|
|
149
|
+
binding: WriterBinding,
|
|
150
|
+
startHost: (options: JobHostOptions) => Promise<JobOwnerHost> = startJobHost,
|
|
151
|
+
): Promise<JobOwnerHost> {
|
|
152
|
+
assertStoredCloseBinding(root, binding);
|
|
153
|
+
let host: JobOwnerHost;
|
|
154
|
+
try {
|
|
155
|
+
host = await startHost(closeHostOptions(binding));
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if (isAttachRefused(error)) {
|
|
158
|
+
refuse('JOB_HOST_ATTACH_REFUSED', `project.json: live host attach refused (reason=${error.reason}, phase=${error.phase}); reopen or restore the bound live host before rig-create job close`);
|
|
159
|
+
}
|
|
160
|
+
if (isReuseMismatch(error)) {
|
|
161
|
+
refuse('JOB_HOST_REUSE_MISMATCH', `project.json: ${error.field} expected=${JSON.stringify(error.expected)} found=${JSON.stringify(error.actual)}; restore the bound host configuration, then run rig-create job close`);
|
|
162
|
+
}
|
|
163
|
+
if (error instanceof Error) {
|
|
164
|
+
const code = (error as Error & { code?: string }).code;
|
|
165
|
+
if (code === 'JOB_HOST_REUSE_MISMATCH') {
|
|
166
|
+
refuse('JOB_HOST_REUSE_MISMATCH', `project.json: ${error.message}; restore the bound host options before rig-create job close`);
|
|
167
|
+
}
|
|
168
|
+
if (code && ['JOB_REQUEST_INVALID', 'JOB_AUTHORITY_REFUSED', 'JOB_PARTS_ENUMERATOR_UNSUPPORTED', 'JOB_SOURCE_UNRETAINABLE'].includes(code)) {
|
|
169
|
+
refuse('JOB_BINDING_INVALID', `project.json: malformed private live-job binding (${code}); reopen the job through rig-create job open`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
if (!host.reused || host.session.jobId !== binding.jobId || host.origin !== binding.origin) {
|
|
175
|
+
host.stop();
|
|
176
|
+
refuse('JOB_HOST_REUSE_MISMATCH', `project.json: host incarnation expected=${binding.jobId}@${binding.origin} found=${host.session.jobId}@${host.origin} reused=${host.reused}; restore the original live host before rig-create job close`);
|
|
177
|
+
}
|
|
178
|
+
return host;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export async function closeCreateJob(
|
|
182
|
+
root: string,
|
|
183
|
+
startHost: (options: JobHostOptions) => Promise<JobOwnerHost> = startJobHost,
|
|
184
|
+
): Promise<void> {
|
|
185
|
+
root = realpathSync(root);
|
|
186
|
+
const release = acquireJobLock(root)!;
|
|
187
|
+
try {
|
|
188
|
+
if (pendingPublications(root).length) {
|
|
189
|
+
refuse('JOB_PUBLISH_PENDING', 'project.json: a committed publication remains pending; run rig-create job reconcile before closing');
|
|
190
|
+
}
|
|
191
|
+
const binding = readWriterBinding(root);
|
|
192
|
+
if (!binding) refuse('JOB_BINDING_INVALID', 'project.json: no writer-owned job binding; open the live job first');
|
|
193
|
+
const host = await attachCreateJobForClose(root, binding, startHost);
|
|
194
|
+
try {
|
|
195
|
+
try {
|
|
196
|
+
host.session.authorize('consumer', `Bearer ${binding.fetchCapability}`);
|
|
197
|
+
} catch {
|
|
198
|
+
refuse('JOB_BINDING_INVALID', 'project.json: writer binding fetchCapability is not authorized for the bound live job; restore the writer-owned binding before rig-create job close');
|
|
199
|
+
}
|
|
200
|
+
const response = await host.ports.handleJobApi(new Request(`${host.origin}/jobs/${binding.jobId}/api`, {
|
|
201
|
+
method: 'POST',
|
|
202
|
+
headers: { authorization: `Bearer ${host.session.hostCredentials().agent}`, 'content-type': 'application/json' },
|
|
203
|
+
body: JSON.stringify({
|
|
204
|
+
schema: binding.identity.apiSchema,
|
|
205
|
+
verb: 'close',
|
|
206
|
+
jobId: binding.jobId,
|
|
207
|
+
requestId: 'create-close',
|
|
208
|
+
idempotencyKey: 'create-close',
|
|
209
|
+
expectedGeneration: host.session.status().generation,
|
|
210
|
+
reason: 'producer-close',
|
|
211
|
+
}),
|
|
212
|
+
}));
|
|
213
|
+
const result = await response.json() as { ok: boolean };
|
|
214
|
+
if (!result.ok) refuse('JOB_BINDING_INVALID', 'project.json: review refused close; restore the bound live host and retry rig-create job close');
|
|
215
|
+
const current = readWriterBinding(root);
|
|
216
|
+
if (!current || !isDeepStrictEqual(current, binding)) {
|
|
217
|
+
refuse('JOB_BINDING_INVALID', 'project.json: private live-job binding changed during close; restore the writer-owned binding');
|
|
218
|
+
}
|
|
219
|
+
rmSync(join(root, JOB_BINDING_FILE));
|
|
220
|
+
} finally {
|
|
221
|
+
host.stop();
|
|
222
|
+
}
|
|
223
|
+
} finally {
|
|
224
|
+
release();
|
|
225
|
+
}
|
|
226
|
+
}
|