@deksden-com/dd-flow-cli 0.9.0-beta.14 → 0.9.0-beta.141
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 +740 -0
- package/README.md +143 -1
- package/dist/build-info.json +8 -8
- package/dist/cli/argument-values.js +38 -0
- package/dist/cli/command-inputs.js +376 -0
- package/dist/cli/command-metadata.js +197 -0
- package/dist/cli/command-option-descriptions.js +191 -0
- package/dist/cli/completion-cli.js +70 -0
- package/dist/cli/completion.js +57 -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 +328 -18
- package/dist/cli/hook-ingress.js +78 -0
- package/dist/cli/input-preparation.js +165 -0
- package/dist/cli/memory-flow-admission.js +44 -0
- package/dist/cli/memory-init-invocation.js +78 -0
- package/dist/cli/memory-init.js +240 -0
- package/dist/cli/memory-storage-admission.js +53 -0
- package/dist/cli/models.js +39 -0
- package/dist/cli/native-hook-ingress.js +80 -0
- package/dist/cli/operator-profiles.js +61 -0
- package/dist/cli/output-options.js +35 -0
- package/dist/cli/response-file.js +71 -0
- package/dist/cli/run-cli.js +1689 -545
- 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 +149 -0
- package/dist/cli.js +71 -2
- package/dist/domain/stage-catalog.js +1 -1
- package/dist/domain/stage-handler-identities.js +20 -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-hooks.d.mts +1 -0
- package/dist/harness-runtime/lib/agy-hooks.mjs +9 -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 +1 -0
- package/dist/harness-runtime/lib/daemon-operations.mjs +371 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +6 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.mjs +728 -0
- package/dist/harness-runtime/lib/dd-agy.mjs +70 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.mjs +196 -0
- package/dist/harness-runtime/lib/dd-codex.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-codex.mjs +817 -0
- package/dist/harness-runtime/lib/dd-droid-daemon.mjs +140 -0
- package/dist/harness-runtime/lib/dd-droid.mjs +584 -0
- package/dist/harness-runtime/lib/dd-grok-daemon.mjs +498 -0
- package/dist/harness-runtime/lib/dd-grok.mjs +177 -0
- package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +557 -0
- package/dist/harness-runtime/lib/dd-opencode.mjs +363 -0
- package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +751 -0
- package/dist/harness-runtime/lib/dd-zcode.mjs +1145 -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 +139 -0
- package/dist/harness-runtime/lib/droid-observation.mjs +66 -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 +683 -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 +16 -0
- package/dist/harness-runtime/lib/native-children.mjs +113 -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 +92 -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 +13 -0
- package/dist/harness-runtime/lib/provider-overload-policy.mjs +138 -0
- package/dist/harness-runtime/lib/runner-events.mjs +200 -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 +51 -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-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/discovery-result.schema.json +184 -0
- package/dist/schemas/execution-bundle.schema.json +205 -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 +28 -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/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 +49 -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 +3 -3
- package/dist/schemas/plan-review-result.schema.json +2 -2
- package/dist/schemas/profile-settings.schema.json +122 -0
- 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/vnext-protocol-plan.schema.json +2 -2
- package/dist/services/branch-context.js +3 -3
- package/dist/services/canon.js +11 -8
- package/dist/services/check-runner-evidence.js +250 -0
- package/dist/services/cleanup.js +133 -40
- package/dist/services/cli-operation-classifier.js +25 -62
- package/dist/services/cli-upgrade-allowlist.js +27 -0
- package/dist/services/code-checks.js +1168 -107
- package/dist/services/codex-hook-delivery.js +32 -0
- package/dist/services/command-context.js +80 -0
- package/dist/services/compatibility-preflight.js +13 -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 +88 -0
- package/dist/services/controller-fanout.js +202 -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 +105 -0
- package/dist/services/descriptor-run-start.js +449 -0
- package/dist/services/descriptor-stage-coordinator.js +197 -0
- package/dist/services/descriptor-stage-settlement.js +222 -0
- package/dist/services/descriptor-stage-start.js +139 -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 +294 -153
- package/dist/services/eval-snapshots.js +1215 -116
- package/dist/services/execution-bundles.js +263 -0
- package/dist/services/execution-policy.js +185 -0
- package/dist/services/executor-onboarding.js +56 -0
- package/dist/services/external-work-launch.js +308 -0
- package/dist/services/flow-catalog.js +21 -0
- package/dist/services/flow-descriptors.js +82 -0
- package/dist/services/frozen-engine.js +250 -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/hooks.js +771 -325
- package/dist/services/hybrid-contracts.js +483 -0
- package/dist/services/ids.js +29 -1
- package/dist/services/installation-lock.js +95 -0
- package/dist/services/installed-flow-source.js +183 -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 +2007 -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 +475 -55
- package/dist/services/memory-accepted-composition.js +77 -0
- package/dist/services/memory-baseline-preservation.js +65 -0
- package/dist/services/memory-completed-correction-wave.js +320 -0
- package/dist/services/memory-compose-handler.js +258 -0
- package/dist/services/memory-composition-acceptance.js +199 -0
- package/dist/services/memory-composition-graph.js +134 -0
- package/dist/services/memory-composition-registration.js +146 -0
- package/dist/services/memory-composition-work-custody.js +151 -0
- package/dist/services/memory-composition-work-results.js +96 -0
- package/dist/services/memory-corrected-review-acceptance.js +129 -0
- package/dist/services/memory-corrected-review-batch.js +30 -0
- package/dist/services/memory-corrected-review-findings.js +106 -0
- package/dist/services/memory-corrected-review-inputs.js +210 -0
- package/dist/services/memory-corrected-review-projection.js +78 -0
- package/dist/services/memory-corrected-review-receipt.js +170 -0
- package/dist/services/memory-corrected-review-registration.js +191 -0
- package/dist/services/memory-correction-check-receipt.js +219 -0
- package/dist/services/memory-correction-input-owner.js +6 -0
- package/dist/services/memory-discover-handler.js +104 -0
- package/dist/services/memory-finish-evidence.js +435 -0
- package/dist/services/memory-finish-handler.js +215 -0
- package/dist/services/memory-finish-integration.js +280 -0
- package/dist/services/memory-finish-readiness.js +122 -0
- package/dist/services/memory-git-integration.js +151 -0
- package/dist/services/memory-historical-corrected-review.js +206 -0
- package/dist/services/memory-historical-original-review.js +130 -0
- package/dist/services/memory-historical-repair-registration.js +99 -0
- package/dist/services/memory-historical-second-review.js +128 -0
- package/dist/services/memory-init-bootstrap-readiness.js +210 -0
- package/dist/services/memory-init-contexts.js +89 -0
- package/dist/services/memory-init-controller-start.js +84 -0
- package/dist/services/memory-init-engine-release.js +223 -0
- package/dist/services/memory-init-git-policy.js +136 -0
- package/dist/services/memory-init-lint-capability.js +185 -0
- package/dist/services/memory-init-native-capacity.js +296 -0
- package/dist/services/memory-init-preflight.js +330 -0
- package/dist/services/memory-init-project-bootstrap.js +599 -0
- package/dist/services/memory-init-request-candidate.js +157 -0
- package/dist/services/memory-init-request-input.js +66 -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 +98 -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 +81 -0
- package/dist/services/memory-init-stores.js +359 -0
- package/dist/services/memory-init-worktrunk-capability.js +178 -0
- package/dist/services/memory-layer-publication.js +611 -0
- package/dist/services/memory-layer.js +156 -0
- package/dist/services/memory-lint-config.js +85 -0
- package/dist/services/memory-native-review-copy.js +165 -0
- package/dist/services/memory-normal-flow-entry.js +75 -0
- package/dist/services/memory-ordinary-defaults.js +112 -0
- package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
- package/dist/services/memory-preflight-handler.js +259 -0
- package/dist/services/memory-repair-current-view.js +299 -0
- package/dist/services/memory-repair-document-delta.js +451 -0
- package/dist/services/memory-repair-history.js +491 -0
- package/dist/services/memory-repair-physical-binding.js +312 -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 +160 -0
- package/dist/services/memory-repair-publication-source.js +225 -0
- package/dist/services/memory-repair-publication.js +794 -0
- package/dist/services/memory-repair-registration.js +239 -0
- package/dist/services/memory-repair-work-baseline.js +413 -0
- package/dist/services/memory-repair-work-completion.js +97 -0
- package/dist/services/memory-repair-work-custody.js +73 -0
- package/dist/services/memory-repair-work-results.js +89 -0
- package/dist/services/memory-repair-workspace.js +252 -0
- package/dist/services/memory-repair-writer-copy.js +735 -0
- package/dist/services/memory-result-binding.js +173 -0
- package/dist/services/memory-retained-review-authority.js +129 -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 +156 -0
- package/dist/services/memory-review-acceptance.js +214 -0
- package/dist/services/memory-review-correction-plan.js +171 -0
- package/dist/services/memory-review-handler.js +585 -0
- package/dist/services/memory-review-inputs.js +200 -0
- package/dist/services/memory-review-receipt.js +180 -0
- package/dist/services/memory-review-registration.js +108 -0
- package/dist/services/memory-review-work-custody.js +124 -0
- package/dist/services/memory-review-work-input.js +72 -0
- package/dist/services/memory-review-work-results.js +73 -0
- package/dist/services/memory-second-corrected-review-inputs.js +165 -0
- package/dist/services/memory-second-correction-plan.js +76 -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 +28 -0
- package/dist/services/memory-stage-results.js +199 -0
- package/dist/services/memory-verification-acceptance.js +135 -0
- package/dist/services/memory-verification-checks.js +252 -0
- package/dist/services/memory-verification-receipt.js +159 -0
- package/dist/services/memory-verify-handler.js +135 -0
- package/dist/services/memory-work-result-preparation.js +63 -0
- package/dist/services/merge-queue.js +228 -149
- package/dist/services/merge-server.js +161 -35
- package/dist/services/migrations.js +37 -16
- package/dist/services/model-catalog.js +109 -0
- package/dist/services/model-discovery.js +46 -0
- package/dist/services/native-daemon-history.js +49 -0
- package/dist/services/native-session-control.js +39 -0
- package/dist/services/operator-profiles.js +236 -0
- package/dist/services/plan-runtime.js +26 -11
- package/dist/services/plans.js +28 -25
- package/dist/services/projects.js +37 -17
- package/dist/services/prompts.js +28 -17
- package/dist/services/protocols.js +163 -87
- package/dist/services/provider-capacity.js +385 -0
- package/dist/services/recovery-observation-budget.js +121 -0
- package/dist/services/recovery-snapshot-database.js +560 -0
- package/dist/services/release-archive-producer.js +52 -0
- package/dist/services/release-archive.js +143 -0
- package/dist/services/release-cache.js +142 -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 +42 -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 +411 -0
- package/dist/services/run-control.js +1056 -0
- package/dist/services/run-controller-adapter.js +399 -0
- package/dist/services/run-controller-capture.js +186 -0
- package/dist/services/run-controller-process.js +208 -0
- package/dist/services/run-controller-recovery.js +289 -0
- package/dist/services/run-controller-state.js +97 -0
- package/dist/services/run-controller.js +1205 -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 +77 -0
- package/dist/services/run-recovery-runtime.js +112 -0
- package/dist/services/run-recovery.js +489 -0
- package/dist/services/run-start-custody.js +177 -0
- package/dist/services/runs.js +1019 -247
- package/dist/services/runtime-budget.js +430 -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 +599 -0
- package/dist/services/runtime-scope-stop.js +210 -0
- package/dist/services/runtime-scope-worker.js +287 -0
- package/dist/services/runtime-service.js +96 -0
- package/dist/services/schema-validation.js +10 -8
- package/dist/services/scope-writer-cleanup.js +27 -0
- package/dist/services/sessions.js +35 -69
- package/dist/services/setup.js +377 -0
- package/dist/services/stage-blocker.js +17 -7
- package/dist/services/stage-context.js +193 -19
- package/dist/services/stage-handlers.js +74 -0
- package/dist/services/stage-lifecycle.js +152 -116
- package/dist/services/stage-pause.js +89 -75
- 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 +375 -0
- package/dist/services/vnext-code-review.js +223 -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 +311 -19
- package/dist/services/vnext-merge.js +332 -111
- package/dist/services/vnext-plan-review.js +279 -127
- package/dist/services/vnext-plan.js +228 -104
- package/dist/services/vnext-protocolize.js +531 -95
- package/dist/services/vnext-specify.js +119 -81
- package/dist/services/vnext-workspace-policy.js +7 -2
- package/dist/services/work-registry.js +1627 -199
- package/dist/services/workspace-bootstrap.js +52 -15
- package/dist/services/workspace-files.js +85 -0
- package/dist/services/worktrees.js +105 -48
- package/dist/shared/entity-references.js +8 -0
- package/dist/shared/errors.js +27 -0
- package/dist/storage/agent-output.js +26 -0
- package/dist/storage/database.js +891 -39
- package/dist/storage/foreign-key-transaction.js +39 -0
- package/dist/storage/immutable-input.js +45 -0
- package/dist/storage/import-guard.js +102 -0
- package/dist/storage/native-cleanup.js +52 -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 +89 -0
- package/dist/storage/writer-migration.js +85 -0
- package/package.json +43 -13
- package/tools/create-canon-release.mjs +33 -0
- package/tools/produce-hybrid-release.mjs +41 -0
- package/tools/repair-paused-run-status.mjs +84 -0
|
@@ -1 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { isControllerManagedInvocation, managedLifecycleCommand } from "./lifecycle-invocations.js";
|
|
2
|
+
/** Successor authority belongs to the controller, not the finishing Session.
|
|
3
|
+
* Manual flows still need an executable next step. Current-stage finish and
|
|
4
|
+
* paused/child Work commands do not pass through this boundary. */
|
|
5
|
+
export function stageSuccessor(context, input) {
|
|
6
|
+
const next = { ...input.metadata, kind: "start_stage", stage: input.stage };
|
|
7
|
+
return isControllerManagedInvocation(context, input.projectRoot, input.runId)
|
|
8
|
+
? { ...next, controller_owned: true, stop_turn: true, instruction: "This Stage is complete. End this Turn now and await the controller's next Stage assignment. Do not start the successor Stage or prepare its command." }
|
|
9
|
+
: { ...next, command: managedLifecycleCommand(context, input.command) };
|
|
10
|
+
}
|
|
@@ -1,19 +1,91 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
import { isDeepStrictEqual } from "node:util";
|
|
3
5
|
import { AppError } from "../shared/errors.js";
|
|
6
|
+
import { canonicalPath } from "../storage/paths.js";
|
|
7
|
+
import { isExecutionRouting } from "./execution-policy.js";
|
|
8
|
+
export const RUN_OPERATIONAL_DECISION_CONTRACT = "run-operational-decision@1";
|
|
9
|
+
const object = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
10
|
+
const text = (value) => typeof value === "string" && Boolean(value.trim());
|
|
11
|
+
const keys = (value, allowed) => object(value) && Object.keys(value).every(key => allowed.includes(key));
|
|
12
|
+
/** Structural validation only: acceptance is supplied by the caller, never inferred from settings. */
|
|
13
|
+
export function validateRunOperationalDecision(value, settings) {
|
|
14
|
+
if (!object(value) || value.schema_id !== RUN_OPERATIONAL_DECISION_CONTRACT || !text(value.id)
|
|
15
|
+
|| !object(value.scope) || !text(value.scope.project_root) || !path.isAbsolute(value.scope.project_root)
|
|
16
|
+
|| [value.scope.eval_id, value.scope.execution_id].some(item => item !== undefined && !text(item))
|
|
17
|
+
|| !object(value.settings) || !object(value.settings.merge_delivery) || value.settings.merge_delivery.strategy !== settings.merge_delivery.strategy
|
|
18
|
+
|| !object(value.settings.merge_cleanup) || value.settings.merge_cleanup.source !== settings.merge_cleanup.source
|
|
19
|
+
|| !object(value.policy) || !text(value.policy.path) || !text(value.policy.sha256) || !/^[a-f0-9]{64}$/.test(value.policy.sha256)
|
|
20
|
+
|| !Array.isArray(value.policy.clauses) || !value.policy.clauses.length || !value.policy.clauses.every(text)
|
|
21
|
+
|| !object(value.acceptance) || !text(value.acceptance.source) || !text(value.acceptance.reference)
|
|
22
|
+
|| value.exception !== undefined && (!object(value.exception) || !text(value.exception.reason) || !text(value.exception.owner)
|
|
23
|
+
|| !text(value.exception.review_at) || !Number.isFinite(Date.parse(value.exception.review_at))
|
|
24
|
+
|| value.exception.expires_at !== undefined && (!text(value.exception.expires_at) || !Number.isFinite(Date.parse(value.exception.expires_at))))) {
|
|
25
|
+
throw new AppError("operational_decision_invalid", "Operational decision requires explicit acceptance, scoped authority and matching settings", 2);
|
|
26
|
+
}
|
|
27
|
+
if (!keys(value, ["schema_id", "id", "scope", "settings", "policy", "acceptance", "exception", "declaration"])
|
|
28
|
+
|| !keys(value.scope, ["project_root", "eval_id", "execution_id"])
|
|
29
|
+
|| !keys(value.settings, ["merge_delivery", "merge_cleanup"])
|
|
30
|
+
|| !keys(value.settings.merge_delivery, ["strategy"]) || !keys(value.settings.merge_cleanup, ["source"])
|
|
31
|
+
|| !keys(value.policy, ["path", "sha256", "clauses"]) || !keys(value.acceptance, ["source", "reference"])
|
|
32
|
+
|| value.exception !== undefined && !keys(value.exception, ["reason", "owner", "review_at", "expires_at"])
|
|
33
|
+
|| value.declaration !== undefined && !keys(value.declaration, ["bytes", "sha256"]))
|
|
34
|
+
throw new AppError("operational_decision_invalid", "Operational decision contains unsupported authority fields", 2);
|
|
35
|
+
if (value.declaration !== undefined) {
|
|
36
|
+
if (!object(value.declaration) || !text(value.declaration.bytes) || !text(value.declaration.sha256)
|
|
37
|
+
|| crypto.createHash("sha256").update(value.declaration.bytes).digest("hex") !== value.declaration.sha256)
|
|
38
|
+
throw new AppError("operational_decision_invalid", "Original operational declaration checksum does not match", 2);
|
|
39
|
+
let declaration;
|
|
40
|
+
try {
|
|
41
|
+
declaration = JSON.parse(value.declaration.bytes);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
throw new AppError("operational_decision_invalid", "Original operational declaration must be JSON", 2);
|
|
45
|
+
}
|
|
46
|
+
if (!object(declaration) || !keys(declaration, ["schema_id", "id", "scope", "settings", "policy", "acceptance", "exception"])
|
|
47
|
+
|| declaration.scope !== undefined && !keys(declaration.scope, ["project_root", "eval_id", "execution_id"])
|
|
48
|
+
|| ["schema_id", "id", "settings", "policy", "acceptance", "exception"].some(key => !isDeepStrictEqual(declaration[key], value[key])))
|
|
49
|
+
throw new AppError("operational_decision_invalid", "Materialized decision changed the accepted declaration", 2);
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
/** Machine validation of declared policy bytes, not an NLP interpretation of Markdown. */
|
|
54
|
+
export function assertOperationalDecisionSource(decision, projectRoot, now) {
|
|
55
|
+
if (canonicalPath(decision.scope.project_root, false) !== canonicalPath(projectRoot, false))
|
|
56
|
+
throw new AppError("operational_decision_scope_mismatch", "Operational decision belongs to another project", 2);
|
|
57
|
+
const file = path.resolve(projectRoot, decision.policy.path);
|
|
58
|
+
const relative = path.relative(fs.realpathSync(projectRoot), fs.existsSync(file) ? fs.realpathSync(file) : file);
|
|
59
|
+
if (relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative) || relative === ".." || !fs.existsSync(file) || crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex") !== decision.policy.sha256)
|
|
60
|
+
throw new AppError("operational_decision_policy_changed", "Operational decision policy source checksum does not match an owned file", 2, { file });
|
|
61
|
+
if (decision.exception?.expires_at && Date.parse(decision.exception.expires_at) <= Date.parse(now))
|
|
62
|
+
throw new AppError("operational_decision_expired", "Explicit operational decision expiration has passed", 2);
|
|
63
|
+
}
|
|
4
64
|
const relativePath = path.join(".memory-bank", "dd-flow", "project-execution.json");
|
|
5
65
|
/** The project owns defaults; a RUN snapshots them once and never re-infers them. */
|
|
6
66
|
export function loadVnextExecutionProfile(projectRoot) {
|
|
67
|
+
return loadVnextExecutionProfileSnapshot(projectRoot).profile;
|
|
68
|
+
}
|
|
69
|
+
/** Parse and identify the same source bytes; a second read cannot bind another declaration. */
|
|
70
|
+
export function loadVnextExecutionProfileSnapshot(projectRoot) {
|
|
7
71
|
const file = path.join(projectRoot, relativePath);
|
|
72
|
+
let bytes;
|
|
8
73
|
let value;
|
|
9
74
|
try {
|
|
10
|
-
|
|
75
|
+
bytes = fs.readFileSync(file);
|
|
76
|
+
value = JSON.parse(bytes.toString("utf8"));
|
|
11
77
|
}
|
|
12
78
|
catch (error) {
|
|
13
79
|
throw new AppError("execution_profile_missing", "vNext flow requires .memory-bank/dd-flow/project-execution.json", 1, { file, cause: String(error) });
|
|
14
80
|
}
|
|
81
|
+
return { profile: validateVnextExecutionProfile(value), bytes };
|
|
82
|
+
}
|
|
83
|
+
/** Pure shared admission contract for project-execution@2 and @3. */
|
|
84
|
+
export function validateVnextExecutionProfile(value) {
|
|
85
|
+
if (!object(value))
|
|
86
|
+
throw new AppError("execution_profile_invalid", "Project execution profile must be an object", 1);
|
|
15
87
|
const profile = value;
|
|
16
|
-
if (profile.schema_id !== "dd-flow/project-execution@2"
|
|
88
|
+
if ((profile.schema_id !== "dd-flow/project-execution@2" && profile.schema_id !== "dd-flow/project-execution@3")
|
|
17
89
|
|| (profile.stage_session_mode !== undefined && profile.stage_session_mode !== "same_session" && profile.stage_session_mode !== "new_session")
|
|
18
90
|
|| !["auto", "off", "standard", "deep"].includes(String(profile.plan_review_mode))
|
|
19
91
|
|| (profile.code_review_mode !== undefined && !["auto", "off", "standard", "deep"].includes(String(profile.code_review_mode)))
|
|
@@ -21,10 +93,13 @@ export function loadVnextExecutionProfile(projectRoot) {
|
|
|
21
93
|
|| profile.merge_delivery?.strategy !== "local"
|
|
22
94
|
|| !["retain", "delete_after_success"].includes(String(profile.merge_cleanup?.source))
|
|
23
95
|
|| !["code_completed", "code_review_completed", "merge_completed"].includes(String(profile.stop_target))
|
|
24
|
-
|| !profile.code_bootstrap || typeof profile.code_bootstrap.command !== "string" || !profile.code_bootstrap.command.trim()
|
|
25
|
-
|
|
26
|
-
|
|
96
|
+
|| (profile.code_bootstrap !== undefined && (!profile.code_bootstrap || typeof profile.code_bootstrap.command !== "string" || !profile.code_bootstrap.command.trim()
|
|
97
|
+
|| typeof profile.code_bootstrap.policy_ref !== "string" || !profile.code_bootstrap.policy_ref.trim()))
|
|
98
|
+
|| (profile.execution === undefined ? profile.schema_id === "dd-flow/project-execution@3" : !isExecutionRouting(profile.execution))) {
|
|
99
|
+
throw new AppError("execution_profile_invalid", "Project execution profile does not match its supported dd-flow schema", 1);
|
|
27
100
|
}
|
|
101
|
+
if (profile.operational_decision !== undefined)
|
|
102
|
+
validateRunOperationalDecision(profile.operational_decision, profile);
|
|
28
103
|
return { ...profile, stage_session_mode: profile.stage_session_mode ?? "same_session", code_review_mode: profile.code_review_mode ?? "off" };
|
|
29
104
|
}
|
|
30
105
|
export function executionProfilePath(projectRoot) { return path.join(projectRoot, relativePath); }
|
|
@@ -3,10 +3,106 @@ import path from "node:path";
|
|
|
3
3
|
import { AppError } from "../shared/errors.js";
|
|
4
4
|
import { resolveProjectRoot } from "../storage/paths.js";
|
|
5
5
|
import { requireProjectByRoot } from "./projects.js";
|
|
6
|
-
import { getFlowRunVariables } from "./runs.js";
|
|
7
|
-
import {
|
|
6
|
+
import { getFlowRunVariables, appendFlowRunTimelineEvent, readFlowRunExecutionBundle } from "./runs.js";
|
|
7
|
+
import { resolveExecutionPolicy } from "./execution-policy.js";
|
|
8
|
+
import { listWorks, failWork, cancelWork, readWorkBatchCustody } from "./work-registry.js";
|
|
9
|
+
import { storageSessionId } from "./session-identity.js";
|
|
10
|
+
import { reconcileUnfinishedChecks } from "./code-checks.js";
|
|
8
11
|
import { vnextStageDirectory } from "../domain/stage-catalog.js";
|
|
12
|
+
import { stageWorkIds, stageGraphScope } from "./stage-work-graph.js";
|
|
13
|
+
import { eligibleProviderChildOverload } from "./provider-capacity.js";
|
|
14
|
+
import { renderNativeChildFollowupInstruction } from "../harness-runtime/lib/delegation-instructions.mjs";
|
|
15
|
+
import { readDescriptorRootWork } from "./descriptor-root-work.js";
|
|
16
|
+
import { selectMemoryCompositionRegistration } from "./memory-composition-registration.js";
|
|
17
|
+
import { safeNativeFailure } from "../harness-runtime/lib/native-children.mjs";
|
|
9
18
|
export const subagentCapacityKey = "runtime.subagent.available_slots";
|
|
19
|
+
/** External concurrency is policy, never evidence of native child qualification. */
|
|
20
|
+
export function getStageFanoutCapacity(context, input) {
|
|
21
|
+
const projectRoot = resolveProjectRoot(input.projectRoot);
|
|
22
|
+
const project = requireProjectByRoot(context, projectRoot);
|
|
23
|
+
const run = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [project.id, input.runId]);
|
|
24
|
+
if (!run)
|
|
25
|
+
throw new AppError("not_found", "RUN is unavailable", 1);
|
|
26
|
+
const index = JSON.parse(run.index_json);
|
|
27
|
+
const bundle = index.execution_bundle ? readFlowRunExecutionBundle(context, { projectRoot, runId: input.runId }) : null;
|
|
28
|
+
const generic = bundle?.execution.work(input.stage).delegation;
|
|
29
|
+
if (generic?.mode === "external")
|
|
30
|
+
return input.nativeOnly
|
|
31
|
+
? { run_key: null, available_slots: null, source: "harness_qualification" }
|
|
32
|
+
: { run_key: null, available_slots: generic.max_parallel, source: "external_policy" };
|
|
33
|
+
// Generic native admission already requires a scoped capacity receipt whose
|
|
34
|
+
// observed count covers this frozen limit. Mutable legacy variables cannot
|
|
35
|
+
// replace that receipt or silently prevent its productive dispatch.
|
|
36
|
+
if (generic?.mode === "native")
|
|
37
|
+
return { run_key: null, available_slots: generic.max_parallel, source: "harness_qualification" };
|
|
38
|
+
const frozen = index.execution_profile;
|
|
39
|
+
if (!bundle && frozen?.settings.execution) {
|
|
40
|
+
if (!frozen.agent_profiles)
|
|
41
|
+
throw new AppError("execution_profile_not_frozen", "Fan-out needs the RUN's frozen profiles", 1);
|
|
42
|
+
const resolved = resolveExecutionPolicy({ ddFlowHome: context.ddFlowHome, policy: frozen.settings.execution, profiles: frozen.agent_profiles, stage: input.stage });
|
|
43
|
+
if (resolved.delegation.mode === "external" && !input.nativeOnly)
|
|
44
|
+
return { run_key: null, available_slots: resolved.delegation.max_parallel, source: "external_policy" };
|
|
45
|
+
}
|
|
46
|
+
const variables = getFlowRunVariables(context, { projectRoot, runId: input.runId });
|
|
47
|
+
const available = variables.variables[subagentCapacityKey];
|
|
48
|
+
return { run_key: subagentCapacityKey, available_slots: typeof available === "number" && Number.isInteger(available) && available >= 0 ? Math.min(available, generic?.max_parallel ?? available) : null, source: "harness_qualification" };
|
|
49
|
+
}
|
|
50
|
+
function nativeFailureController(context, projectId, runId, stage, parent) {
|
|
51
|
+
if (!context.db.get("SELECT 1 FROM sqlite_master WHERE type='table' AND name='run_controllers'"))
|
|
52
|
+
return null;
|
|
53
|
+
const rows = context.db.all("SELECT controller_id,generation,state_json FROM run_controllers WHERE project_id=? AND run_id=? AND status NOT IN ('completed','cancelled','superseded')", [projectId, runId]);
|
|
54
|
+
const matching = rows.filter(row => {
|
|
55
|
+
try {
|
|
56
|
+
const state = JSON.parse(row.state_json);
|
|
57
|
+
return state.stage === stage && state.sessions?.[state.current_session]?.id === parent;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return matching.length === 1 ? matching[0] : null;
|
|
64
|
+
}
|
|
65
|
+
/** Failure metadata authored by a Work is not native evidence. Require the
|
|
66
|
+
* independently recorded reconciliation and its exact current registry links. */
|
|
67
|
+
export function verifiedNativeWorkFailure(context, input) {
|
|
68
|
+
const b = input.receipt.native_binding;
|
|
69
|
+
if (!b || b.schema_id !== "dd-flow/native-work-failure@1")
|
|
70
|
+
return;
|
|
71
|
+
const project = requireProjectByRoot(context, input.projectRoot);
|
|
72
|
+
const scope = stageGraphScope(context, project.id, input.runId, input.stage);
|
|
73
|
+
const controller = nativeFailureController(context, project.id, input.runId, input.stage, input.parentSessionId);
|
|
74
|
+
if (!controller || b.controller_id !== controller.controller_id || b.generation !== controller.generation
|
|
75
|
+
|| b.project_id !== project.id || b.run_id !== input.runId || b.stage !== input.stage
|
|
76
|
+
|| b.stage_attempt_id !== scope.attempt || b.stage_cycle !== scope.cycle
|
|
77
|
+
|| b.work_id !== input.workId || b.parent_work_id !== input.parentWorkId
|
|
78
|
+
|| b.parent_provider_session_id !== input.parentSessionId || b.terminal_turn_id !== input.receipt.terminal_turn_id
|
|
79
|
+
|| input.receipt.source !== "native_child_observation" || input.receipt.outcome !== "failed")
|
|
80
|
+
return;
|
|
81
|
+
const link = context.db.get(`SELECT ws.id FROM work_sessions ws JOIN works w ON w.work_id=ws.work_id JOIN sessions s ON s.project_id=w.project_id AND s.session_id=ws.session_id
|
|
82
|
+
WHERE ws.id=? AND w.project_id=? AND w.run_id=? AND w.work_id=? AND w.parent_work_id=? AND ws.status='failed' AND w.status='failed' AND s.parent_session_id=? AND s.provider_session_id=? AND s.harness=?`, [b.work_session_id, project.id, input.runId, input.workId, input.parentWorkId, storageSessionId({ harness_id: b.harness_id, session_id: input.parentSessionId }), b.provider_session_id, b.harness_id]);
|
|
83
|
+
if (!link)
|
|
84
|
+
return;
|
|
85
|
+
const run = context.db.get("SELECT run_root FROM runs WHERE project_id=? AND id=?", [project.id, input.runId]);
|
|
86
|
+
try {
|
|
87
|
+
const events = fs.readFileSync(path.join(run.run_root, "timeline.jsonl"), "utf8").trim().split("\n");
|
|
88
|
+
const proof = events.some(line => {
|
|
89
|
+
const event = JSON.parse(line);
|
|
90
|
+
if (event.type !== "native_child_reconciliation" || event.stage !== input.stage)
|
|
91
|
+
return false;
|
|
92
|
+
const terminal = event.observations?.children?.find((child) => child.session_id === b.provider_session_id && child.terminal_turn_id === b.terminal_turn_id);
|
|
93
|
+
if (event.observations?.parent_session_id !== b.parent_provider_session_id || event.observations?.harness_id !== b.harness_id
|
|
94
|
+
|| terminal?.status !== "failed" || terminal.terminal_observed_at !== input.receipt.terminal_observed_at
|
|
95
|
+
|| JSON.stringify(safeNativeFailure(terminal.provider_error)) !== JSON.stringify(safeNativeFailure(input.receipt.provider_error)))
|
|
96
|
+
return false;
|
|
97
|
+
return event.reconciled?.some((entry) => entry.outcome === "failed"
|
|
98
|
+
&& entry.native_binding && Object.keys(b).every(key => b[key] === entry.native_binding[key]));
|
|
99
|
+
});
|
|
100
|
+
return proof ? b : undefined;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
10
106
|
export function fanoutState(input) {
|
|
11
107
|
if (!input.hasWork)
|
|
12
108
|
return input.dispatch === "none" ? "coordinator_required" : "dispatch_required";
|
|
@@ -18,7 +114,7 @@ export function fanoutState(input) {
|
|
|
18
114
|
}
|
|
19
115
|
export function fanoutFile(stageRoot) { return path.join(stageRoot, "fanout.json"); }
|
|
20
116
|
export function writeFanoutDescriptor(stageRoot, descriptor) {
|
|
21
|
-
const value = { schema_id: "dd-flow/work-fanout@1", kind: "work_fanout", ...descriptor };
|
|
117
|
+
const value = { schema_id: descriptor.scope ? "dd-flow/work-fanout@2" : "dd-flow/work-fanout@1", kind: "work_fanout", ...descriptor };
|
|
22
118
|
fs.writeFileSync(fanoutFile(stageRoot), `${JSON.stringify(value, null, 2)}\n`);
|
|
23
119
|
return value;
|
|
24
120
|
}
|
|
@@ -27,31 +123,95 @@ export function readFanoutDescriptor(stageRoot) {
|
|
|
27
123
|
if (!fs.existsSync(file))
|
|
28
124
|
return null;
|
|
29
125
|
const value = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
30
|
-
if (
|
|
126
|
+
if (!["dd-flow/work-fanout@1", "dd-flow/work-fanout@2"].includes(String(value.schema_id)) || value.kind !== "work_fanout" || typeof value.stage !== "string" || typeof value.parent_work_id !== "string" || !["none", "plan-review"].includes(String(value.dispatch)) || typeof value.capacity_required !== "boolean" || value.schema_id === "dd-flow/work-fanout@2" && (!value.scope || [value.scope.project_id, value.scope.run_id, value.scope.attempt, value.scope.cycle].some(item => typeof item !== "string"))) {
|
|
31
127
|
throw new AppError("runtime_missing", "Stage fan-out descriptor is invalid", 1, { file });
|
|
32
128
|
}
|
|
33
129
|
return value;
|
|
34
130
|
}
|
|
131
|
+
/** Memory graphs are SQL-owned; a mutable/missing fanout.json is not their
|
|
132
|
+
* dispatch authority. Domain registrations and Work launch owners still fence
|
|
133
|
+
* productive assignments, including reviewer/correction waves.
|
|
134
|
+
*/
|
|
135
|
+
export function memoryStageFanoutDescriptor(context, input) {
|
|
136
|
+
if (!["compose", "review"].includes(input.stage))
|
|
137
|
+
return null;
|
|
138
|
+
const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot));
|
|
139
|
+
const run = context.db.get("SELECT flow_kind,index_json FROM runs WHERE project_id=? AND id=?", [project.id, input.runId]);
|
|
140
|
+
if (run?.flow_kind !== "mb-init")
|
|
141
|
+
return null;
|
|
142
|
+
const bundle = readFlowRunExecutionBundle(context, input);
|
|
143
|
+
if (!bundle || bundle.descriptor.descriptor.id !== "mb-init")
|
|
144
|
+
throw new AppError("stage_graph_compatibility_required", "Memory graph requires its admitted RUN bundle", 1);
|
|
145
|
+
const index = JSON.parse(run.index_json);
|
|
146
|
+
if (index.current_stage !== input.stage || !index.stage_runs.some(stage => stage.stage === input.stage && stage.status === "running"))
|
|
147
|
+
return null;
|
|
148
|
+
const root = readDescriptorRootWork(context, { projectId: project.id, runId: input.runId }, bundle);
|
|
149
|
+
const scope = stageGraphScope(context, project.id, input.runId, input.stage), members = stageWorkIds(context, project.id, input.runId, input.stage);
|
|
150
|
+
if (root.status !== "running" || !members.has(root.workId))
|
|
151
|
+
throw new AppError("stage_graph_conflict", "Memory graph lost its active coordinator", 1);
|
|
152
|
+
for (const id of members) {
|
|
153
|
+
if (id === root.workId)
|
|
154
|
+
continue;
|
|
155
|
+
const work = context.db.get("SELECT parent_work_id,result_schema FROM works WHERE project_id=? AND run_id=? AND work_id=?", [project.id, input.runId, id]);
|
|
156
|
+
const schemas = input.stage === "compose" ? ["dd-flow/memory-composition-work-result@1"] : ["dd-flow/memory-review-work-result@1", "dd-flow/memory-repair-work-result@1"];
|
|
157
|
+
if (!work || work.parent_work_id !== root.workId || !schemas.includes(work.result_schema ?? ""))
|
|
158
|
+
throw new AppError("stage_graph_conflict", "Memory graph contains an unassigned Work", 1);
|
|
159
|
+
const custody = readWorkBatchCustody(context, id);
|
|
160
|
+
if (custody.scope.project_id !== scope.project_id || custody.scope.run_id !== scope.run_id || custody.scope.attempt !== scope.attempt
|
|
161
|
+
|| custody.scope.cycle !== scope.cycle || custody.scope.stage !== input.stage || custody.scope.parent_work_id !== root.workId)
|
|
162
|
+
throw new AppError("stage_graph_conflict", "Memory graph contains foreign allocation custody", 1);
|
|
163
|
+
}
|
|
164
|
+
if (input.stage === "compose") {
|
|
165
|
+
const children = context.db.all("SELECT work_id FROM works WHERE project_id=? AND run_id=? AND parent_work_id=?", [project.id, input.runId, root.workId]).filter(work => members.has(work.work_id));
|
|
166
|
+
const registered = context.db.get("SELECT 1 FROM audit_events WHERE project_id=? AND event_type='memory.composition_registration' AND json_extract(payload_json,'$.run_id')=? AND json_extract(payload_json,'$.scope.attempt')=? AND json_extract(payload_json,'$.scope.cycle')=? LIMIT 1", [project.id, input.runId, scope.attempt, scope.cycle]);
|
|
167
|
+
if (children.length || registered) {
|
|
168
|
+
const registration = selectMemoryCompositionRegistration(context, { ...scope, stage: "compose", parent_work_id: root.workId });
|
|
169
|
+
const ids = new Set(Object.values(registration.work_ids));
|
|
170
|
+
if (ids.size !== children.length || children.some(work => !ids.has(work.work_id)))
|
|
171
|
+
throw new AppError("stage_graph_conflict", "Memory composition differs from its registered graph", 1);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return { schema_id: "dd-flow/work-fanout@2", kind: "work_fanout", scope, stage: input.stage, parent_work_id: root.workId, dispatch: "none", capacity_required: true };
|
|
175
|
+
}
|
|
35
176
|
/** Read-only projection for an external orchestrator. dd-flow keeps the graph authority. */
|
|
36
177
|
export function getVnextFanoutStatus(context, input) {
|
|
37
178
|
const projectRoot = resolveProjectRoot(input.projectRoot);
|
|
38
179
|
const project = requireProjectByRoot(context, projectRoot);
|
|
39
|
-
const run = context.db.get("SELECT run_root FROM runs WHERE project_id = ? AND id = ?", [project.id, input.runId]);
|
|
40
|
-
if (!run
|
|
41
|
-
throw new AppError("not_found", "RUN
|
|
42
|
-
|
|
43
|
-
|
|
180
|
+
const run = context.db.get("SELECT run_root, index_json FROM runs WHERE project_id = ? AND id = ?", [project.id, input.runId]);
|
|
181
|
+
if (!run)
|
|
182
|
+
throw new AppError("not_found", "RUN is not registered", 1, { run_id: input.runId });
|
|
183
|
+
if (!run.run_root)
|
|
184
|
+
throw new AppError("runtime_artifact_missing", "RUN artifact root is unavailable", 1, { run_id: input.runId });
|
|
185
|
+
const index = JSON.parse(run.index_json);
|
|
186
|
+
const bundle = index.execution_bundle ? readFlowRunExecutionBundle(context, { projectRoot, runId: input.runId }) : null;
|
|
187
|
+
const stageRoot = path.join(run.run_root, bundle ? bundle.descriptor.stage(input.stage).directory : vnextStageDirectory(input.stage));
|
|
188
|
+
let descriptor = memoryStageFanoutDescriptor(context, input) ?? readFanoutDescriptor(stageRoot);
|
|
189
|
+
// Registration is authoritative even if projection publication was interrupted,
|
|
190
|
+
// or an otherwise review-off stage acquired an aggregate repair graph.
|
|
191
|
+
if (!descriptor && context.db.get("SELECT 1 FROM sqlite_master WHERE name = 'repair_intents'")) {
|
|
192
|
+
const members = stageWorkIds(context, project.id, input.runId, input.stage);
|
|
193
|
+
const parents = context.db.all("SELECT w.work_id, w.parent_work_id FROM repair_intents i JOIN works w ON w.work_id = i.work_id WHERE i.project_id = ? AND i.run_id = ? AND i.stage = ?", [project.id, input.runId, input.stage]).filter(work => members.has(work.work_id));
|
|
194
|
+
const roots = [...new Set(parents.map(work => work.parent_work_id))];
|
|
195
|
+
if (roots.length > 1)
|
|
196
|
+
throw new AppError("stage_graph_conflict", "Registered repairs disagree on their stage coordinator", 1);
|
|
197
|
+
if (roots.length === 1)
|
|
198
|
+
descriptor = { schema_id: "dd-flow/work-fanout@2", scope: stageGraphScope(context, project.id, input.runId, input.stage), kind: "work_fanout", stage: input.stage, parent_work_id: roots[0], dispatch: "none", capacity_required: true };
|
|
199
|
+
}
|
|
44
200
|
if (!descriptor)
|
|
45
201
|
return { ok: true, run_id: input.runId, stage: input.stage, orchestration: null };
|
|
46
202
|
if (descriptor.stage !== input.stage)
|
|
47
203
|
throw new AppError("runtime_missing", "Stage fan-out descriptor belongs to another stage", 1, { requested_stage: input.stage, descriptor_stage: descriptor.stage });
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
const
|
|
204
|
+
const capacity = getStageFanoutCapacity(context, { projectRoot, runId: input.runId, stage: input.stage });
|
|
205
|
+
const members = stageWorkIds(context, project.id, input.runId, input.stage);
|
|
206
|
+
const currentScope = stageGraphScope(context, project.id, input.runId, input.stage);
|
|
207
|
+
const compatible = descriptor.scope ? Object.entries(currentScope).every(([key, value]) => descriptor.scope[key] === value) : members.size > 0;
|
|
208
|
+
if (!compatible)
|
|
209
|
+
return { ok: true, run_id: input.runId, stage: input.stage, orchestration: { ...descriptor, state: "compatibility_required", compatibility: { code: "stage_graph_compatibility_required", message: "Legacy or stale stage graph has no authoritative current membership; use the pinned engine", expected_scope: currentScope } } };
|
|
210
|
+
const all = listWorks(context, { parentWorkId: descriptor.parent_work_id, includeResults: false, workIds: members });
|
|
211
|
+
const ready = { works: all.works.filter(work => work.ready) };
|
|
52
212
|
const counts = Object.fromEntries(["created", "running", "completed", "failed", "cancelled"].map((status) => [status, all.works.filter((work) => work.status === status).length]));
|
|
53
213
|
const hasWork = all.works.length > 0;
|
|
54
|
-
const capacityKnown =
|
|
214
|
+
const capacityKnown = capacity.available_slots !== null;
|
|
55
215
|
return {
|
|
56
216
|
ok: true,
|
|
57
217
|
run_id: input.runId,
|
|
@@ -62,11 +222,143 @@ export function getVnextFanoutStatus(context, input) {
|
|
|
62
222
|
// not: their coordinator first materializes the Work graph from its
|
|
63
223
|
// authoritative prompt. An empty graph is therefore not a success.
|
|
64
224
|
state: fanoutState({ dispatch: descriptor.dispatch, hasWork, capacityRequired: descriptor.capacity_required, capacityKnown, created: counts.created ?? 0, running: counts.running ?? 0 }),
|
|
65
|
-
capacity
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
},
|
|
69
|
-
works: { ...counts, ready: ready.works.map((work) => ({ work_id: work.work_id, task: work.task, start_command: work.start_command })) }
|
|
225
|
+
capacity,
|
|
226
|
+
graph_revision: all.works.map(work => ({ work_id: work.work_id, status: work.status, depends_on: work.depends_on })),
|
|
227
|
+
works: { ...counts, ready: ready.works.map((work) => ({ work_id: work.work_id, task: work.task, launch_policy: work.launch_policy, start_command: work.start_command })) }
|
|
70
228
|
}
|
|
71
229
|
};
|
|
72
230
|
}
|
|
231
|
+
/** Explicit controller mutation, separate from read-only fanout status.
|
|
232
|
+
* A native child may be mapped only by its registered identity. Reused native
|
|
233
|
+
* Sessions need a provider execution identity: without one we report ambiguity
|
|
234
|
+
* instead of applying a late event to the newest Work attempt. */
|
|
235
|
+
export async function reconcileVnextFanout(context, input) {
|
|
236
|
+
const value = prepareNativeObservations(input.observations);
|
|
237
|
+
const status = getVnextFanoutStatus(context, input);
|
|
238
|
+
if (!status.orchestration)
|
|
239
|
+
return { ok: true, issues: [], reconciled: [] };
|
|
240
|
+
if (status.orchestration.state === "compatibility_required")
|
|
241
|
+
throw new AppError("stage_graph_compatibility_required", "Cannot reconcile a legacy or stale graph", 1);
|
|
242
|
+
const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot));
|
|
243
|
+
const members = stageWorkIds(context, project.id, input.runId, input.stage);
|
|
244
|
+
const parent = storageSessionId({ harness_id: value.harness_id, session_id: value.parent_session_id });
|
|
245
|
+
const issues = [], reconciled = [];
|
|
246
|
+
for (const child of value.children) {
|
|
247
|
+
if (child.provenance === "parent_mismatch" || child.parent_session_id !== undefined && child.parent_session_id !== value.parent_session_id) {
|
|
248
|
+
issues.push({ code: "native_child_parent_mismatch", session_id: child.session_id, observed_parent_session_id: child.parent_session_id ?? null, expected_parent_session_id: value.parent_session_id, outcome: child.status });
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (child.status === "running" || child.status === "unknown")
|
|
252
|
+
continue;
|
|
253
|
+
const sessionId = storageSessionId({ harness_id: value.harness_id, session_id: String(child.session_id) });
|
|
254
|
+
const links = context.db.all(`SELECT ws.id, ws.work_id, ws.status, w.status AS work_status, w.parent_work_id FROM work_sessions ws JOIN works w ON w.work_id = ws.work_id JOIN sessions s ON s.project_id = w.project_id AND s.session_id = ws.session_id WHERE w.project_id = ? AND w.run_id = ? AND ws.session_id = ? AND s.parent_session_id = ? ORDER BY ws.created_at`, [project.id, input.runId, sessionId, parent]);
|
|
255
|
+
const active = links.filter(link => link.status === "running" && link.work_status === "running" && link.parent_work_id === status.orchestration.parent_work_id && members.has(link.work_id));
|
|
256
|
+
if (!active.length) {
|
|
257
|
+
if (!links.length)
|
|
258
|
+
issues.push({ code: "child_launch_association_missing", session_id: child.session_id, outcome: child.status });
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
if (links.length !== 1 || active.length !== 1) {
|
|
262
|
+
issues.push({ code: "child_execution_ambiguous", session_id: child.session_id, work_ids: active.map(link => link.work_id) });
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
const link = active[0];
|
|
266
|
+
if (renderNativeChildFollowupInstruction(String(value.harness_id), String(child.session_id)) && eligibleProviderChildOverload(child, value.parent_session_id)) {
|
|
267
|
+
issues.push({ code: "child_capacity_pending", work_id: link.work_id, session_id: child.session_id });
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const pendingCheck = () => context.db.get("SELECT 1 FROM check_receipts WHERE project_id = ? AND run_id = ? AND work_id = ? AND status = 'running' LIMIT 1", [project.id, input.runId, link.work_id]);
|
|
271
|
+
if (pendingCheck()) {
|
|
272
|
+
const run = context.db.get("SELECT workspace_root, run_root FROM runs WHERE project_id = ? AND id = ?", [project.id, input.runId]);
|
|
273
|
+
try {
|
|
274
|
+
reconcileUnfinishedChecks(context, { projectId: project.id, runId: input.runId, workspaceRoot: run.workspace_root, runHome: run.run_root, workId: link.work_id });
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
if (!(error instanceof AppError) || error.code !== "check_in_progress")
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
if (pendingCheck()) {
|
|
281
|
+
issues.push({ code: "child_check_in_progress", work_id: link.work_id });
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (context.db.get("SELECT 1 FROM works WHERE parent_work_id = ? AND status IN ('created','running','paused') LIMIT 1", [link.work_id])) {
|
|
286
|
+
issues.push({ code: "child_descendants_unsettled", work_id: link.work_id });
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
if (child.status === "settled_by_root") {
|
|
290
|
+
issues.push({ code: "child_execution_outcome_unconfirmed", work_id: link.work_id, session_id: child.session_id });
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (child.status === "completed") {
|
|
294
|
+
issues.push({ code: "execution_ended_without_work_result", work_id: link.work_id, session_id: child.session_id });
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
const providerError = safeNativeFailure(child.provider_error);
|
|
298
|
+
const controller = nativeFailureController(context, project.id, input.runId, input.stage, value.parent_session_id);
|
|
299
|
+
const scope = stageGraphScope(context, project.id, input.runId, input.stage);
|
|
300
|
+
const terminalTime = typeof child.terminal_observed_at === "string" ? Date.parse(child.terminal_observed_at) : NaN;
|
|
301
|
+
const nativeBinding = child.status === "failed" && controller && typeof child.terminal_turn_id === "string" && child.terminal_turn_id.length > 0 && child.terminal_turn_id.length <= 256 && Number.isFinite(terminalTime)
|
|
302
|
+
? { schema_id: "dd-flow/native-work-failure@1", project_id: project.id, run_id: input.runId, stage: input.stage, stage_attempt_id: scope.attempt, stage_cycle: scope.cycle,
|
|
303
|
+
parent_work_id: status.orchestration.parent_work_id, work_id: link.work_id, work_session_id: link.id, harness_id: value.harness_id,
|
|
304
|
+
parent_provider_session_id: value.parent_session_id, provider_session_id: String(child.session_id), terminal_turn_id: child.terminal_turn_id,
|
|
305
|
+
controller_id: controller.controller_id, generation: controller.generation } : undefined;
|
|
306
|
+
const reason = JSON.stringify({ source: "native_child_observation", harness_id: value.harness_id, session_id: child.session_id, work_session_id: link.id, outcome: child.status,
|
|
307
|
+
...(nativeBinding ? { native_binding: nativeBinding } : {}),
|
|
308
|
+
...(typeof child.terminal_turn_id === "string" ? { terminal_turn_id: child.terminal_turn_id } : {}),
|
|
309
|
+
...(typeof child.terminal_observed_at === "string" ? { terminal_observed_at: child.terminal_observed_at } : {}),
|
|
310
|
+
...(providerError ? { provider_error: providerError } : {}) });
|
|
311
|
+
const result = await (child.status === "failed" ? failWork : cancelWork)(context, link.work_id, reason);
|
|
312
|
+
reconciled.push({ work_id: link.work_id, work_session_id: link.id, outcome: child.status, ...(nativeBinding ? { native_binding: nativeBinding } : {}), result });
|
|
313
|
+
}
|
|
314
|
+
appendFlowRunTimelineEvent(context, project.id, input.runId, { type: "native_child_reconciliation", stage: input.stage, observations: value, issues, reconciled });
|
|
315
|
+
return { ok: true, issues, reconciled };
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Records every terminal native child at the Stage where it is first observed.
|
|
319
|
+
* This is separate from fan-out settlement: a historical child can be valid
|
|
320
|
+
* evidence for an earlier Work, while an unbound terminal child is retained
|
|
321
|
+
* as an inconsistency instead of being rediscovered in a later review wave.
|
|
322
|
+
*/
|
|
323
|
+
export function prepareNativeObservations(observations) {
|
|
324
|
+
const value = observations;
|
|
325
|
+
if (!value || typeof value.harness_id !== "string" || !value.harness_id.trim() || typeof value.parent_session_id !== "string" || !value.parent_session_id.trim() || !Array.isArray(value.children)
|
|
326
|
+
|| value.children.some(child => !child || typeof child.session_id !== "string" || !child.session_id.trim() || typeof child.status !== "string" || !["running", "unknown", "completed", "failed", "cancelled", "settled_by_root"].includes(child.status) || child.parent_session_id !== undefined && typeof child.parent_session_id !== "string" || child.provenance !== undefined && !["root_child", "parent_mismatch"].includes(String(child.provenance))))
|
|
327
|
+
throw new AppError("usage", "Expected native observations: harness_id, parent_session_id and children[{session_id,status}]", 2);
|
|
328
|
+
if (new Set(value.children.map(child => child.session_id)).size !== value.children.length)
|
|
329
|
+
throw new AppError("usage", "Native observations must contain each child Session exactly once", 2);
|
|
330
|
+
return { harness_id: value.harness_id, parent_session_id: value.parent_session_id, children: value.children };
|
|
331
|
+
}
|
|
332
|
+
export function observeVnextNativeChildren(context, input) {
|
|
333
|
+
const value = prepareNativeObservations(input.observations);
|
|
334
|
+
const project = requireProjectByRoot(context, resolveProjectRoot(input.projectRoot));
|
|
335
|
+
const parent = storageSessionId({ harness_id: value.harness_id, session_id: value.parent_session_id });
|
|
336
|
+
const issues = [], history = [], pending = [];
|
|
337
|
+
for (const child of value.children) {
|
|
338
|
+
if (child.provenance === "parent_mismatch" || child.parent_session_id !== undefined && child.parent_session_id !== value.parent_session_id) {
|
|
339
|
+
issues.push({ code: "native_child_parent_mismatch", session_id: child.session_id, observed_parent_session_id: child.parent_session_id ?? null, expected_parent_session_id: value.parent_session_id, outcome: child.status, detected_at_stage: input.stage });
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
const sessionId = storageSessionId({ harness_id: value.harness_id, session_id: String(child.session_id) });
|
|
343
|
+
const links = context.db.all(`SELECT ws.id, ws.work_id, ws.status, w.status AS work_status, w.parent_work_id, s.current_stage
|
|
344
|
+
FROM work_sessions ws JOIN works w ON w.work_id = ws.work_id
|
|
345
|
+
JOIN sessions s ON s.project_id = w.project_id AND s.session_id = ws.session_id
|
|
346
|
+
WHERE w.project_id = ? AND w.run_id = ? AND ws.session_id = ? AND s.parent_session_id = ? ORDER BY ws.created_at`, [project.id, input.runId, sessionId, parent]);
|
|
347
|
+
if (child.status === "running" || child.status === "unknown") {
|
|
348
|
+
pending.push({ session_id: child.session_id, outcome: child.status, links: links.map(link => ({ work_id: link.work_id, work_session_id: link.id })) });
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if (!links.length) {
|
|
352
|
+
issues.push({ code: "unbound_native_delegation_detected", session_id: child.session_id, outcome: child.status, detected_at_stage: input.stage, origin_stage: "unknown" });
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (links.length !== 1) {
|
|
356
|
+
issues.push({ code: "child_execution_ambiguous", session_id: child.session_id, outcome: child.status, detected_at_stage: input.stage, work_ids: links.map(link => link.work_id) });
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
const link = links[0];
|
|
360
|
+
history.push({ session_id: child.session_id, outcome: child.status, work_id: link.work_id, work_session_id: link.id, work_status: link.work_status, origin_stage: link.current_stage ?? "unknown", detected_at_stage: input.stage });
|
|
361
|
+
}
|
|
362
|
+
appendFlowRunTimelineEvent(context, project.id, input.runId, { type: "native_child_observation", stage: input.stage, observations: value, issues, history, pending });
|
|
363
|
+
return { ok: true, issues, history, pending };
|
|
364
|
+
}
|