@ornexus/neocortex 4.60.23 → 4.60.25
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/sbom.cdx.json +23 -23
- package/install.js +67 -10
- package/install.ps1 +39 -8
- package/install.sh +18 -6
- package/package.json +5 -2
- package/packages/client/dist/adapters/adapter-registry.d.ts +2 -2
- package/packages/client/dist/adapters/adapter-registry.js +1 -1
- package/packages/client/dist/adapters/grok-adapter.d.ts +11 -0
- package/packages/client/dist/adapters/grok-adapter.js +2 -0
- package/packages/client/dist/adapters/index.d.ts +1 -0
- package/packages/client/dist/adapters/index.js +1 -1
- package/packages/client/dist/adapters/platform-detector.d.ts +1 -1
- package/packages/client/dist/adapters/platform-detector.js +1 -1
- package/packages/client/dist/agent/refresh-stubs.js +2 -2
- package/packages/client/dist/cli.js +21 -2
- package/packages/client/dist/commands/invoke.d.ts +20 -21
- package/packages/client/dist/commands/invoke.js +59 -55
- package/packages/client/dist/commands/story-checkpoint.d.ts +15 -0
- package/packages/client/dist/commands/story-checkpoint.js +1 -0
- package/packages/client/dist/config.js +1 -1
- package/packages/client/dist/generated/command-registry.generated.d.ts +18 -52
- package/packages/client/dist/generated/command-registry.generated.js +1 -1
- package/packages/client/dist/git/direct-yolo-checkpoint.d.ts +67 -0
- package/packages/client/dist/git/direct-yolo-checkpoint.js +3 -0
- package/packages/client/dist/git/git-lifecycle-step-ids.d.ts +2 -0
- package/packages/client/dist/git/git-lifecycle-step-ids.js +1 -0
- package/packages/client/dist/git/git-lifecycle-store.d.ts +198 -0
- package/packages/client/dist/git/git-lifecycle-store.js +4 -0
- package/packages/client/dist/git/secure-filesystem-boundary.d.ts +26 -0
- package/packages/client/dist/git/secure-filesystem-boundary.js +123 -0
- package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +1 -1
- package/packages/client/dist/index.d.ts +2 -0
- package/packages/client/dist/index.js +1 -1
- package/packages/client/dist/memory/shared-project-memory-types.d.ts +29 -2
- package/packages/client/dist/memory/shared-project-memory-types.js +2 -2
- package/packages/client/dist/policy/subagent-approval-policy.js +1 -1
- package/packages/client/dist/runner/headless/continuous-story-workspace.d.ts +131 -0
- package/packages/client/dist/runner/headless/continuous-story-workspace.js +58 -0
- package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.d.ts +23 -0
- package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +1 -0
- package/packages/client/dist/runner/headless/epic-merge-candidate-qa.d.ts +15 -0
- package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +28 -0
- package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.d.ts +12 -0
- package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +8 -0
- package/packages/client/dist/runner/headless/epic-terminal-git-runner.d.ts +134 -0
- package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +2 -0
- package/packages/client/dist/runner/headless/prepared-story-bundle.js +1 -1
- package/packages/client/dist/runner/headless/run-yolo.js +1 -1
- package/packages/client/dist/runner/headless/run-yoloop.d.ts +7 -2
- package/packages/client/dist/runner/headless/run-yoloop.js +8 -1
- package/packages/client/dist/runner/headless/types.d.ts +1 -1
- package/packages/client/dist/runner/headless/types.js +2 -2
- package/packages/client/dist/runner-cli.js +0 -0
- package/packages/client/dist/state/project-state-snapshot.js +1 -1
- package/packages/client/dist/state/state-json-repair.d.ts +9 -0
- package/packages/client/dist/state/state-json-repair.js +3 -3
- package/packages/client/dist/tier/tier-aware-client.js +1 -1
- package/packages/client/dist/yoloop/invoke-hooks.d.ts +13 -10
- package/packages/client/dist/yoloop/invoke-hooks.js +8 -5
- package/packages/client/dist/yoloop/shared-discover-epics.js +1 -1
- package/packages/shared/dist/generated/command-registry.generated.js +18 -66
- package/packages/shared/dist/generated/invocation-schema.generated.js +5 -25
- package/packages/shared/dist/invocation/index.d.ts +1 -1
- package/packages/shared/dist/yoloop/epic-terminal-git.js +227 -0
- package/packages/shared/dist/yoloop/planning-graph.js +119 -0
- package/packages/shared/dist/yoloop/public-story-write-set.js +27 -0
- package/packages/shared/dist/yoloop/wave-decision-receipt.js +19 -0
- package/targets-stubs/antigravity/gemini.md +1 -1
- package/targets-stubs/antigravity/neocortex.md +18 -0
- 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 +21 -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 +20 -1
- package/targets-stubs/cursor/agent.md +20 -2
- package/targets-stubs/gemini-cli/agent.md +2 -2
- package/targets-stubs/gemini-cli/gemini.md +18 -0
- package/targets-stubs/grok/README.md +13 -0
- package/targets-stubs/grok/SKILL.md +50 -0
- package/targets-stubs/grok/config-mcp.toml +22 -0
- package/targets-stubs/grok/install-grok.sh +31 -0
- package/targets-stubs/kimi/neocortex.md +18 -0
- package/targets-stubs/openclaw/SKILL.md +18 -0
- package/targets-stubs/opencode/neocortex-root.md +20 -1
- package/targets-stubs/vscode/neocortex.agent.md +20 -2
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
/** Generated by scripts/generate-command-registry.mjs. Do not edit. */
|
|
2
2
|
export const COMMAND_REGISTRY_SCHEMA_VERSION = 1;
|
|
3
3
|
export const COMMAND_REGISTRY_VERSION = "1.0.0";
|
|
4
|
-
export const COMMAND_REGISTRY_CHECKSUM = "
|
|
4
|
+
export const COMMAND_REGISTRY_CHECKSUM = "5ed842e2bf9a9e959f23096cec199be4200bb4056b99479b5dc47b2dbe1293e6";
|
|
5
5
|
export const COMMAND_REGISTRY_PROJECTION_MANIFEST = {
|
|
6
6
|
"schemaVersion": 1,
|
|
7
7
|
"registryVersion": "1.0.0",
|
|
8
|
-
"registryChecksum": "
|
|
8
|
+
"registryChecksum": "5ed842e2bf9a9e959f23096cec199be4200bb4056b99479b5dc47b2dbe1293e6",
|
|
9
9
|
"projections": [
|
|
10
10
|
{
|
|
11
11
|
"kind": "admin",
|
|
12
|
-
"entryCount":
|
|
13
|
-
"sha256": "
|
|
12
|
+
"entryCount": 62,
|
|
13
|
+
"sha256": "d752e65aa65ee7864416b4c68af6d516233e180cd5b0408dcb244751ede7a21a"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"kind": "client",
|
|
17
|
-
"entryCount":
|
|
18
|
-
"sha256": "
|
|
17
|
+
"entryCount": 62,
|
|
18
|
+
"sha256": "d752e65aa65ee7864416b4c68af6d516233e180cd5b0408dcb244751ede7a21a"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"kind": "docs",
|
|
22
|
-
"entryCount":
|
|
23
|
-
"sha256": "
|
|
22
|
+
"entryCount": 62,
|
|
23
|
+
"sha256": "d752e65aa65ee7864416b4c68af6d516233e180cd5b0408dcb244751ede7a21a"
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"kind": "metrics",
|
|
27
|
-
"entryCount":
|
|
28
|
-
"sha256": "
|
|
27
|
+
"entryCount": 62,
|
|
28
|
+
"sha256": "d752e65aa65ee7864416b4c68af6d516233e180cd5b0408dcb244751ede7a21a"
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"kind": "server",
|
|
32
|
-
"entryCount":
|
|
33
|
-
"sha256": "
|
|
32
|
+
"entryCount": 67,
|
|
33
|
+
"sha256": "1b3e29b3b462a8fb283a308e311ca681d7b106f986723d4c08b84805c878a00a"
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
"kind": "shared",
|
|
37
|
-
"entryCount":
|
|
38
|
-
"sha256": "
|
|
37
|
+
"entryCount": 67,
|
|
38
|
+
"sha256": "0d181e8f869891e7c3e09b76ad00b122ca7c5a4ca530e86391d64517d14b7bc8"
|
|
39
39
|
}
|
|
40
40
|
]
|
|
41
41
|
};
|
|
@@ -2022,54 +2022,6 @@ export const GENERATED_SHARED_COMMANDS = [
|
|
|
2022
2022
|
"visibility": "public",
|
|
2023
2023
|
"subcommands": []
|
|
2024
2024
|
},
|
|
2025
|
-
{
|
|
2026
|
-
"aliases": [
|
|
2027
|
-
"inicializar"
|
|
2028
|
-
],
|
|
2029
|
-
"category": "quick-start",
|
|
2030
|
-
"compatibility": {
|
|
2031
|
-
"deprecatedIn": null,
|
|
2032
|
-
"introducedIn": "1.0.0",
|
|
2033
|
-
"removedIn": null,
|
|
2034
|
-
"replacement": null
|
|
2035
|
-
},
|
|
2036
|
-
"description": {
|
|
2037
|
-
"en": "Initialize project",
|
|
2038
|
-
"es": "Inicializar proyecto",
|
|
2039
|
-
"pt-BR": "Inicializar projeto"
|
|
2040
|
-
},
|
|
2041
|
-
"examples": [
|
|
2042
|
-
"@neocortex *init",
|
|
2043
|
-
"@neocortex init",
|
|
2044
|
-
"@neocortex 2"
|
|
2045
|
-
],
|
|
2046
|
-
"id": "init",
|
|
2047
|
-
"inputShape": "epics",
|
|
2048
|
-
"mode": "utility",
|
|
2049
|
-
"name": "Inicializar + Enrichment",
|
|
2050
|
-
"number": 2,
|
|
2051
|
-
"policy": {
|
|
2052
|
-
"billingClass": "billable",
|
|
2053
|
-
"idempotencyClass": "logical-supported",
|
|
2054
|
-
"minimumTier": "free",
|
|
2055
|
-
"mutationClass": "stateful",
|
|
2056
|
-
"privilege": "authenticated",
|
|
2057
|
-
"quotaClass": "workflow",
|
|
2058
|
-
"replayClass": "signed-request",
|
|
2059
|
-
"strictReadOnly": "deny"
|
|
2060
|
-
},
|
|
2061
|
-
"projections": [
|
|
2062
|
-
"admin",
|
|
2063
|
-
"client",
|
|
2064
|
-
"docs",
|
|
2065
|
-
"metrics",
|
|
2066
|
-
"server",
|
|
2067
|
-
"shared"
|
|
2068
|
-
],
|
|
2069
|
-
"stepId": "step-u-init",
|
|
2070
|
-
"visibility": "public",
|
|
2071
|
-
"subcommands": []
|
|
2072
|
-
},
|
|
2073
2025
|
{
|
|
2074
2026
|
"aliases": [
|
|
2075
2027
|
"continuity-jobs",
|
|
@@ -3575,9 +3527,9 @@ export const GENERATED_SHARED_COMMANDS = [
|
|
|
3575
3527
|
"replacement": null
|
|
3576
3528
|
},
|
|
3577
3529
|
"description": {
|
|
3578
|
-
"en": "
|
|
3579
|
-
"es": "Configurar branch",
|
|
3580
|
-
"pt-BR": "Configurar branch"
|
|
3530
|
+
"en": "Set up branch in the current checkout",
|
|
3531
|
+
"es": "Configurar branch en el checkout actual",
|
|
3532
|
+
"pt-BR": "Configurar branch no checkout atual"
|
|
3581
3533
|
},
|
|
3582
3534
|
"examples": [
|
|
3583
3535
|
"@neocortex *setup-branch @docs/stories/P126.01.story.md"
|
|
@@ -3585,7 +3537,7 @@ export const GENERATED_SHARED_COMMANDS = [
|
|
|
3585
3537
|
"id": "setup-branch",
|
|
3586
3538
|
"inputShape": "story",
|
|
3587
3539
|
"mode": "step",
|
|
3588
|
-
"name": "Configurar Branch
|
|
3540
|
+
"name": "Configurar Branch",
|
|
3589
3541
|
"number": 24,
|
|
3590
3542
|
"policy": {
|
|
3591
3543
|
"billingClass": "billable",
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
export const GENERATED_INVOCATION_SCHEMA_MANIFEST = {
|
|
3
3
|
"schemaVersion": "p205-invocation-schema-v1",
|
|
4
4
|
"registryVersion": "1.0.0",
|
|
5
|
-
"registryChecksum": "
|
|
6
|
-
"schemaChecksum": "
|
|
7
|
-
"commandCount":
|
|
5
|
+
"registryChecksum": "5ed842e2bf9a9e959f23096cec199be4200bb4056b99479b5dc47b2dbe1293e6",
|
|
6
|
+
"schemaChecksum": "c3252fa75c16cc81bd0ea0e8b33868d121c2e45258f9b425c310af9337cfbd6f",
|
|
7
|
+
"commandCount": 62,
|
|
8
8
|
"optionCount": 47,
|
|
9
|
-
"positionalCount":
|
|
9
|
+
"positionalCount": 43,
|
|
10
10
|
"operationCount": 33,
|
|
11
|
-
"projectionSha256": "
|
|
11
|
+
"projectionSha256": "9843f3f7155ed3a6244c020a324c2d2818c5d4fd2d7590eeb78b9e055bc18e75",
|
|
12
12
|
"commands": [
|
|
13
13
|
{
|
|
14
14
|
"commandId": "arch-api-contracts",
|
|
@@ -830,26 +830,6 @@ export const GENERATED_INVOCATION_SCHEMA_MANIFEST = {
|
|
|
830
830
|
],
|
|
831
831
|
"terminator": true
|
|
832
832
|
},
|
|
833
|
-
{
|
|
834
|
-
"commandId": "init",
|
|
835
|
-
"inputShape": "epics",
|
|
836
|
-
"operation": {
|
|
837
|
-
"required": false,
|
|
838
|
-
"unknownAsPositional": false,
|
|
839
|
-
"operations": []
|
|
840
|
-
},
|
|
841
|
-
"options": [],
|
|
842
|
-
"positionals": [
|
|
843
|
-
{
|
|
844
|
-
"cardinality": "one",
|
|
845
|
-
"id": "epics",
|
|
846
|
-
"kind": "target-ref",
|
|
847
|
-
"order": 0,
|
|
848
|
-
"required": false
|
|
849
|
-
}
|
|
850
|
-
],
|
|
851
|
-
"terminator": true
|
|
852
|
-
},
|
|
853
833
|
{
|
|
854
834
|
"commandId": "jobs",
|
|
855
835
|
"inputShape": "continuity-jobs",
|
|
@@ -120,7 +120,7 @@ export interface InvocationCommandSchemaV1 {
|
|
|
120
120
|
readonly positionals: readonly InvocationPositionalSchemaV1[];
|
|
121
121
|
readonly terminator: true;
|
|
122
122
|
}
|
|
123
|
-
export declare const INVOCATION_SCHEMA_CHECKSUM: "
|
|
123
|
+
export declare const INVOCATION_SCHEMA_CHECKSUM: "c3252fa75c16cc81bd0ea0e8b33868d121c2e45258f9b425c310af9337cfbd6f";
|
|
124
124
|
export interface InvocationSchemaManifestV1 {
|
|
125
125
|
readonly schemaVersion: typeof INVOCATION_SCHEMA_VERSION;
|
|
126
126
|
readonly registryVersion: string;
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/** Public contracts and pure safety decisions for epic-owned terminal Git. */
|
|
2
|
+
export const EPIC_TERMINAL_GIT_REASON_CODES = Object.freeze({
|
|
3
|
+
READY: 'epic-terminal-git-ready',
|
|
4
|
+
ALREADY_COMPLETE: 'epic-terminal-git-already-complete',
|
|
5
|
+
ORIGIN_MISSING: 'epic-origin-branch-missing',
|
|
6
|
+
EXECUTION_MISSING: 'epic-execution-branch-missing',
|
|
7
|
+
SAME_BRANCH: 'epic-origin-equals-execution',
|
|
8
|
+
LOCAL_GATES_REQUIRED: 'epic-local-gates-required',
|
|
9
|
+
STORY_CHECKPOINTS_REQUIRED: 'epic-story-checkpoints-required',
|
|
10
|
+
LEASE_ACTIVE: 'epic-writer-lease-active',
|
|
11
|
+
HEAD_MISMATCH: 'epic-execution-head-mismatch',
|
|
12
|
+
GRAPH_REVISION_MISMATCH: 'epic-graph-revision-mismatch',
|
|
13
|
+
MERGE_CONFLICT: 'epic-terminal-merge-conflict',
|
|
14
|
+
REMOTE_POLICY_DENIED: 'epic-terminal-remote-policy-denied',
|
|
15
|
+
RETRY_ELIGIBLE: 'epic-terminal-retry-eligible',
|
|
16
|
+
RECOVERED_PHYSICAL_PUSH: 'epic-terminal-recovered-physical-push',
|
|
17
|
+
OWNERSHIP_UNPROVEN: 'git-resource-ownership-unproven',
|
|
18
|
+
RESOURCE_ACTIVE: 'git-resource-active',
|
|
19
|
+
RESOURCE_ORIGIN: 'git-resource-is-origin',
|
|
20
|
+
RESOURCE_CURRENT: 'git-resource-is-current',
|
|
21
|
+
RESOURCE_PROTECTED: 'git-resource-protected',
|
|
22
|
+
UNIQUE_COMMITS: 'git-resource-has-unique-commits',
|
|
23
|
+
INTEGRATION_UNPROVEN: 'git-resource-integration-unproven',
|
|
24
|
+
SAFE_TO_RECONCILE: 'git-resource-safe-to-reconcile',
|
|
25
|
+
ALREADY_RECONCILED: 'git-resource-already-reconciled',
|
|
26
|
+
AGGREGATE_QA_REQUIRED: 'epic-aggregate-qa-receipt-required',
|
|
27
|
+
AGGREGATE_QA_STALE: 'epic-aggregate-qa-receipt-stale',
|
|
28
|
+
ORIGIN_BINDING_REQUIRED: 'epic-origin-binding-required',
|
|
29
|
+
PROVIDER_TRUTH_UNKNOWN: 'git-resource-provider-truth-unknown',
|
|
30
|
+
WORKTREE_ACTIVE: 'git-resource-worktree-active',
|
|
31
|
+
RESOURCE_RACED: 'git-resource-expected-oid-raced',
|
|
32
|
+
REMOTE_DELETE_CAS_UNAVAILABLE: 'git-resource-remote-delete-cas-unavailable',
|
|
33
|
+
ORIGIN_CAPTURE_WINDOW_MISSED: 'epic-origin-binding-capture-window-missed',
|
|
34
|
+
ORIGIN_PHYSICAL_DRIFT: 'epic-origin-binding-physical-drift',
|
|
35
|
+
PHYSICAL_REVALIDATION_REQUIRED: 'epic-terminal-physical-revalidation-required',
|
|
36
|
+
PHYSICAL_ANCESTRY_UNPROVEN: 'epic-terminal-physical-ancestry-unproven',
|
|
37
|
+
PR_STRICT_BASE_GUARD_REQUIRED: 'epic-terminal-pr-strict-base-guard-required',
|
|
38
|
+
PR_BASE_GUARD_UNVERIFIABLE: 'epic-terminal-pr-base-guard-unverifiable',
|
|
39
|
+
PR_MERGE_QUEUE_LOCAL_GATE_REQUIRED: 'epic-terminal-pr-merge-queue-local-gate-required',
|
|
40
|
+
});
|
|
41
|
+
export function validateEpicTerminalGitDirective(directive, actual) {
|
|
42
|
+
const reasons = [];
|
|
43
|
+
if (!nonEmpty(directive.originBranch))
|
|
44
|
+
reasons.push(EPIC_TERMINAL_GIT_REASON_CODES.ORIGIN_MISSING);
|
|
45
|
+
if (!nonEmpty(directive.executionBranch))
|
|
46
|
+
reasons.push(EPIC_TERMINAL_GIT_REASON_CODES.EXECUTION_MISSING);
|
|
47
|
+
if (directive.originBranch === directive.executionBranch)
|
|
48
|
+
reasons.push(EPIC_TERMINAL_GIT_REASON_CODES.SAME_BRANCH);
|
|
49
|
+
if (directive.localGates?.passed !== true || directive.localGates.receiptRefs.length === 0) {
|
|
50
|
+
reasons.push(EPIC_TERMINAL_GIT_REASON_CODES.LOCAL_GATES_REQUIRED);
|
|
51
|
+
}
|
|
52
|
+
const aggregate = actual.aggregateQaReceipt;
|
|
53
|
+
const directedAggregate = directive.localGates?.aggregateQaReceipt;
|
|
54
|
+
if (!aggregate
|
|
55
|
+
|| aggregate.schemaVersion !== 1
|
|
56
|
+
|| aggregate.evidenceVersion !== 'p205-execution-v2'
|
|
57
|
+
|| aggregate.producer !== 'local-yolo-tdd'
|
|
58
|
+
|| aggregate.contract !== 'P205-CI-02'
|
|
59
|
+
|| aggregate.command !== 'node scripts/test-root.mjs --gate complete'
|
|
60
|
+
|| aggregate.verdict !== 'passed'
|
|
61
|
+
|| aggregate.executionHeadSha !== actual.executionHeadSha
|
|
62
|
+
|| aggregate.executionHeadSha !== directive.expectedExecutionHeadSha
|
|
63
|
+
|| aggregate.graphRevision !== directive.graphRevision
|
|
64
|
+
|| aggregate.receiptRef.length === 0
|
|
65
|
+
|| aggregate.gateIds.length === 0
|
|
66
|
+
|| !isHash(aggregate.manifestDigest)
|
|
67
|
+
|| !isHash(aggregate.resultDigest)
|
|
68
|
+
|| !directedAggregate
|
|
69
|
+
|| directedAggregate.executionHeadSha !== aggregate.executionHeadSha
|
|
70
|
+
|| directedAggregate.graphRevision !== aggregate.graphRevision
|
|
71
|
+
|| directedAggregate.checkedAt !== aggregate.checkedAt
|
|
72
|
+
|| directedAggregate.receiptRef !== aggregate.receiptRef
|
|
73
|
+
|| directedAggregate.manifestDigest !== aggregate.manifestDigest
|
|
74
|
+
|| directedAggregate.resultDigest !== aggregate.resultDigest
|
|
75
|
+
|| !sameSet(directedAggregate.gateIds, aggregate.gateIds)
|
|
76
|
+
|| !directive.localGates.receiptRefs.includes(aggregate.receiptRef)) {
|
|
77
|
+
reasons.push(EPIC_TERMINAL_GIT_REASON_CODES.AGGREGATE_QA_REQUIRED);
|
|
78
|
+
}
|
|
79
|
+
else if (!Number.isFinite(Date.parse(aggregate.checkedAt)) || actual.nowIso && (Date.parse(actual.nowIso) - Date.parse(aggregate.checkedAt) > 30 * 60 * 1000
|
|
80
|
+
|| Date.parse(aggregate.checkedAt) - Date.parse(actual.nowIso) > 5 * 60 * 1000)) {
|
|
81
|
+
reasons.push(EPIC_TERMINAL_GIT_REASON_CODES.AGGREGATE_QA_STALE);
|
|
82
|
+
}
|
|
83
|
+
const originBinding = actual.originBinding;
|
|
84
|
+
if (!originBinding
|
|
85
|
+
|| originBinding.schemaVersion !== 1
|
|
86
|
+
|| originBinding.capturedFromCurrentCheckout !== true
|
|
87
|
+
|| originBinding.originBranch !== directive.originBranch
|
|
88
|
+
|| originBinding.executionBranch !== directive.executionBranch
|
|
89
|
+
|| !isSha(originBinding.originHeadSha)
|
|
90
|
+
|| !Number.isFinite(Date.parse(originBinding.capturedAt))) {
|
|
91
|
+
reasons.push(EPIC_TERMINAL_GIT_REASON_CODES.ORIGIN_BINDING_REQUIRED);
|
|
92
|
+
}
|
|
93
|
+
if (actual.writerLeaseActive)
|
|
94
|
+
reasons.push(EPIC_TERMINAL_GIT_REASON_CODES.LEASE_ACTIVE);
|
|
95
|
+
if (!sameSet(directive.storyCheckpointIds, actual.acceptedCheckpointIds)) {
|
|
96
|
+
reasons.push(EPIC_TERMINAL_GIT_REASON_CODES.STORY_CHECKPOINTS_REQUIRED);
|
|
97
|
+
}
|
|
98
|
+
if (!isSha(directive.expectedExecutionHeadSha) || directive.expectedExecutionHeadSha !== actual.executionHeadSha) {
|
|
99
|
+
reasons.push(EPIC_TERMINAL_GIT_REASON_CODES.HEAD_MISMATCH);
|
|
100
|
+
}
|
|
101
|
+
if (directive.graphRevision && directive.graphRevision !== actual.graphRevision) {
|
|
102
|
+
reasons.push(EPIC_TERMINAL_GIT_REASON_CODES.GRAPH_REVISION_MISMATCH);
|
|
103
|
+
}
|
|
104
|
+
if (!/^[a-f0-9]{64}$/i.test(directive.graphRevision))
|
|
105
|
+
reasons.push(EPIC_TERMINAL_GIT_REASON_CODES.GRAPH_REVISION_MISMATCH);
|
|
106
|
+
if (actual.existingReceipt?.physicalStatus === 'pushed'
|
|
107
|
+
&& actual.existingReceipt.idempotencyKey === directive.idempotencyKey
|
|
108
|
+
&& actual.existingReceipt.executionHeadSha === directive.expectedExecutionHeadSha) {
|
|
109
|
+
return { ready: true, reasonCodes: [EPIC_TERMINAL_GIT_REASON_CODES.ALREADY_COMPLETE] };
|
|
110
|
+
}
|
|
111
|
+
return reasons.length === 0
|
|
112
|
+
? { ready: true, reasonCodes: [EPIC_TERMINAL_GIT_REASON_CODES.READY] }
|
|
113
|
+
: { ready: false, reasonCodes: unique(reasons) };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Fail-closed ownership and integration classifier. A canonical-looking name is
|
|
117
|
+
* never sufficient: state/receipt proof plus convention and provider metadata
|
|
118
|
+
* or PR head/base evidence are required before any destructive action.
|
|
119
|
+
*/
|
|
120
|
+
export function classifyGitReconciliationCandidate(candidate) {
|
|
121
|
+
const evidence = unique(candidate.ownershipEvidence);
|
|
122
|
+
const hasDurableProof = evidence.includes('state_reference') || evidence.includes('terminal_receipt');
|
|
123
|
+
const hasConvention = evidence.includes('canonical_convention');
|
|
124
|
+
const hasCorroboration = candidate.kind === 'pull_request'
|
|
125
|
+
? evidence.includes('pr_head_base_match')
|
|
126
|
+
: evidence.includes('managed_metadata');
|
|
127
|
+
const managed = hasDurableProof && hasConvention && hasCorroboration;
|
|
128
|
+
const preserve = (...reasonCodes) => Object.freeze({
|
|
129
|
+
schemaVersion: 1,
|
|
130
|
+
resourceId: candidate.resourceId,
|
|
131
|
+
action: 'preserve',
|
|
132
|
+
managed,
|
|
133
|
+
reasonCodes: Object.freeze(unique(reasonCodes)),
|
|
134
|
+
evidence: Object.freeze(evidence),
|
|
135
|
+
publicSafe: true,
|
|
136
|
+
});
|
|
137
|
+
if (candidate.lifecycle === 'already_absent' && candidate.providerVerified) {
|
|
138
|
+
return Object.freeze({ schemaVersion: 1, resourceId: candidate.resourceId, action: 'no_op', managed, reasonCodes: [EPIC_TERMINAL_GIT_REASON_CODES.ALREADY_RECONCILED], evidence, publicSafe: true });
|
|
139
|
+
}
|
|
140
|
+
if (!managed)
|
|
141
|
+
return preserve(EPIC_TERMINAL_GIT_REASON_CODES.OWNERSHIP_UNPROVEN);
|
|
142
|
+
if (!candidate.providerVerified)
|
|
143
|
+
return preserve(EPIC_TERMINAL_GIT_REASON_CODES.PROVIDER_TRUTH_UNKNOWN);
|
|
144
|
+
if (candidate.origin)
|
|
145
|
+
return preserve(EPIC_TERMINAL_GIT_REASON_CODES.RESOURCE_ORIGIN);
|
|
146
|
+
if (candidate.current)
|
|
147
|
+
return preserve(EPIC_TERMINAL_GIT_REASON_CODES.RESOURCE_CURRENT);
|
|
148
|
+
if (candidate.worktreeActive)
|
|
149
|
+
return preserve(EPIC_TERMINAL_GIT_REASON_CODES.WORKTREE_ACTIVE);
|
|
150
|
+
if (candidate.protected)
|
|
151
|
+
return preserve(EPIC_TERMINAL_GIT_REASON_CODES.RESOURCE_PROTECTED);
|
|
152
|
+
if (candidate.lifecycle === 'active')
|
|
153
|
+
return preserve(EPIC_TERMINAL_GIT_REASON_CODES.RESOURCE_ACTIVE);
|
|
154
|
+
if (candidate.hasExclusiveCommits)
|
|
155
|
+
return preserve(EPIC_TERMINAL_GIT_REASON_CODES.UNIQUE_COMMITS);
|
|
156
|
+
if (candidate.previouslyReconciled)
|
|
157
|
+
return preserve(EPIC_TERMINAL_GIT_REASON_CODES.RESOURCE_RACED);
|
|
158
|
+
if (!candidate.commitsReachable && !candidate.contentEquivalent) {
|
|
159
|
+
return preserve(EPIC_TERMINAL_GIT_REASON_CODES.INTEGRATION_UNPROVEN);
|
|
160
|
+
}
|
|
161
|
+
// Generic Git deletion has no safe expected-OID guard without force flags.
|
|
162
|
+
// The GitHub capability guards both target and integration origin atomically.
|
|
163
|
+
if (candidate.kind === 'remote_branch' && candidate.remoteDeletionCas !== 'github-update-refs-v1') {
|
|
164
|
+
return preserve(EPIC_TERMINAL_GIT_REASON_CODES.REMOTE_DELETE_CAS_UNAVAILABLE);
|
|
165
|
+
}
|
|
166
|
+
const action = candidate.kind === 'local_branch'
|
|
167
|
+
? 'delete_local_branch'
|
|
168
|
+
: candidate.kind === 'remote_branch' ? 'delete_remote_branch' : 'close_pull_request';
|
|
169
|
+
return Object.freeze({
|
|
170
|
+
schemaVersion: 1,
|
|
171
|
+
resourceId: candidate.resourceId,
|
|
172
|
+
action,
|
|
173
|
+
managed: true,
|
|
174
|
+
reasonCodes: [EPIC_TERMINAL_GIT_REASON_CODES.SAFE_TO_RECONCILE],
|
|
175
|
+
evidence: Object.freeze(evidence),
|
|
176
|
+
publicSafe: true,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
export function reconcileTerminalReceipt(current, requested) {
|
|
180
|
+
if (!current)
|
|
181
|
+
return { kind: 'accepted', receipt: requested };
|
|
182
|
+
if (current.idempotencyKey !== requested.idempotencyKey)
|
|
183
|
+
return { kind: 'accepted', receipt: requested };
|
|
184
|
+
if (current.epicId === requested.epicId
|
|
185
|
+
&& current.executionBranch === requested.executionBranch
|
|
186
|
+
&& current.originBranch === requested.originBranch
|
|
187
|
+
&& current.baseSha === requested.baseSha
|
|
188
|
+
&& current.executionHeadSha === requested.executionHeadSha
|
|
189
|
+
&& current.mergeSha === requested.mergeSha
|
|
190
|
+
&& current.pushedSha === requested.pushedSha
|
|
191
|
+
&& current.physicalStatus === requested.physicalStatus) {
|
|
192
|
+
if (requested.candidateQa && JSON.stringify(current.candidateQa) !== JSON.stringify(requested.candidateQa)) {
|
|
193
|
+
return { kind: 'accepted', receipt: requested };
|
|
194
|
+
}
|
|
195
|
+
if (requested.providerGuard && JSON.stringify(current.providerGuard) !== JSON.stringify(requested.providerGuard)) {
|
|
196
|
+
return { kind: 'accepted', receipt: requested };
|
|
197
|
+
}
|
|
198
|
+
return { kind: 'reused', receipt: current };
|
|
199
|
+
}
|
|
200
|
+
// A failed/prepared attempt is not integrated physical truth. The root has to
|
|
201
|
+
// revalidate a new candidate, but its successful retry must replace that debt.
|
|
202
|
+
// Never rewrite a pushed/merged receipt or move an idempotency key to a new owner.
|
|
203
|
+
if (current.retryEligible && !current.pushedSha
|
|
204
|
+
&& ['prepared', 'blocked_local_or_repo', 'denied_external_gate'].includes(current.physicalStatus)
|
|
205
|
+
&& current.epicId === requested.epicId
|
|
206
|
+
&& current.executionBranch === requested.executionBranch
|
|
207
|
+
&& current.originBranch === requested.originBranch
|
|
208
|
+
&& current.executionHeadSha === requested.executionHeadSha) {
|
|
209
|
+
return { kind: 'accepted', receipt: requested };
|
|
210
|
+
}
|
|
211
|
+
return { kind: 'blocked', reasonCode: 'epic-terminal-receipt-idempotency-conflict' };
|
|
212
|
+
}
|
|
213
|
+
function nonEmpty(value) {
|
|
214
|
+
return typeof value === 'string' && value.trim().length > 0;
|
|
215
|
+
}
|
|
216
|
+
function isSha(value) {
|
|
217
|
+
return /^[a-f0-9]{7,64}$/i.test(value);
|
|
218
|
+
}
|
|
219
|
+
function isHash(value) {
|
|
220
|
+
return typeof value === 'string' && /^[a-f0-9]{64}$/i.test(value);
|
|
221
|
+
}
|
|
222
|
+
function unique(values) {
|
|
223
|
+
return [...new Set(values)];
|
|
224
|
+
}
|
|
225
|
+
function sameSet(left, right) {
|
|
226
|
+
return left.length === right.length && [...left].sort().every((item, index) => item === [...right].sort()[index]);
|
|
227
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* P208.01 -- public-safe planning evidence for intelligent epic waves.
|
|
3
|
+
*
|
|
4
|
+
* This module normalizes evidence only. It never authorizes concurrency or
|
|
5
|
+
* mutates state; the planner must treat `evidence: unknown` conservatively.
|
|
6
|
+
*/
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
export const YOLOOP_PLANNING_GRAPH_VERSION = 1;
|
|
9
|
+
export const YOLOOP_MAX_WRITE_CONCURRENCY = 1;
|
|
10
|
+
const CLAIM_KINDS = new Set([
|
|
11
|
+
'file', 'module', 'contract', 'schema', 'api', 'migration', 'manifest',
|
|
12
|
+
'generated-file', 'lockfile', 'global-state', 'tool', 'service', 'port',
|
|
13
|
+
'database', 'fixture', 'human-gate', 'side-effect',
|
|
14
|
+
]);
|
|
15
|
+
const ACCESSES = new Set(['read', 'write', 'exclusive']);
|
|
16
|
+
const EVIDENCE = new Set(['verified', 'declared', 'unknown']);
|
|
17
|
+
const MAX_CLAIMS = 128;
|
|
18
|
+
const MAX_ATTEMPTS = 32;
|
|
19
|
+
export function normalizeYoloopStoryPlanningEvidence(value) {
|
|
20
|
+
const dependencyBasis = EVIDENCE.has(value?.dependencyBasis)
|
|
21
|
+
? value?.dependencyBasis
|
|
22
|
+
: 'unknown';
|
|
23
|
+
const claims = uniqueSortedClaims((value?.claims ?? []).slice(0, MAX_CLAIMS).map(normalizeClaim));
|
|
24
|
+
const semanticArtifacts = uniqueSortedSemantic((value?.semanticArtifacts ?? []).slice(0, MAX_CLAIMS).map(normalizeSemantic));
|
|
25
|
+
const attempts = normalizeAttempts(value?.attempts ?? []);
|
|
26
|
+
const normalized = {
|
|
27
|
+
schemaVersion: YOLOOP_PLANNING_GRAPH_VERSION,
|
|
28
|
+
dependencyBasis,
|
|
29
|
+
claims,
|
|
30
|
+
semanticArtifacts,
|
|
31
|
+
...(boundedInteger(value?.priority, -1_000, 1_000) !== undefined ? { priority: boundedInteger(value?.priority, -1_000, 1_000) } : {}),
|
|
32
|
+
...(boundedInteger(value?.estimatedCost, 0, 1_000_000) !== undefined ? { estimatedCost: boundedInteger(value?.estimatedCost, 0, 1_000_000) } : {}),
|
|
33
|
+
...(isRisk(value?.risk) ? { risk: value.risk } : { risk: 'unknown' }),
|
|
34
|
+
...(attempts.length > 0 ? { attempts } : {}),
|
|
35
|
+
};
|
|
36
|
+
return { ...normalized, graphRevision: revisionFor(normalized) };
|
|
37
|
+
}
|
|
38
|
+
export function normalizeYoloopPlanningCapacity(value) {
|
|
39
|
+
return {
|
|
40
|
+
supportsReadOnlyParallel: value?.supportsReadOnlyParallel === true,
|
|
41
|
+
supportsIsolatedBuildTest: value?.supportsIsolatedBuildTest === true,
|
|
42
|
+
supportsPreparedBundles: value?.supportsPreparedBundles === true,
|
|
43
|
+
maxPreparationConcurrency: positiveBounded(value?.maxPreparationConcurrency, 1, 64),
|
|
44
|
+
maxBuildTestConcurrency: positiveBounded(value?.maxBuildTestConcurrency, 1, 64),
|
|
45
|
+
maxWriteConcurrency: YOLOOP_MAX_WRITE_CONCURRENCY,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function normalizeYoloopPlanningBudget(value) {
|
|
49
|
+
const maxEstimatedCost = boundedInteger(value?.maxEstimatedCost, 0, 1_000_000);
|
|
50
|
+
const remainingEstimatedCost = boundedInteger(value?.remainingEstimatedCost, 0, 1_000_000);
|
|
51
|
+
return {
|
|
52
|
+
maxStories: positiveBounded(value?.maxStories, 1, 64),
|
|
53
|
+
...(maxEstimatedCost !== undefined ? { maxEstimatedCost } : {}),
|
|
54
|
+
...(remainingEstimatedCost !== undefined ? { remainingEstimatedCost } : {}),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function normalizeClaim(value) {
|
|
58
|
+
const kind = CLAIM_KINDS.has(value.kind) ? value.kind : 'global-state';
|
|
59
|
+
const access = ACCESSES.has(value.access) ? value.access : 'exclusive';
|
|
60
|
+
const evidence = EVIDENCE.has(value.evidence) ? value.evidence : 'unknown';
|
|
61
|
+
const ref = safeRef(value.ref) || 'unknown';
|
|
62
|
+
const globalSensitive = value.globalSensitive === true || isGlobalSensitive(kind, ref);
|
|
63
|
+
return { kind, ref, access, evidence, ...(globalSensitive ? { globalSensitive: true } : {}) };
|
|
64
|
+
}
|
|
65
|
+
function normalizeSemantic(value) {
|
|
66
|
+
return {
|
|
67
|
+
ref: safeRef(value.ref) || 'unknown',
|
|
68
|
+
direction: value.direction === 'produces' || value.direction === 'consumes' ? value.direction : 'consumes',
|
|
69
|
+
evidence: EVIDENCE.has(value.evidence) ? value.evidence : 'unknown',
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function normalizeAttempts(values) {
|
|
73
|
+
return values.slice(-MAX_ATTEMPTS).map((value, index) => ({
|
|
74
|
+
attempt: positiveBounded(value.attempt, index + 1, 1_000_000),
|
|
75
|
+
outcome: ['passed', 'failed', 'blocked', 'cancelled', 'rolled-back'].includes(value.outcome) ? value.outcome : 'blocked',
|
|
76
|
+
reasonCodes: uniqueStrings(value.reasonCodes).slice(0, 32),
|
|
77
|
+
...(value.discoveredClaims ? { discoveredClaims: uniqueSortedClaims(value.discoveredClaims.slice(0, MAX_CLAIMS).map(normalizeClaim)) } : {}),
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
function safeRef(value) {
|
|
81
|
+
if (typeof value !== 'string')
|
|
82
|
+
return '';
|
|
83
|
+
const trimmed = value.trim().replace(/\\/g, '/');
|
|
84
|
+
if (!trimmed || trimmed.length > 240 || trimmed.startsWith('/') || trimmed.includes('..') || /[\u0000-\u001f]/.test(trimmed))
|
|
85
|
+
return '';
|
|
86
|
+
return /^[A-Za-z0-9._/:@#-]+$/.test(trimmed) ? trimmed : '';
|
|
87
|
+
}
|
|
88
|
+
function isGlobalSensitive(kind, ref) {
|
|
89
|
+
return ['migration', 'manifest', 'generated-file', 'lockfile', 'global-state'].includes(kind) ||
|
|
90
|
+
/(^|\/)(package-lock\.json|pnpm-lock\.yaml|yarn\.lock|migrations?|generated)(\/|$)/i.test(ref);
|
|
91
|
+
}
|
|
92
|
+
function uniqueSortedClaims(values) {
|
|
93
|
+
return uniqueBy(values, (value) => `${value.kind}:${value.ref}:${value.access}:${value.evidence}:${value.globalSensitive === true}`)
|
|
94
|
+
.sort((a, b) => `${a.kind}:${a.ref}:${a.access}`.localeCompare(`${b.kind}:${b.ref}:${b.access}`));
|
|
95
|
+
}
|
|
96
|
+
function uniqueSortedSemantic(values) {
|
|
97
|
+
return uniqueBy(values, (value) => `${value.ref}:${value.direction}:${value.evidence}`)
|
|
98
|
+
.sort((a, b) => `${a.ref}:${a.direction}`.localeCompare(`${b.ref}:${b.direction}`));
|
|
99
|
+
}
|
|
100
|
+
function uniqueStrings(values) {
|
|
101
|
+
return [...new Set(values.map(safeRef).filter(Boolean))].sort((a, b) => a.localeCompare(b));
|
|
102
|
+
}
|
|
103
|
+
function uniqueBy(values, key) {
|
|
104
|
+
const seen = new Set();
|
|
105
|
+
return values.filter((value) => { const next = key(value); if (seen.has(next))
|
|
106
|
+
return false; seen.add(next); return true; });
|
|
107
|
+
}
|
|
108
|
+
function isRisk(value) {
|
|
109
|
+
return value === 'low' || value === 'normal' || value === 'high' || value === 'critical' || value === 'unknown';
|
|
110
|
+
}
|
|
111
|
+
function boundedInteger(value, min, max) {
|
|
112
|
+
return typeof value === 'number' && Number.isInteger(value) && value >= min && value <= max ? value : undefined;
|
|
113
|
+
}
|
|
114
|
+
function positiveBounded(value, fallback, max) {
|
|
115
|
+
return boundedInteger(value, 1, max) ?? fallback;
|
|
116
|
+
}
|
|
117
|
+
function revisionFor(value) {
|
|
118
|
+
return createHash('sha256').update(JSON.stringify(value)).digest('hex');
|
|
119
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { normalizeContinuousWriteRef } from './wave-decision-receipt.js';
|
|
2
|
+
export function publicWriteSet(story) {
|
|
3
|
+
const claimRefs = (story.planning?.claims ?? [])
|
|
4
|
+
.filter((claim) => claim.access !== 'read' && claim.evidence === 'verified')
|
|
5
|
+
.map((claim) => claim.ref);
|
|
6
|
+
const authoredRefs = [
|
|
7
|
+
...claimRefs,
|
|
8
|
+
...(story.files_to_modify ?? []),
|
|
9
|
+
...(story.contracts ?? []),
|
|
10
|
+
...(story.contract_refs ?? []),
|
|
11
|
+
...(story.shared_surfaces ?? []),
|
|
12
|
+
].map(normalizeContinuousWriteRef);
|
|
13
|
+
// Never reduce an invalid authored scope to only the lifecycle paths.
|
|
14
|
+
if (authoredRefs.some((ref) => ref === undefined))
|
|
15
|
+
return [];
|
|
16
|
+
return [...new Set([
|
|
17
|
+
'.neocortex/state.json',
|
|
18
|
+
`docs/stories/${safeRef(story.id)}.story.md`,
|
|
19
|
+
...authoredRefs,
|
|
20
|
+
])].sort();
|
|
21
|
+
}
|
|
22
|
+
function safeRef(value) {
|
|
23
|
+
if (typeof value !== 'string')
|
|
24
|
+
return '';
|
|
25
|
+
const normalized = value.trim().replace(/\\/g, '/');
|
|
26
|
+
return normalized && normalized.length <= 240 && !normalized.startsWith('/') && !normalized.includes('..') && /^[A-Za-z0-9._/:@#-]+$/.test(normalized) ? normalized : '';
|
|
27
|
+
}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
/** P208.03 -- public-safe deterministic planning DecisionReceipts. */
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
|
+
/** Canonical public write-path boundary, shipped with bundle admission to every client. */
|
|
4
|
+
export function normalizeContinuousWriteRef(value) {
|
|
5
|
+
if (typeof value !== 'string')
|
|
6
|
+
return undefined;
|
|
7
|
+
const normalized = value.replace(/\\/g, '/');
|
|
8
|
+
if (!normalized || normalized.length > 240 || normalized.startsWith('/')
|
|
9
|
+
|| /^[A-Za-z]:/.test(normalized) || normalized.includes('..') || normalized.includes('//')
|
|
10
|
+
|| normalized.split('/').includes('.') || !/^[A-Za-z0-9._/:@#-]+$/.test(normalized))
|
|
11
|
+
return undefined;
|
|
12
|
+
return normalized;
|
|
13
|
+
}
|
|
3
14
|
export const YOLOOP_WAVE_DECISION_RECEIPT_VERSION = 1;
|
|
4
15
|
export function createYoloopWaveDecisionReceipt(input) {
|
|
5
16
|
const epicId = requireId(input.epicId, 'epic-id-invalid');
|
|
@@ -42,6 +53,13 @@ export function validateYoloopPreparationBundle(bundle, expected) {
|
|
|
42
53
|
errors.push('bundle-graph-stale');
|
|
43
54
|
if (![bundle.baseSha, bundle.bundleDigest, bundle.graphRevision, bundle.claimRevision].every(isHash))
|
|
44
55
|
errors.push('bundle-digest-invalid');
|
|
56
|
+
if (!Array.isArray(bundle.authorizedWriteSet) || bundle.authorizedWriteSet.length === 0
|
|
57
|
+
|| bundle.authorizedWriteSet.some((ref) => typeof ref !== 'string' || normalizeContinuousWriteRef(ref) !== ref)
|
|
58
|
+
|| expected.authorizedWriteSet && !sameStrings(bundle.authorizedWriteSet, expected.authorizedWriteSet))
|
|
59
|
+
errors.push('bundle-write-set-invalid');
|
|
60
|
+
if (!bundle.contextDigests || typeof bundle.contextDigests !== 'object'
|
|
61
|
+
|| Object.entries(bundle.contextDigests).some(([path, digest]) => normalizeContinuousWriteRef(path) !== path || !isHash(digest)))
|
|
62
|
+
errors.push('bundle-context-digests-invalid');
|
|
45
63
|
if (!isTimestamp(bundle.createdAt) || !isTimestamp(bundle.expiresAt) || bundle.expiresAt <= expected.nowIso || bundle.expiresAt <= bundle.createdAt)
|
|
46
64
|
errors.push('bundle-expired');
|
|
47
65
|
if (!Array.isArray(bundle.validationRefs) || bundle.validationRefs.length === 0 || bundle.validationRefs.some((ref) => !isSafeRef(ref)))
|
|
@@ -75,3 +93,4 @@ function isHash(value) { return /^[a-f0-9]{40,64}$/.test(value); }
|
|
|
75
93
|
function isTimestamp(value) { return typeof value === 'string' && Number.isFinite(Date.parse(value)); }
|
|
76
94
|
function isSafeRef(value) { return typeof value === 'string' && value.length > 0 && value.length <= 200 && !value.startsWith('/') && !value.includes('..') && /^[A-Za-z0-9._/:@#-]+$/.test(value); }
|
|
77
95
|
function uniqueSafe(values) { return Object.freeze([...new Set(values)].sort()); }
|
|
96
|
+
function sameStrings(left, right) { return left.length === right.length && left.every((value, index) => value === right[index]); }
|
|
@@ -52,3 +52,21 @@ history, ambient metadata, raw logs, or raw stdout/stderr into this profile. Do
|
|
|
52
52
|
not pass unmanaged user-owned content. Do not embed, reveal, summarize, or reconstruct proprietary prompts, server-side
|
|
53
53
|
implementation details, orchestration logic, secrets, license keys, or customer
|
|
54
54
|
data. This child must not invoke another Neocortex child.
|
|
55
|
+
|
|
56
|
+
At the root only, `epicTerminalGitDirective` uses the recorded origin and
|
|
57
|
+
forbids worktree management, force-push and ambiguous/unintegrated cleanup.
|
|
58
|
+
`epicGitReconciliationDirective` runs fail-closed before start/resume children
|
|
59
|
+
and supports explicit `dryRun` audit without Git effects.
|
|
60
|
+
Terminal effects require a fresh aggregate-QA receipt bound to the exact physical
|
|
61
|
+
execution HEAD/current graph and an immutable physical origin binding. PR reuse
|
|
62
|
+
and cleanup revalidate exact SHAs and fresh provider/ref truth immediately before
|
|
63
|
+
effects; active, manual-worktree, ambiguous, protected or raced resources remain.
|
|
64
|
+
Post-commit lease/checkpoint and physical receipts use the fsync/CAS runtime store
|
|
65
|
+
in a private user-owned directory inside the Git common-dir, never a tracked-state rewrite. Accepted story checkpoints
|
|
66
|
+
require independent typed QA and root commit-range review receipts bound to the
|
|
67
|
+
story, commit range, bundle digest and graph revision; fresh physical recomputation is authoritative and generic receipts cannot
|
|
68
|
+
authorize pass/approval. Persisted merge state never replaces fresh root physical
|
|
69
|
+
verification when a terminal-complete response carries the terminal directive.
|
|
70
|
+
Remote branch deletion is
|
|
71
|
+
preserved with `git-resource-remote-delete-cas-unavailable` when no OID-bound
|
|
72
|
+
provider primitive exists; local refs and PRs still reconcile when fully proven.
|