@ornexus/neocortex 4.60.71 → 4.60.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/dist/release-source.json +1 -1
  2. package/dist/sbom.cdx.json +1211 -1217
  3. package/install.ps1 +1 -1
  4. package/install.sh +1 -1
  5. package/package.json +2 -2
  6. package/packages/client/dist/adapters/adapter-registry.js +108 -1
  7. package/packages/client/dist/adapters/antigravity-adapter.js +77 -2
  8. package/packages/client/dist/adapters/claude-code-adapter.js +79 -3
  9. package/packages/client/dist/adapters/codex-adapter.js +80 -2
  10. package/packages/client/dist/adapters/cursor-adapter.js +115 -4
  11. package/packages/client/dist/adapters/gemini-adapter.js +71 -2
  12. package/packages/client/dist/adapters/grok-adapter.js +42 -2
  13. package/packages/client/dist/adapters/index.js +22 -1
  14. package/packages/client/dist/adapters/platform-detector.js +212 -1
  15. package/packages/client/dist/adapters/target-adapter.js +12 -0
  16. package/packages/client/dist/adapters/vscode-adapter.js +72 -2
  17. package/packages/client/dist/agent/refresh-stubs.js +417 -2
  18. package/packages/client/dist/agent/update-agent-yaml.js +102 -1
  19. package/packages/client/dist/agent/update-description.js +251 -1
  20. package/packages/client/dist/cache/crypto-utils.js +78 -1
  21. package/packages/client/dist/cache/encrypted-cache.js +108 -1
  22. package/packages/client/dist/cache/in-memory-asset-cache.js +73 -1
  23. package/packages/client/dist/cache/index.js +13 -1
  24. package/packages/client/dist/cache/protected-pi-boundary.js +44 -1
  25. package/packages/client/dist/checkpoint/checkpoint-client-reader.js +127 -2
  26. package/packages/client/dist/checkpoint/index.js +11 -1
  27. package/packages/client/dist/checkpoint/shared-checkpoint-types.js +32 -1
  28. package/packages/client/dist/cli.js +358 -5
  29. package/packages/client/dist/commands/activate.js +394 -8
  30. package/packages/client/dist/commands/architecture-answers.js +274 -7
  31. package/packages/client/dist/commands/architecture-memory-terminal.js +253 -4
  32. package/packages/client/dist/commands/architecture-non-ui-continuation.js +100 -1
  33. package/packages/client/dist/commands/architecture-root-binding.js +51 -1
  34. package/packages/client/dist/commands/cache-status.js +112 -2
  35. package/packages/client/dist/commands/config.js +88 -1
  36. package/packages/client/dist/commands/doctor.js +635 -2
  37. package/packages/client/dist/commands/invoke.js +7200 -143
  38. package/packages/client/dist/commands/legacy-epic-terminal.js +71 -1
  39. package/packages/client/dist/commands/legacy-story-branch.js +96 -1
  40. package/packages/client/dist/commands/legacy-story-pr.js +276 -1
  41. package/packages/client/dist/commands/mutation-qa-checkpoint.js +285 -5
  42. package/packages/client/dist/commands/mutation-qa-gate.js +54 -1
  43. package/packages/client/dist/commands/mutation-qa-git.js +41 -1
  44. package/packages/client/dist/commands/mutation-qa-policy.js +102 -1
  45. package/packages/client/dist/commands/mutation-qa-run.js +219 -3
  46. package/packages/client/dist/commands/mutation-qa-verdict.js +149 -1
  47. package/packages/client/dist/commands/mutation-qa.js +220 -1
  48. package/packages/client/dist/commands/native-agent.js +136 -2
  49. package/packages/client/dist/commands/planning-diagnosis.js +43 -1
  50. package/packages/client/dist/commands/planning-generation.js +53 -1
  51. package/packages/client/dist/commands/planning-memory.js +40 -1
  52. package/packages/client/dist/commands/planning-research.js +42 -1
  53. package/packages/client/dist/commands/private-session.js +75 -1
  54. package/packages/client/dist/commands/property-qa.js +139 -1
  55. package/packages/client/dist/commands/qa-control.js +16 -1
  56. package/packages/client/dist/commands/qa-scan-browser-launch.js +55 -1
  57. package/packages/client/dist/commands/qa-scan-browser-route.js +28 -1
  58. package/packages/client/dist/commands/qa-scan-capture.js +663 -5
  59. package/packages/client/dist/commands/qa-scan-discovery.js +376 -3
  60. package/packages/client/dist/commands/qa-scan-review.js +826 -5
  61. package/packages/client/dist/commands/qa-synthetic-backend-capture.js +266 -1
  62. package/packages/client/dist/commands/qa-synthetic-backend-review.js +297 -1
  63. package/packages/client/dist/commands/qa-synthetic-backend.js +340 -2
  64. package/packages/client/dist/commands/qa-synthetic-broker-port.js +85 -1
  65. package/packages/client/dist/commands/qa-synthetic-browser.js +39 -1
  66. package/packages/client/dist/commands/refactor-characterization.js +671 -21
  67. package/packages/client/dist/commands/refactor-commit.js +399 -13
  68. package/packages/client/dist/commands/refactor-control.js +142 -3
  69. package/packages/client/dist/commands/refactor-cpp-assertions.js +93 -3
  70. package/packages/client/dist/commands/refactor-review.js +283 -5
  71. package/packages/client/dist/commands/refactor-root.js +588 -7
  72. package/packages/client/dist/commands/refresh-memory.js +156 -3
  73. package/packages/client/dist/commands/shared-architecture-non-ui.js +24 -1
  74. package/packages/client/dist/commands/story-checkpoint.js +171 -1
  75. package/packages/client/dist/config/profile-directory.js +13 -1
  76. package/packages/client/dist/config/resolver-selection.js +278 -1
  77. package/packages/client/dist/config/secure-config.js +281 -12
  78. package/packages/client/dist/config.js +223 -2
  79. package/packages/client/dist/constants.js +25 -1
  80. package/packages/client/dist/context/context-collector.js +222 -2
  81. package/packages/client/dist/context/context-sanitizer.js +145 -1
  82. package/packages/client/dist/continuity/autonomous-governance.js +285 -1
  83. package/packages/client/dist/continuity/continuity-client-state-store.js +1587 -1
  84. package/packages/client/dist/continuity/invoke-hooks.js +129 -1
  85. package/packages/client/dist/continuity/migrations/001-initial-schema.js +12 -2
  86. package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.js +12 -2
  87. package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.js +12 -2
  88. package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.js +12 -2
  89. package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.js +12 -2
  90. package/packages/client/dist/continuity/migrations/006-native-agent-dispatches.js +10 -2
  91. package/packages/client/dist/continuity/native-agent-store.js +69 -1
  92. package/packages/client/dist/continuity/native-agent-types.js +90 -1
  93. package/packages/client/dist/continuity/outbox.js +117 -1
  94. package/packages/client/dist/continuity/runner-bootstrap-policy.js +172 -1
  95. package/packages/client/dist/continuity/sqlite-store.d.ts +22 -1
  96. package/packages/client/dist/continuity/sqlite-store.js +2612 -81
  97. package/packages/client/dist/effects/invoke-effect-gateways.js +62 -1
  98. package/packages/client/dist/errors/error-messages.js +228 -2
  99. package/packages/client/dist/errors/frontmatter-diagnostics.js +125 -1
  100. package/packages/client/dist/evidence/collector.js +347 -1
  101. package/packages/client/dist/evidence/index.js +1 -1
  102. package/packages/client/dist/evidence/types.js +2 -0
  103. package/packages/client/dist/fs/atomic-state-replace.js +152 -1
  104. package/packages/client/dist/generated/command-registry.generated.js +4076 -1
  105. package/packages/client/dist/generated/public-projections.generated.js +149 -1
  106. package/packages/client/dist/git/direct-yolo-c01-retry.js +138 -4
  107. package/packages/client/dist/git/direct-yolo-checkpoint.js +1234 -4
  108. package/packages/client/dist/git/epic-operational-state.d.ts +198 -0
  109. package/packages/client/dist/git/epic-operational-state.js +672 -0
  110. package/packages/client/dist/git/git-lifecycle-step-ids.js +14 -1
  111. package/packages/client/dist/git/git-lifecycle-store.d.ts +9 -1
  112. package/packages/client/dist/git/git-lifecycle-store.js +1981 -9
  113. package/packages/client/dist/git/legacy-story-branch-checkpoint.js +259 -9
  114. package/packages/client/dist/git/legacy-story-branch-setup.js +348 -4
  115. package/packages/client/dist/git/legacy-story-pr.js +3538 -70
  116. package/packages/client/dist/git/secure-filesystem-boundary.js +182 -5
  117. package/packages/client/dist/graph-retrieval/pre-command-hook.js +284 -1
  118. package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +237 -1
  119. package/packages/client/dist/i18n/first-run.js +60 -2
  120. package/packages/client/dist/index.js +47 -1
  121. package/packages/client/dist/invocation/invoke-input.js +24 -1
  122. package/packages/client/dist/license/index.js +5 -1
  123. package/packages/client/dist/license/license-client.js +304 -1
  124. package/packages/client/dist/machine/fingerprint.js +163 -2
  125. package/packages/client/dist/machine/index.js +5 -1
  126. package/packages/client/dist/memory/project-memory-path-scope.js +62 -1
  127. package/packages/client/dist/memory/project-memory-writer.js +1007 -40
  128. package/packages/client/dist/memory/shared-project-memory-types.js +253 -2
  129. package/packages/client/dist/migrations/epic-lifecycle-backfill.d.ts +97 -0
  130. package/packages/client/dist/migrations/epic-lifecycle-backfill.js +1060 -0
  131. package/packages/client/dist/migrations/project-identity-capability.js +50 -1
  132. package/packages/client/dist/migrations/project-identity.js +493 -7
  133. package/packages/client/dist/migrations/state-json.d.ts +22 -0
  134. package/packages/client/dist/migrations/state-json.js +393 -4
  135. package/packages/client/dist/policy/architecture-policy.js +184 -2
  136. package/packages/client/dist/policy/index.js +7 -1
  137. package/packages/client/dist/policy/shared-policy-types.js +38 -0
  138. package/packages/client/dist/policy/subagent-approval-policy.js +55 -1
  139. package/packages/client/dist/private-execution/clean-baseline.js +279 -2
  140. package/packages/client/dist/private-execution/codex-executor.js +574 -4
  141. package/packages/client/dist/private-execution/codex-host-runtime.js +137 -1
  142. package/packages/client/dist/private-execution/codex-lifecycle-guard.js +97 -1
  143. package/packages/client/dist/private-execution/codex-scoped-permissions.js +128 -1
  144. package/packages/client/dist/private-execution/delivery.js +410 -13
  145. package/packages/client/dist/private-execution/diagnosis-root-review.js +294 -2
  146. package/packages/client/dist/private-execution/frozen-handoff.js +19 -6
  147. package/packages/client/dist/private-execution/implementation-validation.js +106 -2
  148. package/packages/client/dist/private-execution/isolated-admission.js +1432 -23
  149. package/packages/client/dist/private-execution/isolated-session.js +725 -5
  150. package/packages/client/dist/private-execution/isolated-workspace.js +122 -1
  151. package/packages/client/dist/private-execution/pact-consumer-runtime.js +409 -3
  152. package/packages/client/dist/private-execution/pact-test-source.js +258 -1
  153. package/packages/client/dist/private-execution/pact-toolchain.js +290 -3
  154. package/packages/client/dist/private-execution/pact-write-set.js +172 -1
  155. package/packages/client/dist/private-execution/planning-diagnosis-checkpoint.js +406 -5
  156. package/packages/client/dist/private-execution/planning-generation-checkpoint.js +462 -5
  157. package/packages/client/dist/private-execution/planning-memory-checkpoint.js +139 -3
  158. package/packages/client/dist/private-execution/planning-research-checkpoint.js +325 -4
  159. package/packages/client/dist/private-execution/private-report-store.js +42 -1
  160. package/packages/client/dist/private-execution/property-test-candidate.js +103 -1
  161. package/packages/client/dist/private-execution/property-test-choices.js +147 -3
  162. package/packages/client/dist/private-execution/property-test-plan.js +271 -7
  163. package/packages/client/dist/private-execution/property-test-review.js +258 -4
  164. package/packages/client/dist/private-execution/property-test-runtime.js +372 -9
  165. package/packages/client/dist/private-execution/property-test-source.js +139 -1
  166. package/packages/client/dist/private-execution/root-checkpoint.js +80 -1
  167. package/packages/client/dist/private-execution/root-memory-git-evidence.js +135 -3
  168. package/packages/client/dist/private-execution/root-memory-recovery.js +93 -1
  169. package/packages/client/dist/private-execution/root-memory-request.js +29 -1
  170. package/packages/client/dist/private-execution/root-memory-scope.js +178 -1
  171. package/packages/client/dist/private-execution/root-memory-writer.js +102 -1
  172. package/packages/client/dist/private-execution/session-lease.js +63 -1
  173. package/packages/client/dist/private-execution/shared-private-admission-types.js +50 -1
  174. package/packages/client/dist/private-execution/shared-project-validation.js +66 -1
  175. package/packages/client/dist/private-execution/shared-root-memory-types.js +61 -1
  176. package/packages/client/dist/private-execution/ux-source-validation.js +372 -1
  177. package/packages/client/dist/private-execution/ux-write-set.js +191 -2
  178. package/packages/client/dist/registry/registry-reconciliation.js +234 -1
  179. package/packages/client/dist/resilience/circuit-breaker.js +170 -1
  180. package/packages/client/dist/resilience/degradation-manager.js +164 -1
  181. package/packages/client/dist/resilience/freshness-indicator.js +100 -1
  182. package/packages/client/dist/resilience/index.js +8 -1
  183. package/packages/client/dist/resilience/recovery-detector.js +74 -1
  184. package/packages/client/dist/resolvers/asset-resolver.js +13 -0
  185. package/packages/client/dist/resolvers/local-resolver.js +255 -8
  186. package/packages/client/dist/resolvers/remote-resolver.js +233 -1
  187. package/packages/client/dist/runner/binary.js +404 -1
  188. package/packages/client/dist/runner/cli.js +1571 -17
  189. package/packages/client/dist/runner/headless/adapters.js +49 -1
  190. package/packages/client/dist/runner/headless/claude-code-adapter.js +79 -1
  191. package/packages/client/dist/runner/headless/continuous-story-workspace.js +1628 -11
  192. package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +69 -1
  193. package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +110 -2
  194. package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +1236 -8
  195. package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +318 -2
  196. package/packages/client/dist/runner/headless/fake-adapter.js +62 -1
  197. package/packages/client/dist/runner/headless/managed-profile.js +132 -1
  198. package/packages/client/dist/runner/headless/opencode-adapter.js +145 -2
  199. package/packages/client/dist/runner/headless/prepared-story-bundle.js +43 -1
  200. package/packages/client/dist/runner/headless/resolver.js +231 -1
  201. package/packages/client/dist/runner/headless/run-yolo.js +885 -1
  202. package/packages/client/dist/runner/headless/run-yoloop.js +2574 -2
  203. package/packages/client/dist/runner/headless/types.js +574 -2
  204. package/packages/client/dist/runner/local-console.js +396 -13
  205. package/packages/client/dist/runner/portal-sync-worker.js +1487 -1
  206. package/packages/client/dist/runner/project-identity.js +106 -1
  207. package/packages/client/dist/runner/scheduler.js +995 -7
  208. package/packages/client/dist/runner-cli.js +18 -2
  209. package/packages/client/dist/state/invocation-shape.js +13 -1
  210. package/packages/client/dist/state/project-state-snapshot.d.ts +8 -0
  211. package/packages/client/dist/state/project-state-snapshot.js +1731 -1
  212. package/packages/client/dist/state/state-json-repair.js +785 -3
  213. package/packages/client/dist/state/structural-dag-projection.js +118 -1
  214. package/packages/client/dist/telemetry/index.js +5 -1
  215. package/packages/client/dist/telemetry/offline-queue.js +131 -1
  216. package/packages/client/dist/tier/index.js +5 -1
  217. package/packages/client/dist/tier/tier-aware-client.js +405 -1
  218. package/packages/client/dist/types/index.js +38 -1
  219. package/packages/client/dist/version.js +27 -1
  220. package/packages/client/dist/yolo/change-evidence-collector.js +126 -1
  221. package/packages/client/dist/yolo/invoke-envelope-capability.js +62 -1
  222. package/packages/client/dist/yolo/spec-envelope-collector.js +184 -5
  223. package/packages/client/dist/yoloop/discovery-hook.js +300 -2
  224. package/packages/client/dist/yoloop/index.js +8 -1
  225. package/packages/client/dist/yoloop/invoke-hooks.js +669 -12
  226. package/packages/client/dist/yoloop/shared-discover-epics.js +1007 -1
  227. package/packages/client/dist/yoloop/shared-yoloop-types.d.ts +65 -1
  228. package/packages/client/dist/yoloop/shared-yoloop-types.js +33 -1
  229. package/packages/client/dist/yoloop/target-normalization.js +180 -1
  230. package/packages/client/dist/yoloop/yoloop-client-state-store.d.ts +8 -0
  231. package/packages/client/dist/yoloop/yoloop-client-state-store.js +1920 -1
  232. package/packages/shared/dist/yolo/spec-envelope.js +3 -6
  233. package/targets-stubs/antigravity/gemini.md +1 -1
  234. package/targets-stubs/antigravity/skill/SKILL.md +1 -1
  235. package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
  236. package/targets-stubs/claude-code/neocortex-root.md +2 -2
  237. package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
  238. package/targets-stubs/claude-code/neocortex.md +2 -2
  239. package/targets-stubs/codex/AGENTS.md +1 -1
  240. package/targets-stubs/cursor/agent.md +2 -2
  241. package/targets-stubs/gemini-cli/agent.md +2 -2
  242. package/targets-stubs/opencode/neocortex-root.md +1 -1
  243. package/targets-stubs/vscode/neocortex.agent.md +2 -2
@@ -1 +1,1731 @@
1
- import{createHash as H}from"node:crypto";import{analyzeDependencyDag as I,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"],Q=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"]),n=(r,e,t={})=>({commandId:r,stateProjectionPolicy:e,...t}),A=Object.freeze({status:n("status","full"),"arch-plan":n("arch-plan","full"),"arch-prd":n("arch-prd","full"),"arch-architecture":n("arch-architecture","epic-targeted",{structuralRequired:!0}),"arch-api-contracts":n("arch-api-contracts","epic-targeted",{structuralRequired:!0}),"arch-api-integrations":n("arch-api-integrations","epic-targeted",{structuralRequired:!0}),"arch-database":n("arch-database","epic-targeted",{structuralRequired:!0}),"arch-security":n("arch-security","epic-targeted",{structuralRequired:!0}),"arch-design-system":n("arch-design-system","epic-targeted",{structuralRequired:!0}),"arch-ux-design":n("arch-ux-design","epic-targeted",{structuralRequired:!0}),"arch-performance":n("arch-performance","epic-targeted",{structuralRequired:!0}),"arch-testing":n("arch-testing","epic-targeted",{structuralRequired:!0}),"arch-infrastructure":n("arch-infrastructure","epic-targeted",{structuralRequired:!0}),"arch-review":n("arch-review","epic-targeted",{structuralRequired:!0}),"arch-fitness-functions":n("arch-fitness-functions","epic-targeted",{structuralRequired:!0}),"create-epic":n("create-epic","epic-summary"),"idea-diagnose":n("idea-diagnose","full"),"idea-research":n("idea-research","epic-targeted",{structuralRequired:!0}),"generate-epic":n("generate-epic","epic-targeted",{structuralRequired:!0}),exec:n("exec","story-targeted",{structuralRequired:!0}),yolo:n("yolo","story-targeted",{structuralRequired:!0}),"yolo-inline":n("yolo-inline","story-targeted",{structuralRequired:!0}),epic:n("epic","epic-targeted",{structuralRequired:!0}),"setup-branch":n("setup-branch","story-targeted",{structuralRequired:!0}),diagnose:n("diagnose","adaptive-targeted"),"diagnose-inline":n("diagnose-inline","full"),research:n("research","adaptive-targeted"),"research-inline":n("research-inline","full"),"write-spec":n("write-spec","story-targeted",{structuralRequired:!0}),"create-tasks":n("create-tasks","story-targeted",{structuralRequired:!0}),implement:n("implement","story-targeted",{structuralRequired:!0}),commit:n("commit","story-targeted",{structuralRequired:!0}),"commit-push":n("commit","story-targeted",{structuralRequired:!0}),sync:n("sync","story-targeted",{structuralRequired:!0}),"sync-main":n("sync","story-targeted",{structuralRequired:!0}),"create-pr":n("create-pr","story-targeted",{structuralRequired:!0}),review:n("review","story-targeted"),"review-pr":n("review","story-targeted"),merge:n("merge","story-targeted",{structuralRequired:!0}),"merge-pr":n("merge","story-targeted",{structuralRequired:!0}),"fix-blocked":n("fix-blocked","story-targeted"),"finalize-epic":n("finalize-epic","epic-targeted"),"resolve-conflicts":n("resolve-conflicts","story-targeted"),"update-memory":n("update-memory","full"),"update-project-memory":n("update-memory","story-targeted",{structuralRequired:!0}),refactor:n("refactor","adaptive-targeted"),"refactor-suggest":n("refactor","story-targeted",{structuralRequired:!0}),cleanup:n("cleanup","full"),audit:n("audit","full"),"tech-debt":n("tech-debt","full"),menu:n("menu","full"),plans:n("plans","full"),billing:n("billing","full"),subscribe:n("subscribe","full"),"qa-scan":n("qa-scan","full"),yoloop:n("yoloop","yoloop-targeted",{structuralRequired:!0}),"migrate-state":n("migrate-state","full"),"migrate-project-id":n("migrate-project-id","full"),"policy-audit":n("policy-audit","full"),"mutation-test":n("mutation-test","full"),"sync-openapi":n("sync-openapi","full"),"generate-pacts":n("generate-pacts","full"),"verify-pacts":n("verify-pacts","full"),"property-test":n("property-test","full"),"property-tests":n("property-test","story-targeted",{structuralRequired:!0}),"chaos-plan":n("chaos-plan","full"),"ui-ux-review":n("ui-ux-review","adaptive-targeted"),"solyd-system":n("solyd-system","adaptive-targeted"),goal:n("goal","continuity-scoped"),loop:n("loop","continuity-scoped"),jobs:n("jobs","continuity-scoped"),runner:n("runner","continuity-scoped"),"goal-tick":n("goal-tick","continuity-scoped"),"loop-tick":n("loop-tick","continuity-scoped"),"validate-tests":n("validate-tests","story-targeted",{structuralRequired:!0}),"qa-gate":n("qa-gate","story-targeted",{structuralRequired:!0})}),X=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"}),ee=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 w(r,e=120){if(typeof r!="string")return;const t=r.trim(),i=d(r,e);return i===t?i:void 0}function T(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 te(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(te);if(!e.some(t=>t===void 0))return[...new Set(e)].sort((t,i)=>t.localeCompare(i,"en"))}function re(r){return typeof r=="string"&&Q.has(r.trim().toLowerCase().replace(/_/g,"-"))}function C(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(o=>typeof o=="string")&&(t[i]=[...c])}return t}function ie(r,e){const t=e.checkpoint;if(!h(t)||t.schemaVersion!==1||t.storyId!==r||t.epicId!==e.epic_id||!T(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||!w(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=C(t,["schemaVersion","storyId","epicId","branch","baseSha","headSha","idempotencyKey","dispatchId","bundleId","bundleDigest","graphRevision","claimRevision","qaVerdict","reviewVerdict","recordedAt","commits","receiptRefs"]);return i.qaReceipt=C(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=C(t.reviewReceipt,["schemaVersion","kind","producer","storyId","epicId","baseSha","headSha","bundleDigest","graphRevision","sourceEvidenceDigest","qaReceiptRef","verdict","reviewedAt","receiptRef"])),i}function ce(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 C(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||!T(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 C(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 o=d(c,80);if(!(!o||e.has(o))&&(e.add(o),t.push(o),t.length>=J))return t}return t}function ne(r){return r.trim().replace(/^@?\*/,"").replace(/^@/,"").toLowerCase()}function se(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=se(r);if(!e)return A.menu;const t=ne(e),i=ee[t]??X[t]??t;return A[i]??null}function ae(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 ze(r,e,t,i="full-compatible",c=["full-state"]){const o=ae(r,e,t,i,c);return v({...e,scope:o},e,o)}function de(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 ue(r){const e=r.trim(),t=e.search(/\s/);return t===-1?"":e.slice(t).trim()}function q(r){return ue(r).split(/\s+/).map(e=>e.replace(/^@/,"").replace(/^['"]|['"]$/g,"")).filter(e=>e.length>0&&!e.startsWith("-"))}function Fe(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(o=>typeof o=="string"&&o.length>0);for(const o of c)if(e.epics[o])return o;return null}function le(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=le(r,e);if(i)return i;for(const c of q(r)){if(/^[A-Z]?\d+(?:\.\d+)+$/i.test(c))continue;const o=P(c,e);if(o)return o}return null}function pe(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 o=i?.lock?.currentEpicId??i?.lock?.epicId;return typeof o=="string"&&e.epics[o]?o:null}function fe(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 o of c)typeof o=="string"&&x(o,e,t)}function ye(r,e){const t=I(e.stories,[r]),i={};for(const c of t.orderedIds){const o=e.stories[c];o&&(i[c]=o)}return i}function $(r,e,t=[]){const i={};for(const c of t)e.epics[c]&&(i[c]=e.epics[c]);for(const[c,o]of Object.entries(r)){const s=j(o,c);s&&e.epics[s]&&(i[s]=e.epics[s])}return i}function me(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 o of c)typeof o=="string"&&o.length>0&&me(o,e,t)}function V(r,e,t){const i=I(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 o={};for(const s of[...c].sort((a,u)=>a.localeCompare(u,"en"))){const a=t.epics[s];a&&(o[s]=s===r?a:K(s,a))}return o}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=I(t.stories,i),o={};for(const s of c.orderedIds){const a=t.stories[s];a&&(o[s]=j(a,s)===r?oe(s,a):Y(s,a))}return o}function ge(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")),o=H("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:o,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(!re(e.status))return{...i,...c?{scheduling_checkpoint_evidence:c}:{}};const o=e.source==="create-epic"||e.source==="discovered"?e.source:void 0,s=T(e.branch_name),a=w(e.last_step,120),u=Array.isArray(e.steps_completed)&&e.steps_completed.length<=64?e.steps_completed.map(m=>w(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=ie(r,e),g=p?ce(r,e):void 0;return{...i,...o?{source:o}:{},...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 K(r,e){const t=Array.isArray(e.stories)?[...new Set(e.stories.filter(c=>typeof c=="string"&&c.length>0))].sort((c,o)=>c.localeCompare(o,"en")):[],i=Array.isArray(e.depends_on)?[...new Set(e.depends_on.filter(c=>typeof c=="string"&&c.length>0))].sort((c,o)=>c.localeCompare(o,"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 he(r,e,t){const i=I(e.stories),c=I(e.epics),o=Object.fromEntries(i.orderedIds.map(u=>[u,Y(u,e.stories[u])])),s=Object.fromEntries(c.orderedIds.map(u=>[u,K(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 v({...e,stories:o,epics:s,scope:a},e,a)}function be(r,e){const t=new Set,i=r.stories;if(Array.isArray(i))for(const o of i)typeof o=="string"&&x(o,e,t);const c={};for(const o of t){const s=e.stories[o];s&&(c[o]=s)}return c}function _e(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 W(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 Se(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 je(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 ve(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 Ie(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,o={...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(o).length>0?o:void 0}function ke(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 Ce(r,e,t){const i=d(e?.activeStoryId),c=d(e?.activeEpicId),o=d(e?.activeStepId),s=i&&r.stories[i]?j(r.stories[i],i):null;if((i||c||o)&&N(r,c??s))return{epicId:c??null,storyId:i??null,stepId:o??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 Ee(r,e){const t=W(r.stories),i=W(r.epics),c=Se(r.epics),o=Object.values(r.epics).filter(g=>(k.includes(g.lifecycle_classification)?g.lifecycle_classification:"active")==="active"&&!L(g.status)).length,s=ve(r),a=Ie(r),u=ke(r),l=Ce(r,s,a),f=je(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:o,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 v(r,e,t){return{...r,stateSummary:Ee(e,t)}}function Re(r,e,t){const i={};for(const o of Object.keys(e.epics))i[o]={id:o};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 v({...e,stories:{},epics:i,scope:c},e,c)}function b(r,e,t,i=["summary-only","stories-omitted"],c="summary-only"){const o=_e(e),s={kind:"projected",commandId:t.commandId,stateProjectionPolicy:t.stateProjectionPolicy,projectionMode:c,trigger:r,targetEpicId:null,targetStoryId:null,includedStoryCount:0,includedEpicCount:Object.keys(o).length,omittedStoryCount:Object.keys(e.stories).length,omittedEpicCount:Math.max(0,Object.keys(e.epics).length-Object.keys(o).length),reason:"summary-only",reasonCodes:_(i)};return v({...e,stories:{},epics:o,scope:s},e,s)}function D(r,e,t,i,c,o){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):ye(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:_(o,l?["epic-graph-authority-complete"]:[])};return v({...e,stories:f,epics:p,scope:g},e,g)}function B(r,e,t,i,c,o){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=be(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:_(o)};return v({...e,stories:a,epics:u,scope:l},e,l)}function Oe(r,e,t){const i=fe(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 o=pe(r,e),s=O({commandId:t.commandId,explicitYoloopEpicId:c,sessionYoloopEpicId:c?null:o});if(s==="yoloop-discovery")return he(r,e,t);if(!o||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[o];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(o,a,e),l=V(o,u,e);if(!l[o])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:o,targetStoryId:null,targetEpicCoverage:ge(o,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 v({...e,stories:u,epics:l,scope:p},e,p)}function Ae(r,e){const t={};for(const[i,c]of Object.entries(r.epics)){const o=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}:{},...o.length>0?{stories:o}:{},...o.length>0&&Array.isArray(c.depends_on)?{depends_on:c.depends_on.filter(s=>typeof s=="string"&&s.length>0)}:{},...o.length>0&&(c.branch_mode==="epic"||c.branch_mode==="story")?{branch_mode:c.branch_mode}:{},...o.length>0&&typeof c.execution_branch=="string"?{execution_branch:c.execution_branch}:{},...o.length>0&&typeof c.origin_branch=="string"?{origin_branch:c.origin_branch}:{},...o.length>0&&(c.branch_lease===null||typeof c.branch_lease=="object")?{branch_lease:c.branch_lease}:{},...o.length>0&&(c.origin_binding===null||typeof c.origin_binding=="object")?{origin_binding:c.origin_binding}:{},...o.length>0&&(c.aggregate_qa_receipt===null||typeof c.aggregate_qa_receipt=="object")?{aggregate_qa_receipt:c.aggregate_qa_receipt}:{}}}return t}function we(r){return r.stateSummary?.totals.stories??(r.scope?.includedStoryCount??Object.keys(r.stories).length)+(r.scope?.omittedStoryCount??0)}function Te(r){return r.stateSummary?.totals.epics??(r.scope?.includedEpicCount??Object.keys(r.epics).length)+(r.scope?.omittedEpicCount??0)}function qe(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 Le(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 o=Ae(r,t),s=Object.keys(c).length,a=Object.keys(o).length,u=Math.max(0,we(r)-s),l=Math.max(0,Te(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=qe(r,p);return{...r,stories:c,epics:o,scope:p,...g?{stateSummary:g}:{}}}function Pe(r,e){const t=r.trim(),i=z(t);try{if(!i){if(de(t)){const o=n("story-reference","story-targeted"),s=F(t);if(s)return D(t,e,o,s,"targeted-story",["story-reference-targeted"])}return b(t,e,n("unknown","adaptive-targeted"),["unknown-command-summary-only"])}if(i.stateProjectionPolicy==="epic-summary")return Re(t,e,i);if(i.stateProjectionPolicy==="yoloop-targeted")return Oe(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 o=O({commandId:i.commandId});return b(t,e,i,["yolo-inline","stories-omitted","historical-content-omitted"],o??"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 o=R(t,e);return o?B(t,e,i,o,"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 o=R(t,e);return o?B(t,e,i,o,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??n("unknown","adaptive-targeted"),["projection-error-summary-only"])}}const xe=new Set(["yolo-story","yolo-inline","yoloop-target","yoloop-session","yoloop-discovery"]);function Ne(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 $e(r,e){const t=z(r.trim());if(!t||!["yolo","yolo-inline","yoloop"].includes(t.commandId))return null;try{const i=Pe(r,e),c=i.scope?.projectionMode;if(!c||!xe.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:Ne(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})}}export{Le as degradeStateSnapshotForPayloadLimit,Pe as projectStateSnapshotForInvoke,$e as projectStateSnapshotResultV2ForInvoke};
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
+ }