@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,1731 +1 @@
1
- /**
2
- * @license FSL-1.1
3
- * Copyright (c) 2026 OrNexus AI
4
- *
5
- * Pure request-scoped projection helpers for invoke state snapshots.
6
- */
7
- import { createHash } from 'node:crypto';
8
- import { analyzeDependencyDag, StructuralDagError, } from './structural-dag-projection.js';
9
- import { classifyInvocationShapeV2 } from './invocation-shape.js';
10
- const RECENT_STORY_LIMIT = 12;
11
- const REASON_CODE_LIMIT = 16;
12
- const EPIC_LIFECYCLE_CLASSIFICATIONS = ['active', 'archived', 'rolled-back', 'synthetic', 'orphan'];
13
- // Publish-safe shadow of packages/shared/src/yoloop/status-policy.ts. The
14
- // standalone client tarball cannot take a runtime dependency on @neocortex/shared.
15
- const YOLOOP_ACTIVE_STORY_STATUS_SET = new Set([
16
- 'in-progress', 'branch-ready', 'diagnose', 'research', 'write-spec',
17
- 'create-tasks', 'implemented', 'refactor-suggest-done',
18
- 'property-tests-emitted', 'tests-validated', 'qa-gate-passed',
19
- 'memory-updated', 'committed', 'synced', 'pr-created', 'pr-reviewed',
20
- 'partial',
21
- ]);
22
- /**
23
- * P224.01 bounded common-authority evidence for a future invoke handoff.
24
- * This module remains pure: callers read the private store elsewhere and pass
25
- * only the already-redacted projection. Absolute paths, source bytes, unknown
26
- * private fields and certificates are intentionally impossible to project.
27
- */
28
- export function projectEpicOperationalEvidenceForRequest(value) {
29
- const hash = /^[a-f0-9]{64}$/;
30
- const safeId = /^P[1-9][0-9]*(?:\.[0-9]+)*$/;
31
- const safeBranch = /^[A-Za-z0-9][A-Za-z0-9._/-]{0,239}$/;
32
- if (value.schemaVersion !== 'EpicOperationalPublicProjection/1.0'
33
- || !hash.test(value.repositoryFingerprint)
34
- || !hash.test(value.identityHash)
35
- || !safeId.test(value.epicId)
36
- || !safeBranch.test(value.executionBranch)
37
- || !hash.test(value.graphRevision)
38
- || !Number.isSafeInteger(value.storeRevision) || value.storeRevision < 0
39
- || !Number.isSafeInteger(value.writerEpoch) || value.writerEpoch < 1
40
- || (value.runId !== null && value.runId.length > 128)
41
- || (value.runStatus !== null && value.runStatus.length > 32)
42
- || (value.runRevision !== null && (!Number.isSafeInteger(value.runRevision) || value.runRevision < 0))
43
- || (value.snapshotHash !== null && !hash.test(value.snapshotHash))
44
- || !hash.test(value.continuationSessionHash)
45
- || !hash.test(value.pendingAuthorityHash)
46
- || !Number.isSafeInteger(value.pendingAuthorityCount) || value.pendingAuthorityCount < 0
47
- || value.pendingAuthorityCount > 1_024
48
- || value.reasonCodes.length > 16
49
- || value.reasonCodes.some((reason) => !/^[a-z0-9][a-z0-9-]{0,79}$/.test(reason))
50
- || value.publicSafe !== true) {
51
- throw new Error('epic-operational-projection-invalid');
52
- }
53
- return Object.freeze({
54
- schemaVersion: value.schemaVersion,
55
- repositoryFingerprint: value.repositoryFingerprint,
56
- identityHash: value.identityHash,
57
- epicId: value.epicId,
58
- executionBranch: value.executionBranch,
59
- graphRevision: value.graphRevision,
60
- storeRevision: value.storeRevision,
61
- writerEpoch: value.writerEpoch,
62
- runId: value.runId,
63
- runStatus: value.runStatus,
64
- runRevision: value.runRevision,
65
- snapshotHash: value.snapshotHash,
66
- continuationSessionHash: value.continuationSessionHash,
67
- pendingAuthorityHash: value.pendingAuthorityHash,
68
- pendingAuthorityCount: value.pendingAuthorityCount,
69
- lockActive: value.lockActive,
70
- currentSessionActive: value.currentSessionActive,
71
- journalActive: value.journalActive,
72
- reasonCodes: [...value.reasonCodes],
73
- publicSafe: true,
74
- });
75
- }
76
- const policy = (commandId, stateProjectionPolicy, options = {}) => ({
77
- commandId,
78
- stateProjectionPolicy,
79
- ...options,
80
- });
81
- // P198.03: local publish-safe shadow of the P198.01 shared command-context
82
- // projection policies. The published CLI does not ship `packages/shared/dist`, so
83
- // this file must not add a runtime `@neocortex/shared` import until packaging is
84
- // changed. Keep ids/aliases/numbers aligned with the public command registry.
85
- const COMMAND_POLICY_BY_ID = Object.freeze({
86
- status: policy('status', 'full'),
87
- 'arch-plan': policy('arch-plan', 'full'),
88
- 'arch-prd': policy('arch-prd', 'full'),
89
- 'arch-architecture': policy('arch-architecture', 'epic-targeted', { structuralRequired: true }),
90
- 'arch-api-contracts': policy('arch-api-contracts', 'epic-targeted', { structuralRequired: true }),
91
- 'arch-api-integrations': policy('arch-api-integrations', 'epic-targeted', { structuralRequired: true }),
92
- 'arch-database': policy('arch-database', 'epic-targeted', { structuralRequired: true }),
93
- 'arch-security': policy('arch-security', 'epic-targeted', { structuralRequired: true }),
94
- 'arch-design-system': policy('arch-design-system', 'epic-targeted', { structuralRequired: true }),
95
- 'arch-ux-design': policy('arch-ux-design', 'epic-targeted', { structuralRequired: true }),
96
- 'arch-performance': policy('arch-performance', 'epic-targeted', { structuralRequired: true }),
97
- 'arch-testing': policy('arch-testing', 'epic-targeted', { structuralRequired: true }),
98
- 'arch-infrastructure': policy('arch-infrastructure', 'epic-targeted', { structuralRequired: true }),
99
- 'arch-review': policy('arch-review', 'epic-targeted', { structuralRequired: true }),
100
- 'arch-fitness-functions': policy('arch-fitness-functions', 'epic-targeted', { structuralRequired: true }),
101
- 'create-epic': policy('create-epic', 'epic-summary'),
102
- 'idea-diagnose': policy('idea-diagnose', 'full'),
103
- 'idea-research': policy('idea-research', 'epic-targeted', { structuralRequired: true }),
104
- 'generate-epic': policy('generate-epic', 'epic-targeted', { structuralRequired: true }),
105
- exec: policy('exec', 'story-targeted', { structuralRequired: true }),
106
- yolo: policy('yolo', 'story-targeted', { structuralRequired: true }),
107
- 'yolo-inline': policy('yolo-inline', 'story-targeted', { structuralRequired: true }),
108
- epic: policy('epic', 'epic-targeted', { structuralRequired: true }),
109
- 'setup-branch': policy('setup-branch', 'story-targeted', { structuralRequired: true }),
110
- diagnose: policy('diagnose', 'adaptive-targeted'),
111
- 'diagnose-inline': policy('diagnose-inline', 'full'),
112
- research: policy('research', 'adaptive-targeted'),
113
- 'research-inline': policy('research-inline', 'full'),
114
- 'write-spec': policy('write-spec', 'story-targeted', { structuralRequired: true }),
115
- 'create-tasks': policy('create-tasks', 'story-targeted', { structuralRequired: true }),
116
- implement: policy('implement', 'story-targeted', { structuralRequired: true }),
117
- commit: policy('commit', 'story-targeted', { structuralRequired: true }),
118
- 'commit-push': policy('commit', 'story-targeted', { structuralRequired: true }),
119
- sync: policy('sync', 'story-targeted', { structuralRequired: true }),
120
- 'sync-main': policy('sync', 'story-targeted', { structuralRequired: true }),
121
- 'create-pr': policy('create-pr', 'story-targeted', { structuralRequired: true }),
122
- review: policy('review', 'story-targeted'),
123
- 'review-pr': policy('review', 'story-targeted'),
124
- merge: policy('merge', 'story-targeted', { structuralRequired: true }),
125
- 'merge-pr': policy('merge', 'story-targeted', { structuralRequired: true }),
126
- 'fix-blocked': policy('fix-blocked', 'story-targeted'),
127
- 'finalize-epic': policy('finalize-epic', 'epic-targeted'),
128
- 'resolve-conflicts': policy('resolve-conflicts', 'story-targeted'),
129
- 'update-memory': policy('update-memory', 'full'),
130
- 'update-project-memory': policy('update-memory', 'story-targeted', { structuralRequired: true }),
131
- refactor: policy('refactor', 'adaptive-targeted'),
132
- 'refactor-suggest': policy('refactor', 'story-targeted', { structuralRequired: true }),
133
- cleanup: policy('cleanup', 'full'),
134
- audit: policy('audit', 'full'),
135
- 'tech-debt': policy('tech-debt', 'full'),
136
- menu: policy('menu', 'full'),
137
- plans: policy('plans', 'full'),
138
- billing: policy('billing', 'full'),
139
- subscribe: policy('subscribe', 'full'),
140
- 'qa-scan': policy('qa-scan', 'full'),
141
- yoloop: policy('yoloop', 'yoloop-targeted', { structuralRequired: true }),
142
- 'migrate-state': policy('migrate-state', 'full'),
143
- 'migrate-project-id': policy('migrate-project-id', 'full'),
144
- 'policy-audit': policy('policy-audit', 'full'),
145
- 'mutation-test': policy('mutation-test', 'full'),
146
- 'sync-openapi': policy('sync-openapi', 'full'),
147
- 'generate-pacts': policy('generate-pacts', 'full'),
148
- 'verify-pacts': policy('verify-pacts', 'full'),
149
- 'property-test': policy('property-test', 'full'),
150
- 'property-tests': policy('property-test', 'story-targeted', { structuralRequired: true }),
151
- 'chaos-plan': policy('chaos-plan', 'full'),
152
- 'ui-ux-review': policy('ui-ux-review', 'adaptive-targeted'),
153
- 'solyd-system': policy('solyd-system', 'adaptive-targeted'),
154
- goal: policy('goal', 'continuity-scoped'),
155
- loop: policy('loop', 'continuity-scoped'),
156
- jobs: policy('jobs', 'continuity-scoped'),
157
- runner: policy('runner', 'continuity-scoped'),
158
- 'goal-tick': policy('goal-tick', 'continuity-scoped'),
159
- 'loop-tick': policy('loop-tick', 'continuity-scoped'),
160
- 'validate-tests': policy('validate-tests', 'story-targeted', { structuralRequired: true }),
161
- 'qa-gate': policy('qa-gate', 'story-targeted', { structuralRequired: true }),
162
- });
163
- const COMMAND_ALIAS_TO_ID = Object.freeze({
164
- st: 'status',
165
- arquitetura: 'arch-plan',
166
- architecture: 'arch-plan',
167
- arch: 'arch-plan',
168
- prd: 'arch-prd',
169
- 'product-requirements': 'arch-prd',
170
- 'arch-doc': 'arch-architecture',
171
- 'tech-architecture': 'arch-architecture',
172
- 'api-contracts': 'arch-api-contracts',
173
- 'api-contract': 'arch-api-contracts',
174
- 'api-integrations': 'arch-api-integrations',
175
- 'api-int': 'arch-api-integrations',
176
- 'database-schema': 'arch-database',
177
- 'db-schema': 'arch-database',
178
- db: 'arch-database',
179
- 'cyber-security': 'arch-security',
180
- security: 'arch-security',
181
- sec: 'arch-security',
182
- 'design-system': 'arch-design-system',
183
- ds: 'arch-design-system',
184
- 'atomic-design': 'arch-design-system',
185
- 'ux-design': 'arch-ux-design',
186
- ux: 'arch-ux-design',
187
- wireframes: 'arch-ux-design',
188
- wireframe: 'arch-ux-design',
189
- 'user-flows': 'arch-ux-design',
190
- performance: 'arch-performance',
191
- perf: 'arch-performance',
192
- 'capacity-planning': 'arch-performance',
193
- capacity: 'arch-performance',
194
- 'arch-perf': 'arch-performance',
195
- 'performance-strategy': 'arch-performance',
196
- 'testing-strategy': 'arch-testing',
197
- 'test-plan': 'arch-testing',
198
- 'test-strategy': 'arch-testing',
199
- 'arch-test': 'arch-testing',
200
- infrastructure: 'arch-infrastructure',
201
- infra: 'arch-infrastructure',
202
- 'deploy-plan': 'arch-infrastructure',
203
- deployment: 'arch-infrastructure',
204
- 'arch-infra': 'arch-infrastructure',
205
- 'arch-deploy': 'arch-infrastructure',
206
- 'review-consolidation': 'arch-review',
207
- consolidation: 'arch-review',
208
- 'architecture-review': 'arch-review',
209
- 'arch-consolidation': 'arch-review',
210
- fitness: 'arch-fitness-functions',
211
- 'fitness-functions': 'arch-fitness-functions',
212
- archfit: 'arch-fitness-functions',
213
- 'arch-fit': 'arch-fitness-functions',
214
- 'fit-funcs': 'arch-fitness-functions',
215
- 'criar-epic': 'create-epic',
216
- planejamento: 'create-epic',
217
- 'idea-diag': 'idea-diagnose',
218
- 'idea-pesq': 'idea-research',
219
- 'gerar-epic': 'generate-epic',
220
- executar: 'exec',
221
- pipeline: 'exec',
222
- 'parallel-epic': 'epic',
223
- setup: 'setup-branch',
224
- branch: 'setup-branch',
225
- diag: 'diagnose',
226
- diagnostico: 'diagnose',
227
- c02: 'diagnose',
228
- pesquisar: 'research',
229
- pesq: 'research',
230
- 'research-fix': 'research',
231
- c03: 'research',
232
- spec: 'write-spec',
233
- especificacao: 'write-spec',
234
- c04: 'write-spec',
235
- tasks: 'create-tasks',
236
- tarefas: 'create-tasks',
237
- c05: 'create-tasks',
238
- impl: 'implement',
239
- implementar: 'implement',
240
- c06: 'implement',
241
- push: 'commit',
242
- 'commit_push': 'commit',
243
- cp: 'commit',
244
- c07: 'commit',
245
- sincronizar: 'sync',
246
- c08: 'sync',
247
- pr: 'create-pr',
248
- c09: 'create-pr',
249
- revisar: 'review',
250
- c11: 'review',
251
- mesclar: 'merge',
252
- c12: 'merge',
253
- fix: 'fix-blocked',
254
- corrigir: 'fix-blocked',
255
- finalizar: 'finalize-epic',
256
- conflitos: 'resolve-conflicts',
257
- memoria: 'update-memory',
258
- refactoring: 'refactor',
259
- refact: 'refactor',
260
- refac: 'refactor',
261
- rf: 'refactor',
262
- 'cleanup-code': 'refactor',
263
- 'code-cleanup': 'refactor',
264
- 'code-quality': 'refactor',
265
- 'improve-code': 'refactor',
266
- modernize: 'refactor',
267
- modernization: 'refactor',
268
- legacy: 'refactor',
269
- 'legacy-code': 'refactor',
270
- 'debt-pay': 'refactor',
271
- 'pay-debt': 'refactor',
272
- 'debt-reduction': 'refactor',
273
- 'smell-fix': 'refactor',
274
- 'fix-smells': 'refactor',
275
- 'code-smells': 'refactor',
276
- strangler: 'refactor',
277
- 'strangler-fig': 'refactor',
278
- limpar: 'cleanup',
279
- limpeza: 'cleanup',
280
- auditar: 'audit',
281
- auditoria: 'audit',
282
- debt: 'tech-debt',
283
- debts: 'tech-debt',
284
- 'debt-list': 'tech-debt',
285
- 'tech-debts': 'tech-debt',
286
- td: 'tech-debt',
287
- help: 'menu',
288
- ajuda: 'menu',
289
- '?': 'menu',
290
- commands: 'menu',
291
- cmds: 'menu',
292
- planos: 'plans',
293
- pricing: 'plans',
294
- bill: 'billing',
295
- subscription: 'billing',
296
- sub: 'billing',
297
- upgrade: 'subscribe',
298
- checkout: 'subscribe',
299
- qa: 'qa-scan',
300
- 'qa-test': 'qa-scan',
301
- 'visual-qa': 'qa-scan',
302
- 'e2e-scan': 'qa-scan',
303
- troubleshoot: 'qa-scan',
304
- 'debug-ui': 'qa-scan',
305
- scan: 'qa-scan',
306
- a11y: 'qa-scan',
307
- accessibility: 'qa-scan',
308
- wcag: 'qa-scan',
309
- 'auto-yolo': 'yoloop',
310
- 'epic-runner': 'yoloop',
311
- 'story-runner': 'yoloop',
312
- 'loop-yolo': 'yoloop',
313
- 'auto-epic': 'yoloop',
314
- migrate: 'migrate-state',
315
- 'state-migrate': 'migrate-state',
316
- 'schema-migrate': 'migrate-state',
317
- policy: 'policy-audit',
318
- 'audit-policy': 'policy-audit',
319
- 'policy-history': 'policy-audit',
320
- policies: 'policy-audit',
321
- mutation: 'mutation-test',
322
- stryker: 'mutation-test',
323
- 'kill-mutants': 'mutation-test',
324
- 'openapi-sync': 'sync-openapi',
325
- 'api-sync': 'sync-openapi',
326
- 'spec-sync': 'sync-openapi',
327
- 'regen-openapi': 'sync-openapi',
328
- pacts: 'generate-pacts',
329
- 'gen-pacts': 'generate-pacts',
330
- 'regen-pacts': 'generate-pacts',
331
- 'create-pacts': 'generate-pacts',
332
- 'verify-pact': 'verify-pacts',
333
- 'pact-verify': 'verify-pacts',
334
- 'check-pacts': 'verify-pacts',
335
- 'pact-check': 'verify-pacts',
336
- property: 'property-test',
337
- pbt: 'property-test',
338
- proptest: 'property-test',
339
- 'invariant-test': 'property-test',
340
- chaos: 'chaos-plan',
341
- gameday: 'chaos-plan',
342
- 'resilience-test': 'chaos-plan',
343
- 'ux-review': 'ui-ux-review',
344
- 'design-review': 'ui-ux-review',
345
- 'visual-review': 'ui-ux-review',
346
- 'product-polish': 'ui-ux-review',
347
- 'security-system': 'solyd-system',
348
- 'authorized-security': 'solyd-system',
349
- 'sec-system': 'solyd-system',
350
- goals: 'goal',
351
- 'durable-goal': 'goal',
352
- 'continuity-goal': 'goal',
353
- loops: 'loop',
354
- 'durable-loop': 'loop',
355
- 'continuity-loop': 'loop',
356
- job: 'jobs',
357
- 'continuity-jobs': 'jobs',
358
- 'neocortex-runner': 'runner',
359
- 'continuity-runner': 'runner',
360
- });
361
- const COMMAND_NUMBER_TO_ID = Object.freeze({
362
- '1': 'status',
363
- '3': 'arch-plan',
364
- '4': 'arch-prd',
365
- '5': 'arch-architecture',
366
- '6': 'arch-api-contracts',
367
- '7': 'arch-api-integrations',
368
- '8': 'arch-database',
369
- '9': 'arch-security',
370
- '10': 'arch-design-system',
371
- '11': 'arch-ux-design',
372
- '12': 'arch-performance',
373
- '13': 'arch-testing',
374
- '14': 'arch-infrastructure',
375
- '15': 'arch-review',
376
- '16': 'arch-fitness-functions',
377
- '17': 'create-epic',
378
- '18': 'idea-diagnose',
379
- '19': 'idea-research',
380
- '20': 'generate-epic',
381
- '21': 'exec',
382
- '22': 'yolo',
383
- '23': 'epic',
384
- '24': 'setup-branch',
385
- '25': 'diagnose',
386
- '26': 'research',
387
- '27': 'write-spec',
388
- '28': 'create-tasks',
389
- '29': 'implement',
390
- '30': 'commit',
391
- '31': 'sync',
392
- '32': 'create-pr',
393
- '33': 'review',
394
- '34': 'merge',
395
- '35': 'fix-blocked',
396
- '36': 'finalize-epic',
397
- '37': 'resolve-conflicts',
398
- '38': 'update-memory',
399
- '39': 'refactor',
400
- '40': 'cleanup',
401
- '41': 'audit',
402
- '42': 'tech-debt',
403
- '43': 'menu',
404
- '44': 'plans',
405
- '45': 'billing',
406
- '46': 'subscribe',
407
- '47': 'qa-scan',
408
- '48': 'yoloop',
409
- '49': 'migrate-state',
410
- '50': 'policy-audit',
411
- '51': 'mutation-test',
412
- '52': 'sync-openapi',
413
- '53': 'generate-pacts',
414
- '54': 'verify-pacts',
415
- '55': 'property-test',
416
- '56': 'chaos-plan',
417
- '57': 'ui-ux-review',
418
- '58': 'solyd-system',
419
- '59': 'goal',
420
- '60': 'loop',
421
- '61': 'jobs',
422
- '62': 'runner',
423
- });
424
- function safeToken(value, maxLength = 120) {
425
- if (typeof value !== 'string')
426
- return undefined;
427
- const trimmed = value.trim();
428
- if (!trimmed)
429
- return undefined;
430
- return trimmed.replace(/[^a-z0-9_.:-]+/gi, '_').slice(0, maxLength);
431
- }
432
- function safeCanonicalToken(value, maxLength = 120) {
433
- if (typeof value !== 'string')
434
- return undefined;
435
- const trimmed = value.trim();
436
- const safe = safeToken(value, maxLength);
437
- return safe === trimmed ? safe : undefined;
438
- }
439
- function safeGitRef(value) {
440
- if (typeof value !== 'string')
441
- return undefined;
442
- const trimmed = value.trim();
443
- if (!trimmed || trimmed.length > 240 || !/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(trimmed)
444
- || trimmed.includes('..') || trimmed.includes('//') || trimmed.includes('@{')
445
- || trimmed.endsWith('/') || trimmed.endsWith('.')
446
- || trimmed.split('/').some((part) => !part || part.startsWith('.') || part.endsWith('.lock')))
447
- return undefined;
448
- return trimmed;
449
- }
450
- function safeWriteRef(value) {
451
- if (typeof value !== 'string')
452
- return undefined;
453
- const normalized = value.replace(/\\/g, '/');
454
- if (!normalized || normalized.length > 240 || normalized.startsWith('/')
455
- || /^[A-Za-z]:/.test(normalized) || normalized.includes('..') || normalized.includes('//')
456
- || normalized.split('/').includes('.') || !/^[A-Za-z0-9._/:@#-]+$/.test(normalized))
457
- return undefined;
458
- return normalized;
459
- }
460
- function safeWriteRefs(value) {
461
- if (value === undefined)
462
- return undefined;
463
- if (!Array.isArray(value) || value.length > 128)
464
- return undefined;
465
- const refs = value.map(safeWriteRef);
466
- if (refs.some((ref) => ref === undefined))
467
- return undefined;
468
- return [...new Set(refs)].sort((left, right) => left.localeCompare(right, 'en'));
469
- }
470
- function isActiveYoloopStory(status) {
471
- return typeof status === 'string'
472
- && YOLOOP_ACTIVE_STORY_STATUS_SET.has(status.trim().toLowerCase().replace(/_/g, '-'));
473
- }
474
- function pickPublicScalarFields(value, allowlist) {
475
- const result = {};
476
- for (const key of allowlist) {
477
- const field = value[key];
478
- if (typeof field === 'string' || typeof field === 'boolean'
479
- || typeof field === 'number' && Number.isFinite(field))
480
- result[key] = field;
481
- else if (Array.isArray(field) && field.every((item) => typeof item === 'string'))
482
- result[key] = [...field];
483
- }
484
- return result;
485
- }
486
- function publicResumeCheckpoint(storyId, story) {
487
- const value = story.checkpoint;
488
- if (!isRecord(value) || value.schemaVersion !== 1 || value.storyId !== storyId
489
- || value.epicId !== story.epic_id || !safeGitRef(value.branch)
490
- || typeof value.baseSha !== 'string' || !/^[0-9a-f]{7,64}$/i.test(value.baseSha)
491
- || typeof value.headSha !== 'string' || !/^[0-9a-f]{7,64}$/i.test(value.headSha)
492
- || value.baseSha === value.headSha || !safeCanonicalToken(value.idempotencyKey)
493
- || typeof value.recordedAt !== 'string' || !Number.isFinite(Date.parse(value.recordedAt))
494
- || !Array.isArray(value.commits) || value.commits.length === 0 || value.commits.length > 256
495
- || value.commits.some((sha) => typeof sha !== 'string' || !/^[0-9a-f]{7,64}$/i.test(sha))
496
- || !Array.isArray(value.receiptRefs) || value.receiptRefs.length === 0 || value.receiptRefs.length > 256
497
- || value.receiptRefs.some((ref) => typeof ref !== 'string' || ref.length > 240 || ref.includes('..')
498
- || !/^[A-Za-z0-9._:/#\-[\]]+$/.test(ref))
499
- || !isRecord(value.qaReceipt) || value.qaReceipt.kind !== 'story_qa_evidence'
500
- || value.qaReceipt.producer !== 'local-yolo-tdd'
501
- || !['passed', 'blocked'].includes(String(value.qaVerdict))
502
- || !['approved', 'changes-requested', 'pending'].includes(String(value.reviewVerdict)))
503
- return undefined;
504
- if (value.reviewVerdict === 'pending' ? value.reviewReceipt !== undefined : !isRecord(value.reviewReceipt))
505
- return undefined;
506
- // collectStateSnapshot already validated field values. Re-project the exact
507
- // public allowlist so later hooks or synthetic callers cannot append content.
508
- const result = pickPublicScalarFields(value, [
509
- 'schemaVersion', 'storyId', 'epicId', 'branch', 'baseSha', 'headSha',
510
- 'idempotencyKey', 'dispatchId', 'bundleId', 'bundleDigest', 'graphRevision',
511
- 'claimRevision', 'qaVerdict', 'reviewVerdict', 'recordedAt', 'commits',
512
- 'receiptRefs',
513
- ]);
514
- result.qaReceipt = pickPublicScalarFields(value.qaReceipt, [
515
- 'schemaVersion', 'kind', 'producer', 'evidenceVersion', 'storyId', 'epicId',
516
- 'contract', 'command', 'manifestDigest', 'gateIds', 'resultDigest', 'baseSha',
517
- 'headSha', 'bundleDigest', 'graphRevision', 'sourceEvidenceDigest', 'verdict',
518
- 'checkedAt', 'receiptRef',
519
- ]);
520
- if (isRecord(value.reviewReceipt)) {
521
- result.reviewReceipt = pickPublicScalarFields(value.reviewReceipt, [
522
- 'schemaVersion', 'kind', 'producer', 'storyId', 'epicId', 'baseSha',
523
- 'headSha', 'bundleDigest', 'graphRevision', 'sourceEvidenceDigest',
524
- 'qaReceiptRef', 'verdict', 'reviewedAt', 'receiptRef',
525
- ]);
526
- }
527
- return result;
528
- }
529
- function publicCheckpointVerification(storyId, story) {
530
- const value = story.checkpoint_verification;
531
- if (!isRecord(value) || value.schemaVersion !== 1
532
- || value.kind !== 'story_checkpoint_physical_verification'
533
- || value.producer !== 'client-p205-transient-v1' || value.publicSafe !== true
534
- || value.storyId !== storyId || value.epicId !== story.epic_id
535
- || !['verified', 'rejected'].includes(String(value.verdict)))
536
- return undefined;
537
- return pickPublicScalarFields(value, [
538
- 'schemaVersion', 'kind', 'producer', 'storyId', 'epicId', 'branch',
539
- 'baseSha', 'headSha', 'aggregateHeadSha', 'commitBodyDigest',
540
- 'changedPathsDigest', 'claimVerification', 'effectiveClaimRevision',
541
- 'command', 'manifestDigest', 'gateIds', 'resultDigest', 'graphRevision',
542
- 'executionEvidenceDigest', 'sourceEvidenceDigest', 'verifiedAt', 'verdict',
543
- 'reasonCodes', 'publicSafe',
544
- ]);
545
- }
546
- function publicSchedulingCheckpointEvidence(storyId, story) {
547
- const value = story.scheduling_checkpoint_evidence;
548
- const allowed = new Set([
549
- 'schemaVersion', 'kind', 'producer', 'storyId', 'epicId', 'branch', 'baseSha', 'headSha',
550
- 'graphRevision', 'effectiveClaimRevision', 'sourceEvidenceDigest', 'verifiedAt', 'reasonCodes',
551
- 'integrationAuthorized', 'publicSafe',
552
- ]);
553
- if (!isRecord(value) || Object.keys(value).some((key) => !allowed.has(key))
554
- || value.schemaVersion !== 1 || value.kind !== 'story_scheduling_checkpoint_evidence'
555
- || value.producer !== 'client-git-physical-v1' || value.publicSafe !== true
556
- || value.integrationAuthorized !== false || value.storyId !== storyId || value.epicId !== story.epic_id
557
- || !safeGitRef(value.branch) || typeof value.baseSha !== 'string' || !/^[0-9a-f]{40,64}$/i.test(value.baseSha)
558
- || typeof value.headSha !== 'string' || !/^[0-9a-f]{40,64}$/i.test(value.headSha)
559
- || typeof value.graphRevision !== 'string' || !/^[0-9a-f]{64}$/i.test(value.graphRevision)
560
- || typeof value.effectiveClaimRevision !== 'string' || !/^[0-9a-f]{64}$/i.test(value.effectiveClaimRevision)
561
- || typeof value.sourceEvidenceDigest !== 'string' || !/^[0-9a-f]{64}$/i.test(value.sourceEvidenceDigest)
562
- || typeof value.verifiedAt !== 'string' || !Number.isFinite(Date.parse(value.verifiedAt))
563
- || !Array.isArray(value.reasonCodes) || value.reasonCodes.length !== 1
564
- || value.reasonCodes[0] !== 'checkpoint-git-scheduling-verified')
565
- return undefined;
566
- return pickPublicScalarFields(value, [...allowed]);
567
- }
568
- function projectSchedulingLane(storyId, story) {
569
- const projected = { ...story };
570
- const evidence = publicSchedulingCheckpointEvidence(storyId, story);
571
- if (evidence) {
572
- projected.scheduling_checkpoint_evidence = evidence;
573
- delete projected.checkpoint;
574
- delete projected.checkpoint_verification;
575
- }
576
- else {
577
- delete projected.scheduling_checkpoint_evidence;
578
- }
579
- return projected;
580
- }
581
- function isRecord(value) {
582
- return value !== null && typeof value === 'object' && !Array.isArray(value);
583
- }
584
- function safeReasonCodes(...groups) {
585
- const seen = new Set();
586
- const reasonCodes = [];
587
- for (const group of groups) {
588
- for (const reasonCode of group ?? []) {
589
- const safe = safeToken(reasonCode, 80);
590
- if (!safe || seen.has(safe))
591
- continue;
592
- seen.add(safe);
593
- reasonCodes.push(safe);
594
- if (reasonCodes.length >= REASON_CODE_LIMIT)
595
- return reasonCodes;
596
- }
597
- }
598
- return reasonCodes;
599
- }
600
- function normalizeCommandToken(input) {
601
- return input.trim().replace(/^@?\*/, '').replace(/^@/, '').toLowerCase();
602
- }
603
- function leadingCommandToken(input) {
604
- return input.trim().split(/\s+/, 1)[0] ?? '';
605
- }
606
- function resolveCommandProjectionPolicy(args) {
607
- // The exact published @epic-P{N} spelling is a one-token command and its
608
- // own target. It must receive the same structural projection as *epic.
609
- if (/^@epic-P[0-9]{1,12}$/.test(args.trim()))
610
- return COMMAND_POLICY_BY_ID.epic;
611
- const token = leadingCommandToken(args);
612
- if (!token)
613
- return COMMAND_POLICY_BY_ID.menu;
614
- const normalized = normalizeCommandToken(token);
615
- const commandId = COMMAND_NUMBER_TO_ID[normalized]
616
- ?? COMMAND_ALIAS_TO_ID[normalized]
617
- ?? normalized;
618
- return COMMAND_POLICY_BY_ID[commandId] ?? null;
619
- }
620
- function createFullScope(trigger, snapshot, commandPolicy, projectionMode = 'full-compatible', reasonCodes = ['full-state']) {
621
- return {
622
- kind: 'full',
623
- commandId: commandPolicy?.commandId ?? null,
624
- stateProjectionPolicy: commandPolicy?.stateProjectionPolicy ?? null,
625
- projectionMode,
626
- trigger,
627
- targetEpicId: null,
628
- targetStoryId: null,
629
- includedStoryCount: Object.keys(snapshot.stories).length,
630
- includedEpicCount: Object.keys(snapshot.epics).length,
631
- omittedStoryCount: 0,
632
- omittedEpicCount: 0,
633
- reason: 'full-state',
634
- reasonCodes: safeReasonCodes(reasonCodes),
635
- };
636
- }
637
- function fullSnapshot(trigger, snapshot, commandPolicy, projectionMode = 'full-compatible', reasonCodes = ['full-state']) {
638
- const scope = createFullScope(trigger, snapshot, commandPolicy, projectionMode, reasonCodes);
639
- return withStateSummary({
640
- ...snapshot,
641
- scope,
642
- }, snapshot, scope);
643
- }
644
- function firstTokenIsStoryReference(args) {
645
- const [firstToken] = args.trim().split(/\s+/, 1);
646
- if (!firstToken)
647
- return false;
648
- return (/^[A-Z]?\d+(?:\.\d+)+$/i.test(firstToken.replace(/^@/, '')) ||
649
- /(?:^|\/)[A-Z]?\d+(?:\.\d+)+\.story\.md$/i.test(firstToken.replace(/^@/, '')));
650
- }
651
- function extractStoryId(args) {
652
- const storyFileMatch = args.match(/(?:^|[/@\s])([A-Z]?\d+(?:\.\d+)+)\.story\.md\b/i);
653
- if (storyFileMatch?.[1])
654
- return storyFileMatch[1];
655
- const storyIdMatch = args.match(/(?:^|\s|@)([A-Z]?\d+(?:\.\d+)+)(?=$|\s)/i);
656
- return storyIdMatch?.[1] ?? null;
657
- }
658
- function triggerRemainder(args) {
659
- const trimmed = args.trim();
660
- const firstWhitespace = trimmed.search(/\s/);
661
- return firstWhitespace === -1 ? '' : trimmed.slice(firstWhitespace).trim();
662
- }
663
- function positionalTokens(args) {
664
- return triggerRemainder(args)
665
- .split(/\s+/)
666
- .map((token) => token.replace(/^@/, '').replace(/^['"]|['"]$/g, ''))
667
- .filter((token) => token.length > 0 && !token.startsWith('-'));
668
- }
669
- function firstPositionalArg(args) {
670
- return positionalTokens(args)[0] ?? null;
671
- }
672
- function resolveEpicId(candidate, snapshot) {
673
- const normalized = candidate.replace(/^@/, '').replace(/^epic-/i, '');
674
- const withoutExtension = normalized.replace(/\.md$/i, '');
675
- const candidates = [
676
- withoutExtension,
677
- withoutExtension.toUpperCase(),
678
- /^p\d+$/i.test(withoutExtension)
679
- ? `P${withoutExtension.replace(/^p/i, '')}`
680
- : null,
681
- /^\d+$/.test(withoutExtension) ? `P${withoutExtension}` : null,
682
- ].filter((entry) => typeof entry === 'string' && entry.length > 0);
683
- for (const entry of candidates) {
684
- if (snapshot.epics[entry])
685
- return entry;
686
- }
687
- return null;
688
- }
689
- function extractEpicIdFromCanonicalFile(args, snapshot) {
690
- const match = args.match(/(?:^|[/@\s])epic-(P?\d+)\.md\b/i);
691
- if (!match?.[1])
692
- return null;
693
- return resolveEpicId(match[1], snapshot);
694
- }
695
- function extractTargetEpicId(args, snapshot) {
696
- const directEpic = args.trim().match(/^@epic-(P[0-9]{1,12})$/);
697
- if (directEpic)
698
- return resolveEpicId(directEpic[1], snapshot);
699
- const fromFile = extractEpicIdFromCanonicalFile(args, snapshot);
700
- if (fromFile)
701
- return fromFile;
702
- for (const token of positionalTokens(args)) {
703
- if (/^[A-Z]?\d+(?:\.\d+)+$/i.test(token))
704
- continue;
705
- const fromToken = resolveEpicId(token, snapshot);
706
- if (fromToken)
707
- return fromToken;
708
- }
709
- return null;
710
- }
711
- function extractYoloopTargetEpicId(args, snapshot) {
712
- const fromTarget = extractTargetEpicId(args, snapshot);
713
- if (fromTarget)
714
- return fromTarget;
715
- const yoloop = snapshot.yoloop;
716
- const sessionEpicId = yoloop?.state?.currentSession?.currentEpicId;
717
- if (typeof sessionEpicId === 'string' && snapshot.epics[sessionEpicId]) {
718
- return sessionEpicId;
719
- }
720
- const lockEpicId = yoloop?.lock?.currentEpicId ?? yoloop?.lock?.epicId;
721
- if (typeof lockEpicId === 'string' && snapshot.epics[lockEpicId]) {
722
- return lockEpicId;
723
- }
724
- return null;
725
- }
726
- function explicitYoloopEpicCandidate(args) {
727
- const fromFile = args.match(/(?:^|[/@\s])epic-(P?\d+)\.md\b/i)?.[1];
728
- if (fromFile)
729
- return /^P/i.test(fromFile) ? fromFile.toUpperCase() : `P${fromFile}`;
730
- for (const token of positionalTokens(args)) {
731
- if (/^P\d+$/i.test(token))
732
- return token.toUpperCase();
733
- if (/^\d+$/.test(token))
734
- return `P${token}`;
735
- }
736
- return null;
737
- }
738
- function storyEpicId(story, storyId) {
739
- if (typeof story.epic_id === 'string' && story.epic_id.length > 0) {
740
- return story.epic_id;
741
- }
742
- const derived = storyId.split('.').slice(0, -1).join('.');
743
- return derived.length > 0 ? derived : null;
744
- }
745
- function isTerminalStoryStatus(status) {
746
- return typeof status === 'string' && ['done', 'completed', 'merged', 'cancelled', 'canceled', 'abandoned'].includes(status.toLowerCase());
747
- }
748
- function addStoryAndDependencies(storyId, snapshot, includedStoryIds) {
749
- if (includedStoryIds.has(storyId))
750
- return;
751
- const story = snapshot.stories[storyId];
752
- if (!story)
753
- return;
754
- includedStoryIds.add(storyId);
755
- const dependsOn = story.depends_on;
756
- if (!Array.isArray(dependsOn))
757
- return;
758
- for (const dependencyId of dependsOn) {
759
- if (typeof dependencyId === 'string') {
760
- addStoryAndDependencies(dependencyId, snapshot, includedStoryIds);
761
- }
762
- }
763
- }
764
- function buildProjectedStories(targetStoryId, snapshot) {
765
- const analysis = analyzeDependencyDag(snapshot.stories, [targetStoryId]);
766
- const projectedStories = {};
767
- for (const storyId of analysis.orderedIds) {
768
- const story = snapshot.stories[storyId];
769
- if (story) {
770
- projectedStories[storyId] = story;
771
- }
772
- }
773
- return projectedStories;
774
- }
775
- function buildProjectedEpics(projectedStories, snapshot, requiredEpicIds = []) {
776
- const projectedEpics = {};
777
- for (const epicId of requiredEpicIds) {
778
- if (snapshot.epics[epicId]) {
779
- projectedEpics[epicId] = snapshot.epics[epicId];
780
- }
781
- }
782
- for (const [storyId, story] of Object.entries(projectedStories)) {
783
- const epicId = storyEpicId(story, storyId);
784
- if (epicId && snapshot.epics[epicId]) {
785
- projectedEpics[epicId] = snapshot.epics[epicId];
786
- }
787
- }
788
- return projectedEpics;
789
- }
790
- function addEpicAndDependencies(epicId, snapshot, includedEpicIds) {
791
- if (includedEpicIds.has(epicId))
792
- return;
793
- const epic = snapshot.epics[epicId];
794
- if (!epic)
795
- return;
796
- includedEpicIds.add(epicId);
797
- const dependsOn = epic.depends_on;
798
- if (!Array.isArray(dependsOn))
799
- return;
800
- for (const dependencyId of dependsOn) {
801
- if (typeof dependencyId === 'string' && dependencyId.length > 0) {
802
- addEpicAndDependencies(dependencyId, snapshot, includedEpicIds);
803
- }
804
- }
805
- }
806
- function buildProjectedYoloopEpics(targetEpicId, projectedStories, snapshot) {
807
- const epicAnalysis = analyzeDependencyDag(snapshot.epics, [targetEpicId]);
808
- const requiredEpicIds = new Set(epicAnalysis.orderedIds);
809
- for (const [storyId, story] of Object.entries(projectedStories)) {
810
- const parentEpicId = storyEpicId(story, storyId);
811
- if (parentEpicId && snapshot.epics[parentEpicId])
812
- requiredEpicIds.add(parentEpicId);
813
- }
814
- const projectedEpics = {};
815
- for (const epicId of [...requiredEpicIds].sort((left, right) => left.localeCompare(right, 'en'))) {
816
- const epic = snapshot.epics[epicId];
817
- if (!epic)
818
- continue;
819
- projectedEpics[epicId] = epicId === targetEpicId ? epic : compactStructuralEpic(epicId, epic);
820
- }
821
- return projectedEpics;
822
- }
823
- function buildProjectedYoloopStories(targetEpicId, targetEpic, snapshot) {
824
- const storyIds = targetEpic.stories;
825
- if (!Array.isArray(storyIds)
826
- || storyIds.some((storyId) => typeof storyId !== 'string' || storyId.length === 0)) {
827
- throw new StructuralDagError('STRUCTURAL_DEPENDENCY_MISSING', {
828
- nodes: 0,
829
- edges: 0,
830
- malformedStoryMemberships: 1,
831
- });
832
- }
833
- const analysis = analyzeDependencyDag(snapshot.stories, storyIds);
834
- const projectedStories = {};
835
- for (const storyId of analysis.orderedIds) {
836
- const story = snapshot.stories[storyId];
837
- if (story) {
838
- projectedStories[storyId] = storyEpicId(story, storyId) === targetEpicId
839
- ? projectSchedulingLane(storyId, story)
840
- : compactStructuralStory(storyId, story);
841
- }
842
- }
843
- return projectedStories;
844
- }
845
- function buildTargetEpicCoverage(targetEpicId, targetEpic, projectedStories) {
846
- const declaredStoryIds = [...targetEpic.stories]
847
- .sort((left, right) => left.localeCompare(right, 'en'));
848
- const includedStoryIds = Object.entries(projectedStories)
849
- .filter(([storyId, story]) => storyEpicId(story, storyId) === targetEpicId)
850
- .map(([storyId]) => storyId)
851
- .sort((left, right) => left.localeCompare(right, 'en'));
852
- const membershipSha256 = createHash('sha256')
853
- .update(`target-epic-coverage-v1\0${JSON.stringify({ targetEpicId, declaredStoryIds, includedStoryIds })}`)
854
- .digest('hex');
855
- return {
856
- schemaVersion: 'TargetEpicCoverage/1.0',
857
- targetEpicId,
858
- declaredStoryIds,
859
- includedStoryIds,
860
- membershipSha256,
861
- publicSafe: true,
862
- };
863
- }
864
- function compactStructuralStory(storyId, story) {
865
- const dependsOn = Array.isArray(story.depends_on)
866
- ? [...new Set(story.depends_on.filter((value) => typeof value === 'string' && value.length > 0))]
867
- .sort((left, right) => left.localeCompare(right, 'en'))
868
- : [];
869
- const compact = {
870
- id: safeToken(story.id) ?? storyId,
871
- ...(safeToken(story.epic_id) ? { epic_id: safeToken(story.epic_id) } : {}),
872
- ...(safeToken(story.status, 40) ? { status: safeToken(story.status, 40) } : {}),
873
- depends_on: dependsOn,
874
- };
875
- const schedulingEvidence = publicSchedulingCheckpointEvidence(storyId, story);
876
- if (!isActiveYoloopStory(story.status)) {
877
- return { ...compact, ...(schedulingEvidence ? { scheduling_checkpoint_evidence: schedulingEvidence } : {}) };
878
- }
879
- const source = story.source === 'create-epic' || story.source === 'discovered'
880
- ? story.source : undefined;
881
- const branchName = safeGitRef(story.branch_name);
882
- const lastStep = safeCanonicalToken(story.last_step, 120);
883
- const steps = Array.isArray(story.steps_completed) && story.steps_completed.length <= 64
884
- ? story.steps_completed.map((step) => safeCanonicalToken(step, 120))
885
- : [];
886
- const validSteps = steps.length > 0 && steps.every((step) => step !== undefined)
887
- ? steps : undefined;
888
- const prNumber = typeof story.pr_number === 'number' && Number.isSafeInteger(story.pr_number)
889
- && story.pr_number > 0 ? story.pr_number : undefined;
890
- const checkpoint = publicResumeCheckpoint(storyId, story);
891
- const checkpointVerification = checkpoint ? publicCheckpointVerification(storyId, story) : undefined;
892
- return {
893
- ...compact,
894
- ...(source ? { source } : {}),
895
- ...(branchName ? { branch_name: branchName } : {}),
896
- ...(lastStep ? { last_step: lastStep } : {}),
897
- ...(validSteps ? { steps_completed: validSteps } : {}),
898
- ...(prNumber ? { pr_number: prNumber } : {}),
899
- ...(checkpoint ? { checkpoint } : {}),
900
- ...(checkpointVerification ? { checkpoint_verification: checkpointVerification } : {}),
901
- ...(schedulingEvidence ? { scheduling_checkpoint_evidence: schedulingEvidence } : {}),
902
- ...(safeWriteRefs(story.files_to_modify) !== undefined
903
- ? { files_to_modify: safeWriteRefs(story.files_to_modify) } : {}),
904
- ...(safeWriteRefs(story.contracts) !== undefined
905
- ? { contracts: safeWriteRefs(story.contracts) } : {}),
906
- ...(safeWriteRefs(story.contract_refs) !== undefined
907
- ? { contract_refs: safeWriteRefs(story.contract_refs) } : {}),
908
- ...(safeWriteRefs(story.shared_surfaces) !== undefined
909
- ? { shared_surfaces: safeWriteRefs(story.shared_surfaces) } : {}),
910
- };
911
- }
912
- function compactStructuralEpic(epicId, epic) {
913
- const stories = Array.isArray(epic.stories)
914
- ? [...new Set(epic.stories.filter((value) => typeof value === 'string' && value.length > 0))]
915
- .sort((left, right) => left.localeCompare(right, 'en'))
916
- : [];
917
- const dependsOn = Array.isArray(epic.depends_on)
918
- ? [...new Set(epic.depends_on.filter((value) => typeof value === 'string' && value.length > 0))]
919
- .sort((left, right) => left.localeCompare(right, 'en'))
920
- : [];
921
- return {
922
- id: safeToken(epic.id) ?? epicId,
923
- ...(safeToken(epic.status, 40) ? { status: safeToken(epic.status, 40) } : {}),
924
- ...(safeToken(epic.lifecycle_classification, 40)
925
- ? { lifecycle_classification: safeToken(epic.lifecycle_classification, 40) }
926
- : {}),
927
- stories,
928
- depends_on: dependsOn,
929
- };
930
- }
931
- function buildYoloopDiscoveryProjection(trigger, snapshot, commandPolicy) {
932
- const storyAnalysis = analyzeDependencyDag(snapshot.stories);
933
- const epicAnalysis = analyzeDependencyDag(snapshot.epics);
934
- const projectedStories = Object.fromEntries(storyAnalysis.orderedIds.map((storyId) => [
935
- storyId,
936
- compactStructuralStory(storyId, snapshot.stories[storyId]),
937
- ]));
938
- const projectedEpics = Object.fromEntries(epicAnalysis.orderedIds.map((epicId) => [
939
- epicId,
940
- compactStructuralEpic(epicId, snapshot.epics[epicId]),
941
- ]));
942
- const scope = {
943
- kind: 'projected',
944
- commandId: commandPolicy.commandId,
945
- stateProjectionPolicy: commandPolicy.stateProjectionPolicy,
946
- projectionMode: 'yoloop-discovery',
947
- trigger,
948
- targetEpicId: null,
949
- targetStoryId: null,
950
- includedStoryCount: storyAnalysis.orderedIds.length,
951
- includedEpicCount: epicAnalysis.orderedIds.length,
952
- omittedStoryCount: 0,
953
- omittedEpicCount: 0,
954
- reason: 'targeted-invocation',
955
- reasonCodes: safeReasonCodes([
956
- 'structural-required',
957
- 'yoloop-discovery',
958
- `structural-edges-${storyAnalysis.edgeCount + epicAnalysis.edgeCount}`,
959
- 'content-fields-omitted',
960
- ]),
961
- };
962
- return withStateSummary({
963
- ...snapshot,
964
- stories: projectedStories,
965
- epics: projectedEpics,
966
- scope,
967
- }, snapshot, scope);
968
- }
969
- function buildProjectedTargetEpicStories(targetEpic, snapshot) {
970
- const includedStoryIds = new Set();
971
- const storyIds = targetEpic.stories;
972
- if (Array.isArray(storyIds)) {
973
- for (const storyId of storyIds) {
974
- if (typeof storyId === 'string') {
975
- addStoryAndDependencies(storyId, snapshot, includedStoryIds);
976
- }
977
- }
978
- }
979
- const projectedStories = {};
980
- for (const storyId of includedStoryIds) {
981
- const story = snapshot.stories[storyId];
982
- if (story) {
983
- projectedStories[storyId] = story;
984
- }
985
- }
986
- return projectedStories;
987
- }
988
- function buildEpicStubs(snapshot) {
989
- const projectedEpics = {};
990
- for (const [epicId, epic] of Object.entries(snapshot.epics)) {
991
- projectedEpics[epicId] = {
992
- id: safeToken(epic.id) ?? epicId,
993
- ...(safeToken(epic.status) ? { status: safeToken(epic.status) } : {}),
994
- ...(EPIC_LIFECYCLE_CLASSIFICATIONS.includes(epic.lifecycle_classification)
995
- ? { lifecycle_classification: epic.lifecycle_classification }
996
- : {}),
997
- ...(typeof epic.total_stories === 'number' && Number.isFinite(epic.total_stories)
998
- ? { total_stories: epic.total_stories }
999
- : {}),
1000
- ...(typeof epic.completed_stories === 'number' && Number.isFinite(epic.completed_stories)
1001
- ? { completed_stories: epic.completed_stories }
1002
- : {}),
1003
- };
1004
- }
1005
- return projectedEpics;
1006
- }
1007
- function countStatuses(records) {
1008
- const counts = {};
1009
- for (const record of Object.values(records)) {
1010
- const status = safeToken(record.status, 40) ?? 'unknown';
1011
- counts[status] = (counts[status] ?? 0) + 1;
1012
- }
1013
- return counts;
1014
- }
1015
- function countEpicLifecycles(records) {
1016
- const counts = Object.fromEntries(EPIC_LIFECYCLE_CLASSIFICATIONS.map((classification) => [classification, 0]));
1017
- for (const record of Object.values(records)) {
1018
- const classification = EPIC_LIFECYCLE_CLASSIFICATIONS.includes(record.lifecycle_classification)
1019
- ? record.lifecycle_classification
1020
- : 'active';
1021
- counts[classification] = (counts[classification] ?? 0) + 1;
1022
- }
1023
- return counts;
1024
- }
1025
- function isActiveEpicLifecycle(snapshot, epicId) {
1026
- if (!epicId)
1027
- return true;
1028
- const epic = snapshot.epics[epicId];
1029
- if (!epic)
1030
- return true;
1031
- return !EPIC_LIFECYCLE_CLASSIFICATIONS.includes(epic.lifecycle_classification) || epic.lifecycle_classification === 'active';
1032
- }
1033
- function sortableStoryTimestamp(story) {
1034
- for (const key of ['last_updated', 'updated_at', 'completed_at', 'created_at', 'discovered_at']) {
1035
- const value = story[key];
1036
- if (typeof value !== 'string')
1037
- continue;
1038
- const parsed = Date.parse(value);
1039
- if (Number.isFinite(parsed))
1040
- return parsed;
1041
- }
1042
- return 0;
1043
- }
1044
- function recentStories(snapshot) {
1045
- return Object.entries(snapshot.stories)
1046
- .map(([id, story]) => ({ id, story, timestamp: sortableStoryTimestamp(story) }))
1047
- .sort((left, right) => right.timestamp - left.timestamp || left.id.localeCompare(right.id))
1048
- .slice(0, RECENT_STORY_LIMIT)
1049
- .map(({ id, story }) => ({
1050
- id,
1051
- ...(safeToken(story.epic_id) ? { epicId: safeToken(story.epic_id) } : {}),
1052
- ...(safeToken(story.status, 40) ? { status: safeToken(story.status, 40) } : {}),
1053
- ...(safeToken(story.last_step ?? story.lastStep) ? { lastStep: safeToken(story.last_step ?? story.lastStep) } : {}),
1054
- ...(safeToken(story.last_updated ?? story.updated_at ?? story.completed_at ?? story.created_at)
1055
- ? { lastUpdated: safeToken(story.last_updated ?? story.updated_at ?? story.completed_at ?? story.created_at) }
1056
- : {}),
1057
- }));
1058
- }
1059
- function currentSessionRef(snapshot) {
1060
- const session = snapshot.current_session;
1061
- if (!session)
1062
- return undefined;
1063
- const ref = {
1064
- activeEpicId: safeToken(session.active_epic_id) ?? null,
1065
- activeStoryId: safeToken(session.active_story_id) ?? null,
1066
- activeStepId: safeToken(session.active_step_id) ?? null,
1067
- sessionId: safeToken(session.session_id) ?? null,
1068
- startedAt: safeToken(session.started_at) ?? null,
1069
- };
1070
- return Object.values(ref).some((value) => value !== null && value !== undefined) ? ref : undefined;
1071
- }
1072
- function yoloopSessionRef(snapshot) {
1073
- const yoloop = snapshot.yoloop;
1074
- if (!isRecord(yoloop))
1075
- return undefined;
1076
- const state = isRecord(yoloop.state) ? yoloop.state : undefined;
1077
- const currentSession = isRecord(state?.currentSession) ? state.currentSession : undefined;
1078
- const lock = isRecord(yoloop.lock) ? yoloop.lock : undefined;
1079
- const ref = {
1080
- ...(typeof yoloop.active === 'boolean' ? { active: yoloop.active } : {}),
1081
- currentEpicId: safeToken(currentSession?.currentEpicId ?? yoloop.currentEpicId) ?? null,
1082
- currentStoryId: safeToken(currentSession?.currentStoryId ?? yoloop.currentStoryId) ?? null,
1083
- sessionId: safeToken(currentSession?.sessionId ?? yoloop.sessionId) ?? null,
1084
- lockEpicId: safeToken(lock?.currentEpicId ?? lock?.epicId) ?? null,
1085
- };
1086
- return Object.keys(ref).length > 0 ? ref : undefined;
1087
- }
1088
- function continuitySessionRef(snapshot) {
1089
- const continuity = snapshot.continuity;
1090
- if (!isRecord(continuity))
1091
- return undefined;
1092
- const reasonCodes = Array.isArray(continuity.reasonCodes)
1093
- ? continuity.reasonCodes.filter((entry) => typeof entry === 'string')
1094
- : undefined;
1095
- return {
1096
- present: true,
1097
- activeJobId: safeToken(continuity.activeJobId ?? continuity.jobId) ?? null,
1098
- activeGoalId: safeToken(continuity.activeGoalId ?? continuity.goalId) ?? null,
1099
- activeLoopId: safeToken(continuity.activeLoopId ?? continuity.loopId) ?? null,
1100
- ...(reasonCodes && reasonCodes.length > 0 ? { reasonCodes: safeReasonCodes(reasonCodes) } : {}),
1101
- };
1102
- }
1103
- function deriveActiveRef(snapshot, session, yoloop) {
1104
- const sessionStoryId = safeToken(session?.activeStoryId);
1105
- const sessionEpicId = safeToken(session?.activeEpicId);
1106
- const sessionStepId = safeToken(session?.activeStepId);
1107
- const sessionStoryEpicId = sessionStoryId && snapshot.stories[sessionStoryId]
1108
- ? storyEpicId(snapshot.stories[sessionStoryId], sessionStoryId)
1109
- : null;
1110
- if ((sessionStoryId || sessionEpicId || sessionStepId) && isActiveEpicLifecycle(snapshot, sessionEpicId ?? sessionStoryEpicId)) {
1111
- return {
1112
- epicId: sessionEpicId ?? null,
1113
- storyId: sessionStoryId ?? null,
1114
- stepId: sessionStepId ?? null,
1115
- };
1116
- }
1117
- const yoloopStoryId = safeToken(yoloop?.currentStoryId);
1118
- const yoloopEpicId = safeToken(yoloop?.currentEpicId ?? yoloop?.lockEpicId);
1119
- if ((yoloopStoryId || yoloopEpicId) && isActiveEpicLifecycle(snapshot, yoloopEpicId)) {
1120
- return {
1121
- epicId: yoloopEpicId ?? null,
1122
- storyId: yoloopStoryId ?? null,
1123
- stepId: null,
1124
- };
1125
- }
1126
- const latestNonTerminal = Object.entries(snapshot.stories)
1127
- .map(([id, story]) => ({ id, story, timestamp: sortableStoryTimestamp(story) }))
1128
- .filter(({ id, story }) => !isTerminalStoryStatus(story.status) && isActiveEpicLifecycle(snapshot, storyEpicId(story, id)))
1129
- .sort((left, right) => right.timestamp - left.timestamp || left.id.localeCompare(right.id))[0];
1130
- if (latestNonTerminal) {
1131
- return {
1132
- epicId: storyEpicId(latestNonTerminal.story, latestNonTerminal.id),
1133
- storyId: latestNonTerminal.id,
1134
- stepId: safeToken(latestNonTerminal.story.last_step ?? latestNonTerminal.story.lastStep) ?? null,
1135
- };
1136
- }
1137
- return { epicId: null, storyId: null, stepId: null };
1138
- }
1139
- function buildStateSummary(sourceSnapshot, scope) {
1140
- const storyStatus = countStatuses(sourceSnapshot.stories);
1141
- const epicStatus = countStatuses(sourceSnapshot.epics);
1142
- const epicLifecycle = countEpicLifecycles(sourceSnapshot.epics);
1143
- const activeEpics = Object.values(sourceSnapshot.epics).filter((epic) => {
1144
- const lifecycle = EPIC_LIFECYCLE_CLASSIFICATIONS.includes(epic.lifecycle_classification)
1145
- ? epic.lifecycle_classification
1146
- : 'active';
1147
- return lifecycle === 'active' && !isTerminalStoryStatus(epic.status);
1148
- }).length;
1149
- const session = currentSessionRef(sourceSnapshot);
1150
- const yoloop = yoloopSessionRef(sourceSnapshot);
1151
- const continuity = continuitySessionRef(sourceSnapshot);
1152
- const active = deriveActiveRef(sourceSnapshot, session, yoloop);
1153
- const recent = recentStories(sourceSnapshot);
1154
- const reasonCodes = safeReasonCodes(scope.reasonCodes, [
1155
- 'state-summary-attached',
1156
- 'state-summary-bounded',
1157
- `projection-${scope.projectionMode ?? scope.kind}`,
1158
- scope.stateProjectionPolicy ? `policy-${scope.stateProjectionPolicy}` : 'policy-unknown',
1159
- recent.length >= RECENT_STORY_LIMIT ? 'recent-stories-capped' : 'recent-stories-bounded',
1160
- active.storyId || active.epicId ? 'active-ref-derived' : 'active-ref-empty',
1161
- yoloop ? 'yoloop-session-present' : 'yoloop-session-absent',
1162
- continuity ? 'continuity-session-present' : 'continuity-session-absent',
1163
- ]);
1164
- return {
1165
- schemaVersion: 1,
1166
- totals: {
1167
- stories: Object.keys(sourceSnapshot.stories).length,
1168
- epics: Object.keys(sourceSnapshot.epics).length,
1169
- storyStatus,
1170
- epicStatus,
1171
- epicLifecycle,
1172
- activeEpics,
1173
- blockedStories: storyStatus.blocked ?? 0,
1174
- },
1175
- active,
1176
- blockedCount: storyStatus.blocked ?? 0,
1177
- recentStories: recent,
1178
- ...(session ? { currentSession: session } : {}),
1179
- ...(yoloop ? { currentYoloopSession: yoloop } : {}),
1180
- ...(continuity ? { currentContinuitySession: continuity } : {}),
1181
- projection: {
1182
- commandId: scope.commandId ?? null,
1183
- stateProjectionPolicy: scope.stateProjectionPolicy ?? null,
1184
- projectionMode: scope.projectionMode,
1185
- scopeKind: scope.kind,
1186
- includedStoryCount: scope.includedStoryCount,
1187
- includedEpicCount: scope.includedEpicCount ?? Object.keys(sourceSnapshot.epics).length,
1188
- omittedStoryCount: scope.omittedStoryCount,
1189
- omittedEpicCount: scope.omittedEpicCount,
1190
- reason: scope.reason,
1191
- },
1192
- reasonCodes,
1193
- publicSafe: true,
1194
- };
1195
- }
1196
- function withStateSummary(projected, sourceSnapshot, scope) {
1197
- return {
1198
- ...projected,
1199
- stateSummary: buildStateSummary(sourceSnapshot, scope),
1200
- };
1201
- }
1202
- function buildCreateEpicProjection(trigger, snapshot, commandPolicy) {
1203
- const projectedEpics = {};
1204
- for (const epicId of Object.keys(snapshot.epics)) {
1205
- projectedEpics[epicId] = { id: epicId };
1206
- }
1207
- const scope = {
1208
- kind: 'projected',
1209
- commandId: commandPolicy.commandId,
1210
- stateProjectionPolicy: commandPolicy.stateProjectionPolicy,
1211
- projectionMode: 'summary-only',
1212
- trigger,
1213
- targetEpicId: null,
1214
- targetStoryId: null,
1215
- includedStoryCount: 0,
1216
- includedEpicCount: Object.keys(projectedEpics).length,
1217
- omittedStoryCount: Object.keys(snapshot.stories).length,
1218
- omittedEpicCount: 0,
1219
- reason: 'epic-summary',
1220
- reasonCodes: ['epic-summary', 'stories-omitted', 'epic-stubs-only'],
1221
- };
1222
- return withStateSummary({
1223
- ...snapshot,
1224
- stories: {},
1225
- epics: projectedEpics,
1226
- scope,
1227
- }, snapshot, scope);
1228
- }
1229
- function buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, reasonCodes = ['summary-only', 'stories-omitted'], projectionMode = 'summary-only') {
1230
- const projectedEpics = buildEpicStubs(snapshot);
1231
- const scope = {
1232
- kind: 'projected',
1233
- commandId: commandPolicy.commandId,
1234
- stateProjectionPolicy: commandPolicy.stateProjectionPolicy,
1235
- projectionMode,
1236
- trigger,
1237
- targetEpicId: null,
1238
- targetStoryId: null,
1239
- includedStoryCount: 0,
1240
- includedEpicCount: Object.keys(projectedEpics).length,
1241
- omittedStoryCount: Object.keys(snapshot.stories).length,
1242
- omittedEpicCount: Math.max(0, Object.keys(snapshot.epics).length - Object.keys(projectedEpics).length),
1243
- reason: 'summary-only',
1244
- reasonCodes: safeReasonCodes(reasonCodes),
1245
- };
1246
- return withStateSummary({
1247
- ...snapshot,
1248
- stories: {},
1249
- epics: projectedEpics,
1250
- scope,
1251
- }, snapshot, scope);
1252
- }
1253
- function buildStoryProjection(trigger, snapshot, commandPolicy, targetStoryId, projectionMode, reasonCodes) {
1254
- const targetStory = snapshot.stories[targetStoryId];
1255
- if (!targetStory) {
1256
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1257
- stories: Object.keys(snapshot.stories).length,
1258
- epics: Object.keys(snapshot.epics).length,
1259
- targetKind: 'story',
1260
- });
1261
- }
1262
- const targetEpicId = storyEpicId(targetStory, targetStoryId);
1263
- if (!targetEpicId) {
1264
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1265
- stories: Object.keys(snapshot.stories).length,
1266
- epics: Object.keys(snapshot.epics).length,
1267
- targetKind: 'epic',
1268
- });
1269
- }
1270
- const targetEpic = snapshot.epics[targetEpicId];
1271
- if (!targetEpic) {
1272
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1273
- stories: Object.keys(snapshot.stories).length,
1274
- epics: Object.keys(snapshot.epics).length,
1275
- targetKind: 'epic',
1276
- });
1277
- }
1278
- // Direct *yolo needs the same epic topology seen by *yoloop so a standalone
1279
- // invocation can bootstrap the canonical P207 graph epoch. Other story
1280
- // commands remain dependency-scoped. Stories outside the owning epic are
1281
- // retained only as compact structural dependencies by the yoloop projector.
1282
- const yoloEpicGraph = projectionMode === 'yolo-story';
1283
- const projectedStories = yoloEpicGraph
1284
- ? buildProjectedYoloopStories(targetEpicId, targetEpic, snapshot)
1285
- : buildProjectedStories(targetStoryId, snapshot);
1286
- const projectedEpics = yoloEpicGraph
1287
- ? buildProjectedYoloopEpics(targetEpicId, projectedStories, snapshot)
1288
- : buildProjectedEpics(projectedStories, snapshot);
1289
- if (!projectedStories[targetStoryId] || !projectedEpics[targetEpicId]) {
1290
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1291
- stories: Object.keys(projectedStories).length,
1292
- epics: Object.keys(projectedEpics).length,
1293
- targetKind: 'story',
1294
- });
1295
- }
1296
- const scope = {
1297
- kind: 'projected',
1298
- commandId: commandPolicy.commandId,
1299
- stateProjectionPolicy: commandPolicy.stateProjectionPolicy,
1300
- projectionMode,
1301
- trigger,
1302
- targetEpicId,
1303
- targetStoryId,
1304
- includedStoryCount: Object.keys(projectedStories).length,
1305
- includedEpicCount: Object.keys(projectedEpics).length,
1306
- omittedStoryCount: Math.max(0, Object.keys(snapshot.stories).length - Object.keys(projectedStories).length),
1307
- omittedEpicCount: Math.max(0, Object.keys(snapshot.epics).length - Object.keys(projectedEpics).length),
1308
- reason: 'targeted-invocation',
1309
- reasonCodes: safeReasonCodes(reasonCodes, yoloEpicGraph ? ['epic-graph-authority-complete'] : []),
1310
- };
1311
- return withStateSummary({
1312
- ...snapshot,
1313
- stories: projectedStories,
1314
- epics: projectedEpics,
1315
- scope,
1316
- }, snapshot, scope);
1317
- }
1318
- function buildTargetedEpicProjection(trigger, snapshot, commandPolicy, targetEpicId, projectionMode, reasonCodes) {
1319
- const targetEpic = snapshot.epics[targetEpicId];
1320
- if (!targetEpic) {
1321
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1322
- stories: Object.keys(snapshot.stories).length,
1323
- epics: Object.keys(snapshot.epics).length,
1324
- targetKind: 'epic',
1325
- });
1326
- }
1327
- const projectedStories = buildProjectedTargetEpicStories(targetEpic, snapshot);
1328
- const projectedEpics = buildProjectedEpics(projectedStories, snapshot, [targetEpicId]);
1329
- if (!projectedEpics[targetEpicId]) {
1330
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1331
- stories: Object.keys(projectedStories).length,
1332
- epics: Object.keys(projectedEpics).length,
1333
- targetKind: 'epic',
1334
- });
1335
- }
1336
- const scope = {
1337
- kind: 'projected',
1338
- commandId: commandPolicy.commandId,
1339
- stateProjectionPolicy: commandPolicy.stateProjectionPolicy,
1340
- projectionMode,
1341
- trigger,
1342
- targetEpicId,
1343
- targetStoryId: null,
1344
- includedStoryCount: Object.keys(projectedStories).length,
1345
- includedEpicCount: Object.keys(projectedEpics).length,
1346
- omittedStoryCount: Math.max(0, Object.keys(snapshot.stories).length - Object.keys(projectedStories).length),
1347
- omittedEpicCount: Math.max(0, Object.keys(snapshot.epics).length - Object.keys(projectedEpics).length),
1348
- reason: 'targeted-invocation',
1349
- reasonCodes: safeReasonCodes(reasonCodes),
1350
- };
1351
- return withStateSummary({
1352
- ...snapshot,
1353
- stories: projectedStories,
1354
- epics: projectedEpics,
1355
- scope,
1356
- }, snapshot, scope);
1357
- }
1358
- function buildYoloopProjection(trigger, snapshot, commandPolicy) {
1359
- const explicitCandidate = explicitYoloopEpicCandidate(trigger);
1360
- const explicitTargetEpicId = extractTargetEpicId(trigger, snapshot);
1361
- if (explicitCandidate && !explicitTargetEpicId) {
1362
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1363
- stories: Object.keys(snapshot.stories).length,
1364
- epics: Object.keys(snapshot.epics).length,
1365
- targetKind: 'epic',
1366
- });
1367
- }
1368
- const targetEpicId = extractYoloopTargetEpicId(trigger, snapshot);
1369
- const shape = classifyInvocationShapeV2({
1370
- commandId: commandPolicy.commandId,
1371
- explicitYoloopEpicId: explicitTargetEpicId,
1372
- sessionYoloopEpicId: explicitTargetEpicId ? null : targetEpicId,
1373
- });
1374
- if (shape === 'yoloop-discovery')
1375
- return buildYoloopDiscoveryProjection(trigger, snapshot, commandPolicy);
1376
- if (!targetEpicId || (shape !== 'yoloop-target' && shape !== 'yoloop-session')) {
1377
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1378
- stories: Object.keys(snapshot.stories).length,
1379
- epics: Object.keys(snapshot.epics).length,
1380
- targetKind: 'epic',
1381
- });
1382
- }
1383
- const targetEpic = snapshot.epics[targetEpicId];
1384
- if (!targetEpic) {
1385
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1386
- stories: Object.keys(snapshot.stories).length,
1387
- epics: Object.keys(snapshot.epics).length,
1388
- targetKind: 'epic',
1389
- });
1390
- }
1391
- const projectedStories = buildProjectedYoloopStories(targetEpicId, targetEpic, snapshot);
1392
- const projectedEpics = buildProjectedYoloopEpics(targetEpicId, projectedStories, snapshot);
1393
- if (!projectedEpics[targetEpicId]) {
1394
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1395
- stories: Object.keys(projectedStories).length,
1396
- epics: Object.keys(projectedEpics).length,
1397
- targetKind: 'epic',
1398
- });
1399
- }
1400
- const projectionMode = shape;
1401
- const scope = {
1402
- kind: 'projected',
1403
- commandId: commandPolicy.commandId,
1404
- stateProjectionPolicy: commandPolicy.stateProjectionPolicy,
1405
- projectionMode,
1406
- trigger,
1407
- targetEpicId,
1408
- targetStoryId: null,
1409
- targetEpicCoverage: buildTargetEpicCoverage(targetEpicId, targetEpic, projectedStories),
1410
- includedStoryCount: Object.keys(projectedStories).length,
1411
- includedEpicCount: Object.keys(projectedEpics).length,
1412
- omittedStoryCount: Math.max(0, Object.keys(snapshot.stories).length - Object.keys(projectedStories).length),
1413
- omittedEpicCount: Math.max(0, Object.keys(snapshot.epics).length - Object.keys(projectedEpics).length),
1414
- reason: 'targeted-invocation',
1415
- reasonCodes: ['structural-required', projectionMode, 'yoloop-targeted'],
1416
- };
1417
- return withStateSummary({
1418
- ...snapshot,
1419
- stories: projectedStories,
1420
- epics: projectedEpics,
1421
- scope,
1422
- }, snapshot, scope);
1423
- }
1424
- function buildPayloadGuardrailEpics(snapshot, retainedStoryIds) {
1425
- const projectedEpics = {};
1426
- for (const [epicId, epic] of Object.entries(snapshot.epics)) {
1427
- const retainedEpicStories = Array.isArray(epic.stories)
1428
- ? epic.stories.filter((storyId) => typeof storyId === 'string' && retainedStoryIds.has(storyId))
1429
- : [];
1430
- projectedEpics[epicId] = {
1431
- id: safeToken(epic.id) ?? epicId,
1432
- ...(safeToken(epic.status, 40) ? { status: safeToken(epic.status, 40) } : {}),
1433
- ...(typeof epic.total_stories === 'number' && Number.isFinite(epic.total_stories)
1434
- ? { total_stories: epic.total_stories }
1435
- : {}),
1436
- ...(typeof epic.completed_stories === 'number' && Number.isFinite(epic.completed_stories)
1437
- ? { completed_stories: epic.completed_stories }
1438
- : {}),
1439
- ...(retainedEpicStories.length > 0 ? { stories: retainedEpicStories } : {}),
1440
- ...(retainedEpicStories.length > 0 && Array.isArray(epic.depends_on)
1441
- ? { depends_on: epic.depends_on.filter((value) => typeof value === 'string' && value.length > 0) }
1442
- : {}),
1443
- ...(retainedEpicStories.length > 0 && (epic.branch_mode === 'epic' || epic.branch_mode === 'story')
1444
- ? { branch_mode: epic.branch_mode }
1445
- : {}),
1446
- ...(retainedEpicStories.length > 0 && typeof epic.execution_branch === 'string'
1447
- ? { execution_branch: epic.execution_branch }
1448
- : {}),
1449
- ...(retainedEpicStories.length > 0 && typeof epic.origin_branch === 'string'
1450
- ? { origin_branch: epic.origin_branch }
1451
- : {}),
1452
- ...(retainedEpicStories.length > 0 && (epic.branch_lease === null || typeof epic.branch_lease === 'object')
1453
- ? { branch_lease: epic.branch_lease }
1454
- : {}),
1455
- ...(retainedEpicStories.length > 0 && (epic.origin_binding === null || typeof epic.origin_binding === 'object')
1456
- ? { origin_binding: epic.origin_binding }
1457
- : {}),
1458
- ...(retainedEpicStories.length > 0 && (epic.aggregate_qa_receipt === null || typeof epic.aggregate_qa_receipt === 'object')
1459
- ? { aggregate_qa_receipt: epic.aggregate_qa_receipt }
1460
- : {}),
1461
- };
1462
- }
1463
- return projectedEpics;
1464
- }
1465
- function sourceStoryTotal(snapshot) {
1466
- return snapshot.stateSummary?.totals.stories
1467
- ?? ((snapshot.scope?.includedStoryCount ?? Object.keys(snapshot.stories).length) + (snapshot.scope?.omittedStoryCount ?? 0));
1468
- }
1469
- function sourceEpicTotal(snapshot) {
1470
- return snapshot.stateSummary?.totals.epics
1471
- ?? ((snapshot.scope?.includedEpicCount ?? Object.keys(snapshot.epics).length) + (snapshot.scope?.omittedEpicCount ?? 0));
1472
- }
1473
- function updateStateSummaryForPayloadGuardrail(snapshot, scope) {
1474
- if (!snapshot.stateSummary)
1475
- return undefined;
1476
- return {
1477
- ...snapshot.stateSummary,
1478
- projection: {
1479
- ...snapshot.stateSummary.projection,
1480
- scopeKind: 'projected',
1481
- projectionMode: scope.projectionMode,
1482
- includedStoryCount: scope.includedStoryCount,
1483
- includedEpicCount: scope.includedEpicCount ?? snapshot.stateSummary.projection.includedEpicCount,
1484
- omittedStoryCount: scope.omittedStoryCount,
1485
- omittedEpicCount: scope.omittedEpicCount,
1486
- reason: 'body-size',
1487
- },
1488
- reasonCodes: safeReasonCodes(snapshot.stateSummary.reasonCodes, ['payload-size-guardrail', 'state-summary-preserved', 'nonessential-state-degraded']),
1489
- };
1490
- }
1491
- /**
1492
- * P198.04 -- deterministic post-assembly state degradation.
1493
- *
1494
- * This helper is intentionally pure and request-only. It removes historical story
1495
- * bodies that are not structural for the already-projected request, converts the
1496
- * epic map to public stubs, keeps `stateSummary`, and preserves structural-required
1497
- * story/yolo/yoloop target state instead of silently corrupting it.
1498
- */
1499
- export function degradeStateSnapshotForPayloadLimit(snapshot) {
1500
- const scope = snapshot.scope;
1501
- const retainedStoryIds = new Set();
1502
- const preserveProjectedStructuralStories = scope?.projectionMode === 'structural-required'
1503
- || scope?.projectionMode === 'yolo-story'
1504
- || scope?.projectionMode === 'yoloop-target'
1505
- || scope?.projectionMode === 'yoloop-session'
1506
- || scope?.projectionMode === 'yoloop-discovery';
1507
- if (preserveProjectedStructuralStories) {
1508
- for (const storyId of Object.keys(snapshot.stories)) {
1509
- retainedStoryIds.add(storyId);
1510
- }
1511
- }
1512
- else if (scope?.targetStoryId) {
1513
- addStoryAndDependencies(scope.targetStoryId, snapshot, retainedStoryIds);
1514
- }
1515
- const projectedStories = {};
1516
- for (const storyId of retainedStoryIds) {
1517
- const story = snapshot.stories[storyId];
1518
- if (story)
1519
- projectedStories[storyId] = story;
1520
- }
1521
- const projectedEpics = buildPayloadGuardrailEpics(snapshot, retainedStoryIds);
1522
- const includedStoryCount = Object.keys(projectedStories).length;
1523
- const includedEpicCount = Object.keys(projectedEpics).length;
1524
- const omittedStoryCount = Math.max(0, sourceStoryTotal(snapshot) - includedStoryCount);
1525
- const omittedEpicCount = Math.max(0, sourceEpicTotal(snapshot) - includedEpicCount);
1526
- const projectionMode = preserveProjectedStructuralStories
1527
- ? scope?.projectionMode ?? 'structural-required'
1528
- : scope?.projectionMode === 'yolo-story'
1529
- ? 'yolo-story'
1530
- : 'summary-only';
1531
- const nextScope = {
1532
- kind: 'projected',
1533
- commandId: scope?.commandId ?? null,
1534
- stateProjectionPolicy: scope?.stateProjectionPolicy ?? null,
1535
- projectionMode,
1536
- targetEpicId: scope?.targetEpicId ?? null,
1537
- targetStoryId: scope?.targetStoryId ?? null,
1538
- ...(scope?.targetEpicCoverage ? { targetEpicCoverage: scope.targetEpicCoverage } : {}),
1539
- includedStoryCount,
1540
- includedEpicCount,
1541
- omittedStoryCount,
1542
- omittedEpicCount,
1543
- reason: 'body-size',
1544
- reasonCodes: safeReasonCodes(scope?.reasonCodes, [
1545
- 'payload-size-guardrail',
1546
- retainedStoryIds.size > 0 ? 'structural-targets-preserved' : 'stories-omitted',
1547
- 'epics-stubbed',
1548
- 'state-summary-preserved',
1549
- 'redundant-trigger-omitted',
1550
- ]),
1551
- };
1552
- const stateSummary = updateStateSummaryForPayloadGuardrail(snapshot, nextScope);
1553
- return {
1554
- ...snapshot,
1555
- stories: projectedStories,
1556
- epics: projectedEpics,
1557
- scope: nextScope,
1558
- ...(stateSummary ? { stateSummary } : {}),
1559
- };
1560
- }
1561
- /**
1562
- * Return a request-scoped state snapshot for invoke commands.
1563
- *
1564
- * The function is intentionally pure. Structural uncertainty fails closed;
1565
- * callers must surface the public code instead of sending a full-state fallback.
1566
- */
1567
- export function projectStateSnapshotForInvoke(args, snapshot) {
1568
- const trigger = args.trim();
1569
- const commandPolicy = resolveCommandProjectionPolicy(trigger);
1570
- try {
1571
- if (!commandPolicy) {
1572
- if (firstTokenIsStoryReference(trigger)) {
1573
- const storyReferencePolicy = policy('story-reference', 'story-targeted');
1574
- const targetStoryId = extractStoryId(trigger);
1575
- if (targetStoryId) {
1576
- return buildStoryProjection(trigger, snapshot, storyReferencePolicy, targetStoryId, 'targeted-story', ['story-reference-targeted']);
1577
- }
1578
- }
1579
- return buildSummaryOnlyProjection(trigger, snapshot, policy('unknown', 'adaptive-targeted'), ['unknown-command-summary-only']);
1580
- }
1581
- if (commandPolicy.stateProjectionPolicy === 'epic-summary') {
1582
- return buildCreateEpicProjection(trigger, snapshot, commandPolicy);
1583
- }
1584
- if (commandPolicy.stateProjectionPolicy === 'yoloop-targeted') {
1585
- return buildYoloopProjection(trigger, snapshot, commandPolicy);
1586
- }
1587
- const targetStoryId = extractStoryId(trigger);
1588
- if (commandPolicy.stateProjectionPolicy === 'story-targeted') {
1589
- if (targetStoryId) {
1590
- const invocationShape = classifyInvocationShapeV2({ commandId: commandPolicy.commandId, targetStoryId });
1591
- const yoloStory = invocationShape === 'yolo-story';
1592
- return buildStoryProjection(trigger, snapshot, commandPolicy, targetStoryId, yoloStory ? 'yolo-story' : commandPolicy.structuralRequired ? 'structural-required' : 'targeted-story', [yoloStory ? 'yolo-story' : commandPolicy.structuralRequired ? 'structural-required' : 'targeted-story']);
1593
- }
1594
- if (commandPolicy.commandId === 'yolo' || commandPolicy.commandId === 'yolo-inline') {
1595
- const invocationShape = classifyInvocationShapeV2({ commandId: commandPolicy.commandId });
1596
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['yolo-inline', 'stories-omitted', 'historical-content-omitted'], invocationShape ?? 'yolo-inline');
1597
- }
1598
- // Commit without a story is an exact root working-tree workflow. It
1599
- // needs no story graph, but a malformed or unknown target must not gain
1600
- // this summary-only escape from structural target validation.
1601
- if (commandPolicy.commandId === 'commit' && /^\*?(?:commit|commit-push)$/i.test(trigger)) {
1602
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['working-tree-commit', 'stories-omitted', 'historical-content-omitted']);
1603
- }
1604
- return commandPolicy.structuralRequired
1605
- ? (() => {
1606
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1607
- stories: Object.keys(snapshot.stories).length,
1608
- epics: Object.keys(snapshot.epics).length,
1609
- targetKind: 'story',
1610
- });
1611
- })()
1612
- : buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['story-target-missing-summary-only']);
1613
- }
1614
- if (commandPolicy.stateProjectionPolicy === 'adaptive-targeted') {
1615
- if (targetStoryId && snapshot.stories[targetStoryId]) {
1616
- return buildStoryProjection(trigger, snapshot, commandPolicy, targetStoryId, 'targeted-story', ['adaptive-story-targeted']);
1617
- }
1618
- const targetEpicId = extractTargetEpicId(trigger, snapshot);
1619
- if (targetEpicId) {
1620
- return buildTargetedEpicProjection(trigger, snapshot, commandPolicy, targetEpicId, 'targeted-epic', ['adaptive-epic-targeted']);
1621
- }
1622
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['adaptive-summary-only', 'target-unresolved-summary-only']);
1623
- }
1624
- if (commandPolicy.stateProjectionPolicy === 'epic-targeted') {
1625
- // The root *arch-plan pipeline delegates its current stage with the
1626
- // internal marker `epic-arch`. It has no user-selected epic yet; keep
1627
- // this exact marker only when the bounded root checkpoint names the
1628
- // same stage. The server still verifies the accounting receipt.
1629
- if (commandPolicy.commandId.startsWith('arch-')
1630
- && /(?:^|\s)epic-arch\s*$/i.test(trigger)
1631
- && snapshot.archPlan?.execution?.currentStageCommand === commandPolicy.commandId) {
1632
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['architecture-root-delegated']);
1633
- }
1634
- const targetEpicId = extractTargetEpicId(trigger, snapshot);
1635
- if (targetEpicId) {
1636
- return buildTargetedEpicProjection(trigger, snapshot, commandPolicy, targetEpicId, commandPolicy.structuralRequired ? 'structural-required' : 'targeted-epic', [commandPolicy.structuralRequired ? 'structural-required' : 'targeted-epic']);
1637
- }
1638
- return commandPolicy.structuralRequired
1639
- ? (() => {
1640
- throw new StructuralDagError('STRUCTURAL_TARGET_NOT_FOUND', {
1641
- stories: Object.keys(snapshot.stories).length,
1642
- epics: Object.keys(snapshot.epics).length,
1643
- targetKind: 'epic',
1644
- });
1645
- })()
1646
- : buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['epic-target-missing-summary-only']);
1647
- }
1648
- if (commandPolicy.stateProjectionPolicy === 'continuity-scoped') {
1649
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['continuity-scoped-summary-only']);
1650
- }
1651
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy, ['policy-full-summary-only']);
1652
- }
1653
- catch (error) {
1654
- if (error instanceof StructuralDagError)
1655
- throw error;
1656
- if (commandPolicy?.structuralRequired) {
1657
- throw new StructuralDagError('STRUCTURAL_DEPENDENCY_MISSING', {
1658
- stories: Object.keys(snapshot.stories).length,
1659
- epics: Object.keys(snapshot.epics).length,
1660
- projectionErrors: 1,
1661
- });
1662
- }
1663
- return buildSummaryOnlyProjection(trigger, snapshot, commandPolicy ?? policy('unknown', 'adaptive-targeted'), ['projection-error-summary-only']);
1664
- }
1665
- }
1666
- const V2_INVOCATION_SHAPES = new Set([
1667
- 'yolo-story',
1668
- 'yolo-inline',
1669
- 'yoloop-target',
1670
- 'yoloop-session',
1671
- 'yoloop-discovery',
1672
- ]);
1673
- function projectedEdgeCount(snapshot) {
1674
- let edges = 0;
1675
- for (const collection of [snapshot.stories, snapshot.epics]) {
1676
- for (const entry of Object.values(collection)) {
1677
- if (Array.isArray(entry.depends_on)) {
1678
- edges += entry.depends_on.filter((value) => typeof value === 'string').length;
1679
- }
1680
- }
1681
- }
1682
- return edges;
1683
- }
1684
- /**
1685
- * Versioned result contract for the five structural YOLO/yoloop shapes.
1686
- * Other command families retain their existing projection policy and return
1687
- * null because they are outside StateProjectionV2's closed shape union.
1688
- */
1689
- export function projectStateSnapshotResultV2ForInvoke(args, snapshot) {
1690
- const commandPolicy = resolveCommandProjectionPolicy(args.trim());
1691
- if (!commandPolicy
1692
- || !['yolo', 'yolo-inline', 'yoloop'].includes(commandPolicy.commandId)) {
1693
- return null;
1694
- }
1695
- try {
1696
- const projected = projectStateSnapshotForInvoke(args, snapshot);
1697
- const shape = projected.scope?.projectionMode;
1698
- if (!shape || !V2_INVOCATION_SHAPES.has(shape)) {
1699
- throw new StructuralDagError('STRUCTURAL_DEPENDENCY_MISSING', {
1700
- stories: Object.keys(projected.stories).length,
1701
- epics: Object.keys(projected.epics).length,
1702
- projectionShapeErrors: 1,
1703
- });
1704
- }
1705
- return Object.freeze({
1706
- ok: true,
1707
- version: 2,
1708
- shape,
1709
- snapshot: projected,
1710
- included: {
1711
- epics: projected.scope?.includedEpicCount ?? Object.keys(projected.epics).length,
1712
- stories: projected.scope?.includedStoryCount ?? Object.keys(projected.stories).length,
1713
- edges: projectedEdgeCount(projected),
1714
- },
1715
- omitted: {
1716
- epics: projected.scope?.omittedEpicCount ?? 0,
1717
- stories: projected.scope?.omittedStoryCount ?? 0,
1718
- },
1719
- cycleCount: 0,
1720
- });
1721
- }
1722
- catch (error) {
1723
- if (!(error instanceof StructuralDagError))
1724
- throw error;
1725
- return Object.freeze({
1726
- ok: false,
1727
- code: error.code,
1728
- publicDetails: error.publicDetails,
1729
- });
1730
- }
1731
- }
1
+ import{createHash as B}from"node:crypto";import{analyzeDependencyDag as C,StructuralDagError as y}from"./structural-dag-projection.js";import{classifyInvocationShapeV2 as O}from"./invocation-shape.js";const U=12,J=16,k=["active","archived","rolled-back","synthetic","orphan"],X=new Set(["in-progress","branch-ready","diagnose","research","write-spec","create-tasks","implemented","refactor-suggest-done","property-tests-emitted","tests-validated","qa-gate-passed","memory-updated","committed","synced","pr-created","pr-reviewed","partial"]);function Q(r){return r==="STRUCTURAL_TARGET_NOT_FOUND"?"registration-missing":r==="STRUCTURAL_DEPENDENCY_CYCLE"?"dependency-cycle":"dependency-missing"}function Fe(r){const e=/^[a-f0-9]{64}$/,t=/^P[1-9][0-9]*(?:\.[0-9]+)*$/,i=/^[A-Za-z0-9][A-Za-z0-9._/-]{0,239}$/;if(r.schemaVersion!=="EpicOperationalPublicProjection/1.0"||!e.test(r.repositoryFingerprint)||!e.test(r.identityHash)||!t.test(r.epicId)||!i.test(r.executionBranch)||!e.test(r.graphRevision)||!Number.isSafeInteger(r.storeRevision)||r.storeRevision<0||!Number.isSafeInteger(r.writerEpoch)||r.writerEpoch<1||r.runId!==null&&r.runId.length>128||r.runStatus!==null&&r.runStatus.length>32||r.runRevision!==null&&(!Number.isSafeInteger(r.runRevision)||r.runRevision<0)||r.snapshotHash!==null&&!e.test(r.snapshotHash)||!e.test(r.continuationSessionHash)||!e.test(r.pendingAuthorityHash)||!Number.isSafeInteger(r.pendingAuthorityCount)||r.pendingAuthorityCount<0||r.pendingAuthorityCount>1024||r.reasonCodes.length>16||r.reasonCodes.some(c=>!/^[a-z0-9][a-z0-9-]{0,79}$/.test(c))||r.publicSafe!==!0)throw new Error("epic-operational-projection-invalid");return Object.freeze({schemaVersion:r.schemaVersion,repositoryFingerprint:r.repositoryFingerprint,identityHash:r.identityHash,epicId:r.epicId,executionBranch:r.executionBranch,graphRevision:r.graphRevision,storeRevision:r.storeRevision,writerEpoch:r.writerEpoch,runId:r.runId,runStatus:r.runStatus,runRevision:r.runRevision,snapshotHash:r.snapshotHash,continuationSessionHash:r.continuationSessionHash,pendingAuthorityHash:r.pendingAuthorityHash,pendingAuthorityCount:r.pendingAuthorityCount,lockActive:r.lockActive,currentSessionActive:r.currentSessionActive,journalActive:r.journalActive,reasonCodes:[...r.reasonCodes],publicSafe:!0})}const o=(r,e,t={})=>({commandId:r,stateProjectionPolicy:e,...t}),A=Object.freeze({status:o("status","full"),"arch-plan":o("arch-plan","full"),"arch-prd":o("arch-prd","full"),"arch-architecture":o("arch-architecture","epic-targeted",{structuralRequired:!0}),"arch-api-contracts":o("arch-api-contracts","epic-targeted",{structuralRequired:!0}),"arch-api-integrations":o("arch-api-integrations","epic-targeted",{structuralRequired:!0}),"arch-database":o("arch-database","epic-targeted",{structuralRequired:!0}),"arch-security":o("arch-security","epic-targeted",{structuralRequired:!0}),"arch-design-system":o("arch-design-system","epic-targeted",{structuralRequired:!0}),"arch-ux-design":o("arch-ux-design","epic-targeted",{structuralRequired:!0}),"arch-performance":o("arch-performance","epic-targeted",{structuralRequired:!0}),"arch-testing":o("arch-testing","epic-targeted",{structuralRequired:!0}),"arch-infrastructure":o("arch-infrastructure","epic-targeted",{structuralRequired:!0}),"arch-review":o("arch-review","epic-targeted",{structuralRequired:!0}),"arch-fitness-functions":o("arch-fitness-functions","epic-targeted",{structuralRequired:!0}),"create-epic":o("create-epic","epic-summary"),"idea-diagnose":o("idea-diagnose","full"),"idea-research":o("idea-research","epic-targeted",{structuralRequired:!0}),"generate-epic":o("generate-epic","epic-targeted",{structuralRequired:!0}),exec:o("exec","story-targeted",{structuralRequired:!0}),yolo:o("yolo","story-targeted",{structuralRequired:!0}),"yolo-inline":o("yolo-inline","story-targeted",{structuralRequired:!0}),epic:o("epic","epic-targeted",{structuralRequired:!0}),"setup-branch":o("setup-branch","story-targeted",{structuralRequired:!0}),diagnose:o("diagnose","adaptive-targeted"),"diagnose-inline":o("diagnose-inline","full"),research:o("research","adaptive-targeted"),"research-inline":o("research-inline","full"),"write-spec":o("write-spec","story-targeted",{structuralRequired:!0}),"create-tasks":o("create-tasks","story-targeted",{structuralRequired:!0}),implement:o("implement","story-targeted",{structuralRequired:!0}),commit:o("commit","story-targeted",{structuralRequired:!0}),"commit-push":o("commit","story-targeted",{structuralRequired:!0}),sync:o("sync","story-targeted",{structuralRequired:!0}),"sync-main":o("sync","story-targeted",{structuralRequired:!0}),"create-pr":o("create-pr","story-targeted",{structuralRequired:!0}),review:o("review","story-targeted"),"review-pr":o("review","story-targeted"),merge:o("merge","story-targeted",{structuralRequired:!0}),"merge-pr":o("merge","story-targeted",{structuralRequired:!0}),"fix-blocked":o("fix-blocked","story-targeted"),"finalize-epic":o("finalize-epic","epic-targeted"),"resolve-conflicts":o("resolve-conflicts","story-targeted"),"update-memory":o("update-memory","full"),"update-project-memory":o("update-memory","story-targeted",{structuralRequired:!0}),refactor:o("refactor","adaptive-targeted"),"refactor-suggest":o("refactor","story-targeted",{structuralRequired:!0}),cleanup:o("cleanup","full"),audit:o("audit","full"),"tech-debt":o("tech-debt","full"),menu:o("menu","full"),plans:o("plans","full"),billing:o("billing","full"),subscribe:o("subscribe","full"),"qa-scan":o("qa-scan","full"),yoloop:o("yoloop","yoloop-targeted",{structuralRequired:!0}),"migrate-state":o("migrate-state","full"),"migrate-project-id":o("migrate-project-id","full"),"policy-audit":o("policy-audit","full"),"mutation-test":o("mutation-test","full"),"sync-openapi":o("sync-openapi","full"),"generate-pacts":o("generate-pacts","full"),"verify-pacts":o("verify-pacts","full"),"property-test":o("property-test","full"),"property-tests":o("property-test","story-targeted",{structuralRequired:!0}),"chaos-plan":o("chaos-plan","full"),"ui-ux-review":o("ui-ux-review","adaptive-targeted"),"solyd-system":o("solyd-system","adaptive-targeted"),goal:o("goal","continuity-scoped"),loop:o("loop","continuity-scoped"),jobs:o("jobs","continuity-scoped"),runner:o("runner","continuity-scoped"),"goal-tick":o("goal-tick","continuity-scoped"),"loop-tick":o("loop-tick","continuity-scoped"),"validate-tests":o("validate-tests","story-targeted",{structuralRequired:!0}),"qa-gate":o("qa-gate","story-targeted",{structuralRequired:!0})}),ee=Object.freeze({st:"status",arquitetura:"arch-plan",architecture:"arch-plan",arch:"arch-plan",prd:"arch-prd","product-requirements":"arch-prd","arch-doc":"arch-architecture","tech-architecture":"arch-architecture","api-contracts":"arch-api-contracts","api-contract":"arch-api-contracts","api-integrations":"arch-api-integrations","api-int":"arch-api-integrations","database-schema":"arch-database","db-schema":"arch-database",db:"arch-database","cyber-security":"arch-security",security:"arch-security",sec:"arch-security","design-system":"arch-design-system",ds:"arch-design-system","atomic-design":"arch-design-system","ux-design":"arch-ux-design",ux:"arch-ux-design",wireframes:"arch-ux-design",wireframe:"arch-ux-design","user-flows":"arch-ux-design",performance:"arch-performance",perf:"arch-performance","capacity-planning":"arch-performance",capacity:"arch-performance","arch-perf":"arch-performance","performance-strategy":"arch-performance","testing-strategy":"arch-testing","test-plan":"arch-testing","test-strategy":"arch-testing","arch-test":"arch-testing",infrastructure:"arch-infrastructure",infra:"arch-infrastructure","deploy-plan":"arch-infrastructure",deployment:"arch-infrastructure","arch-infra":"arch-infrastructure","arch-deploy":"arch-infrastructure","review-consolidation":"arch-review",consolidation:"arch-review","architecture-review":"arch-review","arch-consolidation":"arch-review",fitness:"arch-fitness-functions","fitness-functions":"arch-fitness-functions",archfit:"arch-fitness-functions","arch-fit":"arch-fitness-functions","fit-funcs":"arch-fitness-functions","criar-epic":"create-epic",planejamento:"create-epic","idea-diag":"idea-diagnose","idea-pesq":"idea-research","gerar-epic":"generate-epic",executar:"exec",pipeline:"exec","parallel-epic":"epic",setup:"setup-branch",branch:"setup-branch",diag:"diagnose",diagnostico:"diagnose",c02:"diagnose",pesquisar:"research",pesq:"research","research-fix":"research",c03:"research",spec:"write-spec",especificacao:"write-spec",c04:"write-spec",tasks:"create-tasks",tarefas:"create-tasks",c05:"create-tasks",impl:"implement",implementar:"implement",c06:"implement",push:"commit",commit_push:"commit",cp:"commit",c07:"commit",sincronizar:"sync",c08:"sync",pr:"create-pr",c09:"create-pr",revisar:"review",c11:"review",mesclar:"merge",c12:"merge",fix:"fix-blocked",corrigir:"fix-blocked",finalizar:"finalize-epic",conflitos:"resolve-conflicts",memoria:"update-memory",refactoring:"refactor",refact:"refactor",refac:"refactor",rf:"refactor","cleanup-code":"refactor","code-cleanup":"refactor","code-quality":"refactor","improve-code":"refactor",modernize:"refactor",modernization:"refactor",legacy:"refactor","legacy-code":"refactor","debt-pay":"refactor","pay-debt":"refactor","debt-reduction":"refactor","smell-fix":"refactor","fix-smells":"refactor","code-smells":"refactor",strangler:"refactor","strangler-fig":"refactor",limpar:"cleanup",limpeza:"cleanup",auditar:"audit",auditoria:"audit",debt:"tech-debt",debts:"tech-debt","debt-list":"tech-debt","tech-debts":"tech-debt",td:"tech-debt",help:"menu",ajuda:"menu","?":"menu",commands:"menu",cmds:"menu",planos:"plans",pricing:"plans",bill:"billing",subscription:"billing",sub:"billing",upgrade:"subscribe",checkout:"subscribe",qa:"qa-scan","qa-test":"qa-scan","visual-qa":"qa-scan","e2e-scan":"qa-scan",troubleshoot:"qa-scan","debug-ui":"qa-scan",scan:"qa-scan",a11y:"qa-scan",accessibility:"qa-scan",wcag:"qa-scan","auto-yolo":"yoloop","epic-runner":"yoloop","story-runner":"yoloop","loop-yolo":"yoloop","auto-epic":"yoloop",migrate:"migrate-state","state-migrate":"migrate-state","schema-migrate":"migrate-state",policy:"policy-audit","audit-policy":"policy-audit","policy-history":"policy-audit",policies:"policy-audit",mutation:"mutation-test",stryker:"mutation-test","kill-mutants":"mutation-test","openapi-sync":"sync-openapi","api-sync":"sync-openapi","spec-sync":"sync-openapi","regen-openapi":"sync-openapi",pacts:"generate-pacts","gen-pacts":"generate-pacts","regen-pacts":"generate-pacts","create-pacts":"generate-pacts","verify-pact":"verify-pacts","pact-verify":"verify-pacts","check-pacts":"verify-pacts","pact-check":"verify-pacts",property:"property-test",pbt:"property-test",proptest:"property-test","invariant-test":"property-test",chaos:"chaos-plan",gameday:"chaos-plan","resilience-test":"chaos-plan","ux-review":"ui-ux-review","design-review":"ui-ux-review","visual-review":"ui-ux-review","product-polish":"ui-ux-review","security-system":"solyd-system","authorized-security":"solyd-system","sec-system":"solyd-system",goals:"goal","durable-goal":"goal","continuity-goal":"goal",loops:"loop","durable-loop":"loop","continuity-loop":"loop",job:"jobs","continuity-jobs":"jobs","neocortex-runner":"runner","continuity-runner":"runner"}),te=Object.freeze({1:"status",3:"arch-plan",4:"arch-prd",5:"arch-architecture",6:"arch-api-contracts",7:"arch-api-integrations",8:"arch-database",9:"arch-security",10:"arch-design-system",11:"arch-ux-design",12:"arch-performance",13:"arch-testing",14:"arch-infrastructure",15:"arch-review",16:"arch-fitness-functions",17:"create-epic",18:"idea-diagnose",19:"idea-research",20:"generate-epic",21:"exec",22:"yolo",23:"epic",24:"setup-branch",25:"diagnose",26:"research",27:"write-spec",28:"create-tasks",29:"implement",30:"commit",31:"sync",32:"create-pr",33:"review",34:"merge",35:"fix-blocked",36:"finalize-epic",37:"resolve-conflicts",38:"update-memory",39:"refactor",40:"cleanup",41:"audit",42:"tech-debt",43:"menu",44:"plans",45:"billing",46:"subscribe",47:"qa-scan",48:"yoloop",49:"migrate-state",50:"policy-audit",51:"mutation-test",52:"sync-openapi",53:"generate-pacts",54:"verify-pacts",55:"property-test",56:"chaos-plan",57:"ui-ux-review",58:"solyd-system",59:"goal",60:"loop",61:"jobs",62:"runner"});function d(r,e=120){if(typeof r!="string")return;const t=r.trim();if(t)return t.replace(/[^a-z0-9_.:-]+/gi,"_").slice(0,e)}function T(r,e=120){if(typeof r!="string")return;const t=r.trim(),i=d(r,e);return i===t?i:void 0}function w(r){if(typeof r!="string")return;const e=r.trim();if(!(!e||e.length>240||!/^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(e)||e.includes("..")||e.includes("//")||e.includes("@{")||e.endsWith("/")||e.endsWith(".")||e.split("/").some(t=>!t||t.startsWith(".")||t.endsWith(".lock"))))return e}function re(r){if(typeof r!="string")return;const e=r.replace(/\\/g,"/");if(!(!e||e.length>240||e.startsWith("/")||/^[A-Za-z]:/.test(e)||e.includes("..")||e.includes("//")||e.split("/").includes(".")||!/^[A-Za-z0-9._/:@#-]+$/.test(e)))return e}function S(r){if(r===void 0||!Array.isArray(r)||r.length>128)return;const e=r.map(re);if(!e.some(t=>t===void 0))return[...new Set(e)].sort((t,i)=>t.localeCompare(i,"en"))}function ie(r){return typeof r=="string"&&X.has(r.trim().toLowerCase().replace(/_/g,"-"))}function v(r,e){const t={};for(const i of e){const c=r[i];typeof c=="string"||typeof c=="boolean"||typeof c=="number"&&Number.isFinite(c)?t[i]=c:Array.isArray(c)&&c.every(n=>typeof n=="string")&&(t[i]=[...c])}return t}function ce(r,e){const t=e.checkpoint;if(!h(t)||t.schemaVersion!==1||t.storyId!==r||t.epicId!==e.epic_id||!w(t.branch)||typeof t.baseSha!="string"||!/^[0-9a-f]{7,64}$/i.test(t.baseSha)||typeof t.headSha!="string"||!/^[0-9a-f]{7,64}$/i.test(t.headSha)||t.baseSha===t.headSha||!T(t.idempotencyKey)||typeof t.recordedAt!="string"||!Number.isFinite(Date.parse(t.recordedAt))||!Array.isArray(t.commits)||t.commits.length===0||t.commits.length>256||t.commits.some(c=>typeof c!="string"||!/^[0-9a-f]{7,64}$/i.test(c))||!Array.isArray(t.receiptRefs)||t.receiptRefs.length===0||t.receiptRefs.length>256||t.receiptRefs.some(c=>typeof c!="string"||c.length>240||c.includes("..")||!/^[A-Za-z0-9._:/#\-[\]]+$/.test(c))||!h(t.qaReceipt)||t.qaReceipt.kind!=="story_qa_evidence"||t.qaReceipt.producer!=="local-yolo-tdd"||!["passed","blocked"].includes(String(t.qaVerdict))||!["approved","changes-requested","pending"].includes(String(t.reviewVerdict))||(t.reviewVerdict==="pending"?t.reviewReceipt!==void 0:!h(t.reviewReceipt)))return;const i=v(t,["schemaVersion","storyId","epicId","branch","baseSha","headSha","idempotencyKey","dispatchId","bundleId","bundleDigest","graphRevision","claimRevision","qaVerdict","reviewVerdict","recordedAt","commits","receiptRefs"]);return i.qaReceipt=v(t.qaReceipt,["schemaVersion","kind","producer","evidenceVersion","storyId","epicId","contract","command","manifestDigest","gateIds","resultDigest","baseSha","headSha","bundleDigest","graphRevision","sourceEvidenceDigest","verdict","checkedAt","receiptRef"]),h(t.reviewReceipt)&&(i.reviewReceipt=v(t.reviewReceipt,["schemaVersion","kind","producer","storyId","epicId","baseSha","headSha","bundleDigest","graphRevision","sourceEvidenceDigest","qaReceiptRef","verdict","reviewedAt","receiptRef"])),i}function ne(r,e){const t=e.checkpoint_verification;if(!(!h(t)||t.schemaVersion!==1||t.kind!=="story_checkpoint_physical_verification"||t.producer!=="client-p205-transient-v1"||t.publicSafe!==!0||t.storyId!==r||t.epicId!==e.epic_id||!["verified","rejected"].includes(String(t.verdict))))return v(t,["schemaVersion","kind","producer","storyId","epicId","branch","baseSha","headSha","aggregateHeadSha","commitBodyDigest","changedPathsDigest","claimVerification","effectiveClaimRevision","command","manifestDigest","gateIds","resultDigest","graphRevision","executionEvidenceDigest","sourceEvidenceDigest","verifiedAt","verdict","reasonCodes","publicSafe"])}function M(r,e){const t=e.scheduling_checkpoint_evidence,i=new Set(["schemaVersion","kind","producer","storyId","epicId","branch","baseSha","headSha","graphRevision","effectiveClaimRevision","sourceEvidenceDigest","verifiedAt","reasonCodes","integrationAuthorized","publicSafe"]);if(!(!h(t)||Object.keys(t).some(c=>!i.has(c))||t.schemaVersion!==1||t.kind!=="story_scheduling_checkpoint_evidence"||t.producer!=="client-git-physical-v1"||t.publicSafe!==!0||t.integrationAuthorized!==!1||t.storyId!==r||t.epicId!==e.epic_id||!w(t.branch)||typeof t.baseSha!="string"||!/^[0-9a-f]{40,64}$/i.test(t.baseSha)||typeof t.headSha!="string"||!/^[0-9a-f]{40,64}$/i.test(t.headSha)||typeof t.graphRevision!="string"||!/^[0-9a-f]{64}$/i.test(t.graphRevision)||typeof t.effectiveClaimRevision!="string"||!/^[0-9a-f]{64}$/i.test(t.effectiveClaimRevision)||typeof t.sourceEvidenceDigest!="string"||!/^[0-9a-f]{64}$/i.test(t.sourceEvidenceDigest)||typeof t.verifiedAt!="string"||!Number.isFinite(Date.parse(t.verifiedAt))||!Array.isArray(t.reasonCodes)||t.reasonCodes.length!==1||t.reasonCodes[0]!=="checkpoint-git-scheduling-verified"))return v(t,[...i])}function oe(r,e){const t={...e},i=M(r,e);return i?(t.scheduling_checkpoint_evidence=i,delete t.checkpoint,delete t.checkpoint_verification):delete t.scheduling_checkpoint_evidence,t}function h(r){return r!==null&&typeof r=="object"&&!Array.isArray(r)}function _(...r){const e=new Set,t=[];for(const i of r)for(const c of i??[]){const n=d(c,80);if(!(!n||e.has(n))&&(e.add(n),t.push(n),t.length>=J))return t}return t}function se(r){return r.trim().replace(/^@?\*/,"").replace(/^@/,"").toLowerCase()}function ae(r){return r.trim().split(/\s+/,1)[0]??""}function z(r){if(/^@epic-P[0-9]{1,12}$/.test(r.trim()))return A.epic;const e=ae(r);if(!e)return A.menu;const t=se(e),i=te[t]??ee[t]??t;return A[i]??null}function de(r,e,t,i="full-compatible",c=["full-state"]){return{kind:"full",commandId:t?.commandId??null,stateProjectionPolicy:t?.stateProjectionPolicy??null,projectionMode:i,trigger:r,targetEpicId:null,targetStoryId:null,includedStoryCount:Object.keys(e.stories).length,includedEpicCount:Object.keys(e.epics).length,omittedStoryCount:0,omittedEpicCount:0,reason:"full-state",reasonCodes:_(c)}}function Le(r,e,t,i="full-compatible",c=["full-state"]){const n=de(r,e,t,i,c);return I({...e,scope:n},e,n)}function ue(r){const[e]=r.trim().split(/\s+/,1);return e?/^[A-Z]?\d+(?:\.\d+)+$/i.test(e.replace(/^@/,""))||/(?:^|\/)[A-Z]?\d+(?:\.\d+)+\.story\.md$/i.test(e.replace(/^@/,"")):!1}function F(r){const e=r.match(/(?:^|[/@\s])([A-Z]?\d+(?:\.\d+)+)\.story\.md\b/i);return e?.[1]?e[1]:r.match(/(?:^|\s|@)([A-Z]?\d+(?:\.\d+)+)(?=$|\s)/i)?.[1]??null}function le(r){const e=r.trim(),t=e.search(/\s/);return t===-1?"":e.slice(t).trim()}function q(r){return le(r).split(/\s+/).map(e=>e.replace(/^@/,"").replace(/^['"]|['"]$/g,"")).filter(e=>e.length>0&&!e.startsWith("-"))}function $e(r){return q(r)[0]??null}function P(r,e){const i=r.replace(/^@/,"").replace(/^epic-/i,"").replace(/\.md$/i,""),c=[i,i.toUpperCase(),/^p\d+$/i.test(i)?`P${i.replace(/^p/i,"")}`:null,/^\d+$/.test(i)?`P${i}`:null].filter(n=>typeof n=="string"&&n.length>0);for(const n of c)if(e.epics[n])return n;return null}function pe(r,e){const t=r.match(/(?:^|[/@\s])epic-(P?\d+)\.md\b/i);return t?.[1]?P(t[1],e):null}function R(r,e){const t=r.trim().match(/^@epic-(P[0-9]{1,12})$/);if(t)return P(t[1],e);const i=pe(r,e);if(i)return i;for(const c of q(r)){if(/^[A-Z]?\d+(?:\.\d+)+$/i.test(c))continue;const n=P(c,e);if(n)return n}return null}function fe(r,e){const t=R(r,e);if(t)return t;const i=e.yoloop,c=i?.state?.currentSession?.currentEpicId;if(typeof c=="string"&&e.epics[c])return c;const n=i?.lock?.currentEpicId??i?.lock?.epicId;return typeof n=="string"&&e.epics[n]?n:null}function ye(r){const e=r.match(/(?:^|[/@\s])epic-(P?\d+)\.md\b/i)?.[1];if(e)return/^P/i.test(e)?e.toUpperCase():`P${e}`;for(const t of q(r)){if(/^P\d+$/i.test(t))return t.toUpperCase();if(/^\d+$/.test(t))return`P${t}`}return null}function j(r,e){if(typeof r.epic_id=="string"&&r.epic_id.length>0)return r.epic_id;const t=e.split(".").slice(0,-1).join(".");return t.length>0?t:null}function L(r){return typeof r=="string"&&["done","completed","merged","cancelled","canceled","abandoned"].includes(r.toLowerCase())}function x(r,e,t){if(t.has(r))return;const i=e.stories[r];if(!i)return;t.add(r);const c=i.depends_on;if(Array.isArray(c))for(const n of c)typeof n=="string"&&x(n,e,t)}function me(r,e){const t=C(e.stories,[r]),i={};for(const c of t.orderedIds){const n=e.stories[c];n&&(i[c]=n)}return i}function $(r,e,t=[]){const i={};for(const c of t)e.epics[c]&&(i[c]=e.epics[c]);for(const[c,n]of Object.entries(r)){const s=j(n,c);s&&e.epics[s]&&(i[s]=e.epics[s])}return i}function ge(r,e,t){if(t.has(r))return;const i=e.epics[r];if(!i)return;t.add(r);const c=i.depends_on;if(Array.isArray(c))for(const n of c)typeof n=="string"&&n.length>0&&ge(n,e,t)}function V(r,e,t){const i=C(t.epics,[r]),c=new Set(i.orderedIds);for(const[s,a]of Object.entries(e)){const u=j(a,s);u&&t.epics[u]&&c.add(u)}const n={};for(const s of[...c].sort((a,u)=>a.localeCompare(u,"en"))){const a=t.epics[s];a&&(n[s]=s===r?a:H(s,a))}return n}function G(r,e,t){const i=e.stories;if(!Array.isArray(i)||i.some(s=>typeof s!="string"||s.length===0))throw new y("STRUCTURAL_DEPENDENCY_MISSING",{nodes:0,edges:0,malformedStoryMemberships:1});const c=C(t.stories,i),n={};for(const s of c.orderedIds){const a=t.stories[s];a&&(n[s]=j(a,s)===r?oe(s,a):Y(s,a))}return n}function he(r,e,t){const i=[...e.stories].sort((s,a)=>s.localeCompare(a,"en")),c=Object.entries(t).filter(([s,a])=>j(a,s)===r).map(([s])=>s).sort((s,a)=>s.localeCompare(a,"en")),n=B("sha256").update(`target-epic-coverage-v1\0${JSON.stringify({targetEpicId:r,declaredStoryIds:i,includedStoryIds:c})}`).digest("hex");return{schemaVersion:"TargetEpicCoverage/1.0",targetEpicId:r,declaredStoryIds:i,includedStoryIds:c,membershipSha256:n,publicSafe:!0}}function Y(r,e){const t=Array.isArray(e.depends_on)?[...new Set(e.depends_on.filter(m=>typeof m=="string"&&m.length>0))].sort((m,E)=>m.localeCompare(E,"en")):[],i={id:d(e.id)??r,...d(e.epic_id)?{epic_id:d(e.epic_id)}:{},...d(e.status,40)?{status:d(e.status,40)}:{},depends_on:t},c=M(r,e);if(!ie(e.status))return{...i,...c?{scheduling_checkpoint_evidence:c}:{}};const n=e.source==="create-epic"||e.source==="discovered"?e.source:void 0,s=w(e.branch_name),a=T(e.last_step,120),u=Array.isArray(e.steps_completed)&&e.steps_completed.length<=64?e.steps_completed.map(m=>T(m,120)):[],l=u.length>0&&u.every(m=>m!==void 0)?u:void 0,f=typeof e.pr_number=="number"&&Number.isSafeInteger(e.pr_number)&&e.pr_number>0?e.pr_number:void 0,p=ce(r,e),g=p?ne(r,e):void 0;return{...i,...n?{source:n}:{},...s?{branch_name:s}:{},...a?{last_step:a}:{},...l?{steps_completed:l}:{},...f?{pr_number:f}:{},...p?{checkpoint:p}:{},...g?{checkpoint_verification:g}:{},...c?{scheduling_checkpoint_evidence:c}:{},...S(e.files_to_modify)!==void 0?{files_to_modify:S(e.files_to_modify)}:{},...S(e.contracts)!==void 0?{contracts:S(e.contracts)}:{},...S(e.contract_refs)!==void 0?{contract_refs:S(e.contract_refs)}:{},...S(e.shared_surfaces)!==void 0?{shared_surfaces:S(e.shared_surfaces)}:{}}}function H(r,e){const t=Array.isArray(e.stories)?[...new Set(e.stories.filter(c=>typeof c=="string"&&c.length>0))].sort((c,n)=>c.localeCompare(n,"en")):[],i=Array.isArray(e.depends_on)?[...new Set(e.depends_on.filter(c=>typeof c=="string"&&c.length>0))].sort((c,n)=>c.localeCompare(n,"en")):[];return{id:d(e.id)??r,...d(e.status,40)?{status:d(e.status,40)}:{},...d(e.lifecycle_classification,40)?{lifecycle_classification:d(e.lifecycle_classification,40)}:{},stories:t,depends_on:i}}function be(r,e,t){const i=C(e.stories),c=C(e.epics),n=Object.fromEntries(i.orderedIds.map(u=>[u,Y(u,e.stories[u])])),s=Object.fromEntries(c.orderedIds.map(u=>[u,H(u,e.epics[u])])),a={kind:"projected",commandId:t.commandId,stateProjectionPolicy:t.stateProjectionPolicy,projectionMode:"yoloop-discovery",trigger:r,targetEpicId:null,targetStoryId:null,includedStoryCount:i.orderedIds.length,includedEpicCount:c.orderedIds.length,omittedStoryCount:0,omittedEpicCount:0,reason:"targeted-invocation",reasonCodes:_(["structural-required","yoloop-discovery",`structural-edges-${i.edgeCount+c.edgeCount}`,"content-fields-omitted"])};return I({...e,stories:n,epics:s,scope:a},e,a)}function _e(r,e){const t=new Set,i=r.stories;if(Array.isArray(i))for(const n of i)typeof n=="string"&&x(n,e,t);const c={};for(const n of t){const s=e.stories[n];s&&(c[n]=s)}return c}function Se(r){const e={};for(const[t,i]of Object.entries(r.epics))e[t]={id:d(i.id)??t,...d(i.status)?{status:d(i.status)}:{},...k.includes(i.lifecycle_classification)?{lifecycle_classification:i.lifecycle_classification}:{},...typeof i.total_stories=="number"&&Number.isFinite(i.total_stories)?{total_stories:i.total_stories}:{},...typeof i.completed_stories=="number"&&Number.isFinite(i.completed_stories)?{completed_stories:i.completed_stories}:{}};return e}function K(r){const e={};for(const t of Object.values(r)){const i=d(t.status,40)??"unknown";e[i]=(e[i]??0)+1}return e}function je(r){const e=Object.fromEntries(k.map(t=>[t,0]));for(const t of Object.values(r)){const i=k.includes(t.lifecycle_classification)?t.lifecycle_classification:"active";e[i]=(e[i]??0)+1}return e}function N(r,e){if(!e)return!0;const t=r.epics[e];return t?!k.includes(t.lifecycle_classification)||t.lifecycle_classification==="active":!0}function Z(r){for(const e of["last_updated","updated_at","completed_at","created_at","discovered_at"]){const t=r[e];if(typeof t!="string")continue;const i=Date.parse(t);if(Number.isFinite(i))return i}return 0}function Ie(r){return Object.entries(r.stories).map(([e,t])=>({id:e,story:t,timestamp:Z(t)})).sort((e,t)=>t.timestamp-e.timestamp||e.id.localeCompare(t.id)).slice(0,U).map(({id:e,story:t})=>({id:e,...d(t.epic_id)?{epicId:d(t.epic_id)}:{},...d(t.status,40)?{status:d(t.status,40)}:{},...d(t.last_step??t.lastStep)?{lastStep:d(t.last_step??t.lastStep)}:{},...d(t.last_updated??t.updated_at??t.completed_at??t.created_at)?{lastUpdated:d(t.last_updated??t.updated_at??t.completed_at??t.created_at)}:{}}))}function Ce(r){const e=r.current_session;if(!e)return;const t={activeEpicId:d(e.active_epic_id)??null,activeStoryId:d(e.active_story_id)??null,activeStepId:d(e.active_step_id)??null,sessionId:d(e.session_id)??null,startedAt:d(e.started_at)??null};return Object.values(t).some(i=>i!=null)?t:void 0}function ke(r){const e=r.yoloop;if(!h(e))return;const t=h(e.state)?e.state:void 0,i=h(t?.currentSession)?t.currentSession:void 0,c=h(e.lock)?e.lock:void 0,n={...typeof e.active=="boolean"?{active:e.active}:{},currentEpicId:d(i?.currentEpicId??e.currentEpicId)??null,currentStoryId:d(i?.currentStoryId??e.currentStoryId)??null,sessionId:d(i?.sessionId??e.sessionId)??null,lockEpicId:d(c?.currentEpicId??c?.epicId)??null};return Object.keys(n).length>0?n:void 0}function ve(r){const e=r.continuity;if(!h(e))return;const t=Array.isArray(e.reasonCodes)?e.reasonCodes.filter(i=>typeof i=="string"):void 0;return{present:!0,activeJobId:d(e.activeJobId??e.jobId)??null,activeGoalId:d(e.activeGoalId??e.goalId)??null,activeLoopId:d(e.activeLoopId??e.loopId)??null,...t&&t.length>0?{reasonCodes:_(t)}:{}}}function Ee(r,e,t){const i=d(e?.activeStoryId),c=d(e?.activeEpicId),n=d(e?.activeStepId),s=i&&r.stories[i]?j(r.stories[i],i):null;if((i||c||n)&&N(r,c??s))return{epicId:c??null,storyId:i??null,stepId:n??null};const a=d(t?.currentStoryId),u=d(t?.currentEpicId??t?.lockEpicId);if((a||u)&&N(r,u))return{epicId:u??null,storyId:a??null,stepId:null};const l=Object.entries(r.stories).map(([f,p])=>({id:f,story:p,timestamp:Z(p)})).filter(({id:f,story:p})=>!L(p.status)&&N(r,j(p,f))).sort((f,p)=>p.timestamp-f.timestamp||f.id.localeCompare(p.id))[0];return l?{epicId:j(l.story,l.id),storyId:l.id,stepId:d(l.story.last_step??l.story.lastStep)??null}:{epicId:null,storyId:null,stepId:null}}function Re(r,e){const t=K(r.stories),i=K(r.epics),c=je(r.epics),n=Object.values(r.epics).filter(g=>(k.includes(g.lifecycle_classification)?g.lifecycle_classification:"active")==="active"&&!L(g.status)).length,s=Ce(r),a=ke(r),u=ve(r),l=Ee(r,s,a),f=Ie(r),p=_(e.reasonCodes,["state-summary-attached","state-summary-bounded",`projection-${e.projectionMode??e.kind}`,e.stateProjectionPolicy?`policy-${e.stateProjectionPolicy}`:"policy-unknown",f.length>=U?"recent-stories-capped":"recent-stories-bounded",l.storyId||l.epicId?"active-ref-derived":"active-ref-empty",a?"yoloop-session-present":"yoloop-session-absent",u?"continuity-session-present":"continuity-session-absent"]);return{schemaVersion:1,totals:{stories:Object.keys(r.stories).length,epics:Object.keys(r.epics).length,storyStatus:t,epicStatus:i,epicLifecycle:c,activeEpics:n,blockedStories:t.blocked??0},active:l,blockedCount:t.blocked??0,recentStories:f,...s?{currentSession:s}:{},...a?{currentYoloopSession:a}:{},...u?{currentContinuitySession:u}:{},projection:{commandId:e.commandId??null,stateProjectionPolicy:e.stateProjectionPolicy??null,projectionMode:e.projectionMode,scopeKind:e.kind,includedStoryCount:e.includedStoryCount,includedEpicCount:e.includedEpicCount??Object.keys(r.epics).length,omittedStoryCount:e.omittedStoryCount,omittedEpicCount:e.omittedEpicCount,reason:e.reason},reasonCodes:p,publicSafe:!0}}function I(r,e,t){return{...r,stateSummary:Re(e,t)}}function Oe(r,e,t){const i={};for(const n of Object.keys(e.epics))i[n]={id:n};const c={kind:"projected",commandId:t.commandId,stateProjectionPolicy:t.stateProjectionPolicy,projectionMode:"summary-only",trigger:r,targetEpicId:null,targetStoryId:null,includedStoryCount:0,includedEpicCount:Object.keys(i).length,omittedStoryCount:Object.keys(e.stories).length,omittedEpicCount:0,reason:"epic-summary",reasonCodes:["epic-summary","stories-omitted","epic-stubs-only"]};return I({...e,stories:{},epics:i,scope:c},e,c)}function b(r,e,t,i=["summary-only","stories-omitted"],c="summary-only"){const n=Se(e),s={kind:"projected",commandId:t.commandId,stateProjectionPolicy:t.stateProjectionPolicy,projectionMode:c,trigger:r,targetEpicId:null,targetStoryId:null,includedStoryCount:0,includedEpicCount:Object.keys(n).length,omittedStoryCount:Object.keys(e.stories).length,omittedEpicCount:Math.max(0,Object.keys(e.epics).length-Object.keys(n).length),reason:"summary-only",reasonCodes:_(i)};return I({...e,stories:{},epics:n,scope:s},e,s)}function D(r,e,t,i,c,n){const s=e.stories[i];if(!s)throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"story"});const a=j(s,i);if(!a)throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"});const u=e.epics[a];if(!u)throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"});const l=c==="yolo-story",f=l?G(a,u,e):me(i,e),p=l?V(a,f,e):$(f,e);if(!f[i]||!p[a])throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(f).length,epics:Object.keys(p).length,targetKind:"story"});const g={kind:"projected",commandId:t.commandId,stateProjectionPolicy:t.stateProjectionPolicy,projectionMode:c,trigger:r,targetEpicId:a,targetStoryId:i,includedStoryCount:Object.keys(f).length,includedEpicCount:Object.keys(p).length,omittedStoryCount:Math.max(0,Object.keys(e.stories).length-Object.keys(f).length),omittedEpicCount:Math.max(0,Object.keys(e.epics).length-Object.keys(p).length),reason:"targeted-invocation",reasonCodes:_(n,l?["epic-graph-authority-complete"]:[])};return I({...e,stories:f,epics:p,scope:g},e,g)}function W(r,e,t,i,c,n){const s=e.epics[i];if(!s)throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"});const a=_e(s,e),u=$(a,e,[i]);if(!u[i])throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(a).length,epics:Object.keys(u).length,targetKind:"epic"});const l={kind:"projected",commandId:t.commandId,stateProjectionPolicy:t.stateProjectionPolicy,projectionMode:c,trigger:r,targetEpicId:i,targetStoryId:null,includedStoryCount:Object.keys(a).length,includedEpicCount:Object.keys(u).length,omittedStoryCount:Math.max(0,Object.keys(e.stories).length-Object.keys(a).length),omittedEpicCount:Math.max(0,Object.keys(e.epics).length-Object.keys(u).length),reason:"targeted-invocation",reasonCodes:_(n)};return I({...e,stories:a,epics:u,scope:l},e,l)}function Ae(r,e,t){const i=ye(r),c=R(r,e);if(i&&!c)throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"});const n=fe(r,e),s=O({commandId:t.commandId,explicitYoloopEpicId:c,sessionYoloopEpicId:c?null:n});if(s==="yoloop-discovery")return be(r,e,t);if(!n||s!=="yoloop-target"&&s!=="yoloop-session")throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"});const a=e.epics[n];if(!a)throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"});const u=G(n,a,e),l=V(n,u,e);if(!l[n])throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(u).length,epics:Object.keys(l).length,targetKind:"epic"});const f=s,p={kind:"projected",commandId:t.commandId,stateProjectionPolicy:t.stateProjectionPolicy,projectionMode:f,trigger:r,targetEpicId:n,targetStoryId:null,targetEpicCoverage:he(n,a,u),includedStoryCount:Object.keys(u).length,includedEpicCount:Object.keys(l).length,omittedStoryCount:Math.max(0,Object.keys(e.stories).length-Object.keys(u).length),omittedEpicCount:Math.max(0,Object.keys(e.epics).length-Object.keys(l).length),reason:"targeted-invocation",reasonCodes:["structural-required",f,"yoloop-targeted"]};return I({...e,stories:u,epics:l,scope:p},e,p)}function Te(r,e){const t={};for(const[i,c]of Object.entries(r.epics)){const n=Array.isArray(c.stories)?c.stories.filter(s=>typeof s=="string"&&e.has(s)):[];t[i]={id:d(c.id)??i,...d(c.status,40)?{status:d(c.status,40)}:{},...typeof c.total_stories=="number"&&Number.isFinite(c.total_stories)?{total_stories:c.total_stories}:{},...typeof c.completed_stories=="number"&&Number.isFinite(c.completed_stories)?{completed_stories:c.completed_stories}:{},...n.length>0?{stories:n}:{},...n.length>0&&Array.isArray(c.depends_on)?{depends_on:c.depends_on.filter(s=>typeof s=="string"&&s.length>0)}:{},...n.length>0&&(c.branch_mode==="epic"||c.branch_mode==="story")?{branch_mode:c.branch_mode}:{},...n.length>0&&typeof c.execution_branch=="string"?{execution_branch:c.execution_branch}:{},...n.length>0&&typeof c.origin_branch=="string"?{origin_branch:c.origin_branch}:{},...n.length>0&&(c.branch_lease===null||typeof c.branch_lease=="object")?{branch_lease:c.branch_lease}:{},...n.length>0&&(c.origin_binding===null||typeof c.origin_binding=="object")?{origin_binding:c.origin_binding}:{},...n.length>0&&(c.aggregate_qa_receipt===null||typeof c.aggregate_qa_receipt=="object")?{aggregate_qa_receipt:c.aggregate_qa_receipt}:{},...n.length>0&&(c.head_reconciliation_receipt===null||typeof c.head_reconciliation_receipt=="object")?{head_reconciliation_receipt:c.head_reconciliation_receipt}:{}}}return t}function we(r){return r.stateSummary?.totals.stories??(r.scope?.includedStoryCount??Object.keys(r.stories).length)+(r.scope?.omittedStoryCount??0)}function qe(r){return r.stateSummary?.totals.epics??(r.scope?.includedEpicCount??Object.keys(r.epics).length)+(r.scope?.omittedEpicCount??0)}function Pe(r,e){if(r.stateSummary)return{...r.stateSummary,projection:{...r.stateSummary.projection,scopeKind:"projected",projectionMode:e.projectionMode,includedStoryCount:e.includedStoryCount,includedEpicCount:e.includedEpicCount??r.stateSummary.projection.includedEpicCount,omittedStoryCount:e.omittedStoryCount,omittedEpicCount:e.omittedEpicCount,reason:"body-size"},reasonCodes:_(r.stateSummary.reasonCodes,["payload-size-guardrail","state-summary-preserved","nonessential-state-degraded"])}}function Ve(r){const e=r.scope,t=new Set,i=e?.projectionMode==="structural-required"||e?.projectionMode==="yolo-story"||e?.projectionMode==="yoloop-target"||e?.projectionMode==="yoloop-session"||e?.projectionMode==="yoloop-discovery";if(i)for(const m of Object.keys(r.stories))t.add(m);else e?.targetStoryId&&x(e.targetStoryId,r,t);const c={};for(const m of t){const E=r.stories[m];E&&(c[m]=E)}const n=Te(r,t),s=Object.keys(c).length,a=Object.keys(n).length,u=Math.max(0,we(r)-s),l=Math.max(0,qe(r)-a),f=i?e?.projectionMode??"structural-required":e?.projectionMode==="yolo-story"?"yolo-story":"summary-only",p={kind:"projected",commandId:e?.commandId??null,stateProjectionPolicy:e?.stateProjectionPolicy??null,projectionMode:f,targetEpicId:e?.targetEpicId??null,targetStoryId:e?.targetStoryId??null,...e?.targetEpicCoverage?{targetEpicCoverage:e.targetEpicCoverage}:{},includedStoryCount:s,includedEpicCount:a,omittedStoryCount:u,omittedEpicCount:l,reason:"body-size",reasonCodes:_(e?.reasonCodes,["payload-size-guardrail",t.size>0?"structural-targets-preserved":"stories-omitted","epics-stubbed","state-summary-preserved","redundant-trigger-omitted"])},g=Pe(r,p);return{...r,stories:c,epics:n,scope:p,...g?{stateSummary:g}:{}}}function xe(r,e){const t=r.trim(),i=z(t);try{if(!i){if(ue(t)){const n=o("story-reference","story-targeted"),s=F(t);if(s)return D(t,e,n,s,"targeted-story",["story-reference-targeted"])}return b(t,e,o("unknown","adaptive-targeted"),["unknown-command-summary-only"])}if(i.stateProjectionPolicy==="epic-summary")return Oe(t,e,i);if(i.stateProjectionPolicy==="yoloop-targeted")return Ae(t,e,i);const c=F(t);if(i.stateProjectionPolicy==="story-targeted"){if(c){const s=O({commandId:i.commandId,targetStoryId:c})==="yolo-story";return D(t,e,i,c,s?"yolo-story":i.structuralRequired?"structural-required":"targeted-story",[s?"yolo-story":i.structuralRequired?"structural-required":"targeted-story"])}if(i.commandId==="yolo"||i.commandId==="yolo-inline"){const n=O({commandId:i.commandId});return b(t,e,i,["yolo-inline","stories-omitted","historical-content-omitted"],n??"yolo-inline")}return i.commandId==="commit"&&/^\*?(?:commit|commit-push)$/i.test(t)?b(t,e,i,["working-tree-commit","stories-omitted","historical-content-omitted"]):i.structuralRequired?(()=>{throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"story"})})():b(t,e,i,["story-target-missing-summary-only"])}if(i.stateProjectionPolicy==="adaptive-targeted"){if(c&&e.stories[c])return D(t,e,i,c,"targeted-story",["adaptive-story-targeted"]);const n=R(t,e);return n?W(t,e,i,n,"targeted-epic",["adaptive-epic-targeted"]):b(t,e,i,["adaptive-summary-only","target-unresolved-summary-only"])}if(i.stateProjectionPolicy==="epic-targeted"){if(i.commandId.startsWith("arch-")&&/(?:^|\s)epic-arch\s*$/i.test(t)&&e.archPlan?.execution?.currentStageCommand===i.commandId)return b(t,e,i,["architecture-root-delegated"]);const n=R(t,e);return n?W(t,e,i,n,i.structuralRequired?"structural-required":"targeted-epic",[i.structuralRequired?"structural-required":"targeted-epic"]):i.structuralRequired?(()=>{throw new y("STRUCTURAL_TARGET_NOT_FOUND",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,targetKind:"epic"})})():b(t,e,i,["epic-target-missing-summary-only"])}return i.stateProjectionPolicy==="continuity-scoped"?b(t,e,i,["continuity-scoped-summary-only"]):b(t,e,i,["policy-full-summary-only"])}catch(c){if(c instanceof y)throw c;if(i?.structuralRequired)throw new y("STRUCTURAL_DEPENDENCY_MISSING",{stories:Object.keys(e.stories).length,epics:Object.keys(e.epics).length,projectionErrors:1});return b(t,e,i??o("unknown","adaptive-targeted"),["projection-error-summary-only"])}}const Ne=new Set(["yolo-story","yolo-inline","yoloop-target","yoloop-session","yoloop-discovery"]);function De(r){let e=0;for(const t of[r.stories,r.epics])for(const i of Object.values(t))Array.isArray(i.depends_on)&&(e+=i.depends_on.filter(c=>typeof c=="string").length);return e}function Ge(r,e){const t=z(r.trim());if(!t||!["yolo","yolo-inline","yoloop"].includes(t.commandId))return null;try{const i=xe(r,e),c=i.scope?.projectionMode;if(!c||!Ne.has(c))throw new y("STRUCTURAL_DEPENDENCY_MISSING",{stories:Object.keys(i.stories).length,epics:Object.keys(i.epics).length,projectionShapeErrors:1});return Object.freeze({ok:!0,version:2,shape:c,snapshot:i,included:{epics:i.scope?.includedEpicCount??Object.keys(i.epics).length,stories:i.scope?.includedStoryCount??Object.keys(i.stories).length,edges:De(i)},omitted:{epics:i.scope?.omittedEpicCount??0,stories:i.scope?.omittedStoryCount??0},cycleCount:0})}catch(i){if(!(i instanceof y))throw i;return Object.freeze({ok:!1,code:i.code,publicDetails:{...i.publicDetails,...i.code==="STRUCTURAL_CONTEXT_TOO_LARGE"?{}:{planningCause:Q(i.code)}}})}}export{Ve as degradeStateSnapshotForPayloadLimit,Q as planningProjectionCauseForStructuralCode,Fe as projectEpicOperationalEvidenceForRequest,xe as projectStateSnapshotForInvoke,Ge as projectStateSnapshotResultV2ForInvoke};