@deksden-com/dd-flow-cli 0.9.0-beta.15 → 0.9.0-beta.150
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/CHANGELOG.md +895 -0
- package/README.md +140 -6
- package/dist/build-info.json +8 -8
- package/dist/cli/argument-values.js +38 -0
- package/dist/cli/command-inputs.js +386 -0
- package/dist/cli/command-metadata.js +232 -0
- package/dist/cli/command-option-descriptions.js +192 -0
- package/dist/cli/completion-cli.js +70 -0
- package/dist/cli/completion.js +57 -0
- package/dist/cli/diagnostic-invocation.js +46 -0
- package/dist/cli/diagnostic.js +120 -0
- package/dist/cli/error-output.js +52 -0
- package/dist/cli/executor-onboarding.js +76 -0
- package/dist/cli/flows.js +29 -0
- package/dist/cli/harnesses.js +84 -0
- package/dist/cli/help.js +396 -19
- package/dist/cli/hook-ingress.js +102 -0
- package/dist/cli/input-preparation.js +165 -0
- package/dist/cli/memory-flow-admission.js +50 -0
- package/dist/cli/memory-init-invocation.js +85 -0
- package/dist/cli/memory-init.js +249 -0
- package/dist/cli/memory-storage-admission.js +54 -0
- package/dist/cli/memory-storage-qualification.js +105 -0
- package/dist/cli/memory-storage-transition.js +123 -0
- package/dist/cli/memory-upgrade.js +189 -0
- package/dist/cli/models.js +39 -0
- package/dist/cli/native-hook-ingress.js +90 -0
- package/dist/cli/native-hook-preparation.js +55 -0
- package/dist/cli/operator-profiles.js +61 -0
- package/dist/cli/output-options.js +35 -0
- package/dist/cli/response-file.js +72 -0
- package/dist/cli/run-cli.js +1734 -550
- package/dist/cli/runtime-maintenance-diagnostics.js +46 -0
- package/dist/cli/runtime-maintenance-ingress.js +52 -0
- package/dist/cli/runtime-process.js +153 -0
- package/dist/cli/setup.js +150 -0
- package/dist/cli.js +89 -2
- package/dist/domain/diagnostic-aspects.js +103 -0
- package/dist/domain/diagnostic-flows.js +8 -0
- package/dist/domain/stage-catalog.js +1 -1
- package/dist/domain/stage-handler-identities.js +28 -0
- package/dist/harness-runtime/DD-ZCODE.md +112 -0
- package/dist/harness-runtime/OPENCODE-LICENSE.txt +24 -0
- package/dist/harness-runtime/bin/dd-agy.mjs +56 -0
- package/dist/harness-runtime/bin/dd-codex.mjs +27 -0
- package/dist/harness-runtime/bin/dd-droid.mjs +34 -0
- package/dist/harness-runtime/bin/dd-grok.mjs +40 -0
- package/dist/harness-runtime/bin/dd-opencode.mjs +22 -0
- package/dist/harness-runtime/bin/dd-zcode.mjs +87 -0
- package/dist/harness-runtime/lib/adapter-timeouts.d.mts +5 -0
- package/dist/harness-runtime/lib/adapter-timeouts.mjs +34 -0
- package/dist/harness-runtime/lib/agy-error-boundary.mjs +58 -0
- package/dist/harness-runtime/lib/agy-hooks.d.mts +1 -0
- package/dist/harness-runtime/lib/agy-hooks.mjs +9 -0
- package/dist/harness-runtime/lib/agy-native-inspection.mjs +216 -0
- package/dist/harness-runtime/lib/agy-native_pb.js +117 -0
- package/dist/harness-runtime/lib/daemon-observation.d.mts +2 -0
- package/dist/harness-runtime/lib/daemon-observation.mjs +163 -0
- package/dist/harness-runtime/lib/daemon-operations.d.mts +2 -0
- package/dist/harness-runtime/lib/daemon-operations.mjs +462 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +6 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.mjs +1096 -0
- package/dist/harness-runtime/lib/dd-agy.mjs +86 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.mjs +231 -0
- package/dist/harness-runtime/lib/dd-codex.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-codex.mjs +954 -0
- package/dist/harness-runtime/lib/dd-droid-daemon.mjs +141 -0
- package/dist/harness-runtime/lib/dd-droid.mjs +626 -0
- package/dist/harness-runtime/lib/dd-grok-daemon.mjs +555 -0
- package/dist/harness-runtime/lib/dd-grok.mjs +180 -0
- package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +622 -0
- package/dist/harness-runtime/lib/dd-opencode.mjs +390 -0
- package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +752 -0
- package/dist/harness-runtime/lib/dd-zcode.mjs +1175 -0
- package/dist/harness-runtime/lib/delegation-instructions.d.mts +14 -0
- package/dist/harness-runtime/lib/delegation-instructions.mjs +157 -0
- package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
- package/dist/harness-runtime/lib/driver-recovery.mjs +140 -0
- package/dist/harness-runtime/lib/droid-observation.mjs +66 -0
- package/dist/harness-runtime/lib/entity-references.d.mts +2 -0
- package/dist/harness-runtime/lib/entity-references.mjs +9 -0
- package/dist/harness-runtime/lib/lease-renewal.d.mts +8 -0
- package/dist/harness-runtime/lib/lease-renewal.mjs +37 -0
- package/dist/harness-runtime/lib/lifecycle-command.d.mts +20 -0
- package/dist/harness-runtime/lib/lifecycle-command.mjs +273 -0
- package/dist/harness-runtime/lib/lifecycle-contract.d.mts +10 -0
- package/dist/harness-runtime/lib/lifecycle-contract.mjs +19 -0
- package/dist/harness-runtime/lib/managed-daemon.d.mts +16 -0
- package/dist/harness-runtime/lib/managed-daemon.mjs +698 -0
- package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
- package/dist/harness-runtime/lib/model-observations.mjs +101 -0
- package/dist/harness-runtime/lib/native-children.d.mts +23 -0
- package/dist/harness-runtime/lib/native-children.mjs +219 -0
- package/dist/harness-runtime/lib/native-hook-command.d.mts +7 -0
- package/dist/harness-runtime/lib/native-hook-command.mjs +251 -0
- package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
- package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
- package/dist/harness-runtime/lib/native-streams.mjs +45 -0
- package/dist/harness-runtime/lib/observation-clock.d.mts +18 -0
- package/dist/harness-runtime/lib/observation-clock.mjs +95 -0
- package/dist/harness-runtime/lib/opencode-plugin.mjs +85 -0
- package/dist/harness-runtime/lib/operation-context.mjs +5 -0
- package/dist/harness-runtime/lib/operation-errors.d.mts +16 -0
- package/dist/harness-runtime/lib/operation-errors.mjs +127 -0
- package/dist/harness-runtime/lib/operation-progress.d.mts +7 -0
- package/dist/harness-runtime/lib/operation-progress.mjs +114 -0
- package/dist/harness-runtime/lib/process-json.d.mts +5 -0
- package/dist/harness-runtime/lib/process-json.mjs +201 -0
- package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
- package/dist/harness-runtime/lib/provider-overload-policy.d.mts +15 -0
- package/dist/harness-runtime/lib/provider-overload-policy.mjs +151 -0
- package/dist/harness-runtime/lib/runner-events.mjs +202 -0
- package/dist/harness-runtime/lib/runner-lock.mjs +42 -0
- package/dist/harness-runtime/lib/session-settlement.mjs +30 -0
- package/dist/harness-runtime/lib/setup-progress.d.mts +9 -0
- package/dist/harness-runtime/lib/setup-progress.mjs +53 -0
- package/dist/harness-runtime/lib/tool-observations.d.mts +21 -0
- package/dist/harness-runtime/lib/tool-observations.mjs +228 -0
- package/dist/harness-runtime/lib/zcode-usage.mjs +55 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-1y4a697q.js +81 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-2ny4vxct.js +92 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-6mptkzbc.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-7x67cf1q.js +52 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9rqn6x4v.js +16 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9vdz0zwn.js +1661 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ecs5ftka.js +1466 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-frbwqjmf.js +145 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gne7h7mq.js +50 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gx9wnkzr.js +105 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-m2eywc8w.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-nwcpakzx.js +12 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-q4g3afnw.js +623 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-qav6mfdz.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-sxt88q69.js +12 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-t1xa31vm.js +39 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ve4aws36.js +103 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vmytr4q8.js +4 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vt9jbch8.js +36 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vyas3vgt.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-wjyeq25y.js +30 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-xgnj2w4v.js +20 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-y2etg5bs.js +9 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ydhz1zrh.js +238 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-z6qdwcsf.js +62 -0
- package/dist/harness-runtime/vendor/opencode-client/contract.d.ts +1 -0
- package/dist/harness-runtime/vendor/opencode-client/contract.js +12 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/api/api.d.ts +2806 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/api/api.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/api.d.ts +4 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/api.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/client.d.ts +2530 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/client.js +15 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.d.ts +7 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.js +6 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.d.ts +2529 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.js +8 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.d.ts +2 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.js +12 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/index.d.ts +35 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/index.js +75 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/rpc.d.ts +20 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/rpc.js +11 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/service.d.ts +90 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/service.js +187 -0
- package/dist/harness-runtime/vendor/opencode-client/package.json +84 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/api.d.ts +21 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/api.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/client.d.ts +252 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/client.js +14 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.d.ts +8 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.js +6 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.d.ts +259 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.js +7 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.d.ts +3 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.js +79 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.d.ts +8932 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.js +70 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/index.d.ts +6 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/index.js +83 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/rpc.d.ts +32 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/rpc.js +7 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/service.d.ts +24 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/service.js +187 -0
- package/dist/harness-runtime/vendor/opencode-client/pty-handoff.d.ts +12 -0
- package/dist/harness-runtime/vendor/opencode-client/pty-handoff.js +14 -0
- package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.d.ts +20 -0
- package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.js +14 -0
- package/dist/harness-runtime/vendor/opencode-client/service-contender.d.ts +37 -0
- package/dist/harness-runtime/vendor/opencode-client/service-contender.js +10 -0
- package/dist/harness-runtime/vendor/opencode-client/service-probe.d.ts +70 -0
- package/dist/harness-runtime/vendor/opencode-client/service-probe.js +16 -0
- package/dist/harness-runtime/vendor/opencode-client/service-timing.d.ts +12 -0
- package/dist/harness-runtime/vendor/opencode-client/service-timing.js +10 -0
- package/dist/harness-runtime/vendor/opencode-client/service-version.d.ts +2 -0
- package/dist/harness-runtime/vendor/opencode-client/service-version.js +6 -0
- package/dist/harness-runtime/vendor/opencode-client/service.d.ts +52 -0
- package/dist/harness-runtime/vendor/opencode-client/service.js +1 -0
- package/dist/harness-runtime/vendor/opencode-client/shared-events.d.ts +11 -0
- package/dist/harness-runtime/vendor/opencode-client/shared-events.js +8 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/connection.d.ts +37 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/connection.js +10 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/data.d.ts +211 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/data.js +18 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/index.d.ts +3 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/index.js +32 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/pty.d.ts +22 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/pty.js +8 -0
- package/dist/harness-runtime/vendor/opencode-plugin.mjs +3 -0
- package/dist/protocol/local-files.js +18 -9
- package/dist/runtime/context.js +8 -4
- package/dist/schemas/agent-profile.schema.json +1 -1
- package/dist/schemas/code-review-decision.schema.json +9 -0
- package/dist/schemas/code-review-result.schema.json +1 -1
- package/dist/schemas/code-verification.schema.json +7 -5
- package/dist/schemas/code-work-batch.schema.json +2 -2
- package/dist/schemas/diagnostic-stage-result.schema.json +354 -0
- package/dist/schemas/diagnostic-work-result.schema.json +296 -0
- package/dist/schemas/discovery-result.schema.json +184 -0
- package/dist/schemas/execution-bundle.schema.json +211 -0
- package/dist/schemas/execution-settings.schema.json +162 -0
- package/dist/schemas/flow-descriptor.schema.json +54 -0
- package/dist/schemas/flow-run.schema.json +29 -0
- package/dist/schemas/harness-catalog.schema.json +80 -0
- package/dist/schemas/mb-init-compose-result.schema.json +457 -0
- package/dist/schemas/mb-init-discover-result.schema.json +500 -0
- package/dist/schemas/mb-init-finish-result.schema.json +422 -0
- package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
- package/dist/schemas/mb-init-review-result.schema.json +396 -0
- package/dist/schemas/mb-init-verify-result.schema.json +391 -0
- package/dist/schemas/mb-upgrade-stage-result.schema.json +863 -0
- package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
- package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
- package/dist/schemas/memory-composition-work-result.schema.json +38 -0
- package/dist/schemas/memory-repair-work-result.schema.json +56 -0
- package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
- package/dist/schemas/memory-review-work-result.schema.json +43 -0
- package/dist/schemas/model-catalog.schema.json +153 -0
- package/dist/schemas/plan-review-decision.schema.json +12 -3
- package/dist/schemas/plan-review-result.schema.json +2 -2
- package/dist/schemas/profile-settings.schema.json +122 -0
- package/dist/schemas/project-flow-pack-manifest.schema.json +1 -1
- package/dist/schemas/release-impact.schema.json +3 -3
- package/dist/schemas/release-manifest.schema.json +291 -0
- package/dist/schemas/run-control-receipt.schema.json +118 -0
- package/dist/schemas/run-control-request.schema.json +36 -0
- package/dist/schemas/run-engine-binding.schema.json +1 -1
- package/dist/schemas/stage-start-response.schema.json +4 -0
- package/dist/schemas/vnext-protocol-plan.schema.json +2 -2
- package/dist/services/accepted-intent.js +139 -0
- package/dist/services/branch-context.js +3 -3
- package/dist/services/canon.js +54 -15
- package/dist/services/check-environment.js +21 -0
- package/dist/services/check-runner-evidence.js +562 -0
- package/dist/services/cleanup.js +133 -40
- package/dist/services/cli-operation-classifier.js +26 -63
- package/dist/services/cli-upgrade-allowlist.js +27 -0
- package/dist/services/code-checks.js +1398 -119
- package/dist/services/codex-hook-delivery.js +32 -0
- package/dist/services/command-context.js +80 -0
- package/dist/services/compatibility-preflight.js +16 -3
- package/dist/services/config.js +11 -8
- package/dist/services/continuation-outcome.js +20 -0
- package/dist/services/controller-child-capacity.js +13 -0
- package/dist/services/controller-child-observer.js +115 -0
- package/dist/services/controller-execution.js +94 -0
- package/dist/services/controller-fanout.js +226 -0
- package/dist/services/controller-memory-task.js +45 -0
- package/dist/services/controller-memory-worker.js +49 -0
- package/dist/services/dashboard.js +143 -58
- package/dist/services/descriptor-coordinator-session.js +35 -0
- package/dist/services/descriptor-root-work.js +53 -0
- package/dist/services/descriptor-run-settlement.js +107 -0
- package/dist/services/descriptor-run-start.js +475 -0
- package/dist/services/descriptor-stage-coordinator.js +250 -0
- package/dist/services/descriptor-stage-settlement.js +223 -0
- package/dist/services/descriptor-stage-start.js +175 -0
- package/dist/services/diagnostic-evidence.js +73 -0
- package/dist/services/diagnostic-report-publication.js +72 -0
- package/dist/services/diagnostic-report.js +67 -0
- package/dist/services/diagnostic-run-bundle.js +74 -0
- package/dist/services/diagnostic-snapshot.js +159 -0
- package/dist/services/diagnostic-stage-handlers.js +108 -0
- package/dist/services/diagnostic-stage-results.js +132 -0
- package/dist/services/diagnostic-start.js +84 -0
- package/dist/services/diagnostic-work-batch.js +34 -0
- package/dist/services/diagnostic-work-collection.js +97 -0
- package/dist/services/diagnostic-work-registration.js +101 -0
- package/dist/services/diagnostic-work-results.js +93 -0
- package/dist/services/discovery/agy-discovery.js +2 -0
- package/dist/services/discovery/codex-discovery.js +2 -0
- package/dist/services/discovery/droid-discovery.js +2 -0
- package/dist/services/discovery/grok-discovery.js +2 -0
- package/dist/services/discovery/opencode-discovery.js +2 -0
- package/dist/services/discovery/static.js +31 -0
- package/dist/services/discovery/zcode-discovery.js +2 -0
- package/dist/services/engines.js +354 -163
- package/dist/services/eval-snapshots.js +1316 -150
- package/dist/services/execution-bundles.js +275 -0
- package/dist/services/execution-policy.js +185 -0
- package/dist/services/executor-onboarding.js +56 -0
- package/dist/services/external-work-launch.js +310 -0
- package/dist/services/flow-catalog.js +30 -0
- package/dist/services/flow-descriptors.js +82 -0
- package/dist/services/frozen-engine.js +387 -0
- package/dist/services/generic-execution.js +164 -0
- package/dist/services/harness-adapter.js +355 -36
- package/dist/services/harness-config.js +2 -0
- package/dist/services/harness-discovery.js +29 -0
- package/dist/services/harness-doctor.js +75 -0
- package/dist/services/harness-probe-effects.js +51 -0
- package/dist/services/harness-version-probe.js +100 -0
- package/dist/services/hook-memory-routing.js +188 -0
- package/dist/services/hook-recovery-guard.js +14 -0
- package/dist/services/hook-session-observation.js +24 -0
- package/dist/services/hooks.js +791 -326
- package/dist/services/hybrid-contracts.js +474 -0
- package/dist/services/hybrid-digest.js +14 -0
- package/dist/services/ids.js +29 -1
- package/dist/services/installation-lock.js +95 -0
- package/dist/services/installed-flow-source.js +226 -0
- package/dist/services/lanes.js +78 -65
- package/dist/services/lifecycle-command.js +1 -288
- package/dist/services/lifecycle-contract.js +1 -0
- package/dist/services/lifecycle-invocations.js +2148 -0
- package/dist/services/managed-daemon-binding.js +38 -0
- package/dist/services/managed-lease-monitor.js +133 -0
- package/dist/services/managed-processes.js +449 -69
- package/dist/services/memory-accepted-composition.js +78 -0
- package/dist/services/memory-baseline-preservation.js +65 -0
- package/dist/services/memory-completed-correction-wave.js +328 -0
- package/dist/services/memory-compose-handler.js +400 -0
- package/dist/services/memory-composition-acceptance.js +375 -0
- package/dist/services/memory-composition-graph.js +165 -0
- package/dist/services/memory-composition-registration.js +161 -0
- package/dist/services/memory-composition-work-custody.js +156 -0
- package/dist/services/memory-composition-work-results.js +108 -0
- package/dist/services/memory-corrected-review-acceptance.js +129 -0
- package/dist/services/memory-corrected-review-batch.js +37 -0
- package/dist/services/memory-corrected-review-findings.js +108 -0
- package/dist/services/memory-corrected-review-inputs.js +215 -0
- package/dist/services/memory-corrected-review-projection.js +78 -0
- package/dist/services/memory-corrected-review-receipt.js +178 -0
- package/dist/services/memory-corrected-review-registration.js +192 -0
- package/dist/services/memory-correction-check-receipt.js +235 -0
- package/dist/services/memory-correction-input-owner.js +6 -0
- package/dist/services/memory-custody-snapshot.js +36 -0
- package/dist/services/memory-discover-handler.js +104 -0
- package/dist/services/memory-finish-evidence.js +457 -0
- package/dist/services/memory-finish-handler.js +229 -0
- package/dist/services/memory-finish-integration.js +450 -0
- package/dist/services/memory-finish-readiness.js +169 -0
- package/dist/services/memory-git-integration.js +220 -0
- package/dist/services/memory-historical-corrected-review.js +212 -0
- package/dist/services/memory-historical-original-review.js +143 -0
- package/dist/services/memory-historical-repair-registration.js +105 -0
- package/dist/services/memory-historical-second-review.js +147 -0
- package/dist/services/memory-init-bootstrap-readiness.js +210 -0
- package/dist/services/memory-init-contexts.js +131 -0
- package/dist/services/memory-init-controller-start.js +103 -0
- package/dist/services/memory-init-engine-release.js +223 -0
- package/dist/services/memory-init-git-policy.js +165 -0
- package/dist/services/memory-init-lint-capability.js +203 -0
- package/dist/services/memory-init-native-capacity.js +309 -0
- package/dist/services/memory-init-preflight.js +334 -0
- package/dist/services/memory-init-project-bootstrap.js +599 -0
- package/dist/services/memory-init-request-candidate.js +213 -0
- package/dist/services/memory-init-request-input.js +82 -0
- package/dist/services/memory-init-resource-storage.js +125 -0
- package/dist/services/memory-init-run-allocation.js +81 -0
- package/dist/services/memory-init-run-bundle.js +135 -0
- package/dist/services/memory-init-start.js +181 -0
- package/dist/services/memory-init-startup-custody.js +80 -0
- package/dist/services/memory-init-startup-input.js +240 -0
- package/dist/services/memory-init-storage.js +91 -0
- package/dist/services/memory-init-stores.js +359 -0
- package/dist/services/memory-init-worktrunk-capability.js +174 -0
- package/dist/services/memory-layer-publication.js +611 -0
- package/dist/services/memory-layer.js +221 -0
- package/dist/services/memory-lint-config.js +194 -0
- package/dist/services/memory-native-review-copy.js +103 -0
- package/dist/services/memory-normal-flow-entry.js +87 -0
- package/dist/services/memory-ordinary-defaults.js +129 -0
- package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
- package/dist/services/memory-preflight-handler.js +274 -0
- package/dist/services/memory-repair-current-view.js +299 -0
- package/dist/services/memory-repair-document-delta.js +488 -0
- package/dist/services/memory-repair-history.js +496 -0
- package/dist/services/memory-repair-physical-binding.js +194 -0
- package/dist/services/memory-repair-publication-files.js +152 -0
- package/dist/services/memory-repair-publication-intent.js +27 -0
- package/dist/services/memory-repair-publication-plan.js +162 -0
- package/dist/services/memory-repair-publication-source.js +225 -0
- package/dist/services/memory-repair-publication.js +795 -0
- package/dist/services/memory-repair-registration.js +240 -0
- package/dist/services/memory-repair-work-baseline.js +415 -0
- package/dist/services/memory-repair-work-completion.js +117 -0
- package/dist/services/memory-repair-work-custody.js +73 -0
- package/dist/services/memory-repair-work-results.js +108 -0
- package/dist/services/memory-repair-workspace.js +261 -0
- package/dist/services/memory-repair-writer-copy.js +736 -0
- package/dist/services/memory-result-binding.js +239 -0
- package/dist/services/memory-retained-review-authority.js +138 -0
- package/dist/services/memory-retained-review-results.js +70 -0
- package/dist/services/memory-retained-second-baseline.js +102 -0
- package/dist/services/memory-retained-second-repairs.js +162 -0
- package/dist/services/memory-review-acceptance.js +214 -0
- package/dist/services/memory-review-correction-plan.js +206 -0
- package/dist/services/memory-review-handler.js +585 -0
- package/dist/services/memory-review-inputs.js +246 -0
- package/dist/services/memory-review-limits.js +10 -0
- package/dist/services/memory-review-receipt.js +180 -0
- package/dist/services/memory-review-registration.js +117 -0
- package/dist/services/memory-review-work-custody.js +126 -0
- package/dist/services/memory-review-work-input.js +91 -0
- package/dist/services/memory-review-work-results.js +95 -0
- package/dist/services/memory-second-corrected-review-inputs.js +167 -0
- package/dist/services/memory-second-correction-plan.js +77 -0
- package/dist/services/memory-second-repair-baseline.js +91 -0
- package/dist/services/memory-second-repair-launch.js +614 -0
- package/dist/services/memory-second-repair-registration.js +88 -0
- package/dist/services/memory-second-repair-source.js +187 -0
- package/dist/services/memory-second-review-acceptance.js +115 -0
- package/dist/services/memory-source-observations.js +117 -0
- package/dist/services/memory-stage-dispatch.js +65 -0
- package/dist/services/memory-stage-results.js +290 -0
- package/dist/services/memory-tool-probe.js +25 -0
- package/dist/services/memory-upgrade-analysis-handler.js +243 -0
- package/dist/services/memory-upgrade-bootstrap-readiness.js +251 -0
- package/dist/services/memory-upgrade-evidence.js +100 -0
- package/dist/services/memory-upgrade-inventory.js +442 -0
- package/dist/services/memory-upgrade-publication-custody.js +73 -0
- package/dist/services/memory-upgrade-publication.js +413 -0
- package/dist/services/memory-upgrade-selection.js +430 -0
- package/dist/services/memory-upgrade-start.js +60 -0
- package/dist/services/memory-upgrade-storage-readiness.js +340 -0
- package/dist/services/memory-verification-acceptance.js +156 -0
- package/dist/services/memory-verification-checks.js +317 -0
- package/dist/services/memory-verification-receipt.js +160 -0
- package/dist/services/memory-verify-handler.js +137 -0
- package/dist/services/memory-work-result-json.js +12 -0
- package/dist/services/memory-work-result-preparation.js +64 -0
- package/dist/services/merge-queue.js +228 -149
- package/dist/services/merge-server.js +163 -35
- package/dist/services/migrations.js +164 -114
- package/dist/services/model-catalog.js +109 -0
- package/dist/services/model-discovery.js +46 -0
- package/dist/services/native-daemon-history.js +50 -0
- package/dist/services/native-session-control.js +39 -0
- package/dist/services/operator-profiles.js +236 -0
- package/dist/services/physical-startup.js +45 -0
- package/dist/services/plan-runtime.js +26 -11
- package/dist/services/plans.js +28 -25
- package/dist/services/project-registry.js +97 -0
- package/dist/services/project-summary.js +1 -1
- package/dist/services/projects.js +17 -87
- package/dist/services/prompt-delivery.js +71 -0
- package/dist/services/prompts.js +28 -17
- package/dist/services/protocols.js +163 -87
- package/dist/services/provider-capacity.js +455 -0
- package/dist/services/recovery-observation-budget.js +121 -0
- package/dist/services/recovery-snapshot-database.js +588 -0
- package/dist/services/release-archive-producer.js +52 -0
- package/dist/services/release-archive.js +143 -0
- package/dist/services/release-cache.js +150 -0
- package/dist/services/release-compatibility.js +18 -0
- package/dist/services/release-download.js +67 -0
- package/dist/services/release-envelope.js +104 -0
- package/dist/services/release-manifest.js +45 -0
- package/dist/services/release-payload.js +114 -0
- package/dist/services/release-producer.js +63 -0
- package/dist/services/release-provenance.js +160 -0
- package/dist/services/release-registry.js +66 -0
- package/dist/services/release-source.js +194 -0
- package/dist/services/repair-intents.js +31 -0
- package/dist/services/repair-receipt.js +13 -0
- package/dist/services/review-copy.js +165 -0
- package/dist/services/review-deferral.js +23 -0
- package/dist/services/run-control-receipt.js +56 -0
- package/dist/services/run-control-worker.js +428 -0
- package/dist/services/run-control.js +1092 -0
- package/dist/services/run-controller-adapter.js +400 -0
- package/dist/services/run-controller-capture.js +186 -0
- package/dist/services/run-controller-process.js +205 -0
- package/dist/services/run-controller-recovery.js +295 -0
- package/dist/services/run-controller-state.js +97 -0
- package/dist/services/run-controller.js +1326 -0
- package/dist/services/run-engine-bindings.js +1 -1
- package/dist/services/run-fork.js +147 -0
- package/dist/services/run-health.js +149 -0
- package/dist/services/run-observations.js +152 -0
- package/dist/services/run-projection.js +22 -64
- package/dist/services/run-recovery-guard.js +107 -0
- package/dist/services/run-recovery-runtime.js +112 -0
- package/dist/services/run-recovery.js +456 -0
- package/dist/services/run-start-custody.js +189 -0
- package/dist/services/runs.js +1023 -246
- package/dist/services/runtime-budget.js +446 -0
- package/dist/services/runtime-command.js +43 -0
- package/dist/services/runtime-scope-capture.js +52 -0
- package/dist/services/runtime-scope-control.js +468 -0
- package/dist/services/runtime-scope-resume.js +605 -0
- package/dist/services/runtime-scope-stop.js +211 -0
- package/dist/services/runtime-scope-worker.js +314 -0
- package/dist/services/runtime-service.js +19 -14
- package/dist/services/schema-validation.js +10 -8
- package/dist/services/scope-writer-cleanup.js +27 -0
- package/dist/services/sessions.js +36 -91
- package/dist/services/setup.js +427 -0
- package/dist/services/stage-blocker.js +17 -7
- package/dist/services/stage-context.js +193 -19
- package/dist/services/stage-handlers.js +89 -0
- package/dist/services/stage-lifecycle.js +152 -116
- package/dist/services/stage-pause.js +202 -91
- package/dist/services/stage-report-renderer.js +234 -6
- package/dist/services/stage-work-graph.js +52 -0
- package/dist/services/tooling.js +41 -30
- package/dist/services/usage.js +49 -101
- package/dist/services/verification-matrix.js +393 -0
- package/dist/services/version-status.js +1 -1
- package/dist/services/vnext-code-review.js +235 -88
- package/dist/services/vnext-code.js +327 -226
- package/dist/services/vnext-contracts.js +10 -1
- package/dist/services/vnext-execution-profile.js +80 -5
- package/dist/services/vnext-fanout.js +355 -21
- package/dist/services/vnext-merge.js +332 -111
- package/dist/services/vnext-plan-review.js +287 -132
- package/dist/services/vnext-plan.js +228 -104
- package/dist/services/vnext-protocolize.js +533 -95
- package/dist/services/vnext-specify.js +123 -81
- package/dist/services/vnext-workspace-policy.js +7 -2
- package/dist/services/work-registry.js +1706 -200
- package/dist/services/workspace-bootstrap.js +53 -15
- package/dist/services/workspace-files.js +85 -0
- package/dist/services/worktrees.js +105 -48
- package/dist/shared/entity-references.js +1 -0
- package/dist/shared/errors.js +27 -0
- package/dist/storage/agent-output.js +26 -0
- package/dist/storage/data-preservation.js +65 -0
- package/dist/storage/database.js +930 -40
- package/dist/storage/foreign-key-transaction.js +39 -0
- package/dist/storage/immutable-input.js +45 -0
- package/dist/storage/import-guard.js +159 -0
- package/dist/storage/memory-upgrade-schema-bootstrap.js +38 -0
- package/dist/storage/native-cleanup.js +52 -0
- package/dist/storage/paired-writer-migration.js +424 -0
- package/dist/storage/paths.js +17 -4
- package/dist/storage/projection-lock.js +73 -0
- package/dist/storage/work-references.js +23 -0
- package/dist/storage/writer-contract.js +96 -0
- package/dist/storage/writer-migration.js +346 -0
- package/dist/storage/writer-restore.js +217 -0
- package/package.json +50 -13
- package/tools/create-canon-release.mjs +33 -0
- package/tools/probe-codex-history.mjs +37 -0
- package/tools/produce-hybrid-release.mjs +41 -0
- package/tools/repair-paused-run-status.mjs +84 -0
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import { CAPACITY_POLICY, MAX_OVERLOAD_RETRIES, capacityBackoff, nativeItemsSettled, normalizeProviderFailure, overloadExhausted, parseCapacityOperation, refusalObservation, terminalProviderOverload, streamRequestKey } from "../harness-runtime/lib/provider-overload-policy.mjs";
|
|
4
|
+
import { AppError } from "../shared/errors.js";
|
|
5
|
+
import { isObservationLoss } from "../harness-runtime/lib/operation-errors.mjs";
|
|
6
|
+
import { parseLifecycleCommand, commandOption } from "./lifecycle-command.js";
|
|
7
|
+
import { nativeTreeReadiness } from "../harness-runtime/lib/native-children.mjs";
|
|
8
|
+
import { ObservationClock } from "../harness-runtime/lib/observation-clock.mjs";
|
|
9
|
+
/** Native output is evidence, not authority: match the committed current scope. */
|
|
10
|
+
export function ownedProviderBoundary(context, input, boundary) {
|
|
11
|
+
if (typeof boundary.native_hook_event_key !== "string" || typeof boundary.daemon_instance !== "string"
|
|
12
|
+
|| !context.db.get("SELECT 1 FROM hook_events WHERE project_id = ? AND event_key = ? AND daemon_id = ? AND provider_session_id = ? AND status = 'claimed'", [input.projectId, boundary.native_hook_event_key, boundary.daemon_instance, input.sessionId]))
|
|
13
|
+
return false;
|
|
14
|
+
const invocation = context.db.get("SELECT scope_json, outcome_json, command FROM lifecycle_invocations WHERE event_key = ? AND status = 'settled'", [boundary.native_hook_event_key]);
|
|
15
|
+
if (!invocation)
|
|
16
|
+
return false;
|
|
17
|
+
const scope = JSON.parse(invocation.scope_json);
|
|
18
|
+
const outcome = JSON.parse(invocation.outcome_json);
|
|
19
|
+
if (scope.runId !== input.runId || scope.daemonId !== boundary.daemon_instance || scope.rootSessionId !== input.sessionId || scope.generation !== input.generation
|
|
20
|
+
|| outcome.error || outcome.effect !== undefined && outcome.effect !== "committed" || outcome.result?.ok !== true
|
|
21
|
+
|| outcome.result.effect !== undefined && outcome.result.effect !== "committed")
|
|
22
|
+
return false;
|
|
23
|
+
const parsed = parseLifecycleCommand(invocation.command);
|
|
24
|
+
if (parsed.kind === "none" || parsed.kind === "compound" && !(parsed.supported === true && parsed.invocations?.length === 1) || !["stage_pause", "stage_finish", "work_finish"].includes(parsed.invocation.operation)
|
|
25
|
+
|| boundary.outcome === "completed" && parsed.invocation.operation === "stage_pause" || boundary.outcome === "paused" && parsed.invocation.operation !== "stage_pause"
|
|
26
|
+
|| boundary.lifecycle_operation !== undefined && boundary.lifecycle_operation !== parsed.invocation.operation
|
|
27
|
+
|| parsed.invocation.operation !== "work_finish" && commandOption(parsed.invocation, "stage") !== input.stage)
|
|
28
|
+
return false;
|
|
29
|
+
const result = outcome.result;
|
|
30
|
+
if (result.run_id !== undefined && result.run_id !== input.runId || result.stage !== undefined && result.stage !== input.stage
|
|
31
|
+
|| boundary.outcome === "paused" && (result.pause?.id !== boundary.pause?.id || result.outcome !== "paused")
|
|
32
|
+
|| boundary.work_id !== undefined && result.work_id !== undefined && boundary.work_id !== result.work_id)
|
|
33
|
+
return false;
|
|
34
|
+
if (boundary.run_id !== undefined && boundary.run_id !== input.runId || boundary.stage !== undefined && boundary.stage !== input.stage
|
|
35
|
+
|| boundary.work_id !== undefined && input.workId && boundary.work_id !== input.workId)
|
|
36
|
+
return false;
|
|
37
|
+
const run = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [input.projectId, input.runId]);
|
|
38
|
+
const index = JSON.parse(run?.index_json ?? "null");
|
|
39
|
+
const stage = index?.stage_runs?.find(item => item.stage === input.stage);
|
|
40
|
+
if (!stage?.attempt)
|
|
41
|
+
return false;
|
|
42
|
+
const workId = input.workId ?? (typeof boundary.work_id === "string" ? boundary.work_id : null);
|
|
43
|
+
const rows = context.db.all(`SELECT DISTINCT w.work_id, w.status FROM works w JOIN work_sessions ws ON ws.work_id = w.work_id JOIN sessions s ON s.project_id = w.project_id AND s.session_id = ws.session_id JOIN stage_work_memberships m ON m.project_id = w.project_id AND m.run_id = w.run_id AND m.work_id = w.work_id WHERE w.project_id = ? AND w.run_id = ? AND ws.status IN ('running', 'completed') AND s.provider_session_id = ? AND m.stage = ? AND m.attempt = ? AND (? IS NULL OR w.work_id = ?) ${!workId && input.scope === "stage" ? "AND w.parent_work_id IS NULL" : ""}`, [input.projectId, input.runId, input.sessionId, input.stage, stage.attempt, workId, workId]);
|
|
44
|
+
if (rows.length !== 1 || boundary.work_id !== undefined && boundary.work_id !== rows[0].work_id)
|
|
45
|
+
return false;
|
|
46
|
+
if (boundary.outcome === "paused")
|
|
47
|
+
return rows[0].status === "paused" && stage.pause?.work_id === rows[0].work_id && stage.pause.id === boundary.pause?.id;
|
|
48
|
+
return boundary.outcome === "completed" && (input.scope === "work" ? rows[0].status === "completed" : stage.status === "done");
|
|
49
|
+
}
|
|
50
|
+
export function providerChildFailure(child) {
|
|
51
|
+
return child.provider_failure ?? { code: child.native_source ? "provider_capacity_transient" : "turn_interrupted", details: { native_source: child.native_source, provider_session_id: child.session_id, turn_id: child.terminal_turn_id, native_turn_id: child.terminal_turn_id, terminal_status: child.status, observed_at: child.terminal_observed_at ?? null, provider_error: child.provider_error, native_turn_items: child.native_turn_items } };
|
|
52
|
+
}
|
|
53
|
+
export function eligibleProviderChildOverload(child, parentSessionId) {
|
|
54
|
+
return typeof child.session_id === "string" && child.session_id !== parentSessionId && child.parent_session_id === parentSessionId && child.provenance !== "parent_mismatch" && child.status === "failed" && typeof child.terminal_turn_id === "string" && nativeItemsSettled(child.native_turn_items)
|
|
55
|
+
&& terminalProviderOverload(providerChildFailure(child), child.session_id, child.terminal_turn_id);
|
|
56
|
+
}
|
|
57
|
+
/** A terminal root is not a settled tree. Only the daemon's exact owned tree
|
|
58
|
+
* with a settled root and positively live descendants permits waiting. */
|
|
59
|
+
export function capacityReadiness(seen, sessionId, operationId, turnId, items, allowDescendants = false, requestProof) {
|
|
60
|
+
const readiness = nativeTreeReadiness(seen, { sessionId, operationId, turnId, allowDescendants, requestProof });
|
|
61
|
+
return readiness === "inspection_pending" ? readiness : nativeItemsSettled(items) ? readiness : "unproven";
|
|
62
|
+
}
|
|
63
|
+
/** Permit acquisition must still belong to the original task, not merely an
|
|
64
|
+
* open RUN. Controls/inspection and ordinary successor prompts are unaffected. */
|
|
65
|
+
export function assertCapacityOwnerAdmission(context, record, operationId, binding) {
|
|
66
|
+
if (!operationId || !record.project_id || !record.run_id)
|
|
67
|
+
return;
|
|
68
|
+
const root = parseCapacityOperation(operationId).root;
|
|
69
|
+
const childOrdinal = /:child:[a-f0-9]+:followup:(\d+)$/.exec(root)?.[1];
|
|
70
|
+
if (childOrdinal && (!Number.isSafeInteger(Number(childOrdinal)) || Number(childOrdinal) < 1 || Number(childOrdinal) > MAX_OVERLOAD_RETRIES || String(Number(childOrdinal)) !== childOrdinal))
|
|
71
|
+
throw new AppError("capacity_continuation_conflict", "Invalid native child continuation ordinal", 1);
|
|
72
|
+
if (root === operationId && !childOrdinal)
|
|
73
|
+
return;
|
|
74
|
+
const reject = () => { throw new AppError("capacity_owner_boundary_changed", "Queued continuation no longer belongs to an unfinished task; reconcile its durable state", 1, { operation_id: operationId, work_id: record.work_id, run_id: record.run_id }); };
|
|
75
|
+
const metadata = JSON.parse(record.metadata_json);
|
|
76
|
+
const hasTable = (name) => Boolean(context.db.get("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?", [name]));
|
|
77
|
+
const parsed = parseCapacityOperation(operationId);
|
|
78
|
+
if (parsed.ordinal > 0 && !["judge", "probe"].includes(metadata.role ?? "")) {
|
|
79
|
+
if (!binding?.nativeSessionId || !binding.promptSha256)
|
|
80
|
+
reject();
|
|
81
|
+
let intent;
|
|
82
|
+
const predecessor = parsed.ordinal === 1 ? root : `${root}:capacity:${parsed.ordinal - 1}:session.prompt`;
|
|
83
|
+
if (hasTable("run_controller_operations")) {
|
|
84
|
+
const saved = context.db.get("SELECT receipt_json FROM run_controller_operations WHERE operation_id = ? AND controller_id = ? AND generation = ? AND status = 'failed'", [predecessor, record.owner_id, metadata.run_generation ?? 0]);
|
|
85
|
+
if (saved)
|
|
86
|
+
intent = JSON.parse(saved.receipt_json).capacity_intent;
|
|
87
|
+
}
|
|
88
|
+
if (!intent && record.work_id)
|
|
89
|
+
for (const table of ["work_launches", "merge_requests"]) {
|
|
90
|
+
if (!hasTable(table))
|
|
91
|
+
continue;
|
|
92
|
+
const rows = table === "work_launches"
|
|
93
|
+
? context.db.all("SELECT l.adapter_receipt_json FROM work_launches l JOIN works w ON w.work_id = l.work_id WHERE l.work_id = ? AND w.project_id = ? AND w.run_id = ?", [record.work_id, record.project_id, record.run_id])
|
|
94
|
+
: context.db.all("SELECT adapter_receipt_json FROM merge_requests WHERE executor_work_id = ? AND project_id = ? AND run_id = ?", [record.work_id, record.project_id, record.run_id]);
|
|
95
|
+
for (const saved of rows) {
|
|
96
|
+
const retained = JSON.parse(saved.adapter_receipt_json ?? "null");
|
|
97
|
+
intent = retained?.capacity_intents?.find((item) => item.operation_id === operationId);
|
|
98
|
+
if (intent)
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
if (intent)
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
if (intent?.policy && intent.policy !== CAPACITY_POLICY)
|
|
105
|
+
throw new AppError("capacity_policy_mismatch", "Continuation is pinned to another retry policy", 1);
|
|
106
|
+
if (!intent || parsed.ordinal > MAX_OVERLOAD_RETRIES || intent.policy !== CAPACITY_POLICY || intent.root_operation_id !== root || intent.ordinal !== parsed.ordinal
|
|
107
|
+
|| intent.predecessor !== predecessor || intent.operation_id !== operationId || intent.refusal?.turn_id !== intent.turn_id
|
|
108
|
+
|| intent.refusal?.ordinal !== parsed.ordinal - 1 || intent.refusal?.session_id !== intent.session_id
|
|
109
|
+
|| !Number.isFinite(Date.parse(intent.not_before)) || Date.parse(intent.not_before) > Date.parse(context.now())
|
|
110
|
+
|| intent.deadline !== null && (typeof intent.deadline !== "number" || intent.deadline <= Date.parse(context.now()))
|
|
111
|
+
|| binding?.nativeSessionId !== undefined && intent.session_id !== binding.nativeSessionId
|
|
112
|
+
|| binding?.promptSha256 !== undefined && intent.prompt_sha256 !== binding.promptSha256)
|
|
113
|
+
reject();
|
|
114
|
+
}
|
|
115
|
+
if (context.db.get("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'run_recovery_bindings'")) {
|
|
116
|
+
if (context.db.get("SELECT 1 FROM run_recovery_bindings b JOIN run_recovery_guards g ON g.recovery_id = b.recovery_id WHERE g.project_id = ? AND g.run_id = ? AND g.status = 'recovered' AND b.status = 'accepted' AND json_extract(b.runtime_dispatch_json, '$.operation_id') = ?", [record.project_id, record.run_id, root]))
|
|
117
|
+
reject();
|
|
118
|
+
}
|
|
119
|
+
if (record.work_id) {
|
|
120
|
+
const work = context.db.get("SELECT status FROM works WHERE work_id = ? AND project_id = ? AND run_id = ?", [record.work_id, record.project_id, record.run_id]);
|
|
121
|
+
const merge = context.db.get("SELECT status FROM merge_requests WHERE executor_work_id = ? AND project_id = ? AND run_id = ?", [record.work_id, record.project_id, record.run_id]);
|
|
122
|
+
if (merge && !["dispatching", "active"].includes(merge.status))
|
|
123
|
+
reject();
|
|
124
|
+
// MERGE owns the Stage/request boundary: finishing its Work does not
|
|
125
|
+
// necessarily commit stage finish yet. External workers own only Work.
|
|
126
|
+
const mergeOwner = metadata.role === "merge";
|
|
127
|
+
if (!work || !(merge && mergeOwner ? ["created", "running", "completed"] : ["created", "running"]).includes(work.status))
|
|
128
|
+
reject();
|
|
129
|
+
}
|
|
130
|
+
if (!context.db.get("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'run_controllers'"))
|
|
131
|
+
return;
|
|
132
|
+
const controller = context.db.get("SELECT state_json FROM run_controllers WHERE controller_id = ? AND project_id = ? AND run_id = ?", [record.owner_id, record.project_id, record.run_id]);
|
|
133
|
+
if (!controller)
|
|
134
|
+
return;
|
|
135
|
+
const state = JSON.parse(controller.state_json);
|
|
136
|
+
const run = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [record.project_id, record.run_id]);
|
|
137
|
+
const index = JSON.parse(run?.index_json ?? "{}");
|
|
138
|
+
if (state.stage && (index.current_stage && index.current_stage !== state.stage || index.stage_runs?.some(stage => stage.stage === state.stage && ["done", "skipped"].includes(stage.status))))
|
|
139
|
+
reject();
|
|
140
|
+
const child = Object.entries(state.child_capacity ?? {}).find(([, intent]) => intent.operation_id === root)?.[0];
|
|
141
|
+
if (childOrdinal && !child)
|
|
142
|
+
reject();
|
|
143
|
+
if (child && context.db.get("SELECT 1 FROM work_sessions ws JOIN works w ON w.work_id = ws.work_id JOIN sessions s ON s.session_id = ws.session_id WHERE w.project_id = ? AND w.run_id = ? AND s.provider_session_id = ? AND w.status <> 'running'", [record.project_id, record.run_id, child]))
|
|
144
|
+
reject();
|
|
145
|
+
}
|
|
146
|
+
export function capacityDelay(error, ordinal, now = Date.now()) {
|
|
147
|
+
return capacityBackoff(error, ordinal, now);
|
|
148
|
+
}
|
|
149
|
+
/** Continue a confirmed terminal Turn, never replay its completed effects. */
|
|
150
|
+
export async function continueProviderCapacity(input) {
|
|
151
|
+
let { error, operationId } = input;
|
|
152
|
+
const history = [...(input.retainedIntents?.() ?? [])];
|
|
153
|
+
if (history.some(intent => intent.policy !== CAPACITY_POLICY) || input.retainedFailures?.().some(refusal => refusal.policy !== CAPACITY_POLICY))
|
|
154
|
+
throw new AppError("capacity_policy_mismatch", "Retained continuation uses another retry policy", 1);
|
|
155
|
+
if (history.length > MAX_OVERLOAD_RETRIES)
|
|
156
|
+
throw new AppError("capacity_continuation_conflict", "Retained episode exceeds its retry budget", 1);
|
|
157
|
+
const parsed = parseCapacityOperation(input.operationId);
|
|
158
|
+
const rootId = parsed.root;
|
|
159
|
+
const text = input.continuationText ?? "Continue the same assigned task in this Session. Check current durable RUN, Work and Stage state first. Never repeat an observed lifecycle command, accepted HITL answer, check or merge apply; use only an exact issued successor. Stop at the assigned boundary.";
|
|
160
|
+
const promptSha = crypto.createHash("sha256").update(text).digest("hex");
|
|
161
|
+
let ordinal = parsed.ordinal + 1;
|
|
162
|
+
const conflict = (message) => { throw new AppError("capacity_continuation_conflict", message, 1, { operation_id: operationId, root_operation_id: rootId, session_id: input.sessionId }); };
|
|
163
|
+
const blocked = (message) => new AppError("capacity_continuation_blocked", message, 1, { capacity_uncertainty: true, operation_id: operationId, root_operation_id: rootId, provider_session_id: input.sessionId, primary_error: error });
|
|
164
|
+
const observe = async (action, observedOperationId = operationId) => {
|
|
165
|
+
try {
|
|
166
|
+
return await action();
|
|
167
|
+
}
|
|
168
|
+
catch (cause) {
|
|
169
|
+
let primary = cause;
|
|
170
|
+
for (let depth = 0; depth < 4 && primary?.code === "harness_adapter_failed"; depth++)
|
|
171
|
+
primary = (primary.cause ?? primary.details?.cause);
|
|
172
|
+
if (isObservationLoss(primary))
|
|
173
|
+
throw new AppError("operation_observation_lost", "Capacity native observation was lost; do not cancel or resend", 1, { capacity_uncertainty: true, root_operation_id: rootId, operation_id: observedOperationId, provider_session_id: input.sessionId, predecessor_error: error, cause });
|
|
174
|
+
throw cause;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
const refusals = [...(input.retainedFailures?.() ?? [])];
|
|
178
|
+
if (parsed.ordinal > history.length)
|
|
179
|
+
conflict("Continuation has no complete retained predecessor chain");
|
|
180
|
+
for (let index = 0; index < history.length; index++) {
|
|
181
|
+
const intent = history[index];
|
|
182
|
+
const expected = index + 1;
|
|
183
|
+
if (intent.ordinal !== expected || intent.operation_id !== `${rootId}:capacity:${expected}:session.prompt`
|
|
184
|
+
|| intent.predecessor !== (expected === 1 ? rootId : `${rootId}:capacity:${expected - 1}:session.prompt`)
|
|
185
|
+
|| intent.prompt_sha256 !== promptSha || intent.policy !== CAPACITY_POLICY || intent.root_operation_id !== rootId || intent.session_id !== input.sessionId
|
|
186
|
+
|| intent.deadline !== (input.deadline ?? null) || !intent.refusal || intent.refusal.ordinal !== expected - 1 || intent.refusal.turn_id !== intent.turn_id
|
|
187
|
+
|| !Number.isFinite(Date.parse(intent.not_before)))
|
|
188
|
+
conflict("Retained capacity chain is incomplete or belongs to another policy/task");
|
|
189
|
+
const previous = refusals.find(item => item.ordinal === intent.refusal.ordinal);
|
|
190
|
+
if (previous && JSON.stringify(previous) !== JSON.stringify(intent.refusal))
|
|
191
|
+
conflict("Retained failure observation changed");
|
|
192
|
+
if (!previous)
|
|
193
|
+
refusals.push(intent.refusal);
|
|
194
|
+
}
|
|
195
|
+
refusals.sort((a, b) => a.ordinal - b.ordinal);
|
|
196
|
+
for (let index = 0; index < refusals.length; index++) {
|
|
197
|
+
const refusal = refusals[index];
|
|
198
|
+
if (refusal.ordinal !== index || refusal.policy !== CAPACITY_POLICY || refusal.session_id !== input.sessionId || !refusal.turn_id
|
|
199
|
+
|| refusals.slice(0, index).some(item => item.turn_id === refusal.turn_id) || !Number.isFinite(Date.parse(refusal.first_observed_at)))
|
|
200
|
+
conflict("Retained refusal chain is invalid");
|
|
201
|
+
}
|
|
202
|
+
// Reconcile a retained dispatch before preparing another. Native absence is
|
|
203
|
+
// the only safe way to reuse a prepared intent; a lost reply is not absence.
|
|
204
|
+
for (const intent of history) {
|
|
205
|
+
if (intent.ordinal < ordinal)
|
|
206
|
+
continue;
|
|
207
|
+
if (intent.predecessor !== operationId || intent.ordinal !== ordinal || intent.operation_id !== `${rootId}:capacity:${ordinal}:session.prompt`)
|
|
208
|
+
conflict("Retained successor skips its predecessor");
|
|
209
|
+
if (intent.prompt_sha256 !== promptSha || !intent.turn_id || !Number.isFinite(Date.parse(intent.not_before)))
|
|
210
|
+
throw error;
|
|
211
|
+
let observed;
|
|
212
|
+
try {
|
|
213
|
+
observed = await observe(() => input.inspectOperation(intent.operation_id), intent.operation_id);
|
|
214
|
+
}
|
|
215
|
+
catch (cause) {
|
|
216
|
+
let code = cause;
|
|
217
|
+
for (let depth = 0; depth < 4 && code?.code === "harness_adapter_failed"; depth++)
|
|
218
|
+
code = code.details?.cause;
|
|
219
|
+
if (code?.code !== "operation_not_found")
|
|
220
|
+
throw cause;
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
if (observed.operation_id !== intent.operation_id || observed.session_id !== input.sessionId || observed.operation !== "session.prompt")
|
|
224
|
+
conflict("Retained native successor identity changed");
|
|
225
|
+
if (observed.primary_error)
|
|
226
|
+
throw observed.primary_error;
|
|
227
|
+
while (["prepared", "dispatching", "running", "awaiting_provider", "outcome_unknown"].includes(String(observed.state))) {
|
|
228
|
+
input.signal?.throwIfAborted();
|
|
229
|
+
input.assertCurrent();
|
|
230
|
+
const boundary = await observe(async () => await input.decision?.() ?? "continue", intent.operation_id);
|
|
231
|
+
if (boundary === "completed" || boundary === "paused")
|
|
232
|
+
return { provider_session_id: input.sessionId, capacity_decision: boundary };
|
|
233
|
+
if (boundary === "reconciliation_blocked")
|
|
234
|
+
throw new AppError("capacity_continuation_blocked", "Retained native successor has an unresolved owner boundary", 1, { operation_id: intent.operation_id, primary_error: error });
|
|
235
|
+
if (input.deadline !== undefined && Date.now() >= input.deadline)
|
|
236
|
+
throw new AppError("capacity_owner_deadline_exceeded", "Retained successor exhausted its original deadline", 1);
|
|
237
|
+
await delay(250, undefined, { signal: input.signal });
|
|
238
|
+
observed = await observe(() => input.inspectOperation(intent.operation_id), intent.operation_id);
|
|
239
|
+
input.signal?.throwIfAborted();
|
|
240
|
+
input.assertCurrent();
|
|
241
|
+
if (observed.operation_id !== intent.operation_id || observed.session_id !== input.sessionId || observed.operation !== "session.prompt")
|
|
242
|
+
conflict("Retained native successor identity changed");
|
|
243
|
+
if (observed.primary_error)
|
|
244
|
+
throw observed.primary_error;
|
|
245
|
+
}
|
|
246
|
+
if (observed.state === "completed" && observed.result && typeof observed.result === "object") {
|
|
247
|
+
input.signal?.throwIfAborted();
|
|
248
|
+
input.assertCurrent();
|
|
249
|
+
const boundary = await observe(async () => await input.decision?.() ?? "continue", intent.operation_id);
|
|
250
|
+
input.signal?.throwIfAborted();
|
|
251
|
+
input.assertCurrent();
|
|
252
|
+
if (boundary === "reconciliation_blocked")
|
|
253
|
+
throw new AppError("capacity_continuation_blocked", "Retained completion cannot be reconciled with its owner boundary", 1);
|
|
254
|
+
return boundary === "paused" || boundary === "completed" ? { provider_session_id: input.sessionId, capacity_decision: boundary } : observed.result;
|
|
255
|
+
}
|
|
256
|
+
if (observed.state === "failed" && observed.error && !terminalProviderOverload(observed.error, input.sessionId))
|
|
257
|
+
throw observed.error;
|
|
258
|
+
if (observed.state !== "failed" || !terminalProviderOverload(observed.error, input.sessionId))
|
|
259
|
+
throw new AppError("operation_observation_lost", "Retained successor outcome is not proven; do not resend", 1, { operation_id: intent.operation_id, primary_error: error, observed });
|
|
260
|
+
operationId = intent.operation_id;
|
|
261
|
+
error = observed.error;
|
|
262
|
+
ordinal += 1;
|
|
263
|
+
}
|
|
264
|
+
const decide = async (observedOperationId = operationId) => {
|
|
265
|
+
input.signal?.throwIfAborted();
|
|
266
|
+
input.assertCurrent();
|
|
267
|
+
const normalized = normalizeProviderFailure(error, input.sessionId);
|
|
268
|
+
const candidate = normalized?.request_proof.kind === "stream_request" ? normalized.primary_error.details?.recovered_error_boundary : undefined;
|
|
269
|
+
const decision = await observe(async () => await input.decision?.(candidate?.receipt) ?? "continue", observedOperationId);
|
|
270
|
+
input.signal?.throwIfAborted();
|
|
271
|
+
input.assertCurrent();
|
|
272
|
+
if (normalized?.request_proof.kind === "stream_request" && ["completed", "paused"].includes(decision) && !candidate?.receipt)
|
|
273
|
+
throw blocked("Stream refusal has no ordered evidence of recovery before the committed boundary");
|
|
274
|
+
if (decision === "reconciliation_blocked")
|
|
275
|
+
throw new AppError("capacity_continuation_blocked", "Native refusal cannot be reconciled with its durable owner boundary", 1, { primary_error: error, root_operation_id: rootId, provider_session_id: input.sessionId });
|
|
276
|
+
if (decision === "continue" && input.deadline !== undefined && Date.now() >= input.deadline)
|
|
277
|
+
throw new AppError("capacity_owner_deadline_exceeded", "Continuation exhausted its original owner deadline", 1, { primary_error: error, deadline: input.deadline, root_operation_id: rootId, provider_session_id: input.sessionId });
|
|
278
|
+
return decision === "continue" ? null : { provider_session_id: input.sessionId, capacity_decision: decision };
|
|
279
|
+
};
|
|
280
|
+
for (;; ordinal += 1) {
|
|
281
|
+
if (!Number.isSafeInteger(ordinal))
|
|
282
|
+
conflict("Continuation ordinal overflow");
|
|
283
|
+
if (!terminalProviderOverload(error, input.sessionId)) {
|
|
284
|
+
if (ordinal === 1)
|
|
285
|
+
return null;
|
|
286
|
+
throw error;
|
|
287
|
+
}
|
|
288
|
+
if (normalizeProviderFailure(error, input.sessionId)?.request_proof.kind !== "stream_request") {
|
|
289
|
+
const completed = await decide();
|
|
290
|
+
if (completed)
|
|
291
|
+
return completed;
|
|
292
|
+
}
|
|
293
|
+
const prior = await observe(() => input.inspectOperation(operationId));
|
|
294
|
+
const failure = prior.error;
|
|
295
|
+
const confirmed = normalizeProviderFailure(failure, input.sessionId);
|
|
296
|
+
const turnId = confirmed?.turn_id;
|
|
297
|
+
input.signal?.throwIfAborted();
|
|
298
|
+
input.assertCurrent();
|
|
299
|
+
if (prior.primary_error)
|
|
300
|
+
throw prior.primary_error;
|
|
301
|
+
if (prior.operation_id !== operationId || prior.operation !== "session.prompt" || prior.session_id !== input.sessionId
|
|
302
|
+
|| prior.state !== "failed" || prior.primary_error || !turnId || !terminalProviderOverload(failure, input.sessionId, turnId)
|
|
303
|
+
|| confirmed?.request_proof.kind === "stream_request" && confirmed.request_proof.operation_id !== operationId) {
|
|
304
|
+
throw blocked("Retained predecessor does not prove the exact terminal overloaded Turn");
|
|
305
|
+
}
|
|
306
|
+
let pendingClock;
|
|
307
|
+
const readiness = async () => {
|
|
308
|
+
input.signal?.throwIfAborted();
|
|
309
|
+
input.assertCurrent();
|
|
310
|
+
const seen = await observe(() => input.inspectSession(confirmed?.request_proof.kind === "stream_request" ? undefined : turnId));
|
|
311
|
+
input.signal?.throwIfAborted();
|
|
312
|
+
input.assertCurrent();
|
|
313
|
+
// An unloaded exact-Turn snapshot is not conflicting tool evidence.
|
|
314
|
+
// Preserve the bound failure receipt, but never hide a pending item.
|
|
315
|
+
const freshItems = seen.native_turn_items;
|
|
316
|
+
const stream = confirmed?.request_proof.kind === "stream_request";
|
|
317
|
+
const streamMetadata = seen.terminal_metadata;
|
|
318
|
+
const exactFresh = stream ? streamRequestKey(streamMetadata?.request_proof) === turnId : seen.terminal_turn_id === turnId && seen.terminal_status === "failed";
|
|
319
|
+
const items = (exactFresh
|
|
320
|
+
&& !(freshItems?.observed === false && freshItems.pending !== true) ? freshItems : confirmed?.native_turn_items);
|
|
321
|
+
if (confirmed?.request_proof.kind === "stream_request") {
|
|
322
|
+
const metadata = seen.terminal_metadata;
|
|
323
|
+
if (streamRequestKey(metadata?.request_proof) !== turnId)
|
|
324
|
+
return "unproven";
|
|
325
|
+
}
|
|
326
|
+
const current = capacityReadiness(seen, input.sessionId, operationId, turnId, items, input.allowSettledDescendants, confirmed?.request_proof);
|
|
327
|
+
if (current === "inspection_pending") {
|
|
328
|
+
const saved = seen.native_settlement.observation_clock;
|
|
329
|
+
pendingClock ??= new ObservationClock({ timeoutMs: saved.timeout_ms, saved, snapshotIsLive: true });
|
|
330
|
+
if (pendingClock.sample(saved.cursor, saved.observed_at ?? undefined))
|
|
331
|
+
return "unproven";
|
|
332
|
+
}
|
|
333
|
+
return current;
|
|
334
|
+
};
|
|
335
|
+
// Pending is a bound observer, not a refusal or an intent to write. Resolve
|
|
336
|
+
// it before retaining a productive retry. Its producer owns the old clock.
|
|
337
|
+
const waitForReadiness = async (initial) => {
|
|
338
|
+
let current = initial;
|
|
339
|
+
while (current === "owned_children_live" || current === "inspection_pending") {
|
|
340
|
+
await delay(250, undefined, { signal: input.signal });
|
|
341
|
+
const boundary = await decide();
|
|
342
|
+
if (boundary)
|
|
343
|
+
return boundary;
|
|
344
|
+
current = await readiness();
|
|
345
|
+
}
|
|
346
|
+
if (current !== "ready")
|
|
347
|
+
throw blocked("Native predecessor readiness became unproven");
|
|
348
|
+
return null;
|
|
349
|
+
};
|
|
350
|
+
let ready = await readiness();
|
|
351
|
+
while (ready === "inspection_pending") {
|
|
352
|
+
await delay(250, undefined, { signal: input.signal });
|
|
353
|
+
const boundary = await decide();
|
|
354
|
+
if (boundary)
|
|
355
|
+
return boundary;
|
|
356
|
+
ready = await readiness();
|
|
357
|
+
}
|
|
358
|
+
if (ready === "unproven")
|
|
359
|
+
throw blocked("Native predecessor readiness is unproven; do not cancel or replay to manufacture proof");
|
|
360
|
+
if (ready === "ready") {
|
|
361
|
+
const completed = await decide();
|
|
362
|
+
if (completed)
|
|
363
|
+
return completed;
|
|
364
|
+
if (confirmed?.request_proof.kind === "stream_request" && confirmed.primary_error.details?.recovered_error_boundary)
|
|
365
|
+
throw blocked("Recovered native error does not match its current durable owner boundary");
|
|
366
|
+
}
|
|
367
|
+
const native = normalizeProviderFailure(failure, input.sessionId, turnId);
|
|
368
|
+
let refusal = refusals.find(item => item.ordinal === ordinal - 1);
|
|
369
|
+
if (refusal && (refusal.turn_id !== turnId || refusal.session_id !== input.sessionId || refusal.policy !== CAPACITY_POLICY))
|
|
370
|
+
conflict("Failure ordinal identifies a different native Turn");
|
|
371
|
+
if (refusal) {
|
|
372
|
+
const expected = refusalObservation(failure, ordinal - 1, refusal.first_observed_at);
|
|
373
|
+
if (refusal.native_terminal_at !== expected.native_terminal_at || refusal.native_terminal_basis !== expected.native_terminal_basis)
|
|
374
|
+
conflict("Retained refusal time differs from its native receipt");
|
|
375
|
+
}
|
|
376
|
+
if (!refusal) {
|
|
377
|
+
if (refusals.some(item => item.turn_id === turnId))
|
|
378
|
+
conflict("A cached native Turn cannot be a second refusal");
|
|
379
|
+
// A cached legacy failure cannot be assigned a new time during reattach.
|
|
380
|
+
if (ordinal > 1 && parsed.ordinal > 0 && !native.observed_at)
|
|
381
|
+
conflict("Retained continuation has no original failure time");
|
|
382
|
+
const observedAt = typeof native.observed_at === "string" && Number.isFinite(Date.parse(native.observed_at)) ? native.observed_at : new Date().toISOString();
|
|
383
|
+
refusal = refusalObservation(failure, ordinal - 1, observedAt);
|
|
384
|
+
if (!input.atomicIntent)
|
|
385
|
+
input.retainFailure?.(operationId, refusal);
|
|
386
|
+
refusals.push(refusal);
|
|
387
|
+
}
|
|
388
|
+
const exhausted = overloadExhausted(refusals);
|
|
389
|
+
if (exhausted) {
|
|
390
|
+
if (input.atomicIntent)
|
|
391
|
+
input.retainFailure?.(operationId, refusal);
|
|
392
|
+
throw new AppError("provider_unavailable", "Provider overload retry episode exhausted", 1, { ...exhausted, root_operation_id: rootId, provider_session_id: input.sessionId, continuation_count: ordinal - 1, primary_error: refusals.length ? input.error : failure, last_error: failure });
|
|
393
|
+
}
|
|
394
|
+
const nextId = `${rootId}:capacity:${ordinal}:session.prompt`;
|
|
395
|
+
const existing = history.find(item => item.operation_id === nextId);
|
|
396
|
+
if (existing && (existing.predecessor !== operationId || existing.turn_id !== turnId || existing.prompt_sha256 !== promptSha || existing.ordinal !== ordinal))
|
|
397
|
+
throw error;
|
|
398
|
+
let wait;
|
|
399
|
+
try {
|
|
400
|
+
wait = existing ? Math.max(0, Date.parse(existing.not_before) - Date.now()) : capacityDelay(failure, ordinal);
|
|
401
|
+
}
|
|
402
|
+
catch (cause) {
|
|
403
|
+
if (input.atomicIntent)
|
|
404
|
+
input.retainFailure?.(operationId, refusal);
|
|
405
|
+
const metadata = cause;
|
|
406
|
+
throw new AppError(metadata.code ?? "capacity_retry_metadata_invalid", metadata.message ?? "Invalid provider retry metadata", 1, { ...metadata.details, policy: CAPACITY_POLICY, attempts: refusals.length, root_operation_id: rootId, primary_error: input.error, last_error: failure });
|
|
407
|
+
}
|
|
408
|
+
if (!Number.isFinite(wait) || Date.now() + wait > 8.64e15 || input.deadline !== undefined && Date.now() + wait >= input.deadline) {
|
|
409
|
+
if (input.atomicIntent)
|
|
410
|
+
input.retainFailure?.(operationId, refusal);
|
|
411
|
+
throw new AppError("capacity_owner_deadline_exceeded", "Continuation wait exceeds its original owner deadline", 1, { primary_error: failure, deadline: input.deadline ?? null });
|
|
412
|
+
}
|
|
413
|
+
if (!existing) {
|
|
414
|
+
const intent = { predecessor: operationId, operation_id: nextId, turn_id: turnId, request_key: native.request_key, request_proof: native.request_proof, ordinal, prompt_sha256: promptSha, not_before: new Date(Date.now() + wait).toISOString(), policy: CAPACITY_POLICY, root_operation_id: rootId, session_id: input.sessionId, deadline: input.deadline ?? null, refusal };
|
|
415
|
+
input.retainIntent(intent);
|
|
416
|
+
history.push(intent);
|
|
417
|
+
}
|
|
418
|
+
// Intent/refusal are durable before the first wait; no permit or writer is
|
|
419
|
+
// held here, and live siblings are never cancelled as a settlement proof.
|
|
420
|
+
const childBoundary = await waitForReadiness(ready);
|
|
421
|
+
if (childBoundary)
|
|
422
|
+
return childBoundary;
|
|
423
|
+
// Node timers truncate large delays. Bounded slices preserve cancellation
|
|
424
|
+
// and owner checks; monotonic elapsed time does not renew a Retry-After.
|
|
425
|
+
const until = performance.now() + Math.max(0, Date.parse(history.find(item => item.operation_id === nextId).not_before) - Date.now());
|
|
426
|
+
while (performance.now() < until) {
|
|
427
|
+
await delay(Math.min(250, Math.max(0, until - performance.now())), undefined, { signal: input.signal });
|
|
428
|
+
const boundary = await decide();
|
|
429
|
+
if (boundary)
|
|
430
|
+
return boundary;
|
|
431
|
+
}
|
|
432
|
+
const afterWait = await decide();
|
|
433
|
+
if (afterWait)
|
|
434
|
+
return afterWait;
|
|
435
|
+
const refreshedBoundary = await waitForReadiness(await readiness());
|
|
436
|
+
if (refreshedBoundary)
|
|
437
|
+
return refreshedBoundary;
|
|
438
|
+
const beforeDispatch = await decide();
|
|
439
|
+
if (beforeDispatch)
|
|
440
|
+
return beforeDispatch;
|
|
441
|
+
try {
|
|
442
|
+
return await observe(() => input.prompt(nextId, text, ordinal), nextId);
|
|
443
|
+
}
|
|
444
|
+
catch (nextError) {
|
|
445
|
+
// A task can complete/pause while the daemon queues for its permit.
|
|
446
|
+
// Admission then refuses the stale prompt; accept that owner decision
|
|
447
|
+
// before treating the transport's rejection as another provider failure.
|
|
448
|
+
const finished = await decide(nextId);
|
|
449
|
+
if (finished)
|
|
450
|
+
return finished;
|
|
451
|
+
error = nextError;
|
|
452
|
+
operationId = nextId;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { AppError } from "../shared/errors.js";
|
|
3
|
+
import { validateObservationDuration } from "../harness-runtime/lib/observation-clock.mjs";
|
|
4
|
+
export const recoveryObservationBudgetMs = 120_000;
|
|
5
|
+
const activeObservation = new AsyncLocalStorage();
|
|
6
|
+
export const withRecoveryObservation = (budget, action, retainActive = false) => activeObservation.run(retainActive ? activeObservation.getStore() ?? budget : budget, action);
|
|
7
|
+
export const recoveryRpcTimeout = (maximum) => {
|
|
8
|
+
if (maximum != null)
|
|
9
|
+
validateObservationDuration(maximum);
|
|
10
|
+
const observation = activeObservation.getStore();
|
|
11
|
+
// An unbounded productive transport wait is still bounded while recovery is
|
|
12
|
+
// actively reconciling. Outside recovery, its owner policy decides when to
|
|
13
|
+
// stop rather than a hidden adapter timer.
|
|
14
|
+
if (maximum === null)
|
|
15
|
+
return observation ? observation.timeout() : null;
|
|
16
|
+
return observation?.timeout(maximum ?? 30_000) ?? maximum ?? 30_000;
|
|
17
|
+
};
|
|
18
|
+
/** Call only while holding the existing owner-claim transaction. A replay of
|
|
19
|
+
* an explicit request never replenishes time, even after another request. */
|
|
20
|
+
export function renewRecoveryObservation(snapshot, requestId) {
|
|
21
|
+
if (typeof requestId !== "string" || !requestId.trim() || requestId.length > 200)
|
|
22
|
+
throw new AppError("usage", "Reconciliation requires a nonempty request ID of at most 200 characters", 2);
|
|
23
|
+
const previous = snapshot.recovery_observation;
|
|
24
|
+
const ids = previous?.reconciliation_ids ?? [];
|
|
25
|
+
if (!Array.isArray(ids) || ids.some(id => typeof id !== "string"))
|
|
26
|
+
throw new AppError("recovery_observation_invalid", "Retained reconciliation identities are malformed", 1);
|
|
27
|
+
if (ids.includes(requestId))
|
|
28
|
+
return snapshot;
|
|
29
|
+
return { ...snapshot, recovery_observation: { policy_id: "settlement-inactivity@1", observer_started: false, budget_ms: recoveryObservationBudgetMs, remaining_ms: recoveryObservationBudgetMs, progress_markers: [], observation_gaps: 0, reconciliation_ids: [...ids, requestId], poll_index: 0 } };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* New episodes measure silence between confirmed retirement facts; legacy
|
|
33
|
+
* receipts keep cumulative active-observer accounting. A gap never proves
|
|
34
|
+
* native death, and repeated gaps exhaust observation rather than grant time.
|
|
35
|
+
* Remaining time and seen proofs survive owner replacement.
|
|
36
|
+
*/
|
|
37
|
+
export function recoveryObservationBudget(saved, monotonic = () => performance.now()) {
|
|
38
|
+
const prior = saved && typeof saved === "object" ? saved.recovery_observation : null;
|
|
39
|
+
if (prior?.policy_id !== undefined && prior.policy_id !== "settlement-inactivity@1")
|
|
40
|
+
throw new AppError("recovery_observation_invalid", "Unknown retained observation policy", 1);
|
|
41
|
+
const sliding = !prior || prior.policy_id === "settlement-inactivity@1";
|
|
42
|
+
if (prior?.progress_markers !== undefined && (!Array.isArray(prior.progress_markers) || prior.progress_markers.some(marker => typeof marker !== "string"))
|
|
43
|
+
|| prior?.observation_gaps !== undefined && (!Number.isSafeInteger(prior.observation_gaps) || prior.observation_gaps < 0)
|
|
44
|
+
|| prior?.observer_started !== undefined && typeof prior.observer_started !== "boolean")
|
|
45
|
+
throw new AppError("recovery_observation_invalid", "Retained observation progress is malformed", 1);
|
|
46
|
+
const markers = new Set(prior?.progress_markers ?? []);
|
|
47
|
+
let gaps = prior?.observation_gaps ?? 0;
|
|
48
|
+
let remaining = typeof prior?.remaining_ms === "number" && Number.isFinite(prior.remaining_ms)
|
|
49
|
+
? Math.max(0, Math.min(recoveryObservationBudgetMs, prior.remaining_ms))
|
|
50
|
+
: prior == null ? recoveryObservationBudgetMs : 0;
|
|
51
|
+
// A restored observer cannot know what happened while it was absent. Retain
|
|
52
|
+
// one bounded uncertainty episode; repeated reconstruction never grants time.
|
|
53
|
+
if (sliding && prior && prior.observer_started !== false && ++gaps > 1)
|
|
54
|
+
remaining = 0;
|
|
55
|
+
let last = monotonic();
|
|
56
|
+
let pollIndex = Number.isSafeInteger(prior?.poll_index) && prior.poll_index >= 0 ? prior.poll_index : 0;
|
|
57
|
+
const observation = {
|
|
58
|
+
exhausted: () => {
|
|
59
|
+
const current = monotonic();
|
|
60
|
+
const elapsed = current - last;
|
|
61
|
+
last = current;
|
|
62
|
+
// A gap means this process was not observing; it never proves progress
|
|
63
|
+
// or death and therefore does not consume the reconciliation budget.
|
|
64
|
+
if (elapsed >= 0 && elapsed <= 60_000)
|
|
65
|
+
remaining = Math.max(0, remaining - elapsed);
|
|
66
|
+
else if (sliding && ++gaps > 1)
|
|
67
|
+
remaining = 0;
|
|
68
|
+
return remaining === 0;
|
|
69
|
+
},
|
|
70
|
+
observe: snapshot => {
|
|
71
|
+
observation.exhausted();
|
|
72
|
+
if (!sliding || remaining === 0)
|
|
73
|
+
return;
|
|
74
|
+
const proof = settlementProgressMarkers(snapshot);
|
|
75
|
+
const advanced = proof.some(marker => !markers.has(marker));
|
|
76
|
+
proof.forEach(marker => markers.add(marker));
|
|
77
|
+
if (advanced) {
|
|
78
|
+
remaining = recoveryObservationBudgetMs;
|
|
79
|
+
gaps = 0;
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
state: () => ({ ...(sliding ? { policy_id: "settlement-inactivity@1", observer_started: true, progress_markers: [...markers].sort(), observation_gaps: gaps } : {}), budget_ms: recoveryObservationBudgetMs, remaining_ms: Math.ceil(remaining), reconciliation_ids: prior?.reconciliation_ids ?? [], poll_index: pollIndex }),
|
|
83
|
+
timeout: (maximum = 30_000) => {
|
|
84
|
+
validateObservationDuration(maximum);
|
|
85
|
+
if (observation.exhausted())
|
|
86
|
+
throw new AppError("recovery_observation_budget_exhausted", "Recovery observation budget exhausted; explicit reconciliation is required", 1);
|
|
87
|
+
return Math.max(1, Math.min(maximum, Math.ceil(remaining)));
|
|
88
|
+
},
|
|
89
|
+
nextDelay: () => Math.min([1000, 2000, 5000, 10000][Math.min(pollIndex++, 3)], Math.ceil(remaining)),
|
|
90
|
+
};
|
|
91
|
+
return observation;
|
|
92
|
+
}
|
|
93
|
+
/** Only confirmed settlement facts advance recovery. Polls, errors, timestamps,
|
|
94
|
+
* and native model activity cannot replenish physical retirement observation. */
|
|
95
|
+
export function settlementProgressMarkers(snapshot) {
|
|
96
|
+
const result = [];
|
|
97
|
+
const visit = (value, prefix, depth) => {
|
|
98
|
+
if (!value || typeof value !== "object" || depth > 12)
|
|
99
|
+
return;
|
|
100
|
+
if (Array.isArray(value)) {
|
|
101
|
+
for (const item of value)
|
|
102
|
+
visit(item, prefix, depth + 1);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const object = value;
|
|
106
|
+
const identity = ["operation_id", "process_id", "session_id", "run_id", "control_id", "scope_id", "id"].map(key => typeof object[key] === "string" ? `${key}:${object[key]}` : "").filter(Boolean).join("|");
|
|
107
|
+
const location = `${prefix}/${identity}`;
|
|
108
|
+
for (const key of ["physical_settled", "native_settled", "settled", "retired", "published", "committed"])
|
|
109
|
+
if (object[key] === true)
|
|
110
|
+
result.push(`${location}/${key}`);
|
|
111
|
+
if (["completed", "released", "sealed", "verified", "retired"].includes(String(object.status)))
|
|
112
|
+
result.push(`${location}/status:${String(object.status)}`);
|
|
113
|
+
if (object.state === "settled")
|
|
114
|
+
result.push(`${location}/state:settled`);
|
|
115
|
+
for (const [key, item] of Object.entries(object))
|
|
116
|
+
if (key !== "recovery_observation" && key !== "error" && key !== "metadata" && key !== "capture_error")
|
|
117
|
+
visit(item, `${location}/${key}`, depth + 1);
|
|
118
|
+
};
|
|
119
|
+
visit(snapshot, "", 0);
|
|
120
|
+
return [...new Set(result)].sort();
|
|
121
|
+
}
|