@ornexus/neocortex 4.60.71 → 4.60.73

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.
Files changed (243) hide show
  1. package/dist/release-source.json +1 -1
  2. package/dist/sbom.cdx.json +1211 -1217
  3. package/install.ps1 +1 -1
  4. package/install.sh +1 -1
  5. package/package.json +2 -2
  6. package/packages/client/dist/adapters/adapter-registry.js +108 -1
  7. package/packages/client/dist/adapters/antigravity-adapter.js +77 -2
  8. package/packages/client/dist/adapters/claude-code-adapter.js +79 -3
  9. package/packages/client/dist/adapters/codex-adapter.js +80 -2
  10. package/packages/client/dist/adapters/cursor-adapter.js +115 -4
  11. package/packages/client/dist/adapters/gemini-adapter.js +71 -2
  12. package/packages/client/dist/adapters/grok-adapter.js +42 -2
  13. package/packages/client/dist/adapters/index.js +22 -1
  14. package/packages/client/dist/adapters/platform-detector.js +212 -1
  15. package/packages/client/dist/adapters/target-adapter.js +12 -0
  16. package/packages/client/dist/adapters/vscode-adapter.js +72 -2
  17. package/packages/client/dist/agent/refresh-stubs.js +417 -2
  18. package/packages/client/dist/agent/update-agent-yaml.js +102 -1
  19. package/packages/client/dist/agent/update-description.js +251 -1
  20. package/packages/client/dist/cache/crypto-utils.js +78 -1
  21. package/packages/client/dist/cache/encrypted-cache.js +108 -1
  22. package/packages/client/dist/cache/in-memory-asset-cache.js +73 -1
  23. package/packages/client/dist/cache/index.js +13 -1
  24. package/packages/client/dist/cache/protected-pi-boundary.js +44 -1
  25. package/packages/client/dist/checkpoint/checkpoint-client-reader.js +127 -2
  26. package/packages/client/dist/checkpoint/index.js +11 -1
  27. package/packages/client/dist/checkpoint/shared-checkpoint-types.js +32 -1
  28. package/packages/client/dist/cli.js +358 -5
  29. package/packages/client/dist/commands/activate.js +394 -8
  30. package/packages/client/dist/commands/architecture-answers.js +274 -7
  31. package/packages/client/dist/commands/architecture-memory-terminal.js +253 -4
  32. package/packages/client/dist/commands/architecture-non-ui-continuation.js +100 -1
  33. package/packages/client/dist/commands/architecture-root-binding.js +51 -1
  34. package/packages/client/dist/commands/cache-status.js +112 -2
  35. package/packages/client/dist/commands/config.js +88 -1
  36. package/packages/client/dist/commands/doctor.js +635 -2
  37. package/packages/client/dist/commands/invoke.js +7200 -143
  38. package/packages/client/dist/commands/legacy-epic-terminal.js +71 -1
  39. package/packages/client/dist/commands/legacy-story-branch.js +96 -1
  40. package/packages/client/dist/commands/legacy-story-pr.js +276 -1
  41. package/packages/client/dist/commands/mutation-qa-checkpoint.js +285 -5
  42. package/packages/client/dist/commands/mutation-qa-gate.js +54 -1
  43. package/packages/client/dist/commands/mutation-qa-git.js +41 -1
  44. package/packages/client/dist/commands/mutation-qa-policy.js +102 -1
  45. package/packages/client/dist/commands/mutation-qa-run.js +219 -3
  46. package/packages/client/dist/commands/mutation-qa-verdict.js +149 -1
  47. package/packages/client/dist/commands/mutation-qa.js +220 -1
  48. package/packages/client/dist/commands/native-agent.js +136 -2
  49. package/packages/client/dist/commands/planning-diagnosis.js +43 -1
  50. package/packages/client/dist/commands/planning-generation.js +53 -1
  51. package/packages/client/dist/commands/planning-memory.js +40 -1
  52. package/packages/client/dist/commands/planning-research.js +42 -1
  53. package/packages/client/dist/commands/private-session.js +75 -1
  54. package/packages/client/dist/commands/property-qa.js +139 -1
  55. package/packages/client/dist/commands/qa-control.js +16 -1
  56. package/packages/client/dist/commands/qa-scan-browser-launch.js +55 -1
  57. package/packages/client/dist/commands/qa-scan-browser-route.js +28 -1
  58. package/packages/client/dist/commands/qa-scan-capture.js +663 -5
  59. package/packages/client/dist/commands/qa-scan-discovery.js +376 -3
  60. package/packages/client/dist/commands/qa-scan-review.js +826 -5
  61. package/packages/client/dist/commands/qa-synthetic-backend-capture.js +266 -1
  62. package/packages/client/dist/commands/qa-synthetic-backend-review.js +297 -1
  63. package/packages/client/dist/commands/qa-synthetic-backend.js +340 -2
  64. package/packages/client/dist/commands/qa-synthetic-broker-port.js +85 -1
  65. package/packages/client/dist/commands/qa-synthetic-browser.js +39 -1
  66. package/packages/client/dist/commands/refactor-characterization.js +671 -21
  67. package/packages/client/dist/commands/refactor-commit.js +399 -13
  68. package/packages/client/dist/commands/refactor-control.js +142 -3
  69. package/packages/client/dist/commands/refactor-cpp-assertions.js +93 -3
  70. package/packages/client/dist/commands/refactor-review.js +283 -5
  71. package/packages/client/dist/commands/refactor-root.js +588 -7
  72. package/packages/client/dist/commands/refresh-memory.js +156 -3
  73. package/packages/client/dist/commands/shared-architecture-non-ui.js +24 -1
  74. package/packages/client/dist/commands/story-checkpoint.js +171 -1
  75. package/packages/client/dist/config/profile-directory.js +13 -1
  76. package/packages/client/dist/config/resolver-selection.js +278 -1
  77. package/packages/client/dist/config/secure-config.js +281 -12
  78. package/packages/client/dist/config.js +223 -2
  79. package/packages/client/dist/constants.js +25 -1
  80. package/packages/client/dist/context/context-collector.js +222 -2
  81. package/packages/client/dist/context/context-sanitizer.js +145 -1
  82. package/packages/client/dist/continuity/autonomous-governance.js +285 -1
  83. package/packages/client/dist/continuity/continuity-client-state-store.js +1587 -1
  84. package/packages/client/dist/continuity/invoke-hooks.js +129 -1
  85. package/packages/client/dist/continuity/migrations/001-initial-schema.js +12 -2
  86. package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.js +12 -2
  87. package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.js +12 -2
  88. package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.js +12 -2
  89. package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.js +12 -2
  90. package/packages/client/dist/continuity/migrations/006-native-agent-dispatches.js +10 -2
  91. package/packages/client/dist/continuity/native-agent-store.js +69 -1
  92. package/packages/client/dist/continuity/native-agent-types.js +90 -1
  93. package/packages/client/dist/continuity/outbox.js +117 -1
  94. package/packages/client/dist/continuity/runner-bootstrap-policy.js +172 -1
  95. package/packages/client/dist/continuity/sqlite-store.d.ts +22 -1
  96. package/packages/client/dist/continuity/sqlite-store.js +2612 -81
  97. package/packages/client/dist/effects/invoke-effect-gateways.js +62 -1
  98. package/packages/client/dist/errors/error-messages.js +228 -2
  99. package/packages/client/dist/errors/frontmatter-diagnostics.js +125 -1
  100. package/packages/client/dist/evidence/collector.js +347 -1
  101. package/packages/client/dist/evidence/index.js +1 -1
  102. package/packages/client/dist/evidence/types.js +2 -0
  103. package/packages/client/dist/fs/atomic-state-replace.js +152 -1
  104. package/packages/client/dist/generated/command-registry.generated.js +4076 -1
  105. package/packages/client/dist/generated/public-projections.generated.js +149 -1
  106. package/packages/client/dist/git/direct-yolo-c01-retry.js +138 -4
  107. package/packages/client/dist/git/direct-yolo-checkpoint.js +1234 -4
  108. package/packages/client/dist/git/epic-operational-state.d.ts +198 -0
  109. package/packages/client/dist/git/epic-operational-state.js +672 -0
  110. package/packages/client/dist/git/git-lifecycle-step-ids.js +14 -1
  111. package/packages/client/dist/git/git-lifecycle-store.d.ts +9 -1
  112. package/packages/client/dist/git/git-lifecycle-store.js +1981 -9
  113. package/packages/client/dist/git/legacy-story-branch-checkpoint.js +259 -9
  114. package/packages/client/dist/git/legacy-story-branch-setup.js +348 -4
  115. package/packages/client/dist/git/legacy-story-pr.js +3538 -70
  116. package/packages/client/dist/git/secure-filesystem-boundary.js +182 -5
  117. package/packages/client/dist/graph-retrieval/pre-command-hook.js +284 -1
  118. package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +237 -1
  119. package/packages/client/dist/i18n/first-run.js +60 -2
  120. package/packages/client/dist/index.js +47 -1
  121. package/packages/client/dist/invocation/invoke-input.js +24 -1
  122. package/packages/client/dist/license/index.js +5 -1
  123. package/packages/client/dist/license/license-client.js +304 -1
  124. package/packages/client/dist/machine/fingerprint.js +163 -2
  125. package/packages/client/dist/machine/index.js +5 -1
  126. package/packages/client/dist/memory/project-memory-path-scope.js +62 -1
  127. package/packages/client/dist/memory/project-memory-writer.js +1007 -40
  128. package/packages/client/dist/memory/shared-project-memory-types.js +253 -2
  129. package/packages/client/dist/migrations/epic-lifecycle-backfill.d.ts +97 -0
  130. package/packages/client/dist/migrations/epic-lifecycle-backfill.js +1060 -0
  131. package/packages/client/dist/migrations/project-identity-capability.js +50 -1
  132. package/packages/client/dist/migrations/project-identity.js +493 -7
  133. package/packages/client/dist/migrations/state-json.d.ts +22 -0
  134. package/packages/client/dist/migrations/state-json.js +393 -4
  135. package/packages/client/dist/policy/architecture-policy.js +184 -2
  136. package/packages/client/dist/policy/index.js +7 -1
  137. package/packages/client/dist/policy/shared-policy-types.js +38 -0
  138. package/packages/client/dist/policy/subagent-approval-policy.js +55 -1
  139. package/packages/client/dist/private-execution/clean-baseline.js +279 -2
  140. package/packages/client/dist/private-execution/codex-executor.js +574 -4
  141. package/packages/client/dist/private-execution/codex-host-runtime.js +137 -1
  142. package/packages/client/dist/private-execution/codex-lifecycle-guard.js +97 -1
  143. package/packages/client/dist/private-execution/codex-scoped-permissions.js +128 -1
  144. package/packages/client/dist/private-execution/delivery.js +410 -13
  145. package/packages/client/dist/private-execution/diagnosis-root-review.js +294 -2
  146. package/packages/client/dist/private-execution/frozen-handoff.js +19 -6
  147. package/packages/client/dist/private-execution/implementation-validation.js +106 -2
  148. package/packages/client/dist/private-execution/isolated-admission.js +1432 -23
  149. package/packages/client/dist/private-execution/isolated-session.js +725 -5
  150. package/packages/client/dist/private-execution/isolated-workspace.js +122 -1
  151. package/packages/client/dist/private-execution/pact-consumer-runtime.js +409 -3
  152. package/packages/client/dist/private-execution/pact-test-source.js +258 -1
  153. package/packages/client/dist/private-execution/pact-toolchain.js +290 -3
  154. package/packages/client/dist/private-execution/pact-write-set.js +172 -1
  155. package/packages/client/dist/private-execution/planning-diagnosis-checkpoint.js +406 -5
  156. package/packages/client/dist/private-execution/planning-generation-checkpoint.js +462 -5
  157. package/packages/client/dist/private-execution/planning-memory-checkpoint.js +139 -3
  158. package/packages/client/dist/private-execution/planning-research-checkpoint.js +325 -4
  159. package/packages/client/dist/private-execution/private-report-store.js +42 -1
  160. package/packages/client/dist/private-execution/property-test-candidate.js +103 -1
  161. package/packages/client/dist/private-execution/property-test-choices.js +147 -3
  162. package/packages/client/dist/private-execution/property-test-plan.js +271 -7
  163. package/packages/client/dist/private-execution/property-test-review.js +258 -4
  164. package/packages/client/dist/private-execution/property-test-runtime.js +372 -9
  165. package/packages/client/dist/private-execution/property-test-source.js +139 -1
  166. package/packages/client/dist/private-execution/root-checkpoint.js +80 -1
  167. package/packages/client/dist/private-execution/root-memory-git-evidence.js +135 -3
  168. package/packages/client/dist/private-execution/root-memory-recovery.js +93 -1
  169. package/packages/client/dist/private-execution/root-memory-request.js +29 -1
  170. package/packages/client/dist/private-execution/root-memory-scope.js +178 -1
  171. package/packages/client/dist/private-execution/root-memory-writer.js +102 -1
  172. package/packages/client/dist/private-execution/session-lease.js +63 -1
  173. package/packages/client/dist/private-execution/shared-private-admission-types.js +50 -1
  174. package/packages/client/dist/private-execution/shared-project-validation.js +66 -1
  175. package/packages/client/dist/private-execution/shared-root-memory-types.js +61 -1
  176. package/packages/client/dist/private-execution/ux-source-validation.js +372 -1
  177. package/packages/client/dist/private-execution/ux-write-set.js +191 -2
  178. package/packages/client/dist/registry/registry-reconciliation.js +234 -1
  179. package/packages/client/dist/resilience/circuit-breaker.js +170 -1
  180. package/packages/client/dist/resilience/degradation-manager.js +164 -1
  181. package/packages/client/dist/resilience/freshness-indicator.js +100 -1
  182. package/packages/client/dist/resilience/index.js +8 -1
  183. package/packages/client/dist/resilience/recovery-detector.js +74 -1
  184. package/packages/client/dist/resolvers/asset-resolver.js +13 -0
  185. package/packages/client/dist/resolvers/local-resolver.js +255 -8
  186. package/packages/client/dist/resolvers/remote-resolver.js +233 -1
  187. package/packages/client/dist/runner/binary.js +404 -1
  188. package/packages/client/dist/runner/cli.js +1571 -17
  189. package/packages/client/dist/runner/headless/adapters.js +49 -1
  190. package/packages/client/dist/runner/headless/claude-code-adapter.js +79 -1
  191. package/packages/client/dist/runner/headless/continuous-story-workspace.js +1628 -11
  192. package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +69 -1
  193. package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +110 -2
  194. package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +1236 -8
  195. package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +318 -2
  196. package/packages/client/dist/runner/headless/fake-adapter.js +62 -1
  197. package/packages/client/dist/runner/headless/managed-profile.js +132 -1
  198. package/packages/client/dist/runner/headless/opencode-adapter.js +145 -2
  199. package/packages/client/dist/runner/headless/prepared-story-bundle.js +43 -1
  200. package/packages/client/dist/runner/headless/resolver.js +231 -1
  201. package/packages/client/dist/runner/headless/run-yolo.js +885 -1
  202. package/packages/client/dist/runner/headless/run-yoloop.js +2574 -2
  203. package/packages/client/dist/runner/headless/types.js +574 -2
  204. package/packages/client/dist/runner/local-console.js +396 -13
  205. package/packages/client/dist/runner/portal-sync-worker.js +1487 -1
  206. package/packages/client/dist/runner/project-identity.js +106 -1
  207. package/packages/client/dist/runner/scheduler.js +995 -7
  208. package/packages/client/dist/runner-cli.js +18 -2
  209. package/packages/client/dist/state/invocation-shape.js +13 -1
  210. package/packages/client/dist/state/project-state-snapshot.d.ts +8 -0
  211. package/packages/client/dist/state/project-state-snapshot.js +1731 -1
  212. package/packages/client/dist/state/state-json-repair.js +785 -3
  213. package/packages/client/dist/state/structural-dag-projection.js +118 -1
  214. package/packages/client/dist/telemetry/index.js +5 -1
  215. package/packages/client/dist/telemetry/offline-queue.js +131 -1
  216. package/packages/client/dist/tier/index.js +5 -1
  217. package/packages/client/dist/tier/tier-aware-client.js +405 -1
  218. package/packages/client/dist/types/index.js +38 -1
  219. package/packages/client/dist/version.js +27 -1
  220. package/packages/client/dist/yolo/change-evidence-collector.js +126 -1
  221. package/packages/client/dist/yolo/invoke-envelope-capability.js +62 -1
  222. package/packages/client/dist/yolo/spec-envelope-collector.js +184 -5
  223. package/packages/client/dist/yoloop/discovery-hook.js +300 -2
  224. package/packages/client/dist/yoloop/index.js +8 -1
  225. package/packages/client/dist/yoloop/invoke-hooks.js +669 -12
  226. package/packages/client/dist/yoloop/shared-discover-epics.js +1007 -1
  227. package/packages/client/dist/yoloop/shared-yoloop-types.d.ts +65 -1
  228. package/packages/client/dist/yoloop/shared-yoloop-types.js +33 -1
  229. package/packages/client/dist/yoloop/target-normalization.js +180 -1
  230. package/packages/client/dist/yoloop/yoloop-client-state-store.d.ts +8 -0
  231. package/packages/client/dist/yoloop/yoloop-client-state-store.js +1920 -1
  232. package/packages/shared/dist/yolo/spec-envelope.js +3 -6
  233. package/targets-stubs/antigravity/gemini.md +1 -1
  234. package/targets-stubs/antigravity/skill/SKILL.md +1 -1
  235. package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
  236. package/targets-stubs/claude-code/neocortex-root.md +2 -2
  237. package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
  238. package/targets-stubs/claude-code/neocortex.md +2 -2
  239. package/targets-stubs/codex/AGENTS.md +1 -1
  240. package/targets-stubs/cursor/agent.md +2 -2
  241. package/targets-stubs/gemini-cli/agent.md +2 -2
  242. package/targets-stubs/opencode/neocortex-root.md +1 -1
  243. package/targets-stubs/vscode/neocortex.agent.md +2 -2
@@ -1,4 +1,21 @@
1
- import{execFile as st,spawn as Me}from"node:child_process";import{createHash as G,randomBytes as Ke}from"node:crypto";import{lstat as le,readFile as B,realpath as Y,stat as dt}from"node:fs/promises";import{basename as $,dirname as C,isAbsolute as Fe,join as D,relative as ut,resolve as ht}from"node:path";import{promisify as ft}from"node:util";import{admitPreparedStoryBundle as pt}from"./prepared-story-bundle.js";import{acquireGitLifecyclePhysicalIntegrationLock as lt,assertGitLifecyclePrivateDirectory as W,assertGitLifecyclePrivateFile as F,applyGitLifecycleRuntimeOverlay as re,computeImmutableStoryQaEvidenceDigest as yt,computeP205StoryQaEvidenceDigest as wt,ensureGitLifecyclePrivateChildDirectory as be,ensureRuntimeEpic as ye,ensureRuntimeStory as mt,gitLifecycleRuntimeDirectory as gt,mutateGitLifecycleRuntime as X,P205_COMPLETE_COMMAND as St,readGitLifecycleRuntime as V,releaseGitLifecyclePhysicalIntegrationLock as It,removeGitLifecyclePrivateDirectory as oe,verifyAcceptedGitLifecycleStoryCheckpoint as ke,verifyGitLifecyclePhysicalIntegrationLock as xe}from"../../git/git-lifecycle-store.js";import{anchoredAtomicWriteFile as vt,anchoredCreateDirectory as Ee,anchoredDirectoryIdentity as Rt,anchoredExecuteGit as Ae,anchoredEnsureDirectory as bt,anchoredRemoveFile as kt}from"../../git/secure-filesystem-boundary.js";import{GIT_LIFECYCLE_COMMIT_PUSH_STEP_ID as Ve,GIT_LIFECYCLE_REVIEW_PR_STEP_ID as we}from"../../git/git-lifecycle-step-ids.js";const je=ft(st),xt=String.raw`
1
+ /**
2
+ * Branchless preparation sandboxes for continuous yoloop children.
3
+ *
4
+ * A child receives an independent Git index at a detached HEAD, but no branch
5
+ * and no Git worktree are created. Only the root applies the validated result
6
+ * and creates the single logical story commit on the epic branch.
7
+ */
8
+ import { execFile, spawn } from 'node:child_process';
9
+ import { createHash, randomBytes } from 'node:crypto';
10
+ import { lstat, readFile, realpath, stat } from 'node:fs/promises';
11
+ import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
12
+ import { promisify } from 'node:util';
13
+ import { admitPreparedStoryBundle } from './prepared-story-bundle.js';
14
+ import { acquireGitLifecyclePhysicalIntegrationLock, assertGitLifecyclePrivateDirectory, assertGitLifecyclePrivateFile, applyGitLifecycleRuntimeOverlay, computeImmutableStoryQaEvidenceDigest, computeP205StoryQaEvidenceDigest, ensureGitLifecyclePrivateChildDirectory, ensureRuntimeEpic, ensureRuntimeStory, gitLifecycleRuntimeDirectory, mutateGitLifecycleRuntime, P205_COMPLETE_COMMAND, readGitLifecycleRuntime, releaseGitLifecyclePhysicalIntegrationLock, removeGitLifecyclePrivateDirectory, verifyAcceptedGitLifecycleStoryCheckpoint, verifyGitLifecyclePhysicalIntegrationLock, } from '../../git/git-lifecycle-store.js';
15
+ import { anchoredAtomicWriteFile, anchoredCreateDirectory, anchoredDirectoryIdentity, anchoredExecuteGit, anchoredEnsureDirectory, anchoredRemoveFile, } from '../../git/secure-filesystem-boundary.js';
16
+ import { GIT_LIFECYCLE_COMMIT_PUSH_STEP_ID, GIT_LIFECYCLE_REVIEW_PR_STEP_ID, } from '../../git/git-lifecycle-step-ids.js';
17
+ const execFileAsync = promisify(execFile);
18
+ const ANCHORED_CHILD_HELPER = String.raw `
2
19
  const fs = require('node:fs');
3
20
  const cp = require('node:child_process');
4
21
  const [expectedParentDev, expectedParentIno, name, expectedChildDev, expectedChildIno, encoded, handshake] = process.argv.slice(1);
@@ -46,13 +63,1613 @@ runtime.on('close', (code, signal) => {
46
63
  if (signal) process.kill(process.pid, signal);
47
64
  else process.exit(Number.isInteger(code) ? code : 1);
48
65
  });
49
- `;function ur(e,r={}){return async(t,o,n={})=>Nt(e,t,o,n,r)}function hr(e={}){let r=Promise.resolve();return{async prepare(t){if((e.platform??process.platform)==="win32")return f("continuous-sandbox-platform-unsupported");if(!/^[a-f0-9]{64}$/.test(t.dispatchId))return f("continuous-sandbox-dispatch-invalid");if(!ce(t.targetRef))return f("continuous-sandbox-target-invalid");if(!Jt(t.executionBranch))return f("continuous-execution-branch-invalid");if(!/^[a-f0-9]{64}$/.test(t.graphRevision))return f("continuous-graph-revision-invalid");const o=Ht(t.authorizedWriteSet);if(o.length===0||o.length!==t.authorizedWriteSet.length)return f("continuous-authorized-write-set-invalid");const n=Te(o),a=r;let c=()=>{};r=new Promise(s=>{c=s}),await a;let i,d;try{const s=await At(t.projectRoot),g=await P(s,["rev-parse","HEAD"]),S=await Ie(s,t.epicId,t.storyId),v=S.revision,A=await gt(s),w=await be(A,"leases"),j=D(w,t.dispatchId);try{await Ee(w,t.dispatchId),await W(j,w)}catch(m){if(!q(m,"EEXIST"))throw m;await W(j,w);const l=await ue(j,w);if(l!==void 0&&Qt(l.pid))return f("continuous-sandbox-lease-active");if(!l||!await oe(j,w,async E=>ot(await ue(E,w),l)))return f("continuous-sandbox-lease-owner-replaced");await Ee(w,t.dispatchId),await W(j,w)}i=j,d=Object.freeze({pid:process.pid,createdAt:new Date().toISOString(),nonce:Ke(16).toString("hex")}),await te(j,"owner.json",Buffer.from(JSON.stringify(d)),e.beforeSandboxWriteCommit),await F(D(j,"owner.json"),j);const R=await be(A,"sandboxes"),p=D(R,t.dispatchId.slice(0,20)),I=await Ge(p,R);let b,u;const k=I?.preparedAt??new Date().toISOString(),x=I?.workspaceOwnerNonce??Ke(16).toString("hex");if(I){if(I.projectRoot!==s||I.storyId!==t.storyId||I.targetRef!==t.targetRef||I.dispatchId!==t.dispatchId||I.epicId!==t.epicId||I.executionBranch!==t.executionBranch||I.graphRevision!==t.graphRevision||I.claimRevision!==n||I.graphAuthorityRevision!==v||I.graphAuthorityEpoch!==S.epoch||I.graphAuthorityStoryStatus!==S.storyStatus||!rt(I.authorizedWriteSet,o)||(b=I.contextSnapshots.map(m=>({path:m.path,...m.contentBase64!==void 0?{content:Buffer.from(m.contentBase64,"base64")}:{}})),u=await Rt(p),u.dev!==I.workspaceIdentity.dev||u.ino!==I.workspaceIdentity.ino))return f("continuous-sandbox-recovery-mismatch")}else await oe(p,R),u=await Ee(R,$(p)),await W(p,R),await ne(R,$(p),u,["init","--quiet"]),await Dt(s,p),await jt(s,R,$(p),u),await ne(R,$(p),u,["remote","add","neocortex-root",s]),await ne(R,$(p),u,["fetch","--quiet","--no-tags","neocortex-root",g]),await ne(R,$(p),u,["checkout","--quiet","--detach","FETCH_HEAD"]),b=await Et(s,p,t.epicId,t.targetRef,e.beforeSandboxWriteCommit),await Zt(p,R,{schemaVersion:1,projectRoot:s,storyId:t.storyId,targetRef:t.targetRef,epicId:t.epicId,executionBranch:t.executionBranch,graphRevision:t.graphRevision,graphAuthorityRevision:v,graphAuthorityEpoch:S.epoch,graphAuthorityStoryStatus:S.storyStatus,authorizedWriteSet:o,claimRevision:n,dispatchId:t.dispatchId,baseSha:g,preparedAt:k,workspaceOwnerNonce:x,workspaceIdentity:u,contextSnapshots:b.map(m=>({path:m.path,...m.content!==void 0?{contentBase64:m.content.toString("base64")}:{}}))},e.beforeSandboxWriteCommit);return i=void 0,{ok:!0,value:{projectRoot:s,workspacePath:p,workspaceStrategy:"branchless_sandbox",storyId:t.storyId,targetRef:t.targetRef,epicId:t.epicId,executionBranch:t.executionBranch,graphRevision:t.graphRevision,graphAuthorityRevision:v,graphAuthorityEpoch:S.epoch,graphAuthorityStoryStatus:S.storyStatus,authorizedWriteSet:o,claimRevision:n,baseSha:I?.baseSha??g,dispatchId:t.dispatchId,preparedAt:k,leasePath:j,leaseOwnerNonce:d.nonce,workspaceOwnerNonce:x,workspaceIdentity:u,contextSnapshots:b}}}catch{if(i&&d){const s=i,g=d;await oe(s,C(s),async S=>ot(await ue(S,C(s)),g)).catch(()=>{})}return f("continuous-sandbox-prepare-failed")}finally{c()}},async integrate(t,o){const n=await ue(t.leasePath,C(t.leasePath)).catch(()=>{}),a=await Ge(t.workspacePath,C(t.workspacePath)).catch(()=>{});if(!n||n.nonce!==t.leaseOwnerNonce||a?.workspaceOwnerNonce!==t.workspaceOwnerNonce||a.dispatchId!==t.dispatchId||a.storyId!==t.storyId)return f("continuous-sandbox-owner-mismatch");const c=Xe(o?.nowIso??new Date().toISOString()),i=await lt(t.projectRoot,{kind:"continuous",storyId:t.storyId,sessionId:t.dispatchId,idempotencyKey:t.dispatchId,expiresAt:new Date(Date.parse(c)+1800*1e3).toISOString(),persistent:!1,createdAt:c});if(!i.ok)return f(i.reasonCode==="git-lifecycle-integration-backpressure"?"continuous-integration-backpressure":"continuous-integration-lease-failed");let d=[],s=!1,g=!1;try{const S=(await ie(t,["status","--porcelain"])).trimEnd(),v=await De(t,["rev-parse","HEAD"]);if(await ee(t.projectRoot,["symbolic-ref","--quiet","--short","HEAD"])!==t.executionBranch)return f("continuous-execution-branch-mismatch");const w=C(C(t.leasePath)),j=await be(w,"integrated"),R=D(j,t.dispatchId),p=await Ut(R,j);if(p?.childHeadSha===v&&p.bundle.storyId===t.storyId&&p.bundle.epicId===t.epicId&&p.bundle.executionBranch===t.executionBranch&&p.bundle.graphRevision===t.graphRevision&&p.bundle.claimRevision===t.claimRevision&&rt(p.bundle.authorizedWriteSet,t.authorizedWriteSet)&&p.checkpoint.idempotencyKey===t.dispatchId&&p.checkpoint.bundleId===p.bundle.bundleId&&p.checkpoint.bundleDigest===p.bundle.bundleDigest&&p.checkpoint.graphRevision===t.graphRevision&&p.checkpoint.claimRevision===t.claimRevision&&await ae(t.projectRoot,["merge-base","--is-ancestor",p.rootHeadSha,"HEAD"])&&await Yt(t,p.checkpoint))return{ok:!0,value:{headSha:p.rootHeadSha,alreadyIntegrated:!0,bundle:p.bundle,checkpoint:p.checkpoint}};if(v!==t.baseSha)return f("continuous-sandbox-child-git-authority-denied");if(S.length===0)return f("continuous-bundle-empty");const I=S.split(`
50
- `).some(y=>y.length>0&&y[0]!==" "&&y[0]!=="?");I||await De(t,["add","-A"]);const b=L(await ie(t,["diff","--cached","--name-only","-z",t.baseSha]));if(b.length===0||b.some(y=>!ce(y)))return f("continuous-integration-write-set-invalid");if(!await Ct(t,["merge-base","--is-ancestor",t.baseSha,v]))return f("continuous-bundle-base-not-ancestor");if(!await ae(t.projectRoot,["merge-base","--is-ancestor",t.baseSha,"HEAD"]))return f("continuous-root-base-not-ancestor");const u=o?.nowIso??new Date().toISOString(),k=Ft(o?.receiptRefs,t.dispatchId),x=await ie(t,["diff","--cached","--binary",t.baseSha]),m={schemaVersion:1,storyId:t.storyId,epicId:t.epicId,executionBranch:t.executionBranch,baseSha:t.baseSha,bundleDigest:G("sha256").update(x).digest("hex"),graphRevision:t.graphRevision,claimRevision:t.claimRevision,authorizedWriteSet:t.authorizedWriteSet,contextDigests:Object.fromEntries(t.contextSnapshots.map(y=>[y.path,G("sha256").update(y.content??Buffer.alloc(0)).digest("hex")])),validationRefs:k,createdAt:t.preparedAt,expiresAt:new Date(Date.parse(t.preparedAt)+1440*60*1e3).toISOString(),branchless:!0},l=Object.freeze({...m,bundleId:Te(m)}),E=await er(t,l);if(E){const y=await Xt(t,l,E);if(y)return await We(R,v,E.headSha,l,y,e.beforeSandboxWriteCommit),{ok:!0,value:{headSha:E.headSha,alreadyIntegrated:!0,bundle:l,checkpoint:y}}}if(!E&&await Kt(t.projectRoot,t.epicId)!==t.graphAuthorityRevision)return f("continuous-graph-revision-stale");if(E){const y=await Ye({lease:t,bundle:l,baseSha:E.baseSha,headSha:E.headSha,receiptRefs:k,nowIso:u,qaRunner:e.storyQaRunner});if(!y.ok)return y;await e.beforeCheckpointPersist?.({projectRoot:t.projectRoot,storyId:t.storyId,headSha:E.headSha});const O=await Ue({lease:t,physicalLock:i,checkpointAuthority:E.checkpointAuthority,bundle:l,baseSha:E.baseSha,headSha:E.headSha,receiptRefs:[...k,`bundle:${l.bundleId}`,y.value.qaReceipt.receiptRef,y.value.reviewReceipt.receiptRef],qaReceipt:y.value.qaReceipt,reviewReceipt:y.value.reviewReceipt,recordedAt:u,checkpointNow:e.checkpointNow,insideCheckpointPreCommit:e.insideCheckpointPreCommit,afterCheckpointPersist:e.afterCheckpointPersist});return O.ok?(await We(R,v,E.headSha,l,O.value,e.beforeSandboxWriteCommit),{ok:!0,value:{headSha:E.headSha,alreadyIntegrated:!0,bundle:l,checkpoint:O.value}}):O}if(I)return f("continuous-sandbox-child-git-authority-denied");if(L(await z(t.projectRoot,["diff","--cached","--name-only","-z"])).length>0)return f("continuous-integration-root-index-dirty");const J=new Set(t.contextSnapshots.map(y=>y.path));if(b.filter(y=>!t.authorizedWriteSet.some(O=>Se(O,y))).length>0)return f("continuous-bundle-write-set-unauthorized");const M=b.filter(y=>!J.has(y)),Re=new Set(L(await z(t.projectRoot,["diff","--name-only","-z",`${t.baseSha}..HEAD`])));if(M.some(y=>Re.has(y)))return f("continuous-bundle-intervening-conflict");const he=new Set([...L(await z(t.projectRoot,["diff","--name-only","-z"])),...L(await z(t.projectRoot,["ls-files","--others","--exclude-standard","-z"]))]);if(M.some(y=>he.has(y)))return f("continuous-integration-root-conflict");d=await $t(t.projectRoot,[...new Set([...b,".neocortex/state.json"])]);const H=await zt(t,u);if(!H.ok)return H;const K=pt({bundle:l,payload:Buffer.from(x),expected:{epicId:t.epicId,storyId:t.storyId,executionBranch:t.executionBranch,baseSha:t.baseSha,graphRevision:t.graphRevision,claimRevision:t.claimRevision,authorizedWriteSet:t.authorizedWriteSet,nowIso:u},writerLease:H.value});if(K.length>0)return await Ne(t.projectRoot,d),f(`continuous-bundle-admission-${K[0]}`);const fe=await P(t.projectRoot,["rev-parse","HEAD"]);let Q;await e.beforeRootCommit?.({projectRoot:t.projectRoot,storyId:t.storyId,headSha:fe});try{await X(t.projectRoot,y=>{const O=h(ye(y,t.epicId).branch_lease);if(O?.ownerStoryId!==t.storyId||O.sessionId!==t.dispatchId||O.idempotencyKey!==t.dispatchId||Date.parse(String(O.expiresAt))<=Date.now())throw new Error("continuous-checkpoint-writer-lease-lost")},{preCommit:async y=>{const O=await Ie(t.projectRoot,t.epicId,t.storyId,y);if(O.revision!==t.graphAuthorityRevision||O.epoch!==t.graphAuthorityEpoch||O.storyStatus!==t.graphAuthorityStoryStatus)throw new Error("continuous-graph-revision-stale");if(!await xe(i.path,i.owner))throw new Error("continuous-integration-lock-raced");const nt=await ee(t.projectRoot,["symbolic-ref","--quiet","--short","HEAD"]),it=await P(t.projectRoot,["rev-parse","HEAD"]);if(nt!==t.executionBranch||it!==fe)throw new Error("continuous-integration-head-raced");const at=L(await z(t.projectRoot,["diff","--cached","--name-only","-z"])),ct=new Set([...L(await z(t.projectRoot,["diff","--name-only","-z"])),...L(await z(t.projectRoot,["ls-files","--others","--exclude-standard","-z"]))]);if(at.length>0)throw new Error("continuous-integration-root-index-dirty");if(M.some(_=>ct.has(_)))throw new Error("continuous-integration-root-conflict");if(g=!0,M.length>0){const _=await ie(t,["diff","--cached","--binary",t.baseSha,"--",...M]);if(_.length>0&&!await _t(t.projectRoot,["apply","--index","--3way","--whitespace=nowarn"],_))throw new Error("continuous-integration-conflict")}for(const _ of t.contextSnapshots){if(!b.includes(_.path))continue;const qe=await Ce(D(t.projectRoot,_.path)),He=await Ot(t,_.path),Je=_.path===".neocortex/state.json"?qt(_.content,qe,Gt(_.content,He,t.storyId)):Wt(_.content,qe,He);if(!Je.ok)throw new Error(_.path===".neocortex/state.json"?"continuous-state-merge-conflict":"continuous-context-merge-conflict");await te(t.projectRoot,_.path,Je.value),await P(t.projectRoot,["add","-A","--",_.path])}if(b.includes(".neocortex/state.json")&&await P(t.projectRoot,["add","-A","--",".neocortex/state.json"]),await ae(t.projectRoot,["diff","--cached","--quiet"]))throw new Error("continuous-integration-empty-after-admission");Q=await Ie(t.projectRoot,t.epicId,t.storyId,y),await P(t.projectRoot,["commit","-m",`feat(yoloop): integrate ${t.storyId}`,"-m",`Neocortex-Story: ${t.storyId}`,"-m",`Neocortex-Epic: ${t.epicId}`,"-m",`Neocortex-Execution-Branch: ${t.executionBranch}`,"-m",`Neocortex-Prepared-Base: ${t.baseSha}`,"-m",`Neocortex-Dispatch: ${t.dispatchId}`,"-m",`Neocortex-Bundle: ${l.bundleId}`,"-m",`Neocortex-Bundle-Digest: ${l.bundleDigest}`,"-m",`Neocortex-Graph-Revision: ${t.graphRevision}`,"-m",`Neocortex-Claim-Revision: ${t.claimRevision}`,"-m",`Neocortex-Checkpoint-Authority: ${Q.revision}`,"-m",`Neocortex-Checkpoint-Epoch: ${Q.epoch??"null"}`,"-m",`Neocortex-Checkpoint-Story-Status: ${Q.storyStatus??"null"}`]),s=!0}})}catch(y){g&&!s&&await Ne(t.projectRoot,d);const O=y instanceof Error&&/^continuous-/.test(y.message)?y.message:"continuous-integration-failed";return f(O)}const Z=await P(t.projectRoot,["rev-parse","HEAD"]);if(!Q)return f("continuous-checkpoint-authority-missing");await e.afterRootCommit?.({projectRoot:t.projectRoot,storyId:t.storyId,headSha:Z});const U=await Ye({lease:t,bundle:l,baseSha:fe,headSha:Z,receiptRefs:k,nowIso:u,qaRunner:e.storyQaRunner});if(!U.ok)return U;await e.beforeCheckpointPersist?.({projectRoot:t.projectRoot,storyId:t.storyId,headSha:Z});const pe=await Ue({lease:t,physicalLock:i,checkpointAuthority:Q,bundle:l,baseSha:fe,headSha:Z,receiptRefs:[...k,`bundle:${l.bundleId}`,U.value.qaReceipt.receiptRef,U.value.reviewReceipt.receiptRef],qaReceipt:U.value.qaReceipt,reviewReceipt:U.value.reviewReceipt,recordedAt:u,checkpointNow:e.checkpointNow,insideCheckpointPreCommit:e.insideCheckpointPreCommit,afterCheckpointPersist:e.afterCheckpointPersist});return pe.ok?(await We(R,v,Z,l,pe.value,e.beforeSandboxWriteCommit),{ok:!0,value:{headSha:Z,alreadyIntegrated:!1,bundle:l,checkpoint:pe.value}}):pe}catch{return g&&!s&&d.length>0&&await Ne(t.projectRoot,d),f("continuous-integration-failed")}finally{await Tt(t).catch(()=>{}),await It(i.path,i.owner).catch(()=>{})}},async release(t,o){o||await oe(t.workspacePath,C(t.workspacePath),async n=>{const a=await Ge(n,C(t.workspacePath)).catch(()=>{});return a?.workspaceOwnerNonce===t.workspaceOwnerNonce&&a.dispatchId===t.dispatchId&&a.storyId===t.storyId}),await oe(t.leasePath,C(t.leasePath),async n=>(await ue(n,C(t.leasePath)).catch(()=>{}))?.nonce===t.leaseOwnerNonce)}}}async function Et(e,r,t,o,n){const a=[...new Set([".neocortex/state.json",o,`docs/epics/epic-${Vt(t)}.md`])],c=[];for(const i of a){if(!ce(i))continue;const d=await Ce(D(e,i));c.push({path:i,...d!==void 0?{content:d}:{}}),d!==void 0&&await te(r,i,d,n)}return c}async function At(e){const r=await P(e,["rev-parse","--show-toplevel"]),[t,o]=await Promise.all([Y(r),Y(e)]);if(t!==o)throw new Error("project root mismatch");return t}async function jt(e,r,t,o){for(const n of["user.name","user.email"]){const a=await ee(e,["config","--get",n]);a&&await ne(r,t,o,["config",n,a])}}async function Dt(e,r){const t=await V(e);await X(r,o=>{for(const[n,a]of Object.entries(t.epics))o.epics[n]={...structuredClone(a),branch_lease:null};for(const[n,a]of Object.entries(t.stories))o.stories[n]=structuredClone(a)})}async function ne(e,r,t,o){return(await Ae(e,r,t,o)).toString("utf8").trim()}async function ie(e,r){return(await Ae(C(e.workspacePath),$(e.workspacePath),e.workspaceIdentity,r)).toString("utf8")}async function De(e,r){return(await ie(e,r)).trim()}async function Ct(e,r){try{return await De(e,r),!0}catch{return!1}}async function Ot(e,r){try{return await Ae(C(e.workspacePath),$(e.workspacePath),e.workspaceIdentity,["show",`:${r}`])}catch{return}}async function Nt(e,r,t,o,n){const a=Date.now(),c=A=>({exitCode:null,timedOut:!1,durationMs:Date.now()-a,stdout:"",stderr:"",stdoutBytes:0,stderrBytes:0,...A});if(o.signal?.aborted)return c({signal:"SIGTERM",cancelled:!0});if(!r||r.length>4096||r.includes("\0")||t.length>512||t.some(A=>A.length>32768||A.includes("\0")))return c({exitCode:73,stderr:"continuous-child-invocation-invalid",stderrBytes:35});const i=C(e.workspacePath),d=await le(i,{bigint:!0}),s=await dt(i,{bigint:!0});if(!d.isDirectory()||d.isSymbolicLink()||!s.isDirectory()||d.dev!==s.dev||d.ino!==s.ino)return c({exitCode:73,stderr:"continuous-child-parent-invalid",stderrBytes:31});await n.beforeHandoff?.();const g=Buffer.from(JSON.stringify({command:r,args:[...t]})).toString("base64url"),S=o.maxOutputBytes??64e3,v=Math.max(1,Math.min(o.timeoutMs??600*1e3,1800*1e3));return await new Promise(A=>{const w=Me(process.execPath,["-e",xt,String(s.dev),String(s.ino),$(e.workspacePath),e.workspaceIdentity.dev,e.workspaceIdentity.ino,g,n.afterHandoff?"1":"0"],{cwd:i,env:o.env,stdio:["pipe","pipe","pipe"]});let j="",R="",p=0,I=0,b=!1,u=!1,k=!1,x=!n.afterHandoff;const m=(N,J)=>{b||(b=!0,clearTimeout(E),o.signal?.removeEventListener("abort",l),A({exitCode:N,...J?{signal:J}:{},timedOut:u,...k?{cancelled:!0}:{},durationMs:Date.now()-a,stdout:j,stderr:R,stdoutBytes:p,stderrBytes:I}))},l=()=>{k=!0,w.kill("SIGTERM")};o.signal?.addEventListener("abort",l,{once:!0});const E=setTimeout(()=>{u=!0,w.kill("SIGTERM")},v);w.stdout.on("data",N=>{p+=N.length,p+I>S?w.kill("SIGTERM"):j+=N.toString("utf8")}),w.stderr.on("data",N=>{I+=N.length,p+I>S?w.kill("SIGTERM"):R+=N.toString("utf8"),!x&&R.includes(`continuous-child-handoff-ready
51
- `)&&(x=!0,Promise.resolve(n.afterHandoff?.()).then(()=>w.stdin.end()).catch(()=>w.kill("SIGTERM")))}),w.once("error",()=>m(null)),w.once("close",(N,J)=>m(N,J)),n.afterHandoff||w.stdin.end()})}async function P(e,r){return(await z(e,r)).trim()}async function z(e,r){const t=await je("git",r,{cwd:e,encoding:"utf8",maxBuffer:16777216});return String(t.stdout)}async function ee(e,r){try{return await P(e,r)}catch(t){if(q(t,"ENOENT"))return;throw t}}async function ae(e,r){try{return await P(e,r),!0}catch{return!1}}async function _t(e,r,t){return await new Promise(o=>{const n=Me("git",[...r],{cwd:e,stdio:["pipe","ignore","ignore"]});n.once("error",()=>o(!1)),n.once("close",a=>o(a===0)),n.stdin.end(t)})}async function fr(e,r,t){try{const o=await je("git",["show",`${r}:${t}`],{cwd:e,encoding:"buffer",maxBuffer:16777216});return Buffer.from(o.stdout)}catch(o){if(q(o,"ENOENT"))return;throw o}}async function Ce(e){try{return await B(e)}catch(r){if(q(r,"ENOENT"))return;throw r}}async function te(e,r,t,o){const n=se(r);if(!ce(n))throw new Error("continuous-sandbox-write-path-invalid");const a=await Y(e);if(a!==ht(e))throw new Error("continuous-sandbox-write-root-symlink");const c=C(n)==="."?"":C(n),i=await Bt(a,c),d=await Qe(i),s=D(i,$(n));if(await me(s,a,!0),t===void 0){await o?.({boundaryRoot:a,relativePath:n,destinationPath:s}),await Ze(i,a,d),await me(s,a,!0),await kt(i,$(n));return}await o?.({boundaryRoot:a,relativePath:n,destinationPath:s}),await Ze(i,a,d),await me(s,a,!0),await vt(i,$(n),t),await me(s,a,!1)}async function Bt(e,r){let t=e;for(const o of r.split("/").filter(Boolean)){t=D(t,o),await bt(C(t),$(t));const n=await le(t);if(!n.isDirectory()||n.isSymbolicLink()||await Y(t)!==t)throw new Error("continuous-sandbox-write-component-unsafe");Oe(e,t)}return t}async function me(e,r,t){Oe(r,e);try{const o=await le(e);if(o.isSymbolicLink()||!o.isFile())throw new Error("continuous-sandbox-write-destination-unsafe");if(await Y(e)!==e)throw new Error("continuous-sandbox-write-destination-symlink")}catch(o){if(t&&q(o,"ENOENT"))return;throw o}}function Oe(e,r){const t=ut(e,r);if(t===""||t.startsWith("..")||Fe(t))throw new Error("continuous-sandbox-write-containment-invalid")}async function Qe(e){const r=await le(e,{bigint:!0});if(!r.isDirectory()||r.isSymbolicLink())throw new Error("continuous-sandbox-write-parent-unsafe");return{dev:r.dev,ino:r.ino}}async function Pt(e,r,t){try{if(e!==r&&Oe(r,e),await Y(e)!==e)return!1;const o=await Qe(e);return o.dev===t.dev&&o.ino===t.ino}catch{return!1}}async function Ze(e,r,t){if(!await Pt(e,r,t))throw new Error("continuous-sandbox-write-parent-raced")}async function $t(e,r){return await Promise.all(r.map(async t=>{const o=await Ce(D(e,t));return{path:t,...o!==void 0?{content:o}:{}}}))}async function Ne(e,r){const t=r.map(o=>o.path);t.length>0&&await ae(e,["reset","--quiet","HEAD","--",...t]);for(const o of r)await te(e,o.path,o.content)}async function zt(e,r){try{const t=D(e.projectRoot,".neocortex/state.json"),o=T(JSON.parse((await B(t)).toString("utf8"))),n=h(h(o.epics)?.[e.epicId]),a=h(n?.branch_lease),c=Object.freeze({schemaVersion:1,ownerStoryId:e.storyId,sessionId:e.dispatchId,idempotencyKey:e.dispatchId,acquiredAt:r,expiresAt:new Date(Date.parse(r)+600*1e3).toISOString()});let i=!1;return await X(e.projectRoot,d=>{const s=ye(d,e.epicId),g=h(s.branch_lease)??a;if(g&&typeof g.expiresAt=="string"&&g.expiresAt>r&&(g.ownerStoryId!==e.storyId||g.idempotencyKey!==e.dispatchId)){i=!0;return}s.branch_mode="epic",s.execution_branch=e.executionBranch,s.branch_lease=c}),i?f("continuous-epic-checkout-writer-active"):{ok:!0,value:c}}catch{return f("continuous-writer-lease-persist-failed")}}async function Tt(e){await X(e.projectRoot,r=>{const t=ye(r,e.epicId),o=h(t.branch_lease);o?.ownerStoryId===e.storyId&&o.idempotencyKey===e.dispatchId&&(t.branch_lease=null)})}async function Ue(e){try{const r=D(e.lease.projectRoot,".neocortex/state.json"),t=Object.freeze({schemaVersion:1,storyId:e.lease.storyId,epicId:e.lease.epicId,branch:e.lease.executionBranch,baseSha:e.baseSha,headSha:e.headSha,commits:Object.freeze([e.headSha]),idempotencyKey:e.lease.dispatchId,dispatchId:e.lease.dispatchId,bundleId:e.bundle.bundleId,bundleDigest:e.bundle.bundleDigest,graphRevision:e.lease.graphRevision,claimRevision:e.lease.claimRevision,receiptRefs:Object.freeze([...new Set(e.receiptRefs)]),qaVerdict:"passed",reviewVerdict:"approved",qaReceipt:e.qaReceipt,reviewReceipt:e.reviewReceipt,recordedAt:e.recordedAt}),o=T(JSON.parse((await B(r)).toString("utf8"))),n=h(h(o.stories)?.[e.lease.storyId]);let a="persisted",c,i,d,s,g=!1,S;const v=async(u,k,x)=>{const m=await ee(e.lease.projectRoot,["symbolic-ref","--quiet","--short","HEAD"]),l=await P(e.lease.projectRoot,["rev-parse","HEAD"]);if(m!==e.lease.executionBranch||l!==e.headSha)throw new Error("continuous-checkpoint-head-raced");if(u.graphRevision!==e.lease.graphRevision||u.claimRevision!==e.lease.claimRevision||u.bundleId!==e.bundle.bundleId||u.bundleDigest!==e.bundle.bundleDigest)throw new Error("continuous-checkpoint-graph-raced");const E=x??T(JSON.parse((await B(r)).toString("utf8"))),N=re(E,k??await V(e.lease.projectRoot)),J=h(h(N.epics)?.[e.lease.epicId]),ve=h(h(N.stories)?.[e.lease.storyId]),M=Array.isArray(ve?.depends_on)?ve.depends_on.filter(H=>typeof H=="string"):[],Re=h(N.stories);if(J?.execution_branch!==e.lease.executionBranch||M.some(H=>{const K=h(Re?.[H]);return!K||!["done","completed","merged"].includes(String(K.status))}))throw new Error("continuous-checkpoint-dependency-raced");const he=L(await z(e.lease.projectRoot,["diff-tree","--no-commit-id","--name-only","-r","-z",e.headSha]));if(he.length===0||he.some(H=>!e.lease.authorizedWriteSet.some(K=>Se(K,H))))throw new Error("continuous-checkpoint-write-set-raced");if(!await ke(e.lease.projectRoot,u,e.lease.storyId,e.lease.epicId,e.lease.executionBranch,void 0,e.lease.authorizedWriteSet))throw new Error("continuous-checkpoint-receipt-revalidation-failed")},A=await V(e.lease.projectRoot,{required:!0}),w=h(h(A.epics[e.lease.epicId])?.branch_lease);if(w?.ownerStoryId!==e.lease.storyId||w.idempotencyKey!==e.lease.dispatchId||w.sessionId!==e.lease.dispatchId||typeof w.expiresAt!="string"||Date.parse(w.expiresAt)<=(e.checkpointNow?.("before-mutation")??Date.now()))return f("continuous-checkpoint-writer-lease-lost");if(!await xe(e.physicalLock.path,e.physicalLock.owner))return f("continuous-checkpoint-integration-lock-raced");const j=await B(r),R=G("sha256").update(j).digest("hex");await v(t,A);const p=$e(T(JSON.parse(j.toString("utf8"))),A,e.lease.epicId,e.lease.storyId);if(p.revision!==e.checkpointAuthority.revision||p.epoch!==e.checkpointAuthority.epoch||p.storyStatus!==e.checkpointAuthority.storyStatus)return f("continuous-graph-revision-stale");const I=await X(e.lease.projectRoot,u=>{const k=ye(u,e.lease.epicId),x=h(k.branch_lease);i=x===void 0?void 0:structuredClone(x),d=structuredClone(u),g=u.stories[e.lease.storyId]!==void 0,s=structuredClone(u.stories[e.lease.storyId]??{}),S=structuredClone(k.branch_lease);const m=mt(u,e.lease.storyId),l=h(m.checkpoint)??h(n?.checkpoint);if(l?.idempotencyKey===e.lease.dispatchId){l.baseSha!==e.baseSha||l.headSha!==e.headSha||l.bundleId!==e.bundle.bundleId||l.bundleDigest!==e.bundle.bundleDigest||l.graphRevision!==e.lease.graphRevision||l.claimRevision!==e.lease.claimRevision?a="conflict":(a="reused",c=l,k.branch_lease=null);return}if(x?.ownerStoryId!==e.lease.storyId||x.idempotencyKey!==e.lease.dispatchId||x.sessionId!==e.lease.dispatchId){a="lease-lost";return}m.checkpoint=t,m.status="done",m.last_step=we;const E=Array.isArray(m.steps_completed)?m.steps_completed.filter(N=>typeof N=="string"):[];m.steps_completed=[...new Set([...E,Ve,we])],k.branch_lease=null},{expectedRevision:A.revision,preCommit:async u=>{if(i?.ownerStoryId!==e.lease.storyId||i.idempotencyKey!==e.lease.dispatchId||i.sessionId!==e.lease.dispatchId||typeof i.expiresAt!="string"||Date.parse(i.expiresAt)<=(e.checkpointNow?.("pre-commit")??Date.now()))throw new Error("continuous-checkpoint-writer-lease-lost");if(await e.insideCheckpointPreCommit?.({projectRoot:e.lease.projectRoot,storyId:e.lease.storyId,headSha:e.headSha}),!await xe(e.physicalLock.path,e.physicalLock.owner))throw new Error("continuous-checkpoint-integration-lock-raced");await v(c??t,u);const k=await B(r);if(G("sha256").update(k).digest("hex")!==R)throw new Error("continuous-graph-revision-stale");if(!d)throw new Error("continuous-checkpoint-authority-missing");const x=T(JSON.parse(k.toString("utf8"))),m=$e(x,d,e.lease.epicId,e.lease.storyId);if(m.revision!==e.checkpointAuthority.revision||m.epoch!==e.checkpointAuthority.epoch||m.storyStatus!==e.checkpointAuthority.storyStatus)throw new Error("continuous-graph-revision-stale");if(a==="persisted"&&!ze(x,u,e.lease,t))throw new Error("continuous-checkpoint-projection-raced")}}),b=a;if(b==="conflict")return f("continuous-checkpoint-idempotency-conflict");if(b==="lease-lost")return f("continuous-checkpoint-writer-lease-lost");if(b==="reused"&&c)try{return await v(c),{ok:!0,value:c}}catch{return f("continuous-checkpoint-reused-evidence-invalid")}try{await e.afterCheckpointPersist?.({projectRoot:e.lease.projectRoot,storyId:e.lease.storyId,headSha:e.headSha});const u=await V(e.lease.projectRoot,{required:!0});if(u.revision!==I.document.revision)throw new Error("continuous-checkpoint-post-persist-runtime-raced");await v(t,u);const k=await B(r);if(G("sha256").update(k).digest("hex")!==R)throw new Error("continuous-checkpoint-post-persist-authority-raced");const x=T(JSON.parse(k.toString("utf8")));if(!ze(x,u,e.lease,t))throw new Error("continuous-checkpoint-post-persist-projection-raced")}catch{const u=await B(r).catch(()=>{}),k=u===void 0||G("sha256").update(u).digest("hex")!==R;return await X(e.lease.projectRoot,x=>{const m=h(x.epics[e.lease.epicId]),l=h(x.stories[e.lease.storyId]),E=u===void 0?void 0:T(JSON.parse(u.toString("utf8")));if(!m||!l||!E||!ze(E,x,e.lease,t))throw new Error("continuous-checkpoint-cleanup-cas-conflict");if(k){g?Mt(l,s??{}):delete x.stories[e.lease.storyId],S===void 0?delete m.branch_lease:m.branch_lease=structuredClone(S);return}l.checkpoint=null,l.status="blocked",m.branch_lease=null},{expectedRevision:I.document.revision}).catch(()=>{}),f("continuous-checkpoint-post-persist-raced")}return{ok:!0,value:t}}catch(r){const t=r instanceof Error&&/^continuous-/.test(r.message)?r.message:"continuous-checkpoint-persist-failed";return f(t)}}async function Ye(e){try{if(await P(e.lease.projectRoot,["rev-parse","HEAD"])!==e.headSha)return f("continuous-story-evidence-head-raced");const r=await B(D(e.lease.projectRoot,"config","release-gates.v2.json"),"utf8"),t=JSON.parse(r),o=Array.isArray(t.requiredCompleteClasses)?t.requiredCompleteClasses.filter(b=>typeof b=="string"&&/^[a-z0-9-]+$/.test(b)):[];if(t.contract!=="P205-CI-02"||o.length===0)return f("continuous-story-qa-manifest-invalid");const n=String((await je(process.execPath,["scripts/test-root.mjs","--gate","complete"],{cwd:e.lease.projectRoot,encoding:"utf8",maxBuffer:32*1024*1024})).stdout);if(await e.qaRunner?.({projectRoot:e.lease.projectRoot,storyId:e.lease.storyId,headSha:e.headSha}),await P(e.lease.projectRoot,["rev-parse","HEAD"])!==e.headSha)return f("continuous-story-qa-head-raced");const a=Xe(e.nowIso),c=await P(e.lease.projectRoot,["rev-list","--count",`${e.baseSha}..${e.headSha}`]),i=await z(e.lease.projectRoot,["show","--no-patch","--format=%H%n%P%n%B",e.headSha]),d=L(await z(e.lease.projectRoot,["diff","--name-only","-z",`${e.baseSha}..${e.headSha}`])),s=yt({storyId:e.lease.storyId,baseSha:e.baseSha,headSha:e.headSha,bundleDigest:e.bundle.bundleDigest,graphRevision:e.lease.graphRevision,commitBody:i,changedPaths:d}),g=G("sha256").update(r).digest("hex"),S=G("sha256").update(n).digest("hex"),v=wt({gitEvidenceDigest:s,headSha:e.headSha,graphRevision:e.lease.graphRevision,manifestDigest:g,gateIds:o,resultDigest:S}),A=`story-qa:${v}`,w=Object.freeze({schemaVersion:1,kind:"story_qa_evidence",producer:"local-yolo-tdd",evidenceVersion:"p205-execution-v2",storyId:e.lease.storyId,epicId:e.lease.epicId,baseSha:e.baseSha,headSha:e.headSha,bundleDigest:e.bundle.bundleDigest,graphRevision:e.lease.graphRevision,contract:"P205-CI-02",command:St,manifestDigest:g,gateIds:Object.freeze(o),resultDigest:S,sourceEvidenceDigest:v,verdict:"passed",checkedAt:a,receiptRef:A}),j=[`Neocortex-Story: ${e.lease.storyId}`,`Neocortex-Epic: ${e.lease.epicId}`,`Neocortex-Bundle-Digest: ${e.bundle.bundleDigest}`,`Neocortex-Graph-Revision: ${e.lease.graphRevision}`];if(c!=="1"||!j.every(b=>i.includes(b))||d.length===0||d.some(b=>!e.lease.authorizedWriteSet.some(u=>Se(u,b))))return f("continuous-story-review-evidence-rejected");const R=G("sha256").update(["root-commit-range-review-v1",e.lease.storyId,e.baseSha,e.headSha,e.bundle.bundleDigest,e.lease.graphRevision,A,G("sha256").update(i).digest("hex"),[...d].sort().join(",")].join("\0")).digest("hex"),p=`story-review:${R}`,I=Object.freeze({schemaVersion:1,kind:"story_review_evidence",producer:"root-commit-range-review",storyId:e.lease.storyId,epicId:e.lease.epicId,baseSha:e.baseSha,headSha:e.headSha,bundleDigest:e.bundle.bundleDigest,graphRevision:e.lease.graphRevision,sourceEvidenceDigest:R,qaReceiptRef:A,verdict:"approved",reviewedAt:a,receiptRef:p});return{ok:!0,value:{qaReceipt:w,reviewReceipt:I}}}catch{return f("continuous-story-evidence-production-failed")}}function Xe(e){return Number.isFinite(Date.parse(e))?new Date(Date.parse(e)).toISOString():new Date().toISOString()}function Gt(e,r,t){if(r!==void 0)try{const o=e===void 0?{}:T(JSON.parse(e.toString("utf8"))),n=T(JSON.parse(r.toString("utf8"))),a=structuredClone(o),c=h(h(o.stories)?.[t]),i=h(h(n.stories)?.[t]),d=Lt(a,"stories"),s=structuredClone(c??{});for(const g of["status","last_step","steps_completed","last_updated","blocked_reason","blocked_at","implementation_evidence","validation_evidence","qa_gate"])i&&Object.prototype.hasOwnProperty.call(i,g)&&(s[g]=structuredClone(i[g]));return d[t]=s,Buffer.from(`${JSON.stringify(a,null,2)}
52
- `)}catch{return Buffer.from("{invalid-child-state")}}function Lt(e,r){const t=h(e[r]);if(t)return t;const o={};return e[r]=o,o}function T(e){if(!e||typeof e!="object"||Array.isArray(e))throw new Error("record expected");return e}function h(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:void 0}function Wt(e,r,t){return Pe(t,e)||Pe(r,t)?{ok:!0,value:r}:Pe(r,e)?{ok:!0,value:t}:f("continuous-context-merge-conflict")}function qt(e,r,t){try{const o=et(_e(e),_e(r),_e(t));return o.ok?{ok:!0,value:o.value===void 0?void 0:Buffer.from(`${JSON.stringify(o.value,null,2)}
53
- `)}:o}catch{return f("continuous-state-merge-invalid")}}function _e(e){return e===void 0?void 0:JSON.parse(e.toString("utf8"))}function et(e,r,t){if(ge(t,e)||ge(r,t))return{ok:!0,value:r};if(ge(r,e))return{ok:!0,value:t};if(Be(e)&&Be(r)&&Be(t)){const o={};for(const n of[...new Set([...Object.keys(e),...Object.keys(r),...Object.keys(t)])].sort()){const a=et(e[n],r[n],t[n]);if(!a.ok)return a;a.value!==void 0&&(o[n]=a.value)}return{ok:!0,value:o}}if(Array.isArray(e)&&Array.isArray(r)&&Array.isArray(t)&&tt(e,r)&&tt(e,t)){const o=[...e,...r.slice(e.length),...t.slice(e.length)],n=new Set;return{ok:!0,value:o.filter(a=>{const c=JSON.stringify(a);return n.has(c)?!1:(n.add(c),!0)})}}return f("continuous-state-merge-conflict")}function Be(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function tt(e,r){return e.length<=r.length&&e.every((t,o)=>ge(t,r[o]))}function ge(e,r){return JSON.stringify(e)===JSON.stringify(r)}function Pe(e,r){return e===void 0||r===void 0?e===r:e.equals(r)}function L(e){return e.split("\0").filter(Boolean)}function ce(e){const r=se(e);return r.length>0&&r.length<=1024&&!Fe(r)&&!/^[A-Za-z]:\//.test(r)&&!r.split("/").includes("..")&&!r.includes("\0")&&!r.startsWith("/")}function se(e){return e.replaceAll("\\","/").replace(/^\.\//,"").replace(/\/{2,}/g,"/")}function Ht(e){const r=e.map(se).filter(ce);return[...new Set(r)].sort()}function Se(e,r){const t=se(e),o=se(r);return t===o||t.endsWith("/")&&o.startsWith(t)}function Jt(e){return e.length>0&&e.length<=240&&!e.startsWith("-")&&!e.startsWith("/")&&!e.endsWith("/")&&!e.endsWith(".lock")&&!e.includes("..")&&!e.includes("\\")&&!e.includes("@{")&&!e.includes("//")&&/^[A-Za-z0-9._/-]+$/.test(e)}function rt(e,r){return e.length===r.length&&e.every((t,o)=>t===r[o])}async function Ie(e,r,t,o){const n=T(JSON.parse(await B(D(e,".neocortex/state.json"),"utf8")));return $e(n,o??await V(e),r,t)}function $e(e,r,t,o){const n=re(e,r),a=h(n.epics),c=h(n.stories),i=h(a?.[t])??{},d=(Array.isArray(i.stories)?i.stories:Array.isArray(i.story_ids)?i.story_ids:[]).filter(v=>typeof v=="string"),s=d.length>0?d:Object.entries(c??{}).filter(([v,A])=>h(A)?.epic_id===t||v.startsWith(`${t}.`)).map(([v])=>v).sort(),g=["status","depends_on","files_to_modify","contracts","contract_refs","shared_surfaces","steps_completed","last_step","branch_name","physicalMergeStatus","merged","checkpoint","planning","attempts","retry_count","rollback_receipt","cancelled_at"],S=Object.fromEntries(s.map(v=>{const A=h(c?.[v])??{};return[v,Object.fromEntries(g.filter(w=>Object.prototype.hasOwnProperty.call(A,w)).map(w=>[w,A[w]]))]}));return{revision:Te({epicId:t,epic:{stories:s,status:i.status??null,branch_mode:i.branch_mode??null,execution_branch:i.execution_branch??null,graph_revision:i.graph_revision??null,depends_on:i.depends_on??null,planning:i.planning??null,execution_plan:i.execution_plan??null,waves:i.waves??null,current_wave:i.current_wave??null,replan:i.replan??null,replan_revision:i.replan_revision??null,dependency_graph:i.dependency_graph??null,scheduler:i.scheduler??null,attempts:i.attempts??null,retry_count:i.retry_count??null},stories:S}),epoch:typeof i.graph_revision=="string"?i.graph_revision:null,storyStatus:typeof h(c?.[o])?.status=="string"?String(h(c?.[o])?.status):null}}function ze(e,r,t,o){const n=re(e,r),a=h(h(n.epics)?.[t.epicId]),c=h(h(n.stories)?.[t.storyId]),i=Array.isArray(c?.steps_completed)?c.steps_completed.filter(d=>typeof d=="string"):[];return!!(a&&c&&a.branch_lease===null&&c.status==="done"&&c.last_step===we&&i.includes(Ve)&&i.includes(we)&&de(c.checkpoint)===de(o))}function Mt(e,r){for(const t of Object.keys(e))delete e[t];Object.assign(e,structuredClone(r))}async function Kt(e,r){return(await Ie(e,r,"")).revision}function Te(e){return G("sha256").update(de(e)).digest("hex")}function de(e){return e===null||typeof e!="object"?JSON.stringify(e):Array.isArray(e)?`[${e.map(de).join(",")}]`:`{${Object.entries(e).sort(([r],[t])=>r.localeCompare(t)).map(([r,t])=>`${JSON.stringify(r)}:${de(t)}`).join(",")}}`}function Ft(e,r){const t=(e??[]).filter(o=>/^[A-Za-z0-9._/:@#-]{1,200}$/.test(o)&&!o.includes(".."));return Object.freeze([...new Set(t.length>0?t:[`dispatch:${r}`])].sort())}function Vt(e){return e.replace(/[^A-Za-z0-9._-]/g,"-").slice(0,80)}function f(e){return{ok:!1,reasonCode:e}}function q(e,r){return e instanceof Error&&"code"in e&&e.code===r}async function ue(e,r){try{await W(e,r);const t=D(e,"owner.json");await F(t,e);const o=JSON.parse(await B(t,"utf8"));if(!Number.isSafeInteger(o.pid)||Number(o.pid)<=0||typeof o.createdAt!="string"||!Number.isFinite(Date.parse(o.createdAt))||typeof o.nonce!="string"||!/^[a-f0-9]{32}$/.test(o.nonce))throw new Error("continuous-sandbox-lease-owner-invalid");return{pid:Number(o.pid),createdAt:o.createdAt,nonce:o.nonce}}catch(t){if(q(t,"ENOENT"))return;throw t}}function ot(e,r){return e?.pid===r.pid&&e.createdAt===r.createdAt&&e.nonce===r.nonce}function Qt(e){try{return process.kill(e,0),!0}catch(r){return q(r,"EPERM")}}async function Ge(e,r){try{await W(e,r);const t=D(e,".git");await W(t,e);const o=D(t,"neocortex-sandbox.json");await F(o,t);const n=JSON.parse(await B(o,"utf8"));if(n.schemaVersion!==1||typeof n.workspaceOwnerNonce!="string"||!/^[a-f0-9]{32}$/.test(n.workspaceOwnerNonce)||!/^[a-f0-9]{64}$/.test(n.graphAuthorityRevision)||!(n.graphAuthorityEpoch===null||/^[a-f0-9]{64}$/.test(n.graphAuthorityEpoch))||!(n.graphAuthorityStoryStatus===null||typeof n.graphAuthorityStoryStatus=="string"&&n.graphAuthorityStoryStatus.length<=80)||typeof n.workspaceIdentity?.dev!="string"||!/^[0-9]+$/.test(n.workspaceIdentity.dev)||typeof n.workspaceIdentity?.ino!="string"||!/^[0-9]+$/.test(n.workspaceIdentity.ino))throw new Error("continuous-sandbox-metadata-invalid");return n}catch(t){if(q(t,"ENOENT"))return;throw t}}async function Zt(e,r,t,o){await W(e,r);const n=D(e,".git");await W(n,e);const a=D(n,"neocortex-sandbox.json");await te(e,".git/neocortex-sandbox.json",Buffer.from(`${JSON.stringify(t,null,2)}
54
- `),o),await F(a,n)}async function Ut(e,r){try{await F(e,r);const t=JSON.parse(await B(e,"utf8"));return typeof t.childHeadSha=="string"&&typeof t.rootHeadSha=="string"&&/^[a-f0-9]{40,64}$/.test(t.childHeadSha)&&/^[a-f0-9]{40,64}$/.test(t.rootHeadSha)&&t.bundle?.schemaVersion===1&&t.checkpoint?.schemaVersion===1?t:void 0}catch(t){if(q(t,"ENOENT"))return;throw t}}async function Yt(e,r){try{const t=T(JSON.parse(await B(D(e.projectRoot,".neocortex/state.json"),"utf8"))),o=re(t,await V(e.projectRoot)),n=h(h(o.stories)?.[e.storyId]),a=h(n?.checkpoint);return a?.idempotencyKey===r.idempotencyKey&&a.headSha===r.headSha&&a.bundleDigest===r.bundleDigest&&h(h(o.epics)?.[e.epicId])?.branch_lease===null&&await ke(e.projectRoot,a,e.storyId,e.epicId,e.executionBranch,void 0,e.authorizedWriteSet)}catch{return!1}}async function Xt(e,r,t){try{const o=T(JSON.parse(await B(D(e.projectRoot,".neocortex/state.json"),"utf8"))),n=re(o,await V(e.projectRoot)),a=h(h(n.stories)?.[e.storyId]),c=h(a?.checkpoint);return c?.schemaVersion!==1||c.storyId!==e.storyId||c.epicId!==e.epicId||c.branch!==e.executionBranch||c.baseSha!==t.baseSha||c.headSha!==t.headSha||c.idempotencyKey!==e.dispatchId||c.dispatchId!==e.dispatchId||c.bundleId!==r.bundleId||c.bundleDigest!==r.bundleDigest||c.graphRevision!==e.graphRevision||c.claimRevision!==e.claimRevision||h(h(n.epics)?.[e.epicId])?.branch_lease!==null||!await ke(e.projectRoot,c,e.storyId,e.epicId,e.executionBranch,void 0,e.authorizedWriteSet)?void 0:c}catch{return}}async function er(e,r){const t=(await ee(e.projectRoot,["log","--format=%H","--fixed-strings",`--grep=Neocortex-Dispatch: ${e.dispatchId}`]))?.split(`
55
- `).filter(S=>/^[a-f0-9]{40,64}$/.test(S))??[];if(t.length!==1)return;const o=t[0];if(!await ae(e.projectRoot,["merge-base","--is-ancestor",o,"HEAD"]))return;const n=await P(e.projectRoot,["show","-s","--format=%B",o]),a=new Set(n.split(`
56
- `).map(S=>S.trim()));for(const S of[`Neocortex-Story: ${e.storyId}`,`Neocortex-Epic: ${e.epicId}`,`Neocortex-Execution-Branch: ${e.executionBranch}`,`Neocortex-Prepared-Base: ${e.baseSha}`,`Neocortex-Dispatch: ${e.dispatchId}`,`Neocortex-Bundle: ${r.bundleId}`,`Neocortex-Bundle-Digest: ${r.bundleDigest}`,`Neocortex-Graph-Revision: ${e.graphRevision}`,`Neocortex-Claim-Revision: ${e.claimRevision}`])if(!a.has(S))return;const c=Le(n,"Neocortex-Checkpoint-Authority"),i=Le(n,"Neocortex-Checkpoint-Epoch"),d=Le(n,"Neocortex-Checkpoint-Story-Status");if(!c||!/^[a-f0-9]{64}$/.test(c)||!i||!(i==="null"||/^[a-f0-9]{64}$/.test(i))||!d||d.length>80)return;const s=await ee(e.projectRoot,["rev-parse",`${o}^`]);if(!s||!/^[a-f0-9]{40,64}$/.test(s))return;const g=L(await z(e.projectRoot,["diff-tree","--no-commit-id","--name-only","-r","-z",o]));if(!(g.length===0||g.some(S=>!r.authorizedWriteSet.some(v=>Se(v,S)))))return{baseSha:s,headSha:o,checkpointAuthority:{revision:c,epoch:i==="null"?null:i,storyStatus:d==="null"?null:d}}}function Le(e,r){const t=`${r}: `,o=e.split(`
57
- `).map(n=>n.trim()).filter(n=>n.startsWith(t));return o.length===1?o[0].slice(t.length):void 0}async function We(e,r,t,o,n,a){const c=C(e);await W(c,C(c));try{await F(e,c)}catch(i){if(!q(i,"ENOENT"))throw i}await te(c,$(e),Buffer.from(`${JSON.stringify({childHeadSha:r,rootHeadSha:t,bundle:o,checkpoint:n})}
58
- `),a),await F(e,c)}export{ur as createAnchoredContinuousStoryCommandRunner,hr as createBranchlessContinuousStoryWorkspaceManager};
66
+ `;
67
+ /**
68
+ * Create the only command runner authorized for a continuous child. The helper
69
+ * owns and revalidates the sandbox cwd before launching the runtime, so the
70
+ * mutable public pathname is never reused as the runtime's cwd.
71
+ */
72
+ export function createAnchoredContinuousStoryCommandRunner(lease, hooks = {}) {
73
+ return async (command, args, options = {}) => runAnchoredChildCommand(lease, command, args, options, hooks);
74
+ }
75
+ /** Default continuous-DAG workspace policy. It never creates a Git worktree. */
76
+ export function createBranchlessContinuousStoryWorkspaceManager(options = {}) {
77
+ let preparationTail = Promise.resolve();
78
+ return {
79
+ async prepare(input) {
80
+ if ((options.platform ?? process.platform) === 'win32') {
81
+ return failure('continuous-sandbox-platform-unsupported');
82
+ }
83
+ if (!/^[a-f0-9]{64}$/.test(input.dispatchId))
84
+ return failure('continuous-sandbox-dispatch-invalid');
85
+ if (!safeRelativePath(input.targetRef))
86
+ return failure('continuous-sandbox-target-invalid');
87
+ if (!safeBranch(input.executionBranch))
88
+ return failure('continuous-execution-branch-invalid');
89
+ if (!/^[a-f0-9]{64}$/.test(input.graphRevision))
90
+ return failure('continuous-graph-revision-invalid');
91
+ const authorizedWriteSet = normalizeWriteSet(input.authorizedWriteSet);
92
+ if (authorizedWriteSet.length === 0 || authorizedWriteSet.length !== input.authorizedWriteSet.length) {
93
+ return failure('continuous-authorized-write-set-invalid');
94
+ }
95
+ const claimRevision = hashCanonical(authorizedWriteSet);
96
+ const previousPreparation = preparationTail;
97
+ let unlockPreparation = () => undefined;
98
+ preparationTail = new Promise((resolvePreparation) => { unlockPreparation = resolvePreparation; });
99
+ await previousPreparation;
100
+ let acquiredLeasePath;
101
+ let acquiredLeaseOwner;
102
+ try {
103
+ const projectRoot = await canonicalRoot(input.projectRoot);
104
+ const baseSha = await git(projectRoot, ['rev-parse', 'HEAD']);
105
+ const graphAuthority = await readCurrentGraphAuthoritySnapshot(projectRoot, input.epicId, input.storyId);
106
+ const graphAuthorityRevision = graphAuthority.revision;
107
+ const runtimeDirectory = await gitLifecycleRuntimeDirectory(projectRoot);
108
+ const leasesRoot = await ensureGitLifecyclePrivateChildDirectory(runtimeDirectory, 'leases');
109
+ const leasePath = join(leasesRoot, input.dispatchId);
110
+ try {
111
+ await anchoredCreateDirectory(leasesRoot, input.dispatchId);
112
+ await assertGitLifecyclePrivateDirectory(leasePath, leasesRoot);
113
+ }
114
+ catch (error) {
115
+ if (!isNodeError(error, 'EEXIST'))
116
+ throw error;
117
+ await assertGitLifecyclePrivateDirectory(leasePath, leasesRoot);
118
+ const owner = await readLeaseOwner(leasePath, leasesRoot);
119
+ if (owner !== undefined && processExists(owner.pid))
120
+ return failure('continuous-sandbox-lease-active');
121
+ if (!owner || !(await removeGitLifecyclePrivateDirectory(leasePath, leasesRoot, async (renamed) => sameLeaseOwner(await readLeaseOwner(renamed, leasesRoot), owner))))
122
+ return failure('continuous-sandbox-lease-owner-replaced');
123
+ await anchoredCreateDirectory(leasesRoot, input.dispatchId);
124
+ await assertGitLifecyclePrivateDirectory(leasePath, leasesRoot);
125
+ }
126
+ acquiredLeasePath = leasePath;
127
+ acquiredLeaseOwner = Object.freeze({
128
+ pid: process.pid,
129
+ createdAt: new Date().toISOString(),
130
+ nonce: randomBytes(16).toString('hex'),
131
+ });
132
+ await writeOptional(leasePath, 'owner.json', Buffer.from(JSON.stringify(acquiredLeaseOwner)), options.beforeSandboxWriteCommit);
133
+ await assertGitLifecyclePrivateFile(join(leasePath, 'owner.json'), leasePath);
134
+ const sandboxesRoot = await ensureGitLifecyclePrivateChildDirectory(runtimeDirectory, 'sandboxes');
135
+ const workspacePath = join(sandboxesRoot, input.dispatchId.slice(0, 20));
136
+ const recovered = await readSandboxMetadata(workspacePath, sandboxesRoot);
137
+ let contextSnapshots;
138
+ let workspaceIdentity;
139
+ const preparedAt = recovered?.preparedAt ?? new Date().toISOString();
140
+ const workspaceOwnerNonce = recovered?.workspaceOwnerNonce ?? randomBytes(16).toString('hex');
141
+ if (recovered) {
142
+ if (recovered.projectRoot !== projectRoot || recovered.storyId !== input.storyId
143
+ || recovered.targetRef !== input.targetRef || recovered.dispatchId !== input.dispatchId
144
+ || recovered.epicId !== input.epicId || recovered.executionBranch !== input.executionBranch
145
+ || recovered.graphRevision !== input.graphRevision || recovered.claimRevision !== claimRevision
146
+ || recovered.graphAuthorityRevision !== graphAuthorityRevision
147
+ || recovered.graphAuthorityEpoch !== graphAuthority.epoch
148
+ || recovered.graphAuthorityStoryStatus !== graphAuthority.storyStatus
149
+ || !sameStrings(recovered.authorizedWriteSet, authorizedWriteSet))
150
+ return failure('continuous-sandbox-recovery-mismatch');
151
+ contextSnapshots = recovered.contextSnapshots.map((snapshot) => ({
152
+ path: snapshot.path,
153
+ ...(snapshot.contentBase64 !== undefined ? { content: Buffer.from(snapshot.contentBase64, 'base64') } : {}),
154
+ }));
155
+ workspaceIdentity = await anchoredDirectoryIdentity(workspacePath);
156
+ if (workspaceIdentity.dev !== recovered.workspaceIdentity.dev
157
+ || workspaceIdentity.ino !== recovered.workspaceIdentity.ino) {
158
+ return failure('continuous-sandbox-recovery-mismatch');
159
+ }
160
+ }
161
+ else {
162
+ await removeGitLifecyclePrivateDirectory(workspacePath, sandboxesRoot);
163
+ workspaceIdentity = await anchoredCreateDirectory(sandboxesRoot, basename(workspacePath));
164
+ await assertGitLifecyclePrivateDirectory(workspacePath, sandboxesRoot);
165
+ await sandboxGitAt(sandboxesRoot, basename(workspacePath), workspaceIdentity, ['init', '--quiet']);
166
+ await initializeBranchlessRuntimeProjection(projectRoot, workspacePath);
167
+ await copyGitIdentity(projectRoot, sandboxesRoot, basename(workspacePath), workspaceIdentity);
168
+ await sandboxGitAt(sandboxesRoot, basename(workspacePath), workspaceIdentity, ['remote', 'add', 'neocortex-root', projectRoot]);
169
+ await sandboxGitAt(sandboxesRoot, basename(workspacePath), workspaceIdentity, ['fetch', '--quiet', '--no-tags', 'neocortex-root', baseSha]);
170
+ await sandboxGitAt(sandboxesRoot, basename(workspacePath), workspaceIdentity, ['checkout', '--quiet', '--detach', 'FETCH_HEAD']);
171
+ contextSnapshots = await copyCurrentContext(projectRoot, workspacePath, input.epicId, input.targetRef, options.beforeSandboxWriteCommit);
172
+ await writeSandboxMetadata(workspacePath, sandboxesRoot, {
173
+ schemaVersion: 1,
174
+ projectRoot,
175
+ storyId: input.storyId,
176
+ targetRef: input.targetRef,
177
+ epicId: input.epicId,
178
+ executionBranch: input.executionBranch,
179
+ graphRevision: input.graphRevision,
180
+ graphAuthorityRevision,
181
+ graphAuthorityEpoch: graphAuthority.epoch,
182
+ graphAuthorityStoryStatus: graphAuthority.storyStatus,
183
+ authorizedWriteSet,
184
+ claimRevision,
185
+ dispatchId: input.dispatchId,
186
+ baseSha,
187
+ preparedAt,
188
+ workspaceOwnerNonce,
189
+ workspaceIdentity,
190
+ contextSnapshots: contextSnapshots.map((snapshot) => ({
191
+ path: snapshot.path,
192
+ ...(snapshot.content !== undefined ? { contentBase64: snapshot.content.toString('base64') } : {}),
193
+ })),
194
+ }, options.beforeSandboxWriteCommit);
195
+ }
196
+ acquiredLeasePath = undefined;
197
+ return {
198
+ ok: true,
199
+ value: {
200
+ projectRoot,
201
+ workspacePath,
202
+ workspaceStrategy: 'branchless_sandbox',
203
+ storyId: input.storyId,
204
+ targetRef: input.targetRef,
205
+ epicId: input.epicId,
206
+ executionBranch: input.executionBranch,
207
+ graphRevision: input.graphRevision,
208
+ graphAuthorityRevision,
209
+ graphAuthorityEpoch: graphAuthority.epoch,
210
+ graphAuthorityStoryStatus: graphAuthority.storyStatus,
211
+ authorizedWriteSet,
212
+ claimRevision,
213
+ baseSha: recovered?.baseSha ?? baseSha,
214
+ dispatchId: input.dispatchId,
215
+ preparedAt,
216
+ leasePath,
217
+ leaseOwnerNonce: acquiredLeaseOwner.nonce,
218
+ workspaceOwnerNonce,
219
+ workspaceIdentity,
220
+ contextSnapshots,
221
+ },
222
+ };
223
+ }
224
+ catch {
225
+ if (acquiredLeasePath && acquiredLeaseOwner) {
226
+ const cleanupLeasePath = acquiredLeasePath;
227
+ const cleanupLeaseOwner = acquiredLeaseOwner;
228
+ await removeGitLifecyclePrivateDirectory(cleanupLeasePath, dirname(cleanupLeasePath), async (renamed) => sameLeaseOwner(await readLeaseOwner(renamed, dirname(cleanupLeasePath)), cleanupLeaseOwner)).catch(() => undefined);
229
+ }
230
+ return failure('continuous-sandbox-prepare-failed');
231
+ }
232
+ finally {
233
+ unlockPreparation();
234
+ }
235
+ },
236
+ async integrate(lease, authority) {
237
+ const leaseOwner = await readLeaseOwner(lease.leasePath, dirname(lease.leasePath)).catch(() => undefined);
238
+ const sandboxOwner = await readSandboxMetadata(lease.workspacePath, dirname(lease.workspacePath)).catch(() => undefined);
239
+ if (!leaseOwner || leaseOwner.nonce !== lease.leaseOwnerNonce
240
+ || sandboxOwner?.workspaceOwnerNonce !== lease.workspaceOwnerNonce
241
+ || sandboxOwner.dispatchId !== lease.dispatchId || sandboxOwner.storyId !== lease.storyId) {
242
+ return failure('continuous-sandbox-owner-mismatch');
243
+ }
244
+ const lockStartedAt = normalizeEvidenceTime(authority?.nowIso ?? new Date().toISOString());
245
+ const physicalLock = await acquireGitLifecyclePhysicalIntegrationLock(lease.projectRoot, {
246
+ kind: 'continuous', storyId: lease.storyId, sessionId: lease.dispatchId,
247
+ idempotencyKey: lease.dispatchId,
248
+ expiresAt: new Date(Date.parse(lockStartedAt) + 30 * 60 * 1000).toISOString(),
249
+ persistent: false, createdAt: lockStartedAt,
250
+ });
251
+ if (!physicalLock.ok)
252
+ return failure(physicalLock.reasonCode === 'git-lifecycle-integration-backpressure'
253
+ ? 'continuous-integration-backpressure' : 'continuous-integration-lease-failed');
254
+ let rootSnapshots = [];
255
+ let rootCommitCreated = false;
256
+ let rootEffectsStarted = false;
257
+ try {
258
+ // Preserve the leading porcelain status column: `sandboxGit` trims it
259
+ // and would misclassify an ordinary unstaged modification as staged.
260
+ const sandboxStatus = (await sandboxGitRaw(lease, ['status', '--porcelain'])).trimEnd();
261
+ const childHeadSha = await sandboxGit(lease, ['rev-parse', 'HEAD']);
262
+ const currentBranch = await gitOptional(lease.projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
263
+ if (currentBranch !== lease.executionBranch)
264
+ return failure('continuous-execution-branch-mismatch');
265
+ const runtimeDirectory = dirname(dirname(lease.leasePath));
266
+ const integratedRoot = await ensureGitLifecyclePrivateChildDirectory(runtimeDirectory, 'integrated');
267
+ const markerPath = join(integratedRoot, lease.dispatchId);
268
+ const marker = await readMarker(markerPath, integratedRoot);
269
+ if (marker?.childHeadSha === childHeadSha
270
+ && marker.bundle.storyId === lease.storyId
271
+ && marker.bundle.epicId === lease.epicId
272
+ && marker.bundle.executionBranch === lease.executionBranch
273
+ && marker.bundle.graphRevision === lease.graphRevision
274
+ && marker.bundle.claimRevision === lease.claimRevision
275
+ && sameStrings(marker.bundle.authorizedWriteSet, lease.authorizedWriteSet)
276
+ && marker.checkpoint.idempotencyKey === lease.dispatchId
277
+ && marker.checkpoint.bundleId === marker.bundle.bundleId
278
+ && marker.checkpoint.bundleDigest === marker.bundle.bundleDigest
279
+ && marker.checkpoint.graphRevision === lease.graphRevision
280
+ && marker.checkpoint.claimRevision === lease.claimRevision
281
+ && await gitExitOk(lease.projectRoot, ['merge-base', '--is-ancestor', marker.rootHeadSha, 'HEAD'])
282
+ && await checkpointExistsInRootState(lease, marker.checkpoint)) {
283
+ return {
284
+ ok: true,
285
+ value: {
286
+ headSha: marker.rootHeadSha,
287
+ alreadyIntegrated: true,
288
+ bundle: marker.bundle,
289
+ checkpoint: marker.checkpoint,
290
+ },
291
+ };
292
+ }
293
+ // The delegated child owns only filesystem writes. Any staged path or
294
+ // commit is an attempted authority escalation; the root writer alone
295
+ // stages, integrates and creates the single logical story commit.
296
+ if (childHeadSha !== lease.baseSha) {
297
+ return failure('continuous-sandbox-child-git-authority-denied');
298
+ }
299
+ if (sandboxStatus.length === 0)
300
+ return failure('continuous-bundle-empty');
301
+ const childStaged = sandboxStatus.split('\n')
302
+ .some((line) => line.length > 0 && line[0] !== ' ' && line[0] !== '?');
303
+ if (!childStaged)
304
+ await sandboxGit(lease, ['add', '-A']);
305
+ const changedPaths = splitNull(await sandboxGitRaw(lease, ['diff', '--cached', '--name-only', '-z', lease.baseSha]));
306
+ if (changedPaths.length === 0 || changedPaths.some((path) => !safeRelativePath(path))) {
307
+ return failure('continuous-integration-write-set-invalid');
308
+ }
309
+ if (!(await sandboxGitExitOk(lease, ['merge-base', '--is-ancestor', lease.baseSha, childHeadSha]))) {
310
+ return failure('continuous-bundle-base-not-ancestor');
311
+ }
312
+ if (!(await gitExitOk(lease.projectRoot, ['merge-base', '--is-ancestor', lease.baseSha, 'HEAD']))) {
313
+ return failure('continuous-root-base-not-ancestor');
314
+ }
315
+ const nowIso = authority?.nowIso ?? new Date().toISOString();
316
+ const receiptRefs = normalizeReceiptRefs(authority?.receiptRefs, lease.dispatchId);
317
+ const payload = await sandboxGitRaw(lease, ['diff', '--cached', '--binary', lease.baseSha]);
318
+ const bundleBody = {
319
+ schemaVersion: 1,
320
+ storyId: lease.storyId,
321
+ epicId: lease.epicId,
322
+ executionBranch: lease.executionBranch,
323
+ baseSha: lease.baseSha,
324
+ bundleDigest: createHash('sha256').update(payload).digest('hex'),
325
+ graphRevision: lease.graphRevision,
326
+ claimRevision: lease.claimRevision,
327
+ authorizedWriteSet: lease.authorizedWriteSet,
328
+ contextDigests: Object.fromEntries(lease.contextSnapshots.map((snapshot) => [
329
+ snapshot.path,
330
+ createHash('sha256').update(snapshot.content ?? Buffer.alloc(0)).digest('hex'),
331
+ ])),
332
+ validationRefs: receiptRefs,
333
+ createdAt: lease.preparedAt,
334
+ expiresAt: new Date(Date.parse(lease.preparedAt) + 24 * 60 * 60 * 1000).toISOString(),
335
+ branchless: true,
336
+ };
337
+ const bundle = Object.freeze({
338
+ ...bundleBody,
339
+ bundleId: hashCanonical(bundleBody),
340
+ });
341
+ const recoveredCommit = await findIntegratedDispatchCommit(lease, bundle);
342
+ if (recoveredCommit) {
343
+ const existingCheckpoint = await readMatchingRootCheckpoint(lease, bundle, recoveredCommit);
344
+ if (existingCheckpoint) {
345
+ await writeMarker(markerPath, childHeadSha, recoveredCommit.headSha, bundle, existingCheckpoint, options.beforeSandboxWriteCommit);
346
+ return {
347
+ ok: true,
348
+ value: { headSha: recoveredCommit.headSha, alreadyIntegrated: true, bundle, checkpoint: existingCheckpoint },
349
+ };
350
+ }
351
+ }
352
+ if (!recoveredCommit
353
+ && await readCurrentGraphAuthorityRevision(lease.projectRoot, lease.epicId) !== lease.graphAuthorityRevision) {
354
+ return failure('continuous-graph-revision-stale');
355
+ }
356
+ if (recoveredCommit) {
357
+ const evidence = await produceIndependentCheckpointEvidence({
358
+ lease, bundle, baseSha: recoveredCommit.baseSha, headSha: recoveredCommit.headSha,
359
+ receiptRefs, nowIso, qaRunner: options.storyQaRunner,
360
+ });
361
+ if (!evidence.ok)
362
+ return evidence;
363
+ await options.beforeCheckpointPersist?.({
364
+ projectRoot: lease.projectRoot, storyId: lease.storyId, headSha: recoveredCommit.headSha,
365
+ });
366
+ const checkpoint = await persistRootCheckpoint({
367
+ lease,
368
+ physicalLock,
369
+ checkpointAuthority: recoveredCommit.checkpointAuthority,
370
+ bundle,
371
+ baseSha: recoveredCommit.baseSha,
372
+ headSha: recoveredCommit.headSha,
373
+ receiptRefs: [...receiptRefs, `bundle:${bundle.bundleId}`, evidence.value.qaReceipt.receiptRef, evidence.value.reviewReceipt.receiptRef],
374
+ qaReceipt: evidence.value.qaReceipt,
375
+ reviewReceipt: evidence.value.reviewReceipt,
376
+ recordedAt: nowIso,
377
+ checkpointNow: options.checkpointNow,
378
+ insideCheckpointPreCommit: options.insideCheckpointPreCommit,
379
+ afterCheckpointPersist: options.afterCheckpointPersist,
380
+ });
381
+ if (!checkpoint.ok)
382
+ return checkpoint;
383
+ await writeMarker(markerPath, childHeadSha, recoveredCommit.headSha, bundle, checkpoint.value, options.beforeSandboxWriteCommit);
384
+ return { ok: true, value: { headSha: recoveredCommit.headSha, alreadyIntegrated: true, bundle, checkpoint: checkpoint.value } };
385
+ }
386
+ // A staged index is accepted only as replay input when immutable root
387
+ // evidence above proves that this exact bundle was already integrated.
388
+ // It can never authorize a fresh root effect.
389
+ if (childStaged)
390
+ return failure('continuous-sandbox-child-git-authority-denied');
391
+ const stagedPaths = splitNull(await gitRaw(lease.projectRoot, ['diff', '--cached', '--name-only', '-z']));
392
+ if (stagedPaths.length > 0)
393
+ return failure('continuous-integration-root-index-dirty');
394
+ const managedPaths = new Set(lease.contextSnapshots.map((snapshot) => snapshot.path));
395
+ const unauthorized = changedPaths.filter((path) => !lease.authorizedWriteSet.some((authorized) => writeSetCovers(authorized, path)));
396
+ if (unauthorized.length > 0)
397
+ return failure('continuous-bundle-write-set-unauthorized');
398
+ const patchPaths = changedPaths.filter((path) => !managedPaths.has(path));
399
+ const interveningPaths = new Set(splitNull(await gitRaw(lease.projectRoot, ['diff', '--name-only', '-z', `${lease.baseSha}..HEAD`])));
400
+ if (patchPaths.some((path) => interveningPaths.has(path)))
401
+ return failure('continuous-bundle-intervening-conflict');
402
+ const dirtyPaths = new Set([
403
+ ...splitNull(await gitRaw(lease.projectRoot, ['diff', '--name-only', '-z'])),
404
+ ...splitNull(await gitRaw(lease.projectRoot, ['ls-files', '--others', '--exclude-standard', '-z'])),
405
+ ]);
406
+ if (patchPaths.some((path) => dirtyPaths.has(path)))
407
+ return failure('continuous-integration-root-conflict');
408
+ rootSnapshots = await snapshotPaths(lease.projectRoot, [...new Set([...changedPaths, '.neocortex/state.json'])]);
409
+ const writer = await acquireRootWriterLease(lease, nowIso);
410
+ if (!writer.ok)
411
+ return writer;
412
+ const admissionErrors = admitPreparedStoryBundle({
413
+ bundle,
414
+ payload: Buffer.from(payload),
415
+ expected: {
416
+ epicId: lease.epicId,
417
+ storyId: lease.storyId,
418
+ executionBranch: lease.executionBranch,
419
+ baseSha: lease.baseSha,
420
+ graphRevision: lease.graphRevision,
421
+ claimRevision: lease.claimRevision,
422
+ authorizedWriteSet: lease.authorizedWriteSet,
423
+ nowIso,
424
+ },
425
+ writerLease: writer.value,
426
+ });
427
+ if (admissionErrors.length > 0) {
428
+ await restoreIntegration(lease.projectRoot, rootSnapshots);
429
+ return failure(`continuous-bundle-admission-${admissionErrors[0]}`);
430
+ }
431
+ const rootBaseSha = await git(lease.projectRoot, ['rev-parse', 'HEAD']);
432
+ let checkpointAuthority;
433
+ await options.beforeRootCommit?.({
434
+ projectRoot: lease.projectRoot,
435
+ storyId: lease.storyId,
436
+ headSha: rootBaseSha,
437
+ });
438
+ try {
439
+ await mutateGitLifecycleRuntime(lease.projectRoot, (document) => {
440
+ const currentWriter = asRecordOrUndefined(ensureRuntimeEpic(document, lease.epicId).branch_lease);
441
+ if (currentWriter?.ownerStoryId !== lease.storyId
442
+ || currentWriter.sessionId !== lease.dispatchId
443
+ || currentWriter.idempotencyKey !== lease.dispatchId
444
+ || Date.parse(String(currentWriter.expiresAt)) <= Date.now()) {
445
+ throw new Error('continuous-checkpoint-writer-lease-lost');
446
+ }
447
+ }, { preCommit: async (document) => {
448
+ const currentAuthority = await readCurrentGraphAuthoritySnapshot(lease.projectRoot, lease.epicId, lease.storyId, document);
449
+ if (currentAuthority.revision !== lease.graphAuthorityRevision
450
+ || currentAuthority.epoch !== lease.graphAuthorityEpoch
451
+ || currentAuthority.storyStatus !== lease.graphAuthorityStoryStatus) {
452
+ throw new Error('continuous-graph-revision-stale');
453
+ }
454
+ if (!(await verifyGitLifecyclePhysicalIntegrationLock(physicalLock.path, physicalLock.owner))) {
455
+ throw new Error('continuous-integration-lock-raced');
456
+ }
457
+ const guardedBranch = await gitOptional(lease.projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
458
+ const guardedHead = await git(lease.projectRoot, ['rev-parse', 'HEAD']);
459
+ if (guardedBranch !== lease.executionBranch || guardedHead !== rootBaseSha) {
460
+ throw new Error('continuous-integration-head-raced');
461
+ }
462
+ const guardedStaged = splitNull(await gitRaw(lease.projectRoot, ['diff', '--cached', '--name-only', '-z']));
463
+ const guardedDirty = new Set([
464
+ ...splitNull(await gitRaw(lease.projectRoot, ['diff', '--name-only', '-z'])),
465
+ ...splitNull(await gitRaw(lease.projectRoot, ['ls-files', '--others', '--exclude-standard', '-z'])),
466
+ ]);
467
+ if (guardedStaged.length > 0)
468
+ throw new Error('continuous-integration-root-index-dirty');
469
+ if (patchPaths.some((path) => guardedDirty.has(path)))
470
+ throw new Error('continuous-integration-root-conflict');
471
+ rootEffectsStarted = true;
472
+ if (patchPaths.length > 0) {
473
+ const patch = await sandboxGitRaw(lease, ['diff', '--cached', '--binary', lease.baseSha, '--', ...patchPaths]);
474
+ if (patch.length > 0 && !(await gitWithInput(lease.projectRoot, ['apply', '--index', '--3way', '--whitespace=nowarn'], patch)))
475
+ throw new Error('continuous-integration-conflict');
476
+ }
477
+ for (const snapshot of lease.contextSnapshots) {
478
+ if (!changedPaths.includes(snapshot.path))
479
+ continue;
480
+ const current = await readOptional(join(lease.projectRoot, snapshot.path));
481
+ const child = await sandboxGitIndexBlob(lease, snapshot.path);
482
+ const merged = snapshot.path === '.neocortex/state.json'
483
+ ? mergeJsonBuffers(snapshot.content, current, filterChildGitState(snapshot.content, child, lease.storyId))
484
+ : mergeBuffers(snapshot.content, current, child);
485
+ if (!merged.ok)
486
+ throw new Error(snapshot.path === '.neocortex/state.json'
487
+ ? 'continuous-state-merge-conflict'
488
+ : 'continuous-context-merge-conflict');
489
+ await writeOptional(lease.projectRoot, snapshot.path, merged.value);
490
+ await git(lease.projectRoot, ['add', '-A', '--', snapshot.path]);
491
+ }
492
+ if (changedPaths.includes('.neocortex/state.json')) {
493
+ await git(lease.projectRoot, ['add', '-A', '--', '.neocortex/state.json']);
494
+ }
495
+ if (await gitExitOk(lease.projectRoot, ['diff', '--cached', '--quiet'])) {
496
+ throw new Error('continuous-integration-empty-after-admission');
497
+ }
498
+ checkpointAuthority = await readCurrentGraphAuthoritySnapshot(lease.projectRoot, lease.epicId, lease.storyId, document);
499
+ await git(lease.projectRoot, [
500
+ 'commit', '-m', `feat(yoloop): integrate ${lease.storyId}`,
501
+ '-m', `Neocortex-Story: ${lease.storyId}`,
502
+ '-m', `Neocortex-Epic: ${lease.epicId}`,
503
+ '-m', `Neocortex-Execution-Branch: ${lease.executionBranch}`,
504
+ '-m', `Neocortex-Prepared-Base: ${lease.baseSha}`,
505
+ '-m', `Neocortex-Dispatch: ${lease.dispatchId}`,
506
+ '-m', `Neocortex-Bundle: ${bundle.bundleId}`,
507
+ '-m', `Neocortex-Bundle-Digest: ${bundle.bundleDigest}`,
508
+ '-m', `Neocortex-Graph-Revision: ${lease.graphRevision}`,
509
+ '-m', `Neocortex-Claim-Revision: ${lease.claimRevision}`,
510
+ '-m', `Neocortex-Checkpoint-Authority: ${checkpointAuthority.revision}`,
511
+ '-m', `Neocortex-Checkpoint-Epoch: ${checkpointAuthority.epoch ?? 'null'}`,
512
+ '-m', `Neocortex-Checkpoint-Story-Status: ${checkpointAuthority.storyStatus ?? 'null'}`,
513
+ ]);
514
+ rootCommitCreated = true;
515
+ } });
516
+ }
517
+ catch (error) {
518
+ if (rootEffectsStarted && !rootCommitCreated)
519
+ await restoreIntegration(lease.projectRoot, rootSnapshots);
520
+ const reasonCode = error instanceof Error && /^continuous-/.test(error.message)
521
+ ? error.message
522
+ : 'continuous-integration-failed';
523
+ return failure(reasonCode);
524
+ }
525
+ const rootHeadSha = await git(lease.projectRoot, ['rev-parse', 'HEAD']);
526
+ if (!checkpointAuthority)
527
+ return failure('continuous-checkpoint-authority-missing');
528
+ await options.afterRootCommit?.({
529
+ projectRoot: lease.projectRoot, storyId: lease.storyId, headSha: rootHeadSha,
530
+ });
531
+ const evidence = await produceIndependentCheckpointEvidence({
532
+ lease, bundle, baseSha: rootBaseSha, headSha: rootHeadSha,
533
+ receiptRefs, nowIso, qaRunner: options.storyQaRunner,
534
+ });
535
+ if (!evidence.ok)
536
+ return evidence;
537
+ await options.beforeCheckpointPersist?.({
538
+ projectRoot: lease.projectRoot, storyId: lease.storyId, headSha: rootHeadSha,
539
+ });
540
+ const checkpoint = await persistRootCheckpoint({
541
+ lease,
542
+ physicalLock,
543
+ checkpointAuthority,
544
+ bundle,
545
+ baseSha: rootBaseSha,
546
+ headSha: rootHeadSha,
547
+ receiptRefs: [...receiptRefs, `bundle:${bundle.bundleId}`, evidence.value.qaReceipt.receiptRef, evidence.value.reviewReceipt.receiptRef],
548
+ qaReceipt: evidence.value.qaReceipt,
549
+ reviewReceipt: evidence.value.reviewReceipt,
550
+ recordedAt: nowIso,
551
+ checkpointNow: options.checkpointNow,
552
+ insideCheckpointPreCommit: options.insideCheckpointPreCommit,
553
+ afterCheckpointPersist: options.afterCheckpointPersist,
554
+ });
555
+ if (!checkpoint.ok)
556
+ return checkpoint;
557
+ await writeMarker(markerPath, childHeadSha, rootHeadSha, bundle, checkpoint.value, options.beforeSandboxWriteCommit);
558
+ return { ok: true, value: { headSha: rootHeadSha, alreadyIntegrated: false, bundle, checkpoint: checkpoint.value } };
559
+ }
560
+ catch {
561
+ if (rootEffectsStarted && !rootCommitCreated && rootSnapshots.length > 0) {
562
+ await restoreIntegration(lease.projectRoot, rootSnapshots);
563
+ }
564
+ return failure('continuous-integration-failed');
565
+ }
566
+ finally {
567
+ await releaseRootWriterLease(lease).catch(() => undefined);
568
+ await releaseGitLifecyclePhysicalIntegrationLock(physicalLock.path, physicalLock.owner).catch(() => undefined);
569
+ }
570
+ },
571
+ async release(lease, preserveForRecovery) {
572
+ if (!preserveForRecovery) {
573
+ await removeGitLifecyclePrivateDirectory(lease.workspacePath, dirname(lease.workspacePath), async (renamed) => {
574
+ const metadata = await readSandboxMetadata(renamed, dirname(lease.workspacePath)).catch(() => undefined);
575
+ return metadata?.workspaceOwnerNonce === lease.workspaceOwnerNonce
576
+ && metadata.dispatchId === lease.dispatchId && metadata.storyId === lease.storyId;
577
+ });
578
+ }
579
+ await removeGitLifecyclePrivateDirectory(lease.leasePath, dirname(lease.leasePath), async (renamed) => {
580
+ const owner = await readLeaseOwner(renamed, dirname(lease.leasePath)).catch(() => undefined);
581
+ return owner?.nonce === lease.leaseOwnerNonce;
582
+ });
583
+ },
584
+ };
585
+ }
586
+ async function copyCurrentContext(projectRoot, workspacePath, epicId, targetRef, beforeCommit) {
587
+ const paths = [...new Set(['.neocortex/state.json', targetRef, `docs/epics/epic-${safeRef(epicId)}.md`])];
588
+ const snapshots = [];
589
+ for (const path of paths) {
590
+ if (!safeRelativePath(path))
591
+ continue;
592
+ const content = await readOptional(join(projectRoot, path));
593
+ snapshots.push({ path, ...(content !== undefined ? { content } : {}) });
594
+ if (content !== undefined)
595
+ await writeOptional(workspacePath, path, content, beforeCommit);
596
+ }
597
+ return snapshots;
598
+ }
599
+ async function canonicalRoot(projectRoot) {
600
+ const root = await git(projectRoot, ['rev-parse', '--show-toplevel']);
601
+ const [canonicalGitRoot, canonicalInputRoot] = await Promise.all([realpath(root), realpath(projectRoot)]);
602
+ if (canonicalGitRoot !== canonicalInputRoot)
603
+ throw new Error('project root mismatch');
604
+ return canonicalGitRoot;
605
+ }
606
+ async function copyGitIdentity(projectRoot, workspaceParent, workspaceName, workspaceIdentity) {
607
+ for (const key of ['user.name', 'user.email']) {
608
+ const value = await gitOptional(projectRoot, ['config', '--get', key]);
609
+ if (value)
610
+ await sandboxGitAt(workspaceParent, workspaceName, workspaceIdentity, ['config', key, value]);
611
+ }
612
+ }
613
+ async function initializeBranchlessRuntimeProjection(projectRoot, workspacePath) {
614
+ const rootRuntime = await readGitLifecycleRuntime(projectRoot);
615
+ await mutateGitLifecycleRuntime(workspacePath, (document) => {
616
+ for (const [epicId, epic] of Object.entries(rootRuntime.epics)) {
617
+ document.epics[epicId] = {
618
+ ...structuredClone(epic),
619
+ branch_lease: null,
620
+ };
621
+ }
622
+ for (const [storyId, story] of Object.entries(rootRuntime.stories)) {
623
+ document.stories[storyId] = structuredClone(story);
624
+ }
625
+ });
626
+ }
627
+ async function sandboxGitAt(workspaceParent, workspaceName, workspaceIdentity, args) {
628
+ return (await anchoredExecuteGit(workspaceParent, workspaceName, workspaceIdentity, args)).toString('utf8').trim();
629
+ }
630
+ async function sandboxGitRaw(lease, args) {
631
+ return (await anchoredExecuteGit(dirname(lease.workspacePath), basename(lease.workspacePath), lease.workspaceIdentity, args)).toString('utf8');
632
+ }
633
+ async function sandboxGit(lease, args) {
634
+ return (await sandboxGitRaw(lease, args)).trim();
635
+ }
636
+ async function sandboxGitExitOk(lease, args) {
637
+ try {
638
+ await sandboxGit(lease, args);
639
+ return true;
640
+ }
641
+ catch {
642
+ return false;
643
+ }
644
+ }
645
+ async function sandboxGitIndexBlob(lease, path) {
646
+ try {
647
+ return await anchoredExecuteGit(dirname(lease.workspacePath), basename(lease.workspacePath), lease.workspaceIdentity, ['show', `:${path}`]);
648
+ }
649
+ catch {
650
+ return undefined;
651
+ }
652
+ }
653
+ async function runAnchoredChildCommand(lease, command, args, options, hooks) {
654
+ const startedAt = Date.now();
655
+ const empty = (overrides) => ({
656
+ exitCode: null, timedOut: false, durationMs: Date.now() - startedAt,
657
+ stdout: '', stderr: '', stdoutBytes: 0, stderrBytes: 0, ...overrides,
658
+ });
659
+ if (options.signal?.aborted)
660
+ return empty({ signal: 'SIGTERM', cancelled: true });
661
+ if (!command || command.length > 4096 || command.includes('\0') || args.length > 512
662
+ || args.some((arg) => arg.length > 32768 || arg.includes('\0'))) {
663
+ return empty({ exitCode: 73, stderr: 'continuous-child-invocation-invalid', stderrBytes: 35 });
664
+ }
665
+ const parentPath = dirname(lease.workspacePath);
666
+ const parentEntry = await lstat(parentPath, { bigint: true });
667
+ const parentIdentity = await stat(parentPath, { bigint: true });
668
+ if (!parentEntry.isDirectory() || parentEntry.isSymbolicLink() || !parentIdentity.isDirectory()
669
+ || parentEntry.dev !== parentIdentity.dev || parentEntry.ino !== parentIdentity.ino) {
670
+ return empty({ exitCode: 73, stderr: 'continuous-child-parent-invalid', stderrBytes: 31 });
671
+ }
672
+ await hooks.beforeHandoff?.();
673
+ const encoded = Buffer.from(JSON.stringify({ command, args: [...args] })).toString('base64url');
674
+ const maxOutputBytes = options.maxOutputBytes ?? 64_000;
675
+ const timeoutMs = Math.max(1, Math.min(options.timeoutMs ?? 10 * 60 * 1000, 30 * 60 * 1000));
676
+ return await new Promise((resolveCommand) => {
677
+ const child = spawn(process.execPath, [
678
+ '-e', ANCHORED_CHILD_HELPER,
679
+ String(parentIdentity.dev), String(parentIdentity.ino), basename(lease.workspacePath),
680
+ lease.workspaceIdentity.dev, lease.workspaceIdentity.ino, encoded, hooks.afterHandoff ? '1' : '0',
681
+ ], { cwd: parentPath, env: options.env, stdio: ['pipe', 'pipe', 'pipe'] });
682
+ let stdout = '';
683
+ let stderr = '';
684
+ let stdoutBytes = 0;
685
+ let stderrBytes = 0;
686
+ let settled = false;
687
+ let timedOut = false;
688
+ let cancelled = false;
689
+ let handoffStarted = !hooks.afterHandoff;
690
+ const finish = (exitCode, signal) => {
691
+ if (settled)
692
+ return;
693
+ settled = true;
694
+ clearTimeout(timer);
695
+ options.signal?.removeEventListener('abort', abort);
696
+ resolveCommand({
697
+ exitCode, ...(signal ? { signal } : {}), timedOut, ...(cancelled ? { cancelled: true } : {}),
698
+ durationMs: Date.now() - startedAt, stdout, stderr, stdoutBytes, stderrBytes,
699
+ });
700
+ };
701
+ const abort = () => { cancelled = true; child.kill('SIGTERM'); };
702
+ options.signal?.addEventListener('abort', abort, { once: true });
703
+ const timer = setTimeout(() => { timedOut = true; child.kill('SIGTERM'); }, timeoutMs);
704
+ child.stdout.on('data', (chunk) => {
705
+ stdoutBytes += chunk.length;
706
+ if (stdoutBytes + stderrBytes > maxOutputBytes)
707
+ child.kill('SIGTERM');
708
+ else
709
+ stdout += chunk.toString('utf8');
710
+ });
711
+ child.stderr.on('data', (chunk) => {
712
+ stderrBytes += chunk.length;
713
+ if (stdoutBytes + stderrBytes > maxOutputBytes)
714
+ child.kill('SIGTERM');
715
+ else
716
+ stderr += chunk.toString('utf8');
717
+ if (!handoffStarted && stderr.includes('continuous-child-handoff-ready\n')) {
718
+ handoffStarted = true;
719
+ Promise.resolve(hooks.afterHandoff?.())
720
+ .then(() => child.stdin.end())
721
+ .catch(() => child.kill('SIGTERM'));
722
+ }
723
+ });
724
+ child.once('error', () => finish(null));
725
+ child.once('close', (code, signal) => finish(code, signal));
726
+ if (!hooks.afterHandoff)
727
+ child.stdin.end();
728
+ });
729
+ }
730
+ async function git(cwd, args) {
731
+ return (await gitRaw(cwd, args)).trim();
732
+ }
733
+ async function gitRaw(cwd, args) {
734
+ const result = await execFileAsync('git', args, { cwd, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 });
735
+ return String(result.stdout);
736
+ }
737
+ async function gitOptional(cwd, args) {
738
+ try {
739
+ return await git(cwd, args);
740
+ }
741
+ catch (error) {
742
+ if (isNodeError(error, 'ENOENT'))
743
+ return undefined;
744
+ throw error;
745
+ }
746
+ }
747
+ async function gitExitOk(cwd, args) {
748
+ try {
749
+ await git(cwd, args);
750
+ return true;
751
+ }
752
+ catch {
753
+ return false;
754
+ }
755
+ }
756
+ async function gitWithInput(cwd, args, input) {
757
+ return await new Promise((resolveProcess) => {
758
+ const child = spawn('git', [...args], { cwd, stdio: ['pipe', 'ignore', 'ignore'] });
759
+ child.once('error', () => resolveProcess(false));
760
+ child.once('close', (code) => resolveProcess(code === 0));
761
+ child.stdin.end(input);
762
+ });
763
+ }
764
+ async function gitBlob(cwd, revision, path) {
765
+ try {
766
+ const result = await execFileAsync('git', ['show', `${revision}:${path}`], { cwd, encoding: 'buffer', maxBuffer: 16 * 1024 * 1024 });
767
+ return Buffer.from(result.stdout);
768
+ }
769
+ catch (error) {
770
+ if (isNodeError(error, 'ENOENT'))
771
+ return undefined;
772
+ throw error;
773
+ }
774
+ }
775
+ async function readOptional(path) {
776
+ try {
777
+ return await readFile(path);
778
+ }
779
+ catch (error) {
780
+ if (isNodeError(error, 'ENOENT'))
781
+ return undefined;
782
+ throw error;
783
+ }
784
+ }
785
+ async function writeOptional(boundaryRootInput, relativePathInput, content, beforeCommit) {
786
+ const relativePath = normalizeRepositoryPath(relativePathInput);
787
+ if (!safeRelativePath(relativePath))
788
+ throw new Error('continuous-sandbox-write-path-invalid');
789
+ const boundaryRoot = await realpath(boundaryRootInput);
790
+ if (boundaryRoot !== resolve(boundaryRootInput))
791
+ throw new Error('continuous-sandbox-write-root-symlink');
792
+ const parentRelative = dirname(relativePath) === '.' ? '' : dirname(relativePath);
793
+ const parentPath = await ensureContainedDirectoryPath(boundaryRoot, parentRelative);
794
+ const parentIdentity = await directoryIdentity(parentPath);
795
+ const destinationPath = join(parentPath, basename(relativePath));
796
+ await assertContainedDestination(destinationPath, boundaryRoot, true);
797
+ if (content === undefined) {
798
+ await beforeCommit?.({ boundaryRoot, relativePath, destinationPath });
799
+ await assertSameDirectoryIdentity(parentPath, boundaryRoot, parentIdentity);
800
+ await assertContainedDestination(destinationPath, boundaryRoot, true);
801
+ await anchoredRemoveFile(parentPath, basename(relativePath));
802
+ return;
803
+ }
804
+ await beforeCommit?.({ boundaryRoot, relativePath, destinationPath });
805
+ await assertSameDirectoryIdentity(parentPath, boundaryRoot, parentIdentity);
806
+ await assertContainedDestination(destinationPath, boundaryRoot, true);
807
+ await anchoredAtomicWriteFile(parentPath, basename(relativePath), content);
808
+ await assertContainedDestination(destinationPath, boundaryRoot, false);
809
+ }
810
+ async function ensureContainedDirectoryPath(boundaryRoot, relativeDirectory) {
811
+ let current = boundaryRoot;
812
+ for (const component of relativeDirectory.split('/').filter(Boolean)) {
813
+ current = join(current, component);
814
+ await anchoredEnsureDirectory(dirname(current), basename(current));
815
+ const entry = await lstat(current);
816
+ if (!entry.isDirectory() || entry.isSymbolicLink() || await realpath(current) !== current) {
817
+ throw new Error('continuous-sandbox-write-component-unsafe');
818
+ }
819
+ assertPathContained(boundaryRoot, current);
820
+ }
821
+ return current;
822
+ }
823
+ async function assertContainedDestination(path, boundaryRoot, allowMissing) {
824
+ assertPathContained(boundaryRoot, path);
825
+ try {
826
+ const entry = await lstat(path);
827
+ if (entry.isSymbolicLink() || !entry.isFile())
828
+ throw new Error('continuous-sandbox-write-destination-unsafe');
829
+ if (await realpath(path) !== path)
830
+ throw new Error('continuous-sandbox-write-destination-symlink');
831
+ }
832
+ catch (error) {
833
+ if (allowMissing && isNodeError(error, 'ENOENT'))
834
+ return;
835
+ throw error;
836
+ }
837
+ }
838
+ function assertPathContained(boundaryRoot, candidate) {
839
+ const relation = relative(boundaryRoot, candidate);
840
+ if (relation === '' || relation.startsWith('..') || isAbsolute(relation)) {
841
+ throw new Error('continuous-sandbox-write-containment-invalid');
842
+ }
843
+ }
844
+ async function directoryIdentity(path) {
845
+ const entry = await lstat(path, { bigint: true });
846
+ if (!entry.isDirectory() || entry.isSymbolicLink())
847
+ throw new Error('continuous-sandbox-write-parent-unsafe');
848
+ return { dev: entry.dev, ino: entry.ino };
849
+ }
850
+ async function sameDirectoryIdentity(path, boundaryRoot, expected) {
851
+ try {
852
+ if (path !== boundaryRoot)
853
+ assertPathContained(boundaryRoot, path);
854
+ if (await realpath(path) !== path)
855
+ return false;
856
+ const current = await directoryIdentity(path);
857
+ return current.dev === expected.dev && current.ino === expected.ino;
858
+ }
859
+ catch {
860
+ return false;
861
+ }
862
+ }
863
+ async function assertSameDirectoryIdentity(path, boundaryRoot, expected) {
864
+ if (!(await sameDirectoryIdentity(path, boundaryRoot, expected))) {
865
+ throw new Error('continuous-sandbox-write-parent-raced');
866
+ }
867
+ }
868
+ async function snapshotPaths(root, paths) {
869
+ return await Promise.all(paths.map(async (path) => {
870
+ const content = await readOptional(join(root, path));
871
+ return { path, ...(content !== undefined ? { content } : {}) };
872
+ }));
873
+ }
874
+ async function restoreIntegration(root, snapshots) {
875
+ const paths = snapshots.map((snapshot) => snapshot.path);
876
+ if (paths.length > 0)
877
+ await gitExitOk(root, ['reset', '--quiet', 'HEAD', '--', ...paths]);
878
+ for (const snapshot of snapshots)
879
+ await writeOptional(root, snapshot.path, snapshot.content);
880
+ }
881
+ async function acquireRootWriterLease(lease, nowIso) {
882
+ try {
883
+ const statePath = join(lease.projectRoot, '.neocortex/state.json');
884
+ const tracked = asRecord(JSON.parse((await readFile(statePath)).toString('utf8')));
885
+ const legacyEpic = asRecordOrUndefined(asRecordOrUndefined(tracked.epics)?.[lease.epicId]);
886
+ const legacyLease = asRecordOrUndefined(legacyEpic?.branch_lease);
887
+ const requested = Object.freeze({
888
+ schemaVersion: 1,
889
+ ownerStoryId: lease.storyId,
890
+ sessionId: lease.dispatchId,
891
+ idempotencyKey: lease.dispatchId,
892
+ acquiredAt: nowIso,
893
+ expiresAt: new Date(Date.parse(nowIso) + 10 * 60 * 1000).toISOString(),
894
+ });
895
+ let blocked = false;
896
+ await mutateGitLifecycleRuntime(lease.projectRoot, (document) => {
897
+ const epic = ensureRuntimeEpic(document, lease.epicId);
898
+ const current = asRecordOrUndefined(epic.branch_lease) ?? legacyLease;
899
+ if (current && typeof current.expiresAt === 'string' && current.expiresAt > nowIso
900
+ && (current.ownerStoryId !== lease.storyId || current.idempotencyKey !== lease.dispatchId)) {
901
+ blocked = true;
902
+ return;
903
+ }
904
+ epic.branch_mode = 'epic';
905
+ epic.execution_branch = lease.executionBranch;
906
+ epic.branch_lease = requested;
907
+ });
908
+ if (blocked)
909
+ return failure('continuous-epic-checkout-writer-active');
910
+ return { ok: true, value: requested };
911
+ }
912
+ catch {
913
+ return failure('continuous-writer-lease-persist-failed');
914
+ }
915
+ }
916
+ async function releaseRootWriterLease(lease) {
917
+ await mutateGitLifecycleRuntime(lease.projectRoot, (document) => {
918
+ const epic = ensureRuntimeEpic(document, lease.epicId);
919
+ const current = asRecordOrUndefined(epic.branch_lease);
920
+ if (current?.ownerStoryId === lease.storyId && current.idempotencyKey === lease.dispatchId)
921
+ epic.branch_lease = null;
922
+ });
923
+ }
924
+ async function persistRootCheckpoint(input) {
925
+ try {
926
+ const statePath = join(input.lease.projectRoot, '.neocortex/state.json');
927
+ const checkpoint = Object.freeze({
928
+ schemaVersion: 1,
929
+ storyId: input.lease.storyId,
930
+ epicId: input.lease.epicId,
931
+ branch: input.lease.executionBranch,
932
+ baseSha: input.baseSha,
933
+ headSha: input.headSha,
934
+ commits: Object.freeze([input.headSha]),
935
+ idempotencyKey: input.lease.dispatchId,
936
+ dispatchId: input.lease.dispatchId,
937
+ bundleId: input.bundle.bundleId,
938
+ bundleDigest: input.bundle.bundleDigest,
939
+ graphRevision: input.lease.graphRevision,
940
+ claimRevision: input.lease.claimRevision,
941
+ receiptRefs: Object.freeze([...new Set(input.receiptRefs)]),
942
+ qaVerdict: 'passed',
943
+ reviewVerdict: 'approved',
944
+ qaReceipt: input.qaReceipt,
945
+ reviewReceipt: input.reviewReceipt,
946
+ recordedAt: input.recordedAt,
947
+ });
948
+ const tracked = asRecord(JSON.parse((await readFile(statePath)).toString('utf8')));
949
+ const trackedStory = asRecordOrUndefined(asRecordOrUndefined(tracked.stories)?.[input.lease.storyId]);
950
+ let outcome = 'persisted';
951
+ let reused;
952
+ let writerAtCas;
953
+ let authorityRuntimeAtCas;
954
+ let storyAtCasBefore;
955
+ let storyAtCasExisted = false;
956
+ let epicLeaseAtCasBefore;
957
+ const physicalGuard = async (candidate, runtimeDocument, trackedDocument) => {
958
+ const currentBranch = await gitOptional(input.lease.projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
959
+ const currentHead = await git(input.lease.projectRoot, ['rev-parse', 'HEAD']);
960
+ if (currentBranch !== input.lease.executionBranch || currentHead !== input.headSha) {
961
+ throw new Error('continuous-checkpoint-head-raced');
962
+ }
963
+ if (candidate.graphRevision !== input.lease.graphRevision
964
+ || candidate.claimRevision !== input.lease.claimRevision
965
+ || candidate.bundleId !== input.bundle.bundleId
966
+ || candidate.bundleDigest !== input.bundle.bundleDigest) {
967
+ throw new Error('continuous-checkpoint-graph-raced');
968
+ }
969
+ const currentTracked = trackedDocument
970
+ ?? asRecord(JSON.parse((await readFile(statePath)).toString('utf8')));
971
+ const effective = applyGitLifecycleRuntimeOverlay(currentTracked, runtimeDocument ?? await readGitLifecycleRuntime(input.lease.projectRoot));
972
+ const currentEpic = asRecordOrUndefined(asRecordOrUndefined(effective.epics)?.[input.lease.epicId]);
973
+ const currentStory = asRecordOrUndefined(asRecordOrUndefined(effective.stories)?.[input.lease.storyId]);
974
+ const dependencies = Array.isArray(currentStory?.depends_on)
975
+ ? currentStory.depends_on.filter((value) => typeof value === 'string')
976
+ : [];
977
+ const effectiveStories = asRecordOrUndefined(effective.stories);
978
+ if (currentEpic?.execution_branch !== input.lease.executionBranch
979
+ || dependencies.some((dependencyId) => {
980
+ const dependency = asRecordOrUndefined(effectiveStories?.[dependencyId]);
981
+ return !dependency || !['done', 'completed', 'merged'].includes(String(dependency.status));
982
+ })) {
983
+ throw new Error('continuous-checkpoint-dependency-raced');
984
+ }
985
+ const changedPaths = splitNull(await gitRaw(input.lease.projectRoot, [
986
+ 'diff-tree', '--no-commit-id', '--name-only', '-r', '-z', input.headSha,
987
+ ]));
988
+ if (changedPaths.length === 0
989
+ || changedPaths.some((path) => !input.lease.authorizedWriteSet.some((scope) => writeSetCovers(scope, path)))) {
990
+ throw new Error('continuous-checkpoint-write-set-raced');
991
+ }
992
+ if (!(await verifyAcceptedGitLifecycleStoryCheckpoint(input.lease.projectRoot, candidate, input.lease.storyId, input.lease.epicId, input.lease.executionBranch, undefined, input.lease.authorizedWriteSet)))
993
+ throw new Error('continuous-checkpoint-receipt-revalidation-failed');
994
+ };
995
+ const runtimeBefore = await readGitLifecycleRuntime(input.lease.projectRoot, { required: true });
996
+ const writerBefore = asRecordOrUndefined(asRecordOrUndefined(runtimeBefore.epics[input.lease.epicId])?.branch_lease);
997
+ if (writerBefore?.ownerStoryId !== input.lease.storyId
998
+ || writerBefore.idempotencyKey !== input.lease.dispatchId
999
+ || writerBefore.sessionId !== input.lease.dispatchId
1000
+ || typeof writerBefore.expiresAt !== 'string'
1001
+ || Date.parse(writerBefore.expiresAt) <= (input.checkpointNow?.('before-mutation') ?? Date.now())) {
1002
+ return failure('continuous-checkpoint-writer-lease-lost');
1003
+ }
1004
+ if (!(await verifyGitLifecyclePhysicalIntegrationLock(input.physicalLock.path, input.physicalLock.owner))) {
1005
+ return failure('continuous-checkpoint-integration-lock-raced');
1006
+ }
1007
+ const trackedAuthorityBytes = await readFile(statePath);
1008
+ const trackedAuthorityDigest = createHash('sha256').update(trackedAuthorityBytes).digest('hex');
1009
+ await physicalGuard(checkpoint, runtimeBefore);
1010
+ const authorityBefore = currentGraphAuthoritySnapshot(asRecord(JSON.parse(trackedAuthorityBytes.toString('utf8'))), runtimeBefore, input.lease.epicId, input.lease.storyId);
1011
+ if (authorityBefore.revision !== input.checkpointAuthority.revision
1012
+ || authorityBefore.epoch !== input.checkpointAuthority.epoch
1013
+ || authorityBefore.storyStatus !== input.checkpointAuthority.storyStatus) {
1014
+ return failure('continuous-graph-revision-stale');
1015
+ }
1016
+ const persistedMutation = await mutateGitLifecycleRuntime(input.lease.projectRoot, (document) => {
1017
+ const epic = ensureRuntimeEpic(document, input.lease.epicId);
1018
+ const writer = asRecordOrUndefined(epic.branch_lease);
1019
+ writerAtCas = writer === undefined ? undefined : structuredClone(writer);
1020
+ authorityRuntimeAtCas = structuredClone(document);
1021
+ storyAtCasExisted = document.stories[input.lease.storyId] !== undefined;
1022
+ storyAtCasBefore = structuredClone(document.stories[input.lease.storyId] ?? {});
1023
+ epicLeaseAtCasBefore = structuredClone(epic.branch_lease);
1024
+ const story = ensureRuntimeStory(document, input.lease.storyId);
1025
+ const existing = asRecordOrUndefined(story.checkpoint) ?? asRecordOrUndefined(trackedStory?.checkpoint);
1026
+ if (existing?.idempotencyKey === input.lease.dispatchId) {
1027
+ if (existing.baseSha !== input.baseSha || existing.headSha !== input.headSha
1028
+ || existing.bundleId !== input.bundle.bundleId
1029
+ || existing.bundleDigest !== input.bundle.bundleDigest
1030
+ || existing.graphRevision !== input.lease.graphRevision
1031
+ || existing.claimRevision !== input.lease.claimRevision) {
1032
+ outcome = 'conflict';
1033
+ }
1034
+ else {
1035
+ outcome = 'reused';
1036
+ reused = existing;
1037
+ epic.branch_lease = null;
1038
+ }
1039
+ return;
1040
+ }
1041
+ if (writer?.ownerStoryId !== input.lease.storyId
1042
+ || writer.idempotencyKey !== input.lease.dispatchId
1043
+ || writer.sessionId !== input.lease.dispatchId) {
1044
+ outcome = 'lease-lost';
1045
+ return;
1046
+ }
1047
+ story.checkpoint = checkpoint;
1048
+ story.status = 'done';
1049
+ story.last_step = GIT_LIFECYCLE_REVIEW_PR_STEP_ID;
1050
+ const steps = Array.isArray(story.steps_completed) ? story.steps_completed.filter((item) => typeof item === 'string') : [];
1051
+ story.steps_completed = [...new Set([...steps, GIT_LIFECYCLE_COMMIT_PUSH_STEP_ID, GIT_LIFECYCLE_REVIEW_PR_STEP_ID])];
1052
+ epic.branch_lease = null;
1053
+ }, {
1054
+ expectedRevision: runtimeBefore.revision,
1055
+ preCommit: async (document) => {
1056
+ if (writerAtCas?.ownerStoryId !== input.lease.storyId
1057
+ || writerAtCas.idempotencyKey !== input.lease.dispatchId
1058
+ || writerAtCas.sessionId !== input.lease.dispatchId
1059
+ || typeof writerAtCas.expiresAt !== 'string'
1060
+ || Date.parse(writerAtCas.expiresAt) <= (input.checkpointNow?.('pre-commit') ?? Date.now())) {
1061
+ throw new Error('continuous-checkpoint-writer-lease-lost');
1062
+ }
1063
+ await input.insideCheckpointPreCommit?.({
1064
+ projectRoot: input.lease.projectRoot,
1065
+ storyId: input.lease.storyId,
1066
+ headSha: input.headSha,
1067
+ });
1068
+ if (!(await verifyGitLifecyclePhysicalIntegrationLock(input.physicalLock.path, input.physicalLock.owner))) {
1069
+ throw new Error('continuous-checkpoint-integration-lock-raced');
1070
+ }
1071
+ await physicalGuard(reused ?? checkpoint, document);
1072
+ const finalTrackedBytes = await readFile(statePath);
1073
+ if (createHash('sha256').update(finalTrackedBytes).digest('hex') !== trackedAuthorityDigest) {
1074
+ throw new Error('continuous-graph-revision-stale');
1075
+ }
1076
+ if (!authorityRuntimeAtCas)
1077
+ throw new Error('continuous-checkpoint-authority-missing');
1078
+ const finalTracked = asRecord(JSON.parse(finalTrackedBytes.toString('utf8')));
1079
+ const authorityAtCas = currentGraphAuthoritySnapshot(finalTracked, authorityRuntimeAtCas, input.lease.epicId, input.lease.storyId);
1080
+ if (authorityAtCas.revision !== input.checkpointAuthority.revision
1081
+ || authorityAtCas.epoch !== input.checkpointAuthority.epoch
1082
+ || authorityAtCas.storyStatus !== input.checkpointAuthority.storyStatus) {
1083
+ throw new Error('continuous-graph-revision-stale');
1084
+ }
1085
+ if (outcome === 'persisted'
1086
+ && !exactPersistedCheckpointProjection(finalTracked, document, input.lease, checkpoint)) {
1087
+ throw new Error('continuous-checkpoint-projection-raced');
1088
+ }
1089
+ },
1090
+ });
1091
+ // The outcome is assigned inside the serialized mutation callback. TypeScript
1092
+ // does not model writes performed by a callback, so re-widen it here.
1093
+ const finalOutcome = outcome;
1094
+ if (finalOutcome === 'conflict')
1095
+ return failure('continuous-checkpoint-idempotency-conflict');
1096
+ if (finalOutcome === 'lease-lost')
1097
+ return failure('continuous-checkpoint-writer-lease-lost');
1098
+ if (finalOutcome === 'reused' && reused) {
1099
+ try {
1100
+ await physicalGuard(reused);
1101
+ return { ok: true, value: reused };
1102
+ }
1103
+ catch {
1104
+ return failure('continuous-checkpoint-reused-evidence-invalid');
1105
+ }
1106
+ }
1107
+ try {
1108
+ await input.afterCheckpointPersist?.({
1109
+ projectRoot: input.lease.projectRoot,
1110
+ storyId: input.lease.storyId,
1111
+ headSha: input.headSha,
1112
+ });
1113
+ const runtimeAfterPersist = await readGitLifecycleRuntime(input.lease.projectRoot, { required: true });
1114
+ if (runtimeAfterPersist.revision !== persistedMutation.document.revision) {
1115
+ throw new Error('continuous-checkpoint-post-persist-runtime-raced');
1116
+ }
1117
+ await physicalGuard(checkpoint, runtimeAfterPersist);
1118
+ const finalTrackedBytes = await readFile(statePath);
1119
+ if (createHash('sha256').update(finalTrackedBytes).digest('hex') !== trackedAuthorityDigest) {
1120
+ throw new Error('continuous-checkpoint-post-persist-authority-raced');
1121
+ }
1122
+ const finalTracked = asRecord(JSON.parse(finalTrackedBytes.toString('utf8')));
1123
+ if (!exactPersistedCheckpointProjection(finalTracked, runtimeAfterPersist, input.lease, checkpoint)) {
1124
+ throw new Error('continuous-checkpoint-post-persist-projection-raced');
1125
+ }
1126
+ }
1127
+ catch {
1128
+ const cleanupTrackedBytes = await readFile(statePath).catch(() => undefined);
1129
+ const trackedAuthorityChanged = cleanupTrackedBytes === undefined
1130
+ || createHash('sha256').update(cleanupTrackedBytes).digest('hex') !== trackedAuthorityDigest;
1131
+ await mutateGitLifecycleRuntime(input.lease.projectRoot, (document) => {
1132
+ const epic = asRecordOrUndefined(document.epics[input.lease.epicId]);
1133
+ const story = asRecordOrUndefined(document.stories[input.lease.storyId]);
1134
+ const cleanupTracked = cleanupTrackedBytes === undefined
1135
+ ? undefined
1136
+ : asRecord(JSON.parse(cleanupTrackedBytes.toString('utf8')));
1137
+ if (!epic || !story || !cleanupTracked
1138
+ || !exactPersistedCheckpointProjection(cleanupTracked, document, input.lease, checkpoint)) {
1139
+ throw new Error('continuous-checkpoint-cleanup-cas-conflict');
1140
+ }
1141
+ if (trackedAuthorityChanged) {
1142
+ if (storyAtCasExisted)
1143
+ restoreRecord(story, storyAtCasBefore ?? {});
1144
+ else
1145
+ delete document.stories[input.lease.storyId];
1146
+ if (epicLeaseAtCasBefore === undefined)
1147
+ delete epic.branch_lease;
1148
+ else
1149
+ epic.branch_lease = structuredClone(epicLeaseAtCasBefore);
1150
+ return;
1151
+ }
1152
+ story.checkpoint = null;
1153
+ story.status = 'blocked';
1154
+ epic.branch_lease = null;
1155
+ }, { expectedRevision: persistedMutation.document.revision }).catch(() => undefined);
1156
+ return failure('continuous-checkpoint-post-persist-raced');
1157
+ }
1158
+ return { ok: true, value: checkpoint };
1159
+ }
1160
+ catch (error) {
1161
+ const reasonCode = error instanceof Error && /^continuous-/.test(error.message)
1162
+ ? error.message
1163
+ : 'continuous-checkpoint-persist-failed';
1164
+ return failure(reasonCode);
1165
+ }
1166
+ }
1167
+ async function produceIndependentCheckpointEvidence(input) {
1168
+ try {
1169
+ if (await git(input.lease.projectRoot, ['rev-parse', 'HEAD']) !== input.headSha) {
1170
+ return failure('continuous-story-evidence-head-raced');
1171
+ }
1172
+ const manifestRaw = await readFile(join(input.lease.projectRoot, 'config', 'release-gates.v2.json'), 'utf8');
1173
+ const manifest = JSON.parse(manifestRaw);
1174
+ const gateIds = Array.isArray(manifest.requiredCompleteClasses)
1175
+ ? manifest.requiredCompleteClasses.filter((item) => typeof item === 'string' && /^[a-z0-9-]+$/.test(item))
1176
+ : [];
1177
+ if (manifest.contract !== 'P205-CI-02' || gateIds.length === 0) {
1178
+ return failure('continuous-story-qa-manifest-invalid');
1179
+ }
1180
+ const qaOutput = String((await execFileAsync(process.execPath, ['scripts/test-root.mjs', '--gate', 'complete'], {
1181
+ cwd: input.lease.projectRoot,
1182
+ encoding: 'utf8',
1183
+ maxBuffer: 32 * 1024 * 1024,
1184
+ })).stdout);
1185
+ await input.qaRunner?.({ projectRoot: input.lease.projectRoot, storyId: input.lease.storyId, headSha: input.headSha });
1186
+ if (await git(input.lease.projectRoot, ['rev-parse', 'HEAD']) !== input.headSha) {
1187
+ return failure('continuous-story-qa-head-raced');
1188
+ }
1189
+ const checkedAt = normalizeEvidenceTime(input.nowIso);
1190
+ const commitCount = await git(input.lease.projectRoot, ['rev-list', '--count', `${input.baseSha}..${input.headSha}`]);
1191
+ const commitBody = await gitRaw(input.lease.projectRoot, ['show', '--no-patch', '--format=%H%n%P%n%B', input.headSha]);
1192
+ const changedPaths = splitNull(await gitRaw(input.lease.projectRoot, ['diff', '--name-only', '-z', `${input.baseSha}..${input.headSha}`]));
1193
+ const gitEvidenceDigest = computeImmutableStoryQaEvidenceDigest({
1194
+ storyId: input.lease.storyId, baseSha: input.baseSha, headSha: input.headSha,
1195
+ bundleDigest: input.bundle.bundleDigest, graphRevision: input.lease.graphRevision,
1196
+ commitBody, changedPaths,
1197
+ });
1198
+ const manifestDigest = createHash('sha256').update(manifestRaw).digest('hex');
1199
+ const resultDigest = createHash('sha256').update(qaOutput).digest('hex');
1200
+ const qaSourceDigest = computeP205StoryQaEvidenceDigest({
1201
+ gitEvidenceDigest, headSha: input.headSha, graphRevision: input.lease.graphRevision,
1202
+ manifestDigest, gateIds, resultDigest,
1203
+ });
1204
+ const qaReceiptRef = `story-qa:${qaSourceDigest}`;
1205
+ const qaReceipt = Object.freeze({
1206
+ schemaVersion: 1, kind: 'story_qa_evidence', producer: 'local-yolo-tdd', evidenceVersion: 'p205-execution-v2',
1207
+ storyId: input.lease.storyId, epicId: input.lease.epicId,
1208
+ baseSha: input.baseSha, headSha: input.headSha,
1209
+ bundleDigest: input.bundle.bundleDigest, graphRevision: input.lease.graphRevision,
1210
+ contract: 'P205-CI-02', command: P205_COMPLETE_COMMAND,
1211
+ manifestDigest, gateIds: Object.freeze(gateIds), resultDigest,
1212
+ sourceEvidenceDigest: qaSourceDigest, verdict: 'passed', checkedAt, receiptRef: qaReceiptRef,
1213
+ });
1214
+ const trailers = [
1215
+ `Neocortex-Story: ${input.lease.storyId}`,
1216
+ `Neocortex-Epic: ${input.lease.epicId}`,
1217
+ `Neocortex-Bundle-Digest: ${input.bundle.bundleDigest}`,
1218
+ `Neocortex-Graph-Revision: ${input.lease.graphRevision}`,
1219
+ ];
1220
+ if (commitCount !== '1' || !trailers.every((trailer) => commitBody.includes(trailer))
1221
+ || changedPaths.length === 0
1222
+ || changedPaths.some((path) => !input.lease.authorizedWriteSet.some((authorized) => writeSetCovers(authorized, path)))) {
1223
+ return failure('continuous-story-review-evidence-rejected');
1224
+ }
1225
+ const reviewSourceDigest = createHash('sha256').update([
1226
+ 'root-commit-range-review-v1', input.lease.storyId, input.baseSha, input.headSha,
1227
+ input.bundle.bundleDigest, input.lease.graphRevision, qaReceiptRef,
1228
+ createHash('sha256').update(commitBody).digest('hex'), [...changedPaths].sort().join(','),
1229
+ ].join('\0')).digest('hex');
1230
+ const reviewReceiptRef = `story-review:${reviewSourceDigest}`;
1231
+ const reviewReceipt = Object.freeze({
1232
+ schemaVersion: 1, kind: 'story_review_evidence', producer: 'root-commit-range-review',
1233
+ storyId: input.lease.storyId, epicId: input.lease.epicId,
1234
+ baseSha: input.baseSha, headSha: input.headSha,
1235
+ bundleDigest: input.bundle.bundleDigest, graphRevision: input.lease.graphRevision,
1236
+ sourceEvidenceDigest: reviewSourceDigest, qaReceiptRef,
1237
+ verdict: 'approved', reviewedAt: checkedAt, receiptRef: reviewReceiptRef,
1238
+ });
1239
+ return { ok: true, value: { qaReceipt, reviewReceipt } };
1240
+ }
1241
+ catch {
1242
+ return failure('continuous-story-evidence-production-failed');
1243
+ }
1244
+ }
1245
+ function normalizeEvidenceTime(value) {
1246
+ return Number.isFinite(Date.parse(value)) ? new Date(Date.parse(value)).toISOString() : new Date().toISOString();
1247
+ }
1248
+ function filterChildGitState(baseContent, childContent, storyId) {
1249
+ if (childContent === undefined)
1250
+ return undefined;
1251
+ try {
1252
+ const base = baseContent === undefined ? {} : asRecord(JSON.parse(baseContent.toString('utf8')));
1253
+ const untrustedChild = asRecord(JSON.parse(childContent.toString('utf8')));
1254
+ const child = structuredClone(base);
1255
+ const baseStory = asRecordOrUndefined(asRecordOrUndefined(base.stories)?.[storyId]);
1256
+ const untrustedStory = asRecordOrUndefined(asRecordOrUndefined(untrustedChild.stories)?.[storyId]);
1257
+ const stories = ensureRecord(child, 'stories');
1258
+ const childStory = structuredClone(baseStory ?? {});
1259
+ for (const field of [
1260
+ 'status', 'last_step', 'steps_completed', 'last_updated', 'blocked_reason',
1261
+ 'blocked_at', 'implementation_evidence', 'validation_evidence', 'qa_gate',
1262
+ ]) {
1263
+ if (untrustedStory && Object.prototype.hasOwnProperty.call(untrustedStory, field)) {
1264
+ childStory[field] = structuredClone(untrustedStory[field]);
1265
+ }
1266
+ }
1267
+ stories[storyId] = childStory;
1268
+ return Buffer.from(`${JSON.stringify(child, null, 2)}\n`);
1269
+ }
1270
+ catch {
1271
+ return Buffer.from('{invalid-child-state');
1272
+ }
1273
+ }
1274
+ function ensureRecord(parent, key) {
1275
+ const current = asRecordOrUndefined(parent[key]);
1276
+ if (current)
1277
+ return current;
1278
+ const created = {};
1279
+ parent[key] = created;
1280
+ return created;
1281
+ }
1282
+ function asRecord(value) {
1283
+ if (!value || typeof value !== 'object' || Array.isArray(value))
1284
+ throw new Error('record expected');
1285
+ return value;
1286
+ }
1287
+ function asRecordOrUndefined(value) {
1288
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
1289
+ }
1290
+ function mergeBuffers(base, root, child) {
1291
+ if (sameBuffer(child, base) || sameBuffer(root, child))
1292
+ return { ok: true, value: root };
1293
+ if (sameBuffer(root, base))
1294
+ return { ok: true, value: child };
1295
+ return failure('continuous-context-merge-conflict');
1296
+ }
1297
+ function mergeJsonBuffers(base, root, child) {
1298
+ try {
1299
+ const merged = mergeJsonValue(parseJson(base), parseJson(root), parseJson(child));
1300
+ return merged.ok ? { ok: true, value: merged.value === undefined ? undefined : Buffer.from(`${JSON.stringify(merged.value, null, 2)}\n`) } : merged;
1301
+ }
1302
+ catch {
1303
+ return failure('continuous-state-merge-invalid');
1304
+ }
1305
+ }
1306
+ function parseJson(value) {
1307
+ return value === undefined ? undefined : JSON.parse(value.toString('utf8'));
1308
+ }
1309
+ function mergeJsonValue(base, root, child) {
1310
+ if (sameJson(child, base) || sameJson(root, child))
1311
+ return { ok: true, value: root };
1312
+ if (sameJson(root, base))
1313
+ return { ok: true, value: child };
1314
+ if (isPlainRecord(base) && isPlainRecord(root) && isPlainRecord(child)) {
1315
+ const merged = {};
1316
+ for (const key of [...new Set([...Object.keys(base), ...Object.keys(root), ...Object.keys(child)])].sort()) {
1317
+ const value = mergeJsonValue(base[key], root[key], child[key]);
1318
+ if (!value.ok)
1319
+ return value;
1320
+ if (value.value !== undefined)
1321
+ merged[key] = value.value;
1322
+ }
1323
+ return { ok: true, value: merged };
1324
+ }
1325
+ if (Array.isArray(base) && Array.isArray(root) && Array.isArray(child) && isJsonPrefix(base, root) && isJsonPrefix(base, child)) {
1326
+ const values = [...base, ...root.slice(base.length), ...child.slice(base.length)];
1327
+ const seen = new Set();
1328
+ return { ok: true, value: values.filter((item) => {
1329
+ const key = JSON.stringify(item);
1330
+ if (seen.has(key))
1331
+ return false;
1332
+ seen.add(key);
1333
+ return true;
1334
+ }) };
1335
+ }
1336
+ return failure('continuous-state-merge-conflict');
1337
+ }
1338
+ function isPlainRecord(value) {
1339
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
1340
+ }
1341
+ function isJsonPrefix(prefix, value) {
1342
+ return prefix.length <= value.length && prefix.every((item, index) => sameJson(item, value[index]));
1343
+ }
1344
+ function sameJson(left, right) {
1345
+ return JSON.stringify(left) === JSON.stringify(right);
1346
+ }
1347
+ function sameBuffer(left, right) {
1348
+ return left === undefined || right === undefined ? left === right : left.equals(right);
1349
+ }
1350
+ function splitNull(value) {
1351
+ return value.split('\0').filter(Boolean);
1352
+ }
1353
+ function safeRelativePath(value) {
1354
+ const normalized = normalizeRepositoryPath(value);
1355
+ return normalized.length > 0 && normalized.length <= 1024 && !isAbsolute(normalized)
1356
+ && !/^[A-Za-z]:\//.test(normalized) && !normalized.split('/').includes('..')
1357
+ && !normalized.includes('\0') && !normalized.startsWith('/');
1358
+ }
1359
+ function normalizeRepositoryPath(value) {
1360
+ return value.replaceAll('\\', '/').replace(/^\.\//, '').replace(/\/{2,}/g, '/');
1361
+ }
1362
+ function normalizeWriteSet(values) {
1363
+ const normalized = values.map(normalizeRepositoryPath).filter(safeRelativePath);
1364
+ return [...new Set(normalized)].sort();
1365
+ }
1366
+ function writeSetCovers(authorized, changed) {
1367
+ const scope = normalizeRepositoryPath(authorized);
1368
+ const path = normalizeRepositoryPath(changed);
1369
+ return scope === path || scope.endsWith('/') && path.startsWith(scope);
1370
+ }
1371
+ function safeBranch(value) {
1372
+ return value.length > 0 && value.length <= 240 && !value.startsWith('-') && !value.startsWith('/')
1373
+ && !value.endsWith('/') && !value.endsWith('.lock') && !value.includes('..') && !value.includes('\\')
1374
+ && !value.includes('@{') && !value.includes('//') && /^[A-Za-z0-9._/-]+$/.test(value);
1375
+ }
1376
+ function sameStrings(left, right) {
1377
+ return left.length === right.length && left.every((value, index) => value === right[index]);
1378
+ }
1379
+ async function readCurrentGraphAuthoritySnapshot(projectRoot, epicId, storyId, runtimeDocument) {
1380
+ const tracked = asRecord(JSON.parse(await readFile(join(projectRoot, '.neocortex/state.json'), 'utf8')));
1381
+ return currentGraphAuthoritySnapshot(tracked, runtimeDocument ?? await readGitLifecycleRuntime(projectRoot), epicId, storyId);
1382
+ }
1383
+ function currentGraphAuthoritySnapshot(tracked, runtimeDocument, epicId, storyId) {
1384
+ const effective = applyGitLifecycleRuntimeOverlay(tracked, runtimeDocument);
1385
+ const epics = asRecordOrUndefined(effective.epics);
1386
+ const stories = asRecordOrUndefined(effective.stories);
1387
+ const epic = asRecordOrUndefined(epics?.[epicId]) ?? {};
1388
+ const authoredStoryIds = (Array.isArray(epic.stories) ? epic.stories : Array.isArray(epic.story_ids) ? epic.story_ids : [])
1389
+ .filter((value) => typeof value === 'string');
1390
+ const storyIds = authoredStoryIds.length > 0
1391
+ ? authoredStoryIds
1392
+ : Object.entries(stories ?? {})
1393
+ .filter(([storyId, value]) => {
1394
+ const story = asRecordOrUndefined(value);
1395
+ return story?.epic_id === epicId || storyId.startsWith(`${epicId}.`);
1396
+ })
1397
+ .map(([storyId]) => storyId)
1398
+ .sort();
1399
+ const authorityFields = [
1400
+ 'status', 'depends_on', 'files_to_modify', 'contracts', 'contract_refs', 'shared_surfaces',
1401
+ 'steps_completed', 'last_step', 'branch_name', 'physicalMergeStatus', 'merged', 'checkpoint',
1402
+ 'planning', 'attempts', 'retry_count', 'rollback_receipt', 'cancelled_at',
1403
+ ];
1404
+ const storyAuthority = Object.fromEntries(storyIds.map((storyId) => {
1405
+ const story = asRecordOrUndefined(stories?.[storyId]) ?? {};
1406
+ return [storyId, Object.fromEntries(authorityFields
1407
+ .filter((field) => Object.prototype.hasOwnProperty.call(story, field))
1408
+ .map((field) => [field, story[field]]))];
1409
+ }));
1410
+ return {
1411
+ revision: hashCanonical({
1412
+ epicId,
1413
+ epic: {
1414
+ stories: storyIds,
1415
+ status: epic.status ?? null,
1416
+ branch_mode: epic.branch_mode ?? null,
1417
+ execution_branch: epic.execution_branch ?? null,
1418
+ graph_revision: epic.graph_revision ?? null,
1419
+ depends_on: epic.depends_on ?? null,
1420
+ planning: epic.planning ?? null,
1421
+ execution_plan: epic.execution_plan ?? null,
1422
+ waves: epic.waves ?? null,
1423
+ current_wave: epic.current_wave ?? null,
1424
+ replan: epic.replan ?? null,
1425
+ replan_revision: epic.replan_revision ?? null,
1426
+ dependency_graph: epic.dependency_graph ?? null,
1427
+ scheduler: epic.scheduler ?? null,
1428
+ attempts: epic.attempts ?? null,
1429
+ retry_count: epic.retry_count ?? null,
1430
+ },
1431
+ stories: storyAuthority,
1432
+ }),
1433
+ epoch: typeof epic.graph_revision === 'string' ? epic.graph_revision : null,
1434
+ storyStatus: typeof asRecordOrUndefined(stories?.[storyId])?.status === 'string'
1435
+ ? String(asRecordOrUndefined(stories?.[storyId])?.status)
1436
+ : null,
1437
+ };
1438
+ }
1439
+ function exactPersistedCheckpointProjection(tracked, runtimeDocument, lease, checkpoint) {
1440
+ const effective = applyGitLifecycleRuntimeOverlay(tracked, runtimeDocument);
1441
+ const epic = asRecordOrUndefined(asRecordOrUndefined(effective.epics)?.[lease.epicId]);
1442
+ const story = asRecordOrUndefined(asRecordOrUndefined(effective.stories)?.[lease.storyId]);
1443
+ const steps = Array.isArray(story?.steps_completed)
1444
+ ? story.steps_completed.filter((value) => typeof value === 'string')
1445
+ : [];
1446
+ return Boolean(epic && story
1447
+ && epic.branch_lease === null
1448
+ && story.status === 'done'
1449
+ && story.last_step === GIT_LIFECYCLE_REVIEW_PR_STEP_ID
1450
+ && steps.includes(GIT_LIFECYCLE_COMMIT_PUSH_STEP_ID)
1451
+ && steps.includes(GIT_LIFECYCLE_REVIEW_PR_STEP_ID)
1452
+ && canonicalJson(story.checkpoint) === canonicalJson(checkpoint));
1453
+ }
1454
+ function restoreRecord(target, previous) {
1455
+ for (const key of Object.keys(target))
1456
+ delete target[key];
1457
+ Object.assign(target, structuredClone(previous));
1458
+ }
1459
+ async function readCurrentGraphAuthorityRevision(projectRoot, epicId) {
1460
+ return (await readCurrentGraphAuthoritySnapshot(projectRoot, epicId, '')).revision;
1461
+ }
1462
+ function hashCanonical(value) {
1463
+ return createHash('sha256').update(canonicalJson(value)).digest('hex');
1464
+ }
1465
+ function canonicalJson(value) {
1466
+ if (value === null || typeof value !== 'object')
1467
+ return JSON.stringify(value);
1468
+ if (Array.isArray(value))
1469
+ return `[${value.map(canonicalJson).join(',')}]`;
1470
+ return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, child]) => `${JSON.stringify(key)}:${canonicalJson(child)}`).join(',')}}`;
1471
+ }
1472
+ function normalizeReceiptRefs(values, dispatchId) {
1473
+ const safe = (values ?? []).filter((value) => /^[A-Za-z0-9._/:@#-]{1,200}$/.test(value) && !value.includes('..'));
1474
+ return Object.freeze([...new Set(safe.length > 0 ? safe : [`dispatch:${dispatchId}`])].sort());
1475
+ }
1476
+ function safeRef(value) {
1477
+ return value.replace(/[^A-Za-z0-9._-]/g, '-').slice(0, 80);
1478
+ }
1479
+ function failure(reasonCode) {
1480
+ return { ok: false, reasonCode };
1481
+ }
1482
+ function isNodeError(error, code) {
1483
+ return error instanceof Error && 'code' in error && error.code === code;
1484
+ }
1485
+ async function readLeaseOwner(leasePath, leasesRoot) {
1486
+ try {
1487
+ await assertGitLifecyclePrivateDirectory(leasePath, leasesRoot);
1488
+ const ownerPath = join(leasePath, 'owner.json');
1489
+ await assertGitLifecyclePrivateFile(ownerPath, leasePath);
1490
+ const parsed = JSON.parse(await readFile(ownerPath, 'utf8'));
1491
+ if (!Number.isSafeInteger(parsed.pid) || Number(parsed.pid) <= 0
1492
+ || typeof parsed.createdAt !== 'string' || !Number.isFinite(Date.parse(parsed.createdAt))
1493
+ || typeof parsed.nonce !== 'string' || !/^[a-f0-9]{32}$/.test(parsed.nonce)) {
1494
+ throw new Error('continuous-sandbox-lease-owner-invalid');
1495
+ }
1496
+ return { pid: Number(parsed.pid), createdAt: parsed.createdAt, nonce: parsed.nonce };
1497
+ }
1498
+ catch (error) {
1499
+ if (isNodeError(error, 'ENOENT'))
1500
+ return undefined;
1501
+ throw error;
1502
+ }
1503
+ }
1504
+ function sameLeaseOwner(left, right) {
1505
+ return left?.pid === right.pid && left.createdAt === right.createdAt && left.nonce === right.nonce;
1506
+ }
1507
+ function processExists(pid) {
1508
+ try {
1509
+ process.kill(pid, 0);
1510
+ return true;
1511
+ }
1512
+ catch (error) {
1513
+ return isNodeError(error, 'EPERM');
1514
+ }
1515
+ }
1516
+ async function readSandboxMetadata(workspacePath, sandboxesRoot) {
1517
+ try {
1518
+ await assertGitLifecyclePrivateDirectory(workspacePath, sandboxesRoot);
1519
+ const gitDirectory = join(workspacePath, '.git');
1520
+ await assertGitLifecyclePrivateDirectory(gitDirectory, workspacePath);
1521
+ const metadataPath = join(gitDirectory, 'neocortex-sandbox.json');
1522
+ await assertGitLifecyclePrivateFile(metadataPath, gitDirectory);
1523
+ const parsed = JSON.parse(await readFile(metadataPath, 'utf8'));
1524
+ if (parsed.schemaVersion !== 1 || typeof parsed.workspaceOwnerNonce !== 'string'
1525
+ || !/^[a-f0-9]{32}$/.test(parsed.workspaceOwnerNonce)
1526
+ || !/^[a-f0-9]{64}$/.test(parsed.graphAuthorityRevision)
1527
+ || !(parsed.graphAuthorityEpoch === null || /^[a-f0-9]{64}$/.test(parsed.graphAuthorityEpoch))
1528
+ || !(parsed.graphAuthorityStoryStatus === null
1529
+ || typeof parsed.graphAuthorityStoryStatus === 'string' && parsed.graphAuthorityStoryStatus.length <= 80)
1530
+ || typeof parsed.workspaceIdentity?.dev !== 'string' || !/^[0-9]+$/.test(parsed.workspaceIdentity.dev)
1531
+ || typeof parsed.workspaceIdentity?.ino !== 'string' || !/^[0-9]+$/.test(parsed.workspaceIdentity.ino)) {
1532
+ throw new Error('continuous-sandbox-metadata-invalid');
1533
+ }
1534
+ return parsed;
1535
+ }
1536
+ catch (error) {
1537
+ if (isNodeError(error, 'ENOENT'))
1538
+ return undefined;
1539
+ throw error;
1540
+ }
1541
+ }
1542
+ async function writeSandboxMetadata(workspacePath, sandboxesRoot, metadata, beforeCommit) {
1543
+ await assertGitLifecyclePrivateDirectory(workspacePath, sandboxesRoot);
1544
+ const gitDirectory = join(workspacePath, '.git');
1545
+ await assertGitLifecyclePrivateDirectory(gitDirectory, workspacePath);
1546
+ const metadataPath = join(gitDirectory, 'neocortex-sandbox.json');
1547
+ await writeOptional(workspacePath, '.git/neocortex-sandbox.json', Buffer.from(`${JSON.stringify(metadata, null, 2)}\n`), beforeCommit);
1548
+ await assertGitLifecyclePrivateFile(metadataPath, gitDirectory);
1549
+ }
1550
+ async function readMarker(markerPath, integratedRoot) {
1551
+ try {
1552
+ await assertGitLifecyclePrivateFile(markerPath, integratedRoot);
1553
+ const parsed = JSON.parse(await readFile(markerPath, 'utf8'));
1554
+ return typeof parsed.childHeadSha === 'string' && typeof parsed.rootHeadSha === 'string'
1555
+ && /^[a-f0-9]{40,64}$/.test(parsed.childHeadSha) && /^[a-f0-9]{40,64}$/.test(parsed.rootHeadSha)
1556
+ && parsed.bundle?.schemaVersion === 1 && parsed.checkpoint?.schemaVersion === 1
1557
+ ? parsed
1558
+ : undefined;
1559
+ }
1560
+ catch (error) {
1561
+ if (isNodeError(error, 'ENOENT'))
1562
+ return undefined;
1563
+ throw error;
1564
+ }
1565
+ }
1566
+ async function checkpointExistsInRootState(lease, checkpoint) {
1567
+ try {
1568
+ const tracked = asRecord(JSON.parse(await readFile(join(lease.projectRoot, '.neocortex/state.json'), 'utf8')));
1569
+ const state = applyGitLifecycleRuntimeOverlay(tracked, await readGitLifecycleRuntime(lease.projectRoot));
1570
+ const current = asRecordOrUndefined(asRecordOrUndefined(state.stories)?.[lease.storyId]);
1571
+ const persisted = asRecordOrUndefined(current?.checkpoint);
1572
+ return persisted?.idempotencyKey === checkpoint.idempotencyKey
1573
+ && persisted.headSha === checkpoint.headSha
1574
+ && persisted.bundleDigest === checkpoint.bundleDigest
1575
+ && asRecordOrUndefined(asRecordOrUndefined(state.epics)?.[lease.epicId])?.branch_lease === null
1576
+ && await verifyAcceptedGitLifecycleStoryCheckpoint(lease.projectRoot, persisted, lease.storyId, lease.epicId, lease.executionBranch, undefined, lease.authorizedWriteSet);
1577
+ }
1578
+ catch {
1579
+ return false;
1580
+ }
1581
+ }
1582
+ async function readMatchingRootCheckpoint(lease, bundle, commit) {
1583
+ try {
1584
+ const tracked = asRecord(JSON.parse(await readFile(join(lease.projectRoot, '.neocortex/state.json'), 'utf8')));
1585
+ const state = applyGitLifecycleRuntimeOverlay(tracked, await readGitLifecycleRuntime(lease.projectRoot));
1586
+ const story = asRecordOrUndefined(asRecordOrUndefined(state.stories)?.[lease.storyId]);
1587
+ const checkpoint = asRecordOrUndefined(story?.checkpoint);
1588
+ if (checkpoint?.schemaVersion !== 1
1589
+ || checkpoint.storyId !== lease.storyId
1590
+ || checkpoint.epicId !== lease.epicId
1591
+ || checkpoint.branch !== lease.executionBranch
1592
+ || checkpoint.baseSha !== commit.baseSha
1593
+ || checkpoint.headSha !== commit.headSha
1594
+ || checkpoint.idempotencyKey !== lease.dispatchId
1595
+ || checkpoint.dispatchId !== lease.dispatchId
1596
+ || checkpoint.bundleId !== bundle.bundleId
1597
+ || checkpoint.bundleDigest !== bundle.bundleDigest
1598
+ || checkpoint.graphRevision !== lease.graphRevision
1599
+ || checkpoint.claimRevision !== lease.claimRevision
1600
+ || asRecordOrUndefined(asRecordOrUndefined(state.epics)?.[lease.epicId])?.branch_lease !== null
1601
+ || !(await verifyAcceptedGitLifecycleStoryCheckpoint(lease.projectRoot, checkpoint, lease.storyId, lease.epicId, lease.executionBranch, undefined, lease.authorizedWriteSet)))
1602
+ return undefined;
1603
+ return checkpoint;
1604
+ }
1605
+ catch {
1606
+ return undefined;
1607
+ }
1608
+ }
1609
+ async function findIntegratedDispatchCommit(lease, bundle) {
1610
+ const matches = (await gitOptional(lease.projectRoot, [
1611
+ 'log', '--format=%H', '--fixed-strings', `--grep=Neocortex-Dispatch: ${lease.dispatchId}`,
1612
+ ]))?.split('\n').filter((sha) => /^[a-f0-9]{40,64}$/.test(sha)) ?? [];
1613
+ if (matches.length !== 1)
1614
+ return undefined;
1615
+ const headSha = matches[0];
1616
+ if (!(await gitExitOk(lease.projectRoot, ['merge-base', '--is-ancestor', headSha, 'HEAD'])))
1617
+ return undefined;
1618
+ const message = await git(lease.projectRoot, ['show', '-s', '--format=%B', headSha]);
1619
+ const trailers = new Set(message.split('\n').map((line) => line.trim()));
1620
+ for (const trailer of [
1621
+ `Neocortex-Story: ${lease.storyId}`,
1622
+ `Neocortex-Epic: ${lease.epicId}`,
1623
+ `Neocortex-Execution-Branch: ${lease.executionBranch}`,
1624
+ `Neocortex-Prepared-Base: ${lease.baseSha}`,
1625
+ `Neocortex-Dispatch: ${lease.dispatchId}`,
1626
+ `Neocortex-Bundle: ${bundle.bundleId}`,
1627
+ `Neocortex-Bundle-Digest: ${bundle.bundleDigest}`,
1628
+ `Neocortex-Graph-Revision: ${lease.graphRevision}`,
1629
+ `Neocortex-Claim-Revision: ${lease.claimRevision}`,
1630
+ ])
1631
+ if (!trailers.has(trailer))
1632
+ return undefined;
1633
+ const authorityRevision = readCommitTrailer(message, 'Neocortex-Checkpoint-Authority');
1634
+ const authorityEpoch = readCommitTrailer(message, 'Neocortex-Checkpoint-Epoch');
1635
+ const authorityStoryStatus = readCommitTrailer(message, 'Neocortex-Checkpoint-Story-Status');
1636
+ if (!authorityRevision || !/^[a-f0-9]{64}$/.test(authorityRevision)
1637
+ || !authorityEpoch || !(authorityEpoch === 'null' || /^[a-f0-9]{64}$/.test(authorityEpoch))
1638
+ || !authorityStoryStatus || authorityStoryStatus.length > 80)
1639
+ return undefined;
1640
+ const parentSha = await gitOptional(lease.projectRoot, ['rev-parse', `${headSha}^`]);
1641
+ if (!parentSha || !/^[a-f0-9]{40,64}$/.test(parentSha))
1642
+ return undefined;
1643
+ const committedPaths = splitNull(await gitRaw(lease.projectRoot, [
1644
+ 'diff-tree', '--no-commit-id', '--name-only', '-r', '-z', headSha,
1645
+ ]));
1646
+ if (committedPaths.length === 0 || committedPaths.some((path) => !bundle.authorizedWriteSet.some((scope) => writeSetCovers(scope, path))))
1647
+ return undefined;
1648
+ return {
1649
+ baseSha: parentSha,
1650
+ headSha,
1651
+ checkpointAuthority: {
1652
+ revision: authorityRevision,
1653
+ epoch: authorityEpoch === 'null' ? null : authorityEpoch,
1654
+ storyStatus: authorityStoryStatus === 'null' ? null : authorityStoryStatus,
1655
+ },
1656
+ };
1657
+ }
1658
+ function readCommitTrailer(message, name) {
1659
+ const prefix = `${name}: `;
1660
+ const matches = message.split('\n').map((line) => line.trim()).filter((line) => line.startsWith(prefix));
1661
+ return matches.length === 1 ? matches[0].slice(prefix.length) : undefined;
1662
+ }
1663
+ async function writeMarker(markerPath, childHeadSha, rootHeadSha, bundle, checkpoint, beforeCommit) {
1664
+ const integratedRoot = dirname(markerPath);
1665
+ await assertGitLifecyclePrivateDirectory(integratedRoot, dirname(integratedRoot));
1666
+ try {
1667
+ await assertGitLifecyclePrivateFile(markerPath, integratedRoot);
1668
+ }
1669
+ catch (error) {
1670
+ if (!isNodeError(error, 'ENOENT'))
1671
+ throw error;
1672
+ }
1673
+ await writeOptional(integratedRoot, basename(markerPath), Buffer.from(`${JSON.stringify({ childHeadSha, rootHeadSha, bundle, checkpoint })}\n`), beforeCommit);
1674
+ await assertGitLifecyclePrivateFile(markerPath, integratedRoot);
1675
+ }