@zxyycom/vibe-check 0.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 +154 -0
- package/dist/esm/check/check.mjs +5 -0
- package/dist/esm/check/check.mjs.map +1 -0
- package/dist/esm/check/descriptor-validation.mjs +37 -0
- package/dist/esm/check/descriptor-validation.mjs.map +1 -0
- package/dist/esm/check/descriptor.mjs +2 -0
- package/dist/esm/check/descriptor.mjs.map +1 -0
- package/dist/esm/check/inherited-collection.mjs +62 -0
- package/dist/esm/check/inherited-collection.mjs.map +1 -0
- package/dist/esm/check/options-snapshot.mjs +75 -0
- package/dist/esm/check/options-snapshot.mjs.map +1 -0
- package/dist/esm/check-settlement/fact-validation.mjs +216 -0
- package/dist/esm/check-settlement/fact-validation.mjs.map +1 -0
- package/dist/esm/check-settlement/facts.mjs +2 -0
- package/dist/esm/check-settlement/facts.mjs.map +1 -0
- package/dist/esm/check-settlement/outcome-normalization.mjs +80 -0
- package/dist/esm/check-settlement/outcome-normalization.mjs.map +1 -0
- package/dist/esm/check-settlement/record-store.mjs +59 -0
- package/dist/esm/check-settlement/record-store.mjs.map +1 -0
- package/dist/esm/check-settlement/session.mjs +179 -0
- package/dist/esm/check-settlement/session.mjs.map +1 -0
- package/dist/esm/data-boundary/canonical-data.mjs +159 -0
- package/dist/esm/data-boundary/canonical-data.mjs.map +1 -0
- package/dist/esm/data-boundary/canonical-json.mjs +2 -0
- package/dist/esm/data-boundary/canonical-json.mjs.map +1 -0
- package/dist/esm/data-boundary/closed-values.mjs +98 -0
- package/dist/esm/data-boundary/closed-values.mjs.map +1 -0
- package/dist/esm/data-boundary/value-shapes.mjs +13 -0
- package/dist/esm/data-boundary/value-shapes.mjs.map +1 -0
- package/dist/esm/finding-waivers/reconciliation.mjs +84 -0
- package/dist/esm/finding-waivers/reconciliation.mjs.map +1 -0
- package/dist/esm/index.mjs +26 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/machine-output/v4/atomic-publication.mjs +102 -0
- package/dist/esm/machine-output/v4/atomic-publication.mjs.map +1 -0
- package/dist/esm/machine-output/v4/freeze-publication-value.mjs +14 -0
- package/dist/esm/machine-output/v4/freeze-publication-value.mjs.map +1 -0
- package/dist/esm/machine-output/v4/projection.mjs +23 -0
- package/dist/esm/machine-output/v4/projection.mjs.map +1 -0
- package/dist/esm/machine-output/v4/publication-invariants.mjs +59 -0
- package/dist/esm/machine-output/v4/publication-invariants.mjs.map +1 -0
- package/dist/esm/machine-output/v4/publication-model.mjs +19 -0
- package/dist/esm/machine-output/v4/publication-model.mjs.map +1 -0
- package/dist/esm/machine-output/v4/publish.mjs +20 -0
- package/dist/esm/machine-output/v4/publish.mjs.map +1 -0
- package/dist/esm/machine-output/v4/records-fingerprint.mjs +9 -0
- package/dist/esm/machine-output/v4/records-fingerprint.mjs.map +1 -0
- package/dist/esm/machine-output/v4/schema-identities.mjs +8 -0
- package/dist/esm/machine-output/v4/schema-identities.mjs.map +1 -0
- package/dist/esm/machine-output/v4/schema.mjs +50 -0
- package/dist/esm/machine-output/v4/schema.mjs.map +1 -0
- package/dist/esm/machine-output/v4/serializers.mjs +9 -0
- package/dist/esm/machine-output/v4/serializers.mjs.map +1 -0
- package/dist/esm/machine-output/v4/validation-result.mjs +16 -0
- package/dist/esm/machine-output/v4/validation-result.mjs.map +1 -0
- package/dist/esm/machine-output/v4/validation.mjs +131 -0
- package/dist/esm/machine-output/v4/validation.mjs.map +1 -0
- package/dist/esm/package-checks/code-quality-findings/policy.mjs +49 -0
- package/dist/esm/package-checks/code-quality-findings/policy.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/area-policy.mjs +71 -0
- package/dist/esm/package-checks/duplicate-detection/area-policy.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/cache/cache-contract.mjs +2 -0
- package/dist/esm/package-checks/duplicate-detection/cache/cache-contract.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/cache/identity.mjs +37 -0
- package/dist/esm/package-checks/duplicate-detection/cache/identity.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/cache/key.mjs +38 -0
- package/dist/esm/package-checks/duplicate-detection/cache/key.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/cache/payload.mjs +47 -0
- package/dist/esm/package-checks/duplicate-detection/cache/payload.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/cache/store.mjs +44 -0
- package/dist/esm/package-checks/duplicate-detection/cache/store.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/default-check.mjs +39 -0
- package/dist/esm/package-checks/duplicate-detection/default-check.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/execution.mjs +124 -0
- package/dist/esm/package-checks/duplicate-detection/execution.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/final-data.mjs +6 -0
- package/dist/esm/package-checks/duplicate-detection/final-data.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/availability.mjs +77 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/availability.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/command-path.mjs +6 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/command-path.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/command-resolution.mjs +87 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/command-resolution.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/json-report.mjs +94 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/json-report.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/scanner-contract.mjs +2 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/scanner-contract.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/scanner.mjs +180 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/scanner.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/scoped-fragments.mjs +10 -0
- package/dist/esm/package-checks/duplicate-detection/jscpd/scoped-fragments.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/measurement-model.mjs +2 -0
- package/dist/esm/package-checks/duplicate-detection/measurement-model.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/measurement.mjs +151 -0
- package/dist/esm/package-checks/duplicate-detection/measurement.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/options-resolution.mjs +126 -0
- package/dist/esm/package-checks/duplicate-detection/options-resolution.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/options-validation.mjs +60 -0
- package/dist/esm/package-checks/duplicate-detection/options-validation.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/options.mjs +2 -0
- package/dist/esm/package-checks/duplicate-detection/options.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/project-revision.mjs +5 -0
- package/dist/esm/package-checks/duplicate-detection/project-revision.mjs.map +1 -0
- package/dist/esm/package-checks/duplicate-detection/records.mjs +119 -0
- package/dist/esm/package-checks/duplicate-detection/records.mjs.map +1 -0
- package/dist/esm/package-checks/file-metrics/constructor.mjs +39 -0
- package/dist/esm/package-checks/file-metrics/constructor.mjs.map +1 -0
- package/dist/esm/package-checks/file-metrics/execution.mjs +170 -0
- package/dist/esm/package-checks/file-metrics/execution.mjs.map +1 -0
- package/dist/esm/package-checks/file-metrics/final-data.mjs +6 -0
- package/dist/esm/package-checks/file-metrics/final-data.mjs.map +1 -0
- package/dist/esm/package-checks/file-metrics/measurement-model.mjs +2 -0
- package/dist/esm/package-checks/file-metrics/measurement-model.mjs.map +1 -0
- package/dist/esm/package-checks/file-metrics/measurement.mjs +33 -0
- package/dist/esm/package-checks/file-metrics/measurement.mjs.map +1 -0
- package/dist/esm/package-checks/file-metrics/options-resolution.mjs +171 -0
- package/dist/esm/package-checks/file-metrics/options-resolution.mjs.map +1 -0
- package/dist/esm/package-checks/file-metrics/options-validation.mjs +82 -0
- package/dist/esm/package-checks/file-metrics/options-validation.mjs.map +1 -0
- package/dist/esm/package-checks/file-metrics/options.mjs +2 -0
- package/dist/esm/package-checks/file-metrics/options.mjs.map +1 -0
- package/dist/esm/package-checks/file-metrics/records.mjs +109 -0
- package/dist/esm/package-checks/file-metrics/records.mjs.map +1 -0
- package/dist/esm/package-checks/file-metrics/scc/availability.mjs +59 -0
- package/dist/esm/package-checks/file-metrics/scc/availability.mjs.map +1 -0
- package/dist/esm/package-checks/file-metrics/scc/csv.mjs +17 -0
- package/dist/esm/package-checks/file-metrics/scc/csv.mjs.map +1 -0
- package/dist/esm/package-checks/file-metrics/scc/parser.mjs +145 -0
- package/dist/esm/package-checks/file-metrics/scc/parser.mjs.map +1 -0
- package/dist/esm/package-checks/file-metrics/scc/scanner.mjs +54 -0
- package/dist/esm/package-checks/file-metrics/scc/scanner.mjs.map +1 -0
- package/dist/esm/package-checks/final-data-parsing.mjs +35 -0
- package/dist/esm/package-checks/final-data-parsing.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/analysis.mjs +96 -0
- package/dist/esm/package-checks/function-metrics/analysis.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/constructor.mjs +43 -0
- package/dist/esm/package-checks/function-metrics/constructor.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/execution.mjs +178 -0
- package/dist/esm/package-checks/function-metrics/execution.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/final-data.mjs +6 -0
- package/dist/esm/package-checks/function-metrics/final-data.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/lizard/availability.mjs +64 -0
- package/dist/esm/package-checks/function-metrics/lizard/availability.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/lizard/csv.mjs +17 -0
- package/dist/esm/package-checks/function-metrics/lizard/csv.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/lizard/parser.mjs +138 -0
- package/dist/esm/package-checks/function-metrics/lizard/parser.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/lizard/scanner.mjs +35 -0
- package/dist/esm/package-checks/function-metrics/lizard/scanner.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/measurement-model.mjs +2 -0
- package/dist/esm/package-checks/function-metrics/measurement-model.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/measurement.mjs +35 -0
- package/dist/esm/package-checks/function-metrics/measurement.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/options-resolution.mjs +171 -0
- package/dist/esm/package-checks/function-metrics/options-resolution.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/options-validation.mjs +71 -0
- package/dist/esm/package-checks/function-metrics/options-validation.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/options.mjs +2 -0
- package/dist/esm/package-checks/function-metrics/options.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/records.mjs +133 -0
- package/dist/esm/package-checks/function-metrics/records.mjs.map +1 -0
- package/dist/esm/package-checks/function-metrics/target-files.mjs +75 -0
- package/dist/esm/package-checks/function-metrics/target-files.mjs.map +1 -0
- package/dist/esm/package-checks/host-environment/error-message.mjs +4 -0
- package/dist/esm/package-checks/host-environment/error-message.mjs.map +1 -0
- package/dist/esm/package-checks/host-environment/filesystem.mjs +81 -0
- package/dist/esm/package-checks/host-environment/filesystem.mjs.map +1 -0
- package/dist/esm/package-checks/host-environment/git.mjs +51 -0
- package/dist/esm/package-checks/host-environment/git.mjs.map +1 -0
- package/dist/esm/package-checks/host-environment/path.mjs +18 -0
- package/dist/esm/package-checks/host-environment/path.mjs.map +1 -0
- package/dist/esm/package-checks/host-environment/process/command.mjs +13 -0
- package/dist/esm/package-checks/host-environment/process/command.mjs.map +1 -0
- package/dist/esm/package-checks/host-environment/process/contract.mjs +2 -0
- package/dist/esm/package-checks/host-environment/process/contract.mjs.map +1 -0
- package/dist/esm/package-checks/host-environment/process/env.mjs +19 -0
- package/dist/esm/package-checks/host-environment/process/env.mjs.map +1 -0
- package/dist/esm/package-checks/host-environment/process/failure.mjs +34 -0
- package/dist/esm/package-checks/host-environment/process/failure.mjs.map +1 -0
- package/dist/esm/package-checks/host-environment/process/result.mjs +33 -0
- package/dist/esm/package-checks/host-environment/process/result.mjs.map +1 -0
- package/dist/esm/package-checks/host-environment/process/runner.mjs +30 -0
- package/dist/esm/package-checks/host-environment/process/runner.mjs.map +1 -0
- package/dist/esm/package-checks/json-document/strict-document.mjs +163 -0
- package/dist/esm/package-checks/json-document/strict-document.mjs.map +1 -0
- package/dist/esm/package-checks/json-schema-validation/default-check.mjs +39 -0
- package/dist/esm/package-checks/json-schema-validation/default-check.mjs.map +1 -0
- package/dist/esm/package-checks/json-schema-validation/execution-stages.mjs +141 -0
- package/dist/esm/package-checks/json-schema-validation/execution-stages.mjs.map +1 -0
- package/dist/esm/package-checks/json-schema-validation/final-data.mjs +64 -0
- package/dist/esm/package-checks/json-schema-validation/final-data.mjs.map +1 -0
- package/dist/esm/package-checks/json-schema-validation/issue-collector.mjs +35 -0
- package/dist/esm/package-checks/json-schema-validation/issue-collector.mjs.map +1 -0
- package/dist/esm/package-checks/json-schema-validation/json-schema-validation.mjs +118 -0
- package/dist/esm/package-checks/json-schema-validation/json-schema-validation.mjs.map +1 -0
- package/dist/esm/package-checks/json-schema-validation/options-resolution.mjs +45 -0
- package/dist/esm/package-checks/json-schema-validation/options-resolution.mjs.map +1 -0
- package/dist/esm/package-checks/json-schema-validation/options-validation.mjs +212 -0
- package/dist/esm/package-checks/json-schema-validation/options-validation.mjs.map +1 -0
- package/dist/esm/package-checks/json-schema-validation/options.mjs +2 -0
- package/dist/esm/package-checks/json-schema-validation/options.mjs.map +1 -0
- package/dist/esm/package-checks/json-schema-validation/reference-resolver.mjs +128 -0
- package/dist/esm/package-checks/json-schema-validation/reference-resolver.mjs.map +1 -0
- package/dist/esm/package-checks/json-schema-validation/remote-response.mjs +71 -0
- package/dist/esm/package-checks/json-schema-validation/remote-response.mjs.map +1 -0
- package/dist/esm/package-checks/json-schema-validation/schema-engine.mjs +190 -0
- package/dist/esm/package-checks/json-schema-validation/schema-engine.mjs.map +1 -0
- package/dist/esm/package-checks/json-schema-validation/schema-policy.mjs +234 -0
- package/dist/esm/package-checks/json-schema-validation/schema-policy.mjs.map +1 -0
- package/dist/esm/package-checks/json-validation/default-check.mjs +39 -0
- package/dist/esm/package-checks/json-validation/default-check.mjs.map +1 -0
- package/dist/esm/package-checks/json-validation/final-data.mjs +27 -0
- package/dist/esm/package-checks/json-validation/final-data.mjs.map +1 -0
- package/dist/esm/package-checks/json-validation/json-validation.mjs +138 -0
- package/dist/esm/package-checks/json-validation/json-validation.mjs.map +1 -0
- package/dist/esm/package-checks/json-validation/options-resolution.mjs +33 -0
- package/dist/esm/package-checks/json-validation/options-resolution.mjs.map +1 -0
- package/dist/esm/package-checks/json-validation/options-validation.mjs +16 -0
- package/dist/esm/package-checks/json-validation/options-validation.mjs.map +1 -0
- package/dist/esm/package-checks/json-validation/options.mjs +2 -0
- package/dist/esm/package-checks/json-validation/options.mjs.map +1 -0
- package/dist/esm/package-checks/maintenance-reminders/assessment-results.mjs +73 -0
- package/dist/esm/package-checks/maintenance-reminders/assessment-results.mjs.map +1 -0
- package/dist/esm/package-checks/maintenance-reminders/final-data.mjs +153 -0
- package/dist/esm/package-checks/maintenance-reminders/final-data.mjs.map +1 -0
- package/dist/esm/package-checks/maintenance-reminders/maintenance-reminders.mjs +155 -0
- package/dist/esm/package-checks/maintenance-reminders/maintenance-reminders.mjs.map +1 -0
- package/dist/esm/package-checks/maintenance-reminders/maintenance-support.mjs +58 -0
- package/dist/esm/package-checks/maintenance-reminders/maintenance-support.mjs.map +1 -0
- package/dist/esm/package-checks/maintenance-reminders/measurement.mjs +125 -0
- package/dist/esm/package-checks/maintenance-reminders/measurement.mjs.map +1 -0
- package/dist/esm/package-checks/maintenance-reminders/options-validation.mjs +72 -0
- package/dist/esm/package-checks/maintenance-reminders/options-validation.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/default-check.mjs +55 -0
- package/dist/esm/package-checks/markdown-link-validation/default-check.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/execution.mjs +199 -0
- package/dist/esm/package-checks/markdown-link-validation/execution.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/filesystem-probes.mjs +109 -0
- package/dist/esm/package-checks/markdown-link-validation/filesystem-probes.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/final-data.mjs +28 -0
- package/dist/esm/package-checks/markdown-link-validation/final-data.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/local-resolution.mjs +158 -0
- package/dist/esm/package-checks/markdown-link-validation/local-resolution.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/local-resolver.mjs +17 -0
- package/dist/esm/package-checks/markdown-link-validation/local-resolver.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/markdown-parser.mjs +191 -0
- package/dist/esm/package-checks/markdown-link-validation/markdown-parser.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/options-resolution.mjs +83 -0
- package/dist/esm/package-checks/markdown-link-validation/options-resolution.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/options-validation.mjs +50 -0
- package/dist/esm/package-checks/markdown-link-validation/options-validation.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/options.mjs +2 -0
- package/dist/esm/package-checks/markdown-link-validation/options.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/records.mjs +32 -0
- package/dist/esm/package-checks/markdown-link-validation/records.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/resolver-engine.mjs +196 -0
- package/dist/esm/package-checks/markdown-link-validation/resolver-engine.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/target-descriptor.mjs +23 -0
- package/dist/esm/package-checks/markdown-link-validation/target-descriptor.mjs.map +1 -0
- package/dist/esm/package-checks/markdown-link-validation/traversal-result.mjs +41 -0
- package/dist/esm/package-checks/markdown-link-validation/traversal-result.mjs.map +1 -0
- package/dist/esm/package-checks/project-files/collection.mjs +142 -0
- package/dist/esm/package-checks/project-files/collection.mjs.map +1 -0
- package/dist/esm/package-checks/project-files/config-glob.mjs +11 -0
- package/dist/esm/package-checks/project-files/config-glob.mjs.map +1 -0
- package/dist/esm/package-checks/project-files/configuration.mjs +104 -0
- package/dist/esm/package-checks/project-files/configuration.mjs.map +1 -0
- package/dist/esm/package-checks/project-files/exact-input-measurement.mjs +24 -0
- package/dist/esm/package-checks/project-files/exact-input-measurement.mjs.map +1 -0
- package/dist/esm/package-checks/project-files/file-fingerprint.mjs +36 -0
- package/dist/esm/package-checks/project-files/file-fingerprint.mjs.map +1 -0
- package/dist/esm/package-checks/project-files/gitlink-revision.mjs +57 -0
- package/dist/esm/package-checks/project-files/gitlink-revision.mjs.map +1 -0
- package/dist/esm/package-checks/project-files/gitlink-worktree.mjs +72 -0
- package/dist/esm/package-checks/project-files/gitlink-worktree.mjs.map +1 -0
- package/dist/esm/package-checks/project-files/input-eligibility.mjs +13 -0
- package/dist/esm/package-checks/project-files/input-eligibility.mjs.map +1 -0
- package/dist/esm/package-checks/project-files/reported-path.mjs +30 -0
- package/dist/esm/package-checks/project-files/reported-path.mjs.map +1 -0
- package/dist/esm/package-checks/project-files/revision-paths.mjs +19 -0
- package/dist/esm/package-checks/project-files/revision-paths.mjs.map +1 -0
- package/dist/esm/package-checks/project-files/revision-worktree-files.mjs +102 -0
- package/dist/esm/package-checks/project-files/revision-worktree-files.mjs.map +1 -0
- package/dist/esm/project-definition/check-tree/authoring.mjs +242 -0
- package/dist/esm/project-definition/check-tree/authoring.mjs.map +1 -0
- package/dist/esm/project-definition/check-tree/materialization.mjs +50 -0
- package/dist/esm/project-definition/check-tree/materialization.mjs.map +1 -0
- package/dist/esm/project-definition/check-tree/resolution.mjs +60 -0
- package/dist/esm/project-definition/check-tree/resolution.mjs.map +1 -0
- package/dist/esm/project-definition/output-defaults.mjs +7 -0
- package/dist/esm/project-definition/output-defaults.mjs.map +1 -0
- package/dist/esm/project-definition/output-validation.mjs +44 -0
- package/dist/esm/project-definition/output-validation.mjs.map +1 -0
- package/dist/esm/project-definition/project-definition-validation.mjs +95 -0
- package/dist/esm/project-definition/project-definition-validation.mjs.map +1 -0
- package/dist/esm/project-definition/project-definition.mjs +92 -0
- package/dist/esm/project-definition/project-definition.mjs.map +1 -0
- package/dist/esm/project-run/aggregation.mjs +66 -0
- package/dist/esm/project-run/aggregation.mjs.map +1 -0
- package/dist/esm/project-run/check-execution/callback.mjs +70 -0
- package/dist/esm/project-run/check-execution/callback.mjs.map +1 -0
- package/dist/esm/project-run/check-execution/dependencies.mjs +50 -0
- package/dist/esm/project-run/check-execution/dependencies.mjs.map +1 -0
- package/dist/esm/project-run/check-execution/execution-finalization.mjs +103 -0
- package/dist/esm/project-run/check-execution/execution-finalization.mjs.map +1 -0
- package/dist/esm/project-run/check-execution/execution-settlement.mjs +90 -0
- package/dist/esm/project-run/check-execution/execution-settlement.mjs.map +1 -0
- package/dist/esm/project-run/check-execution/messages.mjs +38 -0
- package/dist/esm/project-run/check-execution/messages.mjs.map +1 -0
- package/dist/esm/project-run/check-execution/plan.mjs +35 -0
- package/dist/esm/project-run/check-execution/plan.mjs.map +1 -0
- package/dist/esm/project-run/check-execution/preflight-result.mjs +83 -0
- package/dist/esm/project-run/check-execution/preflight-result.mjs.map +1 -0
- package/dist/esm/project-run/check-execution/preflight.mjs +186 -0
- package/dist/esm/project-run/check-execution/preflight.mjs.map +1 -0
- package/dist/esm/project-run/check-execution/resolved-checks.mjs +168 -0
- package/dist/esm/project-run/check-execution/resolved-checks.mjs.map +1 -0
- package/dist/esm/project-run/check-execution/terminal-result.mjs +49 -0
- package/dist/esm/project-run/check-execution/terminal-result.mjs.map +1 -0
- package/dist/esm/project-run/completion.mjs +173 -0
- package/dist/esm/project-run/completion.mjs.map +1 -0
- package/dist/esm/project-run/controls/contract.mjs +2 -0
- package/dist/esm/project-run/controls/contract.mjs.map +1 -0
- package/dist/esm/project-run/controls/outputs-override-validation.mjs +61 -0
- package/dist/esm/project-run/controls/outputs-override-validation.mjs.map +1 -0
- package/dist/esm/project-run/controls/validation-result.mjs +2 -0
- package/dist/esm/project-run/controls/validation-result.mjs.map +1 -0
- package/dist/esm/project-run/controls/validation.mjs +156 -0
- package/dist/esm/project-run/controls/validation.mjs.map +1 -0
- package/dist/esm/project-run/diagnostic-logging/diagnostic-detail-rendering.mjs +182 -0
- package/dist/esm/project-run/diagnostic-logging/diagnostic-detail-rendering.mjs.map +1 -0
- package/dist/esm/project-run/diagnostic-logging/logger.mjs +242 -0
- package/dist/esm/project-run/diagnostic-logging/logger.mjs.map +1 -0
- package/dist/esm/project-run/invocation-creation.mjs +111 -0
- package/dist/esm/project-run/invocation-creation.mjs.map +1 -0
- package/dist/esm/project-run/invocation.mjs +195 -0
- package/dist/esm/project-run/invocation.mjs.map +1 -0
- package/dist/esm/project-run/machine-publication.mjs +16 -0
- package/dist/esm/project-run/machine-publication.mjs.map +1 -0
- package/dist/esm/project-run/output-configuration.mjs +17 -0
- package/dist/esm/project-run/output-configuration.mjs.map +1 -0
- package/dist/esm/project-run/output-status.mjs +43 -0
- package/dist/esm/project-run/output-status.mjs.map +1 -0
- package/dist/esm/project-run/progress-rendering/presentation.mjs +135 -0
- package/dist/esm/project-run/progress-rendering/presentation.mjs.map +1 -0
- package/dist/esm/project-run/progress-rendering/renderer-formatting.mjs +100 -0
- package/dist/esm/project-run/progress-rendering/renderer-formatting.mjs.map +1 -0
- package/dist/esm/project-run/progress-rendering/renderer-lifecycle.mjs +123 -0
- package/dist/esm/project-run/progress-rendering/renderer-lifecycle.mjs.map +1 -0
- package/dist/esm/project-run/progress-rendering/renderer.mjs +12 -0
- package/dist/esm/project-run/progress-rendering/renderer.mjs.map +1 -0
- package/dist/esm/project-run/project-context.mjs +8 -0
- package/dist/esm/project-run/project-context.mjs.map +1 -0
- package/dist/esm/project-run/result.mjs +54 -0
- package/dist/esm/project-run/result.mjs.map +1 -0
- package/dist/esm/project-run/run.mjs +23 -0
- package/dist/esm/project-run/run.mjs.map +1 -0
- package/dist/esm/project-run/task-scheduler/execution-state.mjs +66 -0
- package/dist/esm/project-run/task-scheduler/execution-state.mjs.map +1 -0
- package/dist/esm/project-run/task-scheduler/graph-validation.mjs +119 -0
- package/dist/esm/project-run/task-scheduler/graph-validation.mjs.map +1 -0
- package/dist/esm/project-run/task-scheduler/graph.mjs +116 -0
- package/dist/esm/project-run/task-scheduler/graph.mjs.map +1 -0
- package/dist/esm/project-run/task-scheduler/scheduler-admission-decision.mjs +82 -0
- package/dist/esm/project-run/task-scheduler/scheduler-admission-decision.mjs.map +1 -0
- package/dist/esm/project-run/task-scheduler/scheduler-blocker-summary.mjs +27 -0
- package/dist/esm/project-run/task-scheduler/scheduler-blocker-summary.mjs.map +1 -0
- package/dist/esm/project-run/task-scheduler/scheduler-decision-inspection.mjs +125 -0
- package/dist/esm/project-run/task-scheduler/scheduler-decision-inspection.mjs.map +1 -0
- package/dist/esm/project-run/task-scheduler/scheduler-decision-model.mjs +45 -0
- package/dist/esm/project-run/task-scheduler/scheduler-decision-model.mjs.map +1 -0
- package/dist/esm/project-run/task-scheduler/scheduler-decision.mjs +74 -0
- package/dist/esm/project-run/task-scheduler/scheduler-decision.mjs.map +1 -0
- package/dist/esm/project-run/task-scheduler/scheduler.mjs +147 -0
- package/dist/esm/project-run/task-scheduler/scheduler.mjs.map +1 -0
- package/docs/api-mechanics.md +205 -0
- package/docs/checks/duplicate-detection.md +195 -0
- package/docs/checks/file-metrics.md +229 -0
- package/docs/checks/function-metrics.md +222 -0
- package/docs/checks/json-schema-validation.md +190 -0
- package/docs/checks/json-validation.md +133 -0
- package/docs/checks/maintenance-reminders.md +158 -0
- package/docs/checks/markdown-link-validation.md +192 -0
- package/docs/examples/artifacts/mixed-outcomes/definition.ts +195 -0
- package/docs/examples/artifacts/mixed-outcomes/records.ndjson +2 -0
- package/docs/examples/artifacts/mixed-outcomes/run.json +70 -0
- package/docs/output.md +97 -0
- package/docs/schemas/vibe-check-record.schema.json +33 -0
- package/docs/schemas/vibe-check-run.schema.json +173 -0
- package/index.mjs +1 -0
- package/package.json +49 -0
- package/src/check/check.ts +497 -0
- package/src/check/descriptor-validation.ts +60 -0
- package/src/check/descriptor.ts +5 -0
- package/src/check/inherited-collection.ts +101 -0
- package/src/check/options-snapshot.ts +80 -0
- package/src/check-settlement/fact-validation.ts +289 -0
- package/src/check-settlement/facts.ts +27 -0
- package/src/check-settlement/outcome-normalization.ts +118 -0
- package/src/check-settlement/record-store.ts +73 -0
- package/src/check-settlement/session.ts +257 -0
- package/src/data-boundary/canonical-data.ts +188 -0
- package/src/data-boundary/canonical-json.ts +11 -0
- package/src/data-boundary/closed-values.ts +126 -0
- package/src/data-boundary/value-shapes.ts +15 -0
- package/src/finding-waivers/reconciliation.ts +176 -0
- package/src/index.ts +123 -0
- package/src/machine-output/v4/atomic-publication.ts +123 -0
- package/src/machine-output/v4/freeze-publication-value.ts +12 -0
- package/src/machine-output/v4/projection.ts +36 -0
- package/src/machine-output/v4/publication-invariants.ts +89 -0
- package/src/machine-output/v4/publication-model.ts +38 -0
- package/src/machine-output/v4/publish.ts +23 -0
- package/src/machine-output/v4/records-fingerprint.ts +12 -0
- package/src/machine-output/v4/schema-identities.ts +8 -0
- package/src/machine-output/v4/schema.ts +97 -0
- package/src/machine-output/v4/serializers.ts +18 -0
- package/src/machine-output/v4/validation-result.ts +59 -0
- package/src/machine-output/v4/validation.ts +166 -0
- package/src/package-checks/code-quality-findings/policy.ts +85 -0
- package/src/package-checks/duplicate-detection/area-policy.ts +103 -0
- package/src/package-checks/duplicate-detection/cache/cache-contract.ts +49 -0
- package/src/package-checks/duplicate-detection/cache/identity.ts +61 -0
- package/src/package-checks/duplicate-detection/cache/key.ts +46 -0
- package/src/package-checks/duplicate-detection/cache/payload.ts +78 -0
- package/src/package-checks/duplicate-detection/cache/store.ts +77 -0
- package/src/package-checks/duplicate-detection/default-check.ts +50 -0
- package/src/package-checks/duplicate-detection/execution.ts +168 -0
- package/src/package-checks/duplicate-detection/final-data.ts +10 -0
- package/src/package-checks/duplicate-detection/jscpd/availability.ts +137 -0
- package/src/package-checks/duplicate-detection/jscpd/command-path.ts +8 -0
- package/src/package-checks/duplicate-detection/jscpd/command-resolution.ts +112 -0
- package/src/package-checks/duplicate-detection/jscpd/json-report.ts +137 -0
- package/src/package-checks/duplicate-detection/jscpd/scanner-contract.ts +18 -0
- package/src/package-checks/duplicate-detection/jscpd/scanner.ts +257 -0
- package/src/package-checks/duplicate-detection/jscpd/scoped-fragments.ts +17 -0
- package/src/package-checks/duplicate-detection/measurement-model.ts +44 -0
- package/src/package-checks/duplicate-detection/measurement.ts +223 -0
- package/src/package-checks/duplicate-detection/options-resolution.ts +162 -0
- package/src/package-checks/duplicate-detection/options-validation.ts +75 -0
- package/src/package-checks/duplicate-detection/options.ts +72 -0
- package/src/package-checks/duplicate-detection/project-revision.ts +5 -0
- package/src/package-checks/duplicate-detection/records.ts +171 -0
- package/src/package-checks/file-metrics/constructor.ts +46 -0
- package/src/package-checks/file-metrics/execution.ts +233 -0
- package/src/package-checks/file-metrics/final-data.ts +10 -0
- package/src/package-checks/file-metrics/measurement-model.ts +10 -0
- package/src/package-checks/file-metrics/measurement.ts +52 -0
- package/src/package-checks/file-metrics/options-resolution.ts +213 -0
- package/src/package-checks/file-metrics/options-validation.ts +104 -0
- package/src/package-checks/file-metrics/options.ts +91 -0
- package/src/package-checks/file-metrics/records.ts +182 -0
- package/src/package-checks/file-metrics/scc/availability.ts +100 -0
- package/src/package-checks/file-metrics/scc/csv.ts +20 -0
- package/src/package-checks/file-metrics/scc/parser.ts +223 -0
- package/src/package-checks/file-metrics/scc/scanner.ts +68 -0
- package/src/package-checks/final-data-parsing.ts +49 -0
- package/src/package-checks/function-metrics/analysis.ts +138 -0
- package/src/package-checks/function-metrics/constructor.ts +55 -0
- package/src/package-checks/function-metrics/execution.ts +263 -0
- package/src/package-checks/function-metrics/final-data.ts +10 -0
- package/src/package-checks/function-metrics/lizard/availability.ts +90 -0
- package/src/package-checks/function-metrics/lizard/csv.ts +20 -0
- package/src/package-checks/function-metrics/lizard/parser.ts +179 -0
- package/src/package-checks/function-metrics/lizard/scanner.ts +62 -0
- package/src/package-checks/function-metrics/measurement-model.ts +30 -0
- package/src/package-checks/function-metrics/measurement.ts +57 -0
- package/src/package-checks/function-metrics/options-resolution.ts +215 -0
- package/src/package-checks/function-metrics/options-validation.ts +89 -0
- package/src/package-checks/function-metrics/options.ts +84 -0
- package/src/package-checks/function-metrics/records.ts +254 -0
- package/src/package-checks/function-metrics/target-files.ts +85 -0
- package/src/package-checks/host-environment/error-message.ts +3 -0
- package/src/package-checks/host-environment/filesystem.ts +110 -0
- package/src/package-checks/host-environment/git.ts +68 -0
- package/src/package-checks/host-environment/path.ts +20 -0
- package/src/package-checks/host-environment/process/command.ts +21 -0
- package/src/package-checks/host-environment/process/contract.ts +56 -0
- package/src/package-checks/host-environment/process/env.ts +25 -0
- package/src/package-checks/host-environment/process/failure.ts +40 -0
- package/src/package-checks/host-environment/process/result.ts +39 -0
- package/src/package-checks/host-environment/process/runner.ts +47 -0
- package/src/package-checks/json-document/strict-document.ts +209 -0
- package/src/package-checks/json-schema-validation/default-check.ts +54 -0
- package/src/package-checks/json-schema-validation/execution-stages.ts +230 -0
- package/src/package-checks/json-schema-validation/final-data.ts +115 -0
- package/src/package-checks/json-schema-validation/issue-collector.ts +43 -0
- package/src/package-checks/json-schema-validation/json-schema-validation.ts +191 -0
- package/src/package-checks/json-schema-validation/options-resolution.ts +61 -0
- package/src/package-checks/json-schema-validation/options-validation.ts +256 -0
- package/src/package-checks/json-schema-validation/options.ts +66 -0
- package/src/package-checks/json-schema-validation/reference-resolver.ts +165 -0
- package/src/package-checks/json-schema-validation/remote-response.ts +84 -0
- package/src/package-checks/json-schema-validation/schema-engine.ts +263 -0
- package/src/package-checks/json-schema-validation/schema-policy.ts +275 -0
- package/src/package-checks/json-validation/default-check.ts +48 -0
- package/src/package-checks/json-validation/final-data.ts +46 -0
- package/src/package-checks/json-validation/json-validation.ts +212 -0
- package/src/package-checks/json-validation/options-resolution.ts +50 -0
- package/src/package-checks/json-validation/options-validation.ts +27 -0
- package/src/package-checks/json-validation/options.ts +18 -0
- package/src/package-checks/maintenance-reminders/assessment-results.ts +117 -0
- package/src/package-checks/maintenance-reminders/final-data.ts +239 -0
- package/src/package-checks/maintenance-reminders/maintenance-reminders.ts +264 -0
- package/src/package-checks/maintenance-reminders/maintenance-support.ts +67 -0
- package/src/package-checks/maintenance-reminders/measurement.ts +183 -0
- package/src/package-checks/maintenance-reminders/options-validation.ts +88 -0
- package/src/package-checks/markdown-link-validation/default-check.ts +70 -0
- package/src/package-checks/markdown-link-validation/execution.ts +325 -0
- package/src/package-checks/markdown-link-validation/filesystem-probes.ts +127 -0
- package/src/package-checks/markdown-link-validation/final-data.ts +47 -0
- package/src/package-checks/markdown-link-validation/local-resolution.ts +306 -0
- package/src/package-checks/markdown-link-validation/local-resolver.ts +51 -0
- package/src/package-checks/markdown-link-validation/markdown-parser.ts +302 -0
- package/src/package-checks/markdown-link-validation/options-resolution.ts +114 -0
- package/src/package-checks/markdown-link-validation/options-validation.ts +72 -0
- package/src/package-checks/markdown-link-validation/options.ts +50 -0
- package/src/package-checks/markdown-link-validation/records.ts +77 -0
- package/src/package-checks/markdown-link-validation/resolver-engine.ts +276 -0
- package/src/package-checks/markdown-link-validation/target-descriptor.ts +34 -0
- package/src/package-checks/markdown-link-validation/traversal-result.ts +58 -0
- package/src/package-checks/project-files/collection.ts +199 -0
- package/src/package-checks/project-files/config-glob.ts +17 -0
- package/src/package-checks/project-files/configuration.ts +152 -0
- package/src/package-checks/project-files/exact-input-measurement.ts +38 -0
- package/src/package-checks/project-files/file-fingerprint.ts +46 -0
- package/src/package-checks/project-files/gitlink-revision.ts +82 -0
- package/src/package-checks/project-files/gitlink-worktree.ts +106 -0
- package/src/package-checks/project-files/input-eligibility.ts +21 -0
- package/src/package-checks/project-files/reported-path.ts +35 -0
- package/src/package-checks/project-files/revision-paths.ts +34 -0
- package/src/package-checks/project-files/revision-worktree-files.ts +148 -0
- package/src/project-definition/check-tree/authoring.ts +332 -0
- package/src/project-definition/check-tree/materialization.ts +56 -0
- package/src/project-definition/check-tree/resolution.ts +108 -0
- package/src/project-definition/output-defaults.ts +6 -0
- package/src/project-definition/output-validation.ts +54 -0
- package/src/project-definition/project-definition-validation.ts +123 -0
- package/src/project-definition/project-definition.ts +184 -0
- package/src/project-run/aggregation.ts +90 -0
- package/src/project-run/check-execution/callback.ts +106 -0
- package/src/project-run/check-execution/dependencies.ts +70 -0
- package/src/project-run/check-execution/execution-finalization.ts +177 -0
- package/src/project-run/check-execution/execution-settlement.ts +147 -0
- package/src/project-run/check-execution/messages.ts +46 -0
- package/src/project-run/check-execution/plan.ts +46 -0
- package/src/project-run/check-execution/preflight-result.ts +131 -0
- package/src/project-run/check-execution/preflight.ts +321 -0
- package/src/project-run/check-execution/resolved-checks.ts +285 -0
- package/src/project-run/check-execution/terminal-result.ts +74 -0
- package/src/project-run/completion.ts +263 -0
- package/src/project-run/controls/contract.ts +24 -0
- package/src/project-run/controls/outputs-override-validation.ts +86 -0
- package/src/project-run/controls/validation-result.ts +12 -0
- package/src/project-run/controls/validation.ts +176 -0
- package/src/project-run/diagnostic-logging/diagnostic-detail-rendering.ts +223 -0
- package/src/project-run/diagnostic-logging/logger.ts +325 -0
- package/src/project-run/invocation-creation.ts +160 -0
- package/src/project-run/invocation.ts +303 -0
- package/src/project-run/machine-publication.ts +23 -0
- package/src/project-run/output-configuration.ts +24 -0
- package/src/project-run/output-status.ts +69 -0
- package/src/project-run/progress-rendering/presentation.ts +189 -0
- package/src/project-run/progress-rendering/renderer-formatting.ts +141 -0
- package/src/project-run/progress-rendering/renderer-lifecycle.ts +152 -0
- package/src/project-run/progress-rendering/renderer.ts +68 -0
- package/src/project-run/project-context.ts +11 -0
- package/src/project-run/result.ts +175 -0
- package/src/project-run/run.ts +50 -0
- package/src/project-run/task-scheduler/execution-state.ts +153 -0
- package/src/project-run/task-scheduler/graph-validation.ts +176 -0
- package/src/project-run/task-scheduler/graph.ts +185 -0
- package/src/project-run/task-scheduler/scheduler-admission-decision.ts +177 -0
- package/src/project-run/task-scheduler/scheduler-blocker-summary.ts +42 -0
- package/src/project-run/task-scheduler/scheduler-decision-inspection.ts +199 -0
- package/src/project-run/task-scheduler/scheduler-decision-model.ts +158 -0
- package/src/project-run/task-scheduler/scheduler-decision.ts +103 -0
- package/src/project-run/task-scheduler/scheduler.ts +228 -0
- package/third-party-licenses/momoa-3.3.12-LICENSE +201 -0
- package/types/check/check.d.ts +350 -0
- package/types/check/descriptor-validation.d.ts +18 -0
- package/types/check/descriptor.d.ts +5 -0
- package/types/check/inherited-collection.d.ts +35 -0
- package/types/check/options-snapshot.d.ts +2 -0
- package/types/check-settlement/fact-validation.d.ts +14 -0
- package/types/check-settlement/facts.d.ts +19 -0
- package/types/check-settlement/outcome-normalization.d.ts +9 -0
- package/types/check-settlement/record-store.d.ts +14 -0
- package/types/check-settlement/session.d.ts +41 -0
- package/types/data-boundary/canonical-data.d.ts +13 -0
- package/types/data-boundary/canonical-json.d.ts +6 -0
- package/types/data-boundary/closed-values.d.ts +8 -0
- package/types/data-boundary/value-shapes.d.ts +4 -0
- package/types/finding-waivers/reconciliation.d.ts +66 -0
- package/types/index.d.ts +57 -0
- package/types/machine-output/v4/atomic-publication.d.ts +9 -0
- package/types/machine-output/v4/freeze-publication-value.d.ts +6 -0
- package/types/machine-output/v4/projection.d.ts +7 -0
- package/types/machine-output/v4/publication-invariants.d.ts +3 -0
- package/types/machine-output/v4/publication-model.d.ts +15 -0
- package/types/machine-output/v4/publish.d.ts +7 -0
- package/types/machine-output/v4/records-fingerprint.d.ts +4 -0
- package/types/machine-output/v4/schema-identities.d.ts +7 -0
- package/types/machine-output/v4/schema.d.ts +44 -0
- package/types/machine-output/v4/serializers.d.ts +6 -0
- package/types/machine-output/v4/validation-result.d.ts +26 -0
- package/types/machine-output/v4/validation.d.ts +6 -0
- package/types/package-checks/code-quality-findings/policy.d.ts +20 -0
- package/types/package-checks/duplicate-detection/area-policy.d.ts +3 -0
- package/types/package-checks/duplicate-detection/cache/cache-contract.d.ts +48 -0
- package/types/package-checks/duplicate-detection/cache/identity.d.ts +17 -0
- package/types/package-checks/duplicate-detection/cache/key.d.ts +4 -0
- package/types/package-checks/duplicate-detection/cache/payload.d.ts +4 -0
- package/types/package-checks/duplicate-detection/cache/store.d.ts +18 -0
- package/types/package-checks/duplicate-detection/default-check.d.ts +11 -0
- package/types/package-checks/duplicate-detection/execution.d.ts +11 -0
- package/types/package-checks/duplicate-detection/final-data.d.ts +5 -0
- package/types/package-checks/duplicate-detection/jscpd/availability.d.ts +19 -0
- package/types/package-checks/duplicate-detection/jscpd/command-path.d.ts +1 -0
- package/types/package-checks/duplicate-detection/jscpd/command-resolution.d.ts +23 -0
- package/types/package-checks/duplicate-detection/jscpd/json-report.d.ts +2 -0
- package/types/package-checks/duplicate-detection/jscpd/scanner-contract.d.ts +11 -0
- package/types/package-checks/duplicate-detection/jscpd/scanner.d.ts +21 -0
- package/types/package-checks/duplicate-detection/jscpd/scoped-fragments.d.ts +4 -0
- package/types/package-checks/duplicate-detection/measurement-model.d.ts +36 -0
- package/types/package-checks/duplicate-detection/measurement.d.ts +14 -0
- package/types/package-checks/duplicate-detection/options-resolution.d.ts +3 -0
- package/types/package-checks/duplicate-detection/options-validation.d.ts +1 -0
- package/types/package-checks/duplicate-detection/options.d.ts +65 -0
- package/types/package-checks/duplicate-detection/project-revision.d.ts +1 -0
- package/types/package-checks/duplicate-detection/records.d.ts +22 -0
- package/types/package-checks/file-metrics/constructor.d.ts +11 -0
- package/types/package-checks/file-metrics/execution.d.ts +11 -0
- package/types/package-checks/file-metrics/final-data.d.ts +5 -0
- package/types/package-checks/file-metrics/measurement-model.d.ts +12 -0
- package/types/package-checks/file-metrics/measurement.d.ts +13 -0
- package/types/package-checks/file-metrics/options-resolution.d.ts +3 -0
- package/types/package-checks/file-metrics/options-validation.d.ts +3 -0
- package/types/package-checks/file-metrics/options.d.ts +75 -0
- package/types/package-checks/file-metrics/records.d.ts +43 -0
- package/types/package-checks/file-metrics/scc/availability.d.ts +18 -0
- package/types/package-checks/file-metrics/scc/csv.d.ts +1 -0
- package/types/package-checks/file-metrics/scc/parser.d.ts +25 -0
- package/types/package-checks/file-metrics/scc/scanner.d.ts +14 -0
- package/types/package-checks/final-data-parsing.d.ts +9 -0
- package/types/package-checks/function-metrics/analysis.d.ts +10 -0
- package/types/package-checks/function-metrics/constructor.d.ts +11 -0
- package/types/package-checks/function-metrics/execution.d.ts +7 -0
- package/types/package-checks/function-metrics/final-data.d.ts +5 -0
- package/types/package-checks/function-metrics/lizard/availability.d.ts +11 -0
- package/types/package-checks/function-metrics/lizard/csv.d.ts +1 -0
- package/types/package-checks/function-metrics/lizard/parser.d.ts +17 -0
- package/types/package-checks/function-metrics/lizard/scanner.d.ts +15 -0
- package/types/package-checks/function-metrics/measurement-model.d.ts +26 -0
- package/types/package-checks/function-metrics/measurement.d.ts +21 -0
- package/types/package-checks/function-metrics/options-resolution.d.ts +3 -0
- package/types/package-checks/function-metrics/options-validation.d.ts +3 -0
- package/types/package-checks/function-metrics/options.d.ts +76 -0
- package/types/package-checks/function-metrics/records.d.ts +37 -0
- package/types/package-checks/function-metrics/target-files.d.ts +3 -0
- package/types/package-checks/host-environment/error-message.d.ts +1 -0
- package/types/package-checks/host-environment/filesystem.d.ts +19 -0
- package/types/package-checks/host-environment/git.d.ts +13 -0
- package/types/package-checks/host-environment/path.d.ts +3 -0
- package/types/package-checks/host-environment/process/command.d.ts +7 -0
- package/types/package-checks/host-environment/process/contract.d.ts +50 -0
- package/types/package-checks/host-environment/process/env.d.ts +16 -0
- package/types/package-checks/host-environment/process/failure.d.ts +4 -0
- package/types/package-checks/host-environment/process/result.d.ts +2 -0
- package/types/package-checks/host-environment/process/runner.d.ts +3 -0
- package/types/package-checks/json-document/strict-document.d.ts +35 -0
- package/types/package-checks/json-schema-validation/default-check.d.ts +11 -0
- package/types/package-checks/json-schema-validation/execution-stages.d.ts +27 -0
- package/types/package-checks/json-schema-validation/final-data.d.ts +15 -0
- package/types/package-checks/json-schema-validation/issue-collector.d.ts +12 -0
- package/types/package-checks/json-schema-validation/json-schema-validation.d.ts +42 -0
- package/types/package-checks/json-schema-validation/options-resolution.d.ts +3 -0
- package/types/package-checks/json-schema-validation/options-validation.d.ts +2 -0
- package/types/package-checks/json-schema-validation/options.d.ts +53 -0
- package/types/package-checks/json-schema-validation/reference-resolver.d.ts +23 -0
- package/types/package-checks/json-schema-validation/remote-response.d.ts +2 -0
- package/types/package-checks/json-schema-validation/schema-engine.d.ts +33 -0
- package/types/package-checks/json-schema-validation/schema-policy.d.ts +17 -0
- package/types/package-checks/json-validation/default-check.d.ts +11 -0
- package/types/package-checks/json-validation/final-data.d.ts +10 -0
- package/types/package-checks/json-validation/json-validation.d.ts +28 -0
- package/types/package-checks/json-validation/options-resolution.d.ts +3 -0
- package/types/package-checks/json-validation/options-validation.d.ts +2 -0
- package/types/package-checks/json-validation/options.d.ts +13 -0
- package/types/package-checks/maintenance-reminders/assessment-results.d.ts +10 -0
- package/types/package-checks/maintenance-reminders/final-data.d.ts +47 -0
- package/types/package-checks/maintenance-reminders/maintenance-reminders.d.ts +111 -0
- package/types/package-checks/maintenance-reminders/maintenance-support.d.ts +7 -0
- package/types/package-checks/maintenance-reminders/measurement.d.ts +10 -0
- package/types/package-checks/maintenance-reminders/options-validation.d.ts +3 -0
- package/types/package-checks/markdown-link-validation/default-check.d.ts +27 -0
- package/types/package-checks/markdown-link-validation/execution.d.ts +12 -0
- package/types/package-checks/markdown-link-validation/filesystem-probes.d.ts +10 -0
- package/types/package-checks/markdown-link-validation/final-data.d.ts +10 -0
- package/types/package-checks/markdown-link-validation/local-resolution.d.ts +92 -0
- package/types/package-checks/markdown-link-validation/local-resolver.d.ts +5 -0
- package/types/package-checks/markdown-link-validation/markdown-parser.d.ts +37 -0
- package/types/package-checks/markdown-link-validation/options-resolution.d.ts +3 -0
- package/types/package-checks/markdown-link-validation/options-validation.d.ts +2 -0
- package/types/package-checks/markdown-link-validation/options.d.ts +43 -0
- package/types/package-checks/markdown-link-validation/records.d.ts +37 -0
- package/types/package-checks/markdown-link-validation/resolver-engine.d.ts +15 -0
- package/types/package-checks/markdown-link-validation/target-descriptor.d.ts +5 -0
- package/types/package-checks/markdown-link-validation/traversal-result.d.ts +12 -0
- package/types/package-checks/project-files/collection.d.ts +9 -0
- package/types/package-checks/project-files/config-glob.d.ts +5 -0
- package/types/package-checks/project-files/configuration.d.ts +31 -0
- package/types/package-checks/project-files/exact-input-measurement.d.ts +12 -0
- package/types/package-checks/project-files/file-fingerprint.d.ts +7 -0
- package/types/package-checks/project-files/gitlink-revision.d.ts +9 -0
- package/types/package-checks/project-files/gitlink-worktree.d.ts +26 -0
- package/types/package-checks/project-files/input-eligibility.d.ts +7 -0
- package/types/package-checks/project-files/reported-path.d.ts +1 -0
- package/types/package-checks/project-files/revision-paths.d.ts +12 -0
- package/types/package-checks/project-files/revision-worktree-files.d.ts +5 -0
- package/types/project-definition/check-tree/authoring.d.ts +41 -0
- package/types/project-definition/check-tree/materialization.d.ts +4 -0
- package/types/project-definition/check-tree/resolution.d.ts +25 -0
- package/types/project-definition/output-defaults.d.ts +14 -0
- package/types/project-definition/output-validation.d.ts +3 -0
- package/types/project-definition/project-definition-validation.d.ts +6 -0
- package/types/project-definition/project-definition.d.ts +88 -0
- package/types/project-run/aggregation.d.ts +7 -0
- package/types/project-run/check-execution/callback.d.ts +24 -0
- package/types/project-run/check-execution/dependencies.d.ts +9 -0
- package/types/project-run/check-execution/execution-finalization.d.ts +18 -0
- package/types/project-run/check-execution/execution-settlement.d.ts +41 -0
- package/types/project-run/check-execution/messages.d.ts +3 -0
- package/types/project-run/check-execution/plan.d.ts +10 -0
- package/types/project-run/check-execution/preflight-result.d.ts +23 -0
- package/types/project-run/check-execution/preflight.d.ts +27 -0
- package/types/project-run/check-execution/resolved-checks.d.ts +51 -0
- package/types/project-run/check-execution/terminal-result.d.ts +27 -0
- package/types/project-run/completion.d.ts +14 -0
- package/types/project-run/controls/contract.d.ts +24 -0
- package/types/project-run/controls/outputs-override-validation.d.ts +3 -0
- package/types/project-run/controls/validation-result.d.ts +14 -0
- package/types/project-run/controls/validation.d.ts +3 -0
- package/types/project-run/diagnostic-logging/diagnostic-detail-rendering.d.ts +11 -0
- package/types/project-run/diagnostic-logging/logger.d.ts +33 -0
- package/types/project-run/invocation-creation.d.ts +12 -0
- package/types/project-run/invocation.d.ts +34 -0
- package/types/project-run/machine-publication.d.ts +10 -0
- package/types/project-run/output-configuration.d.ts +3 -0
- package/types/project-run/output-status.d.ts +21 -0
- package/types/project-run/progress-rendering/presentation.d.ts +28 -0
- package/types/project-run/progress-rendering/renderer-formatting.d.ts +23 -0
- package/types/project-run/progress-rendering/renderer-lifecycle.d.ts +24 -0
- package/types/project-run/progress-rendering/renderer.d.ts +44 -0
- package/types/project-run/project-context.d.ts +7 -0
- package/types/project-run/result.d.ts +99 -0
- package/types/project-run/run.d.ts +18 -0
- package/types/project-run/task-scheduler/execution-state.d.ts +67 -0
- package/types/project-run/task-scheduler/graph-validation.d.ts +11 -0
- package/types/project-run/task-scheduler/graph.d.ts +40 -0
- package/types/project-run/task-scheduler/scheduler-admission-decision.d.ts +8 -0
- package/types/project-run/task-scheduler/scheduler-blocker-summary.d.ts +4 -0
- package/types/project-run/task-scheduler/scheduler-decision-inspection.d.ts +24 -0
- package/types/project-run/task-scheduler/scheduler-decision-model.d.ts +94 -0
- package/types/project-run/task-scheduler/scheduler-decision.d.ts +8 -0
- package/types/project-run/task-scheduler/scheduler.d.ts +3 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-state.mjs","sourceRoot":"","sources":["../../../../src/project-run/task-scheduler/execution-state.ts"],"names":[],"mappings":"AAoEA,MAAM,UAAU,oBAAoB,CAClC,KAAuB,EACvB,OAAqC;IAErC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAwB,CAAC;IACnD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE;YACvB,KAAK;YACL,iBAAiB,EAAE,IAAI,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC;YACnD,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;IACL,CAAC;IACD,OAAO;QACL,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;QAC1C,KAAK;QACL,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;QACzB,WAAW,EAAE,IAAI,GAAG,EAAE;QACtB,cAAc,EAAE,IAAI,GAAG,EAAE;QACzB,mBAAmB,EAAE,IAAI,GAAG,EAAE;QAC9B,UAAU;QACV,iBAAiB,EAAE,SAAS;QAC5B,WAAW,EAAE,KAAK;KACnB,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,sBAAsB,CAAU,KAA8B;IAC5E,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC,MAAM,CAC3B,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;aAC3B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC;aACjC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAClC;QACD,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,gBAAgB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI;QAChD,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnE,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC;QACxD,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5D,YAAY,EAAE,MAAM,CAAC,MAAM,CACzB,CAAC,GAAG,KAAK,CAAC,mBAAmB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,CAC1D,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CACjD,CACF;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,IAAiB,EACjB,KAA8B;IAE9B,OAAO,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAU,KAA8B;IACxE,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,iBAAiB,GAAG,SAAS,CAAC;IACpC,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACnC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QACD,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,wBAAwB,EAAE,CAAC,CAAC,CAAC;IACnF,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,KAA8B,EAC9B,IAAiB,EACjB,UAAmC;IAEnC,IAAI,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,EAAE,yBAAyB,CAAC,CAAC;IAC5D,CAAC;IACD,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACxC,IAAI,KAAK,EAAE,KAAK,CAAC,cAAc,KAAK,IAAI,CAAC,EAAE,EAAE,CAAC;QAC5C,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC;IACzB,CAAC;AACH,CAAC","sourcesContent":["import type { PlannedTask, PlannedTaskGraph, PlannedTaskScope, TaskGraph } from \"./graph.ts\";\nimport type { DiagnosticLogger } from \"../diagnostic-logging/logger.ts\";\nimport type { SchedulerSnapshot } from \"./scheduler-decision.ts\";\n\nexport type TaskSettlement<TResult> = Readonly<\n | { readonly kind: \"completed\"; readonly value: TResult }\n | { readonly kind: \"failed\"; readonly error: unknown }\n | { readonly kind: \"blocked\"; readonly dependencyIds: readonly string[] }\n | { readonly kind: \"cancelled-before-start\" }\n>;\n\nexport interface SettledTask<TResult> {\n readonly task: PlannedTask;\n readonly settlement: TaskSettlement<TResult>;\n}\n\nexport interface TaskExecutionContext {\n readonly signal: AbortSignal | undefined;\n}\n\nexport interface TaskGraphRun<TResult> {\n readonly cancelled: boolean;\n /** One entry per static graph Task, in static graph order. */\n readonly settlements: readonly SettledTask<TResult>[];\n}\n\nexport interface RunTaskGraphOptions<TResult> {\n readonly diagnosticLogger?: DiagnosticLogger;\n readonly graph: TaskGraph;\n readonly maxParallel: number;\n readonly signal?: AbortSignal;\n readonly execute: (\n task: PlannedTask,\n context: TaskExecutionContext\n ) => TResult | Promise<TResult>;\n}\n\nexport type RunningTaskCompletion<TResult> = Readonly<{\n readonly taskId: string;\n readonly settlement: TaskSettlement<TResult>;\n}>;\n\nexport interface RunningTask<TResult> {\n readonly task: PlannedTask;\n readonly completion: Promise<RunningTaskCompletion<TResult>>;\n}\n\nexport interface RuntimeScope {\n readonly scope: PlannedTaskScope;\n readonly activationTaskIds: ReadonlySet<string>;\n isActive: boolean;\n}\n\nexport interface SchedulerState<TResult> {\n readonly diagnosticLogger: DiagnosticLogger | undefined;\n readonly graph: PlannedTaskGraph;\n readonly maxParallel: number;\n readonly signal: AbortSignal | undefined;\n readonly execute: RunTaskGraphOptions<TResult>[\"execute\"];\n readonly pending: PlannedTask[];\n readonly runningById: Map<string, RunningTask<TResult>>;\n readonly runningMutexes: Set<string>;\n readonly settlementsByTaskId: Map<string, TaskSettlement<TResult>>;\n readonly scopesById: ReadonlyMap<string, RuntimeScope>;\n reservationTaskId: string | undefined;\n isCancelled: boolean;\n}\n\nexport function createSchedulerState<TResult>(\n graph: PlannedTaskGraph,\n options: RunTaskGraphOptions<TResult>\n): SchedulerState<TResult> {\n const scopesById = new Map<string, RuntimeScope>();\n for (const scope of graph.scopes) {\n scopesById.set(scope.id, {\n scope,\n activationTaskIds: new Set(scope.activationTaskIds),\n isActive: false\n });\n }\n return {\n diagnosticLogger: options.diagnosticLogger,\n graph,\n maxParallel: options.maxParallel,\n signal: options.signal,\n execute: options.execute,\n pending: [...graph.tasks],\n runningById: new Map(),\n runningMutexes: new Set(),\n settlementsByTaskId: new Map(),\n scopesById,\n reservationTaskId: undefined,\n isCancelled: false\n };\n}\n\n/** Projects mutable execution state into the pure scheduler-decision input. */\nexport function snapshotSchedulerState<TResult>(state: SchedulerState<TResult>): SchedulerSnapshot {\n return Object.freeze({\n activeScopeIds: Object.freeze(\n [...state.scopesById.values()]\n .filter((scope) => scope.isActive)\n .map((scope) => scope.scope.id)\n ),\n graph: state.graph,\n isAbortRequested: state.signal?.aborted === true,\n isCancelled: state.isCancelled,\n maxParallel: state.maxParallel,\n pendingTaskIds: Object.freeze(state.pending.map((task) => task.id)),\n reservationTaskId: state.reservationTaskId,\n runningMutexes: Object.freeze([...state.runningMutexes]),\n runningTaskIds: Object.freeze([...state.runningById.keys()]),\n settledTasks: Object.freeze(\n [...state.settlementsByTaskId].map(([taskId, settlement]) =>\n Object.freeze({ kind: settlement.kind, taskId })\n )\n )\n });\n}\n\nexport function scopeForTask<TResult>(\n task: PlannedTask,\n state: SchedulerState<TResult>\n): RuntimeScope | undefined {\n return task.scopeId === undefined ? undefined : state.scopesById.get(task.scopeId);\n}\n\nexport function cancelPendingTasks<TResult>(state: SchedulerState<TResult>): void {\n state.isCancelled = true;\n state.reservationTaskId = undefined;\n while (state.pending.length > 0) {\n const task = state.pending.shift();\n if (task === undefined) {\n throw new Error(\"task graph pending queue changed unexpectedly\");\n }\n recordSettlement(state, task, Object.freeze({ kind: \"cancelled-before-start\" }));\n }\n}\n\nexport function recordSettlement<TResult>(\n state: SchedulerState<TResult>,\n task: PlannedTask,\n settlement: TaskSettlement<TResult>\n): void {\n if (state.settlementsByTaskId.has(task.id)) {\n throw new Error(`task ${task.id} settled more than once`);\n }\n state.settlementsByTaskId.set(task.id, settlement);\n const scope = scopeForTask(task, state);\n if (scope?.scope.terminalTaskId === task.id) {\n scope.isActive = false;\n }\n}\n"]}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/** Validates dependency and scope relations after graph-shaped input is normalized. */
|
|
2
|
+
export function validatePreparedTaskGraph(input) {
|
|
3
|
+
validateDependencies(input.tasks, input.taskById);
|
|
4
|
+
validateDependencyCycles(input.tasks, input.taskById);
|
|
5
|
+
validateScopes(input);
|
|
6
|
+
}
|
|
7
|
+
function validateDependencies(tasks, taskById) {
|
|
8
|
+
for (const task of tasks) {
|
|
9
|
+
for (const dependency of task.dependsOn) {
|
|
10
|
+
if (!taskById.has(dependency)) {
|
|
11
|
+
throw new Error(`task ${task.id} depends on unknown task ${dependency}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function validateDependencyCycles(tasks, taskById) {
|
|
17
|
+
const visiting = new Set();
|
|
18
|
+
const visited = new Set();
|
|
19
|
+
const visit = (task) => {
|
|
20
|
+
if (visiting.has(task.id)) {
|
|
21
|
+
throw new Error(`task dependency cycle includes ${task.id}`);
|
|
22
|
+
}
|
|
23
|
+
if (visited.has(task.id))
|
|
24
|
+
return;
|
|
25
|
+
visiting.add(task.id);
|
|
26
|
+
for (const dependency of task.dependsOn) {
|
|
27
|
+
const dependencyTask = taskById.get(dependency);
|
|
28
|
+
if (dependencyTask === undefined) {
|
|
29
|
+
throw new Error(`task ${task.id} depends on unknown task ${dependency}`);
|
|
30
|
+
}
|
|
31
|
+
visit(dependencyTask);
|
|
32
|
+
}
|
|
33
|
+
visiting.delete(task.id);
|
|
34
|
+
visited.add(task.id);
|
|
35
|
+
};
|
|
36
|
+
for (const task of tasks) {
|
|
37
|
+
visit(task);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function validateScopes(input) {
|
|
41
|
+
validateRootMaxParallel(input.rootMaxParallel);
|
|
42
|
+
validateTaskScopeMembership(input.tasks, input.scopeById);
|
|
43
|
+
for (const scope of input.scopes) {
|
|
44
|
+
validateScopeCap(scope, input.rootMaxParallel);
|
|
45
|
+
validateScopeTerminal(scope, input.taskById);
|
|
46
|
+
validateScopeActivation(scope, input.taskById);
|
|
47
|
+
validateScopeTerminalReachability(scope, input.tasks, input.taskById);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function validateRootMaxParallel(rootMaxParallel) {
|
|
51
|
+
if (rootMaxParallel !== undefined &&
|
|
52
|
+
(!Number.isSafeInteger(rootMaxParallel) || rootMaxParallel <= 0)) {
|
|
53
|
+
throw new TypeError("task engine maxParallel must be a positive safe integer");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function validateTaskScopeMembership(tasks, scopeById) {
|
|
57
|
+
for (const task of tasks) {
|
|
58
|
+
if (task.scopeId !== undefined && !scopeById.has(task.scopeId)) {
|
|
59
|
+
throw new Error(`task ${task.id} references unknown scope ${task.scopeId}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function validateScopeCap(scope, rootMaxParallel) {
|
|
64
|
+
if (rootMaxParallel !== undefined && scope.maxParallel > rootMaxParallel) {
|
|
65
|
+
throw new Error(`task scope ${scope.id} maxParallel exceeds task engine maxParallel`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function validateScopeTerminal(scope, taskById) {
|
|
69
|
+
const terminal = taskById.get(scope.terminalTaskId);
|
|
70
|
+
if (terminal?.scopeId !== scope.id) {
|
|
71
|
+
throw new Error(`task scope ${scope.id} terminal task must belong to the scope`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function validateScopeActivation(scope, taskById) {
|
|
75
|
+
const activationIds = new Set();
|
|
76
|
+
for (const taskId of scope.activationTaskIds) {
|
|
77
|
+
if (activationIds.has(taskId)) {
|
|
78
|
+
throw new Error(`task scope ${scope.id} repeats activation task ${taskId}`);
|
|
79
|
+
}
|
|
80
|
+
activationIds.add(taskId);
|
|
81
|
+
const task = taskById.get(taskId);
|
|
82
|
+
if (task?.scopeId !== scope.id) {
|
|
83
|
+
throw new Error(`task scope ${scope.id} activation task must belong to the scope: ${taskId}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function validateScopeTerminalReachability(scope, tasks, taskById) {
|
|
88
|
+
for (const task of tasks) {
|
|
89
|
+
if (task.scopeId !== scope.id || task.id === scope.terminalTaskId)
|
|
90
|
+
continue;
|
|
91
|
+
if (!dependsOnTask({ requiredDependencyId: task.id, taskById, taskId: scope.terminalTaskId })) {
|
|
92
|
+
throw new Error(`task scope ${scope.id} terminal task must depend on scoped task ${task.id}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function dependsOnTask(query) {
|
|
97
|
+
return traverseDependencies({
|
|
98
|
+
pending: [...taskDependencies(query.taskById, query.taskId)],
|
|
99
|
+
query,
|
|
100
|
+
visited: new Set()
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function traverseDependencies(traversal) {
|
|
104
|
+
while (traversal.pending.length > 0) {
|
|
105
|
+
const dependencyId = traversal.pending.pop();
|
|
106
|
+
if (dependencyId === undefined || traversal.visited.has(dependencyId))
|
|
107
|
+
continue;
|
|
108
|
+
if (dependencyId === traversal.query.requiredDependencyId)
|
|
109
|
+
return true;
|
|
110
|
+
traversal.visited.add(dependencyId);
|
|
111
|
+
traversal.pending.push(...taskDependencies(traversal.query.taskById, dependencyId));
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
function taskDependencies(taskById, taskId) {
|
|
116
|
+
const task = taskById.get(taskId);
|
|
117
|
+
return task === undefined ? [] : task.dependsOn;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=graph-validation.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-validation.mjs","sourceRoot":"","sources":["../../../../src/project-run/task-scheduler/graph-validation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PlannedTask, PlannedTaskScope } from \"./graph.ts\";\n\ninterface PreparedTaskGraphValidationInput {\n readonly rootMaxParallel: number | undefined;\n readonly scopeById: ReadonlyMap<string, PlannedTaskScope>;\n readonly scopes: readonly PlannedTaskScope[];\n readonly taskById: ReadonlyMap<string, PlannedTask>;\n readonly tasks: readonly PlannedTask[];\n}\n\ninterface DependencyPathQuery {\n readonly requiredDependencyId: string;\n readonly taskById: ReadonlyMap<string, PlannedTask>;\n readonly taskId: string;\n}\n\ninterface DependencyTraversal {\n readonly pending: string[];\n readonly query: DependencyPathQuery;\n readonly visited: Set<string>;\n}\n\n/** Validates dependency and scope relations after graph-shaped input is normalized. */\nexport function validatePreparedTaskGraph(input: PreparedTaskGraphValidationInput): void {\n validateDependencies(input.tasks, input.taskById);\n validateDependencyCycles(input.tasks, input.taskById);\n validateScopes(input);\n}\n\nfunction validateDependencies(\n tasks: readonly PlannedTask[],\n taskById: ReadonlyMap<string, PlannedTask>\n): void {\n for (const task of tasks) {\n for (const dependency of task.dependsOn) {\n if (!taskById.has(dependency)) {\n throw new Error(`task ${task.id} depends on unknown task ${dependency}`);\n }\n }\n }\n}\n\nfunction validateDependencyCycles(\n tasks: readonly PlannedTask[],\n taskById: ReadonlyMap<string, PlannedTask>\n): void {\n const visiting = new Set<string>();\n const visited = new Set<string>();\n\n const visit = (task: PlannedTask): void => {\n if (visiting.has(task.id)) {\n throw new Error(`task dependency cycle includes ${task.id}`);\n }\n if (visited.has(task.id)) return;\n\n visiting.add(task.id);\n for (const dependency of task.dependsOn) {\n const dependencyTask = taskById.get(dependency);\n if (dependencyTask === undefined) {\n throw new Error(`task ${task.id} depends on unknown task ${dependency}`);\n }\n visit(dependencyTask);\n }\n visiting.delete(task.id);\n visited.add(task.id);\n };\n\n for (const task of tasks) {\n visit(task);\n }\n}\n\nfunction validateScopes(input: PreparedTaskGraphValidationInput): void {\n validateRootMaxParallel(input.rootMaxParallel);\n validateTaskScopeMembership(input.tasks, input.scopeById);\n for (const scope of input.scopes) {\n validateScopeCap(scope, input.rootMaxParallel);\n validateScopeTerminal(scope, input.taskById);\n validateScopeActivation(scope, input.taskById);\n validateScopeTerminalReachability(scope, input.tasks, input.taskById);\n }\n}\n\nfunction validateRootMaxParallel(rootMaxParallel: number | undefined): void {\n if (\n rootMaxParallel !== undefined &&\n (!Number.isSafeInteger(rootMaxParallel) || rootMaxParallel <= 0)\n ) {\n throw new TypeError(\"task engine maxParallel must be a positive safe integer\");\n }\n}\n\nfunction validateTaskScopeMembership(\n tasks: readonly PlannedTask[],\n scopeById: ReadonlyMap<string, PlannedTaskScope>\n): void {\n for (const task of tasks) {\n if (task.scopeId !== undefined && !scopeById.has(task.scopeId)) {\n throw new Error(`task ${task.id} references unknown scope ${task.scopeId}`);\n }\n }\n}\n\nfunction validateScopeCap(scope: PlannedTaskScope, rootMaxParallel: number | undefined): void {\n if (rootMaxParallel !== undefined && scope.maxParallel > rootMaxParallel) {\n throw new Error(`task scope ${scope.id} maxParallel exceeds task engine maxParallel`);\n }\n}\n\nfunction validateScopeTerminal(\n scope: PlannedTaskScope,\n taskById: ReadonlyMap<string, PlannedTask>\n): void {\n const terminal = taskById.get(scope.terminalTaskId);\n if (terminal?.scopeId !== scope.id) {\n throw new Error(`task scope ${scope.id} terminal task must belong to the scope`);\n }\n}\n\nfunction validateScopeActivation(\n scope: PlannedTaskScope,\n taskById: ReadonlyMap<string, PlannedTask>\n): void {\n const activationIds = new Set<string>();\n for (const taskId of scope.activationTaskIds) {\n if (activationIds.has(taskId)) {\n throw new Error(`task scope ${scope.id} repeats activation task ${taskId}`);\n }\n activationIds.add(taskId);\n const task = taskById.get(taskId);\n if (task?.scopeId !== scope.id) {\n throw new Error(`task scope ${scope.id} activation task must belong to the scope: ${taskId}`);\n }\n }\n}\n\nfunction validateScopeTerminalReachability(\n scope: PlannedTaskScope,\n tasks: readonly PlannedTask[],\n taskById: ReadonlyMap<string, PlannedTask>\n): void {\n for (const task of tasks) {\n if (task.scopeId !== scope.id || task.id === scope.terminalTaskId) continue;\n if (!dependsOnTask({ requiredDependencyId: task.id, taskById, taskId: scope.terminalTaskId })) {\n throw new Error(`task scope ${scope.id} terminal task must depend on scoped task ${task.id}`);\n }\n }\n}\n\nfunction dependsOnTask(query: DependencyPathQuery): boolean {\n return traverseDependencies({\n pending: [...taskDependencies(query.taskById, query.taskId)],\n query,\n visited: new Set()\n });\n}\n\nfunction traverseDependencies(traversal: DependencyTraversal): boolean {\n while (traversal.pending.length > 0) {\n const dependencyId = traversal.pending.pop();\n if (dependencyId === undefined || traversal.visited.has(dependencyId)) continue;\n if (dependencyId === traversal.query.requiredDependencyId) return true;\n\n traversal.visited.add(dependencyId);\n traversal.pending.push(...taskDependencies(traversal.query.taskById, dependencyId));\n }\n return false;\n}\n\nfunction taskDependencies(\n taskById: ReadonlyMap<string, PlannedTask>,\n taskId: string\n): readonly string[] {\n const task = taskById.get(taskId);\n return task === undefined ? [] : task.dependsOn;\n}\n"]}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { validatePreparedTaskGraph } from "./graph-validation.mjs";
|
|
2
|
+
const TASK_GRAPH_KEYS = ["tasks", "scopes"];
|
|
3
|
+
const TASK_NODE_KEYS = ["id", "dependsOn", "mutex", "scopeId"];
|
|
4
|
+
const TASK_SCOPE_KEYS = ["id", "maxParallel", "activationTaskIds", "terminalTaskId"];
|
|
5
|
+
/** Validates untrusted graph-shaped input without admitting it to scheduler execution. */
|
|
6
|
+
export function validateTaskGraph(graph) {
|
|
7
|
+
prepareTaskGraph(graph);
|
|
8
|
+
}
|
|
9
|
+
export function prepareTaskGraph(graph, rootMaxParallel) {
|
|
10
|
+
const data = record(graph, "task graph", TASK_GRAPH_KEYS);
|
|
11
|
+
const tasks = normalizeTasks(data.tasks);
|
|
12
|
+
const scopes = normalizeScopes(data.scopes);
|
|
13
|
+
const taskById = new Map(tasks.map((task) => [task.id, task]));
|
|
14
|
+
const scopeById = new Map(scopes.map((scope) => [scope.id, scope]));
|
|
15
|
+
validatePreparedTaskGraph({ rootMaxParallel, scopeById, scopes, taskById, tasks });
|
|
16
|
+
return Object.freeze({
|
|
17
|
+
tasks: Object.freeze(tasks),
|
|
18
|
+
scopes: Object.freeze(scopes)
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function normalizeTasks(value) {
|
|
22
|
+
if (!Array.isArray(value)) {
|
|
23
|
+
throw new TypeError("task graph tasks must be an array");
|
|
24
|
+
}
|
|
25
|
+
const ids = new Set();
|
|
26
|
+
const tasks = [];
|
|
27
|
+
for (const [index, candidate] of value.entries()) {
|
|
28
|
+
const data = record(candidate, `task graph tasks[${index}]`, TASK_NODE_KEYS);
|
|
29
|
+
const id = nonEmptyString(data.id, `task graph tasks[${index}].id`);
|
|
30
|
+
if (ids.has(id)) {
|
|
31
|
+
throw new TypeError(`duplicate task id: ${id}`);
|
|
32
|
+
}
|
|
33
|
+
ids.add(id);
|
|
34
|
+
const scopeId = optionalNonEmptyString(data.scopeId, `task ${id}.scopeId`);
|
|
35
|
+
tasks.push(Object.freeze({
|
|
36
|
+
id,
|
|
37
|
+
dependsOn: Object.freeze(stringList(data.dependsOn, `task ${id}.dependsOn`)),
|
|
38
|
+
mutex: Object.freeze(stringList(data.mutex, `task ${id}.mutex`)),
|
|
39
|
+
scopeId
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
return tasks;
|
|
43
|
+
}
|
|
44
|
+
function normalizeScopes(value) {
|
|
45
|
+
if (value === undefined) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
if (!Array.isArray(value)) {
|
|
49
|
+
throw new TypeError("task graph scopes must be an array");
|
|
50
|
+
}
|
|
51
|
+
const ids = new Set();
|
|
52
|
+
const scopes = [];
|
|
53
|
+
for (const [index, candidate] of value.entries()) {
|
|
54
|
+
const data = record(candidate, `task graph scopes[${index}]`, TASK_SCOPE_KEYS);
|
|
55
|
+
const id = nonEmptyString(data.id, `task graph scopes[${index}].id`);
|
|
56
|
+
if (ids.has(id)) {
|
|
57
|
+
throw new TypeError(`duplicate task scope id: ${id}`);
|
|
58
|
+
}
|
|
59
|
+
ids.add(id);
|
|
60
|
+
const maxParallel = positiveSafeInteger(data.maxParallel, `task scope ${id}.maxParallel`);
|
|
61
|
+
const activationTaskIds = requiredStringList(data.activationTaskIds, `task scope ${id}.activationTaskIds`);
|
|
62
|
+
const terminalTaskId = nonEmptyString(data.terminalTaskId, `task scope ${id}.terminalTaskId`);
|
|
63
|
+
scopes.push(Object.freeze({
|
|
64
|
+
id,
|
|
65
|
+
maxParallel,
|
|
66
|
+
activationTaskIds: Object.freeze(activationTaskIds),
|
|
67
|
+
terminalTaskId
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
return scopes;
|
|
71
|
+
}
|
|
72
|
+
function record(value, fieldName, allowedKeys) {
|
|
73
|
+
if (!isTaskGraphRecord(value)) {
|
|
74
|
+
throw new TypeError(`${fieldName} must be an object`);
|
|
75
|
+
}
|
|
76
|
+
for (const key of Object.keys(value)) {
|
|
77
|
+
if (!allowedKeys.includes(key)) {
|
|
78
|
+
throw new TypeError(`${fieldName} has unknown property: ${key}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
function isTaskGraphRecord(value) {
|
|
84
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
85
|
+
}
|
|
86
|
+
function nonEmptyString(value, fieldName) {
|
|
87
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
88
|
+
throw new TypeError(`${fieldName} must be a non-empty string`);
|
|
89
|
+
}
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
function optionalNonEmptyString(value, fieldName) {
|
|
93
|
+
return value === undefined ? undefined : nonEmptyString(value, fieldName);
|
|
94
|
+
}
|
|
95
|
+
function stringList(value, fieldName) {
|
|
96
|
+
if (value === undefined) {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
if (!Array.isArray(value)) {
|
|
100
|
+
throw new TypeError(`${fieldName} must be an array of non-empty strings`);
|
|
101
|
+
}
|
|
102
|
+
return value.map((item, index) => nonEmptyString(item, `${fieldName}[${index}]`));
|
|
103
|
+
}
|
|
104
|
+
function requiredStringList(value, fieldName) {
|
|
105
|
+
if (value === undefined) {
|
|
106
|
+
throw new TypeError(`${fieldName} must be an array of non-empty strings`);
|
|
107
|
+
}
|
|
108
|
+
return stringList(value, fieldName);
|
|
109
|
+
}
|
|
110
|
+
function positiveSafeInteger(value, fieldName) {
|
|
111
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0) {
|
|
112
|
+
throw new TypeError(`${fieldName} must be a positive safe integer`);
|
|
113
|
+
}
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=graph.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.mjs","sourceRoot":"","sources":["../../../../src/project-run/task-scheduler/graph.ts"],"names":[],"mappings":"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","sourcesContent":["import { validatePreparedTaskGraph } from \"./graph-validation.ts\";\n\nexport interface TaskNode {\n readonly id: string;\n readonly dependsOn?: readonly string[];\n readonly mutex?: readonly string[];\n readonly scopeId?: string;\n}\n\n/**\n * A scheduling scope is intentionally product-agnostic. Product adapters may\n * use its opaque id to bind local Check semantics, but the engine only uses\n * membership, a cap, activation candidates, and the terminal relation.\n */\nexport interface TaskScope {\n readonly id: string;\n readonly maxParallel: number;\n readonly activationTaskIds: readonly string[];\n readonly terminalTaskId: string;\n}\n\nexport interface TaskGraph {\n readonly tasks: readonly TaskNode[];\n readonly scopes?: readonly TaskScope[];\n}\n\nexport interface PlannedTask {\n readonly id: string;\n readonly dependsOn: readonly string[];\n readonly mutex: readonly string[];\n readonly scopeId: string | undefined;\n}\n\nexport interface PlannedTaskScope {\n readonly id: string;\n readonly maxParallel: number;\n readonly activationTaskIds: readonly string[];\n readonly terminalTaskId: string;\n}\n\nexport interface PlannedTaskGraph {\n readonly tasks: readonly PlannedTask[];\n readonly scopes: readonly PlannedTaskScope[];\n}\n\nconst TASK_GRAPH_KEYS = [\"tasks\", \"scopes\"] as const;\nconst TASK_NODE_KEYS = [\"id\", \"dependsOn\", \"mutex\", \"scopeId\"] as const;\nconst TASK_SCOPE_KEYS = [\"id\", \"maxParallel\", \"activationTaskIds\", \"terminalTaskId\"] as const;\n\n/** Validates untrusted graph-shaped input without admitting it to scheduler execution. */\nexport function validateTaskGraph(graph: unknown): void {\n prepareTaskGraph(graph);\n}\n\nexport function prepareTaskGraph(graph: unknown, rootMaxParallel?: number): PlannedTaskGraph {\n const data = record(graph, \"task graph\", TASK_GRAPH_KEYS);\n const tasks = normalizeTasks(data.tasks);\n const scopes = normalizeScopes(data.scopes);\n const taskById = new Map(tasks.map((task) => [task.id, task] as const));\n const scopeById = new Map(scopes.map((scope) => [scope.id, scope] as const));\n\n validatePreparedTaskGraph({ rootMaxParallel, scopeById, scopes, taskById, tasks });\n\n return Object.freeze({\n tasks: Object.freeze(tasks),\n scopes: Object.freeze(scopes)\n });\n}\n\nfunction normalizeTasks(value: unknown): PlannedTask[] {\n if (!Array.isArray(value)) {\n throw new TypeError(\"task graph tasks must be an array\");\n }\n\n const ids = new Set<string>();\n const tasks: PlannedTask[] = [];\n for (const [index, candidate] of value.entries()) {\n const data = record(candidate, `task graph tasks[${index}]`, TASK_NODE_KEYS);\n const id = nonEmptyString(data.id, `task graph tasks[${index}].id`);\n if (ids.has(id)) {\n throw new TypeError(`duplicate task id: ${id}`);\n }\n ids.add(id);\n const scopeId = optionalNonEmptyString(data.scopeId, `task ${id}.scopeId`);\n tasks.push(\n Object.freeze({\n id,\n dependsOn: Object.freeze(stringList(data.dependsOn, `task ${id}.dependsOn`)),\n mutex: Object.freeze(stringList(data.mutex, `task ${id}.mutex`)),\n scopeId\n })\n );\n }\n return tasks;\n}\n\nfunction normalizeScopes(value: unknown): PlannedTaskScope[] {\n if (value === undefined) {\n return [];\n }\n if (!Array.isArray(value)) {\n throw new TypeError(\"task graph scopes must be an array\");\n }\n\n const ids = new Set<string>();\n const scopes: PlannedTaskScope[] = [];\n for (const [index, candidate] of value.entries()) {\n const data = record(candidate, `task graph scopes[${index}]`, TASK_SCOPE_KEYS);\n const id = nonEmptyString(data.id, `task graph scopes[${index}].id`);\n if (ids.has(id)) {\n throw new TypeError(`duplicate task scope id: ${id}`);\n }\n ids.add(id);\n const maxParallel = positiveSafeInteger(data.maxParallel, `task scope ${id}.maxParallel`);\n const activationTaskIds = requiredStringList(\n data.activationTaskIds,\n `task scope ${id}.activationTaskIds`\n );\n const terminalTaskId = nonEmptyString(data.terminalTaskId, `task scope ${id}.terminalTaskId`);\n scopes.push(\n Object.freeze({\n id,\n maxParallel,\n activationTaskIds: Object.freeze(activationTaskIds),\n terminalTaskId\n })\n );\n }\n return scopes;\n}\n\nfunction record(\n value: unknown,\n fieldName: string,\n allowedKeys: readonly string[]\n): Readonly<Record<string, unknown>> {\n if (!isTaskGraphRecord(value)) {\n throw new TypeError(`${fieldName} must be an object`);\n }\n for (const key of Object.keys(value)) {\n if (!allowedKeys.includes(key)) {\n throw new TypeError(`${fieldName} has unknown property: ${key}`);\n }\n }\n return value;\n}\n\nfunction isTaskGraphRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction nonEmptyString(value: unknown, fieldName: string): string {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new TypeError(`${fieldName} must be a non-empty string`);\n }\n return value;\n}\n\nfunction optionalNonEmptyString(value: unknown, fieldName: string): string | undefined {\n return value === undefined ? undefined : nonEmptyString(value, fieldName);\n}\n\nfunction stringList(value: unknown, fieldName: string): string[] {\n if (value === undefined) {\n return [];\n }\n if (!Array.isArray(value)) {\n throw new TypeError(`${fieldName} must be an array of non-empty strings`);\n }\n return value.map((item, index) => nonEmptyString(item, `${fieldName}[${index}]`));\n}\n\nfunction requiredStringList(value: unknown, fieldName: string): string[] {\n if (value === undefined) {\n throw new TypeError(`${fieldName} must be an array of non-empty strings`);\n }\n return stringList(value, fieldName);\n}\n\nfunction positiveSafeInteger(value: unknown, fieldName: string): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value <= 0) {\n throw new TypeError(`${fieldName} must be a positive safe integer`);\n }\n return value;\n}\n"]}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { activationScopeFor, canAdmit, capacityWaitReason, isDependencyMutexEligible, selectConstrainedContinuation, selectTighteningTask } from "./scheduler-decision-inspection.mjs";
|
|
2
|
+
import { freezeDecision, reservationClear, reservationSet, reservationUnchanged } from "./scheduler-decision-model.mjs";
|
|
3
|
+
export function decideAdmission(cycle) {
|
|
4
|
+
const eligibleTasks = cycle.state.pendingTasks.filter((task) => isDependencyMutexEligible(task, cycle.state));
|
|
5
|
+
if (eligibleTasks.length === 0) {
|
|
6
|
+
return awaitDecision(cycle, {
|
|
7
|
+
eligibleTasks,
|
|
8
|
+
reason: "dependency-or-mutex",
|
|
9
|
+
reservationUpdate: reservationUnchanged()
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
const reservedTask = taskById(cycle.state.reservationTaskId, eligibleTasks);
|
|
13
|
+
if (reservedTask !== undefined)
|
|
14
|
+
return decideReservedAdmission(cycle, eligibleTasks, reservedTask);
|
|
15
|
+
return decideUnreservedAdmission(cycle, eligibleTasks);
|
|
16
|
+
}
|
|
17
|
+
function decideReservedAdmission(cycle, eligibleTasks, reservedTask) {
|
|
18
|
+
const selection = {
|
|
19
|
+
reason: "reservation",
|
|
20
|
+
reservationUpdate: reservationClear(),
|
|
21
|
+
task: reservedTask
|
|
22
|
+
};
|
|
23
|
+
if (canAdmit(cycle.state, reservedTask))
|
|
24
|
+
return admitDecision(cycle, selection, eligibleTasks);
|
|
25
|
+
return awaitDecision(cycle, {
|
|
26
|
+
eligibleTasks,
|
|
27
|
+
reason: "reserved-tightening-scope",
|
|
28
|
+
reservationUpdate: reservationUnchanged()
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function decideUnreservedAdmission(cycle, eligibleTasks) {
|
|
32
|
+
const reservationUpdate = staleReservationUpdate(cycle.state);
|
|
33
|
+
const tighteningTask = selectTighteningTask(cycle.state, eligibleTasks, cycle.context.capacity.effectiveMaxParallel);
|
|
34
|
+
if (tighteningTask !== undefined) {
|
|
35
|
+
return admissionOrCapacityWait(cycle, eligibleTasks, { reason: "tightening-scope", reservationUpdate, task: tighteningTask }, "reserved-tightening-scope");
|
|
36
|
+
}
|
|
37
|
+
const continuation = selectConstrainedContinuation(cycle.state, eligibleTasks, cycle.context.capacity.effectiveMaxParallel);
|
|
38
|
+
if (continuation !== undefined) {
|
|
39
|
+
return admissionOrCapacityWait(cycle, eligibleTasks, { reason: "constrained-continuation", reservationUpdate, task: continuation }, capacityWaitReason(cycle.state));
|
|
40
|
+
}
|
|
41
|
+
return admissionOrCapacityWait(cycle, eligibleTasks, { reason: "canonical-order", reservationUpdate, task: eligibleTasks[0] }, capacityWaitReason(cycle.state));
|
|
42
|
+
}
|
|
43
|
+
function admissionOrCapacityWait(cycle, eligibleTasks, selection, waitReason) {
|
|
44
|
+
if (canAdmit(cycle.state, selection.task))
|
|
45
|
+
return admitDecision(cycle, selection, eligibleTasks);
|
|
46
|
+
const reservationUpdate = selection.reason === "tightening-scope"
|
|
47
|
+
? reservationSet(selection.task.id)
|
|
48
|
+
: selection.reservationUpdate;
|
|
49
|
+
return awaitDecision(cycle, { eligibleTasks, reason: waitReason, reservationUpdate });
|
|
50
|
+
}
|
|
51
|
+
function admitDecision(cycle, selection, eligibleTasks) {
|
|
52
|
+
return freezeDecision({
|
|
53
|
+
...cycle.context,
|
|
54
|
+
eligibleCount: eligibleTasks.length,
|
|
55
|
+
kind: "admit",
|
|
56
|
+
reason: selection.reason,
|
|
57
|
+
reservationUpdate: selection.reservationUpdate,
|
|
58
|
+
scopeToActivate: activationScopeFor(cycle.state, selection.task)?.id ?? null,
|
|
59
|
+
taskId: selection.task.id,
|
|
60
|
+
trigger: cycle.trigger
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function awaitDecision(cycle, waiting) {
|
|
64
|
+
if (cycle.state.runningTaskIds.size === 0) {
|
|
65
|
+
throw new Error("scheduler has pending tasks but no runnable or running task");
|
|
66
|
+
}
|
|
67
|
+
return freezeDecision({
|
|
68
|
+
...cycle.context,
|
|
69
|
+
eligibleCount: waiting.eligibleTasks.length,
|
|
70
|
+
kind: "await-running",
|
|
71
|
+
reason: waiting.reason,
|
|
72
|
+
reservationUpdate: waiting.reservationUpdate,
|
|
73
|
+
trigger: cycle.trigger
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function staleReservationUpdate(state) {
|
|
77
|
+
return state.reservationTaskId === undefined ? reservationUnchanged() : reservationClear();
|
|
78
|
+
}
|
|
79
|
+
function taskById(taskId, tasks) {
|
|
80
|
+
return taskId === undefined ? undefined : tasks.find((task) => task.id === taskId);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=scheduler-admission-decision.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler-admission-decision.mjs","sourceRoot":"","sources":["../../../../src/project-run/task-scheduler/scheduler-admission-decision.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PlannedTask } from \"./graph.ts\";\nimport {\n activationScopeFor,\n canAdmit,\n capacityWaitReason,\n isDependencyMutexEligible,\n selectConstrainedContinuation,\n selectTighteningTask,\n type SchedulerInspection\n} from \"./scheduler-decision-inspection.ts\";\nimport {\n freezeDecision,\n reservationClear,\n reservationSet,\n reservationUnchanged,\n type ReservationUpdate,\n type SchedulerAdmissionReason,\n type SchedulerAwaitReason,\n type SchedulerDecision,\n type SchedulerDecisionContext,\n type SchedulerTrigger\n} from \"./scheduler-decision-model.ts\";\n\nexport interface SchedulerDecisionCycle {\n readonly context: SchedulerDecisionContext;\n readonly state: SchedulerInspection;\n readonly trigger: SchedulerTrigger;\n}\n\ninterface AdmissionSelection {\n readonly reason: SchedulerAdmissionReason;\n readonly reservationUpdate: ReservationUpdate;\n readonly task: PlannedTask;\n}\n\ninterface AwaitingSchedulerDecision {\n readonly eligibleTasks: readonly PlannedTask[];\n readonly reason: SchedulerAwaitReason;\n readonly reservationUpdate: ReservationUpdate;\n}\n\nexport function decideAdmission(cycle: SchedulerDecisionCycle): SchedulerDecision {\n const eligibleTasks = cycle.state.pendingTasks.filter((task) =>\n isDependencyMutexEligible(task, cycle.state)\n );\n if (eligibleTasks.length === 0) {\n return awaitDecision(cycle, {\n eligibleTasks,\n reason: \"dependency-or-mutex\",\n reservationUpdate: reservationUnchanged()\n });\n }\n\n const reservedTask = taskById(cycle.state.reservationTaskId, eligibleTasks);\n if (reservedTask !== undefined)\n return decideReservedAdmission(cycle, eligibleTasks, reservedTask);\n\n return decideUnreservedAdmission(cycle, eligibleTasks);\n}\n\nfunction decideReservedAdmission(\n cycle: SchedulerDecisionCycle,\n eligibleTasks: readonly PlannedTask[],\n reservedTask: PlannedTask\n): SchedulerDecision {\n const selection: AdmissionSelection = {\n reason: \"reservation\",\n reservationUpdate: reservationClear(),\n task: reservedTask\n };\n if (canAdmit(cycle.state, reservedTask)) return admitDecision(cycle, selection, eligibleTasks);\n return awaitDecision(cycle, {\n eligibleTasks,\n reason: \"reserved-tightening-scope\",\n reservationUpdate: reservationUnchanged()\n });\n}\n\nfunction decideUnreservedAdmission(\n cycle: SchedulerDecisionCycle,\n eligibleTasks: readonly PlannedTask[]\n): SchedulerDecision {\n const reservationUpdate = staleReservationUpdate(cycle.state);\n const tighteningTask = selectTighteningTask(\n cycle.state,\n eligibleTasks,\n cycle.context.capacity.effectiveMaxParallel\n );\n if (tighteningTask !== undefined) {\n return admissionOrCapacityWait(\n cycle,\n eligibleTasks,\n { reason: \"tightening-scope\", reservationUpdate, task: tighteningTask },\n \"reserved-tightening-scope\"\n );\n }\n\n const continuation = selectConstrainedContinuation(\n cycle.state,\n eligibleTasks,\n cycle.context.capacity.effectiveMaxParallel\n );\n if (continuation !== undefined) {\n return admissionOrCapacityWait(\n cycle,\n eligibleTasks,\n { reason: \"constrained-continuation\", reservationUpdate, task: continuation },\n capacityWaitReason(cycle.state)\n );\n }\n\n return admissionOrCapacityWait(\n cycle,\n eligibleTasks,\n { reason: \"canonical-order\", reservationUpdate, task: eligibleTasks[0] },\n capacityWaitReason(cycle.state)\n );\n}\n\nfunction admissionOrCapacityWait(\n cycle: SchedulerDecisionCycle,\n eligibleTasks: readonly PlannedTask[],\n selection: AdmissionSelection,\n waitReason: SchedulerAwaitReason\n): SchedulerDecision {\n if (canAdmit(cycle.state, selection.task)) return admitDecision(cycle, selection, eligibleTasks);\n const reservationUpdate =\n selection.reason === \"tightening-scope\"\n ? reservationSet(selection.task.id)\n : selection.reservationUpdate;\n return awaitDecision(cycle, { eligibleTasks, reason: waitReason, reservationUpdate });\n}\n\nfunction admitDecision(\n cycle: SchedulerDecisionCycle,\n selection: AdmissionSelection,\n eligibleTasks: readonly PlannedTask[]\n): SchedulerDecision {\n return freezeDecision({\n ...cycle.context,\n eligibleCount: eligibleTasks.length,\n kind: \"admit\",\n reason: selection.reason,\n reservationUpdate: selection.reservationUpdate,\n scopeToActivate: activationScopeFor(cycle.state, selection.task)?.id ?? null,\n taskId: selection.task.id,\n trigger: cycle.trigger\n });\n}\n\nfunction awaitDecision(\n cycle: SchedulerDecisionCycle,\n waiting: AwaitingSchedulerDecision\n): SchedulerDecision {\n if (cycle.state.runningTaskIds.size === 0) {\n throw new Error(\"scheduler has pending tasks but no runnable or running task\");\n }\n return freezeDecision({\n ...cycle.context,\n eligibleCount: waiting.eligibleTasks.length,\n kind: \"await-running\",\n reason: waiting.reason,\n reservationUpdate: waiting.reservationUpdate,\n trigger: cycle.trigger\n });\n}\n\nfunction staleReservationUpdate(state: SchedulerInspection): ReservationUpdate {\n return state.reservationTaskId === undefined ? reservationUnchanged() : reservationClear();\n}\n\nfunction taskById(\n taskId: string | undefined,\n tasks: readonly PlannedTask[]\n): PlannedTask | undefined {\n return taskId === undefined ? undefined : tasks.find((task) => task.id === taskId);\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Summarizes why pending Tasks cannot currently advance. */
|
|
2
|
+
export function summarizeSchedulerBlockers(state, capacity) {
|
|
3
|
+
let dependency = 0;
|
|
4
|
+
let mutex = 0;
|
|
5
|
+
for (const task of state.pendingTasks) {
|
|
6
|
+
if (hasUncompletedDependency(task.dependsOn, state.settlementKindByTaskId)) {
|
|
7
|
+
dependency += 1;
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
if (hasRunningMutex(task.mutex, state.runningMutexes))
|
|
11
|
+
mutex += 1;
|
|
12
|
+
}
|
|
13
|
+
return Object.freeze({
|
|
14
|
+
dependency,
|
|
15
|
+
mutex,
|
|
16
|
+
rootCapacity: state.runningTaskIds.size >= state.maxParallel,
|
|
17
|
+
scopeCapacity: capacity.effectiveMaxParallel < state.maxParallel &&
|
|
18
|
+
state.runningTaskIds.size >= capacity.effectiveMaxParallel
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function hasUncompletedDependency(dependencyIds, settlementKindByTaskId) {
|
|
22
|
+
return dependencyIds.some((dependencyId) => settlementKindByTaskId.get(dependencyId) !== "completed");
|
|
23
|
+
}
|
|
24
|
+
function hasRunningMutex(mutexNames, runningMutexes) {
|
|
25
|
+
return mutexNames.some((mutexName) => runningMutexes.has(mutexName));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=scheduler-blocker-summary.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler-blocker-summary.mjs","sourceRoot":"","sources":["../../../../src/project-run/task-scheduler/scheduler-blocker-summary.ts"],"names":[],"mappings":"AAGA,6DAA6D;AAC7D,MAAM,UAAU,0BAA0B,CACxC,KAA0B,EAC1B,QAA2B;IAE3B,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QACtC,IAAI,wBAAwB,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,sBAAsB,CAAC,EAAE,CAAC;YAC3E,UAAU,IAAI,CAAC,CAAC;YAChB,SAAS;QACX,CAAC;QACD,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC;YAAE,KAAK,IAAI,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,UAAU;QACV,KAAK;QACL,YAAY,EAAE,KAAK,CAAC,cAAc,CAAC,IAAI,IAAI,KAAK,CAAC,WAAW;QAC5D,aAAa,EACX,QAAQ,CAAC,oBAAoB,GAAG,KAAK,CAAC,WAAW;YACjD,KAAK,CAAC,cAAc,CAAC,IAAI,IAAI,QAAQ,CAAC,oBAAoB;KAC7D,CAAC,CAAC;AACL,CAAC;AAED,SAAS,wBAAwB,CAC/B,aAAgC,EAChC,sBAAqE;IAErE,OAAO,aAAa,CAAC,IAAI,CACvB,CAAC,YAAY,EAAE,EAAE,CAAC,sBAAsB,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,WAAW,CAC3E,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CACtB,UAA6B,EAC7B,cAAqD;IAErD,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;AACvE,CAAC","sourcesContent":["import type { SchedulerInspection } from \"./scheduler-decision-inspection.ts\";\nimport type { SchedulerBlockerSummary, SchedulerCapacity } from \"./scheduler-decision-model.ts\";\n\n/** Summarizes why pending Tasks cannot currently advance. */\nexport function summarizeSchedulerBlockers(\n state: SchedulerInspection,\n capacity: SchedulerCapacity\n): SchedulerBlockerSummary {\n let dependency = 0;\n let mutex = 0;\n for (const task of state.pendingTasks) {\n if (hasUncompletedDependency(task.dependsOn, state.settlementKindByTaskId)) {\n dependency += 1;\n continue;\n }\n if (hasRunningMutex(task.mutex, state.runningMutexes)) mutex += 1;\n }\n return Object.freeze({\n dependency,\n mutex,\n rootCapacity: state.runningTaskIds.size >= state.maxParallel,\n scopeCapacity:\n capacity.effectiveMaxParallel < state.maxParallel &&\n state.runningTaskIds.size >= capacity.effectiveMaxParallel\n });\n}\n\nfunction hasUncompletedDependency(\n dependencyIds: readonly string[],\n settlementKindByTaskId: SchedulerInspection[\"settlementKindByTaskId\"]\n): boolean {\n return dependencyIds.some(\n (dependencyId) => settlementKindByTaskId.get(dependencyId) !== \"completed\"\n );\n}\n\nfunction hasRunningMutex(\n mutexNames: readonly string[],\n runningMutexes: SchedulerInspection[\"runningMutexes\"]\n): boolean {\n return mutexNames.some((mutexName) => runningMutexes.has(mutexName));\n}\n"]}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { summarizeSchedulerBlockers } from "./scheduler-blocker-summary.mjs";
|
|
2
|
+
export function inspectSnapshot(snapshot) {
|
|
3
|
+
const tasksById = new Map(snapshot.graph.tasks.map((task) => [task.id, task]));
|
|
4
|
+
const pendingTasks = snapshot.pendingTaskIds.map((taskId) => pendingTaskFor(taskId, tasksById));
|
|
5
|
+
return Object.freeze({
|
|
6
|
+
activeScopeIds: new Set(snapshot.activeScopeIds),
|
|
7
|
+
graph: snapshot.graph,
|
|
8
|
+
maxParallel: snapshot.maxParallel,
|
|
9
|
+
pendingTasks: Object.freeze(pendingTasks),
|
|
10
|
+
reservationTaskId: snapshot.reservationTaskId,
|
|
11
|
+
runningMutexes: new Set(snapshot.runningMutexes),
|
|
12
|
+
runningTaskIds: new Set(snapshot.runningTaskIds),
|
|
13
|
+
settlementKindByTaskId: new Map(snapshot.settledTasks.map(({ taskId, kind }) => [taskId, kind]))
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export function decisionContext(state) {
|
|
17
|
+
const capacity = capacityFor(state);
|
|
18
|
+
return Object.freeze({
|
|
19
|
+
blockers: summarizeSchedulerBlockers(state, capacity),
|
|
20
|
+
capacity,
|
|
21
|
+
reservation: Object.freeze({ taskId: state.reservationTaskId ?? null })
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
export function selectBlockedTask(state) {
|
|
25
|
+
for (let index = state.pendingTasks.length - 1; index >= 0; index -= 1) {
|
|
26
|
+
const task = state.pendingTasks[index];
|
|
27
|
+
const dependencyIds = blockingDependencyIds(task, state.settlementKindByTaskId);
|
|
28
|
+
if (dependencyIds !== undefined)
|
|
29
|
+
return Object.freeze({ dependencyIds: Object.freeze(dependencyIds), task });
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
export function isDependencyMutexEligible(task, state) {
|
|
34
|
+
return (task.dependsOn.every((dependencyId) => state.settlementKindByTaskId.get(dependencyId) === "completed") && task.mutex.every((mutex) => !state.runningMutexes.has(mutex)));
|
|
35
|
+
}
|
|
36
|
+
export function capacityWaitReason(state) {
|
|
37
|
+
return state.runningTaskIds.size >= state.maxParallel ? "root-capacity" : "active-scope-capacity";
|
|
38
|
+
}
|
|
39
|
+
export function canAdmit(state, task) {
|
|
40
|
+
return state.runningTaskIds.size < prospectiveMaxParallel(state, task);
|
|
41
|
+
}
|
|
42
|
+
export function activationScopeFor(state, task) {
|
|
43
|
+
const scope = scopeForTask(state, task);
|
|
44
|
+
return scope?.activationTaskIds.includes(task.id) === true && !state.activeScopeIds.has(scope.id)
|
|
45
|
+
? scope
|
|
46
|
+
: undefined;
|
|
47
|
+
}
|
|
48
|
+
export function selectTighteningTask(state, eligibleTasks, effectiveMaxParallel) {
|
|
49
|
+
return eligibleTasks
|
|
50
|
+
.filter((task) => activatesTighteningScope(state, task, effectiveMaxParallel))
|
|
51
|
+
.sort((left, right) => compareConstrainedTasks(state, left, right))[0];
|
|
52
|
+
}
|
|
53
|
+
export function selectConstrainedContinuation(state, eligibleTasks, effectiveMaxParallel) {
|
|
54
|
+
return eligibleTasks
|
|
55
|
+
.filter((task) => isConstrainedContinuation(state, task, effectiveMaxParallel))
|
|
56
|
+
.sort((left, right) => compareConstrainedTasks(state, left, right))[0];
|
|
57
|
+
}
|
|
58
|
+
function pendingTaskFor(taskId, tasksById) {
|
|
59
|
+
const task = tasksById.get(taskId);
|
|
60
|
+
if (task === undefined)
|
|
61
|
+
throw new Error(`scheduler snapshot has unknown pending task ${taskId}`);
|
|
62
|
+
return task;
|
|
63
|
+
}
|
|
64
|
+
function blockingDependencyIds(task, settlementKindByTaskId) {
|
|
65
|
+
const settlementKinds = task.dependsOn.map((dependencyId) => [dependencyId, settlementKindByTaskId.get(dependencyId)]);
|
|
66
|
+
if (settlementKinds.some(([, kind]) => kind === undefined))
|
|
67
|
+
return undefined;
|
|
68
|
+
const dependencyIds = settlementKinds.flatMap(([dependencyId, kind]) => kind === "completed" ? [] : [dependencyId]);
|
|
69
|
+
return dependencyIds.length === 0 ? undefined : dependencyIds;
|
|
70
|
+
}
|
|
71
|
+
function capacityFor(state) {
|
|
72
|
+
return Object.freeze({
|
|
73
|
+
effectiveMaxParallel: effectiveMaxParallelFor(state),
|
|
74
|
+
maxParallel: state.maxParallel,
|
|
75
|
+
running: state.runningTaskIds.size
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function effectiveMaxParallelFor(state) {
|
|
79
|
+
let effective = state.maxParallel;
|
|
80
|
+
for (const scope of state.graph.scopes) {
|
|
81
|
+
if (state.activeScopeIds.has(scope.id))
|
|
82
|
+
effective = Math.min(effective, scope.maxParallel);
|
|
83
|
+
}
|
|
84
|
+
return effective;
|
|
85
|
+
}
|
|
86
|
+
function prospectiveMaxParallel(state, task) {
|
|
87
|
+
const scope = activationScopeFor(state, task);
|
|
88
|
+
return scope === undefined
|
|
89
|
+
? effectiveMaxParallelFor(state)
|
|
90
|
+
: Math.min(effectiveMaxParallelFor(state), scope.maxParallel);
|
|
91
|
+
}
|
|
92
|
+
function activatesTighteningScope(state, task, effectiveMaxParallel) {
|
|
93
|
+
const scope = activationScopeFor(state, task);
|
|
94
|
+
return scope !== undefined && scope.maxParallel < effectiveMaxParallel;
|
|
95
|
+
}
|
|
96
|
+
function isConstrainedContinuation(state, task, effectiveMaxParallel) {
|
|
97
|
+
const scope = scopeForTask(state, task);
|
|
98
|
+
return (scope !== undefined &&
|
|
99
|
+
state.activeScopeIds.has(scope.id) &&
|
|
100
|
+
scope.maxParallel < state.maxParallel &&
|
|
101
|
+
scope.maxParallel === effectiveMaxParallel);
|
|
102
|
+
}
|
|
103
|
+
function compareConstrainedTasks(state, left, right) {
|
|
104
|
+
const leftScope = scopeForTask(state, left);
|
|
105
|
+
const rightScope = scopeForTask(state, right);
|
|
106
|
+
if (leftScope === undefined || rightScope === undefined) {
|
|
107
|
+
throw new Error("constrained task is missing a scope");
|
|
108
|
+
}
|
|
109
|
+
return (leftScope.maxParallel - rightScope.maxParallel ||
|
|
110
|
+
compareText(leftScope.id, rightScope.id) ||
|
|
111
|
+
compareText(left.id, right.id));
|
|
112
|
+
}
|
|
113
|
+
function compareText(left, right) {
|
|
114
|
+
if (left < right)
|
|
115
|
+
return -1;
|
|
116
|
+
if (left > right)
|
|
117
|
+
return 1;
|
|
118
|
+
return 0;
|
|
119
|
+
}
|
|
120
|
+
function scopeForTask(state, task) {
|
|
121
|
+
return task.scopeId === undefined
|
|
122
|
+
? undefined
|
|
123
|
+
: state.graph.scopes.find((scope) => scope.id === task.scopeId);
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=scheduler-decision-inspection.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler-decision-inspection.mjs","sourceRoot":"","sources":["../../../../src/project-run/task-scheduler/scheduler-decision-inspection.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PlannedTask, PlannedTaskGraph, PlannedTaskScope } from \"./graph.ts\";\nimport { summarizeSchedulerBlockers } from \"./scheduler-blocker-summary.ts\";\nimport type {\n SchedulerAwaitReason,\n SchedulerCapacity,\n SchedulerDecisionContext,\n SchedulerSettlementKind,\n SchedulerSnapshot\n} from \"./scheduler-decision-model.ts\";\n\nexport interface SchedulerInspection {\n readonly activeScopeIds: ReadonlySet<string>;\n readonly graph: PlannedTaskGraph;\n readonly maxParallel: number;\n readonly pendingTasks: readonly PlannedTask[];\n readonly reservationTaskId: string | undefined;\n readonly runningMutexes: ReadonlySet<string>;\n readonly runningTaskIds: ReadonlySet<string>;\n readonly settlementKindByTaskId: ReadonlyMap<string, SchedulerSettlementKind>;\n}\n\nexport function inspectSnapshot(snapshot: SchedulerSnapshot): SchedulerInspection {\n const tasksById = new Map(snapshot.graph.tasks.map((task) => [task.id, task] as const));\n const pendingTasks = snapshot.pendingTaskIds.map((taskId) => pendingTaskFor(taskId, tasksById));\n return Object.freeze({\n activeScopeIds: new Set(snapshot.activeScopeIds),\n graph: snapshot.graph,\n maxParallel: snapshot.maxParallel,\n pendingTasks: Object.freeze(pendingTasks),\n reservationTaskId: snapshot.reservationTaskId,\n runningMutexes: new Set(snapshot.runningMutexes),\n runningTaskIds: new Set(snapshot.runningTaskIds),\n settlementKindByTaskId: new Map(\n snapshot.settledTasks.map(({ taskId, kind }) => [taskId, kind] as const)\n )\n });\n}\n\nexport function decisionContext(state: SchedulerInspection): SchedulerDecisionContext {\n const capacity = capacityFor(state);\n return Object.freeze({\n blockers: summarizeSchedulerBlockers(state, capacity),\n capacity,\n reservation: Object.freeze({ taskId: state.reservationTaskId ?? null })\n });\n}\n\nexport function selectBlockedTask(\n state: SchedulerInspection\n): Readonly<{ readonly dependencyIds: readonly string[]; readonly task: PlannedTask }> | undefined {\n for (let index = state.pendingTasks.length - 1; index >= 0; index -= 1) {\n const task = state.pendingTasks[index];\n const dependencyIds = blockingDependencyIds(task, state.settlementKindByTaskId);\n if (dependencyIds !== undefined)\n return Object.freeze({ dependencyIds: Object.freeze(dependencyIds), task });\n }\n return undefined;\n}\n\nexport function isDependencyMutexEligible(task: PlannedTask, state: SchedulerInspection): boolean {\n return (\n task.dependsOn.every(\n (dependencyId) => state.settlementKindByTaskId.get(dependencyId) === \"completed\"\n ) && task.mutex.every((mutex) => !state.runningMutexes.has(mutex))\n );\n}\n\nexport function capacityWaitReason(state: SchedulerInspection): SchedulerAwaitReason {\n return state.runningTaskIds.size >= state.maxParallel ? \"root-capacity\" : \"active-scope-capacity\";\n}\n\nexport function canAdmit(state: SchedulerInspection, task: PlannedTask): boolean {\n return state.runningTaskIds.size < prospectiveMaxParallel(state, task);\n}\n\nexport function activationScopeFor(\n state: SchedulerInspection,\n task: PlannedTask\n): PlannedTaskScope | undefined {\n const scope = scopeForTask(state, task);\n return scope?.activationTaskIds.includes(task.id) === true && !state.activeScopeIds.has(scope.id)\n ? scope\n : undefined;\n}\n\nexport function selectTighteningTask(\n state: SchedulerInspection,\n eligibleTasks: readonly PlannedTask[],\n effectiveMaxParallel: number\n): PlannedTask | undefined {\n return eligibleTasks\n .filter((task) => activatesTighteningScope(state, task, effectiveMaxParallel))\n .sort((left, right) => compareConstrainedTasks(state, left, right))[0];\n}\n\nexport function selectConstrainedContinuation(\n state: SchedulerInspection,\n eligibleTasks: readonly PlannedTask[],\n effectiveMaxParallel: number\n): PlannedTask | undefined {\n return eligibleTasks\n .filter((task) => isConstrainedContinuation(state, task, effectiveMaxParallel))\n .sort((left, right) => compareConstrainedTasks(state, left, right))[0];\n}\n\nfunction pendingTaskFor(taskId: string, tasksById: ReadonlyMap<string, PlannedTask>): PlannedTask {\n const task = tasksById.get(taskId);\n if (task === undefined) throw new Error(`scheduler snapshot has unknown pending task ${taskId}`);\n return task;\n}\n\nfunction blockingDependencyIds(\n task: PlannedTask,\n settlementKindByTaskId: ReadonlyMap<string, SchedulerSettlementKind>\n): string[] | undefined {\n const settlementKinds = task.dependsOn.map(\n (dependencyId) => [dependencyId, settlementKindByTaskId.get(dependencyId)] as const\n );\n if (settlementKinds.some(([, kind]) => kind === undefined)) return undefined;\n const dependencyIds = settlementKinds.flatMap(([dependencyId, kind]) =>\n kind === \"completed\" ? [] : [dependencyId]\n );\n return dependencyIds.length === 0 ? undefined : dependencyIds;\n}\n\nfunction capacityFor(state: SchedulerInspection): SchedulerCapacity {\n return Object.freeze({\n effectiveMaxParallel: effectiveMaxParallelFor(state),\n maxParallel: state.maxParallel,\n running: state.runningTaskIds.size\n });\n}\n\nfunction effectiveMaxParallelFor(state: SchedulerInspection): number {\n let effective = state.maxParallel;\n for (const scope of state.graph.scopes) {\n if (state.activeScopeIds.has(scope.id)) effective = Math.min(effective, scope.maxParallel);\n }\n return effective;\n}\n\nfunction prospectiveMaxParallel(state: SchedulerInspection, task: PlannedTask): number {\n const scope = activationScopeFor(state, task);\n return scope === undefined\n ? effectiveMaxParallelFor(state)\n : Math.min(effectiveMaxParallelFor(state), scope.maxParallel);\n}\n\nfunction activatesTighteningScope(\n state: SchedulerInspection,\n task: PlannedTask,\n effectiveMaxParallel: number\n): boolean {\n const scope = activationScopeFor(state, task);\n return scope !== undefined && scope.maxParallel < effectiveMaxParallel;\n}\n\nfunction isConstrainedContinuation(\n state: SchedulerInspection,\n task: PlannedTask,\n effectiveMaxParallel: number\n): boolean {\n const scope = scopeForTask(state, task);\n return (\n scope !== undefined &&\n state.activeScopeIds.has(scope.id) &&\n scope.maxParallel < state.maxParallel &&\n scope.maxParallel === effectiveMaxParallel\n );\n}\n\nfunction compareConstrainedTasks(\n state: SchedulerInspection,\n left: PlannedTask,\n right: PlannedTask\n): number {\n const leftScope = scopeForTask(state, left);\n const rightScope = scopeForTask(state, right);\n if (leftScope === undefined || rightScope === undefined) {\n throw new Error(\"constrained task is missing a scope\");\n }\n return (\n leftScope.maxParallel - rightScope.maxParallel ||\n compareText(leftScope.id, rightScope.id) ||\n compareText(left.id, right.id)\n );\n}\n\nfunction compareText(left: string, right: string): number {\n if (left < right) return -1;\n if (left > right) return 1;\n return 0;\n}\n\nfunction scopeForTask(state: SchedulerInspection, task: PlannedTask): PlannedTaskScope | undefined {\n return task.scopeId === undefined\n ? undefined\n : state.graph.scopes.find((scope) => scope.id === task.scopeId);\n}\n"]}
|