@ornexus/neocortex 4.60.73 → 4.60.75
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/dist/release-source.json +1 -1
- package/dist/sbom.cdx.json +1216 -1210
- package/install.ps1 +1 -1
- package/install.sh +1 -1
- package/package.json +2 -2
- package/packages/client/dist/adapters/adapter-registry.js +1 -108
- package/packages/client/dist/adapters/antigravity-adapter.js +2 -77
- package/packages/client/dist/adapters/claude-code-adapter.js +3 -79
- package/packages/client/dist/adapters/codex-adapter.js +2 -80
- package/packages/client/dist/adapters/cursor-adapter.js +4 -115
- package/packages/client/dist/adapters/gemini-adapter.js +2 -71
- package/packages/client/dist/adapters/grok-adapter.js +2 -42
- package/packages/client/dist/adapters/index.js +1 -22
- package/packages/client/dist/adapters/platform-detector.js +1 -212
- package/packages/client/dist/adapters/target-adapter.js +0 -12
- package/packages/client/dist/adapters/vscode-adapter.js +2 -72
- package/packages/client/dist/agent/refresh-stubs.js +2 -417
- package/packages/client/dist/agent/update-agent-yaml.js +1 -102
- package/packages/client/dist/agent/update-description.js +1 -251
- package/packages/client/dist/cache/crypto-utils.js +1 -78
- package/packages/client/dist/cache/encrypted-cache.d.ts +27 -0
- package/packages/client/dist/cache/encrypted-cache.js +1 -108
- package/packages/client/dist/cache/in-memory-asset-cache.js +1 -73
- package/packages/client/dist/cache/index.js +1 -13
- package/packages/client/dist/cache/protected-pi-boundary.js +1 -44
- package/packages/client/dist/checkpoint/checkpoint-client-reader.js +2 -127
- package/packages/client/dist/checkpoint/index.js +1 -11
- package/packages/client/dist/checkpoint/shared-checkpoint-types.js +1 -32
- package/packages/client/dist/cli.js +5 -358
- package/packages/client/dist/commands/activate.js +8 -394
- package/packages/client/dist/commands/architecture-answers.js +7 -274
- package/packages/client/dist/commands/architecture-memory-terminal.js +4 -253
- package/packages/client/dist/commands/architecture-non-ui-continuation.js +1 -100
- package/packages/client/dist/commands/architecture-root-binding.js +1 -51
- package/packages/client/dist/commands/cache-status.js +2 -112
- package/packages/client/dist/commands/config.js +1 -88
- package/packages/client/dist/commands/doctor.js +2 -635
- package/packages/client/dist/commands/invoke.d.ts +38 -1
- package/packages/client/dist/commands/invoke.js +143 -7200
- package/packages/client/dist/commands/legacy-epic-terminal.js +1 -71
- package/packages/client/dist/commands/legacy-story-branch.js +1 -96
- package/packages/client/dist/commands/legacy-story-pr.js +1 -276
- package/packages/client/dist/commands/mutation-qa-checkpoint.js +5 -285
- package/packages/client/dist/commands/mutation-qa-gate.js +1 -54
- package/packages/client/dist/commands/mutation-qa-git.js +1 -41
- package/packages/client/dist/commands/mutation-qa-policy.js +1 -102
- package/packages/client/dist/commands/mutation-qa-run.js +3 -219
- package/packages/client/dist/commands/mutation-qa-verdict.js +1 -149
- package/packages/client/dist/commands/mutation-qa.js +1 -220
- package/packages/client/dist/commands/native-agent.js +2 -136
- package/packages/client/dist/commands/planning-diagnosis.js +1 -43
- package/packages/client/dist/commands/planning-generation.js +1 -53
- package/packages/client/dist/commands/planning-memory.js +1 -40
- package/packages/client/dist/commands/planning-research.js +1 -42
- package/packages/client/dist/commands/private-session.js +1 -75
- package/packages/client/dist/commands/property-qa.js +1 -139
- package/packages/client/dist/commands/qa-control.js +1 -16
- package/packages/client/dist/commands/qa-scan-browser-launch.js +1 -55
- package/packages/client/dist/commands/qa-scan-browser-route.js +1 -28
- package/packages/client/dist/commands/qa-scan-capture.js +5 -663
- package/packages/client/dist/commands/qa-scan-discovery.js +3 -376
- package/packages/client/dist/commands/qa-scan-review.js +5 -826
- package/packages/client/dist/commands/qa-synthetic-backend-capture.js +1 -266
- package/packages/client/dist/commands/qa-synthetic-backend-review.js +1 -297
- package/packages/client/dist/commands/qa-synthetic-backend.js +2 -340
- package/packages/client/dist/commands/qa-synthetic-broker-port.js +1 -85
- package/packages/client/dist/commands/qa-synthetic-browser.js +1 -39
- package/packages/client/dist/commands/refactor-characterization.js +21 -671
- package/packages/client/dist/commands/refactor-commit.js +13 -399
- package/packages/client/dist/commands/refactor-control.js +3 -142
- package/packages/client/dist/commands/refactor-cpp-assertions.js +3 -93
- package/packages/client/dist/commands/refactor-review.js +5 -283
- package/packages/client/dist/commands/refactor-root.js +7 -588
- package/packages/client/dist/commands/refresh-memory.js +3 -156
- package/packages/client/dist/commands/shared-architecture-non-ui.js +1 -24
- package/packages/client/dist/commands/story-checkpoint.js +1 -171
- package/packages/client/dist/config/host-auth-broker.d.ts +31 -0
- package/packages/client/dist/config/host-auth-broker.js +1 -0
- package/packages/client/dist/config/host-auth-reference.d.ts +32 -0
- package/packages/client/dist/config/host-auth-reference.js +1 -0
- package/packages/client/dist/config/profile-directory.js +1 -13
- package/packages/client/dist/config/resolver-selection.js +1 -278
- package/packages/client/dist/config/secure-config.js +12 -281
- package/packages/client/dist/config.js +2 -223
- package/packages/client/dist/constants.js +1 -25
- package/packages/client/dist/context/context-collector.js +2 -222
- package/packages/client/dist/context/context-sanitizer.js +1 -145
- package/packages/client/dist/continuity/autonomous-governance.js +1 -285
- package/packages/client/dist/continuity/continuity-client-state-store.js +1 -1587
- package/packages/client/dist/continuity/invoke-hooks.js +1 -129
- package/packages/client/dist/continuity/migrations/001-initial-schema.js +2 -12
- package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.js +2 -12
- package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.js +2 -12
- package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.js +2 -12
- package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.js +2 -12
- package/packages/client/dist/continuity/migrations/006-native-agent-dispatches.js +2 -10
- package/packages/client/dist/continuity/native-agent-store.js +1 -69
- package/packages/client/dist/continuity/native-agent-types.d.ts +11 -0
- package/packages/client/dist/continuity/native-agent-types.js +1 -90
- package/packages/client/dist/continuity/outbox.js +1 -117
- package/packages/client/dist/continuity/runner-bootstrap-policy.js +1 -172
- package/packages/client/dist/continuity/sqlite-store.js +81 -2612
- package/packages/client/dist/effects/invoke-effect-gateways.js +1 -62
- package/packages/client/dist/errors/error-messages.d.ts +3 -0
- package/packages/client/dist/errors/error-messages.js +2 -228
- package/packages/client/dist/errors/frontmatter-diagnostics.js +1 -125
- package/packages/client/dist/evidence/collector.js +1 -347
- package/packages/client/dist/evidence/index.js +1 -1
- package/packages/client/dist/evidence/types.js +0 -2
- package/packages/client/dist/fs/atomic-state-replace.js +1 -152
- package/packages/client/dist/generated/command-registry.generated.js +1 -4076
- package/packages/client/dist/generated/public-projections.generated.js +1 -149
- package/packages/client/dist/git/direct-yolo-c01-retry.js +4 -138
- package/packages/client/dist/git/direct-yolo-checkpoint.d.ts +11 -1
- package/packages/client/dist/git/direct-yolo-checkpoint.js +4 -1234
- package/packages/client/dist/git/epic-operational-state.js +2 -672
- package/packages/client/dist/git/git-lifecycle-step-ids.js +1 -14
- package/packages/client/dist/git/git-lifecycle-store.d.ts +23 -0
- package/packages/client/dist/git/git-lifecycle-store.js +10 -1981
- package/packages/client/dist/git/legacy-story-branch-checkpoint.js +9 -259
- package/packages/client/dist/git/legacy-story-branch-setup.js +4 -348
- package/packages/client/dist/git/legacy-story-pr.js +70 -3538
- package/packages/client/dist/git/secure-filesystem-boundary.js +5 -182
- package/packages/client/dist/graph-retrieval/pre-command-hook.js +1 -284
- package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +1 -237
- package/packages/client/dist/i18n/first-run.js +2 -60
- package/packages/client/dist/index.d.ts +2 -0
- package/packages/client/dist/index.js +1 -47
- package/packages/client/dist/invocation/invoke-input.js +1 -24
- package/packages/client/dist/license/host-auth-recovery.d.ts +158 -0
- package/packages/client/dist/license/host-auth-recovery.js +1 -0
- package/packages/client/dist/license/index.js +1 -5
- package/packages/client/dist/license/license-client.d.ts +10 -1
- package/packages/client/dist/license/license-client.js +1 -304
- package/packages/client/dist/machine/fingerprint.js +2 -163
- package/packages/client/dist/machine/index.js +1 -5
- package/packages/client/dist/memory/project-memory-path-scope.js +1 -62
- package/packages/client/dist/memory/project-memory-writer.js +40 -1007
- package/packages/client/dist/memory/shared-project-memory-types.js +2 -253
- package/packages/client/dist/migrations/epic-lifecycle-backfill.js +3 -1060
- package/packages/client/dist/migrations/project-identity-capability.js +1 -50
- package/packages/client/dist/migrations/project-identity.js +7 -493
- package/packages/client/dist/migrations/state-json.js +4 -393
- package/packages/client/dist/policy/architecture-policy.js +2 -184
- package/packages/client/dist/policy/index.js +1 -7
- package/packages/client/dist/policy/shared-policy-types.js +0 -38
- package/packages/client/dist/policy/subagent-approval-policy.js +1 -55
- package/packages/client/dist/private-execution/clean-baseline.js +2 -279
- package/packages/client/dist/private-execution/codex-executor.js +4 -574
- package/packages/client/dist/private-execution/codex-host-runtime.js +1 -137
- package/packages/client/dist/private-execution/codex-lifecycle-guard.js +1 -97
- package/packages/client/dist/private-execution/codex-scoped-permissions.js +1 -128
- package/packages/client/dist/private-execution/delivery.js +13 -410
- package/packages/client/dist/private-execution/diagnosis-root-review.js +2 -294
- package/packages/client/dist/private-execution/frozen-handoff.js +6 -19
- package/packages/client/dist/private-execution/implementation-validation.js +2 -106
- package/packages/client/dist/private-execution/isolated-admission.js +23 -1432
- package/packages/client/dist/private-execution/isolated-session.js +5 -725
- package/packages/client/dist/private-execution/isolated-workspace.js +1 -122
- package/packages/client/dist/private-execution/pact-consumer-runtime.js +3 -409
- package/packages/client/dist/private-execution/pact-test-source.js +1 -258
- package/packages/client/dist/private-execution/pact-toolchain.js +3 -290
- package/packages/client/dist/private-execution/pact-write-set.js +1 -172
- package/packages/client/dist/private-execution/planning-diagnosis-checkpoint.js +5 -406
- package/packages/client/dist/private-execution/planning-generation-checkpoint.js +5 -462
- package/packages/client/dist/private-execution/planning-memory-checkpoint.js +3 -139
- package/packages/client/dist/private-execution/planning-research-checkpoint.js +4 -325
- package/packages/client/dist/private-execution/private-report-store.js +1 -42
- package/packages/client/dist/private-execution/property-test-candidate.js +1 -103
- package/packages/client/dist/private-execution/property-test-choices.js +3 -147
- package/packages/client/dist/private-execution/property-test-plan.js +7 -271
- package/packages/client/dist/private-execution/property-test-review.js +4 -258
- package/packages/client/dist/private-execution/property-test-runtime.js +9 -372
- package/packages/client/dist/private-execution/property-test-source.js +1 -139
- package/packages/client/dist/private-execution/root-checkpoint.js +1 -80
- package/packages/client/dist/private-execution/root-memory-git-evidence.js +3 -135
- package/packages/client/dist/private-execution/root-memory-recovery.js +1 -93
- package/packages/client/dist/private-execution/root-memory-request.js +1 -29
- package/packages/client/dist/private-execution/root-memory-scope.js +1 -178
- package/packages/client/dist/private-execution/root-memory-writer.js +1 -102
- package/packages/client/dist/private-execution/session-lease.js +1 -63
- package/packages/client/dist/private-execution/shared-private-admission-types.js +1 -50
- package/packages/client/dist/private-execution/shared-project-validation.js +1 -66
- package/packages/client/dist/private-execution/shared-root-memory-types.js +1 -61
- package/packages/client/dist/private-execution/ux-source-validation.js +1 -372
- package/packages/client/dist/private-execution/ux-write-set.js +2 -191
- package/packages/client/dist/registry/registry-reconciliation.js +1 -234
- package/packages/client/dist/resilience/circuit-breaker.js +1 -170
- package/packages/client/dist/resilience/degradation-manager.js +1 -164
- package/packages/client/dist/resilience/freshness-indicator.js +1 -100
- package/packages/client/dist/resilience/index.js +1 -8
- package/packages/client/dist/resilience/recovery-detector.js +1 -74
- package/packages/client/dist/resolvers/asset-resolver.js +0 -13
- package/packages/client/dist/resolvers/local-resolver.js +8 -255
- package/packages/client/dist/resolvers/remote-resolver.js +1 -233
- package/packages/client/dist/runner/binary.js +1 -404
- package/packages/client/dist/runner/cli.js +17 -1571
- package/packages/client/dist/runner/epic-background-dispatcher.d.ts +61 -0
- package/packages/client/dist/runner/epic-background-dispatcher.js +1 -0
- package/packages/client/dist/runner/headless/adapters.js +1 -49
- package/packages/client/dist/runner/headless/background-root.d.ts +65 -0
- package/packages/client/dist/runner/headless/background-root.js +1 -0
- package/packages/client/dist/runner/headless/claude-code-adapter.js +1 -79
- package/packages/client/dist/runner/headless/continuous-story-workspace.js +11 -1628
- package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +1 -69
- package/packages/client/dist/runner/headless/epic-merge-candidate-qa.d.ts +1 -1
- package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +2 -110
- package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.d.ts +2 -0
- package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +10 -1236
- package/packages/client/dist/runner/headless/epic-terminal-git-runner.d.ts +27 -2
- package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +2 -318
- package/packages/client/dist/runner/headless/fake-adapter.js +1 -62
- package/packages/client/dist/runner/headless/managed-environment-cleanup.d.ts +95 -0
- package/packages/client/dist/runner/headless/managed-environment-cleanup.js +1 -0
- package/packages/client/dist/runner/headless/managed-profile.js +1 -132
- package/packages/client/dist/runner/headless/opencode-adapter.js +2 -145
- package/packages/client/dist/runner/headless/prepared-story-bundle.js +1 -43
- package/packages/client/dist/runner/headless/resolver.js +1 -231
- package/packages/client/dist/runner/headless/run-yolo.js +1 -885
- package/packages/client/dist/runner/headless/run-yoloop.d.ts +1 -0
- package/packages/client/dist/runner/headless/run-yoloop.js +2 -2574
- package/packages/client/dist/runner/headless/types.js +2 -574
- package/packages/client/dist/runner/local-console.js +13 -396
- package/packages/client/dist/runner/portal-sync-worker.js +1 -1487
- package/packages/client/dist/runner/project-identity.js +1 -106
- package/packages/client/dist/runner/scheduler.js +7 -995
- package/packages/client/dist/runner-cli.js +2 -18
- package/packages/client/dist/state/invocation-shape.js +1 -13
- package/packages/client/dist/state/project-state-snapshot.d.ts +7 -0
- package/packages/client/dist/state/project-state-snapshot.js +1 -1731
- package/packages/client/dist/state/state-json-repair.js +3 -785
- package/packages/client/dist/state/structural-dag-projection.js +1 -118
- package/packages/client/dist/telemetry/index.js +1 -5
- package/packages/client/dist/telemetry/offline-queue.js +1 -131
- package/packages/client/dist/tier/index.js +1 -5
- package/packages/client/dist/tier/tier-aware-client.js +1 -405
- package/packages/client/dist/types/index.js +1 -38
- package/packages/client/dist/version.js +1 -27
- package/packages/client/dist/yolo/change-evidence-collector.d.ts +21 -1
- package/packages/client/dist/yolo/change-evidence-collector.js +1 -126
- package/packages/client/dist/yolo/invoke-envelope-capability.js +1 -62
- package/packages/client/dist/yolo/spec-envelope-collector.js +5 -184
- package/packages/client/dist/yoloop/discovery-hook.js +2 -300
- package/packages/client/dist/yoloop/index.js +1 -8
- package/packages/client/dist/yoloop/invoke-hooks.js +12 -669
- package/packages/client/dist/yoloop/shared-discover-epics.js +1 -1007
- package/packages/client/dist/yoloop/shared-yoloop-types.js +1 -33
- package/packages/client/dist/yoloop/target-normalization.js +1 -180
- package/packages/client/dist/yoloop/yoloop-client-state-store.js +1 -1920
- package/packages/shared/dist/invocation/explicit-intent-recovery.d.ts +83 -0
- package/packages/shared/dist/invocation/explicit-intent-recovery.js +187 -0
- package/packages/shared/dist/invocation/index.d.ts +7 -0
- package/packages/shared/dist/invocation/index.js +22 -0
- package/packages/shared/dist/yolo/change-evidence.js +1 -1
- package/packages/shared/dist/yoloop/epic-terminal-git.js +144 -2
- package/targets-stubs/antigravity/gemini.md +1 -1
- package/targets-stubs/antigravity/skill/SKILL.md +1 -1
- package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex-root.md +2 -2
- package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex.md +2 -2
- package/targets-stubs/codex/AGENTS.md +24 -21
- package/targets-stubs/codex/README.md +6 -1
- package/targets-stubs/codex/neocortex.toml +7 -2
- package/targets-stubs/cursor/agent.md +2 -2
- package/targets-stubs/gemini-cli/agent.md +2 -2
- package/targets-stubs/opencode/neocortex-root.md +16 -1
- package/targets-stubs/opencode/neocortex.md +6 -0
- package/targets-stubs/vscode/neocortex.agent.md +2 -2
|
@@ -1,146 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* @license FSL-1.1
|
|
3
|
-
* Copyright (c) 2026 OrNexus AI
|
|
4
|
-
*
|
|
5
|
-
* P190.06 -- runner root-owned execution plane for run_yoloop directives.
|
|
6
|
-
*/
|
|
7
|
-
import { createHash, randomBytes } from 'node:crypto';
|
|
8
|
-
import { spawn } from 'node:child_process';
|
|
9
|
-
import { existsSync } from 'node:fs';
|
|
10
|
-
import * as os from 'node:os';
|
|
11
|
-
import { dirname, join } from 'node:path';
|
|
12
|
-
import { fileURLToPath } from 'node:url';
|
|
13
|
-
import { AUTONOMOUS_GOVERNANCE_EVIDENCE_TAG, AUTONOMOUS_GOVERNANCE_REASON_CODES, autonomousGovernanceMetadata, buildAutonomousGovernanceEnvelope, readAutonomousGovernanceEnvelopeFromMetadata, recordAutonomousGovernance, } from '../../continuity/autonomous-governance.js';
|
|
14
|
-
import { createDefaultHeadlessAdapterRegistry } from './adapters.js';
|
|
15
|
-
import { loadHeadlessRuntimeDefaults, resolveHeadlessRuntime } from './resolver.js';
|
|
16
|
-
import { DEFAULT_HEADLESS_EXECUTION_BACKOFF_MS, DEFAULT_HEADLESS_EXECUTION_LEASE_MS, DEFAULT_HEADLESS_EXECUTION_LIMIT, DEFAULT_HEADLESS_EXECUTION_MAX_ATTEMPTS, DEFAULT_HEADLESS_EXECUTION_STALE_LEASE_AFTER_MS, DEFAULT_HEADLESS_EXECUTION_TIMEOUT_MS, headlessExecutionEntityId, runYoloExecutionPhase, } from './run-yolo.js';
|
|
17
|
-
import { HEADLESS_REASON_CODES, boundPublicSummary, hashPublicValue, redaction, } from './types.js';
|
|
18
|
-
import { validatePhasedYoloopPlan } from './prepared-story-bundle.js';
|
|
19
|
-
import { createAnchoredContinuousStoryCommandRunner, createBranchlessContinuousStoryWorkspaceManager, } from './continuous-story-workspace.js';
|
|
20
|
-
import { executeEpicGitReconciliation, executeEpicTerminalGit } from './epic-terminal-git-runner.js';
|
|
21
|
-
import { createCliEpicTerminalGitAdapter } from './epic-terminal-git-cli-adapter.js';
|
|
22
|
-
import { acquireGitLifecyclePhysicalIntegrationLock, releaseGitLifecyclePhysicalIntegrationLock, } from '../../git/git-lifecycle-store.js';
|
|
23
|
-
import { normalizeContinuousWriteRef } from '../../../../shared/dist/yoloop/wave-decision-receipt.js';
|
|
24
|
-
import { parseReleaseBlockedResult, } from '../../../../shared/dist/yoloop/release-blocked.js';
|
|
25
|
-
export const DEFAULT_HEADLESS_YOLOOP_MAX_ITERATIONS = 20;
|
|
26
|
-
export const DEFAULT_HEADLESS_YOLOOP_MAX_DURATION_MS = 30 * 60 * 1000;
|
|
27
|
-
export const DEFAULT_HEADLESS_YOLOOP_LOCAL_CONCURRENCY_CAP = 1;
|
|
28
|
-
export const MAX_HEADLESS_YOLOOP_LOCAL_CONCURRENCY_CAP = 10;
|
|
29
|
-
/**
|
|
30
|
-
* Resolve the absent-override default from physical capacity. The explicit CLI
|
|
31
|
-
* option remains authoritative; this resolver is injectable for deterministic
|
|
32
|
-
* Node 18 fallback tests.
|
|
33
|
-
*/
|
|
34
|
-
export function resolveDefaultHeadlessYoloopLocalConcurrencyCap(input = {}) {
|
|
35
|
-
let reported = input.availableParallelism;
|
|
36
|
-
if (reported === undefined) {
|
|
37
|
-
const available = os.availableParallelism;
|
|
38
|
-
if (typeof available === 'function') {
|
|
39
|
-
try {
|
|
40
|
-
reported = available();
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
reported = undefined;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (!Number.isFinite(reported) || (reported ?? 0) < 1) {
|
|
48
|
-
const cpuCount = input.cpuCount ?? (() => {
|
|
49
|
-
try {
|
|
50
|
-
return os.cpus().length;
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
return DEFAULT_HEADLESS_YOLOOP_LOCAL_CONCURRENCY_CAP;
|
|
54
|
-
}
|
|
55
|
-
})();
|
|
56
|
-
reported = Number.isFinite(cpuCount) && cpuCount > 0
|
|
57
|
-
? cpuCount
|
|
58
|
-
: DEFAULT_HEADLESS_YOLOOP_LOCAL_CONCURRENCY_CAP;
|
|
59
|
-
}
|
|
60
|
-
return boundedInteger(reported ?? DEFAULT_HEADLESS_YOLOOP_LOCAL_CONCURRENCY_CAP, 1, MAX_HEADLESS_YOLOOP_LOCAL_CONCURRENCY_CAP);
|
|
61
|
-
}
|
|
62
|
-
export const RUN_YOLOOP_DRIVER_STATES = Object.freeze([
|
|
63
|
-
'start',
|
|
64
|
-
'lifecycle_evidence',
|
|
65
|
-
'metadata_parse',
|
|
66
|
-
'child_story_delegation',
|
|
67
|
-
'reinvoke',
|
|
68
|
-
'git_reconciliation',
|
|
69
|
-
'terminal_git',
|
|
70
|
-
'complete',
|
|
71
|
-
'aborted',
|
|
72
|
-
'release_blocked',
|
|
73
|
-
'backoff',
|
|
74
|
-
]);
|
|
75
|
-
const EPIC_TARGET_PATTERN = /^docs\/epics\/epic-[A-Za-z0-9._-]+\.md$/;
|
|
76
|
-
const CHILD_STORY_TARGET_PATTERN = /^docs\/stories\/[A-Za-z0-9._-]+\.story\.md$/;
|
|
77
|
-
const CHILD_PROMPT_PATTERN = /^\*yolo @docs\/stories\/[A-Za-z0-9._-]+\.story\.md(?: branchless-preparation)?$/;
|
|
78
|
-
const BRANCHLESS_PREPARATION_PROMPT_PATTERN = /^\*yolo @docs\/stories\/[A-Za-z0-9._-]+\.story\.md branchless-preparation$/;
|
|
79
|
-
const FRONTMATTER_ENVELOPE_PATTERN = /^(?:\uFEFF)?---(?:\r?\n)/;
|
|
80
|
-
const SAFE_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$/;
|
|
81
|
-
const SHELL_FRAGMENT_PATTERN = /(?:[;&|`$<>]|\$\(|\n|\r|\0)/;
|
|
82
|
-
const UNSAFE_KEY_PATTERN = /(raw[_-]?(?:logs?|payloads?)|std(?:out|err)|stack(?:[_-]?trace)?|transcript|objective(?:[_-]?(?:text|body|prompt))|prompt(?:[_-]?(?:body|text))?|private[_-]?(?:urls?|prompts?)|secret|token|password|protected(?:[_-]?(?:field|body|bodies|internals))?|workflow(?:[_-]?body)?|step(?:[_-]?body)?|customer(?:[_-]?(?:pii|data))?|\bpii\b|authorization|api[_-]?key|license[_-]?key|argv|args|executable(?:[_-]?path)?|binary(?:[_-]?path)?|shell|cwd|command[_-]?path|vendor(?:[_-]?(?:payload|corpus|response|output)))/i;
|
|
83
|
-
const UNSAFE_VALUE_PATTERN = /(https?:\/\/\S+|(?:^|\s)(?:\/(?:home|Users|media|mnt|tmp|var|etc|private)\/\S+|[A-Za-z]:\\\S+)|ghp_[A-Za-z0-9_]+|sk-[A-Za-z0-9_-]+|-----BEGIN [A-Z ]*PRIVATE KEY-----|authorization\s*:|password\s*=|token\s*=|api[_-]?key\s*=|license[_-]?key\s*=|raw[_-]?(?:logs?)\s*[:=]|transcript|stack\s*trace|stderr:|stdout:|system prompt|workflow body|step body|PROTECTED_|PRIVATE_INTERNALS|CUSTOMER_PII|\bPII\b|VENDOR_CORPUS|P190[_-]?SYNTHETIC[_-]?(?:HEADLESS|CONTINUITY))/i;
|
|
84
|
-
const PUBLIC_CHILD_DEBT_CONSTRAINTS = new Set([
|
|
85
|
-
'no_private_prompt_or_history',
|
|
86
|
-
'no_raw_vendor_corpus',
|
|
87
|
-
'no_unrelated_story_context',
|
|
88
|
-
]);
|
|
89
|
-
function hasDelegatedPromptIsolationViolation(prompt) {
|
|
90
|
-
return FRONTMATTER_ENVELOPE_PATTERN.test(prompt) ||
|
|
91
|
-
prompt.includes('@neocortex') ||
|
|
92
|
-
prompt.includes('*yoloop') ||
|
|
93
|
-
SHELL_FRAGMENT_PATTERN.test(prompt) ||
|
|
94
|
-
UNSAFE_VALUE_PATTERN.test(prompt);
|
|
95
|
-
}
|
|
96
|
-
export function isCanonicalDelegatedStoryPrompt(prompt) {
|
|
97
|
-
return !hasDelegatedPromptIsolationViolation(prompt) && CHILD_PROMPT_PATTERN.test(prompt);
|
|
98
|
-
}
|
|
99
|
-
const EXECUTION_DIRECTIVE_ALLOWED_KEYS = new Set([
|
|
100
|
-
'schemaVersion',
|
|
101
|
-
'contractVersion',
|
|
102
|
-
'kind',
|
|
103
|
-
'commandClass',
|
|
104
|
-
'jobId',
|
|
105
|
-
'operationId',
|
|
106
|
-
'idempotencyKey',
|
|
107
|
-
'targetKind',
|
|
108
|
-
'targetRef',
|
|
109
|
-
'commandRef',
|
|
110
|
-
'epicId',
|
|
111
|
-
'runtime',
|
|
112
|
-
'publicSummary',
|
|
113
|
-
'reasonCode',
|
|
114
|
-
'attempts',
|
|
115
|
-
'metadata',
|
|
116
|
-
'redactionSummary',
|
|
117
|
-
'publicSafe',
|
|
118
|
-
]);
|
|
119
|
-
const RUNTIME_ALLOWED_KEYS = new Set(['runtimeId', 'modelId', 'source', 'reasonCode', 'publicSafe']);
|
|
120
|
-
const JOB_ABORTED_REASON_CODE = 'job-aborted';
|
|
121
|
-
const MAX_ITERATIONS_REASON_CODE = 'max-iterations-reached';
|
|
122
|
-
const MAX_DURATION_REASON_CODE = 'max-duration-reached';
|
|
123
|
-
const PUBLIC_TERMINAL_LOCK_RETRY_REASONS = new Set([
|
|
124
|
-
'git-lifecycle-integration-backpressure',
|
|
125
|
-
'git-lifecycle-integration-lock-failed',
|
|
126
|
-
'git-lifecycle-integration-lock-release-failed',
|
|
127
|
-
]);
|
|
128
|
-
const RESUMABLE_YOLOOP_BOUNDARY_REASONS = new Set([
|
|
129
|
-
'yoloop-per-run-cap-resumable',
|
|
130
|
-
'yoloop-session-timeout-resumable',
|
|
131
|
-
]);
|
|
132
|
-
async function defaultIsolatedYoloopRootInvokeTransport(options, boundary) {
|
|
133
|
-
// The thin client's lock belongs to its invocation PID. Keeping invoke in
|
|
134
|
-
// the long-lived runner made the next iteration see its own PID as another
|
|
135
|
-
// live owner forever. Use the normal short-lived client lifetime; only the
|
|
136
|
-
// existing local liveness reconciler may recover its lock after process exit.
|
|
137
|
-
// Loop scheduling and all Git effects remain in this root, not in the child.
|
|
138
|
-
const moduleDirectory = dirname(fileURLToPath(import.meta.url));
|
|
139
|
-
const installedModule = join(moduleDirectory, '../../commands/invoke.js');
|
|
140
|
-
const modulePath = existsSync(installedModule) ? installedModule
|
|
141
|
-
: join(moduleDirectory, '../../../dist/commands/invoke.js');
|
|
142
|
-
return new Promise((resolveResult) => {
|
|
143
|
-
const child = spawn(process.execPath, ['--input-type=module', '-e', `
|
|
1
|
+
import{createHash as Ke,randomBytes as Ue}from"node:crypto";import{spawn as ze}from"node:child_process";import{existsSync as $e}from"node:fs";import*as ke from"node:os";import{dirname as Ye,join as Oe}from"node:path";import{fileURLToPath as Fe}from"node:url";import{AUTONOMOUS_GOVERNANCE_EVIDENCE_TAG as Ve,AUTONOMOUS_GOVERNANCE_REASON_CODES as Ee,autonomousGovernanceMetadata as Re,buildAutonomousGovernanceEnvelope as qe,readAutonomousGovernanceEnvelopeFromMetadata as ve,recordAutonomousGovernance as We}from"../../continuity/autonomous-governance.js";import{createDefaultHeadlessAdapterRegistry as Ge}from"./adapters.js";import{loadHeadlessRuntimeDefaults as Xe,resolveHeadlessRuntime as Ze}from"./resolver.js";import{DEFAULT_HEADLESS_EXECUTION_BACKOFF_MS as Je,DEFAULT_HEADLESS_EXECUTION_LIMIT as Qe,DEFAULT_HEADLESS_EXECUTION_MAX_ATTEMPTS as et,DEFAULT_HEADLESS_EXECUTION_STALE_LEASE_AFTER_MS as tt,DEFAULT_HEADLESS_EXECUTION_TIMEOUT_MS as rt,headlessExecutionEntityId as q,runYoloExecutionPhase as ot}from"./run-yolo.js";import{HEADLESS_REASON_CODES as p,boundPublicSummary as me,hashPublicValue as x,redaction as h}from"./types.js";import{validatePhasedYoloopPlan as at}from"./prepared-story-bundle.js";import{createAnchoredContinuousStoryCommandRunner as nt,createBranchlessContinuousStoryWorkspaceManager as st}from"./continuous-story-workspace.js";import{P205_RELEASE_GATE_BUDGETS as oe}from"../../../../shared/dist/yoloop/epic-terminal-git.js";import{executeEpicGitReconciliation as it,executeEpicTerminalGit as dt}from"./epic-terminal-git-runner.js";import{createCliEpicTerminalGitAdapter as ct}from"./epic-terminal-git-cli-adapter.js";import{acquireGitLifecyclePhysicalIntegrationLock as lt,releaseGitLifecyclePhysicalIntegrationLock as ut}from"../../git/git-lifecycle-store.js";import{normalizeContinuousWriteRef as pt}from"../../../../shared/dist/yoloop/wave-decision-receipt.js";import{parseReleaseBlockedResult as mt}from"../../../../shared/dist/yoloop/release-blocked.js";const ft=20,yt=oe.terminalWorkflowMaxDurationMs,ht=oe.terminalWorkflowMaxDurationMs,fe=1,Pe=10;function Te(e={}){let r=e.availableParallelism;if(r===void 0){const t=ke.availableParallelism;if(typeof t=="function")try{r=t()}catch{r=void 0}}if(!Number.isFinite(r)||(r??0)<1){const t=e.cpuCount??(()=>{try{return ke.cpus().length}catch{return fe}})();r=Number.isFinite(t)&&t>0?t:fe}return F(r??fe,1,Pe)}const Or=Object.freeze(["start","lifecycle_evidence","metadata_parse","child_story_delegation","reinvoke","git_reconciliation","terminal_git","complete","aborted","release_blocked","backoff"]),ye=/^docs\/epics\/epic-[A-Za-z0-9._-]+\.md$/,_t=/^docs\/stories\/[A-Za-z0-9._-]+\.story\.md$/,he=/^\*yolo @docs\/stories\/[A-Za-z0-9._-]+\.story\.md(?: branchless-preparation)?$/,Ct=/^\*yolo @docs\/stories\/[A-Za-z0-9._-]+\.story\.md branchless-preparation$/,It=/^(?:\uFEFF)?---(?:\r?\n)/,bt=/^[A-Za-z0-9][A-Za-z0-9._:-]{0,159}$/,W=/(?:[;&|`$<>]|\$\(|\n|\r|\0)/,ae=/(raw[_-]?(?:logs?|payloads?)|std(?:out|err)|stack(?:[_-]?trace)?|transcript|objective(?:[_-]?(?:text|body|prompt))|prompt(?:[_-]?(?:body|text))?|private[_-]?(?:urls?|prompts?)|secret|token|password|protected(?:[_-]?(?:field|body|bodies|internals))?|workflow(?:[_-]?body)?|step(?:[_-]?body)?|customer(?:[_-]?(?:pii|data))?|\bpii\b|authorization|api[_-]?key|license[_-]?key|argv|args|executable(?:[_-]?path)?|binary(?:[_-]?path)?|shell|cwd|command[_-]?path|vendor(?:[_-]?(?:payload|corpus|response|output)))/i,D=/(https?:\/\/\S+|(?:^|\s)(?:\/(?:home|Users|media|mnt|tmp|var|etc|private)\/\S+|[A-Za-z]:\\\S+)|ghp_[A-Za-z0-9_]+|sk-[A-Za-z0-9_-]+|-----BEGIN [A-Z ]*PRIVATE KEY-----|authorization\s*:|password\s*=|token\s*=|api[_-]?key\s*=|license[_-]?key\s*=|raw[_-]?(?:logs?)\s*[:=]|transcript|stack\s*trace|stderr:|stdout:|system prompt|workflow body|step body|PROTECTED_|PRIVATE_INTERNALS|CUSTOMER_PII|\bPII\b|VENDOR_CORPUS|P190[_-]?SYNTHETIC[_-]?(?:HEADLESS|CONTINUITY))/i,St=new Set(["no_private_prompt_or_history","no_raw_vendor_corpus","no_unrelated_story_context"]);function we(e){return It.test(e)||e.includes("@neocortex")||e.includes("*yoloop")||W.test(e)||D.test(e)}function Er(e){return!we(e)&&he.test(e)}const gt=new Set(["schemaVersion","contractVersion","kind","commandClass","jobId","operationId","idempotencyKey","targetKind","targetRef","commandRef","epicId","runtime","publicSummary","reasonCode","attempts","metadata","redactionSummary","publicSafe"]),At=new Set(["runtimeId","modelId","source","reasonCode","publicSafe"]),kt="job-aborted",Ot="max-iterations-reached",Et="max-duration-reached",Rt=new Set(["git-lifecycle-integration-backpressure","git-lifecycle-integration-lock-failed","git-lifecycle-integration-lock-release-failed"]),xe=new Set(["yoloop-per-run-cap-resumable","yoloop-session-timeout-resumable"]);async function vt(e,r){const t=Ye(Fe(import.meta.url)),a=Oe(t,"../../commands/invoke.js"),o=$e(a)?a:Oe(t,"../../../dist/commands/invoke.js");return new Promise(s=>{const n=ze(process.execPath,["--input-type=module","-e",`
|
|
144
2
|
import { pathToFileURL } from 'node:url';
|
|
145
3
|
process.once('message', async ({ modulePath, options }) => {
|
|
146
4
|
try {
|
|
@@ -149,2434 +7,4 @@ async function defaultIsolatedYoloopRootInvokeTransport(options, boundary) {
|
|
|
149
7
|
process.send(result, () => process.exit(0));
|
|
150
8
|
} catch { process.exit(1); }
|
|
151
9
|
});
|
|
152
|
-
`], { cwd: boundary.projectRoot, stdio: ['ignore', 'pipe', 'pipe', 'ipc'], windowsHide: true });
|
|
153
|
-
let received;
|
|
154
|
-
let bytes = 0;
|
|
155
|
-
let invalid = false;
|
|
156
|
-
const timer = setTimeout(() => { invalid = true; child.kill(); }, boundary.timeoutMs);
|
|
157
|
-
const countOutput = (chunk) => {
|
|
158
|
-
bytes += chunk.length;
|
|
159
|
-
if (bytes > 32 * 1024 * 1024) {
|
|
160
|
-
invalid = true;
|
|
161
|
-
child.kill();
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
child.stdout?.on('data', countOutput);
|
|
165
|
-
child.stderr?.on('data', countOutput);
|
|
166
|
-
child.on('message', (value) => {
|
|
167
|
-
if (received || !isRecord(value) || typeof value.success !== 'boolean'
|
|
168
|
-
|| Buffer.byteLength(JSON.stringify(value)) > 32 * 1024 * 1024) {
|
|
169
|
-
invalid = true;
|
|
170
|
-
child.kill();
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
received = value;
|
|
174
|
-
});
|
|
175
|
-
const failed = { success: false, errorCode: 'headless-root-invoke-failed',
|
|
176
|
-
error: 'The isolated root metadata invocation did not complete.', exitCode: 1 };
|
|
177
|
-
child.on('error', () => { invalid = true; });
|
|
178
|
-
child.on('close', (code) => {
|
|
179
|
-
clearTimeout(timer);
|
|
180
|
-
resolveResult(code === 0 && !invalid && received ? received : failed);
|
|
181
|
-
});
|
|
182
|
-
child.send({ modulePath, options }, (error) => { if (error) {
|
|
183
|
-
invalid = true;
|
|
184
|
-
child.kill();
|
|
185
|
-
} });
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
export async function defaultYoloopRootInvoker(input, invokeTransport = defaultIsolatedYoloopRootInvokeTransport) {
|
|
189
|
-
const startedAt = Date.now();
|
|
190
|
-
const options = {
|
|
191
|
-
args: input.args,
|
|
192
|
-
projectRoot: input.projectRoot,
|
|
193
|
-
format: 'json',
|
|
194
|
-
platformTarget: 'runner',
|
|
195
|
-
serverUrl: input.serverUrl,
|
|
196
|
-
strictReadOnly: input.strictReadOnly,
|
|
197
|
-
};
|
|
198
|
-
const result = await invokeTransport(options, {
|
|
199
|
-
projectRoot: input.projectRoot,
|
|
200
|
-
timeoutMs: input.timeoutMs,
|
|
201
|
-
});
|
|
202
|
-
return {
|
|
203
|
-
success: result.success,
|
|
204
|
-
instructions: result.instructions,
|
|
205
|
-
metadata: result.metadata,
|
|
206
|
-
error: result.error,
|
|
207
|
-
errorCode: result.errorCode,
|
|
208
|
-
exitCode: result.exitCode,
|
|
209
|
-
durationMs: Date.now() - startedAt,
|
|
210
|
-
publicSafe: true,
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
export async function runYoloopExecutionPhase(options) {
|
|
214
|
-
const registry = options.adapterRegistry ?? createDefaultHeadlessAdapterRegistry();
|
|
215
|
-
const limit = boundedInteger(options.limit ?? DEFAULT_HEADLESS_EXECUTION_LIMIT, 1, 10);
|
|
216
|
-
const leaseMs = boundedInteger(options.leaseMs ?? DEFAULT_HEADLESS_EXECUTION_LEASE_MS, 1_000, 60 * 60 * 1000);
|
|
217
|
-
const staleLeaseAfterMs = boundedInteger(options.staleLeaseAfterMs ?? DEFAULT_HEADLESS_EXECUTION_STALE_LEASE_AFTER_MS, 0, 24 * 60 * 60 * 1000);
|
|
218
|
-
const maxAttempts = boundedInteger(options.maxAttempts ?? DEFAULT_HEADLESS_EXECUTION_MAX_ATTEMPTS, 1, 10);
|
|
219
|
-
const localConcurrencyCap = boundedInteger(options.localConcurrencyCap ?? resolveDefaultHeadlessYoloopLocalConcurrencyCap(), 1, MAX_HEADLESS_YOLOOP_LOCAL_CONCURRENCY_CAP);
|
|
220
|
-
const reasonCodes = [];
|
|
221
|
-
const receipts = [];
|
|
222
|
-
const nowIso = options.now();
|
|
223
|
-
const enqueueResult = enqueueRunYoloopExecutionDirectives({
|
|
224
|
-
store: options.store,
|
|
225
|
-
metadata: options.metadata,
|
|
226
|
-
nowIso,
|
|
227
|
-
maxAttempts,
|
|
228
|
-
queueCap: options.queueCap,
|
|
229
|
-
});
|
|
230
|
-
reasonCodes.push(...enqueueResult.reasonCodes);
|
|
231
|
-
const recovered = options.store.recoverStaleHeadlessExecutionAttempts({
|
|
232
|
-
nowIso,
|
|
233
|
-
staleAfterMs: staleLeaseAfterMs,
|
|
234
|
-
limit: limit * 2,
|
|
235
|
-
});
|
|
236
|
-
if (recovered.recoveredAttemptIds.length > 0) {
|
|
237
|
-
reasonCodes.push(HEADLESS_REASON_CODES.EXECUTION_BACKOFF);
|
|
238
|
-
if (recovered.failedAttemptIds.length > 0)
|
|
239
|
-
reasonCodes.push(HEADLESS_REASON_CODES.EXECUTION_TIMEOUT);
|
|
240
|
-
}
|
|
241
|
-
const dueAttempts = options.store
|
|
242
|
-
.listDueHeadlessExecutionAttempts({ nowIso: options.now(), limit: Math.max(limit * 5, 10) })
|
|
243
|
-
.filter((attempt) => attempt.directive_kind === 'run_yoloop')
|
|
244
|
-
.slice(0, limit);
|
|
245
|
-
for (const attempt of dueAttempts) {
|
|
246
|
-
const receipt = await processRunYoloopAttempt({
|
|
247
|
-
store: options.store,
|
|
248
|
-
projectRoot: options.projectRoot,
|
|
249
|
-
runnerId: options.runnerId,
|
|
250
|
-
attempt,
|
|
251
|
-
registry,
|
|
252
|
-
now: options.now,
|
|
253
|
-
leaseMs,
|
|
254
|
-
timeoutMs: boundedInteger(options.timeoutMs ?? DEFAULT_HEADLESS_EXECUTION_TIMEOUT_MS, 1_000, 30 * 60 * 1000),
|
|
255
|
-
backoffMs: boundedInteger(options.backoffMs ?? DEFAULT_HEADLESS_EXECUTION_BACKOFF_MS, 1_000, 60 * 60 * 1000),
|
|
256
|
-
maxAttempts,
|
|
257
|
-
maxIterations: boundedInteger(options.maxIterations ?? DEFAULT_HEADLESS_YOLOOP_MAX_ITERATIONS, 1, 100),
|
|
258
|
-
maxDurationMs: boundedInteger(options.maxDurationMs ?? DEFAULT_HEADLESS_YOLOOP_MAX_DURATION_MS, 1_000, 2 * 60 * 60 * 1000),
|
|
259
|
-
localConcurrencyCap,
|
|
260
|
-
queueCap: options.queueCap,
|
|
261
|
-
adapterOptions: options.adapterOptions,
|
|
262
|
-
runtimeDefaults: options.runtimeDefaults,
|
|
263
|
-
runtimeFallback: options.runtimeFallback,
|
|
264
|
-
yoloopInvoker: options.yoloopInvoker ?? defaultYoloopRootInvoker,
|
|
265
|
-
serverUrl: options.serverUrl,
|
|
266
|
-
idFactory: options.idFactory ?? defaultHeadlessIdFactory,
|
|
267
|
-
continuousWorkspaceManager: options.continuousWorkspaceManager ?? createBranchlessContinuousStoryWorkspaceManager(),
|
|
268
|
-
terminalGitAdapter: options.terminalGitAdapter ?? createCliEpicTerminalGitAdapter(options.projectRoot),
|
|
269
|
-
});
|
|
270
|
-
receipts.push(receipt);
|
|
271
|
-
reasonCodes.push(receipt.reasonCode, ...receipt.workerPoolSummary.reasonCodes);
|
|
272
|
-
}
|
|
273
|
-
return {
|
|
274
|
-
ok: receipts.every((receipt) => receipt.outcome !== 'failed') && enqueueResult.rejectedCount === 0,
|
|
275
|
-
enqueuedAttemptCount: enqueueResult.enqueuedCount,
|
|
276
|
-
dueAttemptCount: dueAttempts.length,
|
|
277
|
-
processedAttemptCount: receipts.filter((receipt) => receipt.outcome !== 'ignored').length,
|
|
278
|
-
recoveredAttemptIds: recovered.recoveredAttemptIds,
|
|
279
|
-
receipts,
|
|
280
|
-
reasonCodes: unique(reasonCodes.length > 0 ? reasonCodes : [HEADLESS_REASON_CODES.OK]),
|
|
281
|
-
publicSafe: true,
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
function enqueueRunYoloopExecutionDirectives(input) {
|
|
285
|
-
let enqueuedCount = 0;
|
|
286
|
-
let rejectedCount = 0;
|
|
287
|
-
const reasonCodes = [];
|
|
288
|
-
for (const candidate of extractExecutionDirectiveCandidates(input.metadata)) {
|
|
289
|
-
if (!isRecord(candidate) || candidate.kind !== 'run_yoloop')
|
|
290
|
-
continue;
|
|
291
|
-
const validation = validateRunYoloopExecutionDirective(candidate);
|
|
292
|
-
if (!validation.ok) {
|
|
293
|
-
rejectedCount += 1;
|
|
294
|
-
reasonCodes.push(validation.reasonCode);
|
|
295
|
-
continue;
|
|
296
|
-
}
|
|
297
|
-
const directive = validation.directive;
|
|
298
|
-
if (!input.store.jobExists(directive.jobId)) {
|
|
299
|
-
rejectedCount += 1;
|
|
300
|
-
reasonCodes.push(AUTONOMOUS_GOVERNANCE_REASON_CODES.BYPASS_BLOCKED);
|
|
301
|
-
continue;
|
|
302
|
-
}
|
|
303
|
-
const directiveHash = hashDirective(directive);
|
|
304
|
-
if (input.store.hasCompletedHeadlessExecutionDirectiveHash(directiveHash)) {
|
|
305
|
-
reasonCodes.push(HEADLESS_REASON_CODES.EXECUTION_COMPLETED);
|
|
306
|
-
continue;
|
|
307
|
-
}
|
|
308
|
-
const governanceEnvelope = buildAutonomousGovernanceEnvelope({
|
|
309
|
-
autonomousKind: 'run_yoloop',
|
|
310
|
-
source: 'headless-run-yoloop',
|
|
311
|
-
targetKind: 'epic',
|
|
312
|
-
targetRef: directive.targetRef,
|
|
313
|
-
epicId: directive.epicId ?? epicIdFromTargetRef(directive.targetRef),
|
|
314
|
-
jobId: directive.jobId,
|
|
315
|
-
operationSeed: directive.operationId,
|
|
316
|
-
commandHash: hashPublicValue(directive.commandRef),
|
|
317
|
-
});
|
|
318
|
-
const governance = recordAutonomousGovernance(input.store, governanceEnvelope, input.nowIso, { requireExistingJob: true });
|
|
319
|
-
if (!governance.ok) {
|
|
320
|
-
rejectedCount += 1;
|
|
321
|
-
reasonCodes.push(governance.reasonCode);
|
|
322
|
-
continue;
|
|
323
|
-
}
|
|
324
|
-
const attemptId = headlessExecutionEntityId('attempt', directive.idempotencyKey);
|
|
325
|
-
const executionId = headlessExecutionEntityId('exec', directive.operationId);
|
|
326
|
-
const result = input.store.enqueueHeadlessExecutionAttempt({
|
|
327
|
-
attemptId,
|
|
328
|
-
executionId,
|
|
329
|
-
jobId: directive.jobId,
|
|
330
|
-
directiveHash,
|
|
331
|
-
directiveKind: 'run_yoloop',
|
|
332
|
-
commandClass: directive.commandClass,
|
|
333
|
-
targetKind: 'epic',
|
|
334
|
-
targetRef: directive.targetRef,
|
|
335
|
-
epicId: directive.epicId ?? epicIdFromTargetRef(directive.targetRef),
|
|
336
|
-
runtimeId: directive.runtime?.runtimeId,
|
|
337
|
-
modelId: directive.runtime?.modelId,
|
|
338
|
-
runtimeSource: normalizeStoredRuntimeSource(directive.runtime?.source),
|
|
339
|
-
reasonCode: directive.reasonCode,
|
|
340
|
-
publicSummary: directive.publicSummary,
|
|
341
|
-
enqueuedAt: input.nowIso,
|
|
342
|
-
notBeforeAt: input.nowIso,
|
|
343
|
-
maxAttempts: input.maxAttempts,
|
|
344
|
-
queueCap: input.queueCap,
|
|
345
|
-
operationId: `${directive.operationId}:enqueue`,
|
|
346
|
-
idempotencyKey: directive.idempotencyKey,
|
|
347
|
-
counts: { directives: 1 },
|
|
348
|
-
hashes: { directive: directiveHash },
|
|
349
|
-
redactionSummary: directive.redactionSummary,
|
|
350
|
-
relativePaths: [directive.targetRef],
|
|
351
|
-
metadata: autonomousGovernanceMetadata(governanceEnvelope, {
|
|
352
|
-
schemaVersion: 1,
|
|
353
|
-
contractVersion: 'continuity-v1',
|
|
354
|
-
jobId: directive.jobId,
|
|
355
|
-
operationId: directive.operationId,
|
|
356
|
-
reasonCode: directive.reasonCode ?? HEADLESS_REASON_CODES.OK,
|
|
357
|
-
targetRef: directive.targetRef,
|
|
358
|
-
directiveHash,
|
|
359
|
-
}),
|
|
360
|
-
});
|
|
361
|
-
if (!result.accepted) {
|
|
362
|
-
rejectedCount += 1;
|
|
363
|
-
reasonCodes.push(result.reasonCode ?? 'queue-cap-reached');
|
|
364
|
-
continue;
|
|
365
|
-
}
|
|
366
|
-
if (result.inserted)
|
|
367
|
-
enqueuedCount += 1;
|
|
368
|
-
reasonCodes.push(HEADLESS_REASON_CODES.OK);
|
|
369
|
-
}
|
|
370
|
-
return { enqueuedCount, rejectedCount, reasonCodes: unique(reasonCodes) };
|
|
371
|
-
}
|
|
372
|
-
async function processRunYoloopAttempt(input) {
|
|
373
|
-
const claimedAt = input.now();
|
|
374
|
-
const leaseId = input.idFactory('lease', input.attempt.attempt_id);
|
|
375
|
-
const leaseExpiresAt = addMilliseconds(claimedAt, input.leaseMs);
|
|
376
|
-
const claim = input.store.claimHeadlessExecutionAttempt({
|
|
377
|
-
attemptId: input.attempt.attempt_id,
|
|
378
|
-
leaseId,
|
|
379
|
-
runnerId: input.runnerId,
|
|
380
|
-
claimedAt,
|
|
381
|
-
leaseExpiresAt,
|
|
382
|
-
reasonCode: HEADLESS_REASON_CODES.OK,
|
|
383
|
-
});
|
|
384
|
-
if (!claim.inserted) {
|
|
385
|
-
return emptyYoloopReceipt(input.attempt, {
|
|
386
|
-
status: input.attempt.status,
|
|
387
|
-
receiptStatus: 'ignored',
|
|
388
|
-
reasonCode: 'lease-conflict',
|
|
389
|
-
timestamp: claimedAt,
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
const duplicateCompletion = input.store.hasCompletedHeadlessExecutionDirectiveHash(input.attempt.directive_hash, input.attempt.attempt_id);
|
|
393
|
-
if (duplicateCompletion) {
|
|
394
|
-
return persistYoloopAttemptOutcome(input.store, input.attempt, {
|
|
395
|
-
leaseId,
|
|
396
|
-
runnerId: input.runnerId,
|
|
397
|
-
status: 'skipped',
|
|
398
|
-
receiptStatus: 'ignored',
|
|
399
|
-
reasonCode: HEADLESS_REASON_CODES.EXECUTION_COMPLETED,
|
|
400
|
-
publicSummary: 'Skipped duplicate run_yoloop directive because the directive hash is already completed.',
|
|
401
|
-
completedAt: input.now(),
|
|
402
|
-
counts: emptyAggregateCounts(),
|
|
403
|
-
hashes: { directive: input.attempt.directive_hash },
|
|
404
|
-
redactionSummary: [],
|
|
405
|
-
relativePaths: [input.attempt.target_ref],
|
|
406
|
-
childStoryIds: [],
|
|
407
|
-
stateTransitions: ['start', 'complete'],
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
const preparation = prepareYoloopAttemptInput(input);
|
|
411
|
-
if (!preparation.ok) {
|
|
412
|
-
return persistYoloopAttemptOutcome(input.store, input.attempt, {
|
|
413
|
-
leaseId,
|
|
414
|
-
runnerId: input.runnerId,
|
|
415
|
-
status: preparation.status,
|
|
416
|
-
receiptStatus: preparation.receiptStatus,
|
|
417
|
-
reasonCode: preparation.reasonCode,
|
|
418
|
-
publicSummary: preparation.publicSummary,
|
|
419
|
-
completedAt: input.now(),
|
|
420
|
-
counts: emptyAggregateCounts(),
|
|
421
|
-
hashes: { directive: input.attempt.directive_hash },
|
|
422
|
-
redactionSummary: preparation.redactionSummary,
|
|
423
|
-
relativePaths: safeAttemptRelativePaths(input.attempt),
|
|
424
|
-
childStoryIds: [],
|
|
425
|
-
stateTransitions: ['start'],
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
const driverResult = await executeRootOwnedYoloop({
|
|
429
|
-
...input,
|
|
430
|
-
prepared: preparation.input,
|
|
431
|
-
});
|
|
432
|
-
const retry = retryDecision(input.attempt, driverResult, input.maxAttempts, input.backoffMs, input.now());
|
|
433
|
-
const status = retry.retry ? 'backoff' : driverResult.status;
|
|
434
|
-
const receiptStatus = retry.retry ? 'deferred' : driverResult.receiptStatus;
|
|
435
|
-
const reasonCode = retry.retry
|
|
436
|
-
? (PUBLIC_TERMINAL_LOCK_RETRY_REASONS.has(driverResult.reasonCode)
|
|
437
|
-
|| RESUMABLE_YOLOOP_BOUNDARY_REASONS.has(driverResult.reasonCode)
|
|
438
|
-
? driverResult.reasonCode : HEADLESS_REASON_CODES.EXECUTION_BACKOFF)
|
|
439
|
-
: driverResult.reasonCode;
|
|
440
|
-
const publicSummary = retry.retry
|
|
441
|
-
? 'Headless run_yoloop execution scheduled bounded retry after transient metadata/runtime outcome.'
|
|
442
|
-
: driverResult.publicSummary;
|
|
443
|
-
return persistYoloopAttemptOutcome(input.store, input.attempt, {
|
|
444
|
-
leaseId,
|
|
445
|
-
runnerId: input.runnerId,
|
|
446
|
-
status,
|
|
447
|
-
receiptStatus,
|
|
448
|
-
reasonCode,
|
|
449
|
-
publicSummary,
|
|
450
|
-
completedAt: input.now(),
|
|
451
|
-
durationMs: driverResult.durationMs,
|
|
452
|
-
notBeforeAt: retry.notBeforeAt,
|
|
453
|
-
retryCount: retry.retryCount,
|
|
454
|
-
counts: driverResult.counts,
|
|
455
|
-
workerPoolSummary: driverResult.workerPoolSummary,
|
|
456
|
-
hashes: { ...driverResult.hashes, directive: input.attempt.directive_hash },
|
|
457
|
-
redactionSummary: driverResult.redactionSummary,
|
|
458
|
-
relativePaths: driverResult.relativePaths,
|
|
459
|
-
childStoryIds: driverResult.childStoryIds,
|
|
460
|
-
runtimeId: preparation.input.runtimeId,
|
|
461
|
-
modelId: preparation.input.modelId,
|
|
462
|
-
runtimeSource: preparation.input.runtimeSource,
|
|
463
|
-
stateTransitions: driverResult.stateTransitions,
|
|
464
|
-
terminalClass: driverResult.terminalClass,
|
|
465
|
-
releaseBlocked: driverResult.releaseBlocked,
|
|
466
|
-
});
|
|
467
|
-
}
|
|
468
|
-
async function executeRootOwnedYoloop(input) {
|
|
469
|
-
const startedAt = Date.now();
|
|
470
|
-
const stateTransitions = ['start'];
|
|
471
|
-
const processedStoryIds = new Set();
|
|
472
|
-
const childStoryIds = [];
|
|
473
|
-
const childTargetRefs = [];
|
|
474
|
-
const hashes = { root: hashPublicValue(input.prepared.rootPrompt) };
|
|
475
|
-
const redactions = [redaction('rootPrompt', 'prompt_body', hashes.root)];
|
|
476
|
-
let iterations = 0;
|
|
477
|
-
let succeededChildCount = 0;
|
|
478
|
-
let failedChildCount = 0;
|
|
479
|
-
let skippedChildCount = 0;
|
|
480
|
-
let metadataCompleteCount = 0;
|
|
481
|
-
let metadataAbortedCount = 0;
|
|
482
|
-
let terminalP205Authority;
|
|
483
|
-
let lifecycleEvidencePrepared = false;
|
|
484
|
-
const workerPool = createMutableWorkerPoolSummary(input.localConcurrencyCap);
|
|
485
|
-
const continuousInFlight = new Map();
|
|
486
|
-
let continuousModeObserved = false;
|
|
487
|
-
const continuousDeferredReasons = new Map();
|
|
488
|
-
const continuousFailureReasons = new Map();
|
|
489
|
-
const recordContinuousChild = (result) => {
|
|
490
|
-
const child = result.child;
|
|
491
|
-
hashes[`child-${child.storyId.replace(/[^A-Za-z0-9_.:-]/g, '-')}`] = result.commandHash;
|
|
492
|
-
redactions.push(result.promptRedaction);
|
|
493
|
-
const receipt = result.receipt;
|
|
494
|
-
if (result.terminalFailure) {
|
|
495
|
-
if (result.deferredFailure) {
|
|
496
|
-
continuousDeferredReasons.set(child.storyId, result.terminalFailure);
|
|
497
|
-
workerPool.backpressurePauseCount += 1;
|
|
498
|
-
return;
|
|
499
|
-
}
|
|
500
|
-
continuousDeferredReasons.delete(child.storyId);
|
|
501
|
-
continuousFailureReasons.set(child.storyId, result.terminalFailure);
|
|
502
|
-
if (!processedStoryIds.has(child.storyId)) {
|
|
503
|
-
processedStoryIds.add(child.storyId);
|
|
504
|
-
childStoryIds.push(child.storyId);
|
|
505
|
-
childTargetRefs.push(child.targetRef);
|
|
506
|
-
failedChildCount += 1;
|
|
507
|
-
}
|
|
508
|
-
return;
|
|
509
|
-
}
|
|
510
|
-
if (!receipt || receipt.outcome === 'deferred') {
|
|
511
|
-
continuousDeferredReasons.set(child.storyId, result.reasonCodes.includes('queue-cap-reached')
|
|
512
|
-
? HEADLESS_REASON_CODES.WORKER_POOL_BACKPRESSURE_PAUSED
|
|
513
|
-
: receipt?.reasonCode || HEADLESS_REASON_CODES.EXECUTION_BACKOFF);
|
|
514
|
-
if (result.reasonCodes.includes('queue-cap-reached'))
|
|
515
|
-
workerPool.backpressurePauseCount += 1;
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
continuousDeferredReasons.delete(child.storyId);
|
|
519
|
-
if (processedStoryIds.has(child.storyId))
|
|
520
|
-
return;
|
|
521
|
-
processedStoryIds.add(child.storyId);
|
|
522
|
-
childStoryIds.push(child.storyId);
|
|
523
|
-
childTargetRefs.push(child.targetRef);
|
|
524
|
-
if (receipt.outcome === 'failed') {
|
|
525
|
-
failedChildCount += 1;
|
|
526
|
-
continuousFailureReasons.set(child.storyId, receipt.reasonCode || HEADLESS_REASON_CODES.EXECUTION_FAILED);
|
|
527
|
-
}
|
|
528
|
-
else if (receipt.outcome === 'ignored')
|
|
529
|
-
skippedChildCount += 1;
|
|
530
|
-
else
|
|
531
|
-
succeededChildCount += 1;
|
|
532
|
-
};
|
|
533
|
-
const settleOneContinuousChild = async () => {
|
|
534
|
-
const settled = await Promise.race([...continuousInFlight.entries()].map(([storyId, entry]) => entry.promise.then((result) => ({ storyId, result }))));
|
|
535
|
-
continuousInFlight.delete(settled.storyId);
|
|
536
|
-
workerPool.completedChildCount += 1;
|
|
537
|
-
workerPool.pendingChildCount = continuousInFlight.size;
|
|
538
|
-
recordContinuousChild(settled.result);
|
|
539
|
-
};
|
|
540
|
-
while (true) {
|
|
541
|
-
if (iterations >= input.maxIterations) {
|
|
542
|
-
stateTransitions.push('backoff');
|
|
543
|
-
return driverResult({
|
|
544
|
-
status: 'failed',
|
|
545
|
-
receiptStatus: 'failed',
|
|
546
|
-
reasonCode: MAX_ITERATIONS_REASON_CODE,
|
|
547
|
-
publicSummary: 'Headless yoloop reached the bounded iteration limit before completion metadata.',
|
|
548
|
-
retryable: false,
|
|
549
|
-
startedAt,
|
|
550
|
-
counts: aggregateCounts(iterations, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
551
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
552
|
-
hashes,
|
|
553
|
-
redactions,
|
|
554
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
555
|
-
childStoryIds,
|
|
556
|
-
stateTransitions,
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
if (Date.now() - startedAt > input.maxDurationMs) {
|
|
560
|
-
stateTransitions.push('backoff');
|
|
561
|
-
return driverResult({
|
|
562
|
-
status: 'failed',
|
|
563
|
-
receiptStatus: 'failed',
|
|
564
|
-
reasonCode: MAX_DURATION_REASON_CODE,
|
|
565
|
-
publicSummary: 'Headless yoloop reached the bounded duration limit before completion metadata.',
|
|
566
|
-
retryable: false,
|
|
567
|
-
startedAt,
|
|
568
|
-
counts: aggregateCounts(iterations, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
569
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
570
|
-
hashes,
|
|
571
|
-
redactions,
|
|
572
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
573
|
-
childStoryIds,
|
|
574
|
-
stateTransitions,
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
|
-
stateTransitions.push('metadata_parse');
|
|
578
|
-
const rootResult = await input.yoloopInvoker({
|
|
579
|
-
projectRoot: input.projectRoot,
|
|
580
|
-
args: input.prepared.rootPrompt,
|
|
581
|
-
attemptId: input.attempt.attempt_id,
|
|
582
|
-
executionId: input.attempt.execution_id,
|
|
583
|
-
jobId: input.attempt.job_id,
|
|
584
|
-
runnerId: input.runnerId,
|
|
585
|
-
iteration: iterations,
|
|
586
|
-
runtimeId: input.prepared.runtimeId,
|
|
587
|
-
...(input.prepared.modelId ? { modelId: input.prepared.modelId } : {}),
|
|
588
|
-
timeoutMs: input.timeoutMs,
|
|
589
|
-
serverUrl: input.serverUrl,
|
|
590
|
-
});
|
|
591
|
-
if (rootResult.durationMs !== undefined)
|
|
592
|
-
hashes[`iter-${iterations}`] = hashPublicValue(String(rootResult.durationMs));
|
|
593
|
-
const metadata = rootResult.metadata;
|
|
594
|
-
const releaseBlockedTransport = rootResult.errorCode === 'YOLOOP_RELEASE_BLOCKED'
|
|
595
|
-
|| metadata?.yoloopReleaseBlocked === true
|
|
596
|
-
|| metadata?.terminalClass === 'release-blocked'
|
|
597
|
-
|| metadata?.releaseBlocked !== undefined;
|
|
598
|
-
if (!rootResult.success && !releaseBlockedTransport) {
|
|
599
|
-
stateTransitions.push('backoff');
|
|
600
|
-
return driverResult({
|
|
601
|
-
status: 'backoff',
|
|
602
|
-
receiptStatus: 'deferred',
|
|
603
|
-
reasonCode: HEADLESS_REASON_CODES.EXECUTION_FAILED,
|
|
604
|
-
publicSummary: 'Headless yoloop root metadata invocation failed with bounded public evidence.',
|
|
605
|
-
retryable: true,
|
|
606
|
-
startedAt,
|
|
607
|
-
counts: aggregateCounts(iterations, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
608
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
609
|
-
hashes,
|
|
610
|
-
redactions,
|
|
611
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
612
|
-
childStoryIds,
|
|
613
|
-
stateTransitions,
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
const terminal = classifyYoloopTerminalMetadata(metadata);
|
|
617
|
-
if (!terminal.ok) {
|
|
618
|
-
stateTransitions.push('backoff');
|
|
619
|
-
return driverResult({
|
|
620
|
-
status: 'failed',
|
|
621
|
-
receiptStatus: 'failed',
|
|
622
|
-
reasonCode: terminal.reasonCode,
|
|
623
|
-
publicSummary: terminal.publicSummary,
|
|
624
|
-
retryable: false,
|
|
625
|
-
startedAt,
|
|
626
|
-
counts: aggregateCounts(iterations, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
627
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
628
|
-
hashes,
|
|
629
|
-
redactions: [...redactions, ...terminal.redactionSummary],
|
|
630
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
631
|
-
childStoryIds,
|
|
632
|
-
stateTransitions,
|
|
633
|
-
});
|
|
634
|
-
}
|
|
635
|
-
const resumableBoundary = extractResumableExhaustionBoundary(metadata);
|
|
636
|
-
if (terminal.aborted && resumableBoundary) {
|
|
637
|
-
while (continuousInFlight.size > 0)
|
|
638
|
-
await settleOneContinuousChild();
|
|
639
|
-
metadataAbortedCount += 1;
|
|
640
|
-
stateTransitions.push('backoff');
|
|
641
|
-
return driverResult({
|
|
642
|
-
status: 'backoff',
|
|
643
|
-
receiptStatus: 'deferred',
|
|
644
|
-
reasonCode: resumableBoundary.reason === 'YOLOOP_SESSION_TIMEOUT'
|
|
645
|
-
? 'yoloop-session-timeout-resumable'
|
|
646
|
-
: 'yoloop-per-run-cap-resumable',
|
|
647
|
-
publicSummary: 'Headless yoloop reached a finite run boundary and scheduled the same queue after cool-down.',
|
|
648
|
-
retryable: true,
|
|
649
|
-
retryNotBeforeAt: resumableBoundary.coolDownUntil,
|
|
650
|
-
startedAt,
|
|
651
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
652
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
653
|
-
hashes,
|
|
654
|
-
redactions,
|
|
655
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
656
|
-
childStoryIds,
|
|
657
|
-
stateTransitions,
|
|
658
|
-
});
|
|
659
|
-
}
|
|
660
|
-
if ((terminal.releaseBlocked || terminal.aborted || terminal.complete || terminal.replay || (terminal.outcome && terminal.outcome !== 'selected' && terminal.outcome !== 'queue_exhausted'))
|
|
661
|
-
&& continuousModeObserved && continuousInFlight.size > 0) {
|
|
662
|
-
await settleOneContinuousChild();
|
|
663
|
-
iterations += 1;
|
|
664
|
-
stateTransitions.push('reinvoke');
|
|
665
|
-
continue;
|
|
666
|
-
}
|
|
667
|
-
if (terminal.releaseBlocked) {
|
|
668
|
-
stateTransitions.push('release_blocked');
|
|
669
|
-
return driverResult({
|
|
670
|
-
status: 'failed',
|
|
671
|
-
receiptStatus: 'failed',
|
|
672
|
-
reasonCode: 'yoloop-release-blocked',
|
|
673
|
-
publicSummary: 'Headless yoloop stopped at a terminal release-blocked boundary without declaring success.',
|
|
674
|
-
retryable: false,
|
|
675
|
-
startedAt,
|
|
676
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
677
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
678
|
-
hashes: { ...hashes, releaseBlocked: hashPublicValue(terminal.releaseBlocked.resultId) },
|
|
679
|
-
redactions,
|
|
680
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
681
|
-
childStoryIds,
|
|
682
|
-
stateTransitions,
|
|
683
|
-
terminalClass: 'release-blocked',
|
|
684
|
-
releaseBlocked: terminal.releaseBlocked,
|
|
685
|
-
});
|
|
686
|
-
}
|
|
687
|
-
const epicIntegration = isRecord(metadata?.epicIntegration) ? metadata.epicIntegration : undefined;
|
|
688
|
-
const integrationReasonCodes = Array.isArray(epicIntegration?.reasonCodes)
|
|
689
|
-
? epicIntegration.reasonCodes.filter((value) => typeof value === 'string')
|
|
690
|
-
: [];
|
|
691
|
-
const lifecycleEvidenceCanRepair = terminal.aborted
|
|
692
|
-
&& metadata?.abortReason === 'epic-integration-checkpoints-incomplete'
|
|
693
|
-
&& epicIntegration?.required === true
|
|
694
|
-
&& epicIntegration.ready === false
|
|
695
|
-
&& integrationReasonCodes.length > 0
|
|
696
|
-
&& integrationReasonCodes.every((reasonCode) => reasonCode === 'epic-aggregate-qa-receipt-required'
|
|
697
|
-
|| reasonCode === 'epic-origin-binding-required');
|
|
698
|
-
// P223 release admission has already completed for this root invocation.
|
|
699
|
-
// Only now may the client produce the physical aggregate/origin evidence
|
|
700
|
-
// needed for the server to emit the terminal Git directive. This avoids a
|
|
701
|
-
// release-blocked request causing Git effects while preserving the
|
|
702
|
-
// pre-P223 terminal-integration convergence path.
|
|
703
|
-
if (lifecycleEvidenceCanRepair && input.terminalGitAdapter.prepareLifecycleEvidence) {
|
|
704
|
-
stateTransitions.push('lifecycle_evidence');
|
|
705
|
-
const evidence = await input.terminalGitAdapter.prepareLifecycleEvidence({
|
|
706
|
-
epicId: input.prepared.epicId,
|
|
707
|
-
nowIso: input.now(),
|
|
708
|
-
});
|
|
709
|
-
if (!evidence.ok) {
|
|
710
|
-
stateTransitions.push('backoff');
|
|
711
|
-
return driverResult({
|
|
712
|
-
status: evidence.retryEligible ? 'backoff' : 'failed',
|
|
713
|
-
receiptStatus: evidence.retryEligible ? 'deferred' : 'failed',
|
|
714
|
-
reasonCode: evidence.reasonCode,
|
|
715
|
-
publicSummary: 'Headless yoloop stopped because physical Git lifecycle evidence could not be produced safely.',
|
|
716
|
-
retryable: evidence.retryEligible,
|
|
717
|
-
startedAt,
|
|
718
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
719
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
720
|
-
hashes,
|
|
721
|
-
redactions,
|
|
722
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
723
|
-
childStoryIds,
|
|
724
|
-
stateTransitions,
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
terminalP205Authority = evidence.p205Authority;
|
|
728
|
-
lifecycleEvidencePrepared = true;
|
|
729
|
-
iterations += 1;
|
|
730
|
-
stateTransitions.push('reinvoke');
|
|
731
|
-
continue;
|
|
732
|
-
}
|
|
733
|
-
if (terminal.aborted) {
|
|
734
|
-
metadataAbortedCount += 1;
|
|
735
|
-
stateTransitions.push('aborted');
|
|
736
|
-
return driverResult({
|
|
737
|
-
status: 'failed',
|
|
738
|
-
receiptStatus: 'failed',
|
|
739
|
-
reasonCode: JOB_ABORTED_REASON_CODE,
|
|
740
|
-
publicSummary: 'Headless yoloop stopped because public metadata reported an aborted loop.',
|
|
741
|
-
retryable: false,
|
|
742
|
-
startedAt,
|
|
743
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
744
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
745
|
-
hashes,
|
|
746
|
-
redactions,
|
|
747
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
748
|
-
childStoryIds,
|
|
749
|
-
stateTransitions,
|
|
750
|
-
});
|
|
751
|
-
}
|
|
752
|
-
if (terminal.outcome && terminal.outcome !== 'selected' && terminal.outcome !== 'queue_exhausted') {
|
|
753
|
-
stateTransitions.push('backoff');
|
|
754
|
-
return driverResult({
|
|
755
|
-
status: 'failed', receiptStatus: 'failed', reasonCode: `yoloop-${terminal.outcome}`,
|
|
756
|
-
publicSummary: 'Headless yoloop stopped on a non-executable graph-first continuation outcome.',
|
|
757
|
-
retryable: false, startedAt,
|
|
758
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
759
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool), hashes, redactions,
|
|
760
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs], childStoryIds, stateTransitions,
|
|
761
|
-
});
|
|
762
|
-
}
|
|
763
|
-
if (terminal.replay) {
|
|
764
|
-
stateTransitions.push('backoff');
|
|
765
|
-
return driverResult({
|
|
766
|
-
status: 'backoff', receiptStatus: 'deferred', reasonCode: 'yoloop-replay-pending',
|
|
767
|
-
publicSummary: 'Headless yoloop observed pending replay authority and did not delegate a second child.',
|
|
768
|
-
retryable: true, startedAt,
|
|
769
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
770
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool), hashes, redactions,
|
|
771
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs], childStoryIds, stateTransitions,
|
|
772
|
-
});
|
|
773
|
-
}
|
|
774
|
-
if (terminal.complete && continuousModeObserved
|
|
775
|
-
&& continuousDeferredReasons.size > 0 && continuousFailureReasons.size === 0) {
|
|
776
|
-
stateTransitions.push('backoff');
|
|
777
|
-
return driverResult({
|
|
778
|
-
status: 'backoff', receiptStatus: 'deferred',
|
|
779
|
-
reasonCode: [...continuousDeferredReasons.values()].sort()[0],
|
|
780
|
-
publicSummary: 'Headless yoloop rejected terminal completion while previously runnable work remained undispatched.',
|
|
781
|
-
retryable: true, startedAt,
|
|
782
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
783
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool), hashes, redactions,
|
|
784
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs], childStoryIds, stateTransitions,
|
|
785
|
-
});
|
|
786
|
-
}
|
|
787
|
-
if (terminal.complete && continuousModeObserved && continuousFailureReasons.size > 0) {
|
|
788
|
-
stateTransitions.push('backoff');
|
|
789
|
-
return driverResult({
|
|
790
|
-
status: 'failed', receiptStatus: 'failed',
|
|
791
|
-
reasonCode: [...continuousFailureReasons.values()].sort()[0],
|
|
792
|
-
publicSummary: 'Headless yoloop rejected terminal completion because runnable work failed before an accepted dispatch receipt.',
|
|
793
|
-
retryable: false, startedAt,
|
|
794
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
795
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool), hashes, redactions,
|
|
796
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs], childStoryIds, stateTransitions,
|
|
797
|
-
});
|
|
798
|
-
}
|
|
799
|
-
// A terminal response can truthfully report queue exhaustion while also
|
|
800
|
-
// carrying the still-required physical Git integration directive. The
|
|
801
|
-
// effect must run before accepting yoloopComplete; the persisted receipt
|
|
802
|
-
// makes the next invocation converge to terminal success.
|
|
803
|
-
const terminalGitDirective = extractEpicTerminalGitDirective(metadata);
|
|
804
|
-
if (terminalGitDirective) {
|
|
805
|
-
if (!lifecycleEvidencePrepared && input.terminalGitAdapter.prepareLifecycleEvidence) {
|
|
806
|
-
stateTransitions.push('lifecycle_evidence');
|
|
807
|
-
const evidence = await input.terminalGitAdapter.prepareLifecycleEvidence({
|
|
808
|
-
epicId: input.prepared.epicId,
|
|
809
|
-
nowIso: input.now(),
|
|
810
|
-
});
|
|
811
|
-
if (!evidence.ok) {
|
|
812
|
-
stateTransitions.push('backoff');
|
|
813
|
-
return driverResult({
|
|
814
|
-
status: evidence.retryEligible ? 'backoff' : 'failed',
|
|
815
|
-
receiptStatus: evidence.retryEligible ? 'deferred' : 'failed',
|
|
816
|
-
reasonCode: evidence.reasonCode,
|
|
817
|
-
publicSummary: 'Headless yoloop stopped because physical Git lifecycle evidence could not be produced safely.',
|
|
818
|
-
retryable: evidence.retryEligible,
|
|
819
|
-
startedAt,
|
|
820
|
-
counts: aggregateCounts(iterations, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
821
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
822
|
-
hashes,
|
|
823
|
-
redactions,
|
|
824
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
825
|
-
childStoryIds,
|
|
826
|
-
stateTransitions,
|
|
827
|
-
});
|
|
828
|
-
}
|
|
829
|
-
terminalP205Authority = evidence.p205Authority;
|
|
830
|
-
lifecycleEvidencePrepared = true;
|
|
831
|
-
}
|
|
832
|
-
stateTransitions.push('terminal_git');
|
|
833
|
-
const lockStartedAt = new Date();
|
|
834
|
-
const physicalLock = await acquireGitLifecyclePhysicalIntegrationLock(input.projectRoot, {
|
|
835
|
-
kind: 'continuous', storyId: terminalGitDirective.epicId,
|
|
836
|
-
sessionId: `${input.runnerId}:${input.attempt.attempt_id}`,
|
|
837
|
-
idempotencyKey: terminalGitDirective.idempotencyKey,
|
|
838
|
-
persistent: false,
|
|
839
|
-
expiresAt: new Date(lockStartedAt.getTime() + Math.max(input.timeoutMs, input.maxDurationMs) + 60_000).toISOString(),
|
|
840
|
-
});
|
|
841
|
-
if (!physicalLock.ok) {
|
|
842
|
-
stateTransitions.push('backoff');
|
|
843
|
-
return driverResult({
|
|
844
|
-
status: 'backoff', receiptStatus: 'deferred', reasonCode: physicalLock.reasonCode,
|
|
845
|
-
publicSummary: 'Headless yoloop deferred terminal Git while another physical writer retained authority.',
|
|
846
|
-
retryable: true, startedAt,
|
|
847
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
848
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool), hashes, redactions,
|
|
849
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs], childStoryIds, stateTransitions,
|
|
850
|
-
});
|
|
851
|
-
}
|
|
852
|
-
let integration;
|
|
853
|
-
let released = false;
|
|
854
|
-
try {
|
|
855
|
-
integration = await executeEpicTerminalGit(terminalGitDirective, input.terminalGitAdapter, input.now, terminalP205Authority);
|
|
856
|
-
}
|
|
857
|
-
finally {
|
|
858
|
-
released = await releaseGitLifecyclePhysicalIntegrationLock(physicalLock.path, physicalLock.owner)
|
|
859
|
-
.catch(() => false);
|
|
860
|
-
}
|
|
861
|
-
if (!released) {
|
|
862
|
-
stateTransitions.push('backoff');
|
|
863
|
-
return driverResult({
|
|
864
|
-
status: 'backoff', receiptStatus: 'deferred', reasonCode: 'git-lifecycle-integration-lock-release-failed',
|
|
865
|
-
publicSummary: 'Headless yoloop stopped because terminal Git writer ownership could not be released safely.',
|
|
866
|
-
retryable: true, startedAt,
|
|
867
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
868
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool), hashes, redactions,
|
|
869
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs], childStoryIds, stateTransitions,
|
|
870
|
-
});
|
|
871
|
-
}
|
|
872
|
-
hashes[`terminal-git-${iterations}`] = hashPublicValue(`${integration.receipt.idempotencyKey}:${integration.receipt.physicalStatus}`);
|
|
873
|
-
if (!integration.ok) {
|
|
874
|
-
const retryable = integration.receipt.retryEligible;
|
|
875
|
-
stateTransitions.push('backoff');
|
|
876
|
-
return driverResult({
|
|
877
|
-
status: retryable ? 'backoff' : 'failed',
|
|
878
|
-
receiptStatus: retryable ? 'deferred' : 'failed',
|
|
879
|
-
reasonCode: integration.reasonCodes[0] ?? 'epic-terminal-git-failed',
|
|
880
|
-
publicSummary: 'Headless yoloop stopped at the epic terminal Git boundary with public-safe retry evidence.',
|
|
881
|
-
retryable,
|
|
882
|
-
startedAt,
|
|
883
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
884
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool), hashes, redactions,
|
|
885
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs], childStoryIds, stateTransitions,
|
|
886
|
-
});
|
|
887
|
-
}
|
|
888
|
-
// A persisted pushed receipt may let the server render queue exhaustion,
|
|
889
|
-
// but it never lets the root accept completion without this invocation's
|
|
890
|
-
// fresh physical ancestry/provider verification. The same directive is
|
|
891
|
-
// therefore emitted on replay and this successful verification is the
|
|
892
|
-
// terminal authority for the current root run.
|
|
893
|
-
if (terminal.complete) {
|
|
894
|
-
metadataCompleteCount += 1;
|
|
895
|
-
stateTransitions.push('complete');
|
|
896
|
-
return driverResult({
|
|
897
|
-
status: 'completed', receiptStatus: 'applied',
|
|
898
|
-
reasonCode: HEADLESS_REASON_CODES.EXECUTION_COMPLETED,
|
|
899
|
-
publicSummary: 'Headless yoloop completed only after fresh root-owned physical Git verification.',
|
|
900
|
-
retryable: false, startedAt,
|
|
901
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
902
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool), hashes, redactions,
|
|
903
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs], childStoryIds, stateTransitions,
|
|
904
|
-
});
|
|
905
|
-
}
|
|
906
|
-
iterations += 1;
|
|
907
|
-
stateTransitions.push('reinvoke');
|
|
908
|
-
continue;
|
|
909
|
-
}
|
|
910
|
-
if (terminal.complete) {
|
|
911
|
-
metadataCompleteCount += 1;
|
|
912
|
-
stateTransitions.push('complete');
|
|
913
|
-
return driverResult({
|
|
914
|
-
status: 'completed',
|
|
915
|
-
receiptStatus: 'applied',
|
|
916
|
-
reasonCode: HEADLESS_REASON_CODES.EXECUTION_COMPLETED,
|
|
917
|
-
publicSummary: 'Headless yoloop completed after public metadata reported yoloopComplete.',
|
|
918
|
-
retryable: false,
|
|
919
|
-
startedAt,
|
|
920
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
921
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
922
|
-
hashes,
|
|
923
|
-
redactions,
|
|
924
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
925
|
-
childStoryIds,
|
|
926
|
-
stateTransitions,
|
|
927
|
-
});
|
|
928
|
-
}
|
|
929
|
-
const reconciliationDirective = extractEpicGitReconciliationDirective(metadata);
|
|
930
|
-
if (reconciliationDirective) {
|
|
931
|
-
stateTransitions.push('git_reconciliation');
|
|
932
|
-
const reconciliation = await executeEpicGitReconciliation(reconciliationDirective, input.terminalGitAdapter, input.now);
|
|
933
|
-
hashes[`git-reconciliation-${iterations}`] = hashPublicValue(`${reconciliationDirective.idempotencyKey}:${reconciliation.reasonCodes.join(',')}`);
|
|
934
|
-
if (!reconciliation.ok) {
|
|
935
|
-
stateTransitions.push('backoff');
|
|
936
|
-
return driverResult({
|
|
937
|
-
status: 'backoff', receiptStatus: 'deferred',
|
|
938
|
-
reasonCode: reconciliation.reasonCodes[0] ?? 'git-reconciliation-failed',
|
|
939
|
-
publicSummary: 'Headless yoloop paused at a fail-closed Git reconciliation boundary.',
|
|
940
|
-
retryable: true, startedAt,
|
|
941
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
942
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool), hashes, redactions,
|
|
943
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs], childStoryIds, stateTransitions,
|
|
944
|
-
});
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
const extraction = extractAuthorizedChildPrompts(metadata, input.prepared.epicId);
|
|
948
|
-
if (!extraction.ok) {
|
|
949
|
-
stateTransitions.push('backoff');
|
|
950
|
-
return driverResult({
|
|
951
|
-
status: 'failed',
|
|
952
|
-
receiptStatus: 'failed',
|
|
953
|
-
reasonCode: extraction.reasonCode,
|
|
954
|
-
publicSummary: extraction.publicSummary,
|
|
955
|
-
retryable: false,
|
|
956
|
-
startedAt,
|
|
957
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
958
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
959
|
-
hashes,
|
|
960
|
-
redactions: [...redactions, ...extraction.redactionSummary],
|
|
961
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
962
|
-
childStoryIds,
|
|
963
|
-
stateTransitions,
|
|
964
|
-
});
|
|
965
|
-
}
|
|
966
|
-
const repeatedChild = extraction.continuous
|
|
967
|
-
? undefined
|
|
968
|
-
: extraction.prompts.find((child) => processedStoryIds.has(child.storyId));
|
|
969
|
-
if (repeatedChild) {
|
|
970
|
-
stateTransitions.push('backoff');
|
|
971
|
-
return driverResult({
|
|
972
|
-
status: 'failed',
|
|
973
|
-
receiptStatus: 'failed',
|
|
974
|
-
reasonCode: HEADLESS_REASON_CODES.YOLOOP_ISOLATION_VIOLATION,
|
|
975
|
-
publicSummary: 'Headless yoloop rejected cyclic child story delegation evidence.',
|
|
976
|
-
retryable: false,
|
|
977
|
-
startedAt,
|
|
978
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
979
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
980
|
-
hashes,
|
|
981
|
-
redactions: [...redactions, redaction('storyId', 'prompt_body', hashPublicValue(repeatedChild.storyId))],
|
|
982
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
983
|
-
childStoryIds,
|
|
984
|
-
stateTransitions,
|
|
985
|
-
});
|
|
986
|
-
}
|
|
987
|
-
workerPool.mode = extraction.mode === 'continuous_dag'
|
|
988
|
-
? 'continuous_dag'
|
|
989
|
-
: extraction.parallelAuthorized ? 'parallel_wave' : 'serial';
|
|
990
|
-
workerPool.serverMaxConcurrency = extraction.serverMaxConcurrency;
|
|
991
|
-
if (extraction.continuous) {
|
|
992
|
-
continuousModeObserved = true;
|
|
993
|
-
const eligible = extraction.prompts.filter((child) => !processedStoryIds.has(child.storyId) && !continuousInFlight.has(child.storyId));
|
|
994
|
-
workerPool.pendingChildCount = eligible.length + continuousInFlight.size;
|
|
995
|
-
if (eligible.length > 0) {
|
|
996
|
-
const capacity = resolveWorkerPoolCapacity({
|
|
997
|
-
store: input.store,
|
|
998
|
-
nowIso: input.now(),
|
|
999
|
-
localCap: input.localConcurrencyCap,
|
|
1000
|
-
serverMaxConcurrency: extraction.serverMaxConcurrency,
|
|
1001
|
-
parallelAuthorized: true,
|
|
1002
|
-
continuous: true,
|
|
1003
|
-
eligibleCount: eligible.length,
|
|
1004
|
-
});
|
|
1005
|
-
workerPool.queueCap = capacity.queueCap;
|
|
1006
|
-
workerPool.availableLeases = capacity.availableLeases;
|
|
1007
|
-
workerPool.effectiveConcurrency = capacity.effectiveConcurrency;
|
|
1008
|
-
workerPool.reasonCodes.push(capacity.reasonCode);
|
|
1009
|
-
if (capacity.effectiveConcurrency === 0 && continuousInFlight.size === 0) {
|
|
1010
|
-
workerPool.backpressurePauseCount += 1;
|
|
1011
|
-
stateTransitions.push('backoff');
|
|
1012
|
-
return driverResult({
|
|
1013
|
-
status: 'backoff', receiptStatus: 'deferred', reasonCode: HEADLESS_REASON_CODES.WORKER_POOL_BACKPRESSURE_PAUSED,
|
|
1014
|
-
publicSummary: 'Headless yoloop retained its eligible frontier while physical worker capacity was unavailable.',
|
|
1015
|
-
retryable: true, startedAt,
|
|
1016
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
1017
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool), hashes, redactions,
|
|
1018
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs], childStoryIds, stateTransitions,
|
|
1019
|
-
});
|
|
1020
|
-
}
|
|
1021
|
-
const launchable = eligible.slice(0, capacity.effectiveConcurrency);
|
|
1022
|
-
stateTransitions.push('child_story_delegation');
|
|
1023
|
-
for (const child of launchable) {
|
|
1024
|
-
continuousInFlight.set(child.storyId, {
|
|
1025
|
-
child,
|
|
1026
|
-
promise: executeYoloopChild({ ...input, child, iteration: iterations }),
|
|
1027
|
-
});
|
|
1028
|
-
}
|
|
1029
|
-
workerPool.startedChildCount += launchable.length;
|
|
1030
|
-
workerPool.peakConcurrency = Math.max(workerPool.peakConcurrency, continuousInFlight.size);
|
|
1031
|
-
workerPool.pendingChildCount = eligible.length - launchable.length + continuousInFlight.size;
|
|
1032
|
-
}
|
|
1033
|
-
if (continuousInFlight.size > 0) {
|
|
1034
|
-
await settleOneContinuousChild();
|
|
1035
|
-
}
|
|
1036
|
-
else if (continuousDeferredReasons.size > 0) {
|
|
1037
|
-
stateTransitions.push('backoff');
|
|
1038
|
-
return driverResult({
|
|
1039
|
-
status: 'backoff', receiptStatus: 'deferred', reasonCode: [...continuousDeferredReasons.values()].sort()[0],
|
|
1040
|
-
publicSummary: 'Headless yoloop retained deferred continuous work for a bounded retry.',
|
|
1041
|
-
retryable: true, startedAt,
|
|
1042
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
1043
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool), hashes, redactions,
|
|
1044
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs], childStoryIds, stateTransitions,
|
|
1045
|
-
});
|
|
1046
|
-
}
|
|
1047
|
-
else if (continuousFailureReasons.size > 0) {
|
|
1048
|
-
stateTransitions.push('backoff');
|
|
1049
|
-
return driverResult({
|
|
1050
|
-
status: 'failed', receiptStatus: 'failed', reasonCode: [...continuousFailureReasons.values()].sort()[0],
|
|
1051
|
-
publicSummary: 'Headless yoloop completed independent work and stopped on the remaining failed dependency closure.',
|
|
1052
|
-
retryable: false, startedAt,
|
|
1053
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
1054
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool), hashes, redactions,
|
|
1055
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs], childStoryIds, stateTransitions,
|
|
1056
|
-
});
|
|
1057
|
-
}
|
|
1058
|
-
iterations += 1;
|
|
1059
|
-
stateTransitions.push('reinvoke');
|
|
1060
|
-
continue;
|
|
1061
|
-
}
|
|
1062
|
-
workerPool.pendingChildCount = extraction.prompts.length;
|
|
1063
|
-
const pending = [...extraction.prompts];
|
|
1064
|
-
while (pending.length > 0) {
|
|
1065
|
-
const capacity = resolveWorkerPoolCapacity({
|
|
1066
|
-
store: input.store,
|
|
1067
|
-
nowIso: input.now(),
|
|
1068
|
-
localCap: input.localConcurrencyCap,
|
|
1069
|
-
serverMaxConcurrency: extraction.serverMaxConcurrency,
|
|
1070
|
-
parallelAuthorized: extraction.parallelAuthorized,
|
|
1071
|
-
continuous: false,
|
|
1072
|
-
eligibleCount: pending.length,
|
|
1073
|
-
});
|
|
1074
|
-
workerPool.queueCap = capacity.queueCap;
|
|
1075
|
-
workerPool.availableLeases = capacity.availableLeases;
|
|
1076
|
-
workerPool.effectiveConcurrency = capacity.effectiveConcurrency;
|
|
1077
|
-
workerPool.reasonCodes.push(capacity.reasonCode);
|
|
1078
|
-
if (capacity.effectiveConcurrency === 0) {
|
|
1079
|
-
workerPool.backpressurePauseCount += 1;
|
|
1080
|
-
workerPool.pendingChildCount = pending.length;
|
|
1081
|
-
stateTransitions.push('backoff');
|
|
1082
|
-
return driverResult({
|
|
1083
|
-
status: 'backoff',
|
|
1084
|
-
receiptStatus: 'deferred',
|
|
1085
|
-
reasonCode: HEADLESS_REASON_CODES.WORKER_POOL_BACKPRESSURE_PAUSED,
|
|
1086
|
-
publicSummary: 'Headless yoloop paused child workers because bounded queue or lease capacity was unavailable.',
|
|
1087
|
-
retryable: true,
|
|
1088
|
-
startedAt,
|
|
1089
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
1090
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
1091
|
-
hashes,
|
|
1092
|
-
redactions,
|
|
1093
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
1094
|
-
childStoryIds,
|
|
1095
|
-
stateTransitions,
|
|
1096
|
-
});
|
|
1097
|
-
}
|
|
1098
|
-
const batch = pending.splice(0, capacity.effectiveConcurrency);
|
|
1099
|
-
workerPool.startedChildCount += batch.length;
|
|
1100
|
-
workerPool.peakConcurrency = Math.max(workerPool.peakConcurrency, batch.length);
|
|
1101
|
-
workerPool.pendingChildCount = pending.length;
|
|
1102
|
-
stateTransitions.push('child_story_delegation');
|
|
1103
|
-
const settled = await Promise.all(batch.map((child) => executeYoloopChild({
|
|
1104
|
-
...input,
|
|
1105
|
-
child,
|
|
1106
|
-
iteration: iterations,
|
|
1107
|
-
})));
|
|
1108
|
-
workerPool.completedChildCount += settled.length;
|
|
1109
|
-
let terminalChild;
|
|
1110
|
-
for (const result of settled) {
|
|
1111
|
-
const child = result.child;
|
|
1112
|
-
hashes[`child-${child.storyId.replace(/[^A-Za-z0-9_.:-]/g, '-')}`] = result.commandHash;
|
|
1113
|
-
redactions.push(result.promptRedaction);
|
|
1114
|
-
childStoryIds.push(child.storyId);
|
|
1115
|
-
childTargetRefs.push(child.targetRef);
|
|
1116
|
-
processedStoryIds.add(child.storyId);
|
|
1117
|
-
const receipt = result.receipt;
|
|
1118
|
-
if (!receipt) {
|
|
1119
|
-
if (result.reasonCodes.includes('queue-cap-reached')) {
|
|
1120
|
-
workerPool.backpressurePauseCount += 1;
|
|
1121
|
-
workerPool.pendingChildCount += 1;
|
|
1122
|
-
workerPool.reasonCodes.push(HEADLESS_REASON_CODES.WORKER_POOL_BACKPRESSURE_PAUSED);
|
|
1123
|
-
terminalChild ??= { kind: 'deferred', reasonCode: HEADLESS_REASON_CODES.WORKER_POOL_BACKPRESSURE_PAUSED };
|
|
1124
|
-
}
|
|
1125
|
-
else {
|
|
1126
|
-
failedChildCount += 1;
|
|
1127
|
-
terminalChild ??= { kind: 'missing', reasonCode: HEADLESS_REASON_CODES.EXECUTION_FAILED };
|
|
1128
|
-
}
|
|
1129
|
-
continue;
|
|
1130
|
-
}
|
|
1131
|
-
if (receipt.outcome === 'deferred') {
|
|
1132
|
-
terminalChild ??= { kind: 'deferred', reasonCode: HEADLESS_REASON_CODES.EXECUTION_BACKOFF };
|
|
1133
|
-
continue;
|
|
1134
|
-
}
|
|
1135
|
-
if (receipt.outcome === 'failed') {
|
|
1136
|
-
failedChildCount += 1;
|
|
1137
|
-
terminalChild ??= { kind: 'failed', reasonCode: receipt.reasonCode || HEADLESS_REASON_CODES.EXECUTION_FAILED };
|
|
1138
|
-
continue;
|
|
1139
|
-
}
|
|
1140
|
-
if (receipt.outcome === 'ignored')
|
|
1141
|
-
skippedChildCount += 1;
|
|
1142
|
-
else
|
|
1143
|
-
succeededChildCount += 1;
|
|
1144
|
-
}
|
|
1145
|
-
if (terminalChild) {
|
|
1146
|
-
const deferred = terminalChild.kind === 'deferred';
|
|
1147
|
-
return driverResult({
|
|
1148
|
-
status: deferred ? 'backoff' : 'failed',
|
|
1149
|
-
receiptStatus: deferred ? 'deferred' : 'failed',
|
|
1150
|
-
reasonCode: terminalChild.reasonCode,
|
|
1151
|
-
publicSummary: terminalChild.kind === 'missing'
|
|
1152
|
-
? 'Headless yoloop child story delegation did not produce a public receipt.'
|
|
1153
|
-
: deferred
|
|
1154
|
-
? 'Headless yoloop child story delegated bounded backoff to the root attempt.'
|
|
1155
|
-
: 'Headless yoloop child story execution failed with public receipt evidence.',
|
|
1156
|
-
retryable: deferred,
|
|
1157
|
-
startedAt,
|
|
1158
|
-
counts: aggregateCounts(iterations + 1, childStoryIds.length, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount),
|
|
1159
|
-
workerPoolSummary: publicWorkerPoolSummary(workerPool),
|
|
1160
|
-
hashes,
|
|
1161
|
-
redactions,
|
|
1162
|
-
relativePaths: [input.prepared.targetRef, ...childTargetRefs],
|
|
1163
|
-
childStoryIds,
|
|
1164
|
-
stateTransitions,
|
|
1165
|
-
});
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
iterations += 1;
|
|
1169
|
-
stateTransitions.push('reinvoke');
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
async function executeYoloopChild(input) {
|
|
1173
|
-
const workspace = input.child.dispatchId
|
|
1174
|
-
? await input.continuousWorkspaceManager.prepare({
|
|
1175
|
-
projectRoot: input.projectRoot,
|
|
1176
|
-
epicId: input.prepared.epicId,
|
|
1177
|
-
storyId: input.child.storyId,
|
|
1178
|
-
targetRef: input.child.targetRef,
|
|
1179
|
-
dispatchId: input.child.dispatchId,
|
|
1180
|
-
executionBranch: input.child.executionBranch ?? '',
|
|
1181
|
-
graphRevision: input.child.graphRevision ?? '',
|
|
1182
|
-
authorizedWriteSet: input.child.writeSet ?? [],
|
|
1183
|
-
})
|
|
1184
|
-
: undefined;
|
|
1185
|
-
if (workspace && !workspace.ok) {
|
|
1186
|
-
return {
|
|
1187
|
-
child: input.child,
|
|
1188
|
-
reasonCodes: [workspace.reasonCode],
|
|
1189
|
-
commandHash: hashPublicValue(input.child.commandRef),
|
|
1190
|
-
promptRedaction: redaction(`child.${input.child.storyId}`, 'prompt_body', hashPublicValue(input.child.commandRef)),
|
|
1191
|
-
terminalFailure: workspace.reasonCode,
|
|
1192
|
-
deferredFailure: /backpressure|lease-active/.test(workspace.reasonCode),
|
|
1193
|
-
};
|
|
1194
|
-
}
|
|
1195
|
-
const childProjectRoot = input.projectRoot;
|
|
1196
|
-
const childCommandRunner = workspace?.ok
|
|
1197
|
-
? createAnchoredContinuousStoryCommandRunner(workspace.value)
|
|
1198
|
-
: input.adapterOptions?.commandRunner;
|
|
1199
|
-
const childDirective = buildChildRunYoloDirective({
|
|
1200
|
-
rootAttempt: input.attempt,
|
|
1201
|
-
child: input.child,
|
|
1202
|
-
iteration: input.iteration,
|
|
1203
|
-
runtimeId: input.prepared.runtimeId,
|
|
1204
|
-
modelId: input.prepared.modelId,
|
|
1205
|
-
runtimeSource: input.prepared.runtimeSource,
|
|
1206
|
-
});
|
|
1207
|
-
const childAttemptId = headlessExecutionEntityId('attempt', childDirective.idempotencyKey);
|
|
1208
|
-
let preserveWorkspace = Boolean(workspace);
|
|
1209
|
-
try {
|
|
1210
|
-
const childResult = await runYoloExecutionPhase({
|
|
1211
|
-
store: input.store,
|
|
1212
|
-
projectRoot: childProjectRoot,
|
|
1213
|
-
runnerId: input.runnerId,
|
|
1214
|
-
now: input.now,
|
|
1215
|
-
metadata: { continuityExecutionDirectives: [childDirective] },
|
|
1216
|
-
adapterRegistry: input.registry,
|
|
1217
|
-
adapterOptions: {
|
|
1218
|
-
...input.adapterOptions,
|
|
1219
|
-
cwd: childProjectRoot,
|
|
1220
|
-
env: {
|
|
1221
|
-
...input.adapterOptions?.env,
|
|
1222
|
-
...(workspace?.ok ? {
|
|
1223
|
-
NEOCORTEX_BRANCHLESS_PROJECT_ROOT: workspace.value.workspacePath,
|
|
1224
|
-
NEOCORTEX_BRANCHLESS_ROOT_AUTHORITY: JSON.stringify(input.child.rootAuthority),
|
|
1225
|
-
} : {}),
|
|
1226
|
-
},
|
|
1227
|
-
...(childCommandRunner ? { commandRunner: childCommandRunner, versionRunner: childCommandRunner } : {}),
|
|
1228
|
-
},
|
|
1229
|
-
runtimeDefaults: input.runtimeDefaults,
|
|
1230
|
-
runtimeFallback: input.runtimeFallback,
|
|
1231
|
-
timeoutMs: input.timeoutMs,
|
|
1232
|
-
maxAttempts: 1,
|
|
1233
|
-
limit: 1,
|
|
1234
|
-
queueCap: input.queueCap,
|
|
1235
|
-
attemptIds: [childAttemptId],
|
|
1236
|
-
idFactory: input.idFactory,
|
|
1237
|
-
});
|
|
1238
|
-
const receipt = childResult.receipts.find((item) => item.attemptId === childAttemptId) ?? childResult.receipts[0];
|
|
1239
|
-
if (workspace?.ok && receipt && receipt.outcome !== 'failed' && receipt.outcome !== 'deferred') {
|
|
1240
|
-
const integration = await input.continuousWorkspaceManager.integrate(workspace.value, {
|
|
1241
|
-
receiptRefs: [`continuity:${receipt.attemptId}`],
|
|
1242
|
-
nowIso: receipt.timestamp,
|
|
1243
|
-
});
|
|
1244
|
-
if (!integration.ok) {
|
|
1245
|
-
return {
|
|
1246
|
-
child: input.child,
|
|
1247
|
-
receipt,
|
|
1248
|
-
reasonCodes: [...childResult.reasonCodes, integration.reasonCode],
|
|
1249
|
-
commandHash: hashPublicValue(input.child.commandRef),
|
|
1250
|
-
promptRedaction: redaction(`child.${input.child.storyId}`, 'prompt_body', hashPublicValue(input.child.commandRef)),
|
|
1251
|
-
terminalFailure: integration.reasonCode,
|
|
1252
|
-
deferredFailure: /backpressure|graph-revision-stale/.test(integration.reasonCode),
|
|
1253
|
-
};
|
|
1254
|
-
}
|
|
1255
|
-
preserveWorkspace = false;
|
|
1256
|
-
}
|
|
1257
|
-
return {
|
|
1258
|
-
child: input.child,
|
|
1259
|
-
receipt,
|
|
1260
|
-
reasonCodes: childResult.reasonCodes,
|
|
1261
|
-
commandHash: hashPublicValue(input.child.commandRef),
|
|
1262
|
-
promptRedaction: redaction(`child.${input.child.storyId}`, 'prompt_body', hashPublicValue(input.child.commandRef)),
|
|
1263
|
-
};
|
|
1264
|
-
}
|
|
1265
|
-
finally {
|
|
1266
|
-
if (workspace?.ok)
|
|
1267
|
-
await input.continuousWorkspaceManager.release(workspace.value, preserveWorkspace);
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
function resolveWorkerPoolCapacity(input) {
|
|
1271
|
-
const snapshot = input.store.collectSnapshotRows({
|
|
1272
|
-
nowIso: input.nowIso,
|
|
1273
|
-
jobLimit: 1,
|
|
1274
|
-
staleLeaseLimit: 1,
|
|
1275
|
-
receiptLimit: 1,
|
|
1276
|
-
eventLimit: 1,
|
|
1277
|
-
snapshotLimit: 1,
|
|
1278
|
-
});
|
|
1279
|
-
const queueCap = Math.max(1, Math.floor(snapshot.queue.capacity));
|
|
1280
|
-
// The current run_yoloop parent owns one active queue lease. Only other active
|
|
1281
|
-
// headless workers reduce the local child-lease budget.
|
|
1282
|
-
const activeOtherLeases = Math.max(0, Math.floor(snapshot.queue.running) - 1);
|
|
1283
|
-
const availableLeases = input.continuous
|
|
1284
|
-
? Math.max(0, Math.floor(snapshot.queue.available))
|
|
1285
|
-
: Math.max(0, Math.min(Math.max(0, input.localCap - activeOtherLeases), Math.floor(snapshot.queue.available)));
|
|
1286
|
-
const serverMaxConcurrency = input.parallelAuthorized
|
|
1287
|
-
? Math.max(1, Math.floor(input.serverMaxConcurrency))
|
|
1288
|
-
: 1;
|
|
1289
|
-
const effectiveConcurrency = Math.max(0, Math.min(input.eligibleCount, serverMaxConcurrency, input.localCap, queueCap, availableLeases));
|
|
1290
|
-
return {
|
|
1291
|
-
queueCap,
|
|
1292
|
-
availableLeases,
|
|
1293
|
-
effectiveConcurrency,
|
|
1294
|
-
reasonCode: effectiveConcurrency === 0
|
|
1295
|
-
? HEADLESS_REASON_CODES.WORKER_POOL_BACKPRESSURE_PAUSED
|
|
1296
|
-
: (input.parallelAuthorized || input.continuous) && effectiveConcurrency > 1
|
|
1297
|
-
? HEADLESS_REASON_CODES.WORKER_POOL_PARALLEL_ACTIVE
|
|
1298
|
-
: HEADLESS_REASON_CODES.WORKER_POOL_SERIAL_FALLBACK,
|
|
1299
|
-
};
|
|
1300
|
-
}
|
|
1301
|
-
function createMutableWorkerPoolSummary(localCap) {
|
|
1302
|
-
return {
|
|
1303
|
-
mode: 'serial',
|
|
1304
|
-
serverMaxConcurrency: 1,
|
|
1305
|
-
localCap,
|
|
1306
|
-
queueCap: 1,
|
|
1307
|
-
availableLeases: 1,
|
|
1308
|
-
effectiveConcurrency: 1,
|
|
1309
|
-
peakConcurrency: 0,
|
|
1310
|
-
pendingChildCount: 0,
|
|
1311
|
-
startedChildCount: 0,
|
|
1312
|
-
completedChildCount: 0,
|
|
1313
|
-
backpressurePauseCount: 0,
|
|
1314
|
-
reasonCodes: [],
|
|
1315
|
-
};
|
|
1316
|
-
}
|
|
1317
|
-
function publicWorkerPoolSummary(summary) {
|
|
1318
|
-
return {
|
|
1319
|
-
mode: summary.mode,
|
|
1320
|
-
serverMaxConcurrency: boundedCount(summary.serverMaxConcurrency),
|
|
1321
|
-
localCap: boundedCount(summary.localCap),
|
|
1322
|
-
queueCap: boundedCount(summary.queueCap),
|
|
1323
|
-
availableLeases: boundedCount(summary.availableLeases),
|
|
1324
|
-
effectiveConcurrency: boundedCount(summary.effectiveConcurrency),
|
|
1325
|
-
peakConcurrency: boundedCount(summary.peakConcurrency),
|
|
1326
|
-
pendingChildCount: boundedCount(summary.pendingChildCount),
|
|
1327
|
-
startedChildCount: boundedCount(summary.startedChildCount),
|
|
1328
|
-
completedChildCount: boundedCount(summary.completedChildCount),
|
|
1329
|
-
backpressurePauseCount: boundedCount(summary.backpressurePauseCount),
|
|
1330
|
-
reasonCodes: unique(summary.reasonCodes.length > 0
|
|
1331
|
-
? summary.reasonCodes
|
|
1332
|
-
: [HEADLESS_REASON_CODES.WORKER_POOL_SERIAL_FALLBACK]).slice(0, 10),
|
|
1333
|
-
publicSafe: true,
|
|
1334
|
-
};
|
|
1335
|
-
}
|
|
1336
|
-
function defaultWorkerPoolSummary(localCap = resolveDefaultHeadlessYoloopLocalConcurrencyCap()) {
|
|
1337
|
-
return publicWorkerPoolSummary(createMutableWorkerPoolSummary(localCap));
|
|
1338
|
-
}
|
|
1339
|
-
function boundedCount(value) {
|
|
1340
|
-
if (!Number.isFinite(value))
|
|
1341
|
-
return 0;
|
|
1342
|
-
return Math.max(0, Math.min(10_000, Math.floor(value)));
|
|
1343
|
-
}
|
|
1344
|
-
function prepareYoloopAttemptInput(input) {
|
|
1345
|
-
const governance = readAutonomousGovernanceEnvelopeFromMetadata(input.attempt.metadata_json, {
|
|
1346
|
-
autonomousKind: 'run_yoloop',
|
|
1347
|
-
jobId: input.attempt.job_id,
|
|
1348
|
-
targetKind: 'epic',
|
|
1349
|
-
targetRef: input.attempt.target_ref,
|
|
1350
|
-
});
|
|
1351
|
-
if (!governance.ok) {
|
|
1352
|
-
return {
|
|
1353
|
-
ok: false,
|
|
1354
|
-
status: 'failed',
|
|
1355
|
-
receiptStatus: 'failed',
|
|
1356
|
-
reasonCode: governance.reasonCode,
|
|
1357
|
-
publicSummary: governance.publicSummary,
|
|
1358
|
-
redactionSummary: governance.redactionSummary,
|
|
1359
|
-
};
|
|
1360
|
-
}
|
|
1361
|
-
const promptValidation = validateRunYoloopAttemptShape(input.attempt);
|
|
1362
|
-
if (!promptValidation.ok)
|
|
1363
|
-
return promptValidation;
|
|
1364
|
-
const runtime = resolveAttemptRuntime(input);
|
|
1365
|
-
if (!runtime.ok) {
|
|
1366
|
-
return {
|
|
1367
|
-
ok: false,
|
|
1368
|
-
status: 'failed',
|
|
1369
|
-
receiptStatus: 'failed',
|
|
1370
|
-
reasonCode: runtime.reasonCode,
|
|
1371
|
-
publicSummary: runtime.publicSummary,
|
|
1372
|
-
redactionSummary: runtime.redactionSummary,
|
|
1373
|
-
};
|
|
1374
|
-
}
|
|
1375
|
-
const epicId = input.attempt.epic_id ?? epicIdFromTargetRef(input.attempt.target_ref);
|
|
1376
|
-
return {
|
|
1377
|
-
ok: true,
|
|
1378
|
-
input: {
|
|
1379
|
-
rootPrompt: `*yoloop @${input.attempt.target_ref}`,
|
|
1380
|
-
targetRef: input.attempt.target_ref,
|
|
1381
|
-
epicId,
|
|
1382
|
-
runtimeId: runtime.runtimeId,
|
|
1383
|
-
...(runtime.modelId ? { modelId: runtime.modelId } : {}),
|
|
1384
|
-
runtimeSource: runtime.runtimeSource,
|
|
1385
|
-
publicSafe: true,
|
|
1386
|
-
},
|
|
1387
|
-
};
|
|
1388
|
-
}
|
|
1389
|
-
function validateRunYoloopAttemptShape(attempt) {
|
|
1390
|
-
const redactions = [];
|
|
1391
|
-
if (attempt.directive_kind !== 'run_yoloop')
|
|
1392
|
-
redactions.push(redaction('directiveKind', 'unsafe_key', 'value-denied'));
|
|
1393
|
-
if (attempt.target_kind !== 'epic')
|
|
1394
|
-
redactions.push(redaction('targetKind', 'prompt_body', 'value-denied'));
|
|
1395
|
-
if (!EPIC_TARGET_PATTERN.test(attempt.target_ref) || SHELL_FRAGMENT_PATTERN.test(attempt.target_ref) || UNSAFE_VALUE_PATTERN.test(attempt.target_ref)) {
|
|
1396
|
-
redactions.push(redaction('targetRef', 'prompt_body', 'value-denied'));
|
|
1397
|
-
}
|
|
1398
|
-
const epicId = epicIdFromTargetRef(attempt.target_ref);
|
|
1399
|
-
if (attempt.epic_id && attempt.epic_id !== epicId)
|
|
1400
|
-
redactions.push(redaction('epicId', 'prompt_body', 'value-denied'));
|
|
1401
|
-
if (redactions.length > 0) {
|
|
1402
|
-
return {
|
|
1403
|
-
ok: false,
|
|
1404
|
-
status: 'failed',
|
|
1405
|
-
receiptStatus: 'failed',
|
|
1406
|
-
reasonCode: HEADLESS_REASON_CODES.PROMPT_REJECTED,
|
|
1407
|
-
publicSummary: 'Headless run_yoloop attempt did not match the canonical public epic prompt shape.',
|
|
1408
|
-
redactionSummary: redactions,
|
|
1409
|
-
};
|
|
1410
|
-
}
|
|
1411
|
-
return {
|
|
1412
|
-
ok: true,
|
|
1413
|
-
input: {
|
|
1414
|
-
rootPrompt: `*yoloop @${attempt.target_ref}`,
|
|
1415
|
-
targetRef: attempt.target_ref,
|
|
1416
|
-
epicId,
|
|
1417
|
-
runtimeId: 'fake',
|
|
1418
|
-
publicSafe: true,
|
|
1419
|
-
},
|
|
1420
|
-
};
|
|
1421
|
-
}
|
|
1422
|
-
function resolveAttemptRuntime(input) {
|
|
1423
|
-
const defaults = input.runtimeDefaults !== undefined
|
|
1424
|
-
? input.runtimeDefaults
|
|
1425
|
-
: loadHeadlessRuntimeDefaults({ projectRoot: input.projectRoot });
|
|
1426
|
-
if (isRecord(defaults) && defaults.ok === false) {
|
|
1427
|
-
return {
|
|
1428
|
-
ok: false,
|
|
1429
|
-
reasonCode: HEADLESS_REASON_CODES.RUNTIME_UNTRUSTED,
|
|
1430
|
-
publicSummary: typeof defaults.publicSummary === 'string' ? defaults.publicSummary : 'Headless runtime defaults failed public-safety validation.',
|
|
1431
|
-
redactionSummary: Array.isArray(defaults.redactionSummary) ? defaults.redactionSummary : [],
|
|
1432
|
-
};
|
|
1433
|
-
}
|
|
1434
|
-
const source = normalizeRuntimeSource(input.attempt.runtime_source) ?? 'explicit';
|
|
1435
|
-
const hint = (input.attempt.runtime_id || input.attempt.model_id)
|
|
1436
|
-
? {
|
|
1437
|
-
...(input.attempt.runtime_id ? { runtimeId: input.attempt.runtime_id } : {}),
|
|
1438
|
-
...(input.attempt.model_id ? { modelId: input.attempt.model_id } : {}),
|
|
1439
|
-
source,
|
|
1440
|
-
publicSafe: true,
|
|
1441
|
-
}
|
|
1442
|
-
: undefined;
|
|
1443
|
-
const resolutionInput = {
|
|
1444
|
-
registry: input.registry,
|
|
1445
|
-
defaults,
|
|
1446
|
-
fallback: input.runtimeFallback,
|
|
1447
|
-
};
|
|
1448
|
-
if (hint) {
|
|
1449
|
-
if (source === 'origin')
|
|
1450
|
-
resolutionInput.origin = hint;
|
|
1451
|
-
else if (source === 'default')
|
|
1452
|
-
resolutionInput.projectDefault = hint;
|
|
1453
|
-
else if (source === 'fallback')
|
|
1454
|
-
resolutionInput.fallback = hint;
|
|
1455
|
-
else
|
|
1456
|
-
resolutionInput.explicit = hint;
|
|
1457
|
-
}
|
|
1458
|
-
const resolution = resolveHeadlessRuntime(resolutionInput);
|
|
1459
|
-
if (!resolution.ok) {
|
|
1460
|
-
return {
|
|
1461
|
-
ok: false,
|
|
1462
|
-
reasonCode: resolution.reasonCode,
|
|
1463
|
-
publicSummary: resolution.publicSummary,
|
|
1464
|
-
redactionSummary: resolution.redactionSummary,
|
|
1465
|
-
};
|
|
1466
|
-
}
|
|
1467
|
-
return {
|
|
1468
|
-
ok: true,
|
|
1469
|
-
runtimeId: resolution.runtimeId,
|
|
1470
|
-
...(resolution.modelId ? { modelId: resolution.modelId } : {}),
|
|
1471
|
-
runtimeSource: resolution.runtimeSource,
|
|
1472
|
-
};
|
|
1473
|
-
}
|
|
1474
|
-
function validateRunYoloopExecutionDirective(input) {
|
|
1475
|
-
const redactions = [];
|
|
1476
|
-
for (const key of Object.keys(input)) {
|
|
1477
|
-
if (!EXECUTION_DIRECTIVE_ALLOWED_KEYS.has(key) || UNSAFE_KEY_PATTERN.test(key)) {
|
|
1478
|
-
redactions.push(redaction(key, unsafeKeyReason(key), 'key-denied'));
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1481
|
-
if (input.publicSafe !== true)
|
|
1482
|
-
redactions.push(redaction('publicSafe', 'unsafe_key', 'value-denied'));
|
|
1483
|
-
const kind = stringField(input, 'kind');
|
|
1484
|
-
const commandClass = stringField(input, 'commandClass');
|
|
1485
|
-
const jobId = stringField(input, 'jobId');
|
|
1486
|
-
const operationId = stringField(input, 'operationId');
|
|
1487
|
-
const idempotencyKey = stringField(input, 'idempotencyKey');
|
|
1488
|
-
const targetKind = stringField(input, 'targetKind');
|
|
1489
|
-
const targetRef = stringField(input, 'targetRef');
|
|
1490
|
-
const commandRef = stringField(input, 'commandRef');
|
|
1491
|
-
const publicSummary = stringField(input, 'publicSummary');
|
|
1492
|
-
const epicId = stringField(input, 'epicId');
|
|
1493
|
-
if (kind !== 'run_yoloop')
|
|
1494
|
-
redactions.push(redaction('kind', 'unsafe_key', 'value-denied'));
|
|
1495
|
-
if (commandClass !== 'goal-tick' && commandClass !== 'loop-tick')
|
|
1496
|
-
redactions.push(redaction('commandClass', 'unsafe_key', 'value-denied'));
|
|
1497
|
-
if (!isSafeIdentifier(jobId))
|
|
1498
|
-
redactions.push(redaction('jobId', 'unsafe_key', 'value-denied'));
|
|
1499
|
-
if (!isSafeIdentifier(operationId))
|
|
1500
|
-
redactions.push(redaction('operationId', 'unsafe_key', 'value-denied'));
|
|
1501
|
-
if (!isSafeIdentifier(idempotencyKey))
|
|
1502
|
-
redactions.push(redaction('idempotencyKey', 'unsafe_key', 'value-denied'));
|
|
1503
|
-
if (targetKind !== 'epic' || !targetRef || !EPIC_TARGET_PATTERN.test(targetRef) || UNSAFE_VALUE_PATTERN.test(targetRef)) {
|
|
1504
|
-
redactions.push(redaction('targetRef', 'prompt_body', 'value-denied'));
|
|
1505
|
-
}
|
|
1506
|
-
const expectedCommandRef = targetRef ? `*yoloop @${targetRef}` : undefined;
|
|
1507
|
-
if (!commandRef || commandRef !== expectedCommandRef || commandRef.includes('@neocortex') || SHELL_FRAGMENT_PATTERN.test(commandRef) || UNSAFE_VALUE_PATTERN.test(commandRef)) {
|
|
1508
|
-
redactions.push(redaction('commandRef', 'prompt_body', 'value-denied'));
|
|
1509
|
-
}
|
|
1510
|
-
if (epicId && targetRef && epicId !== epicIdFromTargetRef(targetRef))
|
|
1511
|
-
redactions.push(redaction('epicId', 'prompt_body', 'value-denied'));
|
|
1512
|
-
if (!publicSummary || publicSummary.length > 240 || UNSAFE_VALUE_PATTERN.test(publicSummary)) {
|
|
1513
|
-
redactions.push(redaction('publicSummary', 'unbounded_text', 'value-denied'));
|
|
1514
|
-
}
|
|
1515
|
-
if (input.reasonCode !== undefined && (typeof input.reasonCode !== 'string' || UNSAFE_VALUE_PATTERN.test(input.reasonCode))) {
|
|
1516
|
-
redactions.push(redaction('reasonCode', 'unsafe_key', 'value-denied'));
|
|
1517
|
-
}
|
|
1518
|
-
const runtime = validateDirectiveRuntime(input.runtime, redactions);
|
|
1519
|
-
if (input.attempts !== undefined)
|
|
1520
|
-
assertPublicSafeCandidate(input.attempts, 'attempts', redactions);
|
|
1521
|
-
if (input.metadata !== undefined)
|
|
1522
|
-
assertPublicSafeCandidate(input.metadata, 'metadata', redactions);
|
|
1523
|
-
const metadata = isRecord(input.metadata) ? input.metadata : undefined;
|
|
1524
|
-
const redactionSummary = validateDirectiveRedactions(input.redactionSummary, redactions);
|
|
1525
|
-
if (redactions.length > 0 || kind !== 'run_yoloop' || !commandClass || !jobId || !operationId || !idempotencyKey || !targetRef || !commandRef || !publicSummary) {
|
|
1526
|
-
const promptRejected = redactions.some((item) => item.reason === 'prompt_body');
|
|
1527
|
-
return {
|
|
1528
|
-
ok: false,
|
|
1529
|
-
reasonCode: promptRejected ? HEADLESS_REASON_CODES.PROMPT_REJECTED : HEADLESS_REASON_CODES.DIRECTIVE_REJECTED,
|
|
1530
|
-
redactionSummary: redactions,
|
|
1531
|
-
};
|
|
1532
|
-
}
|
|
1533
|
-
return {
|
|
1534
|
-
ok: true,
|
|
1535
|
-
directive: {
|
|
1536
|
-
kind: 'run_yoloop',
|
|
1537
|
-
commandClass: commandClass,
|
|
1538
|
-
jobId: jobId,
|
|
1539
|
-
operationId: operationId,
|
|
1540
|
-
idempotencyKey: idempotencyKey,
|
|
1541
|
-
targetKind: 'epic',
|
|
1542
|
-
targetRef: targetRef,
|
|
1543
|
-
commandRef: commandRef,
|
|
1544
|
-
...(epicId ? { epicId } : {}),
|
|
1545
|
-
...(runtime ? { runtime } : {}),
|
|
1546
|
-
publicSummary: publicSummary,
|
|
1547
|
-
...(typeof input.reasonCode === 'string' ? { reasonCode: input.reasonCode } : {}),
|
|
1548
|
-
...(metadata ? { metadata } : {}),
|
|
1549
|
-
...(redactionSummary.length > 0 ? { redactionSummary } : {}),
|
|
1550
|
-
publicSafe: true,
|
|
1551
|
-
},
|
|
1552
|
-
};
|
|
1553
|
-
}
|
|
1554
|
-
function extractAuthorizedChildPrompts(metadata, epicId) {
|
|
1555
|
-
if (!metadata) {
|
|
1556
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop metadata was missing.', []);
|
|
1557
|
-
}
|
|
1558
|
-
const publicSafety = validateYoloopMetadataPublicSubset(metadata);
|
|
1559
|
-
if (!publicSafety.ok)
|
|
1560
|
-
return publicSafety;
|
|
1561
|
-
const prompts = [];
|
|
1562
|
-
const plan = isRecord(metadata.yoloopExecutionPlan) ? metadata.yoloopExecutionPlan : undefined;
|
|
1563
|
-
const planStoryIds = plan ? safeStringArray(plan.storyIds).filter(isStoryId) : [];
|
|
1564
|
-
const continuousNodes = plan?.version === 3 && isRecord(plan.scheduler) && Array.isArray(plan.scheduler.nodes)
|
|
1565
|
-
? new Map(plan.scheduler.nodes.filter(isRecord).map((node) => [String(node.storyId ?? ''), node]))
|
|
1566
|
-
: new Map();
|
|
1567
|
-
const continuousGraphRevision = plan?.version === 3 && isRecord(plan.scheduler) && typeof plan.scheduler.graphRevision === 'string'
|
|
1568
|
-
? plan.scheduler.graphRevision
|
|
1569
|
-
: undefined;
|
|
1570
|
-
const continuousExecutionBranch = plan?.version === 3 && typeof plan.executionBranch === 'string'
|
|
1571
|
-
? plan.executionBranch
|
|
1572
|
-
: undefined;
|
|
1573
|
-
let planValidation;
|
|
1574
|
-
if (plan) {
|
|
1575
|
-
const validation = validateExecutionPlan(plan);
|
|
1576
|
-
if (!validation.ok)
|
|
1577
|
-
return validation;
|
|
1578
|
-
planValidation = validation;
|
|
1579
|
-
for (const prompt of extractPlanPrompts(plan)) {
|
|
1580
|
-
const normalized = normalizeChildPrompt(prompt, epicId, 'execution-plan');
|
|
1581
|
-
if (!normalized.ok)
|
|
1582
|
-
return normalized;
|
|
1583
|
-
prompts.push(enrichContinuousPrompt(normalized.prompt, continuousNodes.get(normalized.prompt.storyId), continuousGraphRevision, continuousExecutionBranch));
|
|
1584
|
-
}
|
|
1585
|
-
if (prompts.length === 0) {
|
|
1586
|
-
for (const storyId of planStoryIds) {
|
|
1587
|
-
const normalized = normalizeChildPrompt(`*yolo @docs/stories/${storyId}.story.md`, epicId, 'execution-plan');
|
|
1588
|
-
if (!normalized.ok)
|
|
1589
|
-
return normalized;
|
|
1590
|
-
prompts.push(enrichContinuousPrompt(normalized.prompt, continuousNodes.get(normalized.prompt.storyId), continuousGraphRevision, continuousExecutionBranch));
|
|
1591
|
-
}
|
|
1592
|
-
}
|
|
1593
|
-
const directiveCompatibility = validatePlanTaskDirectives(metadata.skillDirectives, prompts);
|
|
1594
|
-
if (!directiveCompatibility.ok)
|
|
1595
|
-
return directiveCompatibility;
|
|
1596
|
-
}
|
|
1597
|
-
const nextStoryId = typeof metadata.nextStoryId === 'string' && isStoryId(metadata.nextStoryId)
|
|
1598
|
-
? metadata.nextStoryId
|
|
1599
|
-
: undefined;
|
|
1600
|
-
// A validated execution plan is the sole child-dispatch authority. Compatible
|
|
1601
|
-
// duplicate task directives were checked above but never become a second
|
|
1602
|
-
// dispatch source.
|
|
1603
|
-
for (const directive of plan ? [] : Array.isArray(metadata.skillDirectives) ? metadata.skillDirectives : []) {
|
|
1604
|
-
if (!isRecord(directive) || directive.kind !== 'task')
|
|
1605
|
-
continue;
|
|
1606
|
-
const explicitPrompts = safeStringArray(directive.promptTemplates);
|
|
1607
|
-
if (explicitPrompts.length > 0) {
|
|
1608
|
-
for (const prompt of explicitPrompts) {
|
|
1609
|
-
const normalized = normalizeChildPrompt(prompt, epicId, 'task-directive');
|
|
1610
|
-
if (!normalized.ok)
|
|
1611
|
-
return normalized;
|
|
1612
|
-
prompts.push(normalized.prompt);
|
|
1613
|
-
}
|
|
1614
|
-
continue;
|
|
1615
|
-
}
|
|
1616
|
-
const template = typeof directive.promptTemplate === 'string' ? directive.promptTemplate : undefined;
|
|
1617
|
-
if (!template)
|
|
1618
|
-
continue;
|
|
1619
|
-
const storyIds = safeStringArray(directive.storyIds).filter(isStoryId);
|
|
1620
|
-
const ids = storyIds.length > 0 ? storyIds : nextStoryId ? [nextStoryId] : [];
|
|
1621
|
-
if (ids.length === 0 && CHILD_PROMPT_PATTERN.test(template)) {
|
|
1622
|
-
const normalized = normalizeChildPrompt(template, epicId, 'task-directive');
|
|
1623
|
-
if (!normalized.ok)
|
|
1624
|
-
return normalized;
|
|
1625
|
-
prompts.push(normalized.prompt);
|
|
1626
|
-
continue;
|
|
1627
|
-
}
|
|
1628
|
-
for (const storyId of ids) {
|
|
1629
|
-
const prompt = template.includes('{storyId}') ? template.replaceAll('{storyId}', storyId) : template;
|
|
1630
|
-
const normalized = normalizeChildPrompt(prompt, epicId, 'task-directive');
|
|
1631
|
-
if (!normalized.ok)
|
|
1632
|
-
return normalized;
|
|
1633
|
-
prompts.push(normalized.prompt);
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
if (prompts.length === 0 && nextStoryId) {
|
|
1637
|
-
const normalized = normalizeChildPrompt(`*yolo @docs/stories/${nextStoryId}.story.md`, epicId, 'next-story');
|
|
1638
|
-
if (!normalized.ok)
|
|
1639
|
-
return normalized;
|
|
1640
|
-
prompts.push(normalized.prompt);
|
|
1641
|
-
}
|
|
1642
|
-
const uniquePrompts = uniqueBy(prompts, (item) => item.commandRef);
|
|
1643
|
-
if (planValidation?.continuous) {
|
|
1644
|
-
if (uniquePrompts.length !== planStoryIds.length
|
|
1645
|
-
|| uniquePrompts.some((prompt) => prompt.preparationOnly !== true || prompt.source !== 'execution-plan')) {
|
|
1646
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_ISOLATION_VIOLATION, 'Headless continuous yoloop rejected an ambiguous or non-preparation child prompt.', [redaction('promptTemplates', 'prompt_body', 'operation-denied')]);
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
|
-
else if (uniquePrompts.some((prompt) => prompt.preparationOnly === true)) {
|
|
1650
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_ISOLATION_VIOLATION, 'Headless yoloop rejected branchless preparation outside a validated continuous plan.', [redaction('promptTemplates', 'prompt_body', 'operation-denied')]);
|
|
1651
|
-
}
|
|
1652
|
-
if (planStoryIds.length > 0) {
|
|
1653
|
-
const authorized = new Set(planStoryIds);
|
|
1654
|
-
for (const prompt of uniquePrompts) {
|
|
1655
|
-
if (!authorized.has(prompt.storyId)) {
|
|
1656
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_ISOLATION_VIOLATION, 'Headless yoloop rejected a child prompt outside the server-authorized execution plan.', [redaction('storyId', 'prompt_body', hashPublicValue(prompt.storyId))]);
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
}
|
|
1660
|
-
if (planValidation?.parallelAuthorized && !sameStringSet(uniquePrompts.map((item) => item.storyId), planStoryIds)) {
|
|
1661
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop rejected a parallel plan whose executable prompts did not match the selected wave.', []);
|
|
1662
|
-
}
|
|
1663
|
-
if (uniquePrompts.length === 0 && !planValidation?.continuous) {
|
|
1664
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop metadata did not include an authorized per-story child prompt.', []);
|
|
1665
|
-
}
|
|
1666
|
-
return {
|
|
1667
|
-
ok: true,
|
|
1668
|
-
prompts: uniquePrompts,
|
|
1669
|
-
mode: planValidation?.mode ?? 'legacy',
|
|
1670
|
-
serverMaxConcurrency: planValidation?.serverMaxConcurrency ?? 1,
|
|
1671
|
-
parallelAuthorized: planValidation?.parallelAuthorized ?? false,
|
|
1672
|
-
continuous: planValidation?.continuous ?? false,
|
|
1673
|
-
reasonCodes: [
|
|
1674
|
-
HEADLESS_REASON_CODES.OK,
|
|
1675
|
-
planValidation?.parallelAuthorized
|
|
1676
|
-
? HEADLESS_REASON_CODES.WORKER_POOL_PARALLEL_ACTIVE
|
|
1677
|
-
: HEADLESS_REASON_CODES.WORKER_POOL_SERIAL_FALLBACK,
|
|
1678
|
-
],
|
|
1679
|
-
};
|
|
1680
|
-
}
|
|
1681
|
-
function enrichContinuousPrompt(prompt, node, graphRevision, executionBranch) {
|
|
1682
|
-
if (!node || !graphRevision || !executionBranch)
|
|
1683
|
-
return prompt;
|
|
1684
|
-
const writeSet = Array.isArray(node.writeSet) ? safeStringArray(node.writeSet) : [];
|
|
1685
|
-
const rootAuthority = parseBranchlessRootAuthority(node.childExecutionAuthority, {
|
|
1686
|
-
storyId: prompt.storyId,
|
|
1687
|
-
invocationPrompt: prompt.commandRef,
|
|
1688
|
-
authorizedWriteSet: writeSet,
|
|
1689
|
-
});
|
|
1690
|
-
return {
|
|
1691
|
-
...prompt,
|
|
1692
|
-
...(typeof node.dispatchId === 'string' ? { dispatchId: node.dispatchId } : {}),
|
|
1693
|
-
...(typeof node.idempotencyKey === 'string' ? { idempotencyKey: node.idempotencyKey } : {}),
|
|
1694
|
-
graphRevision,
|
|
1695
|
-
executionBranch,
|
|
1696
|
-
...(writeSet.length > 0 ? { writeSet } : {}),
|
|
1697
|
-
...(rootAuthority ? { rootAuthority } : {}),
|
|
1698
|
-
};
|
|
1699
|
-
}
|
|
1700
|
-
function validateYoloopMetadataPublicSubset(metadata) {
|
|
1701
|
-
const redactions = [];
|
|
1702
|
-
if (metadata.nextStoryId !== undefined)
|
|
1703
|
-
validatePublicMetadataValue(metadata.nextStoryId, 'nextStoryId', redactions);
|
|
1704
|
-
if (metadata.yoloopExecutionPlan !== undefined)
|
|
1705
|
-
validatePublicMetadataValue(metadata.yoloopExecutionPlan, 'yoloopExecutionPlan', redactions);
|
|
1706
|
-
if (Array.isArray(metadata.skillDirectives)) {
|
|
1707
|
-
metadata.skillDirectives.forEach((directive, index) => {
|
|
1708
|
-
if (isRecord(directive) && directive.kind === 'task')
|
|
1709
|
-
validatePublicMetadataValue(directive, `skillDirectives.${index}`, redactions);
|
|
1710
|
-
});
|
|
1711
|
-
}
|
|
1712
|
-
if (redactions.length > 0) {
|
|
1713
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop rejected unsafe public metadata before child delegation.', redactions);
|
|
1714
|
-
}
|
|
1715
|
-
return { ok: true };
|
|
1716
|
-
}
|
|
1717
|
-
function validatePlanTaskDirectives(value, planPrompts) {
|
|
1718
|
-
if (!Array.isArray(value))
|
|
1719
|
-
return { ok: true };
|
|
1720
|
-
const authorized = new Set(planPrompts.map((prompt) => prompt.commandRef));
|
|
1721
|
-
for (const [index, directive] of value.entries()) {
|
|
1722
|
-
if (!isRecord(directive) || directive.kind !== 'task')
|
|
1723
|
-
continue;
|
|
1724
|
-
const promptTemplate = typeof directive.promptTemplate === 'string' ? directive.promptTemplate : undefined;
|
|
1725
|
-
const promptTemplates = safeStringArray(directive.promptTemplates);
|
|
1726
|
-
const redactedDuplicate = promptTemplate === '[REDACTED]'
|
|
1727
|
-
&& directive.subagentType === 'neocortex'
|
|
1728
|
-
&& typeof directive.reasonCode === 'string'
|
|
1729
|
-
&& directive.reasonCode.startsWith('directive-prompt-')
|
|
1730
|
-
&& promptTemplates.length === 0;
|
|
1731
|
-
if (redactedDuplicate)
|
|
1732
|
-
continue;
|
|
1733
|
-
const candidates = [...(promptTemplate ? [promptTemplate] : []), ...promptTemplates];
|
|
1734
|
-
if (directive.subagentType !== 'neocortex'
|
|
1735
|
-
|| candidates.length === 0
|
|
1736
|
-
|| candidates.some((candidate) => !authorized.has(candidate))) {
|
|
1737
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_ISOLATION_VIOLATION, 'Headless yoloop rejected a task directive that conflicted with the server-authorized execution plan.', [redaction(`skillDirectives.${index}`, 'prompt_body', 'operation-denied')]);
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
return { ok: true };
|
|
1741
|
-
}
|
|
1742
|
-
function validatePublicMetadataValue(value, path, redactions) {
|
|
1743
|
-
if (typeof value === 'string') {
|
|
1744
|
-
if (/\.allowedDebt\.constraints\.\d+$/.test(path) && PUBLIC_CHILD_DEBT_CONSTRAINTS.has(value))
|
|
1745
|
-
return;
|
|
1746
|
-
if (UNSAFE_VALUE_PATTERN.test(value) || /\0/.test(value))
|
|
1747
|
-
redactions.push(redaction(path, unsafeKeyReason(path), 'value-denied'));
|
|
1748
|
-
return;
|
|
1749
|
-
}
|
|
1750
|
-
if (value === undefined || value === null || typeof value === 'number' || typeof value === 'boolean')
|
|
1751
|
-
return;
|
|
1752
|
-
if (Array.isArray(value)) {
|
|
1753
|
-
value.forEach((item, index) => validatePublicMetadataValue(item, `${path}.${index}`, redactions));
|
|
1754
|
-
return;
|
|
1755
|
-
}
|
|
1756
|
-
if (isRecord(value)) {
|
|
1757
|
-
for (const [key, child] of Object.entries(value)) {
|
|
1758
|
-
const childPath = `${path}.${key}`;
|
|
1759
|
-
const promptTemplateKey = key === 'promptTemplate'
|
|
1760
|
-
|| key === 'promptTemplates'
|
|
1761
|
-
|| key === 'invocationPrompt'
|
|
1762
|
-
|| key === 'childPromptKind'
|
|
1763
|
-
|| key === 'allowMetaTaskPromptInChild'
|
|
1764
|
-
|| key === 'authorization';
|
|
1765
|
-
if (!promptTemplateKey && UNSAFE_KEY_PATTERN.test(key))
|
|
1766
|
-
redactions.push(redaction(childPath, unsafeKeyReason(key), 'key-denied'));
|
|
1767
|
-
validatePublicMetadataValue(child, childPath, redactions);
|
|
1768
|
-
}
|
|
1769
|
-
return;
|
|
1770
|
-
}
|
|
1771
|
-
redactions.push(redaction(path, 'unsafe_key', 'value-denied'));
|
|
1772
|
-
}
|
|
1773
|
-
function validateExecutionPlan(plan) {
|
|
1774
|
-
const mode = typeof plan.mode === 'string' ? plan.mode : '';
|
|
1775
|
-
const isolationPolicy = isRecord(plan.isolationPolicy) ? plan.isolationPolicy : undefined;
|
|
1776
|
-
const storyIds = safeStringArray(plan.storyIds);
|
|
1777
|
-
if (plan.authorization !== 'server_authorized') {
|
|
1778
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop execution plan was not server-authorized.', []);
|
|
1779
|
-
}
|
|
1780
|
-
if (plan.executor !== 'root_agent' && plan.executor !== 'root_agent_with_child_tasks') {
|
|
1781
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop execution plan executor was not root-owned.', []);
|
|
1782
|
-
}
|
|
1783
|
-
if (mode !== 'serial' && mode !== 'parallel_wave' && mode !== 'continuous_dag' && mode !== 'manual') {
|
|
1784
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop execution plan mode was invalid.', []);
|
|
1785
|
-
}
|
|
1786
|
-
const continuousMode = plan.version === 3 && mode === 'continuous_dag';
|
|
1787
|
-
if (!Array.isArray(plan.storyIds) ||
|
|
1788
|
-
(!continuousMode && storyIds.length === 0) ||
|
|
1789
|
-
storyIds.length !== plan.storyIds.length ||
|
|
1790
|
-
storyIds.some((storyId) => !isStoryId(storyId)) ||
|
|
1791
|
-
new Set(storyIds).size !== storyIds.length) {
|
|
1792
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop execution plan story selection was invalid or ambiguous.', []);
|
|
1793
|
-
}
|
|
1794
|
-
if (!isolationPolicy ||
|
|
1795
|
-
isolationPolicy.rootOwnsLoop !== true ||
|
|
1796
|
-
(isolationPolicy.childPromptKind === 'per_story_branchless_preparation_only' && !continuousMode) ||
|
|
1797
|
-
(Object.prototype.hasOwnProperty.call(isolationPolicy, 'childExecutionBoundary') && !continuousMode) ||
|
|
1798
|
-
(isolationPolicy.childPromptKind !== 'per_story_yolo_only' &&
|
|
1799
|
-
isolationPolicy.childPromptKind !== 'per_story_branchless_preparation_only' &&
|
|
1800
|
-
!(isolationPolicy.childPromptKind === 'none' &&
|
|
1801
|
-
((mode === 'serial' && isolationPolicy.childTaskDelegation === 'not_required') ||
|
|
1802
|
-
(mode === 'parallel_wave' && plan.executor === 'root_agent' && isolationPolicy.childTaskDelegation === 'forbidden')))) ||
|
|
1803
|
-
isolationPolicy.allowOuterYoloopInChild !== false ||
|
|
1804
|
-
isolationPolicy.allowMetaTaskPromptInChild !== false) {
|
|
1805
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_ISOLATION_VIOLATION, 'Headless yoloop rejected an execution plan that did not preserve root-owned child isolation.', [redaction('isolationPolicy', 'prompt_body', 'value-denied')]);
|
|
1806
|
-
}
|
|
1807
|
-
const skippedStories = Array.isArray(plan.skippedStories) ? plan.skippedStories : [];
|
|
1808
|
-
for (const skipped of skippedStories) {
|
|
1809
|
-
if (!isRecord(skipped) || typeof skipped.storyId !== 'string' || !isStoryId(skipped.storyId) || typeof skipped.reason !== 'string') {
|
|
1810
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop skipped-story evidence was malformed.', []);
|
|
1811
|
-
}
|
|
1812
|
-
if (storyIds.includes(skipped.storyId)) {
|
|
1813
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop selected a story that server evidence marked skipped.', []);
|
|
1814
|
-
}
|
|
1815
|
-
}
|
|
1816
|
-
if (continuousMode) {
|
|
1817
|
-
const scheduler = isRecord(plan.scheduler) ? plan.scheduler : undefined;
|
|
1818
|
-
const nodes = Array.isArray(scheduler?.nodes) ? scheduler.nodes.filter(isRecord) : [];
|
|
1819
|
-
const schedulerReady = safeStringArray(scheduler?.readyStoryIds);
|
|
1820
|
-
const schedulerRunning = safeStringArray(scheduler?.runningStoryIds);
|
|
1821
|
-
const promptTemplates = safeStringArray(plan.promptTemplates);
|
|
1822
|
-
const dependencyBasis = isRecord(plan.dependencyBasis) ? plan.dependencyBasis : undefined;
|
|
1823
|
-
const readinessBasis = isRecord(plan.readinessBasis) ? plan.readinessBasis : undefined;
|
|
1824
|
-
const graphRevision = typeof scheduler?.graphRevision === 'string' ? scheduler.graphRevision : '';
|
|
1825
|
-
const executionBranch = typeof plan.executionBranch === 'string' ? plan.executionBranch : '';
|
|
1826
|
-
const nodeIds = nodes.map((node) => typeof node.storyId === 'string' ? node.storyId : '');
|
|
1827
|
-
const unsafeNode = nodes.find((node) => {
|
|
1828
|
-
const storyId = typeof node.storyId === 'string' ? node.storyId : '';
|
|
1829
|
-
const prompt = typeof node.promptTemplate === 'string' ? node.promptTemplate : '';
|
|
1830
|
-
const writeSet = Array.isArray(node.writeSet) ? safeStringArray(node.writeSet) : [];
|
|
1831
|
-
return !isStoryId(storyId) || prompt !== `*yolo @docs/stories/${storyId}.story.md branchless-preparation`
|
|
1832
|
-
|| typeof node.dispatchId !== 'string' || !/^[a-f0-9]{64}$/.test(node.dispatchId)
|
|
1833
|
-
|| typeof node.idempotencyKey !== 'string' || !/^[a-f0-9]{64}$/.test(node.idempotencyKey)
|
|
1834
|
-
|| node.dependencyBasis !== 'verified'
|
|
1835
|
-
|| !Array.isArray(node.dependencies) || safeStringArray(node.dependencies).length !== node.dependencies.length
|
|
1836
|
-
|| !Array.isArray(node.writeSet) || writeSet.length === 0 || writeSet.length !== node.writeSet.length
|
|
1837
|
-
|| !parseBranchlessRootAuthority(node.childExecutionAuthority, {
|
|
1838
|
-
storyId, invocationPrompt: prompt, authorizedWriteSet: writeSet,
|
|
1839
|
-
});
|
|
1840
|
-
});
|
|
1841
|
-
if (plan.executor !== 'root_agent_with_child_tasks'
|
|
1842
|
-
|| plan.legacyConcurrencyIgnored !== true
|
|
1843
|
-
|| Object.prototype.hasOwnProperty.call(plan, 'maxConcurrency')
|
|
1844
|
-
|| Object.prototype.hasOwnProperty.call(plan, 'maxParallel')
|
|
1845
|
-
|| isolationPolicy?.rootOwnedScheduling !== 'continuous_dag_allowed'
|
|
1846
|
-
|| isolationPolicy?.childPromptKind !== 'per_story_branchless_preparation_only'
|
|
1847
|
-
|| isolationPolicy?.childExecutionBoundary !== 'filesystem_only'
|
|
1848
|
-
|| isolationPolicy?.childTaskDelegation !== 'allowed'
|
|
1849
|
-
|| isolationPolicy?.maxDepth !== 1
|
|
1850
|
-
|| isolationPolicy?.childWorkspace !== 'branchless_sandbox'
|
|
1851
|
-
|| isolationPolicy?.epicCheckout !== 'current_checkout'
|
|
1852
|
-
|| isolationPolicy?.workspaceLifecycle !== 'user_managed'
|
|
1853
|
-
|| isolationPolicy?.integrationOwner !== 'root_agent'
|
|
1854
|
-
|| !scheduler
|
|
1855
|
-
|| scheduler.schemaVersion !== 1
|
|
1856
|
-
|| scheduler.strategy !== 'continuous-event-driven-dag'
|
|
1857
|
-
|| scheduler.logicalConcurrency !== 'ready-set'
|
|
1858
|
-
|| scheduler.capacityPolicy !== 'backpressure-only'
|
|
1859
|
-
|| scheduler.rootOwnsLoop !== true
|
|
1860
|
-
|| scheduler.maxDepth !== 1
|
|
1861
|
-
|| !/^[a-f0-9]{64}$/.test(graphRevision)
|
|
1862
|
-
|| !isSafeExecutionBranch(executionBranch)
|
|
1863
|
-
|| new Set(nodeIds).size !== nodeIds.length
|
|
1864
|
-
|| nodeIds.some((storyId) => !isStoryId(storyId))
|
|
1865
|
-
|| schedulerReady.some((storyId) => !nodeIds.includes(storyId))
|
|
1866
|
-
|| schedulerRunning.some((storyId) => !nodeIds.includes(storyId) || schedulerReady.includes(storyId))
|
|
1867
|
-
|| !sameStringSet(storyIds, schedulerReady)
|
|
1868
|
-
|| promptTemplates.length !== storyIds.length
|
|
1869
|
-
|| promptTemplates.some((prompt, index) => prompt !== `*yolo @docs/stories/${storyIds[index]}.story.md branchless-preparation`)
|
|
1870
|
-
|| !dependencyBasis || dependencyBasis.source !== 'state_snapshot'
|
|
1871
|
-
|| !readinessBasis || readinessBasis.source !== 'ready_wave'
|
|
1872
|
-
|| !sameStringSet(safeStringArray(readinessBasis.selectedStoryIds), storyIds)
|
|
1873
|
-
|| unsafeNode) {
|
|
1874
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop rejected an invalid continuous DAG execution plan.', []);
|
|
1875
|
-
}
|
|
1876
|
-
return {
|
|
1877
|
-
ok: true,
|
|
1878
|
-
mode: 'continuous_dag',
|
|
1879
|
-
serverMaxConcurrency: storyIds.length,
|
|
1880
|
-
parallelAuthorized: true,
|
|
1881
|
-
continuous: true,
|
|
1882
|
-
};
|
|
1883
|
-
}
|
|
1884
|
-
if (plan.version === 2) {
|
|
1885
|
-
const phased = validatePhasedYoloopPlan(plan);
|
|
1886
|
-
if (!phased.ok) {
|
|
1887
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop rejected an unsafe phased execution plan.', []);
|
|
1888
|
-
}
|
|
1889
|
-
// A child *yolo performs the complete story lifecycle and may write. Until
|
|
1890
|
-
// preparation-only child directives exist, full child execution is pinned
|
|
1891
|
-
// to the P207 single writer even when preparation phases allow parallelism.
|
|
1892
|
-
return { ok: true, mode: 'parallel_wave', serverMaxConcurrency: phased.childExecutionConcurrency, parallelAuthorized: false, continuous: false };
|
|
1893
|
-
}
|
|
1894
|
-
if (mode !== 'parallel_wave') {
|
|
1895
|
-
return {
|
|
1896
|
-
ok: true,
|
|
1897
|
-
mode: mode,
|
|
1898
|
-
serverMaxConcurrency: 1,
|
|
1899
|
-
parallelAuthorized: false,
|
|
1900
|
-
continuous: false,
|
|
1901
|
-
};
|
|
1902
|
-
}
|
|
1903
|
-
const maxConcurrency = plan.maxConcurrency;
|
|
1904
|
-
const maxParallel = plan.maxParallel;
|
|
1905
|
-
const dependencyBasis = isRecord(plan.dependencyBasis) ? plan.dependencyBasis : undefined;
|
|
1906
|
-
const readinessBasis = isRecord(plan.readinessBasis) ? plan.readinessBasis : undefined;
|
|
1907
|
-
const parallelWaves = Array.isArray(plan.parallelWaves) ? plan.parallelWaves : [];
|
|
1908
|
-
const wave = parallelWaves.length === 1 && isRecord(parallelWaves[0]) ? parallelWaves[0] : undefined;
|
|
1909
|
-
if (isolationPolicy.rootOwnedScheduling !== 'parallel_wave_allowed' ||
|
|
1910
|
-
!Number.isInteger(maxConcurrency) || typeof maxConcurrency !== 'number' || maxConcurrency < 2 || maxConcurrency > storyIds.length ||
|
|
1911
|
-
!Number.isInteger(maxParallel) || maxParallel !== maxConcurrency ||
|
|
1912
|
-
!dependencyBasis || dependencyBasis.source !== 'state_snapshot' || !sameStringSet(safeStringArray(dependencyBasis.storyIds), storyIds) ||
|
|
1913
|
-
!readinessBasis || readinessBasis.source !== 'ready_wave' || !sameStringSet(safeStringArray(readinessBasis.selectedStoryIds), storyIds) ||
|
|
1914
|
-
!wave || !sameStringSet(safeStringArray(wave.storyIds), storyIds) || wave.maxConcurrency !== maxConcurrency) {
|
|
1915
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop parallel plan lacked consistent bounded authorization and readiness evidence.', []);
|
|
1916
|
-
}
|
|
1917
|
-
const wavePrompts = safeStringArray(wave.promptTemplates);
|
|
1918
|
-
if (wavePrompts.length !== storyIds.length || new Set(wavePrompts).size !== wavePrompts.length) {
|
|
1919
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop parallel wave prompts were incomplete or ambiguous.', []);
|
|
1920
|
-
}
|
|
1921
|
-
const proofs = Array.isArray(wave.proofSummaries)
|
|
1922
|
-
? wave.proofSummaries
|
|
1923
|
-
: Array.isArray(plan.proofSummaries) ? plan.proofSummaries : [];
|
|
1924
|
-
const waveProof = proofs.find((proof) => isRecord(proof) && sameStringSet(safeStringArray(proof.storyIds), storyIds));
|
|
1925
|
-
if (!isRecord(waveProof) ||
|
|
1926
|
-
waveProof.dependencyClosure !== 'resolved' ||
|
|
1927
|
-
waveProof.contractOwnership !== 'non_overlapping' ||
|
|
1928
|
-
waveProof.validationSurfaces !== 'compatible') {
|
|
1929
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop parallel plan lacked resolved independence proof.', []);
|
|
1930
|
-
}
|
|
1931
|
-
const unsafeSkipped = skippedStories.find((skipped) => isRecord(skipped) && typeof skipped.reason === 'string' && /(cycle|unresolved|ambiguous)/i.test(skipped.reason));
|
|
1932
|
-
if (unsafeSkipped) {
|
|
1933
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop parallel plan contained unresolved dependency evidence.', []);
|
|
1934
|
-
}
|
|
1935
|
-
return {
|
|
1936
|
-
ok: true,
|
|
1937
|
-
mode: 'parallel_wave',
|
|
1938
|
-
serverMaxConcurrency: maxConcurrency,
|
|
1939
|
-
parallelAuthorized: true,
|
|
1940
|
-
continuous: false,
|
|
1941
|
-
};
|
|
1942
|
-
}
|
|
1943
|
-
function parseBranchlessRootAuthority(value, expected) {
|
|
1944
|
-
if (!isRecord(value) || !isRecord(value.artifact))
|
|
1945
|
-
return undefined;
|
|
1946
|
-
const artifact = value.artifact;
|
|
1947
|
-
const writeSet = Array.isArray(value.authorizedWriteSet) ? safeStringArray(value.authorizedWriteSet) : [];
|
|
1948
|
-
if (Object.keys(value).sort().join('\0') !== [
|
|
1949
|
-
'artifact', 'authorizedWriteSet', 'effectScope', 'invocationPrompt', 'kind',
|
|
1950
|
-
'lifecycleAuthority', 'publicSafe', 'schemaVersion', 'storyId',
|
|
1951
|
-
].sort().join('\0')
|
|
1952
|
-
|| Object.keys(artifact).sort().join('\0') !== [
|
|
1953
|
-
'content', 'contentBinding', 'kind', 'path', 'schemaVersion',
|
|
1954
|
-
].sort().join('\0')
|
|
1955
|
-
|| value.schemaVersion !== 1 || value.kind !== 'branchless_story_preparation'
|
|
1956
|
-
|| value.storyId !== expected.storyId || value.invocationPrompt !== expected.invocationPrompt
|
|
1957
|
-
|| !Array.isArray(value.authorizedWriteSet)
|
|
1958
|
-
|| writeSet.length !== value.authorizedWriteSet.length
|
|
1959
|
-
|| writeSet.some((ref) => normalizeContinuousWriteRef(ref) !== ref)
|
|
1960
|
-
|| !sameOrderedStrings(writeSet, expected.authorizedWriteSet)
|
|
1961
|
-
|| value.effectScope !== 'filesystem_only' || value.lifecycleAuthority !== 'root_only'
|
|
1962
|
-
|| value.publicSafe !== true || artifact.schemaVersion !== 1
|
|
1963
|
-
|| artifact.kind !== 'branchless_root_bound_artifact'
|
|
1964
|
-
|| typeof artifact.path !== 'string' || !writeSet.includes(artifact.path)
|
|
1965
|
-
|| typeof artifact.content !== 'string' || artifact.content.length === 0 || artifact.content.length > 4096
|
|
1966
|
-
|| typeof artifact.contentBinding !== 'string' || !/^[a-f0-9]{64}$/.test(artifact.contentBinding)) {
|
|
1967
|
-
return undefined;
|
|
1968
|
-
}
|
|
1969
|
-
const expectedBinding = createHash('sha256').update([
|
|
1970
|
-
'branchless-root-bound-artifact-v1', expected.storyId, expected.invocationPrompt,
|
|
1971
|
-
...writeSet, 'filesystem_only', 'root_only', artifact.path, artifact.content,
|
|
1972
|
-
].join('\0')).digest('hex');
|
|
1973
|
-
if (artifact.contentBinding !== expectedBinding)
|
|
1974
|
-
return undefined;
|
|
1975
|
-
return value;
|
|
1976
|
-
}
|
|
1977
|
-
function sameOrderedStrings(left, right) {
|
|
1978
|
-
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
1979
|
-
}
|
|
1980
|
-
function extractPlanPrompts(plan) {
|
|
1981
|
-
const prompts = [];
|
|
1982
|
-
prompts.push(...safeStringArray(plan.promptTemplates));
|
|
1983
|
-
for (const step of Array.isArray(plan.serialSteps) ? plan.serialSteps : []) {
|
|
1984
|
-
if (isRecord(step) && typeof step.promptTemplate === 'string')
|
|
1985
|
-
prompts.push(step.promptTemplate);
|
|
1986
|
-
}
|
|
1987
|
-
for (const wave of Array.isArray(plan.parallelWaves) ? plan.parallelWaves : []) {
|
|
1988
|
-
if (isRecord(wave))
|
|
1989
|
-
prompts.push(...safeStringArray(wave.promptTemplates));
|
|
1990
|
-
}
|
|
1991
|
-
return prompts;
|
|
1992
|
-
}
|
|
1993
|
-
function normalizeChildPrompt(prompt, epicId, source) {
|
|
1994
|
-
if (hasDelegatedPromptIsolationViolation(prompt)) {
|
|
1995
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_ISOLATION_VIOLATION, 'Headless yoloop rejected an unsafe child prompt shape.', [redaction('promptTemplate', 'prompt_body', hashPublicValue(prompt))]);
|
|
1996
|
-
}
|
|
1997
|
-
if (!CHILD_PROMPT_PATTERN.test(prompt)) {
|
|
1998
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, 'Headless yoloop child prompt did not match the canonical per-story yolo shape.', [redaction('promptTemplate', 'prompt_body', hashPublicValue(prompt))]);
|
|
1999
|
-
}
|
|
2000
|
-
const preparationOnly = BRANCHLESS_PREPARATION_PROMPT_PATTERN.test(prompt);
|
|
2001
|
-
const targetRef = prompt.replace(/^\*yolo @/, '').replace(/ branchless-preparation$/, '');
|
|
2002
|
-
const storyId = storyIdFromTargetRef(targetRef);
|
|
2003
|
-
if (!CHILD_STORY_TARGET_PATTERN.test(targetRef) || !isStoryId(storyId) || !storyId.startsWith(`${epicId}.`)) {
|
|
2004
|
-
return rejectPromptExtraction(HEADLESS_REASON_CODES.YOLOOP_ISOLATION_VIOLATION, 'Headless yoloop rejected a child prompt outside the targeted public epic.', [redaction('storyId', 'prompt_body', hashPublicValue(storyId))]);
|
|
2005
|
-
}
|
|
2006
|
-
return {
|
|
2007
|
-
ok: true,
|
|
2008
|
-
prompt: { storyId, targetRef, commandRef: prompt, source, ...(preparationOnly ? { preparationOnly: true } : {}) },
|
|
2009
|
-
};
|
|
2010
|
-
}
|
|
2011
|
-
function extractEpicTerminalGitDirective(metadata) {
|
|
2012
|
-
const value = metadata?.epicTerminalGitDirective;
|
|
2013
|
-
if (!isRecord(value)
|
|
2014
|
-
|| value.schemaVersion !== 1
|
|
2015
|
-
|| value.kind !== 'epic_terminal_git'
|
|
2016
|
-
|| typeof value.epicId !== 'string'
|
|
2017
|
-
|| typeof value.executionBranch !== 'string'
|
|
2018
|
-
|| typeof value.originBranch !== 'string'
|
|
2019
|
-
|| typeof value.expectedExecutionHeadSha !== 'string'
|
|
2020
|
-
|| !Array.isArray(value.storyCheckpointIds)
|
|
2021
|
-
|| !isRecord(value.localGates)
|
|
2022
|
-
|| value.localGates.passed !== true
|
|
2023
|
-
|| !Array.isArray(value.localGates.receiptRefs)
|
|
2024
|
-
|| !isRecord(value.reconcile)
|
|
2025
|
-
|| typeof value.idempotencyKey !== 'string'
|
|
2026
|
-
|| value.publicSafe !== true)
|
|
2027
|
-
return undefined;
|
|
2028
|
-
return value;
|
|
2029
|
-
}
|
|
2030
|
-
function extractEpicGitReconciliationDirective(metadata) {
|
|
2031
|
-
const value = metadata?.epicGitReconciliationDirective;
|
|
2032
|
-
if (!isRecord(value)
|
|
2033
|
-
|| value.schemaVersion !== 1
|
|
2034
|
-
|| value.kind !== 'epic_git_reconciliation'
|
|
2035
|
-
|| typeof value.epicId !== 'string'
|
|
2036
|
-
|| typeof value.executionBranch !== 'string'
|
|
2037
|
-
|| typeof value.originBranch !== 'string'
|
|
2038
|
-
|| !['start', 'resume', 'audit'].includes(String(value.lifecycleBoundary))
|
|
2039
|
-
|| typeof value.dryRun !== 'boolean'
|
|
2040
|
-
|| typeof value.idempotencyKey !== 'string'
|
|
2041
|
-
|| value.publicSafe !== true)
|
|
2042
|
-
return undefined;
|
|
2043
|
-
return value;
|
|
2044
|
-
}
|
|
2045
|
-
function classifyYoloopTerminalMetadata(metadata) {
|
|
2046
|
-
if (!metadata || !isRecord(metadata)) {
|
|
2047
|
-
return {
|
|
2048
|
-
ok: false,
|
|
2049
|
-
reasonCode: HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID,
|
|
2050
|
-
publicSummary: 'Headless yoloop root invocation did not return public metadata.',
|
|
2051
|
-
redactionSummary: [],
|
|
2052
|
-
};
|
|
2053
|
-
}
|
|
2054
|
-
const decision = isRecord(metadata.yoloopContinuationDecision) ? metadata.yoloopContinuationDecision : undefined;
|
|
2055
|
-
const outcome = typeof decision?.outcome === 'string' ? decision.outcome : undefined;
|
|
2056
|
-
const complete = outcome === 'queue_exhausted' || metadata.yoloopComplete === true;
|
|
2057
|
-
const aborted = metadata.yoloopAborted === true;
|
|
2058
|
-
const releaseBlocked = parseReleaseBlockedResult(metadata.releaseBlocked);
|
|
2059
|
-
const replay = outcome === 'selected' && decision?.replay === true;
|
|
2060
|
-
if (outcome && !['selected', 'queue_exhausted', 'blocked', 'cycle', 'invalid', 'no_progress'].includes(outcome)) {
|
|
2061
|
-
return { ok: false, reasonCode: HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, publicSummary: 'Headless yoloop rejected an unknown continuation outcome.', redactionSummary: [] };
|
|
2062
|
-
}
|
|
2063
|
-
if (outcome === 'queue_exhausted' && decision?.terminalSuccess !== true) {
|
|
2064
|
-
return { ok: false, reasonCode: HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID, publicSummary: 'Headless yoloop rejected inconsistent queue exhaustion metadata.', redactionSummary: [] };
|
|
2065
|
-
}
|
|
2066
|
-
if (complete && aborted) {
|
|
2067
|
-
return {
|
|
2068
|
-
ok: false,
|
|
2069
|
-
reasonCode: HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID,
|
|
2070
|
-
publicSummary: 'Headless yoloop metadata reported mutually exclusive terminal states.',
|
|
2071
|
-
redactionSummary: [redaction('yoloopTerminal', 'unsafe_key', 'value-denied')],
|
|
2072
|
-
};
|
|
2073
|
-
}
|
|
2074
|
-
const releaseBlockedSignalled = metadata.yoloopReleaseBlocked === true
|
|
2075
|
-
|| metadata.terminalClass === 'release-blocked'
|
|
2076
|
-
|| metadata.releaseBlocked !== undefined;
|
|
2077
|
-
if (releaseBlockedSignalled && (!releaseBlocked || metadata.yoloopReleaseBlocked !== true
|
|
2078
|
-
|| metadata.terminalClass !== 'release-blocked' || complete || aborted || outcome !== undefined)) {
|
|
2079
|
-
return {
|
|
2080
|
-
ok: false,
|
|
2081
|
-
reasonCode: HEADLESS_REASON_CODES.YOLOOP_METADATA_INVALID,
|
|
2082
|
-
publicSummary: 'Headless yoloop rejected inconsistent release-blocked terminal metadata.',
|
|
2083
|
-
redactionSummary: [],
|
|
2084
|
-
};
|
|
2085
|
-
}
|
|
2086
|
-
return { ok: true, complete, aborted, ...(releaseBlocked ? { releaseBlocked } : {}), outcome, replay };
|
|
2087
|
-
}
|
|
2088
|
-
function extractResumableExhaustionBoundary(metadata) {
|
|
2089
|
-
if (!metadata)
|
|
2090
|
-
return undefined;
|
|
2091
|
-
const reason = metadata.abortReason;
|
|
2092
|
-
if (reason !== 'YOLOOP_PER_RUN_CAP_REACHED' && reason !== 'YOLOOP_SESSION_TIMEOUT')
|
|
2093
|
-
return undefined;
|
|
2094
|
-
const boundary = metadata.yoloopResumableBoundary;
|
|
2095
|
-
const boundedId = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
2096
|
-
if (!isRecord(boundary)
|
|
2097
|
-
|| boundary.schemaVersion !== 'YoloopResumableBoundary/1.0'
|
|
2098
|
-
|| boundary.resumable !== true
|
|
2099
|
-
|| boundary.reason !== reason
|
|
2100
|
-
|| boundary.publicSafe !== true
|
|
2101
|
-
|| typeof boundary.coolDownUntil !== 'string'
|
|
2102
|
-
|| !Number.isFinite(Date.parse(boundary.coolDownUntil))
|
|
2103
|
-
|| !Number.isSafeInteger(boundary.retryAfterMs)
|
|
2104
|
-
|| boundary.retryAfterMs < 0
|
|
2105
|
-
|| typeof boundary.operationId !== 'string'
|
|
2106
|
-
|| !boundedId.test(boundary.operationId)
|
|
2107
|
-
|| !isRecord(boundary.receipt)
|
|
2108
|
-
|| boundary.receipt.schemaVersion !== 'YoloopSessionRolloverReceipt/1.0'
|
|
2109
|
-
|| typeof boundary.receipt.runId !== 'string'
|
|
2110
|
-
|| !boundedId.test(boundary.receipt.runId)
|
|
2111
|
-
|| boundary.receipt.operationId !== boundary.operationId
|
|
2112
|
-
|| typeof boundary.receipt.idempotencyKey !== 'string'
|
|
2113
|
-
|| !boundedId.test(boundary.receipt.idempotencyKey)
|
|
2114
|
-
|| typeof boundary.receipt.payloadHash !== 'string'
|
|
2115
|
-
|| !/^[a-f0-9]{64}$/.test(boundary.receipt.payloadHash)
|
|
2116
|
-
|| boundary.receipt.coolDownUntil !== boundary.coolDownUntil
|
|
2117
|
-
|| !Number.isSafeInteger(boundary.receipt.revision)
|
|
2118
|
-
|| boundary.receipt.revision < 0
|
|
2119
|
-
|| (boundary.receipt.snapshotHash !== null
|
|
2120
|
-
&& (typeof boundary.receipt.snapshotHash !== 'string'
|
|
2121
|
-
|| !/^[a-f0-9]{64}$/.test(boundary.receipt.snapshotHash)))
|
|
2122
|
-
|| boundary.receipt.status !== 'exhausted'
|
|
2123
|
-
|| boundary.receipt.publicSafe !== true)
|
|
2124
|
-
return undefined;
|
|
2125
|
-
return { coolDownUntil: boundary.coolDownUntil, reason };
|
|
2126
|
-
}
|
|
2127
|
-
function buildChildRunYoloDirective(input) {
|
|
2128
|
-
const stableBasis = `${input.rootAttempt.execution_id}:${input.child.graphRevision ?? 'legacy'}:${input.child.storyId}`;
|
|
2129
|
-
const operationId = input.child.dispatchId ?? headlessExecutionEntityId('child-op', `${stableBasis}:${input.iteration}`);
|
|
2130
|
-
const idempotencyKey = input.child.idempotencyKey ?? headlessExecutionEntityId('child-idem', `${stableBasis}:${input.iteration}`);
|
|
2131
|
-
return {
|
|
2132
|
-
schemaVersion: 1,
|
|
2133
|
-
contractVersion: 'continuity-v1',
|
|
2134
|
-
kind: 'run_yolo',
|
|
2135
|
-
commandClass: input.rootAttempt.command_class === 'goal-tick' ? 'goal-tick' : 'loop-tick',
|
|
2136
|
-
jobId: input.rootAttempt.job_id,
|
|
2137
|
-
operationId,
|
|
2138
|
-
idempotencyKey,
|
|
2139
|
-
targetKind: 'story',
|
|
2140
|
-
targetRef: input.child.targetRef,
|
|
2141
|
-
commandRef: input.child.commandRef,
|
|
2142
|
-
...(input.child.preparationOnly ? { executionMode: 'branchless_child_preparation' } : {}),
|
|
2143
|
-
storyId: input.child.storyId,
|
|
2144
|
-
runtime: {
|
|
2145
|
-
runtimeId: input.runtimeId,
|
|
2146
|
-
...(input.modelId ? { modelId: input.modelId } : {}),
|
|
2147
|
-
source: input.runtimeSource ?? 'explicit',
|
|
2148
|
-
reasonCode: input.runtimeSource === 'fallback' ? HEADLESS_REASON_CODES.RUNTIME_FALLBACK : HEADLESS_REASON_CODES.RUNTIME_EXPLICIT,
|
|
2149
|
-
publicSafe: true,
|
|
2150
|
-
},
|
|
2151
|
-
publicSummary: `Root-owned yoloop delegated public story ${input.child.storyId}.`,
|
|
2152
|
-
reasonCode: HEADLESS_REASON_CODES.OK,
|
|
2153
|
-
metadata: {
|
|
2154
|
-
governanceSource: 'delegated-subagent',
|
|
2155
|
-
parentAttemptId: input.rootAttempt.attempt_id,
|
|
2156
|
-
parentExecutionId: input.rootAttempt.execution_id,
|
|
2157
|
-
iteration: input.iteration,
|
|
2158
|
-
...(input.child.dispatchId ? { dispatchId: input.child.dispatchId } : {}),
|
|
2159
|
-
...(input.child.graphRevision ? { graphRevision: input.child.graphRevision } : {}),
|
|
2160
|
-
...(input.child.writeSet ? { writeSet: input.child.writeSet } : {}),
|
|
2161
|
-
...(input.child.executionBranch ? { executionBranch: input.child.executionBranch } : {}),
|
|
2162
|
-
...(input.child.graphRevision ? {
|
|
2163
|
-
childWorkspace: 'branchless_sandbox',
|
|
2164
|
-
epicCheckout: 'current_checkout',
|
|
2165
|
-
workspaceLifecycle: 'user_managed',
|
|
2166
|
-
integrationOwner: 'root_agent',
|
|
2167
|
-
maxDepth: 1,
|
|
2168
|
-
} : {}),
|
|
2169
|
-
publicSafe: true,
|
|
2170
|
-
},
|
|
2171
|
-
attempts: [],
|
|
2172
|
-
redactionSummary: [redaction('prompt', 'prompt_body', hashPublicValue(input.child.commandRef))],
|
|
2173
|
-
publicSafe: true,
|
|
2174
|
-
};
|
|
2175
|
-
}
|
|
2176
|
-
function persistYoloopAttemptOutcome(store, attempt, outcome) {
|
|
2177
|
-
const hashes = sanitizePublicRecord(outcome.hashes);
|
|
2178
|
-
const workerPoolSummary = outcome.workerPoolSummary ?? defaultWorkerPoolSummary();
|
|
2179
|
-
const counts = sanitizePublicRecord({
|
|
2180
|
-
iterations: outcome.counts.iterations,
|
|
2181
|
-
childCount: outcome.counts.childCount,
|
|
2182
|
-
succeededChildCount: outcome.counts.succeededChildCount,
|
|
2183
|
-
failedChildCount: outcome.counts.failedChildCount,
|
|
2184
|
-
skippedChildCount: outcome.counts.skippedChildCount,
|
|
2185
|
-
metadataCompleteCount: outcome.counts.metadataCompleteCount,
|
|
2186
|
-
metadataAbortedCount: outcome.counts.metadataAbortedCount,
|
|
2187
|
-
serverMaxConcurrency: workerPoolSummary.serverMaxConcurrency,
|
|
2188
|
-
localCap: workerPoolSummary.localCap,
|
|
2189
|
-
queueCap: workerPoolSummary.queueCap,
|
|
2190
|
-
availableLeases: workerPoolSummary.availableLeases,
|
|
2191
|
-
effectiveConcurrency: workerPoolSummary.effectiveConcurrency,
|
|
2192
|
-
peakConcurrency: workerPoolSummary.peakConcurrency,
|
|
2193
|
-
pendingChildCount: workerPoolSummary.pendingChildCount,
|
|
2194
|
-
startedChildCount: workerPoolSummary.startedChildCount,
|
|
2195
|
-
completedChildCount: workerPoolSummary.completedChildCount,
|
|
2196
|
-
backpressurePauseCount: workerPoolSummary.backpressurePauseCount,
|
|
2197
|
-
});
|
|
2198
|
-
const outcomeMetadata = {
|
|
2199
|
-
schemaVersion: 1,
|
|
2200
|
-
contractVersion: 'continuity-v1',
|
|
2201
|
-
attemptId: attempt.attempt_id,
|
|
2202
|
-
executionId: attempt.execution_id,
|
|
2203
|
-
jobId: attempt.job_id,
|
|
2204
|
-
directiveHash: attempt.directive_hash,
|
|
2205
|
-
status: outcome.status,
|
|
2206
|
-
reasonCode: outcome.reasonCode,
|
|
2207
|
-
storyIds: outcome.childStoryIds.slice(0, 50),
|
|
2208
|
-
counts,
|
|
2209
|
-
hashes,
|
|
2210
|
-
...(outcome.reasonCode === AUTONOMOUS_GOVERNANCE_REASON_CODES.BYPASS_BLOCKED ? { governanceEvidence: AUTONOMOUS_GOVERNANCE_EVIDENCE_TAG } : {}),
|
|
2211
|
-
reasonCodes: unique([outcome.reasonCode, ...workerPoolSummary.reasonCodes, ...outcome.stateTransitions]),
|
|
2212
|
-
publicSummary: boundPublicSummary(outcome.publicSummary),
|
|
2213
|
-
...(outcome.terminalClass ? { terminalClass: outcome.terminalClass } : {}),
|
|
2214
|
-
...(outcome.releaseBlocked ? { releaseBlocked: outcome.releaseBlocked } : {}),
|
|
2215
|
-
};
|
|
2216
|
-
const governance = readAutonomousGovernanceEnvelopeFromMetadata(attempt.metadata_json, {
|
|
2217
|
-
autonomousKind: 'run_yoloop',
|
|
2218
|
-
jobId: attempt.job_id,
|
|
2219
|
-
targetKind: 'epic',
|
|
2220
|
-
targetRef: attempt.target_ref,
|
|
2221
|
-
});
|
|
2222
|
-
// Backoff reuses the same attempt row. Preserve only its already-validated,
|
|
2223
|
-
// public-safe authority envelope so the next tick cannot lose authorization
|
|
2224
|
-
// when completion metadata replaces the queued metadata.
|
|
2225
|
-
const metadata = governance.ok
|
|
2226
|
-
? autonomousGovernanceMetadata(governance.envelope, outcomeMetadata)
|
|
2227
|
-
: outcomeMetadata;
|
|
2228
|
-
store.completeHeadlessExecutionAttempt({
|
|
2229
|
-
attemptId: attempt.attempt_id,
|
|
2230
|
-
executionId: attempt.execution_id,
|
|
2231
|
-
jobId: attempt.job_id,
|
|
2232
|
-
leaseId: outcome.leaseId,
|
|
2233
|
-
runnerId: outcome.runnerId,
|
|
2234
|
-
status: outcome.status,
|
|
2235
|
-
completedAt: outcome.completedAt,
|
|
2236
|
-
durationMs: outcome.durationMs,
|
|
2237
|
-
reasonCode: outcome.reasonCode,
|
|
2238
|
-
publicSummary: boundPublicSummary(outcome.publicSummary),
|
|
2239
|
-
notBeforeAt: outcome.notBeforeAt,
|
|
2240
|
-
retryCount: outcome.retryCount,
|
|
2241
|
-
counts,
|
|
2242
|
-
hashes,
|
|
2243
|
-
redactionSummary: outcome.redactionSummary,
|
|
2244
|
-
relativePaths: unique([attempt.target_ref, ...outcome.relativePaths]),
|
|
2245
|
-
metadata,
|
|
2246
|
-
});
|
|
2247
|
-
store.recordHeadlessExecutionReceipt({
|
|
2248
|
-
receiptId: `receipt-${headlessExecutionEntityId('headless-yoloop', `${attempt.attempt_id}-${outcome.status}`)}`,
|
|
2249
|
-
attemptId: attempt.attempt_id,
|
|
2250
|
-
executionId: attempt.execution_id,
|
|
2251
|
-
jobId: attempt.job_id,
|
|
2252
|
-
status: outcome.receiptStatus,
|
|
2253
|
-
reasonCode: outcome.reasonCode,
|
|
2254
|
-
createdAt: outcome.completedAt,
|
|
2255
|
-
operationId: `${attempt.execution_id}:${outcome.status}:receipt`,
|
|
2256
|
-
idempotencyKey: `${attempt.directive_hash}:${outcome.status}:receipt`,
|
|
2257
|
-
counts,
|
|
2258
|
-
hashes,
|
|
2259
|
-
redactionSummary: outcome.redactionSummary,
|
|
2260
|
-
relativePaths: unique([attempt.target_ref, ...outcome.relativePaths]),
|
|
2261
|
-
metadata,
|
|
2262
|
-
});
|
|
2263
|
-
store.recordHeadlessExecutionSummary({
|
|
2264
|
-
eventId: `event-${headlessExecutionEntityId('headless-yoloop-summary', `${attempt.attempt_id}-${outcome.status}`)}`,
|
|
2265
|
-
attemptId: attempt.attempt_id,
|
|
2266
|
-
executionId: attempt.execution_id,
|
|
2267
|
-
jobId: attempt.job_id,
|
|
2268
|
-
status: outcome.status,
|
|
2269
|
-
runtimeId: outcome.runtimeId,
|
|
2270
|
-
modelId: outcome.modelId,
|
|
2271
|
-
publicSummary: boundPublicSummary(outcome.publicSummary),
|
|
2272
|
-
reasonCode: outcome.reasonCode,
|
|
2273
|
-
createdAt: outcome.completedAt,
|
|
2274
|
-
durationMs: outcome.durationMs,
|
|
2275
|
-
counts,
|
|
2276
|
-
hashes,
|
|
2277
|
-
redactionSummary: outcome.redactionSummary,
|
|
2278
|
-
relativePaths: unique([attempt.target_ref, ...outcome.relativePaths]),
|
|
2279
|
-
metadata,
|
|
2280
|
-
});
|
|
2281
|
-
return {
|
|
2282
|
-
attemptId: attempt.attempt_id,
|
|
2283
|
-
executionId: attempt.execution_id,
|
|
2284
|
-
jobId: attempt.job_id,
|
|
2285
|
-
status: outcome.status,
|
|
2286
|
-
outcome: outcome.receiptStatus,
|
|
2287
|
-
reasonCode: outcome.reasonCode,
|
|
2288
|
-
timestamp: outcome.completedAt,
|
|
2289
|
-
childStoryIds: outcome.childStoryIds,
|
|
2290
|
-
aggregateCounts: outcome.counts,
|
|
2291
|
-
workerPoolSummary,
|
|
2292
|
-
redactionSummary: outcome.redactionSummary,
|
|
2293
|
-
...(outcome.terminalClass ? { terminalClass: outcome.terminalClass } : {}),
|
|
2294
|
-
...(outcome.releaseBlocked ? { releaseBlocked: outcome.releaseBlocked } : {}),
|
|
2295
|
-
publicSafe: true,
|
|
2296
|
-
};
|
|
2297
|
-
}
|
|
2298
|
-
function emptyYoloopReceipt(attempt, input) {
|
|
2299
|
-
return {
|
|
2300
|
-
attemptId: attempt.attempt_id,
|
|
2301
|
-
executionId: attempt.execution_id,
|
|
2302
|
-
jobId: attempt.job_id,
|
|
2303
|
-
status: input.status,
|
|
2304
|
-
outcome: input.receiptStatus,
|
|
2305
|
-
reasonCode: input.reasonCode,
|
|
2306
|
-
timestamp: input.timestamp,
|
|
2307
|
-
childStoryIds: [],
|
|
2308
|
-
aggregateCounts: emptyAggregateCounts(),
|
|
2309
|
-
workerPoolSummary: defaultWorkerPoolSummary(),
|
|
2310
|
-
redactionSummary: [],
|
|
2311
|
-
publicSafe: true,
|
|
2312
|
-
};
|
|
2313
|
-
}
|
|
2314
|
-
function retryDecision(attempt, result, maxAttempts, backoffMs, nowIso) {
|
|
2315
|
-
if (!result.retryable)
|
|
2316
|
-
return { retry: false };
|
|
2317
|
-
if (RESUMABLE_YOLOOP_BOUNDARY_REASONS.has(result.reasonCode)) {
|
|
2318
|
-
return {
|
|
2319
|
-
retry: true,
|
|
2320
|
-
// A valid operational boundary is a resumable checkpoint, not a failed
|
|
2321
|
-
// attempt. Preserve the generic failure budget across any number of
|
|
2322
|
-
// server-authorized timeout/per-run successor boundaries.
|
|
2323
|
-
retryCount: attempt.retry_count,
|
|
2324
|
-
notBeforeAt: laterIsoTimestamp(addMilliseconds(nowIso, backoffMs), result.retryNotBeforeAt),
|
|
2325
|
-
};
|
|
2326
|
-
}
|
|
2327
|
-
const retryCount = attempt.retry_count + 1;
|
|
2328
|
-
if (retryCount >= Math.max(1, attempt.max_attempts || maxAttempts))
|
|
2329
|
-
return { retry: false, retryCount };
|
|
2330
|
-
const multiplier = Math.min(8, 2 ** Math.max(0, attempt.retry_count));
|
|
2331
|
-
return {
|
|
2332
|
-
retry: true,
|
|
2333
|
-
retryCount,
|
|
2334
|
-
notBeforeAt: laterIsoTimestamp(addMilliseconds(nowIso, backoffMs * multiplier), result.retryNotBeforeAt),
|
|
2335
|
-
};
|
|
2336
|
-
}
|
|
2337
|
-
function driverResult(input) {
|
|
2338
|
-
return {
|
|
2339
|
-
status: input.status,
|
|
2340
|
-
receiptStatus: input.receiptStatus,
|
|
2341
|
-
reasonCode: input.reasonCode,
|
|
2342
|
-
publicSummary: input.publicSummary,
|
|
2343
|
-
retryable: input.retryable,
|
|
2344
|
-
...(input.retryNotBeforeAt ? { retryNotBeforeAt: input.retryNotBeforeAt } : {}),
|
|
2345
|
-
durationMs: Math.max(0, Date.now() - input.startedAt),
|
|
2346
|
-
counts: input.counts,
|
|
2347
|
-
workerPoolSummary: input.workerPoolSummary ?? defaultWorkerPoolSummary(),
|
|
2348
|
-
hashes: input.hashes,
|
|
2349
|
-
redactionSummary: input.redactions.slice(0, 50),
|
|
2350
|
-
relativePaths: unique(input.relativePaths).slice(0, 50),
|
|
2351
|
-
childStoryIds: unique(input.childStoryIds).slice(0, 50),
|
|
2352
|
-
stateTransitions: unique(input.stateTransitions),
|
|
2353
|
-
...(input.terminalClass ? { terminalClass: input.terminalClass } : {}),
|
|
2354
|
-
...(input.releaseBlocked ? { releaseBlocked: input.releaseBlocked } : {}),
|
|
2355
|
-
};
|
|
2356
|
-
}
|
|
2357
|
-
function validateDirectiveRuntime(value, redactions) {
|
|
2358
|
-
if (value === undefined)
|
|
2359
|
-
return undefined;
|
|
2360
|
-
if (!isRecord(value)) {
|
|
2361
|
-
redactions.push(redaction('runtime', 'unsafe_key', 'value-denied'));
|
|
2362
|
-
return undefined;
|
|
2363
|
-
}
|
|
2364
|
-
for (const key of Object.keys(value)) {
|
|
2365
|
-
if (!RUNTIME_ALLOWED_KEYS.has(key) || UNSAFE_KEY_PATTERN.test(key))
|
|
2366
|
-
redactions.push(redaction(`runtime.${key}`, unsafeKeyReason(key), 'key-denied'));
|
|
2367
|
-
}
|
|
2368
|
-
if (value.publicSafe !== true)
|
|
2369
|
-
redactions.push(redaction('runtime.publicSafe', 'unsafe_key', 'value-denied'));
|
|
2370
|
-
const runtimeId = stringField(value, 'runtimeId');
|
|
2371
|
-
const modelId = stringField(value, 'modelId');
|
|
2372
|
-
const source = stringField(value, 'source');
|
|
2373
|
-
if (runtimeId && (!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,79}$/.test(runtimeId) || UNSAFE_VALUE_PATTERN.test(runtimeId) || SHELL_FRAGMENT_PATTERN.test(runtimeId))) {
|
|
2374
|
-
redactions.push(redaction('runtime.runtimeId', 'unsafe_key', 'value-denied'));
|
|
2375
|
-
}
|
|
2376
|
-
if (modelId && (!/^[A-Za-z0-9][A-Za-z0-9._:+/-]{0,119}$/.test(modelId) || UNSAFE_VALUE_PATTERN.test(modelId) || SHELL_FRAGMENT_PATTERN.test(modelId))) {
|
|
2377
|
-
redactions.push(redaction('runtime.modelId', 'unsafe_key', 'value-denied'));
|
|
2378
|
-
}
|
|
2379
|
-
if (source !== undefined && source !== 'explicit' && source !== 'origin' && source !== 'default' && source !== 'fallback' && source !== 'unspecified') {
|
|
2380
|
-
redactions.push(redaction('runtime.source', 'unsafe_key', 'value-denied'));
|
|
2381
|
-
}
|
|
2382
|
-
if (value.reasonCode !== undefined && (typeof value.reasonCode !== 'string' || UNSAFE_VALUE_PATTERN.test(value.reasonCode))) {
|
|
2383
|
-
redactions.push(redaction('runtime.reasonCode', 'unsafe_key', 'value-denied'));
|
|
2384
|
-
}
|
|
2385
|
-
if (value.publicSafe !== true)
|
|
2386
|
-
return undefined;
|
|
2387
|
-
return {
|
|
2388
|
-
...(runtimeId ? { runtimeId } : {}),
|
|
2389
|
-
...(modelId ? { modelId } : {}),
|
|
2390
|
-
...(source === 'explicit' || source === 'origin' || source === 'default' || source === 'fallback' || source === 'unspecified' ? { source } : {}),
|
|
2391
|
-
...(typeof value.reasonCode === 'string' ? { reasonCode: value.reasonCode } : {}),
|
|
2392
|
-
publicSafe: true,
|
|
2393
|
-
};
|
|
2394
|
-
}
|
|
2395
|
-
function extractExecutionDirectiveCandidates(metadata) {
|
|
2396
|
-
const records = Array.isArray(metadata) ? metadata : metadata ? [metadata] : [];
|
|
2397
|
-
const directives = [];
|
|
2398
|
-
for (const record of records) {
|
|
2399
|
-
const value = record.continuityExecutionDirectives;
|
|
2400
|
-
if (Array.isArray(value))
|
|
2401
|
-
directives.push(...value);
|
|
2402
|
-
}
|
|
2403
|
-
return directives;
|
|
2404
|
-
}
|
|
2405
|
-
function hashDirective(directive) {
|
|
2406
|
-
return hashPublicValue(stableJson({
|
|
2407
|
-
kind: directive.kind,
|
|
2408
|
-
commandClass: directive.commandClass,
|
|
2409
|
-
jobId: directive.jobId,
|
|
2410
|
-
targetRef: directive.targetRef,
|
|
2411
|
-
commandRef: directive.commandRef,
|
|
2412
|
-
epicId: directive.epicId,
|
|
2413
|
-
runtime: directive.runtime,
|
|
2414
|
-
}));
|
|
2415
|
-
}
|
|
2416
|
-
function stableJson(value) {
|
|
2417
|
-
if (Array.isArray(value))
|
|
2418
|
-
return `[${value.map(stableJson).join(',')}]`;
|
|
2419
|
-
if (isRecord(value)) {
|
|
2420
|
-
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(',')}}`;
|
|
2421
|
-
}
|
|
2422
|
-
return JSON.stringify(value);
|
|
2423
|
-
}
|
|
2424
|
-
function assertPublicSafeCandidate(value, path, redactions) {
|
|
2425
|
-
if (typeof value === 'string') {
|
|
2426
|
-
if (UNSAFE_VALUE_PATTERN.test(value) || SHELL_FRAGMENT_PATTERN.test(value))
|
|
2427
|
-
redactions.push(redaction(path, unsafeKeyReason(path), 'value-denied'));
|
|
2428
|
-
return;
|
|
2429
|
-
}
|
|
2430
|
-
if (value === undefined || value === null || typeof value === 'number' || typeof value === 'boolean')
|
|
2431
|
-
return;
|
|
2432
|
-
if (Array.isArray(value)) {
|
|
2433
|
-
value.forEach((item, index) => assertPublicSafeCandidate(item, `${path}.${index}`, redactions));
|
|
2434
|
-
return;
|
|
2435
|
-
}
|
|
2436
|
-
if (isRecord(value)) {
|
|
2437
|
-
for (const [key, child] of Object.entries(value)) {
|
|
2438
|
-
const field = `${path}.${key}`;
|
|
2439
|
-
if (UNSAFE_KEY_PATTERN.test(key))
|
|
2440
|
-
redactions.push(redaction(field, unsafeKeyReason(key), 'key-denied'));
|
|
2441
|
-
assertPublicSafeCandidate(child, field, redactions);
|
|
2442
|
-
}
|
|
2443
|
-
return;
|
|
2444
|
-
}
|
|
2445
|
-
redactions.push(redaction(path, 'unsafe_key', 'value-denied'));
|
|
2446
|
-
}
|
|
2447
|
-
function validateDirectiveRedactions(value, redactions) {
|
|
2448
|
-
if (value === undefined)
|
|
2449
|
-
return [];
|
|
2450
|
-
if (!Array.isArray(value)) {
|
|
2451
|
-
redactions.push(redaction('redactionSummary', 'unsafe_key', 'value-denied'));
|
|
2452
|
-
return [];
|
|
2453
|
-
}
|
|
2454
|
-
const safe = [];
|
|
2455
|
-
for (const [index, item] of value.entries()) {
|
|
2456
|
-
if (!isRecord(item) || item.publicSafe !== true) {
|
|
2457
|
-
redactions.push(redaction(`redactionSummary.${index}`, 'unsafe_key', 'value-denied'));
|
|
2458
|
-
continue;
|
|
2459
|
-
}
|
|
2460
|
-
const field = stringField(item, 'field');
|
|
2461
|
-
const reason = stringField(item, 'reason');
|
|
2462
|
-
const evidence = stringField(item, 'evidence');
|
|
2463
|
-
if (!field || !reason || !evidence || UNSAFE_VALUE_PATTERN.test(field) || UNSAFE_VALUE_PATTERN.test(reason) || UNSAFE_VALUE_PATTERN.test(evidence)) {
|
|
2464
|
-
redactions.push(redaction(`redactionSummary.${index}`, 'unsafe_key', 'value-denied'));
|
|
2465
|
-
continue;
|
|
2466
|
-
}
|
|
2467
|
-
safe.push({ field, reason, evidence, publicSafe: true });
|
|
2468
|
-
}
|
|
2469
|
-
return safe;
|
|
2470
|
-
}
|
|
2471
|
-
function rejectPromptExtraction(reasonCode, publicSummary, redactionSummary) {
|
|
2472
|
-
return { ok: false, reasonCode, publicSummary, redactionSummary };
|
|
2473
|
-
}
|
|
2474
|
-
function safeStringArray(value) {
|
|
2475
|
-
return Array.isArray(value) ? value.filter((item) => typeof item === 'string') : [];
|
|
2476
|
-
}
|
|
2477
|
-
function isSafeExecutionBranch(value) {
|
|
2478
|
-
return value.length > 0 && value.length <= 240 && !value.startsWith('-') && !value.includes('..')
|
|
2479
|
-
&& !value.includes('\\') && /^[A-Za-z0-9._/-]+$/.test(value);
|
|
2480
|
-
}
|
|
2481
|
-
function sameStringSet(left, right) {
|
|
2482
|
-
return left.length === right.length && new Set(left).size === left.length && left.every((item) => right.includes(item));
|
|
2483
|
-
}
|
|
2484
|
-
function safeAttemptRelativePaths(attempt) {
|
|
2485
|
-
return EPIC_TARGET_PATTERN.test(attempt.target_ref) ? [attempt.target_ref] : [];
|
|
2486
|
-
}
|
|
2487
|
-
function sanitizePublicRecord(record) {
|
|
2488
|
-
if (!record)
|
|
2489
|
-
return undefined;
|
|
2490
|
-
const output = {};
|
|
2491
|
-
for (const [key, value] of Object.entries(record)) {
|
|
2492
|
-
if (!/^[A-Za-z0-9_.:-]{1,80}$/.test(key) || UNSAFE_KEY_PATTERN.test(key) || UNSAFE_VALUE_PATTERN.test(key))
|
|
2493
|
-
continue;
|
|
2494
|
-
if (typeof value === 'string' && UNSAFE_VALUE_PATTERN.test(value))
|
|
2495
|
-
continue;
|
|
2496
|
-
output[key] = value;
|
|
2497
|
-
}
|
|
2498
|
-
return Object.keys(output).length > 0 ? output : undefined;
|
|
2499
|
-
}
|
|
2500
|
-
function emptyAggregateCounts() {
|
|
2501
|
-
return aggregateCounts(0, 0, 0, 0, 0, 0, 0);
|
|
2502
|
-
}
|
|
2503
|
-
function aggregateCounts(iterations, childCount, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount) {
|
|
2504
|
-
return { iterations, childCount, succeededChildCount, failedChildCount, skippedChildCount, metadataCompleteCount, metadataAbortedCount };
|
|
2505
|
-
}
|
|
2506
|
-
function storyIdFromTargetRef(targetRef) {
|
|
2507
|
-
return targetRef.replace(/^docs\/stories\//, '').replace(/\.story\.md$/, '');
|
|
2508
|
-
}
|
|
2509
|
-
function epicIdFromTargetRef(targetRef) {
|
|
2510
|
-
return targetRef.replace(/^docs\/epics\/epic-/, '').replace(/\.md$/, '');
|
|
2511
|
-
}
|
|
2512
|
-
function isStoryId(value) {
|
|
2513
|
-
return /^[A-Za-z0-9][A-Za-z0-9_-]*\.\d+[A-Za-z0-9_-]*$/.test(value) && !UNSAFE_VALUE_PATTERN.test(value) && !SHELL_FRAGMENT_PATTERN.test(value);
|
|
2514
|
-
}
|
|
2515
|
-
function normalizeRuntimeSource(value) {
|
|
2516
|
-
if (value === 'explicit' || value === 'origin' || value === 'default' || value === 'fallback')
|
|
2517
|
-
return value;
|
|
2518
|
-
return undefined;
|
|
2519
|
-
}
|
|
2520
|
-
function normalizeStoredRuntimeSource(value) {
|
|
2521
|
-
if (value === 'explicit' || value === 'origin' || value === 'default' || value === 'fallback' || value === 'unspecified')
|
|
2522
|
-
return value;
|
|
2523
|
-
return undefined;
|
|
2524
|
-
}
|
|
2525
|
-
function unsafeKeyReason(key) {
|
|
2526
|
-
if (/prompt|commandRef/i.test(key))
|
|
2527
|
-
return 'prompt_body';
|
|
2528
|
-
if (/std(?:out|err)|raw|log|transcript|stack/i.test(key))
|
|
2529
|
-
return 'raw_log';
|
|
2530
|
-
if (/url/i.test(key))
|
|
2531
|
-
return 'private_url';
|
|
2532
|
-
if (/path|cwd|argv|args|shell|command|binary|executable/i.test(key))
|
|
2533
|
-
return 'executable_path';
|
|
2534
|
-
if (/secret|token|password|authorization|api[_-]?key|license/i.test(key))
|
|
2535
|
-
return 'secret_or_pii';
|
|
2536
|
-
return 'unsafe_key';
|
|
2537
|
-
}
|
|
2538
|
-
function stringField(record, key) {
|
|
2539
|
-
return typeof record[key] === 'string' ? record[key] : undefined;
|
|
2540
|
-
}
|
|
2541
|
-
function isSafeIdentifier(value) {
|
|
2542
|
-
return Boolean(value && SAFE_ID_PATTERN.test(value) && !UNSAFE_VALUE_PATTERN.test(value) && !SHELL_FRAGMENT_PATTERN.test(value));
|
|
2543
|
-
}
|
|
2544
|
-
function isRecord(value) {
|
|
2545
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
2546
|
-
}
|
|
2547
|
-
function defaultHeadlessIdFactory(prefix, attemptId) {
|
|
2548
|
-
return headlessExecutionEntityId(prefix, `${attemptId}-${Date.now()}-${randomBytes(4).toString('hex')}`);
|
|
2549
|
-
}
|
|
2550
|
-
function addMilliseconds(iso, ms) {
|
|
2551
|
-
const base = Date.parse(iso);
|
|
2552
|
-
return new Date((Number.isFinite(base) ? base : Date.now()) + ms).toISOString();
|
|
2553
|
-
}
|
|
2554
|
-
function laterIsoTimestamp(left, right) {
|
|
2555
|
-
const leftMs = Date.parse(left);
|
|
2556
|
-
const rightMs = right ? Date.parse(right) : Number.NaN;
|
|
2557
|
-
if (!Number.isFinite(rightMs))
|
|
2558
|
-
return left;
|
|
2559
|
-
if (!Number.isFinite(leftMs))
|
|
2560
|
-
return right;
|
|
2561
|
-
return rightMs > leftMs ? right : left;
|
|
2562
|
-
}
|
|
2563
|
-
function boundedInteger(value, min, max) {
|
|
2564
|
-
if (!Number.isFinite(value))
|
|
2565
|
-
return min;
|
|
2566
|
-
return Math.max(min, Math.min(max, Math.floor(value)));
|
|
2567
|
-
}
|
|
2568
|
-
function unique(values) {
|
|
2569
|
-
return Array.from(new Set(values));
|
|
2570
|
-
}
|
|
2571
|
-
function uniqueBy(values, key) {
|
|
2572
|
-
const seen = new Set();
|
|
2573
|
-
const output = [];
|
|
2574
|
-
for (const value of values) {
|
|
2575
|
-
const itemKey = key(value);
|
|
2576
|
-
if (seen.has(itemKey))
|
|
2577
|
-
continue;
|
|
2578
|
-
seen.add(itemKey);
|
|
2579
|
-
output.push(value);
|
|
2580
|
-
}
|
|
2581
|
-
return output;
|
|
2582
|
-
}
|
|
10
|
+
`],{cwd:r.projectRoot,stdio:["ignore","pipe","pipe","ipc"],windowsHide:!0});let c,d=0,l=!1;const y=setTimeout(()=>{l=!0,n.kill()},r.timeoutMs),f=m=>{d+=m.length,d>32*1024*1024&&(l=!0,n.kill())};n.stdout?.on("data",f),n.stderr?.on("data",f),n.on("message",m=>{if(c||!_(m)||typeof m.success!="boolean"||Buffer.byteLength(JSON.stringify(m))>32*1024*1024){l=!0,n.kill();return}c=m});const u={success:!1,errorCode:"headless-root-invoke-failed",error:"The isolated root metadata invocation did not complete.",exitCode:1};n.on("error",()=>{l=!0}),n.on("close",m=>{clearTimeout(y),s(m===0&&!l&&c?c:u)}),n.send({modulePath:o,options:e},m=>{m&&(l=!0,n.kill())})})}async function Pt(e,r=vt){const t=Date.now(),a={args:e.args,projectRoot:e.projectRoot,format:"json",platformTarget:"runner",serverUrl:e.serverUrl,strictReadOnly:e.strictReadOnly},o=await r(a,{projectRoot:e.projectRoot,timeoutMs:e.timeoutMs});return{success:o.success,instructions:o.instructions,metadata:o.metadata,error:o.error,errorCode:o.errorCode,exitCode:o.exitCode,durationMs:Date.now()-t,publicSafe:!0}}async function Rr(e){const r=e.adapterRegistry??Ge(),t=F(e.limit??Qe,1,10),a=F(e.leaseMs??ht,1e3,oe.terminalWorkflowMaxDurationMs),o=F(e.staleLeaseAfterMs??tt,0,1440*60*1e3),s=F(e.maxAttempts??et,1,10),n=F(e.localConcurrencyCap??Te(),1,Pe),c=[],d=[],l=e.now(),y=Tt({store:e.store,metadata:e.metadata,nowIso:l,maxAttempts:s,queueCap:e.queueCap});c.push(...y.reasonCodes);const f=e.store.recoverStaleHeadlessExecutionAttempts({nowIso:l,staleAfterMs:o,limit:t*2});f.recoveredAttemptIds.length>0&&(c.push(p.EXECUTION_BACKOFF),f.failedAttemptIds.length>0&&c.push(p.EXECUTION_TIMEOUT));const u=e.store.listDueHeadlessExecutionAttempts({nowIso:e.now(),limit:Math.max(t*5,10)}).filter(m=>m.directive_kind==="run_yoloop").slice(0,t);for(const m of u){const g=await wt({store:e.store,projectRoot:e.projectRoot,runnerId:e.runnerId,attempt:m,registry:r,now:e.now,leaseMs:a,timeoutMs:F(e.timeoutMs??rt,1e3,oe.terminalWorkflowMaxDurationMs),backoffMs:F(e.backoffMs??Je,1e3,36e5),maxAttempts:s,maxIterations:F(e.maxIterations??ft,1,100),maxDurationMs:F(e.maxDurationMs??yt,1e3,oe.terminalWorkflowMaxDurationMs),localConcurrencyCap:n,queueCap:e.queueCap,adapterOptions:e.adapterOptions,runtimeDefaults:e.runtimeDefaults,runtimeFallback:e.runtimeFallback,yoloopInvoker:e.yoloopInvoker??Pt,serverUrl:e.serverUrl,idFactory:e.idFactory??nr,continuousWorkspaceManager:e.continuousWorkspaceManager??st(),terminalGitAdapter:e.terminalGitAdapter??ct(e.projectRoot)});d.push(g),c.push(g.reasonCode,...g.workerPoolSummary.reasonCodes)}return{ok:d.every(m=>m.outcome!=="failed")&&y.rejectedCount===0,enqueuedAttemptCount:y.enqueuedCount,dueAttemptCount:u.length,processedAttemptCount:d.filter(m=>m.outcome!=="ignored").length,recoveredAttemptIds:f.recoveredAttemptIds,receipts:d,reasonCodes:V(c.length>0?c:[p.OK]),publicSafe:!0}}function Tt(e){let r=0,t=0;const a=[];for(const o of Zt(e.metadata)){if(!_(o)||o.kind!=="run_yoloop")continue;const s=Nt(o);if(!s.ok){t+=1,a.push(s.reasonCode);continue}const n=s.directive;if(!e.store.jobExists(n.jobId)){t+=1,a.push(Ee.BYPASS_BLOCKED);continue}const c=Jt(n);if(e.store.hasCompletedHeadlessExecutionDirectiveHash(c)){a.push(p.EXECUTION_COMPLETED);continue}const d=qe({autonomousKind:"run_yoloop",source:"headless-run-yoloop",targetKind:"epic",targetRef:n.targetRef,epicId:n.epicId??se(n.targetRef),jobId:n.jobId,operationSeed:n.operationId,commandHash:x(n.commandRef)}),l=We(e.store,d,e.nowIso,{requireExistingJob:!0});if(!l.ok){t+=1,a.push(l.reasonCode);continue}const y=q("attempt",n.idempotencyKey),f=q("exec",n.operationId),u=e.store.enqueueHeadlessExecutionAttempt({attemptId:y,executionId:f,jobId:n.jobId,directiveHash:c,directiveKind:"run_yoloop",commandClass:n.commandClass,targetKind:"epic",targetRef:n.targetRef,epicId:n.epicId??se(n.targetRef),runtimeId:n.runtime?.runtimeId,modelId:n.runtime?.modelId,runtimeSource:ar(n.runtime?.source),reasonCode:n.reasonCode,publicSummary:n.publicSummary,enqueuedAt:e.nowIso,notBeforeAt:e.nowIso,maxAttempts:e.maxAttempts,queueCap:e.queueCap,operationId:`${n.operationId}:enqueue`,idempotencyKey:n.idempotencyKey,counts:{directives:1},hashes:{directive:c},redactionSummary:n.redactionSummary,relativePaths:[n.targetRef],metadata:Re(d,{schemaVersion:1,contractVersion:"continuity-v1",jobId:n.jobId,operationId:n.operationId,reasonCode:n.reasonCode??p.OK,targetRef:n.targetRef,directiveHash:c})});if(!u.accepted){t+=1,a.push(u.reasonCode??"queue-cap-reached");continue}u.inserted&&(r+=1),a.push(p.OK)}return{enqueuedCount:r,rejectedCount:t,reasonCodes:V(a)}}async function wt(e){const r=e.now(),t=e.idFactory("lease",e.attempt.attempt_id),a=ge(r,e.leaseMs);if(!e.store.claimHeadlessExecutionAttempt({attemptId:e.attempt.attempt_id,leaseId:t,runnerId:e.runnerId,claimedAt:r,leaseExpiresAt:a,reasonCode:p.OK}).inserted)return Wt(e.attempt,{status:e.attempt.status,receiptStatus:"ignored",reasonCode:"lease-conflict",timestamp:r});if(e.store.hasCompletedHeadlessExecutionDirectiveHash(e.attempt.directive_hash,e.attempt.attempt_id))return Ce(e.store,e.attempt,{leaseId:t,runnerId:e.runnerId,status:"skipped",receiptStatus:"ignored",reasonCode:p.EXECUTION_COMPLETED,publicSummary:"Skipped duplicate run_yoloop directive because the directive hash is already completed.",completedAt:e.now(),counts:be(),hashes:{directive:e.attempt.directive_hash},redactionSummary:[],relativePaths:[e.attempt.target_ref],childStoryIds:[],stateTransitions:["start","complete"]});const n=Lt(e);if(!n.ok)return Ce(e.store,e.attempt,{leaseId:t,runnerId:e.runnerId,status:n.status,receiptStatus:n.receiptStatus,reasonCode:n.reasonCode,publicSummary:n.publicSummary,completedAt:e.now(),counts:be(),hashes:{directive:e.attempt.directive_hash},redactionSummary:n.redactionSummary,relativePaths:tr(e.attempt),childStoryIds:[],stateTransitions:["start"]});const c=await xt({...e,prepared:n.input}),d=Gt(e.attempt,c,e.maxAttempts,e.backoffMs,e.now()),l=d.retry?"backoff":c.status,y=d.retry?"deferred":c.receiptStatus,f=d.retry?Rt.has(c.reasonCode)||xe.has(c.reasonCode)?c.reasonCode:p.EXECUTION_BACKOFF:c.reasonCode,u=d.retry?"Headless run_yoloop execution scheduled bounded retry after transient metadata/runtime outcome.":c.publicSummary;return Ce(e.store,e.attempt,{leaseId:t,runnerId:e.runnerId,status:l,receiptStatus:y,reasonCode:f,publicSummary:u,completedAt:e.now(),durationMs:c.durationMs,notBeforeAt:d.notBeforeAt,retryCount:d.retryCount,counts:c.counts,workerPoolSummary:c.workerPoolSummary,hashes:{...c.hashes,directive:e.attempt.directive_hash},redactionSummary:c.redactionSummary,relativePaths:c.relativePaths,childStoryIds:c.childStoryIds,runtimeId:n.input.runtimeId,modelId:n.input.modelId,runtimeSource:n.input.runtimeSource,stateTransitions:c.stateTransitions,terminalClass:c.terminalClass,releaseBlocked:c.releaseBlocked})}async function xt(e){const r=Date.now(),t=["start"],a=new Set,o=[],s=[],n={root:x(e.prepared.rootPrompt)},c=[h("rootPrompt","prompt_body",n.root)];let d=0,l=0,y=0,f=0,u=0,m=0,g,P=!1;const i=Me(e.localConcurrencyCap),E=new Map;let j=!1;const K=new Map,z=new Map,ie=T=>{const b=T.child;n[`child-${b.storyId.replace(/[^A-Za-z0-9_.:-]/g,"-")}`]=T.commandHash,c.push(T.promptRedaction);const M=T.receipt;if(T.terminalFailure){if(T.deferredFailure){K.set(b.storyId,T.terminalFailure),i.backpressurePauseCount+=1;return}K.delete(b.storyId),z.set(b.storyId,T.terminalFailure),a.has(b.storyId)||(a.add(b.storyId),o.push(b.storyId),s.push(b.targetRef),y+=1);return}if(!M||M.outcome==="deferred"){K.set(b.storyId,T.reasonCodes.includes("queue-cap-reached")?p.WORKER_POOL_BACKPRESSURE_PAUSED:M?.reasonCode||p.EXECUTION_BACKOFF),T.reasonCodes.includes("queue-cap-reached")&&(i.backpressurePauseCount+=1);return}K.delete(b.storyId),!a.has(b.storyId)&&(a.add(b.storyId),o.push(b.storyId),s.push(b.targetRef),M.outcome==="failed"?(y+=1,z.set(b.storyId,M.reasonCode||p.EXECUTION_FAILED)):M.outcome==="ignored"?f+=1:l+=1)},X=async()=>{const T=await Promise.race([...E.entries()].map(([b,M])=>M.promise.then(S=>({storyId:b,result:S}))));E.delete(T.storyId),i.completedChildCount+=1,i.pendingChildCount=E.size,ie(T.result)};for(;;){if(d>=e.maxIterations)return t.push("backoff"),O({status:"failed",receiptStatus:"failed",reasonCode:Ot,publicSummary:"Headless yoloop reached the bounded iteration limit before completion metadata.",retryable:!1,startedAt:r,counts:k(d,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});if(Date.now()-r>e.maxDurationMs)return t.push("backoff"),O({status:"failed",receiptStatus:"failed",reasonCode:Et,publicSummary:"Headless yoloop reached the bounded duration limit before completion metadata.",retryable:!1,startedAt:r,counts:k(d,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});t.push("metadata_parse");const T=await e.yoloopInvoker({projectRoot:e.projectRoot,args:e.prepared.rootPrompt,attemptId:e.attempt.attempt_id,executionId:e.attempt.execution_id,jobId:e.attempt.job_id,runnerId:e.runnerId,iteration:d,runtimeId:e.prepared.runtimeId,...e.prepared.modelId?{modelId:e.prepared.modelId}:{},timeoutMs:e.timeoutMs,serverUrl:e.serverUrl});T.durationMs!==void 0&&(n[`iter-${d}`]=x(String(T.durationMs)));const b=T.metadata,M=T.errorCode==="YOLOOP_RELEASE_BLOCKED"||b?.yoloopReleaseBlocked===!0||b?.terminalClass==="release-blocked"||b?.releaseBlocked!==void 0;if(!T.success&&!M)return t.push("backoff"),O({status:"backoff",receiptStatus:"deferred",reasonCode:p.EXECUTION_FAILED,publicSummary:"Headless yoloop root metadata invocation failed with bounded public evidence.",retryable:!0,startedAt:r,counts:k(d,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});const S=Ft(b);if(!S.ok)return t.push("backoff"),O({status:"failed",receiptStatus:"failed",reasonCode:S.reasonCode,publicSummary:S.publicSummary,retryable:!1,startedAt:r,counts:k(d,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:[...c,...S.redactionSummary],relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});const I=Vt(b);if(S.aborted&&I){for(;E.size>0;)await X();return m+=1,t.push("backoff"),O({status:"backoff",receiptStatus:"deferred",reasonCode:I.reason==="YOLOOP_SESSION_TIMEOUT"?"yoloop-session-timeout-resumable":"yoloop-per-run-cap-resumable",publicSummary:"Headless yoloop reached a finite run boundary and scheduled the same queue after cool-down.",retryable:!0,retryNotBeforeAt:I.coolDownUntil,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t})}if((S.releaseBlocked||S.aborted||S.complete||S.replay||S.outcome&&S.outcome!=="selected"&&S.outcome!=="queue_exhausted")&&j&&E.size>0){await X(),d+=1,t.push("reinvoke");continue}if(S.releaseBlocked)return t.push("release_blocked"),O({status:"failed",receiptStatus:"failed",reasonCode:"yoloop-release-blocked",publicSummary:"Headless yoloop stopped at a terminal release-blocked boundary without declaring success.",retryable:!1,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:{...n,releaseBlocked:x(S.releaseBlocked.resultId)},redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t,terminalClass:"release-blocked",releaseBlocked:S.releaseBlocked});const $=_(b?.epicIntegration)?b.epicIntegration:void 0,ee=Array.isArray($?.reasonCodes)?$.reasonCodes.filter(C=>typeof C=="string"):[];if(S.aborted&&b?.abortReason==="epic-integration-checkpoints-incomplete"&&$?.required===!0&&$.ready===!1&&ee.length>0&&ee.every(C=>C==="epic-aggregate-qa-receipt-required"||C==="epic-origin-binding-required"||/^missing-story-checkpoint:[A-Za-z0-9._-]+$/.test(C))&&e.terminalGitAdapter.prepareLifecycleEvidence){t.push("lifecycle_evidence");const C=await e.terminalGitAdapter.prepareLifecycleEvidence({epicId:e.prepared.epicId,nowIso:e.now()});if(!C.ok)return t.push("backoff"),O({status:C.retryEligible?"backoff":"failed",receiptStatus:C.retryEligible?"deferred":"failed",reasonCode:C.reasonCode,publicSummary:"Headless yoloop stopped because physical Git lifecycle evidence could not be produced safely.",retryable:C.retryEligible,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});g=C.terminalAuthority??C.p205Authority,P=!0,d+=1,t.push("reinvoke");continue}if(S.aborted)return m+=1,t.push("aborted"),O({status:"failed",receiptStatus:"failed",reasonCode:kt,publicSummary:"Headless yoloop stopped because public metadata reported an aborted loop.",retryable:!1,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});if(S.outcome&&S.outcome!=="selected"&&S.outcome!=="queue_exhausted")return t.push("backoff"),O({status:"failed",receiptStatus:"failed",reasonCode:`yoloop-${S.outcome}`,publicSummary:"Headless yoloop stopped on a non-executable graph-first continuation outcome.",retryable:!1,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});if(S.replay)return t.push("backoff"),O({status:"backoff",receiptStatus:"deferred",reasonCode:"yoloop-replay-pending",publicSummary:"Headless yoloop observed pending replay authority and did not delegate a second child.",retryable:!0,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});if(S.complete&&j&&K.size>0&&z.size===0)return t.push("backoff"),O({status:"backoff",receiptStatus:"deferred",reasonCode:[...K.values()].sort()[0],publicSummary:"Headless yoloop rejected terminal completion while previously runnable work remained undispatched.",retryable:!0,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});if(S.complete&&j&&z.size>0)return t.push("backoff"),O({status:"failed",receiptStatus:"failed",reasonCode:[...z.values()].sort()[0],publicSummary:"Headless yoloop rejected terminal completion because runnable work failed before an accepted dispatch receipt.",retryable:!1,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});const ce=$t(b);if(ce){if(!P&&e.terminalGitAdapter.prepareLifecycleEvidence){t.push("lifecycle_evidence");const R=await e.terminalGitAdapter.prepareLifecycleEvidence({epicId:e.prepared.epicId,nowIso:e.now()});if(!R.ok)return t.push("backoff"),O({status:R.retryEligible?"backoff":"failed",receiptStatus:R.retryEligible?"deferred":"failed",reasonCode:R.reasonCode,publicSummary:"Headless yoloop stopped because physical Git lifecycle evidence could not be produced safely.",retryable:R.retryEligible,startedAt:r,counts:k(d,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});g=R.terminalAuthority??R.p205Authority,P=!0}t.push("terminal_git");const C=new Date,L=await lt(e.projectRoot,{kind:"continuous",storyId:ce.epicId,sessionId:`${e.runnerId}:${e.attempt.attempt_id}`,idempotencyKey:ce.idempotencyKey,persistent:!1,expiresAt:new Date(C.getTime()+Math.max(e.timeoutMs,e.maxDurationMs)+6e4).toISOString()});if(!L.ok)return t.push("backoff"),O({status:"backoff",receiptStatus:"deferred",reasonCode:L.reasonCode,publicSummary:"Headless yoloop deferred terminal Git while another physical writer retained authority.",retryable:!0,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});let U,H=!1;try{U=await dt(ce,e.terminalGitAdapter,e.now,g)}finally{H=await ut(L.path,L.owner).catch(()=>!1)}if(!H)return t.push("backoff"),O({status:"backoff",receiptStatus:"deferred",reasonCode:"git-lifecycle-integration-lock-release-failed",publicSummary:"Headless yoloop stopped because terminal Git writer ownership could not be released safely.",retryable:!0,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});if(n[`terminal-git-${d}`]=x(`${U.receipt.idempotencyKey}:${U.receipt.physicalStatus}`),!U.ok){const R=U.receipt.retryEligible;return t.push("backoff"),O({status:R?"backoff":"failed",receiptStatus:R?"deferred":"failed",reasonCode:U.reasonCodes[0]??"epic-terminal-git-failed",publicSummary:"Headless yoloop stopped at the epic terminal Git boundary with public-safe retry evidence.",retryable:R,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t})}if(g=void 0,P=!1,S.complete)return u+=1,t.push("complete"),O({status:"completed",receiptStatus:"applied",reasonCode:p.EXECUTION_COMPLETED,publicSummary:"Headless yoloop completed only after fresh root-owned physical Git verification.",retryable:!1,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});d+=1,t.push("reinvoke");continue}if(S.complete)return u+=1,t.push("complete"),O({status:"completed",receiptStatus:"applied",reasonCode:p.EXECUTION_COMPLETED,publicSummary:"Headless yoloop completed after public metadata reported yoloopComplete.",retryable:!1,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});const pe=Yt(b);if(pe){t.push("git_reconciliation");const C=await it(pe,e.terminalGitAdapter,e.now);if(n[`git-reconciliation-${d}`]=x(`${pe.idempotencyKey}:${C.reasonCodes.join(",")}`),!C.ok)return t.push("backoff"),O({status:"backoff",receiptStatus:"deferred",reasonCode:C.reasonCodes[0]??"git-reconciliation-failed",publicSummary:"Headless yoloop paused at a fail-closed Git reconciliation boundary.",retryable:!0,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t})}const N=Bt(b,e.prepared.epicId);if(!N.ok)return t.push("backoff"),O({status:"failed",receiptStatus:"failed",reasonCode:N.reasonCode,publicSummary:N.publicSummary,retryable:!1,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:[...c,...N.redactionSummary],relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});const Ae=N.continuous?void 0:N.prompts.find(C=>a.has(C.storyId));if(Ae)return t.push("backoff"),O({status:"failed",receiptStatus:"failed",reasonCode:p.YOLOOP_ISOLATION_VIOLATION,publicSummary:"Headless yoloop rejected cyclic child story delegation evidence.",retryable:!1,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:[...c,h("storyId","prompt_body",x(Ae.storyId))],relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});if(i.mode=N.mode==="continuous_dag"?"continuous_dag":N.parallelAuthorized?"parallel_wave":"serial",i.serverMaxConcurrency=N.serverMaxConcurrency,N.continuous){j=!0;const C=N.prompts.filter(L=>!a.has(L.storyId)&&!E.has(L.storyId));if(i.pendingChildCount=C.length+E.size,C.length>0){const L=De({store:e.store,nowIso:e.now(),localCap:e.localConcurrencyCap,serverMaxConcurrency:N.serverMaxConcurrency,parallelAuthorized:!0,continuous:!0,eligibleCount:C.length});if(i.queueCap=L.queueCap,i.availableLeases=L.availableLeases,i.effectiveConcurrency=L.effectiveConcurrency,i.reasonCodes.push(L.reasonCode),L.effectiveConcurrency===0&&E.size===0)return i.backpressurePauseCount+=1,t.push("backoff"),O({status:"backoff",receiptStatus:"deferred",reasonCode:p.WORKER_POOL_BACKPRESSURE_PAUSED,publicSummary:"Headless yoloop retained its eligible frontier while physical worker capacity was unavailable.",retryable:!0,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});const U=C.slice(0,L.effectiveConcurrency);t.push("child_story_delegation");for(const H of U)E.set(H.storyId,{child:H,promise:Le({...e,child:H,iteration:d})});i.startedChildCount+=U.length,i.peakConcurrency=Math.max(i.peakConcurrency,E.size),i.pendingChildCount=C.length-U.length+E.size}if(E.size>0)await X();else{if(K.size>0)return t.push("backoff"),O({status:"backoff",receiptStatus:"deferred",reasonCode:[...K.values()].sort()[0],publicSummary:"Headless yoloop retained deferred continuous work for a bounded retry.",retryable:!0,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});if(z.size>0)return t.push("backoff"),O({status:"failed",receiptStatus:"failed",reasonCode:[...z.values()].sort()[0],publicSummary:"Headless yoloop completed independent work and stopped on the remaining failed dependency closure.",retryable:!1,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t})}d+=1,t.push("reinvoke");continue}i.pendingChildCount=N.prompts.length;const te=[...N.prompts];for(;te.length>0;){const C=De({store:e.store,nowIso:e.now(),localCap:e.localConcurrencyCap,serverMaxConcurrency:N.serverMaxConcurrency,parallelAuthorized:N.parallelAuthorized,continuous:!1,eligibleCount:te.length});if(i.queueCap=C.queueCap,i.availableLeases=C.availableLeases,i.effectiveConcurrency=C.effectiveConcurrency,i.reasonCodes.push(C.reasonCode),C.effectiveConcurrency===0)return i.backpressurePauseCount+=1,i.pendingChildCount=te.length,t.push("backoff"),O({status:"backoff",receiptStatus:"deferred",reasonCode:p.WORKER_POOL_BACKPRESSURE_PAUSED,publicSummary:"Headless yoloop paused child workers because bounded queue or lease capacity was unavailable.",retryable:!0,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t});const L=te.splice(0,C.effectiveConcurrency);i.startedChildCount+=L.length,i.peakConcurrency=Math.max(i.peakConcurrency,L.length),i.pendingChildCount=te.length,t.push("child_story_delegation");const U=await Promise.all(L.map(R=>Le({...e,child:R,iteration:d})));i.completedChildCount+=U.length;let H;for(const R of U){const le=R.child;n[`child-${le.storyId.replace(/[^A-Za-z0-9_.:-]/g,"-")}`]=R.commandHash,c.push(R.promptRedaction),o.push(le.storyId),s.push(le.targetRef),a.add(le.storyId);const re=R.receipt;if(!re){R.reasonCodes.includes("queue-cap-reached")?(i.backpressurePauseCount+=1,i.pendingChildCount+=1,i.reasonCodes.push(p.WORKER_POOL_BACKPRESSURE_PAUSED),H??={kind:"deferred",reasonCode:p.WORKER_POOL_BACKPRESSURE_PAUSED}):(y+=1,H??={kind:"missing",reasonCode:p.EXECUTION_FAILED});continue}if(re.outcome==="deferred"){H??={kind:"deferred",reasonCode:p.EXECUTION_BACKOFF};continue}if(re.outcome==="failed"){y+=1,H??={kind:"failed",reasonCode:re.reasonCode||p.EXECUTION_FAILED};continue}re.outcome==="ignored"?f+=1:l+=1}if(H){const R=H.kind==="deferred";return O({status:R?"backoff":"failed",receiptStatus:R?"deferred":"failed",reasonCode:H.reasonCode,publicSummary:H.kind==="missing"?"Headless yoloop child story delegation did not produce a public receipt.":R?"Headless yoloop child story delegated bounded backoff to the root attempt.":"Headless yoloop child story execution failed with public receipt evidence.",retryable:R,startedAt:r,counts:k(d+1,o.length,l,y,f,u,m),workerPoolSummary:A(i),hashes:n,redactions:c,relativePaths:[e.prepared.targetRef,...s],childStoryIds:o,stateTransitions:t})}}d+=1,t.push("reinvoke")}}async function Le(e){const r=e.child.dispatchId?await e.continuousWorkspaceManager.prepare({projectRoot:e.projectRoot,epicId:e.prepared.epicId,storyId:e.child.storyId,targetRef:e.child.targetRef,dispatchId:e.child.dispatchId,executionBranch:e.child.executionBranch??"",graphRevision:e.child.graphRevision??"",authorizedWriteSet:e.child.writeSet??[]}):void 0;if(r&&!r.ok)return{child:e.child,reasonCodes:[r.reasonCode],commandHash:x(e.child.commandRef),promptRedaction:h(`child.${e.child.storyId}`,"prompt_body",x(e.child.commandRef)),terminalFailure:r.reasonCode,deferredFailure:/backpressure|lease-active/.test(r.reasonCode)};const t=e.projectRoot,a=r?.ok?nt(r.value):e.adapterOptions?.commandRunner,o=qt({rootAttempt:e.attempt,child:e.child,iteration:e.iteration,runtimeId:e.prepared.runtimeId,modelId:e.prepared.modelId,runtimeSource:e.prepared.runtimeSource}),s=q("attempt",o.idempotencyKey);let n=!!r;try{const c=await ot({store:e.store,projectRoot:t,runnerId:e.runnerId,now:e.now,metadata:{continuityExecutionDirectives:[o]},adapterRegistry:e.registry,adapterOptions:{...e.adapterOptions,cwd:t,env:{...e.adapterOptions?.env,...r?.ok?{NEOCORTEX_BRANCHLESS_PROJECT_ROOT:r.value.workspacePath,NEOCORTEX_BRANCHLESS_ROOT_AUTHORITY:JSON.stringify(e.child.rootAuthority)}:{}},...a?{commandRunner:a,versionRunner:a}:{}},runtimeDefaults:e.runtimeDefaults,runtimeFallback:e.runtimeFallback,timeoutMs:e.timeoutMs,maxAttempts:1,limit:1,queueCap:e.queueCap,attemptIds:[s],idFactory:e.idFactory}),d=c.receipts.find(l=>l.attemptId===s)??c.receipts[0];if(r?.ok&&d&&d.outcome!=="failed"&&d.outcome!=="deferred"){const l=await e.continuousWorkspaceManager.integrate(r.value,{receiptRefs:[`continuity:${d.attemptId}`],nowIso:d.timestamp});if(!l.ok)return{child:e.child,receipt:d,reasonCodes:[...c.reasonCodes,l.reasonCode],commandHash:x(e.child.commandRef),promptRedaction:h(`child.${e.child.storyId}`,"prompt_body",x(e.child.commandRef)),terminalFailure:l.reasonCode,deferredFailure:/backpressure|graph-revision-stale/.test(l.reasonCode)};n=!1}return{child:e.child,receipt:d,reasonCodes:c.reasonCodes,commandHash:x(e.child.commandRef),promptRedaction:h(`child.${e.child.storyId}`,"prompt_body",x(e.child.commandRef))}}finally{r?.ok&&await e.continuousWorkspaceManager.release(r.value,n)}}function De(e){const r=e.store.collectSnapshotRows({nowIso:e.nowIso,jobLimit:1,staleLeaseLimit:1,receiptLimit:1,eventLimit:1,snapshotLimit:1}),t=Math.max(1,Math.floor(r.queue.capacity)),a=Math.max(0,Math.floor(r.queue.running)-1),o=e.continuous?Math.max(0,Math.floor(r.queue.available)):Math.max(0,Math.min(Math.max(0,e.localCap-a),Math.floor(r.queue.available))),s=e.parallelAuthorized?Math.max(1,Math.floor(e.serverMaxConcurrency)):1,n=Math.max(0,Math.min(e.eligibleCount,s,e.localCap,t,o));return{queueCap:t,availableLeases:o,effectiveConcurrency:n,reasonCode:n===0?p.WORKER_POOL_BACKPRESSURE_PAUSED:(e.parallelAuthorized||e.continuous)&&n>1?p.WORKER_POOL_PARALLEL_ACTIVE:p.WORKER_POOL_SERIAL_FALLBACK}}function Me(e){return{mode:"serial",serverMaxConcurrency:1,localCap:e,queueCap:1,availableLeases:1,effectiveConcurrency:1,peakConcurrency:0,pendingChildCount:0,startedChildCount:0,completedChildCount:0,backpressurePauseCount:0,reasonCodes:[]}}function A(e){return{mode:e.mode,serverMaxConcurrency:Y(e.serverMaxConcurrency),localCap:Y(e.localCap),queueCap:Y(e.queueCap),availableLeases:Y(e.availableLeases),effectiveConcurrency:Y(e.effectiveConcurrency),peakConcurrency:Y(e.peakConcurrency),pendingChildCount:Y(e.pendingChildCount),startedChildCount:Y(e.startedChildCount),completedChildCount:Y(e.completedChildCount),backpressurePauseCount:Y(e.backpressurePauseCount),reasonCodes:V(e.reasonCodes.length>0?e.reasonCodes:[p.WORKER_POOL_SERIAL_FALLBACK]).slice(0,10),publicSafe:!0}}function _e(e=Te()){return A(Me(e))}function Y(e){return Number.isFinite(e)?Math.max(0,Math.min(1e4,Math.floor(e))):0}function Lt(e){const r=ve(e.attempt.metadata_json,{autonomousKind:"run_yoloop",jobId:e.attempt.job_id,targetKind:"epic",targetRef:e.attempt.target_ref});if(!r.ok)return{ok:!1,status:"failed",receiptStatus:"failed",reasonCode:r.reasonCode,publicSummary:r.publicSummary,redactionSummary:r.redactionSummary};const t=Dt(e.attempt);if(!t.ok)return t;const a=Mt(e);if(!a.ok)return{ok:!1,status:"failed",receiptStatus:"failed",reasonCode:a.reasonCode,publicSummary:a.publicSummary,redactionSummary:a.redactionSummary};const o=e.attempt.epic_id??se(e.attempt.target_ref);return{ok:!0,input:{rootPrompt:`*yoloop @${e.attempt.target_ref}`,targetRef:e.attempt.target_ref,epicId:o,runtimeId:a.runtimeId,...a.modelId?{modelId:a.modelId}:{},runtimeSource:a.runtimeSource,publicSafe:!0}}}function Dt(e){const r=[];e.directive_kind!=="run_yoloop"&&r.push(h("directiveKind","unsafe_key","value-denied")),e.target_kind!=="epic"&&r.push(h("targetKind","prompt_body","value-denied")),(!ye.test(e.target_ref)||W.test(e.target_ref)||D.test(e.target_ref))&&r.push(h("targetRef","prompt_body","value-denied"));const t=se(e.target_ref);return e.epic_id&&e.epic_id!==t&&r.push(h("epicId","prompt_body","value-denied")),r.length>0?{ok:!1,status:"failed",receiptStatus:"failed",reasonCode:p.PROMPT_REJECTED,publicSummary:"Headless run_yoloop attempt did not match the canonical public epic prompt shape.",redactionSummary:r}:{ok:!0,input:{rootPrompt:`*yoloop @${e.target_ref}`,targetRef:e.target_ref,epicId:t,runtimeId:"fake",publicSafe:!0}}}function Mt(e){const r=e.runtimeDefaults!==void 0?e.runtimeDefaults:Xe({projectRoot:e.projectRoot});if(_(r)&&r.ok===!1)return{ok:!1,reasonCode:p.RUNTIME_UNTRUSTED,publicSummary:typeof r.publicSummary=="string"?r.publicSummary:"Headless runtime defaults failed public-safety validation.",redactionSummary:Array.isArray(r.redactionSummary)?r.redactionSummary:[]};const t=or(e.attempt.runtime_source)??"explicit",a=e.attempt.runtime_id||e.attempt.model_id?{...e.attempt.runtime_id?{runtimeId:e.attempt.runtime_id}:{},...e.attempt.model_id?{modelId:e.attempt.model_id}:{},source:t,publicSafe:!0}:void 0,o={registry:e.registry,defaults:r,fallback:e.runtimeFallback};a&&(t==="origin"?o.origin=a:t==="default"?o.projectDefault=a:t==="fallback"?o.fallback=a:o.explicit=a);const s=Ze(o);return s.ok?{ok:!0,runtimeId:s.runtimeId,...s.modelId?{modelId:s.modelId}:{},runtimeSource:s.runtimeSource}:{ok:!1,reasonCode:s.reasonCode,publicSummary:s.publicSummary,redactionSummary:s.redactionSummary}}function Nt(e){const r=[];for(const i of Object.keys(e))(!gt.has(i)||ae.test(i))&&r.push(h(i,Q(i),"key-denied"));e.publicSafe!==!0&&r.push(h("publicSafe","unsafe_key","value-denied"));const t=B(e,"kind"),a=B(e,"commandClass"),o=B(e,"jobId"),s=B(e,"operationId"),n=B(e,"idempotencyKey"),c=B(e,"targetKind"),d=B(e,"targetRef"),l=B(e,"commandRef"),y=B(e,"publicSummary"),f=B(e,"epicId");t!=="run_yoloop"&&r.push(h("kind","unsafe_key","value-denied")),a!=="goal-tick"&&a!=="loop-tick"&&r.push(h("commandClass","unsafe_key","value-denied")),Se(o)||r.push(h("jobId","unsafe_key","value-denied")),Se(s)||r.push(h("operationId","unsafe_key","value-denied")),Se(n)||r.push(h("idempotencyKey","unsafe_key","value-denied")),(c!=="epic"||!d||!ye.test(d)||D.test(d))&&r.push(h("targetRef","prompt_body","value-denied"));const u=d?`*yoloop @${d}`:void 0;(!l||l!==u||l.includes("@neocortex")||W.test(l)||D.test(l))&&r.push(h("commandRef","prompt_body","value-denied")),f&&d&&f!==se(d)&&r.push(h("epicId","prompt_body","value-denied")),(!y||y.length>240||D.test(y))&&r.push(h("publicSummary","unbounded_text","value-denied")),e.reasonCode!==void 0&&(typeof e.reasonCode!="string"||D.test(e.reasonCode))&&r.push(h("reasonCode","unsafe_key","value-denied"));const m=Xt(e.runtime,r);e.attempts!==void 0&&ue(e.attempts,"attempts",r),e.metadata!==void 0&&ue(e.metadata,"metadata",r);const g=_(e.metadata)?e.metadata:void 0,P=Qt(e.redactionSummary,r);return r.length>0||t!=="run_yoloop"||!a||!o||!s||!n||!d||!l||!y?{ok:!1,reasonCode:r.some(E=>E.reason==="prompt_body")?p.PROMPT_REJECTED:p.DIRECTIVE_REJECTED,redactionSummary:r}:{ok:!0,directive:{kind:"run_yoloop",commandClass:a,jobId:o,operationId:s,idempotencyKey:n,targetKind:"epic",targetRef:d,commandRef:l,...f?{epicId:f}:{},...m?{runtime:m}:{},publicSummary:y,...typeof e.reasonCode=="string"?{reasonCode:e.reasonCode}:{},...g?{metadata:g}:{},...P.length>0?{redactionSummary:P}:{},publicSafe:!0}}}function Bt(e,r){if(!e)return v(p.YOLOOP_METADATA_INVALID,"Headless yoloop metadata was missing.",[]);const t=Ht(e);if(!t.ok)return t;const a=[],o=_(e.yoloopExecutionPlan)?e.yoloopExecutionPlan:void 0,s=o?w(o.storyIds).filter(G):[],n=o?.version===3&&_(o.scheduler)&&Array.isArray(o.scheduler.nodes)?new Map(o.scheduler.nodes.filter(_).map(u=>[String(u.storyId??""),u])):new Map,c=o?.version===3&&_(o.scheduler)&&typeof o.scheduler.graphRevision=="string"?o.scheduler.graphRevision:void 0,d=o?.version===3&&typeof o.executionBranch=="string"?o.executionBranch:void 0;let l;if(o){const u=Kt(o);if(!u.ok)return u;l=u;for(const g of zt(o)){const P=J(g,r,"execution-plan");if(!P.ok)return P;a.push(Ne(P.prompt,n.get(P.prompt.storyId),c,d))}if(a.length===0)for(const g of s){const P=J(`*yolo @docs/stories/${g}.story.md`,r,"execution-plan");if(!P.ok)return P;a.push(Ne(P.prompt,n.get(P.prompt.storyId),c,d))}const m=jt(e.skillDirectives,a);if(!m.ok)return m}const y=typeof e.nextStoryId=="string"&&G(e.nextStoryId)?e.nextStoryId:void 0;for(const u of o?[]:Array.isArray(e.skillDirectives)?e.skillDirectives:[]){if(!_(u)||u.kind!=="task")continue;const m=w(u.promptTemplates);if(m.length>0){for(const E of m){const j=J(E,r,"task-directive");if(!j.ok)return j;a.push(j.prompt)}continue}const g=typeof u.promptTemplate=="string"?u.promptTemplate:void 0;if(!g)continue;const P=w(u.storyIds).filter(G),i=P.length>0?P:y?[y]:[];if(i.length===0&&he.test(g)){const E=J(g,r,"task-directive");if(!E.ok)return E;a.push(E.prompt);continue}for(const E of i){const j=g.includes("{storyId}")?g.replaceAll("{storyId}",E):g,K=J(j,r,"task-directive");if(!K.ok)return K;a.push(K.prompt)}}if(a.length===0&&y){const u=J(`*yolo @docs/stories/${y}.story.md`,r,"next-story");if(!u.ok)return u;a.push(u.prompt)}const f=sr(a,u=>u.commandRef);if(l?.continuous){if(f.length!==s.length||f.some(u=>u.preparationOnly!==!0||u.source!=="execution-plan"))return v(p.YOLOOP_ISOLATION_VIOLATION,"Headless continuous yoloop rejected an ambiguous or non-preparation child prompt.",[h("promptTemplates","prompt_body","operation-denied")])}else if(f.some(u=>u.preparationOnly===!0))return v(p.YOLOOP_ISOLATION_VIOLATION,"Headless yoloop rejected branchless preparation outside a validated continuous plan.",[h("promptTemplates","prompt_body","operation-denied")]);if(s.length>0){const u=new Set(s);for(const m of f)if(!u.has(m.storyId))return v(p.YOLOOP_ISOLATION_VIOLATION,"Headless yoloop rejected a child prompt outside the server-authorized execution plan.",[h("storyId","prompt_body",x(m.storyId))])}return l?.parallelAuthorized&&!Z(f.map(u=>u.storyId),s)?v(p.YOLOOP_METADATA_INVALID,"Headless yoloop rejected a parallel plan whose executable prompts did not match the selected wave.",[]):f.length===0&&!l?.continuous?v(p.YOLOOP_METADATA_INVALID,"Headless yoloop metadata did not include an authorized per-story child prompt.",[]):{ok:!0,prompts:f,mode:l?.mode??"legacy",serverMaxConcurrency:l?.serverMaxConcurrency??1,parallelAuthorized:l?.parallelAuthorized??!1,continuous:l?.continuous??!1,reasonCodes:[p.OK,l?.parallelAuthorized?p.WORKER_POOL_PARALLEL_ACTIVE:p.WORKER_POOL_SERIAL_FALLBACK]}}function Ne(e,r,t,a){if(!r||!t||!a)return e;const o=Array.isArray(r.writeSet)?w(r.writeSet):[],s=Be(r.childExecutionAuthority,{storyId:e.storyId,invocationPrompt:e.commandRef,authorizedWriteSet:o});return{...e,...typeof r.dispatchId=="string"?{dispatchId:r.dispatchId}:{},...typeof r.idempotencyKey=="string"?{idempotencyKey:r.idempotencyKey}:{},graphRevision:t,executionBranch:a,...o.length>0?{writeSet:o}:{},...s?{rootAuthority:s}:{}}}function Ht(e){const r=[];return e.nextStoryId!==void 0&&ne(e.nextStoryId,"nextStoryId",r),e.yoloopExecutionPlan!==void 0&&ne(e.yoloopExecutionPlan,"yoloopExecutionPlan",r),Array.isArray(e.skillDirectives)&&e.skillDirectives.forEach((t,a)=>{_(t)&&t.kind==="task"&&ne(t,`skillDirectives.${a}`,r)}),r.length>0?v(p.YOLOOP_METADATA_INVALID,"Headless yoloop rejected unsafe public metadata before child delegation.",r):{ok:!0}}function jt(e,r){if(!Array.isArray(e))return{ok:!0};const t=new Set(r.map(a=>a.commandRef));for(const[a,o]of e.entries()){if(!_(o)||o.kind!=="task")continue;const s=typeof o.promptTemplate=="string"?o.promptTemplate:void 0,n=w(o.promptTemplates);if(s==="[REDACTED]"&&o.subagentType==="neocortex"&&typeof o.reasonCode=="string"&&o.reasonCode.startsWith("directive-prompt-")&&n.length===0)continue;const d=[...s?[s]:[],...n];if(o.subagentType!=="neocortex"||d.length===0||d.some(l=>!t.has(l)))return v(p.YOLOOP_ISOLATION_VIOLATION,"Headless yoloop rejected a task directive that conflicted with the server-authorized execution plan.",[h(`skillDirectives.${a}`,"prompt_body","operation-denied")])}return{ok:!0}}function ne(e,r,t){if(typeof e=="string"){if(/\.allowedDebt\.constraints\.\d+$/.test(r)&&St.has(e))return;(D.test(e)||/\0/.test(e))&&t.push(h(r,Q(r),"value-denied"));return}if(!(e==null||typeof e=="number"||typeof e=="boolean")){if(Array.isArray(e)){e.forEach((a,o)=>ne(a,`${r}.${o}`,t));return}if(_(e)){for(const[a,o]of Object.entries(e)){const s=`${r}.${a}`;!(a==="promptTemplate"||a==="promptTemplates"||a==="invocationPrompt"||a==="childPromptKind"||a==="allowMetaTaskPromptInChild"||a==="authorization")&&ae.test(a)&&t.push(h(s,Q(a),"key-denied")),ne(o,s,t)}return}t.push(h(r,"unsafe_key","value-denied"))}}function Kt(e){const r=typeof e.mode=="string"?e.mode:"",t=_(e.isolationPolicy)?e.isolationPolicy:void 0,a=w(e.storyIds);if(e.authorization!=="server_authorized")return v(p.YOLOOP_METADATA_INVALID,"Headless yoloop execution plan was not server-authorized.",[]);if(e.executor!=="root_agent"&&e.executor!=="root_agent_with_child_tasks")return v(p.YOLOOP_METADATA_INVALID,"Headless yoloop execution plan executor was not root-owned.",[]);if(r!=="serial"&&r!=="parallel_wave"&&r!=="continuous_dag"&&r!=="manual")return v(p.YOLOOP_METADATA_INVALID,"Headless yoloop execution plan mode was invalid.",[]);const o=e.version===3&&r==="continuous_dag";if(!Array.isArray(e.storyIds)||!o&&a.length===0||a.length!==e.storyIds.length||a.some(i=>!G(i))||new Set(a).size!==a.length)return v(p.YOLOOP_METADATA_INVALID,"Headless yoloop execution plan story selection was invalid or ambiguous.",[]);if(!t||t.rootOwnsLoop!==!0||t.childPromptKind==="per_story_branchless_preparation_only"&&!o||Object.prototype.hasOwnProperty.call(t,"childExecutionBoundary")&&!o||t.childPromptKind!=="per_story_yolo_only"&&t.childPromptKind!=="per_story_branchless_preparation_only"&&!(t.childPromptKind==="none"&&(r==="serial"&&t.childTaskDelegation==="not_required"||r==="parallel_wave"&&e.executor==="root_agent"&&t.childTaskDelegation==="forbidden"))||t.allowOuterYoloopInChild!==!1||t.allowMetaTaskPromptInChild!==!1)return v(p.YOLOOP_ISOLATION_VIOLATION,"Headless yoloop rejected an execution plan that did not preserve root-owned child isolation.",[h("isolationPolicy","prompt_body","value-denied")]);const s=Array.isArray(e.skippedStories)?e.skippedStories:[];for(const i of s){if(!_(i)||typeof i.storyId!="string"||!G(i.storyId)||typeof i.reason!="string")return v(p.YOLOOP_METADATA_INVALID,"Headless yoloop skipped-story evidence was malformed.",[]);if(a.includes(i.storyId))return v(p.YOLOOP_METADATA_INVALID,"Headless yoloop selected a story that server evidence marked skipped.",[])}if(o){const i=_(e.scheduler)?e.scheduler:void 0,E=Array.isArray(i?.nodes)?i.nodes.filter(_):[],j=w(i?.readyStoryIds),K=w(i?.runningStoryIds),z=w(e.promptTemplates),ie=_(e.dependencyBasis)?e.dependencyBasis:void 0,X=_(e.readinessBasis)?e.readinessBasis:void 0,T=typeof i?.graphRevision=="string"?i.graphRevision:"",b=typeof e.executionBranch=="string"?e.executionBranch:"",M=E.map(I=>typeof I.storyId=="string"?I.storyId:""),S=E.find(I=>{const $=typeof I.storyId=="string"?I.storyId:"",ee=typeof I.promptTemplate=="string"?I.promptTemplate:"",de=Array.isArray(I.writeSet)?w(I.writeSet):[];return!G($)||ee!==`*yolo @docs/stories/${$}.story.md branchless-preparation`||typeof I.dispatchId!="string"||!/^[a-f0-9]{64}$/.test(I.dispatchId)||typeof I.idempotencyKey!="string"||!/^[a-f0-9]{64}$/.test(I.idempotencyKey)||I.dependencyBasis!=="verified"||!Array.isArray(I.dependencies)||w(I.dependencies).length!==I.dependencies.length||!Array.isArray(I.writeSet)||de.length===0||de.length!==I.writeSet.length||!Be(I.childExecutionAuthority,{storyId:$,invocationPrompt:ee,authorizedWriteSet:de})});return e.executor!=="root_agent_with_child_tasks"||e.legacyConcurrencyIgnored!==!0||Object.prototype.hasOwnProperty.call(e,"maxConcurrency")||Object.prototype.hasOwnProperty.call(e,"maxParallel")||t?.rootOwnedScheduling!=="continuous_dag_allowed"||t?.childPromptKind!=="per_story_branchless_preparation_only"||t?.childExecutionBoundary!=="filesystem_only"||t?.childTaskDelegation!=="allowed"||t?.maxDepth!==1||t?.childWorkspace!=="branchless_sandbox"||t?.epicCheckout!=="current_checkout"||t?.workspaceLifecycle!=="user_managed"||t?.integrationOwner!=="root_agent"||!i||i.schemaVersion!==1||i.strategy!=="continuous-event-driven-dag"||i.logicalConcurrency!=="ready-set"||i.capacityPolicy!=="backpressure-only"||i.rootOwnsLoop!==!0||i.maxDepth!==1||!/^[a-f0-9]{64}$/.test(T)||!er(b)||new Set(M).size!==M.length||M.some(I=>!G(I))||j.some(I=>!M.includes(I))||K.some(I=>!M.includes(I)||j.includes(I))||!Z(a,j)||z.length!==a.length||z.some((I,$)=>I!==`*yolo @docs/stories/${a[$]}.story.md branchless-preparation`)||!ie||ie.source!=="state_snapshot"||!X||X.source!=="ready_wave"||!Z(w(X.selectedStoryIds),a)||S?v(p.YOLOOP_METADATA_INVALID,"Headless yoloop rejected an invalid continuous DAG execution plan.",[]):{ok:!0,mode:"continuous_dag",serverMaxConcurrency:a.length,parallelAuthorized:!0,continuous:!0}}if(e.version===2){const i=at(e);return i.ok?{ok:!0,mode:"parallel_wave",serverMaxConcurrency:i.childExecutionConcurrency,parallelAuthorized:!1,continuous:!1}:v(p.YOLOOP_METADATA_INVALID,"Headless yoloop rejected an unsafe phased execution plan.",[])}if(r!=="parallel_wave")return{ok:!0,mode:r,serverMaxConcurrency:1,parallelAuthorized:!1,continuous:!1};const n=e.maxConcurrency,c=e.maxParallel,d=_(e.dependencyBasis)?e.dependencyBasis:void 0,l=_(e.readinessBasis)?e.readinessBasis:void 0,y=Array.isArray(e.parallelWaves)?e.parallelWaves:[],f=y.length===1&&_(y[0])?y[0]:void 0;if(t.rootOwnedScheduling!=="parallel_wave_allowed"||!Number.isInteger(n)||typeof n!="number"||n<2||n>a.length||!Number.isInteger(c)||c!==n||!d||d.source!=="state_snapshot"||!Z(w(d.storyIds),a)||!l||l.source!=="ready_wave"||!Z(w(l.selectedStoryIds),a)||!f||!Z(w(f.storyIds),a)||f.maxConcurrency!==n)return v(p.YOLOOP_METADATA_INVALID,"Headless yoloop parallel plan lacked consistent bounded authorization and readiness evidence.",[]);const u=w(f.promptTemplates);if(u.length!==a.length||new Set(u).size!==u.length)return v(p.YOLOOP_METADATA_INVALID,"Headless yoloop parallel wave prompts were incomplete or ambiguous.",[]);const g=(Array.isArray(f.proofSummaries)?f.proofSummaries:Array.isArray(e.proofSummaries)?e.proofSummaries:[]).find(i=>_(i)&&Z(w(i.storyIds),a));return!_(g)||g.dependencyClosure!=="resolved"||g.contractOwnership!=="non_overlapping"||g.validationSurfaces!=="compatible"?v(p.YOLOOP_METADATA_INVALID,"Headless yoloop parallel plan lacked resolved independence proof.",[]):s.find(i=>_(i)&&typeof i.reason=="string"&&/(cycle|unresolved|ambiguous)/i.test(i.reason))?v(p.YOLOOP_METADATA_INVALID,"Headless yoloop parallel plan contained unresolved dependency evidence.",[]):{ok:!0,mode:"parallel_wave",serverMaxConcurrency:n,parallelAuthorized:!0,continuous:!1}}function Be(e,r){if(!_(e)||!_(e.artifact))return;const t=e.artifact,a=Array.isArray(e.authorizedWriteSet)?w(e.authorizedWriteSet):[];if(Object.keys(e).sort().join("\0")!==["artifact","authorizedWriteSet","effectScope","invocationPrompt","kind","lifecycleAuthority","publicSafe","schemaVersion","storyId"].sort().join("\0")||Object.keys(t).sort().join("\0")!==["content","contentBinding","kind","path","schemaVersion"].sort().join("\0")||e.schemaVersion!==1||e.kind!=="branchless_story_preparation"||e.storyId!==r.storyId||e.invocationPrompt!==r.invocationPrompt||!Array.isArray(e.authorizedWriteSet)||a.length!==e.authorizedWriteSet.length||a.some(s=>pt(s)!==s)||!Ut(a,r.authorizedWriteSet)||e.effectScope!=="filesystem_only"||e.lifecycleAuthority!=="root_only"||e.publicSafe!==!0||t.schemaVersion!==1||t.kind!=="branchless_root_bound_artifact"||typeof t.path!="string"||!a.includes(t.path)||typeof t.content!="string"||t.content.length===0||t.content.length>4096||typeof t.contentBinding!="string"||!/^[a-f0-9]{64}$/.test(t.contentBinding))return;const o=Ke("sha256").update(["branchless-root-bound-artifact-v1",r.storyId,r.invocationPrompt,...a,"filesystem_only","root_only",t.path,t.content].join("\0")).digest("hex");if(t.contentBinding===o)return e}function Ut(e,r){return e.length===r.length&&e.every((t,a)=>t===r[a])}function zt(e){const r=[];r.push(...w(e.promptTemplates));for(const t of Array.isArray(e.serialSteps)?e.serialSteps:[])_(t)&&typeof t.promptTemplate=="string"&&r.push(t.promptTemplate);for(const t of Array.isArray(e.parallelWaves)?e.parallelWaves:[])_(t)&&r.push(...w(t.promptTemplates));return r}function J(e,r,t){if(we(e))return v(p.YOLOOP_ISOLATION_VIOLATION,"Headless yoloop rejected an unsafe child prompt shape.",[h("promptTemplate","prompt_body",x(e))]);if(!he.test(e))return v(p.YOLOOP_METADATA_INVALID,"Headless yoloop child prompt did not match the canonical per-story yolo shape.",[h("promptTemplate","prompt_body",x(e))]);const a=Ct.test(e),o=e.replace(/^\*yolo @/,"").replace(/ branchless-preparation$/,""),s=rr(o);return!_t.test(o)||!G(s)||!s.startsWith(`${r}.`)?v(p.YOLOOP_ISOLATION_VIOLATION,"Headless yoloop rejected a child prompt outside the targeted public epic.",[h("storyId","prompt_body",x(s))]):{ok:!0,prompt:{storyId:s,targetRef:o,commandRef:e,source:t,...a?{preparationOnly:!0}:{}}}}function $t(e){const r=e?.epicTerminalGitDirective;if(!(!_(r)||r.schemaVersion!==1||r.kind!=="epic_terminal_git"||typeof r.epicId!="string"||typeof r.executionBranch!="string"||typeof r.originBranch!="string"||typeof r.expectedExecutionHeadSha!="string"||!Array.isArray(r.storyCheckpointIds)||!_(r.localGates)||r.localGates.passed!==!0||!Array.isArray(r.localGates.receiptRefs)||!_(r.reconcile)||typeof r.idempotencyKey!="string"||r.publicSafe!==!0))return r}function Yt(e){const r=e?.epicGitReconciliationDirective;if(!(!_(r)||r.schemaVersion!==1||r.kind!=="epic_git_reconciliation"||typeof r.epicId!="string"||typeof r.executionBranch!="string"||typeof r.originBranch!="string"||!["start","resume","audit"].includes(String(r.lifecycleBoundary))||typeof r.dryRun!="boolean"||typeof r.idempotencyKey!="string"||r.publicSafe!==!0))return r}function Ft(e){if(!e||!_(e))return{ok:!1,reasonCode:p.YOLOOP_METADATA_INVALID,publicSummary:"Headless yoloop root invocation did not return public metadata.",redactionSummary:[]};const r=_(e.yoloopContinuationDecision)?e.yoloopContinuationDecision:void 0,t=typeof r?.outcome=="string"?r.outcome:void 0,a=t==="queue_exhausted"||e.yoloopComplete===!0,o=e.yoloopAborted===!0,s=mt(e.releaseBlocked),n=t==="selected"&&r?.replay===!0;return t&&!["selected","queue_exhausted","blocked","cycle","invalid","no_progress"].includes(t)?{ok:!1,reasonCode:p.YOLOOP_METADATA_INVALID,publicSummary:"Headless yoloop rejected an unknown continuation outcome.",redactionSummary:[]}:t==="queue_exhausted"&&r?.terminalSuccess!==!0?{ok:!1,reasonCode:p.YOLOOP_METADATA_INVALID,publicSummary:"Headless yoloop rejected inconsistent queue exhaustion metadata.",redactionSummary:[]}:a&&o?{ok:!1,reasonCode:p.YOLOOP_METADATA_INVALID,publicSummary:"Headless yoloop metadata reported mutually exclusive terminal states.",redactionSummary:[h("yoloopTerminal","unsafe_key","value-denied")]}:(e.yoloopReleaseBlocked===!0||e.terminalClass==="release-blocked"||e.releaseBlocked!==void 0)&&(!s||e.yoloopReleaseBlocked!==!0||e.terminalClass!=="release-blocked"||a||o||t!==void 0)?{ok:!1,reasonCode:p.YOLOOP_METADATA_INVALID,publicSummary:"Headless yoloop rejected inconsistent release-blocked terminal metadata.",redactionSummary:[]}:{ok:!0,complete:a,aborted:o,...s?{releaseBlocked:s}:{},outcome:t,replay:n}}function Vt(e){if(!e)return;const r=e.abortReason;if(r!=="YOLOOP_PER_RUN_CAP_REACHED"&&r!=="YOLOOP_SESSION_TIMEOUT")return;const t=e.yoloopResumableBoundary,a=/^[A-Za-z0-9._:-]{1,128}$/;if(!(!_(t)||t.schemaVersion!=="YoloopResumableBoundary/1.0"||t.resumable!==!0||t.reason!==r||t.publicSafe!==!0||typeof t.coolDownUntil!="string"||!Number.isFinite(Date.parse(t.coolDownUntil))||!Number.isSafeInteger(t.retryAfterMs)||t.retryAfterMs<0||typeof t.operationId!="string"||!a.test(t.operationId)||!_(t.receipt)||t.receipt.schemaVersion!=="YoloopSessionRolloverReceipt/1.0"||typeof t.receipt.runId!="string"||!a.test(t.receipt.runId)||t.receipt.operationId!==t.operationId||typeof t.receipt.idempotencyKey!="string"||!a.test(t.receipt.idempotencyKey)||typeof t.receipt.payloadHash!="string"||!/^[a-f0-9]{64}$/.test(t.receipt.payloadHash)||t.receipt.coolDownUntil!==t.coolDownUntil||!Number.isSafeInteger(t.receipt.revision)||t.receipt.revision<0||t.receipt.snapshotHash!==null&&(typeof t.receipt.snapshotHash!="string"||!/^[a-f0-9]{64}$/.test(t.receipt.snapshotHash))||t.receipt.status!=="exhausted"||t.receipt.publicSafe!==!0))return{coolDownUntil:t.coolDownUntil,reason:r}}function qt(e){const r=`${e.rootAttempt.execution_id}:${e.child.graphRevision??"legacy"}:${e.child.storyId}`,t=e.child.dispatchId??q("child-op",`${r}:${e.iteration}`),a=e.child.idempotencyKey??q("child-idem",`${r}:${e.iteration}`);return{schemaVersion:1,contractVersion:"continuity-v1",kind:"run_yolo",commandClass:e.rootAttempt.command_class==="goal-tick"?"goal-tick":"loop-tick",jobId:e.rootAttempt.job_id,operationId:t,idempotencyKey:a,targetKind:"story",targetRef:e.child.targetRef,commandRef:e.child.commandRef,...e.child.preparationOnly?{executionMode:"branchless_child_preparation"}:{},storyId:e.child.storyId,runtime:{runtimeId:e.runtimeId,...e.modelId?{modelId:e.modelId}:{},source:e.runtimeSource??"explicit",reasonCode:e.runtimeSource==="fallback"?p.RUNTIME_FALLBACK:p.RUNTIME_EXPLICIT,publicSafe:!0},publicSummary:`Root-owned yoloop delegated public story ${e.child.storyId}.`,reasonCode:p.OK,metadata:{governanceSource:"delegated-subagent",parentAttemptId:e.rootAttempt.attempt_id,parentExecutionId:e.rootAttempt.execution_id,iteration:e.iteration,...e.child.dispatchId?{dispatchId:e.child.dispatchId}:{},...e.child.graphRevision?{graphRevision:e.child.graphRevision}:{},...e.child.writeSet?{writeSet:e.child.writeSet}:{},...e.child.executionBranch?{executionBranch:e.child.executionBranch}:{},...e.child.graphRevision?{childWorkspace:"branchless_sandbox",epicCheckout:"current_checkout",workspaceLifecycle:"user_managed",integrationOwner:"root_agent",maxDepth:1}:{},publicSafe:!0},attempts:[],redactionSummary:[h("prompt","prompt_body",x(e.child.commandRef))],publicSafe:!0}}function Ce(e,r,t){const a=He(t.hashes),o=t.workerPoolSummary??_e(),s=He({iterations:t.counts.iterations,childCount:t.counts.childCount,succeededChildCount:t.counts.succeededChildCount,failedChildCount:t.counts.failedChildCount,skippedChildCount:t.counts.skippedChildCount,metadataCompleteCount:t.counts.metadataCompleteCount,metadataAbortedCount:t.counts.metadataAbortedCount,serverMaxConcurrency:o.serverMaxConcurrency,localCap:o.localCap,queueCap:o.queueCap,availableLeases:o.availableLeases,effectiveConcurrency:o.effectiveConcurrency,peakConcurrency:o.peakConcurrency,pendingChildCount:o.pendingChildCount,startedChildCount:o.startedChildCount,completedChildCount:o.completedChildCount,backpressurePauseCount:o.backpressurePauseCount}),n={schemaVersion:1,contractVersion:"continuity-v1",attemptId:r.attempt_id,executionId:r.execution_id,jobId:r.job_id,directiveHash:r.directive_hash,status:t.status,reasonCode:t.reasonCode,storyIds:t.childStoryIds.slice(0,50),counts:s,hashes:a,...t.reasonCode===Ee.BYPASS_BLOCKED?{governanceEvidence:Ve}:{},reasonCodes:V([t.reasonCode,...o.reasonCodes,...t.stateTransitions]),publicSummary:me(t.publicSummary),...t.terminalClass?{terminalClass:t.terminalClass}:{},...t.releaseBlocked?{releaseBlocked:t.releaseBlocked}:{}},c=ve(r.metadata_json,{autonomousKind:"run_yoloop",jobId:r.job_id,targetKind:"epic",targetRef:r.target_ref}),d=c.ok?Re(c.envelope,n):n;return e.completeHeadlessExecutionAttempt({attemptId:r.attempt_id,executionId:r.execution_id,jobId:r.job_id,leaseId:t.leaseId,runnerId:t.runnerId,status:t.status,completedAt:t.completedAt,durationMs:t.durationMs,reasonCode:t.reasonCode,publicSummary:me(t.publicSummary),notBeforeAt:t.notBeforeAt,retryCount:t.retryCount,counts:s,hashes:a,redactionSummary:t.redactionSummary,relativePaths:V([r.target_ref,...t.relativePaths]),metadata:d}),e.recordHeadlessExecutionReceipt({receiptId:`receipt-${q("headless-yoloop",`${r.attempt_id}-${t.status}`)}`,attemptId:r.attempt_id,executionId:r.execution_id,jobId:r.job_id,status:t.receiptStatus,reasonCode:t.reasonCode,createdAt:t.completedAt,operationId:`${r.execution_id}:${t.status}:receipt`,idempotencyKey:`${r.directive_hash}:${t.status}:receipt`,counts:s,hashes:a,redactionSummary:t.redactionSummary,relativePaths:V([r.target_ref,...t.relativePaths]),metadata:d}),e.recordHeadlessExecutionSummary({eventId:`event-${q("headless-yoloop-summary",`${r.attempt_id}-${t.status}`)}`,attemptId:r.attempt_id,executionId:r.execution_id,jobId:r.job_id,status:t.status,runtimeId:t.runtimeId,modelId:t.modelId,publicSummary:me(t.publicSummary),reasonCode:t.reasonCode,createdAt:t.completedAt,durationMs:t.durationMs,counts:s,hashes:a,redactionSummary:t.redactionSummary,relativePaths:V([r.target_ref,...t.relativePaths]),metadata:d}),{attemptId:r.attempt_id,executionId:r.execution_id,jobId:r.job_id,status:t.status,outcome:t.receiptStatus,reasonCode:t.reasonCode,timestamp:t.completedAt,childStoryIds:t.childStoryIds,aggregateCounts:t.counts,workerPoolSummary:o,redactionSummary:t.redactionSummary,...t.terminalClass?{terminalClass:t.terminalClass}:{},...t.releaseBlocked?{releaseBlocked:t.releaseBlocked}:{},publicSafe:!0}}function Wt(e,r){return{attemptId:e.attempt_id,executionId:e.execution_id,jobId:e.job_id,status:r.status,outcome:r.receiptStatus,reasonCode:r.reasonCode,timestamp:r.timestamp,childStoryIds:[],aggregateCounts:be(),workerPoolSummary:_e(),redactionSummary:[],publicSafe:!0}}function Gt(e,r,t,a,o){if(!r.retryable)return{retry:!1};if(xe.has(r.reasonCode))return{retry:!0,retryCount:e.retry_count,notBeforeAt:je(ge(o,a),r.retryNotBeforeAt)};const s=e.retry_count+1;if(s>=Math.max(1,e.max_attempts||t))return{retry:!1,retryCount:s};const n=Math.min(8,2**Math.max(0,e.retry_count));return{retry:!0,retryCount:s,notBeforeAt:je(ge(o,a*n),r.retryNotBeforeAt)}}function O(e){return{status:e.status,receiptStatus:e.receiptStatus,reasonCode:e.reasonCode,publicSummary:e.publicSummary,retryable:e.retryable,...e.retryNotBeforeAt?{retryNotBeforeAt:e.retryNotBeforeAt}:{},durationMs:Math.max(0,Date.now()-e.startedAt),counts:e.counts,workerPoolSummary:e.workerPoolSummary??_e(),hashes:e.hashes,redactionSummary:e.redactions.slice(0,50),relativePaths:V(e.relativePaths).slice(0,50),childStoryIds:V(e.childStoryIds).slice(0,50),stateTransitions:V(e.stateTransitions),...e.terminalClass?{terminalClass:e.terminalClass}:{},...e.releaseBlocked?{releaseBlocked:e.releaseBlocked}:{}}}function Xt(e,r){if(e===void 0)return;if(!_(e)){r.push(h("runtime","unsafe_key","value-denied"));return}for(const s of Object.keys(e))(!At.has(s)||ae.test(s))&&r.push(h(`runtime.${s}`,Q(s),"key-denied"));e.publicSafe!==!0&&r.push(h("runtime.publicSafe","unsafe_key","value-denied"));const t=B(e,"runtimeId"),a=B(e,"modelId"),o=B(e,"source");if(t&&(!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,79}$/.test(t)||D.test(t)||W.test(t))&&r.push(h("runtime.runtimeId","unsafe_key","value-denied")),a&&(!/^[A-Za-z0-9][A-Za-z0-9._:+/-]{0,119}$/.test(a)||D.test(a)||W.test(a))&&r.push(h("runtime.modelId","unsafe_key","value-denied")),o!==void 0&&o!=="explicit"&&o!=="origin"&&o!=="default"&&o!=="fallback"&&o!=="unspecified"&&r.push(h("runtime.source","unsafe_key","value-denied")),e.reasonCode!==void 0&&(typeof e.reasonCode!="string"||D.test(e.reasonCode))&&r.push(h("runtime.reasonCode","unsafe_key","value-denied")),e.publicSafe===!0)return{...t?{runtimeId:t}:{},...a?{modelId:a}:{},...o==="explicit"||o==="origin"||o==="default"||o==="fallback"||o==="unspecified"?{source:o}:{},...typeof e.reasonCode=="string"?{reasonCode:e.reasonCode}:{},publicSafe:!0}}function Zt(e){const r=Array.isArray(e)?e:e?[e]:[],t=[];for(const a of r){const o=a.continuityExecutionDirectives;Array.isArray(o)&&t.push(...o)}return t}function Jt(e){return x(Ie({kind:e.kind,commandClass:e.commandClass,jobId:e.jobId,targetRef:e.targetRef,commandRef:e.commandRef,epicId:e.epicId,runtime:e.runtime}))}function Ie(e){return Array.isArray(e)?`[${e.map(Ie).join(",")}]`:_(e)?`{${Object.keys(e).sort().map(r=>`${JSON.stringify(r)}:${Ie(e[r])}`).join(",")}}`:JSON.stringify(e)}function ue(e,r,t){if(typeof e=="string"){(D.test(e)||W.test(e))&&t.push(h(r,Q(r),"value-denied"));return}if(!(e==null||typeof e=="number"||typeof e=="boolean")){if(Array.isArray(e)){e.forEach((a,o)=>ue(a,`${r}.${o}`,t));return}if(_(e)){for(const[a,o]of Object.entries(e)){const s=`${r}.${a}`;ae.test(a)&&t.push(h(s,Q(a),"key-denied")),ue(o,s,t)}return}t.push(h(r,"unsafe_key","value-denied"))}}function Qt(e,r){if(e===void 0)return[];if(!Array.isArray(e))return r.push(h("redactionSummary","unsafe_key","value-denied")),[];const t=[];for(const[a,o]of e.entries()){if(!_(o)||o.publicSafe!==!0){r.push(h(`redactionSummary.${a}`,"unsafe_key","value-denied"));continue}const s=B(o,"field"),n=B(o,"reason"),c=B(o,"evidence");if(!s||!n||!c||D.test(s)||D.test(n)||D.test(c)){r.push(h(`redactionSummary.${a}`,"unsafe_key","value-denied"));continue}t.push({field:s,reason:n,evidence:c,publicSafe:!0})}return t}function v(e,r,t){return{ok:!1,reasonCode:e,publicSummary:r,redactionSummary:t}}function w(e){return Array.isArray(e)?e.filter(r=>typeof r=="string"):[]}function er(e){return e.length>0&&e.length<=240&&!e.startsWith("-")&&!e.includes("..")&&!e.includes("\\")&&/^[A-Za-z0-9._/-]+$/.test(e)}function Z(e,r){return e.length===r.length&&new Set(e).size===e.length&&e.every(t=>r.includes(t))}function tr(e){return ye.test(e.target_ref)?[e.target_ref]:[]}function He(e){if(!e)return;const r={};for(const[t,a]of Object.entries(e))!/^[A-Za-z0-9_.:-]{1,80}$/.test(t)||ae.test(t)||D.test(t)||typeof a=="string"&&D.test(a)||(r[t]=a);return Object.keys(r).length>0?r:void 0}function be(){return k(0,0,0,0,0,0,0)}function k(e,r,t,a,o,s,n){return{iterations:e,childCount:r,succeededChildCount:t,failedChildCount:a,skippedChildCount:o,metadataCompleteCount:s,metadataAbortedCount:n}}function rr(e){return e.replace(/^docs\/stories\//,"").replace(/\.story\.md$/,"")}function se(e){return e.replace(/^docs\/epics\/epic-/,"").replace(/\.md$/,"")}function G(e){return/^[A-Za-z0-9][A-Za-z0-9_-]*\.\d+[A-Za-z0-9_-]*$/.test(e)&&!D.test(e)&&!W.test(e)}function or(e){if(e==="explicit"||e==="origin"||e==="default"||e==="fallback")return e}function ar(e){if(e==="explicit"||e==="origin"||e==="default"||e==="fallback"||e==="unspecified")return e}function Q(e){return/prompt|commandRef/i.test(e)?"prompt_body":/std(?:out|err)|raw|log|transcript|stack/i.test(e)?"raw_log":/url/i.test(e)?"private_url":/path|cwd|argv|args|shell|command|binary|executable/i.test(e)?"executable_path":/secret|token|password|authorization|api[_-]?key|license/i.test(e)?"secret_or_pii":"unsafe_key"}function B(e,r){return typeof e[r]=="string"?e[r]:void 0}function Se(e){return!!(e&&bt.test(e)&&!D.test(e)&&!W.test(e))}function _(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function nr(e,r){return q(e,`${r}-${Date.now()}-${Ue(4).toString("hex")}`)}function ge(e,r){const t=Date.parse(e);return new Date((Number.isFinite(t)?t:Date.now())+r).toISOString()}function je(e,r){const t=Date.parse(e),a=r?Date.parse(r):Number.NaN;return Number.isFinite(a)?Number.isFinite(t)?a>t?r:e:r:e}function F(e,r,t){return Number.isFinite(e)?Math.max(r,Math.min(t,Math.floor(e))):r}function V(e){return Array.from(new Set(e))}function sr(e,r){const t=new Set,a=[];for(const o of e){const s=r(o);t.has(s)||(t.add(s),a.push(o))}return a}export{ht as DEFAULT_HEADLESS_YOLOOP_LEASE_MS,fe as DEFAULT_HEADLESS_YOLOOP_LOCAL_CONCURRENCY_CAP,yt as DEFAULT_HEADLESS_YOLOOP_MAX_DURATION_MS,ft as DEFAULT_HEADLESS_YOLOOP_MAX_ITERATIONS,Pe as MAX_HEADLESS_YOLOOP_LOCAL_CONCURRENCY_CAP,Or as RUN_YOLOOP_DRIVER_STATES,Pt as defaultYoloopRootInvoker,Er as isCanonicalDelegatedStoryPrompt,Te as resolveDefaultHeadlessYoloopLocalConcurrencyCap,Rr as runYoloopExecutionPhase};
|