zorya-classifier 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE.md +13 -0
- package/README.md +139 -2
- package/dist/app/cli-arguments.d.ts +40 -0
- package/dist/app/cli-arguments.js +67 -0
- package/dist/app/cli-route.d.ts +3 -0
- package/dist/app/cli-route.js +40 -0
- package/dist/app/create-classifier.d.ts +33 -0
- package/dist/app/create-classifier.js +312 -0
- package/dist/app/extraction-files.d.ts +9 -0
- package/dist/app/extraction-files.js +28 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +77 -0
- package/dist/entities/boundary-view.d.ts +29 -0
- package/dist/entities/boundary-view.js +1 -0
- package/dist/entities/contracts.d.ts +471 -0
- package/dist/entities/contracts.js +97 -0
- package/dist/entities/cutout-raster.d.ts +7 -0
- package/dist/entities/cutout-raster.js +1 -0
- package/dist/entities/errors.d.ts +7 -0
- package/dist/entities/errors.js +16 -0
- package/dist/entities/object-proposals.d.ts +53 -0
- package/dist/entities/object-proposals.js +8 -0
- package/dist/entities/representation.d.ts +225 -0
- package/dist/entities/representation.js +33 -0
- package/dist/entities/segmentation-metadata.d.ts +11 -0
- package/dist/entities/segmentation-metadata.js +1 -0
- package/dist/entities/segmentation-verification.d.ts +30 -0
- package/dist/entities/segmentation-verification.js +1 -0
- package/dist/entities/segmentation.d.ts +159 -0
- package/dist/entities/segmentation.js +5 -0
- package/dist/entities/whole-object.d.ts +128 -0
- package/dist/entities/whole-object.js +7 -0
- package/dist/features/choice-beam-layout.d.ts +18 -0
- package/dist/features/choice-beam-layout.js +136 -0
- package/dist/features/choice.d.ts +4 -0
- package/dist/features/choice.js +83 -0
- package/dist/features/prompts.d.ts +8 -0
- package/dist/features/prompts.js +56 -0
- package/dist/features/segmentation/box-check.d.ts +10 -0
- package/dist/features/segmentation/box-check.js +299 -0
- package/dist/features/segmentation/mask.d.ts +6 -0
- package/dist/features/segmentation/mask.js +89 -0
- package/dist/features/segmentation/packed-mask.d.ts +5 -0
- package/dist/features/segmentation/packed-mask.js +53 -0
- package/dist/features/uniform-grid.d.ts +3 -0
- package/dist/features/uniform-grid.js +35 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +2 -0
- package/dist/infrastructure/boundary-view.d.ts +2 -0
- package/dist/infrastructure/boundary-view.js +263 -0
- package/dist/infrastructure/openrouter-common.d.ts +130 -0
- package/dist/infrastructure/openrouter-common.js +317 -0
- package/dist/infrastructure/openrouter-vision.d.ts +11 -0
- package/dist/infrastructure/openrouter-vision.js +17 -0
- package/dist/infrastructure/openrouter.d.ts +19 -0
- package/dist/infrastructure/openrouter.js +207 -0
- package/dist/infrastructure/raster.d.ts +11 -0
- package/dist/infrastructure/raster.js +216 -0
- package/dist/infrastructure/segmentation/box-presentation.d.ts +2 -0
- package/dist/infrastructure/segmentation/box-presentation.js +136 -0
- package/dist/infrastructure/segmentation/cutout-raster.d.ts +3 -0
- package/dist/infrastructure/segmentation/cutout-raster.js +79 -0
- package/dist/infrastructure/segmentation/grabcut/index.d.ts +13 -0
- package/dist/infrastructure/segmentation/grabcut/index.js +118 -0
- package/dist/infrastructure/segmentation/grabcut/worker-inference.d.ts +47 -0
- package/dist/infrastructure/segmentation/grabcut/worker-inference.js +260 -0
- package/dist/infrastructure/segmentation/index.d.ts +2 -0
- package/dist/infrastructure/segmentation/index.js +2 -0
- package/dist/infrastructure/segmentation/mobile-sam/index.d.ts +58 -0
- package/dist/infrastructure/segmentation/mobile-sam/index.js +472 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-inference.d.ts +149 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-inference.js +845 -0
- package/dist/infrastructure/segmentation/native-child.d.ts +23 -0
- package/dist/infrastructure/segmentation/native-child.js +297 -0
- package/dist/infrastructure/segmentation/native-protocol.d.ts +923 -0
- package/dist/infrastructure/segmentation/native-protocol.js +242 -0
- package/dist/infrastructure/segmentation/native-worker.d.ts +1 -0
- package/dist/infrastructure/segmentation/native-worker.js +93 -0
- package/dist/infrastructure/segmentation/probe-backend.d.ts +1 -0
- package/dist/infrastructure/segmentation/probe-backend.js +31 -0
- package/dist/infrastructure/segmentation/proposal-presentation.d.ts +3 -0
- package/dist/infrastructure/segmentation/proposal-presentation.js +371 -0
- package/dist/infrastructure/segmentation/verify-asset.d.ts +4 -0
- package/dist/infrastructure/segmentation/verify-asset.js +32 -0
- package/dist/infrastructure/text-representation.d.ts +23 -0
- package/dist/infrastructure/text-representation.js +226 -0
- package/dist/infrastructure/vision-chat.d.ts +64 -0
- package/dist/infrastructure/vision-chat.js +318 -0
- package/dist/openai-compatible.d.ts +8 -0
- package/dist/openai-compatible.js +11 -0
- package/dist/openrouter.d.ts +4 -0
- package/dist/openrouter.js +2 -0
- package/dist/processes/boundary-state.d.ts +12 -0
- package/dist/processes/boundary-state.js +196 -0
- package/dist/processes/classify.d.ts +3 -0
- package/dist/processes/classify.js +39 -0
- package/dist/processes/extract-from-region.d.ts +19 -0
- package/dist/processes/extract-from-region.js +415 -0
- package/dist/processes/extract.d.ts +25 -0
- package/dist/processes/extract.js +223 -0
- package/dist/processes/locate.d.ts +3 -0
- package/dist/processes/locate.js +274 -0
- package/dist/processes/proposal-location.d.ts +19 -0
- package/dist/processes/proposal-location.js +396 -0
- package/dist/processes/whole-object.d.ts +7 -0
- package/dist/processes/whole-object.js +272 -0
- package/dist/segmentation.d.ts +10 -0
- package/dist/segmentation.js +4 -0
- package/dist/shared/choice-mass.d.ts +2 -0
- package/dist/shared/choice-mass.js +19 -0
- package/dist/shared/gate.d.ts +11 -0
- package/dist/shared/gate.js +52 -0
- package/dist/shared/input-budget.d.ts +7 -0
- package/dist/shared/input-budget.js +21 -0
- package/dist/shared/scope.d.ts +12 -0
- package/dist/shared/scope.js +29 -0
- package/docs/0.2.0-plan.md +190 -0
- package/docs/README.ru.md +258 -0
- package/docs/acceptance.md +144 -0
- package/docs/api.md +49 -0
- package/docs/architecture.md +45 -0
- package/docs/benchmarks.md +63 -0
- package/docs/categorical-presence-port.md +26 -0
- package/docs/evidence/current-linux-check.json +15 -0
- package/docs/evidence/decisions-completion-v1-manifest.json +96 -0
- package/docs/evidence/decisions-completion-v1-report.json +1205 -0
- package/docs/evidence/decisions-selection-v1-manifest.json +96 -0
- package/docs/evidence/decisions-selection-v1-report.json +1457 -0
- package/docs/evidence/jev-pricing-2026-10-18.json +69 -0
- package/docs/evidence/linux-check.json +20 -0
- package/docs/evidence/linux-check.txt +205 -0
- package/docs/evidence/live-release-smoke-manifest.json +82 -0
- package/docs/evidence/live-release-smoke-provenance.json +9 -0
- package/docs/evidence/live-release-smoke-report.json +2136 -0
- package/docs/evidence/live-v1-manifest.json +84 -0
- package/docs/evidence/live-v1-provenance.json +9 -0
- package/docs/evidence/live-v1-report.json +15555 -0
- package/docs/evidence/luna-decisions-fine-probe.json +19 -0
- package/docs/evidence/luna-decisions-locator-smoke-manifest.json +39 -0
- package/docs/evidence/luna-decisions-locator-smoke-report.json +149 -0
- package/docs/evidence/pack-check.json +26 -0
- package/docs/evidence/protocol-probes.json +61 -0
- package/docs/evidence/rejected-vision-selection-v1-qwen-photo-dev-01.json +42 -0
- package/docs/evidence/rejected-vision-selection-v1-qwen-photo-dev-17.json +42 -0
- package/docs/evidence/rejected-vision-selection-v1-qwen-photo-heldout-09.json +42 -0
- package/docs/evidence/rejected-vision-selection-v2-haiku-photo-dev-16.json +42 -0
- package/docs/evidence/rejected-vision-selection-v2-haiku-support-heldout-016.json +42 -0
- package/docs/evidence/v02/baseline.json +1043 -0
- package/docs/evidence/v02/boundary-variants.md +17 -0
- package/docs/evidence/v02/box-confirmation-dev40/README.md +15 -0
- package/docs/evidence/v02/box-confirmation-dev40/component-refinement.json +246 -0
- package/docs/evidence/v02/box-confirmation-dev40/evaluation.json +1663 -0
- package/docs/evidence/v02/box-confirmation-dev40/provenance.json +130 -0
- package/docs/evidence/v02/box-confirmation-dev40/report.json +127 -0
- package/docs/evidence/v02/box-confirmation-dev40-freeze-20261020-v1.json +230 -0
- package/docs/evidence/v02/box-confirmation-method-selection-20261020-v1.json +85 -0
- package/docs/evidence/v02/box-heldout-cancelled-before-dispatch-20261021-v1.json +32 -0
- package/docs/evidence/v02/box-heldout-combined-seal-20261021-v1.json +89 -0
- package/docs/evidence/v02/box-heldout-evaluator-truth-seal-20261021-v1.json +61 -0
- package/docs/evidence/v02/box-heldout-exclusion-audit-20261020-v1.json +81 -0
- package/docs/evidence/v02/box-heldout-map-seal-20261021-v1.json +48 -0
- package/docs/evidence/v02/box-heldout-photo-seal-20261020-v1.json +62 -0
- package/docs/evidence/v02/box-heldout-run-freeze-20261021-v1.json +61 -0
- package/docs/evidence/v02/box-heldout-source-review-20261020-v1.json +134 -0
- package/docs/evidence/v02/box-heldout-ui-seal-20261020-v1.json +44 -0
- package/docs/evidence/v02/calculator-proof-root-review-20261020-v1.json +63 -0
- package/docs/evidence/v02/categorical-dev40-freeze.json +94 -0
- package/docs/evidence/v02/categorical-dev40-preserve.json +460 -0
- package/docs/evidence/v02/categorical-dev40-target-only.json +460 -0
- package/docs/evidence/v02/categorical-heldout-admission-20261020-v3.json +215 -0
- package/docs/evidence/v02/categorical-heldout-admission-20261020-v4.json +270 -0
- package/docs/evidence/v02/categorical-heldout-dispatch-authorization-20261020-v4.json +79 -0
- package/docs/evidence/v02/categorical-heldout-predispatch-20261020-v3.json +57 -0
- package/docs/evidence/v02/categorical-heldout-producer-source-map-v4.json +262 -0
- package/docs/evidence/v02/categorical-heldout-producer-source-map.json +263 -0
- package/docs/evidence/v02/categorical-heldout-run-freeze-20261020-v3.json +35 -0
- package/docs/evidence/v02/categorical-heldout-run-freeze-20261020-v4.json +35 -0
- package/docs/evidence/v02/categorical-heldout-v4/README.md +35 -0
- package/docs/evidence/v02/categorical-heldout-v4/candidate-evaluation.json +2812 -0
- package/docs/evidence/v02/categorical-heldout-v4/candidate-physical-receipts.json +15261 -0
- package/docs/evidence/v02/categorical-heldout-v4/candidate-provenance.json +131 -0
- package/docs/evidence/v02/categorical-heldout-v4/control-evaluation.json +855 -0
- package/docs/evidence/v02/categorical-heldout-v4/control-physical-receipts.json +4402 -0
- package/docs/evidence/v02/categorical-heldout-v4/control-provenance.json +31 -0
- package/docs/evidence/v02/categorical-heldout-v4/mask-normalized-exploratory.json +682 -0
- package/docs/evidence/v02/categorical-heldout-v4/paired-qualification.json +21 -0
- package/docs/evidence/v02/categorical-heldout-v4/report.json +258 -0
- package/docs/evidence/v02/categorical-presence-dev6.json +144 -0
- package/docs/evidence/v02/categorical-presence-dev6.md +18 -0
- package/docs/evidence/v02/categorical-vision-method-selection.json +90 -0
- package/docs/evidence/v02/checked-region-component-v1/README.md +7 -0
- package/docs/evidence/v02/checked-region-component-v1/evidence.json +311 -0
- package/docs/evidence/v02/checked-region-resource-interrupted-2b0d09f.json +102 -0
- package/docs/evidence/v02/checked-region-segmentation-resource-4df544c-receipt.json +167 -0
- package/docs/evidence/v02/checked-region-segmentation-resource-4df544c-root-review.json +58 -0
- package/docs/evidence/v02/checked-region-segmentation-resource-987ac32-receipt.json +158 -0
- package/docs/evidence/v02/ci-012b935.json +17 -0
- package/docs/evidence/v02/ci-0c365cb.json +372 -0
- package/docs/evidence/v02/ci-185bde8.json +32 -0
- package/docs/evidence/v02/ci-24f849f.json +95 -0
- package/docs/evidence/v02/ci-25c19cd.json +375 -0
- package/docs/evidence/v02/ci-2922caf.json +375 -0
- package/docs/evidence/v02/ci-29357d7.json +29 -0
- package/docs/evidence/v02/ci-32aa90d.json +24 -0
- package/docs/evidence/v02/ci-35e3064.json +376 -0
- package/docs/evidence/v02/ci-4331b1b.json +384 -0
- package/docs/evidence/v02/ci-43b7426.json +376 -0
- package/docs/evidence/v02/ci-450439c.json +373 -0
- package/docs/evidence/v02/ci-46283fe.json +29 -0
- package/docs/evidence/v02/ci-4c9c09f.json +34 -0
- package/docs/evidence/v02/ci-5579646.json +27 -0
- package/docs/evidence/v02/ci-6f9cc15.json +127 -0
- package/docs/evidence/v02/ci-7c1051f.json +27 -0
- package/docs/evidence/v02/ci-9837888.json +34 -0
- package/docs/evidence/v02/ci-987ac32.json +29 -0
- package/docs/evidence/v02/ci-9d00fe5.json +25 -0
- package/docs/evidence/v02/ci-9f85acc.json +127 -0
- package/docs/evidence/v02/ci-be275a6.json +201 -0
- package/docs/evidence/v02/ci-c107ddf.json +372 -0
- package/docs/evidence/v02/ci-c35f67d.json +127 -0
- package/docs/evidence/v02/ci-c5eddd8.json +32 -0
- package/docs/evidence/v02/ci-d2042e0.json +372 -0
- package/docs/evidence/v02/ci-d684259.json +375 -0
- package/docs/evidence/v02/ci-e0c190b.json +127 -0
- package/docs/evidence/v02/ci-e551253.json +372 -0
- package/docs/evidence/v02/ci-f9d4633.json +29 -0
- package/docs/evidence/v02/dev1-proposal-evaluation.md +13 -0
- package/docs/evidence/v02/dev2-mobile-sam-proposal-oracle.md +21 -0
- package/docs/evidence/v02/dev2-proposal-evaluation.md +21 -0
- package/docs/evidence/v02/fresh-development.md +16 -0
- package/docs/evidence/v02/fresh-native-numeric/artifact-hashes.json +9 -0
- package/docs/evidence/v02/fresh-native-numeric/evaluation-root-v1.json +568 -0
- package/docs/evidence/v02/fresh-native-numeric/run-manifest.json +342 -0
- package/docs/evidence/v02/fresh-native-numeric/summary.json +5654 -0
- package/docs/evidence/v02/fresh-native-outline-axis/artifact-hashes.json +9 -0
- package/docs/evidence/v02/fresh-native-outline-axis/evaluation-root-v1.json +568 -0
- package/docs/evidence/v02/fresh-native-outline-axis/run-manifest.json +378 -0
- package/docs/evidence/v02/fresh-native-outline-axis/summary.json +5605 -0
- package/docs/evidence/v02/fresh-text/README.md +23 -0
- package/docs/evidence/v02/fresh-text/ascii-contours-v1/classify-followup-run-manifest.json +405 -0
- package/docs/evidence/v02/fresh-text/ascii-contours-v1/classify-followup-summary.json +1646 -0
- package/docs/evidence/v02/fresh-text/ascii-contours-v1/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/ascii-contours-v1/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/ascii-contours-v1/original-summary.json +4416 -0
- package/docs/evidence/v02/fresh-text/ascii-luma-v1/classify-followup-run-manifest.json +405 -0
- package/docs/evidence/v02/fresh-text/ascii-luma-v1/classify-followup-summary.json +1646 -0
- package/docs/evidence/v02/fresh-text/ascii-luma-v1/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/ascii-luma-v1/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/ascii-luma-v1/original-summary.json +4647 -0
- package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/classify-followup-run-manifest.json +405 -0
- package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/classify-followup-summary.json +846 -0
- package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/original-summary.json +1789 -0
- package/docs/evidence/v02/fresh-text/no-image-control/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/no-image-control/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/no-image-control/original-summary.json +3953 -0
- package/docs/evidence/v02/fresh-text/palette-grid-v1/classify-followup-run-manifest.json +405 -0
- package/docs/evidence/v02/fresh-text/palette-grid-v1/classify-followup-summary.json +1646 -0
- package/docs/evidence/v02/fresh-text/palette-grid-v1/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/palette-grid-v1/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/palette-grid-v1/original-summary.json +3974 -0
- package/docs/evidence/v02/fresh-text/pixel-rle-v1/classify-followup-run-manifest.json +405 -0
- package/docs/evidence/v02/fresh-text/pixel-rle-v1/classify-followup-summary.json +1646 -0
- package/docs/evidence/v02/fresh-text/pixel-rle-v1/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/pixel-rle-v1/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/pixel-rle-v1/original-summary.json +4945 -0
- package/docs/evidence/v02/fresh-text/report.json +284 -0
- package/docs/evidence/v02/fresh-text/svg-contours-v1/classify-followup-run-manifest.json +405 -0
- package/docs/evidence/v02/fresh-text/svg-contours-v1/classify-followup-summary.json +846 -0
- package/docs/evidence/v02/fresh-text/svg-contours-v1/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/svg-contours-v1/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/svg-contours-v1/original-summary.json +2189 -0
- package/docs/evidence/v02/heldout-evaluation-20261020.md +37 -0
- package/docs/evidence/v02/heldout-input-derivation.md +18 -0
- package/docs/evidence/v02/integration-0c365cb.json +90 -0
- package/docs/evidence/v02/integration-25c19cd.json +52 -0
- package/docs/evidence/v02/integration-35e3064.json +41 -0
- package/docs/evidence/v02/integration-4331b1b.json +42 -0
- package/docs/evidence/v02/integration-4c9c09f.json +46 -0
- package/docs/evidence/v02/integration-8010aad.json +48 -0
- package/docs/evidence/v02/integration-c1aa640.json +41 -0
- package/docs/evidence/v02/integration-eea1790.json +46 -0
- package/docs/evidence/v02/integration-fa82e65.json +42 -0
- package/docs/evidence/v02/jpeg-transport-offline.json +268 -0
- package/docs/evidence/v02/jpeg-transport-offline.md +7 -0
- package/docs/evidence/v02/local-archive-cleanup.json +59 -0
- package/docs/evidence/v02/native-base64-after.json +30 -0
- package/docs/evidence/v02/native-base64-before.json +32 -0
- package/docs/evidence/v02/native-checked-region-windows-46283fe.json +248 -0
- package/docs/evidence/v02/native-checked-region-windows-987ac32.json +141 -0
- package/docs/evidence/v02/native-grabcut-windows-4c494a3-run2.json +148 -0
- package/docs/evidence/v02/native-grabcut-windows-4c494a3-run3.json +148 -0
- package/docs/evidence/v02/native-grabcut-windows-4c494a3.json +56 -0
- package/docs/evidence/v02/native-proposal-windows-0c365cb.json +148 -0
- package/docs/evidence/v02/native-proposal-windows-450439c.json +156 -0
- package/docs/evidence/v02/native-proposal-windows-4c9c09f-retry1.json +147 -0
- package/docs/evidence/v02/native-proposal-windows-4c9c09f.json +52 -0
- package/docs/evidence/v02/native-region-windows-efc9318.json +163 -0
- package/docs/evidence/v02/native-windows-eea1790-baseline.json +198 -0
- package/docs/evidence/v02/native-windows-eea1790.json +228 -0
- package/docs/evidence/v02/ordinary-luna-axis/run-manifest.json +99 -0
- package/docs/evidence/v02/ordinary-luna-axis/summary.json +811 -0
- package/docs/evidence/v02/owned-temp-cleanup-20261020-v1.json +28 -0
- package/docs/evidence/v02/presentation-paired-20261020.json +1438 -0
- package/docs/evidence/v02/proposal-resource-soak-261dc23.json +201 -0
- package/docs/evidence/v02/proposal-resource-soak-261dc23.md +15 -0
- package/docs/evidence/v02/proposal-resource-soak-450439c-receipt.md +13 -0
- package/docs/evidence/v02/reconstructed-c03-box.json +41 -0
- package/docs/evidence/v02/region-seeded-dev-v1/README.md +17 -0
- package/docs/evidence/v02/region-seeded-dev-v1/evaluation.json +260 -0
- package/docs/evidence/v02/region-seeded-dev-v2/README.md +15 -0
- package/docs/evidence/v02/region-seeded-dev-v2/evaluation.json +232 -0
- package/docs/evidence/v02/region-seeded-dev-v3-candidate-only/README.md +9 -0
- package/docs/evidence/v02/region-seeded-dev-v3-candidate-only/control-identity-failure.json +22 -0
- package/docs/evidence/v02/region-seeded-dev-v3-candidate-only/evaluation.json +160 -0
- package/docs/evidence/v02/region-seeded-dev-v3-control-r2/README.md +9 -0
- package/docs/evidence/v02/region-seeded-dev-v3-control-r2/attempt-accounting.json +55 -0
- package/docs/evidence/v02/region-seeded-dev-v3-control-r2/evaluation.json +136 -0
- package/docs/evidence/v02/region-seeded-development-control-r2-freeze-20261021.json +132 -0
- package/docs/evidence/v02/region-seeded-development-freeze-20261021-v1.json +167 -0
- package/docs/evidence/v02/region-seeded-development-freeze-20261021-v2.json +186 -0
- package/docs/evidence/v02/region-seeded-development-freeze-20261021-v3.json +205 -0
- package/docs/evidence/v02/region-seeded-heldout-cancelled-before-dispatch-20261021-v2.json +20 -0
- package/docs/evidence/v02/region-seeded-heldout-dispatch-authorization-20261021-v3.json +47 -0
- package/docs/evidence/v02/region-seeded-heldout-readiness-audit-20261021-v3.json +125 -0
- package/docs/evidence/v02/region-seeded-heldout-run-freeze-20261021-v2.json +234 -0
- package/docs/evidence/v02/region-seeded-heldout-run-freeze-20261021-v3.json +357 -0
- package/docs/evidence/v02/region-seeded-heldout-v3/README.md +19 -0
- package/docs/evidence/v02/region-seeded-heldout-v3/evaluation-summary.json +445 -0
- package/docs/evidence/v02/region-seeded-method-selection-20261021-v2.json +66 -0
- package/docs/evidence/v02/region-seeded-method-selection-20261021-v3.json +120 -0
- package/docs/evidence/v02/region-segmentation-resource-0ba4c87-receipt.json +156 -0
- package/docs/evidence/v02/resource-soak-linux-8010aad.json +125 -0
- package/docs/evidence/v02/screen-v2-terminal-evaluation.md +22 -0
- package/docs/evidence/v02/seed-outline/run-manifest.json +59 -0
- package/docs/evidence/v02/seed-outline/summary.json +487 -0
- package/docs/evidence/v02/seed-unbounded/run-manifest.json +80 -0
- package/docs/evidence/v02/seed-unbounded/summary.json +730 -0
- package/docs/evidence/v02/segmentation/README.md +21 -0
- package/docs/evidence/v02/segmentation/component-comparison-summary.json +240 -0
- package/docs/evidence/v02/segmentation/provenance/MOBILE-SAM-LICENSE.txt +201 -0
- package/docs/evidence/v02/segmentation/provenance/OPENCV-LICENSE.txt +202 -0
- package/docs/evidence/v02/segmentation/provenance/mobile-sam-download-receipt.json +29 -0
- package/docs/evidence/v02/segmentation/provenance/mobile-sam-graph-audit.json +214 -0
- package/docs/evidence/v02/segmentation/provenance/mobile-sam-model-metadata.json +166 -0
- package/docs/evidence/v02/split-choice-noul-dev6.json +72 -0
- package/docs/evidence/v02/split-choice-noul-dev6.md +11 -0
- package/docs/evidence/v02/supported-vision-screen-20261020.md +65 -0
- package/docs/evidence/v02/wesnoth-1.16.11-minimap-projection-source-audit.md +56 -0
- package/docs/evidence/v02/wesnoth-proof-root-review-20261020-v1.json +76 -0
- package/docs/evidence/vision-cost-reconciliation.json +37 -0
- package/docs/evidence/vision-model-summary.json +562 -0
- package/docs/evidence/vision-selection-v1-manifest.json +95 -0
- package/docs/evidence/vision-selection-v1-report.json +4598 -0
- package/docs/evidence/vision-selection-v2-manifest.json +95 -0
- package/docs/evidence/vision-selection-v2-report.json +1139 -0
- package/docs/evidence/windows-native.json +73 -0
- package/docs/evidence/windows-secrets.json +46 -0
- package/docs/operations.md +21 -0
- package/docs/plan.md +27 -0
- package/docs/provenance.json +32 -0
- package/docs/publishing.md +30 -0
- package/docs/research/text-transport-audit.md +66 -0
- package/docs/results.md +69 -0
- package/docs/v02-usage.md +162 -0
- package/docs/vision-results.md +78 -0
- package/package.json +114 -4
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DecisionPort, RasterPort } from '../entities/contracts.js';
|
|
2
|
+
import type { ImageRepresentationPort } from '../entities/representation.js';
|
|
3
|
+
import type { BoundaryViewPort } from '../entities/boundary-view.js';
|
|
4
|
+
import type { WholeObjectLocateInput, WholeObjectLocalizationResult } from '../entities/whole-object.js';
|
|
5
|
+
export type WholeObjectIntervalPolicy = 'fixed-16-v1' | 'tolerance-aware-v1';
|
|
6
|
+
/** Seed a physical instance, then narrow its four visible source-space boundaries with closed interval Choices. */
|
|
7
|
+
export declare function locateWholeObjectInput(input: Omit<WholeObjectLocateInput, 'signal'>, decision: DecisionPort, raster: RasterPort, signal: AbortSignal, representation?: ImageRepresentationPort, boundaryView?: BoundaryViewPort, intervalPolicy?: WholeObjectIntervalPolicy): Promise<WholeObjectLocalizationResult>;
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { parse } from '../entities/contracts.js';
|
|
3
|
+
import { assertActive, ClassifierError } from '../entities/errors.js';
|
|
4
|
+
import { wholeObjectSchema } from '../entities/whole-object.js';
|
|
5
|
+
import { validateDecision } from '../features/choice.js';
|
|
6
|
+
import { targetState } from '../features/prompts.js';
|
|
7
|
+
import { prepareBoundaryState } from './boundary-state.js';
|
|
8
|
+
import { locateInput } from './locate.js';
|
|
9
|
+
const axisOrder = ['left', 'right', 'top', 'bottom'];
|
|
10
|
+
const boundaryResponseSchema = z
|
|
11
|
+
.object({
|
|
12
|
+
status: z.literal('known'),
|
|
13
|
+
interval: z.object({ start: z.number().int(), endExclusive: z.number().int() }).strict(),
|
|
14
|
+
})
|
|
15
|
+
.strict();
|
|
16
|
+
function partition(interval, tolerancePx, policy) {
|
|
17
|
+
const length = interval.endExclusive - interval.start;
|
|
18
|
+
if (!Number.isSafeInteger(length) || length < 1)
|
|
19
|
+
return [];
|
|
20
|
+
const count = policy === 'tolerance-aware-v1'
|
|
21
|
+
? Math.min(16, Math.max(1, Math.ceil(length / tolerancePx)))
|
|
22
|
+
: Math.min(16, length);
|
|
23
|
+
return Array.from({ length: count }, (_, i) => {
|
|
24
|
+
const start = interval.start + Math.floor((i * length) / count);
|
|
25
|
+
const endExclusive = interval.start + Math.floor(((i + 1) * length) / count);
|
|
26
|
+
return { start, endExclusive };
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function boundsFor(region) {
|
|
30
|
+
return {
|
|
31
|
+
left: { start: region.left, endExclusive: region.left + region.width },
|
|
32
|
+
right: { start: region.left, endExclusive: region.left + region.width },
|
|
33
|
+
top: { start: region.top, endExclusive: region.top + region.height },
|
|
34
|
+
bottom: { start: region.top, endExclusive: region.top + region.height },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function boundaryInstruction(axis) {
|
|
38
|
+
const edge = axis === 'left' ? 'left' : axis === 'right' ? 'right' : axis === 'top' ? 'top' : 'bottom';
|
|
39
|
+
return `Select the interval containing the ${edge}most visible pixel coordinate INSIDE HARD_ROI of the SAME physical instance identified by SEED. If the object continues outside HARD_ROI, locate only the visible intersection with that ROI; do not infer hidden parts. Coordinates use the original oriented source pixels. Choose only a supplied interval or unknown; do not infer free coordinates. The interval limits are half-open integer coordinate ranges. Current boundary intervals are candidate ranges, not new ROI limits.`;
|
|
40
|
+
}
|
|
41
|
+
function choicesFor(axis, current, tolerancePx, policy, showBoundaryView = false) {
|
|
42
|
+
const intervals = partition(current, tolerancePx, policy);
|
|
43
|
+
const labels = intervals.map((_, i) => `${axis}${String(i).padStart(2, '0')}`);
|
|
44
|
+
return {
|
|
45
|
+
intervals,
|
|
46
|
+
labels,
|
|
47
|
+
question: {
|
|
48
|
+
type: 'choice',
|
|
49
|
+
rankingSize: 1,
|
|
50
|
+
instructions: showBoundaryView
|
|
51
|
+
? `${boundaryInstruction(axis)} A separate boundary view uses X/Y display labels. Use the exact display-label-to-choice mapping in the request state; still select only one supplied closed interval or unknown.`
|
|
52
|
+
: boundaryInstruction(axis),
|
|
53
|
+
criteria: {
|
|
54
|
+
...Object.fromEntries(intervals.map((range, i) => [
|
|
55
|
+
labels[i],
|
|
56
|
+
`Integer boundary coordinates in [${range.start}, ${range.endExclusive}).`,
|
|
57
|
+
])),
|
|
58
|
+
unknown: 'The same seeded instance or its boundary cannot be identified reliably.',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function sameInstanceQuestion() {
|
|
64
|
+
return {
|
|
65
|
+
type: 'choice',
|
|
66
|
+
rankingSize: 1,
|
|
67
|
+
instructions: 'Using ORIGINAL and SEED, determine whether extent answers can track the same single visible physical instance represented by SEED. If multiple indistinguishable instances could be the seed, or identity cannot be resolved, choose ambiguous. Select only one supplied answer.',
|
|
68
|
+
criteria: {
|
|
69
|
+
same: 'The visible extent can be tracked to the exact same physical instance represented by SEED.',
|
|
70
|
+
different: 'The apparent extent may belong to a different matching instance than SEED.',
|
|
71
|
+
ambiguous: 'The seeded instance is not uniquely identifiable in the scene.',
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async function prepareState(raster, image, seed, target, exclusions, signal, representation) {
|
|
76
|
+
const seedImage = await raster.crop(image, seed, signal);
|
|
77
|
+
if (!representation) {
|
|
78
|
+
const original = await raster.imageState(image, signal);
|
|
79
|
+
const seedState = await raster.imageState(seedImage, signal);
|
|
80
|
+
return [...targetState(target, exclusions), 'ORIGINAL', ...original, 'SEED', ...seedState];
|
|
81
|
+
}
|
|
82
|
+
const views = [
|
|
83
|
+
{
|
|
84
|
+
id: 'source',
|
|
85
|
+
role: 'source',
|
|
86
|
+
image,
|
|
87
|
+
sourceRegion: { left: 0, top: 0, width: image.width, height: image.height },
|
|
88
|
+
},
|
|
89
|
+
{ id: 'seed', role: 'crop', image: seedImage, sourceRegion: seed },
|
|
90
|
+
];
|
|
91
|
+
const prepared = await representation.prepare({ source: image, views, signal });
|
|
92
|
+
return [
|
|
93
|
+
...targetState(target, exclusions),
|
|
94
|
+
'ORIGINAL AND SEED GEOMETRY',
|
|
95
|
+
JSON.stringify({ seedRegion: seed }),
|
|
96
|
+
...prepared.state,
|
|
97
|
+
];
|
|
98
|
+
}
|
|
99
|
+
function resultMetadata(image, stages, durationMs) {
|
|
100
|
+
return {
|
|
101
|
+
image: { width: image.width, height: image.height, coordinateSpace: 'oriented-source-pixels' },
|
|
102
|
+
stages,
|
|
103
|
+
durationMs,
|
|
104
|
+
knownCostUsd: stages.reduce((sum, stage) => sum + (stage.costUsd ?? 0), 0),
|
|
105
|
+
unknownCostCount: stages.filter((stage) => stage.costUsd === null).length,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function unknown(reason, metadata) {
|
|
109
|
+
return { status: 'unknown', reason, metadata };
|
|
110
|
+
}
|
|
111
|
+
function intervalWidth(interval) {
|
|
112
|
+
return interval.endExclusive - interval.start;
|
|
113
|
+
}
|
|
114
|
+
function selectedChoice(result, question, keys) {
|
|
115
|
+
const answer = result.answers[question];
|
|
116
|
+
if (!answer || (answer.type !== 'choice' && answer.type !== 'ranked-choice'))
|
|
117
|
+
throw new ClassifierError('INVALID_RESPONSE', `Missing closed Choice answer for ${question}`);
|
|
118
|
+
if (answer.type === 'ranked-choice') {
|
|
119
|
+
const choice = answer.ranking[0];
|
|
120
|
+
if (!choice || !keys.includes(choice))
|
|
121
|
+
throw new ClassifierError('INVALID_RESPONSE', 'Unknown ranked interval');
|
|
122
|
+
return choice;
|
|
123
|
+
}
|
|
124
|
+
const maximum = Math.max(...keys.map((key) => answer.probabilities[key] ?? -Infinity));
|
|
125
|
+
const choice = keys.find((key) => answer.probabilities[key] === maximum);
|
|
126
|
+
if (!choice)
|
|
127
|
+
throw new ClassifierError('INVALID_RESPONSE', 'Closed Choice has no winner');
|
|
128
|
+
return choice;
|
|
129
|
+
}
|
|
130
|
+
function finalRegion(bounds, roi, source, seed) {
|
|
131
|
+
const { left, right, top, bottom } = bounds;
|
|
132
|
+
const x1 = left.start, x2 = right.endExclusive;
|
|
133
|
+
const y1 = top.start, y2 = bottom.endExclusive;
|
|
134
|
+
if (x1 >= x2 || y1 >= y2)
|
|
135
|
+
return undefined;
|
|
136
|
+
const region = { left: x1, top: y1, width: x2 - x1, height: y2 - y1 };
|
|
137
|
+
if (x1 < roi.left ||
|
|
138
|
+
y1 < roi.top ||
|
|
139
|
+
x2 > roi.left + roi.width ||
|
|
140
|
+
y2 > roi.top + roi.height ||
|
|
141
|
+
x2 > source.width ||
|
|
142
|
+
y2 > source.height ||
|
|
143
|
+
x1 >= seed.left + seed.width ||
|
|
144
|
+
y1 >= seed.top + seed.height ||
|
|
145
|
+
x2 <= seed.left ||
|
|
146
|
+
y2 <= seed.top)
|
|
147
|
+
return undefined;
|
|
148
|
+
return region;
|
|
149
|
+
}
|
|
150
|
+
/** Seed a physical instance, then narrow its four visible source-space boundaries with closed interval Choices. */
|
|
151
|
+
export async function locateWholeObjectInput(input, decision, raster, signal, representation, boundaryView, intervalPolicy = 'fixed-16-v1') {
|
|
152
|
+
const started = performance.now();
|
|
153
|
+
const args = parse(wholeObjectSchema, input);
|
|
154
|
+
const normalized = await raster.normalize(args.image, signal);
|
|
155
|
+
const roi = args.roi ?? { left: 0, top: 0, width: normalized.width, height: normalized.height };
|
|
156
|
+
const seedInput = {
|
|
157
|
+
image: args.image,
|
|
158
|
+
target: args.target,
|
|
159
|
+
exclusions: args.exclusions,
|
|
160
|
+
roi,
|
|
161
|
+
mode: 'region',
|
|
162
|
+
...(args.representation === undefined ? {} : { representation: args.representation }),
|
|
163
|
+
};
|
|
164
|
+
const stages = [];
|
|
165
|
+
const trackedDecision = {
|
|
166
|
+
async decide(request, callSignal) {
|
|
167
|
+
const result = await decision.decide(request, callSignal);
|
|
168
|
+
stages.push(result.metadata);
|
|
169
|
+
return result;
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
const metadata = () => resultMetadata(normalized, stages, performance.now() - started);
|
|
173
|
+
try {
|
|
174
|
+
const seedResult = await locateInput(seedInput, trackedDecision, raster, signal, undefined, representation);
|
|
175
|
+
if (seedResult.status !== 'located')
|
|
176
|
+
return { ...seedResult, metadata: metadata() };
|
|
177
|
+
const seed = seedResult.region;
|
|
178
|
+
let current = boundsFor(roi);
|
|
179
|
+
for (let pass = 0; pass < args.maxExtentPasses; pass++) {
|
|
180
|
+
assertActive(signal);
|
|
181
|
+
const specs = Object.fromEntries(axisOrder.map((axis) => [
|
|
182
|
+
axis,
|
|
183
|
+
choicesFor(axis, current[axis], args.boxTolerancePx, intervalPolicy, !!boundaryView && !representation),
|
|
184
|
+
]));
|
|
185
|
+
const state = boundaryView && !representation
|
|
186
|
+
? await prepareBoundaryState(raster, normalized, seed, args.target, args.exclusions, signal, boundaryView, roi, current, specs)
|
|
187
|
+
: await prepareState(raster, normalized, seed, args.target, args.exclusions, signal, representation);
|
|
188
|
+
const questions = Object.fromEntries(axisOrder.map((axis) => [axis, specs[axis].question]));
|
|
189
|
+
if (pass === 0)
|
|
190
|
+
questions['instance'] = sameInstanceQuestion();
|
|
191
|
+
const request = {
|
|
192
|
+
state: [
|
|
193
|
+
...state,
|
|
194
|
+
JSON.stringify({
|
|
195
|
+
pass: pass + 1,
|
|
196
|
+
hardRoi: roi,
|
|
197
|
+
seedRegion: seed,
|
|
198
|
+
currentBounds: current,
|
|
199
|
+
}),
|
|
200
|
+
],
|
|
201
|
+
questions,
|
|
202
|
+
};
|
|
203
|
+
const answer = validateDecision(request, await trackedDecision.decide(request, signal));
|
|
204
|
+
assertActive(signal);
|
|
205
|
+
if (pass === 0) {
|
|
206
|
+
const identity = selectedChoice(answer, 'instance', ['same', 'different', 'ambiguous']);
|
|
207
|
+
if (identity !== 'same')
|
|
208
|
+
return unknown('instance-ambiguous', metadata());
|
|
209
|
+
}
|
|
210
|
+
const next = { ...current };
|
|
211
|
+
for (const axis of axisOrder) {
|
|
212
|
+
const spec = specs[axis];
|
|
213
|
+
const selected = selectedChoice(answer, axis, [...spec.labels, 'unknown']);
|
|
214
|
+
if (selected === 'unknown')
|
|
215
|
+
return unknown('extent-uncertain', metadata());
|
|
216
|
+
const chosen = spec.intervals[spec.labels.indexOf(selected)];
|
|
217
|
+
if (!chosen)
|
|
218
|
+
throw new ClassifierError('INVALID_RESPONSE', 'Selected boundary interval is missing');
|
|
219
|
+
next[axis] = parse(boundaryResponseSchema, { status: 'known', interval: chosen }, 'INVALID_RESPONSE').interval;
|
|
220
|
+
}
|
|
221
|
+
if (boundaryView && !representation) {
|
|
222
|
+
const x1 = next.left.start;
|
|
223
|
+
const x2 = next.right.endExclusive;
|
|
224
|
+
const y1 = next.top.start;
|
|
225
|
+
const y2 = next.bottom.endExclusive;
|
|
226
|
+
if (x1 >= x2 ||
|
|
227
|
+
y1 >= y2 ||
|
|
228
|
+
x1 >= seed.left + seed.width ||
|
|
229
|
+
x2 <= seed.left ||
|
|
230
|
+
y1 >= seed.top + seed.height ||
|
|
231
|
+
y2 <= seed.top)
|
|
232
|
+
return unknown('extent-inconsistent', metadata());
|
|
233
|
+
}
|
|
234
|
+
current = next;
|
|
235
|
+
if (axisOrder.every((axis) => intervalWidth(current[axis]) <= args.boxTolerancePx))
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
if (axisOrder.some((axis) => intervalWidth(current[axis]) > args.boxTolerancePx))
|
|
239
|
+
return unknown('extent-uncertain', metadata());
|
|
240
|
+
const bounds = current;
|
|
241
|
+
const region = finalRegion(bounds, roi, normalized, seed);
|
|
242
|
+
if (!region)
|
|
243
|
+
return unknown('extent-inconsistent', metadata());
|
|
244
|
+
const edgeLimited = bounds.left.start === roi.left ||
|
|
245
|
+
bounds.top.start === roi.top ||
|
|
246
|
+
bounds.right.endExclusive === roi.left + roi.width ||
|
|
247
|
+
bounds.bottom.endExclusive === roi.top + roi.height;
|
|
248
|
+
return {
|
|
249
|
+
status: 'located',
|
|
250
|
+
kind: 'whole-object',
|
|
251
|
+
seedRegion: { ...seed },
|
|
252
|
+
region,
|
|
253
|
+
normalizedRegion: {
|
|
254
|
+
left: region.left / normalized.width,
|
|
255
|
+
top: region.top / normalized.height,
|
|
256
|
+
width: region.width / normalized.width,
|
|
257
|
+
height: region.height / normalized.height,
|
|
258
|
+
},
|
|
259
|
+
bounds,
|
|
260
|
+
completeness: edgeLimited ? 'boundary-limited' : 'visible-object',
|
|
261
|
+
method: 'grid-object-extent-v1',
|
|
262
|
+
metadata: metadata(),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
if (error instanceof ClassifierError &&
|
|
267
|
+
error.code === 'RESOURCE_LIMIT' &&
|
|
268
|
+
error.details['component'] === 'representation')
|
|
269
|
+
return unknown('representation-limit', metadata());
|
|
270
|
+
throw error;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Optional native adapters are composed here; importing types never starts native work. */
|
|
2
|
+
export type { BinaryMask, SegmentationInput, SegmentationMetadata, SegmentationResult, SegmentationPort, ExtractionResult, } from './entities/segmentation.js';
|
|
3
|
+
export { createMobileSamSegmenter } from './infrastructure/segmentation/mobile-sam/index.js';
|
|
4
|
+
export type { MobileSamSegmenterOptions } from './infrastructure/segmentation/mobile-sam/index.js';
|
|
5
|
+
export { createMobileSamObjectProposals } from './infrastructure/segmentation/mobile-sam/index.js';
|
|
6
|
+
export type { MobileSamObjectProposalsOptions } from './infrastructure/segmentation/mobile-sam/index.js';
|
|
7
|
+
export type { PackedBinaryMask, ObjectProposal, ObjectProposalInput, ObjectProposalBatch, ObjectProposalPort, } from './entities/object-proposals.js';
|
|
8
|
+
export { packBinaryMask, unpackBinaryMask } from './features/segmentation/packed-mask.js';
|
|
9
|
+
export { createGrabCutSegmenter } from './infrastructure/segmentation/grabcut/index.js';
|
|
10
|
+
export type { GrabCutSegmenterOptions } from './infrastructure/segmentation/grabcut/index.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { createMobileSamSegmenter } from './infrastructure/segmentation/mobile-sam/index.js';
|
|
2
|
+
export { createMobileSamObjectProposals } from './infrastructure/segmentation/mobile-sam/index.js';
|
|
3
|
+
export { packBinaryMask, unpackBinaryMask } from './features/segmentation/packed-mask.js';
|
|
4
|
+
export { createGrabCutSegmenter } from './infrastructure/segmentation/grabcut/index.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Checks wire consistency, not informativeness or calibrated confidence. */
|
|
2
|
+
export function acceptsChoiceMass(scores, step) {
|
|
3
|
+
if (scores.some((score) => !Number.isFinite(score) || score < 0 || score > 1))
|
|
4
|
+
return false;
|
|
5
|
+
const mass = scores.reduce((sum, score) => sum + score, 0);
|
|
6
|
+
if (Math.abs(mass - 1) <= 1e-6)
|
|
7
|
+
return true;
|
|
8
|
+
if (step !== 0.01)
|
|
9
|
+
return false;
|
|
10
|
+
let lower = 0;
|
|
11
|
+
let upper = 0;
|
|
12
|
+
for (const score of scores) {
|
|
13
|
+
if (Math.abs(score - Math.round(score / step) * step) > 1e-12)
|
|
14
|
+
return false;
|
|
15
|
+
lower += Math.max(0, score - step / 2);
|
|
16
|
+
upper += Math.min(1, score + step / 2);
|
|
17
|
+
}
|
|
18
|
+
return lower <= 1 + 1e-12 && upper >= 1 - 1e-12;
|
|
19
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** A slot is retained until the physical job's finally block calls release. */
|
|
2
|
+
export declare class OperationGate {
|
|
3
|
+
private readonly capacity;
|
|
4
|
+
private readonly maxQueue;
|
|
5
|
+
private active;
|
|
6
|
+
private readonly queue;
|
|
7
|
+
constructor(capacity: number, maxQueue: number);
|
|
8
|
+
assertAvailable(): void;
|
|
9
|
+
acquire(signal: AbortSignal): Promise<void>;
|
|
10
|
+
release(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ClassifierError, assertActive } from '../entities/errors.js';
|
|
2
|
+
/** A slot is retained until the physical job's finally block calls release. */
|
|
3
|
+
export class OperationGate {
|
|
4
|
+
capacity;
|
|
5
|
+
maxQueue;
|
|
6
|
+
active = 0;
|
|
7
|
+
queue = [];
|
|
8
|
+
constructor(capacity, maxQueue) {
|
|
9
|
+
this.capacity = capacity;
|
|
10
|
+
this.maxQueue = maxQueue;
|
|
11
|
+
}
|
|
12
|
+
assertAvailable() {
|
|
13
|
+
if (this.active >= this.capacity && this.queue.length >= this.maxQueue)
|
|
14
|
+
throw new ClassifierError('CAPACITY', 'Operation queue is full');
|
|
15
|
+
}
|
|
16
|
+
async acquire(signal) {
|
|
17
|
+
assertActive(signal);
|
|
18
|
+
this.assertAvailable();
|
|
19
|
+
if (this.active < this.capacity) {
|
|
20
|
+
this.active++;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
await new Promise((resolve, reject) => {
|
|
24
|
+
const entry = {
|
|
25
|
+
signal,
|
|
26
|
+
resolve,
|
|
27
|
+
reject,
|
|
28
|
+
onAbort: () => {
|
|
29
|
+
const index = this.queue.indexOf(entry);
|
|
30
|
+
if (index < 0)
|
|
31
|
+
return;
|
|
32
|
+
this.queue.splice(index, 1);
|
|
33
|
+
signal.removeEventListener('abort', entry.onAbort);
|
|
34
|
+
reject(signal.reason);
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
this.queue.push(entry);
|
|
38
|
+
signal.addEventListener('abort', entry.onAbort, { once: true });
|
|
39
|
+
if (signal.aborted)
|
|
40
|
+
entry.onAbort();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
release() {
|
|
44
|
+
this.active--;
|
|
45
|
+
const entry = this.queue.shift();
|
|
46
|
+
if (!entry)
|
|
47
|
+
return;
|
|
48
|
+
entry.signal.removeEventListener('abort', entry.onAbort);
|
|
49
|
+
this.active++;
|
|
50
|
+
entry.resolve();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ClassifierError } from '../entities/errors.js';
|
|
2
|
+
/** Reserves active plus queued snapshots before allocating any owned byte copy. */
|
|
3
|
+
export class InputBudget {
|
|
4
|
+
limit;
|
|
5
|
+
retained = 0;
|
|
6
|
+
constructor(limit) {
|
|
7
|
+
this.limit = limit;
|
|
8
|
+
}
|
|
9
|
+
reserve(bytes) {
|
|
10
|
+
if (!Number.isSafeInteger(bytes) || bytes < 0 || bytes > this.limit - this.retained)
|
|
11
|
+
throw new ClassifierError('CAPACITY', 'Owned input byte budget is full');
|
|
12
|
+
this.retained += bytes;
|
|
13
|
+
let released = false;
|
|
14
|
+
return () => {
|
|
15
|
+
if (released)
|
|
16
|
+
return;
|
|
17
|
+
released = true;
|
|
18
|
+
this.retained -= bytes;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class OperationScope {
|
|
2
|
+
private readonly parent?;
|
|
3
|
+
readonly controller: AbortController;
|
|
4
|
+
readonly signal: AbortSignal;
|
|
5
|
+
readonly startedAt: number;
|
|
6
|
+
private readonly timer;
|
|
7
|
+
private readonly onAbort;
|
|
8
|
+
constructor(timeoutMs: number, parent?: AbortSignal | undefined);
|
|
9
|
+
guard(): void;
|
|
10
|
+
abort(): void;
|
|
11
|
+
dispose(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ClassifierError, assertActive } from '../entities/errors.js';
|
|
2
|
+
export class OperationScope {
|
|
3
|
+
parent;
|
|
4
|
+
controller = new AbortController();
|
|
5
|
+
signal = this.controller.signal;
|
|
6
|
+
startedAt = performance.now();
|
|
7
|
+
timer;
|
|
8
|
+
onAbort;
|
|
9
|
+
constructor(timeoutMs, parent) {
|
|
10
|
+
this.parent = parent;
|
|
11
|
+
this.onAbort = () => this.controller.abort(new ClassifierError('ABORTED', 'Operation cancelled'));
|
|
12
|
+
if (parent?.aborted)
|
|
13
|
+
this.onAbort();
|
|
14
|
+
else
|
|
15
|
+
parent?.addEventListener('abort', this.onAbort, { once: true });
|
|
16
|
+
this.timer = setTimeout(() => this.controller.abort(new ClassifierError('TIMEOUT', 'Operation deadline exceeded')), timeoutMs);
|
|
17
|
+
this.timer.unref();
|
|
18
|
+
}
|
|
19
|
+
guard() {
|
|
20
|
+
assertActive(this.signal);
|
|
21
|
+
}
|
|
22
|
+
abort() {
|
|
23
|
+
this.onAbort();
|
|
24
|
+
}
|
|
25
|
+
dispose() {
|
|
26
|
+
clearTimeout(this.timer);
|
|
27
|
+
this.parent?.removeEventListener('abort', this.onAbort);
|
|
28
|
+
}
|
|
29
|
+
}
|