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