@ornexus/neocortex 4.60.73 → 4.60.75

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/dist/release-source.json +1 -1
  2. package/dist/sbom.cdx.json +1216 -1210
  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 +1 -108
  7. package/packages/client/dist/adapters/antigravity-adapter.js +2 -77
  8. package/packages/client/dist/adapters/claude-code-adapter.js +3 -79
  9. package/packages/client/dist/adapters/codex-adapter.js +2 -80
  10. package/packages/client/dist/adapters/cursor-adapter.js +4 -115
  11. package/packages/client/dist/adapters/gemini-adapter.js +2 -71
  12. package/packages/client/dist/adapters/grok-adapter.js +2 -42
  13. package/packages/client/dist/adapters/index.js +1 -22
  14. package/packages/client/dist/adapters/platform-detector.js +1 -212
  15. package/packages/client/dist/adapters/target-adapter.js +0 -12
  16. package/packages/client/dist/adapters/vscode-adapter.js +2 -72
  17. package/packages/client/dist/agent/refresh-stubs.js +2 -417
  18. package/packages/client/dist/agent/update-agent-yaml.js +1 -102
  19. package/packages/client/dist/agent/update-description.js +1 -251
  20. package/packages/client/dist/cache/crypto-utils.js +1 -78
  21. package/packages/client/dist/cache/encrypted-cache.d.ts +27 -0
  22. package/packages/client/dist/cache/encrypted-cache.js +1 -108
  23. package/packages/client/dist/cache/in-memory-asset-cache.js +1 -73
  24. package/packages/client/dist/cache/index.js +1 -13
  25. package/packages/client/dist/cache/protected-pi-boundary.js +1 -44
  26. package/packages/client/dist/checkpoint/checkpoint-client-reader.js +2 -127
  27. package/packages/client/dist/checkpoint/index.js +1 -11
  28. package/packages/client/dist/checkpoint/shared-checkpoint-types.js +1 -32
  29. package/packages/client/dist/cli.js +5 -358
  30. package/packages/client/dist/commands/activate.js +8 -394
  31. package/packages/client/dist/commands/architecture-answers.js +7 -274
  32. package/packages/client/dist/commands/architecture-memory-terminal.js +4 -253
  33. package/packages/client/dist/commands/architecture-non-ui-continuation.js +1 -100
  34. package/packages/client/dist/commands/architecture-root-binding.js +1 -51
  35. package/packages/client/dist/commands/cache-status.js +2 -112
  36. package/packages/client/dist/commands/config.js +1 -88
  37. package/packages/client/dist/commands/doctor.js +2 -635
  38. package/packages/client/dist/commands/invoke.d.ts +38 -1
  39. package/packages/client/dist/commands/invoke.js +143 -7200
  40. package/packages/client/dist/commands/legacy-epic-terminal.js +1 -71
  41. package/packages/client/dist/commands/legacy-story-branch.js +1 -96
  42. package/packages/client/dist/commands/legacy-story-pr.js +1 -276
  43. package/packages/client/dist/commands/mutation-qa-checkpoint.js +5 -285
  44. package/packages/client/dist/commands/mutation-qa-gate.js +1 -54
  45. package/packages/client/dist/commands/mutation-qa-git.js +1 -41
  46. package/packages/client/dist/commands/mutation-qa-policy.js +1 -102
  47. package/packages/client/dist/commands/mutation-qa-run.js +3 -219
  48. package/packages/client/dist/commands/mutation-qa-verdict.js +1 -149
  49. package/packages/client/dist/commands/mutation-qa.js +1 -220
  50. package/packages/client/dist/commands/native-agent.js +2 -136
  51. package/packages/client/dist/commands/planning-diagnosis.js +1 -43
  52. package/packages/client/dist/commands/planning-generation.js +1 -53
  53. package/packages/client/dist/commands/planning-memory.js +1 -40
  54. package/packages/client/dist/commands/planning-research.js +1 -42
  55. package/packages/client/dist/commands/private-session.js +1 -75
  56. package/packages/client/dist/commands/property-qa.js +1 -139
  57. package/packages/client/dist/commands/qa-control.js +1 -16
  58. package/packages/client/dist/commands/qa-scan-browser-launch.js +1 -55
  59. package/packages/client/dist/commands/qa-scan-browser-route.js +1 -28
  60. package/packages/client/dist/commands/qa-scan-capture.js +5 -663
  61. package/packages/client/dist/commands/qa-scan-discovery.js +3 -376
  62. package/packages/client/dist/commands/qa-scan-review.js +5 -826
  63. package/packages/client/dist/commands/qa-synthetic-backend-capture.js +1 -266
  64. package/packages/client/dist/commands/qa-synthetic-backend-review.js +1 -297
  65. package/packages/client/dist/commands/qa-synthetic-backend.js +2 -340
  66. package/packages/client/dist/commands/qa-synthetic-broker-port.js +1 -85
  67. package/packages/client/dist/commands/qa-synthetic-browser.js +1 -39
  68. package/packages/client/dist/commands/refactor-characterization.js +21 -671
  69. package/packages/client/dist/commands/refactor-commit.js +13 -399
  70. package/packages/client/dist/commands/refactor-control.js +3 -142
  71. package/packages/client/dist/commands/refactor-cpp-assertions.js +3 -93
  72. package/packages/client/dist/commands/refactor-review.js +5 -283
  73. package/packages/client/dist/commands/refactor-root.js +7 -588
  74. package/packages/client/dist/commands/refresh-memory.js +3 -156
  75. package/packages/client/dist/commands/shared-architecture-non-ui.js +1 -24
  76. package/packages/client/dist/commands/story-checkpoint.js +1 -171
  77. package/packages/client/dist/config/host-auth-broker.d.ts +31 -0
  78. package/packages/client/dist/config/host-auth-broker.js +1 -0
  79. package/packages/client/dist/config/host-auth-reference.d.ts +32 -0
  80. package/packages/client/dist/config/host-auth-reference.js +1 -0
  81. package/packages/client/dist/config/profile-directory.js +1 -13
  82. package/packages/client/dist/config/resolver-selection.js +1 -278
  83. package/packages/client/dist/config/secure-config.js +12 -281
  84. package/packages/client/dist/config.js +2 -223
  85. package/packages/client/dist/constants.js +1 -25
  86. package/packages/client/dist/context/context-collector.js +2 -222
  87. package/packages/client/dist/context/context-sanitizer.js +1 -145
  88. package/packages/client/dist/continuity/autonomous-governance.js +1 -285
  89. package/packages/client/dist/continuity/continuity-client-state-store.js +1 -1587
  90. package/packages/client/dist/continuity/invoke-hooks.js +1 -129
  91. package/packages/client/dist/continuity/migrations/001-initial-schema.js +2 -12
  92. package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.js +2 -12
  93. package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.js +2 -12
  94. package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.js +2 -12
  95. package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.js +2 -12
  96. package/packages/client/dist/continuity/migrations/006-native-agent-dispatches.js +2 -10
  97. package/packages/client/dist/continuity/native-agent-store.js +1 -69
  98. package/packages/client/dist/continuity/native-agent-types.d.ts +11 -0
  99. package/packages/client/dist/continuity/native-agent-types.js +1 -90
  100. package/packages/client/dist/continuity/outbox.js +1 -117
  101. package/packages/client/dist/continuity/runner-bootstrap-policy.js +1 -172
  102. package/packages/client/dist/continuity/sqlite-store.js +81 -2612
  103. package/packages/client/dist/effects/invoke-effect-gateways.js +1 -62
  104. package/packages/client/dist/errors/error-messages.d.ts +3 -0
  105. package/packages/client/dist/errors/error-messages.js +2 -228
  106. package/packages/client/dist/errors/frontmatter-diagnostics.js +1 -125
  107. package/packages/client/dist/evidence/collector.js +1 -347
  108. package/packages/client/dist/evidence/index.js +1 -1
  109. package/packages/client/dist/evidence/types.js +0 -2
  110. package/packages/client/dist/fs/atomic-state-replace.js +1 -152
  111. package/packages/client/dist/generated/command-registry.generated.js +1 -4076
  112. package/packages/client/dist/generated/public-projections.generated.js +1 -149
  113. package/packages/client/dist/git/direct-yolo-c01-retry.js +4 -138
  114. package/packages/client/dist/git/direct-yolo-checkpoint.d.ts +11 -1
  115. package/packages/client/dist/git/direct-yolo-checkpoint.js +4 -1234
  116. package/packages/client/dist/git/epic-operational-state.js +2 -672
  117. package/packages/client/dist/git/git-lifecycle-step-ids.js +1 -14
  118. package/packages/client/dist/git/git-lifecycle-store.d.ts +23 -0
  119. package/packages/client/dist/git/git-lifecycle-store.js +10 -1981
  120. package/packages/client/dist/git/legacy-story-branch-checkpoint.js +9 -259
  121. package/packages/client/dist/git/legacy-story-branch-setup.js +4 -348
  122. package/packages/client/dist/git/legacy-story-pr.js +70 -3538
  123. package/packages/client/dist/git/secure-filesystem-boundary.js +5 -182
  124. package/packages/client/dist/graph-retrieval/pre-command-hook.js +1 -284
  125. package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +1 -237
  126. package/packages/client/dist/i18n/first-run.js +2 -60
  127. package/packages/client/dist/index.d.ts +2 -0
  128. package/packages/client/dist/index.js +1 -47
  129. package/packages/client/dist/invocation/invoke-input.js +1 -24
  130. package/packages/client/dist/license/host-auth-recovery.d.ts +158 -0
  131. package/packages/client/dist/license/host-auth-recovery.js +1 -0
  132. package/packages/client/dist/license/index.js +1 -5
  133. package/packages/client/dist/license/license-client.d.ts +10 -1
  134. package/packages/client/dist/license/license-client.js +1 -304
  135. package/packages/client/dist/machine/fingerprint.js +2 -163
  136. package/packages/client/dist/machine/index.js +1 -5
  137. package/packages/client/dist/memory/project-memory-path-scope.js +1 -62
  138. package/packages/client/dist/memory/project-memory-writer.js +40 -1007
  139. package/packages/client/dist/memory/shared-project-memory-types.js +2 -253
  140. package/packages/client/dist/migrations/epic-lifecycle-backfill.js +3 -1060
  141. package/packages/client/dist/migrations/project-identity-capability.js +1 -50
  142. package/packages/client/dist/migrations/project-identity.js +7 -493
  143. package/packages/client/dist/migrations/state-json.js +4 -393
  144. package/packages/client/dist/policy/architecture-policy.js +2 -184
  145. package/packages/client/dist/policy/index.js +1 -7
  146. package/packages/client/dist/policy/shared-policy-types.js +0 -38
  147. package/packages/client/dist/policy/subagent-approval-policy.js +1 -55
  148. package/packages/client/dist/private-execution/clean-baseline.js +2 -279
  149. package/packages/client/dist/private-execution/codex-executor.js +4 -574
  150. package/packages/client/dist/private-execution/codex-host-runtime.js +1 -137
  151. package/packages/client/dist/private-execution/codex-lifecycle-guard.js +1 -97
  152. package/packages/client/dist/private-execution/codex-scoped-permissions.js +1 -128
  153. package/packages/client/dist/private-execution/delivery.js +13 -410
  154. package/packages/client/dist/private-execution/diagnosis-root-review.js +2 -294
  155. package/packages/client/dist/private-execution/frozen-handoff.js +6 -19
  156. package/packages/client/dist/private-execution/implementation-validation.js +2 -106
  157. package/packages/client/dist/private-execution/isolated-admission.js +23 -1432
  158. package/packages/client/dist/private-execution/isolated-session.js +5 -725
  159. package/packages/client/dist/private-execution/isolated-workspace.js +1 -122
  160. package/packages/client/dist/private-execution/pact-consumer-runtime.js +3 -409
  161. package/packages/client/dist/private-execution/pact-test-source.js +1 -258
  162. package/packages/client/dist/private-execution/pact-toolchain.js +3 -290
  163. package/packages/client/dist/private-execution/pact-write-set.js +1 -172
  164. package/packages/client/dist/private-execution/planning-diagnosis-checkpoint.js +5 -406
  165. package/packages/client/dist/private-execution/planning-generation-checkpoint.js +5 -462
  166. package/packages/client/dist/private-execution/planning-memory-checkpoint.js +3 -139
  167. package/packages/client/dist/private-execution/planning-research-checkpoint.js +4 -325
  168. package/packages/client/dist/private-execution/private-report-store.js +1 -42
  169. package/packages/client/dist/private-execution/property-test-candidate.js +1 -103
  170. package/packages/client/dist/private-execution/property-test-choices.js +3 -147
  171. package/packages/client/dist/private-execution/property-test-plan.js +7 -271
  172. package/packages/client/dist/private-execution/property-test-review.js +4 -258
  173. package/packages/client/dist/private-execution/property-test-runtime.js +9 -372
  174. package/packages/client/dist/private-execution/property-test-source.js +1 -139
  175. package/packages/client/dist/private-execution/root-checkpoint.js +1 -80
  176. package/packages/client/dist/private-execution/root-memory-git-evidence.js +3 -135
  177. package/packages/client/dist/private-execution/root-memory-recovery.js +1 -93
  178. package/packages/client/dist/private-execution/root-memory-request.js +1 -29
  179. package/packages/client/dist/private-execution/root-memory-scope.js +1 -178
  180. package/packages/client/dist/private-execution/root-memory-writer.js +1 -102
  181. package/packages/client/dist/private-execution/session-lease.js +1 -63
  182. package/packages/client/dist/private-execution/shared-private-admission-types.js +1 -50
  183. package/packages/client/dist/private-execution/shared-project-validation.js +1 -66
  184. package/packages/client/dist/private-execution/shared-root-memory-types.js +1 -61
  185. package/packages/client/dist/private-execution/ux-source-validation.js +1 -372
  186. package/packages/client/dist/private-execution/ux-write-set.js +2 -191
  187. package/packages/client/dist/registry/registry-reconciliation.js +1 -234
  188. package/packages/client/dist/resilience/circuit-breaker.js +1 -170
  189. package/packages/client/dist/resilience/degradation-manager.js +1 -164
  190. package/packages/client/dist/resilience/freshness-indicator.js +1 -100
  191. package/packages/client/dist/resilience/index.js +1 -8
  192. package/packages/client/dist/resilience/recovery-detector.js +1 -74
  193. package/packages/client/dist/resolvers/asset-resolver.js +0 -13
  194. package/packages/client/dist/resolvers/local-resolver.js +8 -255
  195. package/packages/client/dist/resolvers/remote-resolver.js +1 -233
  196. package/packages/client/dist/runner/binary.js +1 -404
  197. package/packages/client/dist/runner/cli.js +17 -1571
  198. package/packages/client/dist/runner/epic-background-dispatcher.d.ts +61 -0
  199. package/packages/client/dist/runner/epic-background-dispatcher.js +1 -0
  200. package/packages/client/dist/runner/headless/adapters.js +1 -49
  201. package/packages/client/dist/runner/headless/background-root.d.ts +65 -0
  202. package/packages/client/dist/runner/headless/background-root.js +1 -0
  203. package/packages/client/dist/runner/headless/claude-code-adapter.js +1 -79
  204. package/packages/client/dist/runner/headless/continuous-story-workspace.js +11 -1628
  205. package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +1 -69
  206. package/packages/client/dist/runner/headless/epic-merge-candidate-qa.d.ts +1 -1
  207. package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +2 -110
  208. package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.d.ts +2 -0
  209. package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +10 -1236
  210. package/packages/client/dist/runner/headless/epic-terminal-git-runner.d.ts +27 -2
  211. package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +2 -318
  212. package/packages/client/dist/runner/headless/fake-adapter.js +1 -62
  213. package/packages/client/dist/runner/headless/managed-environment-cleanup.d.ts +95 -0
  214. package/packages/client/dist/runner/headless/managed-environment-cleanup.js +1 -0
  215. package/packages/client/dist/runner/headless/managed-profile.js +1 -132
  216. package/packages/client/dist/runner/headless/opencode-adapter.js +2 -145
  217. package/packages/client/dist/runner/headless/prepared-story-bundle.js +1 -43
  218. package/packages/client/dist/runner/headless/resolver.js +1 -231
  219. package/packages/client/dist/runner/headless/run-yolo.js +1 -885
  220. package/packages/client/dist/runner/headless/run-yoloop.d.ts +1 -0
  221. package/packages/client/dist/runner/headless/run-yoloop.js +2 -2574
  222. package/packages/client/dist/runner/headless/types.js +2 -574
  223. package/packages/client/dist/runner/local-console.js +13 -396
  224. package/packages/client/dist/runner/portal-sync-worker.js +1 -1487
  225. package/packages/client/dist/runner/project-identity.js +1 -106
  226. package/packages/client/dist/runner/scheduler.js +7 -995
  227. package/packages/client/dist/runner-cli.js +2 -18
  228. package/packages/client/dist/state/invocation-shape.js +1 -13
  229. package/packages/client/dist/state/project-state-snapshot.d.ts +7 -0
  230. package/packages/client/dist/state/project-state-snapshot.js +1 -1731
  231. package/packages/client/dist/state/state-json-repair.js +3 -785
  232. package/packages/client/dist/state/structural-dag-projection.js +1 -118
  233. package/packages/client/dist/telemetry/index.js +1 -5
  234. package/packages/client/dist/telemetry/offline-queue.js +1 -131
  235. package/packages/client/dist/tier/index.js +1 -5
  236. package/packages/client/dist/tier/tier-aware-client.js +1 -405
  237. package/packages/client/dist/types/index.js +1 -38
  238. package/packages/client/dist/version.js +1 -27
  239. package/packages/client/dist/yolo/change-evidence-collector.d.ts +21 -1
  240. package/packages/client/dist/yolo/change-evidence-collector.js +1 -126
  241. package/packages/client/dist/yolo/invoke-envelope-capability.js +1 -62
  242. package/packages/client/dist/yolo/spec-envelope-collector.js +5 -184
  243. package/packages/client/dist/yoloop/discovery-hook.js +2 -300
  244. package/packages/client/dist/yoloop/index.js +1 -8
  245. package/packages/client/dist/yoloop/invoke-hooks.js +12 -669
  246. package/packages/client/dist/yoloop/shared-discover-epics.js +1 -1007
  247. package/packages/client/dist/yoloop/shared-yoloop-types.js +1 -33
  248. package/packages/client/dist/yoloop/target-normalization.js +1 -180
  249. package/packages/client/dist/yoloop/yoloop-client-state-store.js +1 -1920
  250. package/packages/shared/dist/invocation/explicit-intent-recovery.d.ts +83 -0
  251. package/packages/shared/dist/invocation/explicit-intent-recovery.js +187 -0
  252. package/packages/shared/dist/invocation/index.d.ts +7 -0
  253. package/packages/shared/dist/invocation/index.js +22 -0
  254. package/packages/shared/dist/yolo/change-evidence.js +1 -1
  255. package/packages/shared/dist/yoloop/epic-terminal-git.js +144 -2
  256. package/targets-stubs/antigravity/gemini.md +1 -1
  257. package/targets-stubs/antigravity/skill/SKILL.md +1 -1
  258. package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
  259. package/targets-stubs/claude-code/neocortex-root.md +2 -2
  260. package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
  261. package/targets-stubs/claude-code/neocortex.md +2 -2
  262. package/targets-stubs/codex/AGENTS.md +24 -21
  263. package/targets-stubs/codex/README.md +6 -1
  264. package/targets-stubs/codex/neocortex.toml +7 -2
  265. package/targets-stubs/cursor/agent.md +2 -2
  266. package/targets-stubs/gemini-cli/agent.md +2 -2
  267. package/targets-stubs/opencode/neocortex-root.md +16 -1
  268. package/targets-stubs/opencode/neocortex.md +6 -0
  269. package/targets-stubs/vscode/neocortex.agent.md +2 -2
@@ -1,672 +1,2 @@
1
- import { execFileSync } from 'node:child_process';
2
- import { createHash } from 'node:crypto';
3
- import { existsSync, fsyncSync, lstatSync, mkdirSync, openSync, closeSync, readFileSync, realpathSync, writeFileSync, } from 'node:fs';
4
- import { isAbsolute, join, relative, resolve } from 'node:path';
5
- import { GIT_LIFECYCLE_RUNTIME_DIRECTORY, mutateGitLifecycleRuntime, readGitLifecycleRuntime, readGitLifecycleRuntimeSync, } from './git-lifecycle-store.js';
6
- export const EPIC_OPERATIONAL_SOURCE_LIMIT_BYTES = 4 * 1024 * 1024;
7
- export const EPIC_OPERATIONAL_PAYLOAD_LIMIT_BYTES = 1024 * 1024;
8
- export const EPIC_OPERATIONAL_RECEIPT_CAP = 64;
9
- export const EPIC_OPERATIONAL_IDENTITY_CAP = 2_048;
10
- const HASH = /^[a-f0-9]{64}$/;
11
- const ID = /^P[1-9][0-9]*(?:\.[0-9]+)*$/;
12
- const SAFE_TOKEN = /^[A-Za-z0-9._:/#\-[\]]{1,240}$/;
13
- export function epicOperationalCanonicalJson(value) {
14
- if (value === null || typeof value !== 'object')
15
- return JSON.stringify(value);
16
- if (Array.isArray(value))
17
- return `[${value.map(epicOperationalCanonicalJson).join(',')}]`;
18
- return `{${Object.entries(value)
19
- .filter(([, child]) => child !== undefined)
20
- .sort(([left], [right]) => left.localeCompare(right))
21
- .map(([key, child]) => `${JSON.stringify(key)}:${epicOperationalCanonicalJson(child)}`)
22
- .join(',')}}`;
23
- }
24
- export function epicOperationalHash(domain, value) {
25
- return createHash('sha256').update(`${domain}\0${epicOperationalCanonicalJson(value)}`).digest('hex');
26
- }
27
- export function deriveEpicOperationalRepositoryFingerprint(projectRoot) {
28
- const canonicalRoot = realpathSync(resolve(projectRoot));
29
- const raw = execFileSync('git', ['rev-parse', '--git-common-dir'], {
30
- cwd: canonicalRoot,
31
- encoding: 'utf8',
32
- stdio: ['ignore', 'pipe', 'ignore'],
33
- }).trim();
34
- const absolute = isAbsolute(raw) ? resolve(raw) : resolve(canonicalRoot, raw);
35
- const commonDir = realpathSync(absolute);
36
- if (commonDir !== absolute)
37
- throw new Error('epic-operational-path-unsafe');
38
- const info = lstatSync(commonDir);
39
- if (!info.isDirectory() || info.isSymbolicLink())
40
- throw new Error('epic-operational-path-unsafe');
41
- return epicOperationalHash('p224-epic-operational-repository-v1', {
42
- commonDir,
43
- dev: Number(info.dev),
44
- ino: Number(info.ino),
45
- });
46
- }
47
- export function createEpicOperationalIdentity(projectRoot, input) {
48
- const repositoryFingerprint = deriveEpicOperationalRepositoryFingerprint(projectRoot);
49
- const base = {
50
- schemaVersion: 'EpicOperationalIdentity/1.0',
51
- epicId: input.epicId,
52
- executionBranch: input.executionBranch,
53
- graphRevision: input.graphRevision,
54
- originBindingDigest: input.originBindingDigest,
55
- repositoryFingerprint,
56
- };
57
- const identity = Object.freeze({
58
- ...base,
59
- identityHash: epicOperationalHash('p224-epic-operational-identity-v1', base),
60
- });
61
- assertEpicOperationalIdentity(identity);
62
- return identity;
63
- }
64
- export function createInitialEpicOperationalState(input) {
65
- const value = {
66
- schemaVersion: 'EpicOperationalState/1.0',
67
- repositoryFingerprint: input.identity.repositoryFingerprint,
68
- writerEpoch: 1,
69
- capabilities: ['epic-operational-state-v1', 'epic-lifecycle-backfill-v1'],
70
- identities: { [input.identity.identityHash]: input.identity },
71
- yoloop: { schemaVersion: 'CommonYoloopAuthority/1.0', ...input.yoloop },
72
- projectionBindings: {
73
- schemaVersion: 'EpicOperationalProjectionBindings/1.0',
74
- trackedState: {
75
- status: 'bound',
76
- sourceDigest: input.trackedStateDigest,
77
- authorityRevision: 0,
78
- reasonCodes: ['epic-operational-tracked-state-bound'],
79
- },
80
- sqlite: {
81
- status: input.sqliteStatus ?? 'unbound',
82
- sourceDigest: null,
83
- authorityRevision: 0,
84
- reasonCodes: input.sqliteReasonCodes ?? ['epic-operational-projection-unbound'],
85
- },
86
- },
87
- activeJournal: null,
88
- backfillReceipts: [],
89
- reconciliationReceipts: [],
90
- rollbackReceipts: [],
91
- };
92
- assertEpicOperationalState(value);
93
- return Object.freeze(value);
94
- }
95
- export function assertEpicOperationalState(value) {
96
- const item = record(value);
97
- if (!item)
98
- throw new Error('epic-operational-store-corrupt');
99
- exact(item, [
100
- 'schemaVersion', 'repositoryFingerprint', 'writerEpoch', 'capabilities',
101
- 'identities', 'yoloop', 'projectionBindings', 'activeJournal',
102
- 'backfillReceipts', 'reconciliationReceipts', 'rollbackReceipts',
103
- ]);
104
- const identities = record(item.identities);
105
- const yoloop = record(item.yoloop);
106
- const bindings = record(item.projectionBindings);
107
- if (item.schemaVersion !== 'EpicOperationalState/1.0' || !hash(item.repositoryFingerprint)
108
- || !Number.isSafeInteger(item.writerEpoch) || Number(item.writerEpoch) < 1
109
- || !Array.isArray(item.capabilities)
110
- || !sameStringSet(item.capabilities, ['epic-operational-state-v1', 'epic-lifecycle-backfill-v1'])
111
- || !identities || Object.keys(identities).length > EPIC_OPERATIONAL_IDENTITY_CAP
112
- || !yoloop || !hasExactKeys(yoloop, ['schemaVersion', 'lock', 'state', 'capabilities'])
113
- || yoloop.schemaVersion !== 'CommonYoloopAuthority/1.0'
114
- || !record(yoloop.state) || !(yoloop.lock === null || record(yoloop.lock))
115
- || !Array.isArray(yoloop.capabilities) || yoloop.capabilities.length > 16
116
- || new Set(yoloop.capabilities).size !== yoloop.capabilities.length
117
- || yoloop.capabilities.some((capability) => ![
118
- 'rollover-session-v1', 'successor-transition-v1', 'continuation-replan-v1',
119
- 'cross-epic-continuation-reconcile-v1',
120
- ].includes(String(capability)))
121
- || !bindings || !hasExactKeys(bindings, ['schemaVersion', 'trackedState', 'sqlite'])
122
- || bindings.schemaVersion !== 'EpicOperationalProjectionBindings/1.0'
123
- || !validProjectionBinding(bindings.trackedState) || !validProjectionBinding(bindings.sqlite)
124
- || !(item.activeJournal === null || validJournal(item.activeJournal))
125
- || !boundedReceipts(item.backfillReceipts, 'EpicLifecycleBackfillReceipt/1.0')
126
- || !boundedReceipts(item.reconciliationReceipts, 'YoloopCrossEpicReconciliationReceipt/1.0')
127
- || !boundedReceipts(item.rollbackReceipts, 'EpicOperationalRollbackReceipt/1.0')) {
128
- throw new Error('epic-operational-store-corrupt');
129
- }
130
- for (const [identityHash, identity] of Object.entries(identities)) {
131
- assertEpicOperationalIdentity(identity);
132
- if (identityHash !== identity.identityHash || identity.repositoryFingerprint !== item.repositoryFingerprint) {
133
- throw new Error('epic-operational-identity-mismatch');
134
- }
135
- }
136
- if (Buffer.byteLength(epicOperationalCanonicalJson(item), 'utf8') > EPIC_OPERATIONAL_SOURCE_LIMIT_BYTES) {
137
- throw new Error('epic-operational-source-oversized');
138
- }
139
- }
140
- export function readEpicOperationalState(projectRoot, context) {
141
- const document = readGitLifecycleRuntimeSync(projectRoot, { required: true });
142
- if (document.schemaVersion !== 2 || document.operational === undefined) {
143
- throw new Error('epic-operational-store-missing');
144
- }
145
- assertEpicOperationalState(document.operational);
146
- assertOperationalContext(document, document.operational, context);
147
- return { document, operational: document.operational };
148
- }
149
- export async function mutateEpicOperationalState(projectRoot, context, mutate) {
150
- try {
151
- return await mutateGitLifecycleRuntime(projectRoot, (document) => {
152
- if (document.schemaVersion !== 2 || document.operational === undefined) {
153
- throw new Error('epic-operational-store-missing');
154
- }
155
- assertEpicOperationalState(document.operational);
156
- assertOperationalContext(document, document.operational, context);
157
- return mutate(document.operational, document);
158
- }, { expectedRevision: context.expectedRevision });
159
- }
160
- catch (error) {
161
- if (error instanceof Error && error.message === 'git-lifecycle-runtime-revision-conflict') {
162
- throw new Error('epic-operational-revision-conflict');
163
- }
164
- throw error;
165
- }
166
- }
167
- export function projectEpicOperationalState(document, identityHash) {
168
- if (document.schemaVersion !== 2 || document.operational === undefined) {
169
- throw new Error('epic-operational-store-missing');
170
- }
171
- assertEpicOperationalState(document.operational);
172
- const state = document.operational;
173
- const identity = state.identities[identityHash];
174
- if (!identity)
175
- throw new Error('epic-operational-identity-mismatch');
176
- const run = record(state.yoloop.state.runControl);
177
- const pending = state.yoloop.state.pendingContinuationAuthorities ?? [];
178
- return Object.freeze({
179
- schemaVersion: 'EpicOperationalPublicProjection/1.0',
180
- repositoryFingerprint: state.repositoryFingerprint,
181
- identityHash,
182
- epicId: identity.epicId,
183
- executionBranch: identity.executionBranch,
184
- graphRevision: identity.graphRevision,
185
- storeRevision: document.revision,
186
- writerEpoch: state.writerEpoch,
187
- runId: typeof run?.runId === 'string' ? run.runId : null,
188
- runStatus: typeof run?.status === 'string' ? run.status : null,
189
- runRevision: Number.isSafeInteger(run?.revision) ? Number(run.revision) : null,
190
- snapshotHash: run?.latestSnapshotHash === null || hash(run?.latestSnapshotHash)
191
- ? run?.latestSnapshotHash : null,
192
- continuationSessionHash: epicOperationalHash('p224-common-continuation-session-v1', state.yoloop.state.continuationSession ?? null),
193
- pendingAuthorityHash: epicOperationalHash('p224-common-pending-authorities-v1', pending),
194
- pendingAuthorityCount: pending.length,
195
- lockActive: state.yoloop.lock !== null,
196
- currentSessionActive: state.yoloop.state.currentSession !== null,
197
- journalActive: state.activeJournal !== null,
198
- reasonCodes: ['epic-operational-projection-bounded'],
199
- publicSafe: true,
200
- });
201
- }
202
- export function classifyCrossEpicContinuationReconciliation(input) {
203
- let projection;
204
- try {
205
- projection = projectEpicOperationalState(input.document, input.targetIdentityHash);
206
- }
207
- catch (error) {
208
- return { kind: 'blocked', reasonCodes: [publicOperationalReason(error)] };
209
- }
210
- const operational = input.document.operational;
211
- const targetIdentity = operational.identities[input.targetIdentityHash];
212
- const session = record(operational.yoloop.state.continuationSession);
213
- if (!session)
214
- return { kind: 'not-applicable', reasonCodes: ['yoloop-cross-epic-session-missing'] };
215
- const sourceEpicId = typeof session.epicId === 'string' ? session.epicId : '';
216
- const sourceGraphRevision = typeof session.graphFingerprint === 'string' ? session.graphFingerprint : '';
217
- if (sourceEpicId === input.targetEpicId && sourceGraphRevision === input.targetGraphRevision) {
218
- return { kind: 'not-applicable', reasonCodes: ['yoloop-cross-epic-target-unchanged'] };
219
- }
220
- const reasons = [];
221
- const run = record(operational.yoloop.state.runControl);
222
- const pending = operational.yoloop.state.pendingContinuationAuthorities ?? [];
223
- if (!targetIdentity || targetIdentity.epicId !== input.targetEpicId
224
- || targetIdentity.graphRevision !== input.targetGraphRevision)
225
- reasons.push('epic-operational-identity-mismatch');
226
- if (!operational.yoloop.capabilities.includes('cross-epic-continuation-reconcile-v1'))
227
- reasons.push('yoloop-cross-epic-capability-missing');
228
- if (!run || !['success', 'exhausted'].includes(String(run.status)))
229
- reasons.push('yoloop-cross-epic-predecessor-active');
230
- if (operational.yoloop.lock !== null || operational.yoloop.state.currentSession !== null
231
- || input.legacyActivity !== 'inactive')
232
- reasons.push('yoloop-cross-epic-lock-active');
233
- if (operational.activeJournal !== null)
234
- reasons.push('epic-operational-journal-conflict');
235
- if (operational.reconciliationReceipts.length >= EPIC_OPERATIONAL_RECEIPT_CAP)
236
- reasons.push('yoloop-cross-epic-receipt-capacity');
237
- if (pending.length > 1)
238
- reasons.push('yoloop-cross-epic-authority-ambiguous');
239
- if (pending.length === 1) {
240
- const authority = record(pending[0]);
241
- const certificate = record(authority?.certificate);
242
- if (!authority || !certificate || authority.sessionId !== session.sessionId
243
- || certificate.sessionId !== session.sessionId)
244
- reasons.push('yoloop-cross-epic-authority-ambiguous');
245
- else if (authority.delegated !== false)
246
- reasons.push('yoloop-cross-epic-authority-delegated');
247
- }
248
- if (!hash(sourceGraphRevision) || !hash(session.sessionId)
249
- || projection.runId === null || projection.runRevision === null)
250
- reasons.push('yoloop-cross-epic-state-corrupt');
251
- if (reasons.length > 0)
252
- return { kind: 'blocked', reasonCodes: [...new Set(reasons)] };
253
- return {
254
- kind: 'eligible',
255
- evidence: Object.freeze({
256
- ...projection,
257
- schemaVersion: 'YoloopCrossEpicReconciliationEvidence/1.0',
258
- sourceEpicId,
259
- sourceGraphRevision,
260
- targetEpicId: input.targetEpicId,
261
- targetGraphRevision: input.targetGraphRevision,
262
- decision: 'eligible',
263
- }),
264
- };
265
- }
266
- export function buildCrossEpicContinuationPayloadHash(payload) {
267
- return epicOperationalHash('p224-cross-epic-continuation-reconcile-v1', payload);
268
- }
269
- export async function applyCrossEpicContinuationReconciliation(projectRoot, operation) {
270
- validateCrossEpicOperation(operation);
271
- let current = await readGitLifecycleRuntime(projectRoot, { required: true });
272
- if (current.schemaVersion !== 2 || current.operational === undefined)
273
- throw new Error('epic-operational-store-missing');
274
- assertEpicOperationalState(current.operational);
275
- let operational = current.operational;
276
- const expectedReceipt = crossEpicReceipt(operation);
277
- const replay = operational.reconciliationReceipts.find((receipt) => receipt.operationId === operation.operationId || receipt.idempotencyKey === operation.idempotencyKey);
278
- if (replay) {
279
- if (epicOperationalCanonicalJson(replay) !== epicOperationalCanonicalJson(expectedReceipt)
280
- || epicOperationalHash('p224-common-continuation-session-v1', operational.yoloop.state.continuationSession ?? null)
281
- !== operation.nextSessionHash
282
- || (operational.yoloop.state.pendingContinuationAuthorities?.length ?? 0) !== 0) {
283
- throw new Error('yoloop-cross-epic-replay-conflict');
284
- }
285
- return { applied: false, replay: true, receipt: replay };
286
- }
287
- if (operational.reconciliationReceipts.length >= EPIC_OPERATIONAL_RECEIPT_CAP) {
288
- throw new Error('yoloop-cross-epic-receipt-capacity');
289
- }
290
- const existingJournal = operational.activeJournal;
291
- if (existingJournal && (existingJournal.operationId !== operation.operationId
292
- || existingJournal.idempotencyKey !== operation.idempotencyKey
293
- || existingJournal.payloadHash !== operation.payloadHash)) {
294
- throw new Error('epic-operational-journal-conflict');
295
- }
296
- if (!existingJournal)
297
- assertCrossEpicPreimage(current, operational, operation);
298
- const backup = existingJournal
299
- ? verifyOperationalBackup(projectRoot, existingJournal.backupManifestRef, existingJournal.preimageDigest)
300
- : persistOperationalBackup(projectRoot, operation.operationId, operational);
301
- if (!existingJournal) {
302
- const journal = crossEpicJournal(operation, backup.digest, backup.ref, 'prepared');
303
- const result = await mutateEpicOperationalState(projectRoot, {
304
- identityHash: operation.expectedIdentityHash,
305
- expectedRevision: current.revision,
306
- expectedWriterEpoch: operation.expectedWriterEpoch,
307
- }, (state) => {
308
- state.activeJournal = journal;
309
- });
310
- current = result.document;
311
- operational = current.operational;
312
- }
313
- if (operational.activeJournal?.phase === 'prepared') {
314
- assertCrossEpicPreimage(current, operational, operation, true);
315
- const nextState = {
316
- ...operational.yoloop.state,
317
- continuationSession: operation.nextSession,
318
- pendingContinuationAuthorities: [],
319
- };
320
- const result = await mutateEpicOperationalState(projectRoot, {
321
- identityHash: operation.expectedIdentityHash,
322
- expectedRevision: current.revision,
323
- expectedWriterEpoch: operation.expectedWriterEpoch,
324
- }, (state) => {
325
- state.yoloop = { ...state.yoloop, state: nextState };
326
- state.activeJournal = {
327
- ...state.activeJournal, phase: 'authority-applied',
328
- };
329
- });
330
- current = result.document;
331
- operational = current.operational;
332
- }
333
- if (operational.activeJournal?.phase === 'authority-applied') {
334
- const result = await mutateEpicOperationalState(projectRoot, {
335
- identityHash: operation.expectedIdentityHash,
336
- expectedRevision: current.revision,
337
- expectedWriterEpoch: operation.expectedWriterEpoch,
338
- }, (state) => {
339
- state.activeJournal = {
340
- ...state.activeJournal, phase: 'projections-applied',
341
- projectionStatuses: { trackedState: 'not-applicable', sqlite: 'not-applicable' },
342
- };
343
- });
344
- current = result.document;
345
- operational = current.operational;
346
- }
347
- if (operational.activeJournal?.phase !== 'projections-applied') {
348
- throw new Error('epic-operational-journal-corrupt');
349
- }
350
- const result = await mutateEpicOperationalState(projectRoot, {
351
- identityHash: operation.expectedIdentityHash,
352
- expectedRevision: current.revision,
353
- expectedWriterEpoch: operation.expectedWriterEpoch,
354
- }, (state) => {
355
- if (state.reconciliationReceipts.length >= EPIC_OPERATIONAL_RECEIPT_CAP) {
356
- throw new Error('yoloop-cross-epic-receipt-capacity');
357
- }
358
- state.reconciliationReceipts = [
359
- ...state.reconciliationReceipts,
360
- expectedReceipt,
361
- ];
362
- state.activeJournal = null;
363
- });
364
- assertEpicOperationalState(result.document.operational);
365
- return { applied: true, replay: false, receipt: expectedReceipt };
366
- }
367
- function assertCrossEpicPreimage(document, state, operation, allowPrepared = false) {
368
- const run = record(state.yoloop.state.runControl);
369
- const pending = state.yoloop.state.pendingContinuationAuthorities ?? [];
370
- const identity = state.identities[operation.expectedIdentityHash];
371
- const session = record(state.yoloop.state.continuationSession);
372
- if ((document.revision !== operation.expectedCommonRevision && !allowPrepared)
373
- || state.writerEpoch !== operation.expectedWriterEpoch
374
- || !identity || identity.epicId !== operation.targetEpicId
375
- || identity.graphRevision !== operation.targetGraphRevision
376
- || !state.yoloop.capabilities.includes('cross-epic-continuation-reconcile-v1')
377
- || state.yoloop.lock !== null || state.yoloop.state.currentSession !== null
378
- || !run || run.runId !== operation.expectedRunId || run.status !== operation.expectedRunStatus
379
- || run.revision !== operation.expectedRunRevision
380
- || (run.latestSnapshotHash ?? null) !== operation.expectedSnapshotHash
381
- || !session || session.epicId !== operation.sourceEpicId
382
- || session.graphFingerprint !== operation.sourceGraphRevision
383
- || session.sessionId !== operation.sourceSessionId
384
- || epicOperationalHash('p224-common-continuation-session-v1', state.yoloop.state.continuationSession ?? null)
385
- !== operation.expectedSessionHash
386
- || epicOperationalHash('p224-common-pending-authorities-v1', pending) !== operation.expectedPendingHash
387
- || pending.length !== operation.expectedPendingCount) {
388
- throw new Error('yoloop-cross-epic-revision-conflict');
389
- }
390
- if (pending.length > 1 || pending.some((entry) => {
391
- const authority = record(entry);
392
- const certificate = record(authority?.certificate);
393
- return !authority || authority.delegated !== false || !certificate
394
- || authority.sessionId !== operation.sourceSessionId
395
- || certificate.sessionId !== operation.sourceSessionId;
396
- }))
397
- throw new Error('yoloop-cross-epic-authority-ambiguous');
398
- }
399
- function crossEpicReceipt(operation) {
400
- return Object.freeze({
401
- schemaVersion: 'YoloopCrossEpicReconciliationReceipt/1.0',
402
- operationId: operation.operationId,
403
- idempotencyKey: operation.idempotencyKey,
404
- payloadHash: operation.payloadHash,
405
- sourceEpicId: operation.sourceEpicId,
406
- sourceGraphRevision: operation.sourceGraphRevision,
407
- targetEpicId: operation.targetEpicId,
408
- targetGraphRevision: operation.targetGraphRevision,
409
- runId: operation.expectedRunId,
410
- previousSessionHash: operation.expectedSessionHash,
411
- nextSessionHash: operation.nextSessionHash,
412
- retiredAuthorityHash: operation.expectedPendingHash,
413
- retiredAuthorityCount: operation.expectedPendingCount,
414
- outcome: 'cross-epic-reconciled',
415
- publicSafe: true,
416
- });
417
- }
418
- function crossEpicJournal(operation, preimageDigest, backupManifestRef, phase) {
419
- return {
420
- schemaVersion: 'EpicOperationalJournal/1.0',
421
- kind: 'cross-epic-reconcile',
422
- operationId: operation.operationId,
423
- idempotencyKey: operation.idempotencyKey,
424
- payloadHash: operation.payloadHash,
425
- identityHash: operation.expectedIdentityHash,
426
- expectedRevision: operation.expectedCommonRevision,
427
- expectedWriterEpoch: operation.expectedWriterEpoch,
428
- preimageDigest,
429
- backupManifestRef,
430
- phase,
431
- projectionStatuses: { trackedState: 'not-applicable', sqlite: 'not-applicable' },
432
- reasonCodes: ['epic-operational-backup-verified'],
433
- };
434
- }
435
- function validateCrossEpicOperation(operation) {
436
- const { type: _type, payloadHash: _payloadHash, receipt: _receipt, ...payload } = operation;
437
- const nextSession = record(operation.nextSession);
438
- if (!safeOperationId(operation.operationId) || !safeOperationId(operation.idempotencyKey)
439
- || buildCrossEpicContinuationPayloadHash(payload) !== operation.payloadHash
440
- || Buffer.byteLength(epicOperationalCanonicalJson(payload), 'utf8') > EPIC_OPERATIONAL_PAYLOAD_LIMIT_BYTES
441
- || operation.expectedPendingCount < 0 || operation.expectedPendingCount > 1
442
- || !nextSession || nextSession.epicId !== operation.targetEpicId
443
- || nextSession.graphFingerprint !== operation.targetGraphRevision
444
- || !hash(nextSession.sessionId)
445
- || operation.nextSessionHash !== epicOperationalHash('p224-common-continuation-session-v1', operation.nextSession)
446
- || epicOperationalCanonicalJson(operation.receipt) !== epicOperationalCanonicalJson(crossEpicReceipt(operation))) {
447
- throw new Error('yoloop-cross-epic-replay-conflict');
448
- }
449
- }
450
- function persistOperationalBackup(projectRoot, operationId, operational) {
451
- if (!safeOperationId(operationId))
452
- throw new Error('epic-operational-backup-failed');
453
- const canonicalRoot = realpathSync(resolve(projectRoot));
454
- const rawCommon = execFileSync('git', ['rev-parse', '--git-common-dir'], { cwd: canonicalRoot, encoding: 'utf8' }).trim();
455
- const commonDir = realpathSync(isAbsolute(rawCommon) ? resolve(rawCommon) : resolve(canonicalRoot, rawCommon));
456
- const runtimeDir = join(commonDir, GIT_LIFECYCLE_RUNTIME_DIRECTORY);
457
- const backupsDir = join(runtimeDir, 'backups');
458
- assertPrivateDirectory(runtimeDir, commonDir);
459
- if (!existsSync(backupsDir))
460
- mkdirSync(backupsDir, { mode: 0o700 });
461
- assertPrivateDirectory(backupsDir, runtimeDir);
462
- const name = `${operationId}.operational.json`;
463
- const path = join(backupsDir, name);
464
- const raw = `${JSON.stringify(operational, null, 2)}\n`;
465
- const digest = createHash('sha256').update(raw).digest('hex');
466
- if (existsSync(path)) {
467
- const info = lstatSync(path);
468
- if (!info.isFile() || info.isSymbolicLink()
469
- || createHash('sha256').update(readFileSync(path)).digest('hex') !== digest) {
470
- throw new Error('epic-operational-backup-failed');
471
- }
472
- }
473
- else {
474
- const fd = openSync(path, 'wx', 0o600);
475
- try {
476
- writeFileSync(fd, raw);
477
- fsyncSync(fd);
478
- }
479
- finally {
480
- closeSync(fd);
481
- }
482
- const directoryFd = openSync(backupsDir, 'r');
483
- try {
484
- fsyncSync(directoryFd);
485
- }
486
- finally {
487
- closeSync(directoryFd);
488
- }
489
- }
490
- return { ref: `backups/${name}`, digest };
491
- }
492
- function verifyOperationalBackup(projectRoot, backupRef, expectedDigest) {
493
- if (!/^backups\/[A-Za-z0-9._-]{1,240}$/.test(backupRef) || !hash(expectedDigest)) {
494
- throw new Error('epic-operational-backup-failed');
495
- }
496
- const canonicalRoot = realpathSync(resolve(projectRoot));
497
- const rawCommon = execFileSync('git', ['rev-parse', '--git-common-dir'], {
498
- cwd: canonicalRoot,
499
- encoding: 'utf8',
500
- }).trim();
501
- const commonDir = realpathSync(isAbsolute(rawCommon) ? resolve(rawCommon) : resolve(canonicalRoot, rawCommon));
502
- const runtimeDir = join(commonDir, GIT_LIFECYCLE_RUNTIME_DIRECTORY);
503
- const path = join(runtimeDir, backupRef);
504
- assertPrivateDirectory(runtimeDir, commonDir);
505
- const info = lstatSync(path);
506
- if (!info.isFile() || info.isSymbolicLink()
507
- || createHash('sha256').update(readFileSync(path)).digest('hex') !== expectedDigest) {
508
- throw new Error('epic-operational-backup-failed');
509
- }
510
- return { ref: backupRef, digest: expectedDigest };
511
- }
512
- function assertPrivateDirectory(path, parent) {
513
- const canonicalParent = realpathSync(parent);
514
- if (relative(canonicalParent, resolve(path)).startsWith('..'))
515
- throw new Error('epic-operational-path-unsafe');
516
- const info = lstatSync(path);
517
- if (!info.isDirectory() || info.isSymbolicLink() || realpathSync(path) !== resolve(path)
518
- || (typeof process.getuid === 'function' && (info.uid !== process.getuid() || (info.mode & 0o077) !== 0))) {
519
- throw new Error('epic-operational-path-unsafe');
520
- }
521
- }
522
- function assertOperationalContext(document, state, context) {
523
- if (context?.expectedRevision !== undefined && document.revision !== context.expectedRevision) {
524
- throw new Error('epic-operational-revision-conflict');
525
- }
526
- if (context?.expectedWriterEpoch !== undefined && state.writerEpoch !== context.expectedWriterEpoch) {
527
- throw new Error('epic-operational-epoch-conflict');
528
- }
529
- if (context?.identityHash !== undefined && !state.identities[context.identityHash]) {
530
- throw new Error('epic-operational-identity-mismatch');
531
- }
532
- }
533
- function assertEpicOperationalIdentity(value) {
534
- const item = record(value);
535
- if (!item)
536
- throw new Error('epic-operational-identity-mismatch');
537
- exact(item, [
538
- 'schemaVersion', 'epicId', 'executionBranch', 'graphRevision',
539
- 'originBindingDigest', 'repositoryFingerprint', 'identityHash',
540
- ]);
541
- const { identityHash, ...base } = item;
542
- if (item.schemaVersion !== 'EpicOperationalIdentity/1.0' || !ID.test(String(item.epicId))
543
- || !safeGitRef(item.executionBranch) || !hash(item.graphRevision)
544
- || !hash(item.originBindingDigest) || !hash(item.repositoryFingerprint)
545
- || identityHash !== epicOperationalHash('p224-epic-operational-identity-v1', base)) {
546
- throw new Error('epic-operational-identity-mismatch');
547
- }
548
- }
549
- function validProjectionBinding(value) {
550
- const item = record(value);
551
- return Boolean(item && hasExactKeys(item, ['status', 'sourceDigest', 'authorityRevision', 'reasonCodes'])
552
- && ['bound', 'unbound', 'unavailable'].includes(String(item.status))
553
- && (item.sourceDigest === null || hash(item.sourceDigest))
554
- && Number.isSafeInteger(item.authorityRevision) && Number(item.authorityRevision) >= 0
555
- && Array.isArray(item.reasonCodes) && item.reasonCodes.length <= 16
556
- && item.reasonCodes.every(safeReasonCode));
557
- }
558
- function validJournal(value) {
559
- const item = record(value);
560
- const statuses = record(item?.projectionStatuses);
561
- return Boolean(item && hasExactKeys(item, [
562
- 'schemaVersion', 'kind', 'operationId', 'idempotencyKey', 'payloadHash',
563
- 'identityHash', 'expectedRevision', 'expectedWriterEpoch', 'preimageDigest',
564
- 'backupManifestRef', 'phase', 'projectionStatuses', 'reasonCodes',
565
- ]) && item.schemaVersion === 'EpicOperationalJournal/1.0'
566
- && ['backfill', 'cross-epic-reconcile', 'rollback'].includes(String(item.kind))
567
- && safeToken(item.operationId) && safeToken(item.idempotencyKey) && hash(item.payloadHash)
568
- && hash(item.identityHash) && Number.isSafeInteger(item.expectedRevision)
569
- && Number.isSafeInteger(item.expectedWriterEpoch) && hash(item.preimageDigest)
570
- && typeof item.backupManifestRef === 'string' && item.backupManifestRef.length <= 1_024
571
- && !isAbsolute(item.backupManifestRef) && !item.backupManifestRef.includes('..')
572
- && ['prepared', 'authority-applied', 'projections-applied', 'committed', 'aborted-before-authority'].includes(String(item.phase))
573
- && statuses && hasExactKeys(statuses, ['trackedState', 'sqlite'])
574
- && ['pending', 'applied', 'not-applicable'].includes(String(statuses.trackedState))
575
- && ['pending', 'applied', 'unavailable', 'not-applicable'].includes(String(statuses.sqlite))
576
- && Array.isArray(item.reasonCodes) && item.reasonCodes.length <= 16
577
- && item.reasonCodes.every(safeReasonCode));
578
- }
579
- function boundedReceipts(value, schema) {
580
- return Array.isArray(value) && value.length <= EPIC_OPERATIONAL_RECEIPT_CAP
581
- && value.every((entry) => schema === 'EpicLifecycleBackfillReceipt/1.0'
582
- ? validBackfillReceipt(entry)
583
- : schema === 'YoloopCrossEpicReconciliationReceipt/1.0'
584
- ? validReconciliationReceipt(entry)
585
- : validRollbackReceipt(entry));
586
- }
587
- function validBackfillReceipt(value) {
588
- const item = record(value);
589
- return Boolean(item && hasExactKeys(item, [
590
- 'schemaVersion', 'operationId', 'idempotencyKey', 'payloadHash', 'planDigest',
591
- 'sourceInventoryDigest', 'preimageDigest', 'postimageDigest',
592
- 'authorityPostimageDigest', 'backupManifestDigest', 'identityHash',
593
- 'appliedRevision', 'writerEpoch', 'stateMigrationOperationId', 'outcome',
594
- 'reasonCodes', 'publicSafe',
595
- ]) && item.schemaVersion === 'EpicLifecycleBackfillReceipt/1.0'
596
- && safeOperationId(item.operationId) && safeOperationId(item.idempotencyKey)
597
- && item.operationId === item.idempotencyKey
598
- && [item.payloadHash, item.planDigest, item.sourceInventoryDigest, item.preimageDigest,
599
- item.postimageDigest, item.authorityPostimageDigest, item.backupManifestDigest,
600
- item.identityHash].every(hash)
601
- && Number.isSafeInteger(item.appliedRevision) && Number(item.appliedRevision) >= 1
602
- && Number.isSafeInteger(item.writerEpoch) && Number(item.writerEpoch) >= 1
603
- && (item.stateMigrationOperationId === null || safeOperationId(item.stateMigrationOperationId))
604
- && ['applied', 'already-applied'].includes(String(item.outcome))
605
- && validReasonCodes(item.reasonCodes) && item.publicSafe === true);
606
- }
607
- function validReconciliationReceipt(value) {
608
- const item = record(value);
609
- return Boolean(item && hasExactKeys(item, [
610
- 'schemaVersion', 'operationId', 'idempotencyKey', 'payloadHash', 'sourceEpicId',
611
- 'sourceGraphRevision', 'targetEpicId', 'targetGraphRevision', 'runId',
612
- 'previousSessionHash', 'nextSessionHash', 'retiredAuthorityHash',
613
- 'retiredAuthorityCount', 'outcome', 'publicSafe',
614
- ]) && item.schemaVersion === 'YoloopCrossEpicReconciliationReceipt/1.0'
615
- && safeOperationId(item.operationId) && safeOperationId(item.idempotencyKey)
616
- && hash(item.payloadHash) && ID.test(String(item.sourceEpicId)) && ID.test(String(item.targetEpicId))
617
- && hash(item.sourceGraphRevision) && hash(item.targetGraphRevision)
618
- && safeOperationId(item.runId) && hash(item.previousSessionHash) && hash(item.nextSessionHash)
619
- && hash(item.retiredAuthorityHash) && [0, 1].includes(Number(item.retiredAuthorityCount))
620
- && item.outcome === 'cross-epic-reconciled' && item.publicSafe === true);
621
- }
622
- function validRollbackReceipt(value) {
623
- const item = record(value);
624
- return Boolean(item && hasExactKeys(item, [
625
- 'schemaVersion', 'operationId', 'targetOperationId', 'expectedPostimageDigest',
626
- 'restoredPreimageDigest', 'reasonCodes', 'publicSafe',
627
- ]) && item.schemaVersion === 'EpicOperationalRollbackReceipt/1.0'
628
- && safeOperationId(item.operationId) && safeOperationId(item.targetOperationId)
629
- && hash(item.expectedPostimageDigest) && hash(item.restoredPreimageDigest)
630
- && validReasonCodes(item.reasonCodes) && item.publicSafe === true);
631
- }
632
- function validReasonCodes(value) {
633
- return Array.isArray(value) && value.length <= 16 && value.every(safeReasonCode);
634
- }
635
- function sameStringSet(value, expected) {
636
- return value.length === expected.length && expected.every((item) => value.includes(item));
637
- }
638
- function exact(item, keys) {
639
- const allowed = new Set(keys);
640
- if (Object.keys(item).some((key) => !allowed.has(key)))
641
- throw new Error('epic-operational-store-corrupt');
642
- }
643
- function hasExactKeys(item, keys) {
644
- const actual = Object.keys(item).sort();
645
- const expected = [...keys].sort();
646
- return actual.length === expected.length && actual.every((key, index) => key === expected[index]);
647
- }
648
- function record(value) {
649
- return value && typeof value === 'object' && !Array.isArray(value)
650
- ? value : undefined;
651
- }
652
- function hash(value) {
653
- return typeof value === 'string' && HASH.test(value);
654
- }
655
- function safeToken(value) {
656
- return typeof value === 'string' && SAFE_TOKEN.test(value) && !value.includes('..');
657
- }
658
- function safeOperationId(value) {
659
- return typeof value === 'string' && /^[A-Za-z0-9._:-]{1,128}$/.test(value);
660
- }
661
- function safeReasonCode(value) {
662
- return typeof value === 'string' && /^[a-z0-9][a-z0-9-]{0,79}$/.test(value);
663
- }
664
- function safeGitRef(value) {
665
- return typeof value === 'string' && /^[A-Za-z0-9][A-Za-z0-9._/-]{0,239}$/.test(value)
666
- && !value.includes('..') && !value.includes('//') && !value.includes('@{')
667
- && !value.endsWith('/') && !value.endsWith('.');
668
- }
669
- function publicOperationalReason(error) {
670
- const reason = error instanceof Error ? error.message : '';
671
- return safeReasonCode(reason) ? reason : 'epic-operational-store-corrupt';
672
- }
1
+ import{execFileSync as O}from"node:child_process";import{createHash as S}from"node:crypto";import{existsSync as B,fsyncSync as V,lstatSync as w,mkdirSync as Y,openSync as _,closeSync as J,readFileSync as N,realpathSync as E,writeFileSync as q}from"node:fs";import{isAbsolute as x,join as R,relative as Z,resolve as y}from"node:path";import{GIT_LIFECYCLE_RUNTIME_DIRECTORY as F,mutateGitLifecycleRuntime as U,readGitLifecycleRuntime as Q,readGitLifecycleRuntimeSync as X}from"./git-lifecycle-store.js";const ee=4*1024*1024,ie=1024*1024,C=64,te=2048,oe=/^[a-f0-9]{64}$/,A=/^P[1-9][0-9]*(?:\.[0-9]+)*$/,ne=/^[A-Za-z0-9._:/#\-[\]]{1,240}$/;function m(i){return i===null||typeof i!="object"?JSON.stringify(i):Array.isArray(i)?`[${i.map(m).join(",")}]`:`{${Object.entries(i).filter(([,e])=>e!==void 0).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${m(t)}`).join(",")}}`}function g(i,e){return S("sha256").update(`${i}\0${m(e)}`).digest("hex")}function re(i){const e=E(y(i)),t=O("git",["rev-parse","--git-common-dir"],{cwd:e,encoding:"utf8",stdio:["ignore","pipe","ignore"]}).trim(),o=x(t)?y(t):y(e,t),n=E(o);if(n!==o)throw new Error("epic-operational-path-unsafe");const r=w(n);if(!r.isDirectory()||r.isSymbolicLink())throw new Error("epic-operational-path-unsafe");return g("p224-epic-operational-repository-v1",{commonDir:n,dev:Number(r.dev),ino:Number(r.ino)})}function we(i,e){const t=re(i),o={schemaVersion:"EpicOperationalIdentity/1.0",epicId:e.epicId,executionBranch:e.executionBranch,graphRevision:e.graphRevision,originBindingDigest:e.originBindingDigest,repositoryFingerprint:t},n=Object.freeze({...o,identityHash:g("p224-epic-operational-identity-v1",o)});return W(n),n}function xe(i){const e={schemaVersion:"EpicOperationalState/1.0",repositoryFingerprint:i.identity.repositoryFingerprint,writerEpoch:1,capabilities:["epic-operational-state-v1","epic-lifecycle-backfill-v1"],identities:{[i.identity.identityHash]:i.identity},yoloop:{schemaVersion:"CommonYoloopAuthority/1.0",...i.yoloop},projectionBindings:{schemaVersion:"EpicOperationalProjectionBindings/1.0",trackedState:{status:"bound",sourceDigest:i.trackedStateDigest,authorityRevision:0,reasonCodes:["epic-operational-tracked-state-bound"]},sqlite:{status:i.sqliteStatus??"unbound",sourceDigest:null,authorityRevision:0,reasonCodes:i.sqliteReasonCodes??["epic-operational-projection-unbound"]}},activeJournal:null,backfillReceipts:[],reconciliationReceipts:[],rollbackReceipts:[]};return I(e),Object.freeze(e)}function I(i){const e=p(i);if(!e)throw new Error("epic-operational-store-corrupt");z(e,["schemaVersion","repositoryFingerprint","writerEpoch","capabilities","identities","yoloop","projectionBindings","activeJournal","backfillReceipts","reconciliationReceipts","rollbackReceipts"]);const t=p(e.identities),o=p(e.yoloop),n=p(e.projectionBindings);if(e.schemaVersion!=="EpicOperationalState/1.0"||!l(e.repositoryFingerprint)||!Number.isSafeInteger(e.writerEpoch)||Number(e.writerEpoch)<1||!Array.isArray(e.capabilities)||!ge(e.capabilities,["epic-operational-state-v1","epic-lifecycle-backfill-v1"])||!t||Object.keys(t).length>te||!o||!v(o,["schemaVersion","lock","state","capabilities"])||o.schemaVersion!=="CommonYoloopAuthority/1.0"||!p(o.state)||!(o.lock===null||p(o.lock))||!Array.isArray(o.capabilities)||o.capabilities.length>16||new Set(o.capabilities).size!==o.capabilities.length||o.capabilities.some(r=>!["rollover-session-v1","successor-transition-v1","continuation-replan-v1","cross-epic-continuation-reconcile-v1"].includes(String(r)))||!n||!v(n,["schemaVersion","trackedState","sqlite"])||n.schemaVersion!=="EpicOperationalProjectionBindings/1.0"||!T(n.trackedState)||!T(n.sqlite)||!(e.activeJournal===null||ue(e.activeJournal))||!P(e.backfillReceipts,"EpicLifecycleBackfillReceipt/1.0")||!P(e.reconciliationReceipts,"YoloopCrossEpicReconciliationReceipt/1.0")||!P(e.rollbackReceipts,"EpicOperationalRollbackReceipt/1.0"))throw new Error("epic-operational-store-corrupt");for(const[r,c]of Object.entries(t))if(W(c),r!==c.identityHash||c.repositoryFingerprint!==e.repositoryFingerprint)throw new Error("epic-operational-identity-mismatch");if(Buffer.byteLength(m(e),"utf8")>ee)throw new Error("epic-operational-source-oversized")}function Ce(i,e){const t=X(i,{required:!0});if(t.schemaVersion!==2||t.operational===void 0)throw new Error("epic-operational-store-missing");return I(t.operational),K(t,t.operational,e),{document:t,operational:t.operational}}async function k(i,e,t){try{return await U(i,o=>{if(o.schemaVersion!==2||o.operational===void 0)throw new Error("epic-operational-store-missing");return I(o.operational),K(o,o.operational,e),t(o.operational,o)},{expectedRevision:e.expectedRevision})}catch(o){throw o instanceof Error&&o.message==="git-lifecycle-runtime-revision-conflict"?new Error("epic-operational-revision-conflict"):o}}function se(i,e){if(i.schemaVersion!==2||i.operational===void 0)throw new Error("epic-operational-store-missing");I(i.operational);const t=i.operational,o=t.identities[e];if(!o)throw new Error("epic-operational-identity-mismatch");const n=p(t.yoloop.state.runControl),r=t.yoloop.state.pendingContinuationAuthorities??[];return Object.freeze({schemaVersion:"EpicOperationalPublicProjection/1.0",repositoryFingerprint:t.repositoryFingerprint,identityHash:e,epicId:o.epicId,executionBranch:o.executionBranch,graphRevision:o.graphRevision,storeRevision:i.revision,writerEpoch:t.writerEpoch,runId:typeof n?.runId=="string"?n.runId:null,runStatus:typeof n?.status=="string"?n.status:null,runRevision:Number.isSafeInteger(n?.revision)?Number(n.revision):null,snapshotHash:n?.latestSnapshotHash===null||l(n?.latestSnapshotHash)?n?.latestSnapshotHash:null,continuationSessionHash:g("p224-common-continuation-session-v1",t.yoloop.state.continuationSession??null),pendingAuthorityHash:g("p224-common-pending-authorities-v1",r),pendingAuthorityCount:r.length,lockActive:t.yoloop.lock!==null,currentSessionActive:t.yoloop.state.currentSession!==null,journalActive:t.activeJournal!==null,reasonCodes:["epic-operational-projection-bounded"],publicSafe:!0})}function ke(i){let e;try{e=se(i.document,i.targetIdentityHash)}catch(d){return{kind:"blocked",reasonCodes:[Ee(d)]}}const t=i.document.operational,o=t.identities[i.targetIdentityHash],n=p(t.yoloop.state.continuationSession);if(!n)return{kind:"not-applicable",reasonCodes:["yoloop-cross-epic-session-missing"]};const r=typeof n.epicId=="string"?n.epicId:"",c=typeof n.graphFingerprint=="string"?n.graphFingerprint:"";if(r===i.targetEpicId&&c===i.targetGraphRevision)return{kind:"not-applicable",reasonCodes:["yoloop-cross-epic-target-unchanged"]};const s=[],u=p(t.yoloop.state.runControl),a=t.yoloop.state.pendingContinuationAuthorities??[];if((!o||o.epicId!==i.targetEpicId||o.graphRevision!==i.targetGraphRevision)&&s.push("epic-operational-identity-mismatch"),t.yoloop.capabilities.includes("cross-epic-continuation-reconcile-v1")||s.push("yoloop-cross-epic-capability-missing"),(!u||!["success","exhausted"].includes(String(u.status)))&&s.push("yoloop-cross-epic-predecessor-active"),(t.yoloop.lock!==null||t.yoloop.state.currentSession!==null||i.legacyActivity!=="inactive")&&s.push("yoloop-cross-epic-lock-active"),t.activeJournal!==null&&s.push("epic-operational-journal-conflict"),t.reconciliationReceipts.length>=C&&s.push("yoloop-cross-epic-receipt-capacity"),a.length>1&&s.push("yoloop-cross-epic-authority-ambiguous"),a.length===1){const d=p(a[0]),h=p(d?.certificate);!d||!h||d.sessionId!==n.sessionId||h.sessionId!==n.sessionId?s.push("yoloop-cross-epic-authority-ambiguous"):d.delegated!==!1&&s.push("yoloop-cross-epic-authority-delegated")}return(!l(c)||!l(n.sessionId)||e.runId===null||e.runRevision===null)&&s.push("yoloop-cross-epic-state-corrupt"),s.length>0?{kind:"blocked",reasonCodes:[...new Set(s)]}:{kind:"eligible",evidence:Object.freeze({...e,schemaVersion:"YoloopCrossEpicReconciliationEvidence/1.0",sourceEpicId:r,sourceGraphRevision:c,targetEpicId:i.targetEpicId,targetGraphRevision:i.targetGraphRevision,decision:"eligible"})}}function ce(i){return g("p224-cross-epic-continuation-reconcile-v1",i)}async function He(i,e){pe(e);let t=await Q(i,{required:!0});if(t.schemaVersion!==2||t.operational===void 0)throw new Error("epic-operational-store-missing");I(t.operational);let o=t.operational;const n=L(e),r=o.reconciliationReceipts.find(a=>a.operationId===e.operationId||a.idempotencyKey===e.idempotencyKey);if(r){if(m(r)!==m(n)||g("p224-common-continuation-session-v1",o.yoloop.state.continuationSession??null)!==e.nextSessionHash||(o.yoloop.state.pendingContinuationAuthorities?.length??0)!==0)throw new Error("yoloop-cross-epic-replay-conflict");return{applied:!1,replay:!0,receipt:r}}if(o.reconciliationReceipts.length>=C)throw new Error("yoloop-cross-epic-receipt-capacity");const c=o.activeJournal;if(c&&(c.operationId!==e.operationId||c.idempotencyKey!==e.idempotencyKey||c.payloadHash!==e.payloadHash))throw new Error("epic-operational-journal-conflict");c||G(t,o,e);const s=c?de(i,c.backupManifestRef,c.preimageDigest):le(i,e.operationId,o);if(!c){const a=ae(e,s.digest,s.ref,"prepared");t=(await k(i,{identityHash:e.expectedIdentityHash,expectedRevision:t.revision,expectedWriterEpoch:e.expectedWriterEpoch},h=>{h.activeJournal=a})).document,o=t.operational}if(o.activeJournal?.phase==="prepared"){G(t,o,e,!0);const a={...o.yoloop.state,continuationSession:e.nextSession,pendingContinuationAuthorities:[]};t=(await k(i,{identityHash:e.expectedIdentityHash,expectedRevision:t.revision,expectedWriterEpoch:e.expectedWriterEpoch},h=>{h.yoloop={...h.yoloop,state:a},h.activeJournal={...h.activeJournal,phase:"authority-applied"}})).document,o=t.operational}if(o.activeJournal?.phase==="authority-applied"&&(t=(await k(i,{identityHash:e.expectedIdentityHash,expectedRevision:t.revision,expectedWriterEpoch:e.expectedWriterEpoch},d=>{d.activeJournal={...d.activeJournal,phase:"projections-applied",projectionStatuses:{trackedState:"not-applicable",sqlite:"not-applicable"}}})).document,o=t.operational),o.activeJournal?.phase!=="projections-applied")throw new Error("epic-operational-journal-corrupt");const u=await k(i,{identityHash:e.expectedIdentityHash,expectedRevision:t.revision,expectedWriterEpoch:e.expectedWriterEpoch},a=>{if(a.reconciliationReceipts.length>=C)throw new Error("yoloop-cross-epic-receipt-capacity");a.reconciliationReceipts=[...a.reconciliationReceipts,n],a.activeJournal=null});return I(u.document.operational),{applied:!0,replay:!1,receipt:n}}function G(i,e,t,o=!1){const n=p(e.yoloop.state.runControl),r=e.yoloop.state.pendingContinuationAuthorities??[],c=e.identities[t.expectedIdentityHash],s=p(e.yoloop.state.continuationSession);if(i.revision!==t.expectedCommonRevision&&!o||e.writerEpoch!==t.expectedWriterEpoch||!c||c.epicId!==t.targetEpicId||c.graphRevision!==t.targetGraphRevision||!e.yoloop.capabilities.includes("cross-epic-continuation-reconcile-v1")||e.yoloop.lock!==null||e.yoloop.state.currentSession!==null||!n||n.runId!==t.expectedRunId||n.status!==t.expectedRunStatus||n.revision!==t.expectedRunRevision||(n.latestSnapshotHash??null)!==t.expectedSnapshotHash||!s||s.epicId!==t.sourceEpicId||s.graphFingerprint!==t.sourceGraphRevision||s.sessionId!==t.sourceSessionId||g("p224-common-continuation-session-v1",e.yoloop.state.continuationSession??null)!==t.expectedSessionHash||g("p224-common-pending-authorities-v1",r)!==t.expectedPendingHash||r.length!==t.expectedPendingCount)throw new Error("yoloop-cross-epic-revision-conflict");if(r.length>1||r.some(u=>{const a=p(u),d=p(a?.certificate);return!a||a.delegated!==!1||!d||a.sessionId!==t.sourceSessionId||d.sessionId!==t.sourceSessionId}))throw new Error("yoloop-cross-epic-authority-ambiguous")}function L(i){return Object.freeze({schemaVersion:"YoloopCrossEpicReconciliationReceipt/1.0",operationId:i.operationId,idempotencyKey:i.idempotencyKey,payloadHash:i.payloadHash,sourceEpicId:i.sourceEpicId,sourceGraphRevision:i.sourceGraphRevision,targetEpicId:i.targetEpicId,targetGraphRevision:i.targetGraphRevision,runId:i.expectedRunId,previousSessionHash:i.expectedSessionHash,nextSessionHash:i.nextSessionHash,retiredAuthorityHash:i.expectedPendingHash,retiredAuthorityCount:i.expectedPendingCount,outcome:"cross-epic-reconciled",publicSafe:!0})}function ae(i,e,t,o){return{schemaVersion:"EpicOperationalJournal/1.0",kind:"cross-epic-reconcile",operationId:i.operationId,idempotencyKey:i.idempotencyKey,payloadHash:i.payloadHash,identityHash:i.expectedIdentityHash,expectedRevision:i.expectedCommonRevision,expectedWriterEpoch:i.expectedWriterEpoch,preimageDigest:e,backupManifestRef:t,phase:o,projectionStatuses:{trackedState:"not-applicable",sqlite:"not-applicable"},reasonCodes:["epic-operational-backup-verified"]}}function pe(i){const{type:e,payloadHash:t,receipt:o,...n}=i,r=p(i.nextSession);if(!f(i.operationId)||!f(i.idempotencyKey)||ce(n)!==i.payloadHash||Buffer.byteLength(m(n),"utf8")>ie||i.expectedPendingCount<0||i.expectedPendingCount>1||!r||r.epicId!==i.targetEpicId||r.graphFingerprint!==i.targetGraphRevision||!l(r.sessionId)||i.nextSessionHash!==g("p224-common-continuation-session-v1",i.nextSession)||m(i.receipt)!==m(L(i)))throw new Error("yoloop-cross-epic-replay-conflict")}function le(i,e,t){if(!f(e))throw new Error("epic-operational-backup-failed");const o=E(y(i)),n=O("git",["rev-parse","--git-common-dir"],{cwd:o,encoding:"utf8"}).trim(),r=E(x(n)?y(n):y(o,n)),c=R(r,F),s=R(c,"backups");D(c,r),B(s)||Y(s,{mode:448}),D(s,c);const u=`${e}.operational.json`,a=R(s,u),d=`${JSON.stringify(t,null,2)}
2
+ `,h=S("sha256").update(d).digest("hex");if(B(a)){const b=w(a);if(!b.isFile()||b.isSymbolicLink()||S("sha256").update(N(a)).digest("hex")!==h)throw new Error("epic-operational-backup-failed")}else{const b=_(a,"wx",384);try{q(b,d),V(b)}finally{J(b)}const j=_(s,"r");try{V(j)}finally{J(j)}}return{ref:`backups/${u}`,digest:h}}function de(i,e,t){if(!/^backups\/[A-Za-z0-9._-]{1,240}$/.test(e)||!l(t))throw new Error("epic-operational-backup-failed");const o=E(y(i)),n=O("git",["rev-parse","--git-common-dir"],{cwd:o,encoding:"utf8"}).trim(),r=E(x(n)?y(n):y(o,n)),c=R(r,F),s=R(c,e);D(c,r);const u=w(s);if(!u.isFile()||u.isSymbolicLink()||S("sha256").update(N(s)).digest("hex")!==t)throw new Error("epic-operational-backup-failed");return{ref:e,digest:t}}function D(i,e){const t=E(e);if(Z(t,y(i)).startsWith(".."))throw new Error("epic-operational-path-unsafe");const o=w(i);if(!o.isDirectory()||o.isSymbolicLink()||E(i)!==y(i)||typeof process.getuid=="function"&&(o.uid!==process.getuid()||(o.mode&63)!==0))throw new Error("epic-operational-path-unsafe")}function K(i,e,t){if(t?.expectedRevision!==void 0&&i.revision!==t.expectedRevision)throw new Error("epic-operational-revision-conflict");if(t?.expectedWriterEpoch!==void 0&&e.writerEpoch!==t.expectedWriterEpoch)throw new Error("epic-operational-epoch-conflict");if(t?.identityHash!==void 0&&!e.identities[t.identityHash])throw new Error("epic-operational-identity-mismatch")}function W(i){const e=p(i);if(!e)throw new Error("epic-operational-identity-mismatch");z(e,["schemaVersion","epicId","executionBranch","graphRevision","originBindingDigest","repositoryFingerprint","identityHash"]);const{identityHash:t,...o}=e;if(e.schemaVersion!=="EpicOperationalIdentity/1.0"||!A.test(String(e.epicId))||!me(e.executionBranch)||!l(e.graphRevision)||!l(e.originBindingDigest)||!l(e.repositoryFingerprint)||t!==g("p224-epic-operational-identity-v1",o))throw new Error("epic-operational-identity-mismatch")}function T(i){const e=p(i);return!!(e&&v(e,["status","sourceDigest","authorityRevision","reasonCodes"])&&["bound","unbound","unavailable"].includes(String(e.status))&&(e.sourceDigest===null||l(e.sourceDigest))&&Number.isSafeInteger(e.authorityRevision)&&Number(e.authorityRevision)>=0&&Array.isArray(e.reasonCodes)&&e.reasonCodes.length<=16&&e.reasonCodes.every(H))}function ue(i){const e=p(i),t=p(e?.projectionStatuses);return!!(e&&v(e,["schemaVersion","kind","operationId","idempotencyKey","payloadHash","identityHash","expectedRevision","expectedWriterEpoch","preimageDigest","backupManifestRef","phase","projectionStatuses","reasonCodes"])&&e.schemaVersion==="EpicOperationalJournal/1.0"&&["backfill","cross-epic-reconcile","rollback"].includes(String(e.kind))&&M(e.operationId)&&M(e.idempotencyKey)&&l(e.payloadHash)&&l(e.identityHash)&&Number.isSafeInteger(e.expectedRevision)&&Number.isSafeInteger(e.expectedWriterEpoch)&&l(e.preimageDigest)&&typeof e.backupManifestRef=="string"&&e.backupManifestRef.length<=1024&&!x(e.backupManifestRef)&&!e.backupManifestRef.includes("..")&&["prepared","authority-applied","projections-applied","committed","aborted-before-authority"].includes(String(e.phase))&&t&&v(t,["trackedState","sqlite"])&&["pending","applied","not-applicable"].includes(String(t.trackedState))&&["pending","applied","unavailable","not-applicable"].includes(String(t.sqlite))&&Array.isArray(e.reasonCodes)&&e.reasonCodes.length<=16&&e.reasonCodes.every(H))}function P(i,e){return Array.isArray(i)&&i.length<=C&&i.every(t=>e==="EpicLifecycleBackfillReceipt/1.0"?he(t):e==="YoloopCrossEpicReconciliationReceipt/1.0"?ye(t):fe(t))}function he(i){const e=p(i);return!!(e&&v(e,["schemaVersion","operationId","idempotencyKey","payloadHash","planDigest","sourceInventoryDigest","preimageDigest","postimageDigest","authorityPostimageDigest","backupManifestDigest","identityHash","appliedRevision","writerEpoch","stateMigrationOperationId","outcome","reasonCodes","publicSafe"])&&e.schemaVersion==="EpicLifecycleBackfillReceipt/1.0"&&f(e.operationId)&&f(e.idempotencyKey)&&e.operationId===e.idempotencyKey&&[e.payloadHash,e.planDigest,e.sourceInventoryDigest,e.preimageDigest,e.postimageDigest,e.authorityPostimageDigest,e.backupManifestDigest,e.identityHash].every(l)&&Number.isSafeInteger(e.appliedRevision)&&Number(e.appliedRevision)>=1&&Number.isSafeInteger(e.writerEpoch)&&Number(e.writerEpoch)>=1&&(e.stateMigrationOperationId===null||f(e.stateMigrationOperationId))&&["applied","already-applied"].includes(String(e.outcome))&&$(e.reasonCodes)&&e.publicSafe===!0)}function ye(i){const e=p(i);return!!(e&&v(e,["schemaVersion","operationId","idempotencyKey","payloadHash","sourceEpicId","sourceGraphRevision","targetEpicId","targetGraphRevision","runId","previousSessionHash","nextSessionHash","retiredAuthorityHash","retiredAuthorityCount","outcome","publicSafe"])&&e.schemaVersion==="YoloopCrossEpicReconciliationReceipt/1.0"&&f(e.operationId)&&f(e.idempotencyKey)&&l(e.payloadHash)&&A.test(String(e.sourceEpicId))&&A.test(String(e.targetEpicId))&&l(e.sourceGraphRevision)&&l(e.targetGraphRevision)&&f(e.runId)&&l(e.previousSessionHash)&&l(e.nextSessionHash)&&l(e.retiredAuthorityHash)&&[0,1].includes(Number(e.retiredAuthorityCount))&&e.outcome==="cross-epic-reconciled"&&e.publicSafe===!0)}function fe(i){const e=p(i);return!!(e&&v(e,["schemaVersion","operationId","targetOperationId","expectedPostimageDigest","restoredPreimageDigest","reasonCodes","publicSafe"])&&e.schemaVersion==="EpicOperationalRollbackReceipt/1.0"&&f(e.operationId)&&f(e.targetOperationId)&&l(e.expectedPostimageDigest)&&l(e.restoredPreimageDigest)&&$(e.reasonCodes)&&e.publicSafe===!0)}function $(i){return Array.isArray(i)&&i.length<=16&&i.every(H)}function ge(i,e){return i.length===e.length&&e.every(t=>i.includes(t))}function z(i,e){const t=new Set(e);if(Object.keys(i).some(o=>!t.has(o)))throw new Error("epic-operational-store-corrupt")}function v(i,e){const t=Object.keys(i).sort(),o=[...e].sort();return t.length===o.length&&t.every((n,r)=>n===o[r])}function p(i){return i&&typeof i=="object"&&!Array.isArray(i)?i:void 0}function l(i){return typeof i=="string"&&oe.test(i)}function M(i){return typeof i=="string"&&ne.test(i)&&!i.includes("..")}function f(i){return typeof i=="string"&&/^[A-Za-z0-9._:-]{1,128}$/.test(i)}function H(i){return typeof i=="string"&&/^[a-z0-9][a-z0-9-]{0,79}$/.test(i)}function me(i){return typeof i=="string"&&/^[A-Za-z0-9][A-Za-z0-9._/-]{0,239}$/.test(i)&&!i.includes("..")&&!i.includes("//")&&!i.includes("@{")&&!i.endsWith("/")&&!i.endsWith(".")}function Ee(i){const e=i instanceof Error?i.message:"";return H(e)?e:"epic-operational-store-corrupt"}export{te as EPIC_OPERATIONAL_IDENTITY_CAP,ie as EPIC_OPERATIONAL_PAYLOAD_LIMIT_BYTES,C as EPIC_OPERATIONAL_RECEIPT_CAP,ee as EPIC_OPERATIONAL_SOURCE_LIMIT_BYTES,He as applyCrossEpicContinuationReconciliation,I as assertEpicOperationalState,ce as buildCrossEpicContinuationPayloadHash,ke as classifyCrossEpicContinuationReconciliation,we as createEpicOperationalIdentity,xe as createInitialEpicOperationalState,re as deriveEpicOperationalRepositoryFingerprint,m as epicOperationalCanonicalJson,g as epicOperationalHash,k as mutateEpicOperationalState,se as projectEpicOperationalState,Ce as readEpicOperationalState};