@ornexus/neocortex 4.60.65 → 4.60.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/release-source.json +1 -1
  2. package/dist/sbom.cdx.json +1598 -1640
  3. package/install.ps1 +1 -1
  4. package/install.sh +2 -1
  5. package/package.json +17 -7
  6. package/packages/client/dist/cli.js +15 -2
  7. package/packages/client/dist/commands/architecture-root-binding.js +1 -1
  8. package/packages/client/dist/commands/doctor.d.ts +135 -0
  9. package/packages/client/dist/commands/doctor.js +2 -0
  10. package/packages/client/dist/commands/invoke.d.ts +19 -1
  11. package/packages/client/dist/commands/invoke.js +83 -82
  12. package/packages/client/dist/commands/story-checkpoint.d.ts +3 -1
  13. package/packages/client/dist/commands/story-checkpoint.js +1 -1
  14. package/packages/client/dist/continuity/sqlite-store.js +1 -1
  15. package/packages/client/dist/git/direct-yolo-c01-retry.d.ts +21 -0
  16. package/packages/client/dist/git/direct-yolo-c01-retry.js +4 -0
  17. package/packages/client/dist/git/direct-yolo-checkpoint.d.ts +1 -5
  18. package/packages/client/dist/git/direct-yolo-checkpoint.js +4 -4
  19. package/packages/client/dist/git/git-lifecycle-store.d.ts +0 -2
  20. package/packages/client/dist/git/git-lifecycle-store.js +8 -9
  21. package/packages/client/dist/private-execution/clean-baseline.d.ts +2 -3
  22. package/packages/client/dist/private-execution/clean-baseline.js +2 -2
  23. package/packages/client/dist/private-execution/isolated-admission.d.ts +2 -0
  24. package/packages/client/dist/private-execution/isolated-admission.js +16 -11
  25. package/packages/client/dist/runner/headless/run-yoloop.d.ts +4 -1
  26. package/packages/client/dist/runner/headless/run-yoloop.js +2 -2
  27. package/packages/client/dist/runner-cli.js +0 -0
  28. package/packages/client/dist/yolo/invoke-envelope-capability.d.ts +16 -0
  29. package/packages/client/dist/yolo/invoke-envelope-capability.js +1 -0
  30. package/packages/client/dist/yolo/spec-envelope-collector.d.ts +7 -0
  31. package/packages/client/dist/yolo/spec-envelope-collector.js +3 -3
  32. package/packages/shared/dist/architecture-non-ui-scope.js +22 -0
  33. package/packages/shared/dist/architecture-public-topology.js +11 -0
  34. package/packages/shared/dist/compatibility/index.js +476 -0
  35. package/packages/shared/dist/invocation/index.js +4 -2
  36. package/packages/shared/dist/private-qa-structural-admission.js +14 -0
  37. package/packages/shared/dist/private-yolo-predecessor-decision.js +32 -0
  38. package/packages/shared/dist/project-validation-commands.js +74 -0
  39. package/packages/shared/dist/yolo/spec-envelope.js +2 -0
  40. package/packages/shared/dist/yoloop/release-blocked.js +653 -0
  41. package/targets-stubs/antigravity/gemini.md +1 -1
  42. package/targets-stubs/antigravity/skill/SKILL.md +3 -2
  43. package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
  44. package/targets-stubs/claude-code/neocortex-root.md +5 -5
  45. package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
  46. package/targets-stubs/claude-code/neocortex.md +8 -9
  47. package/targets-stubs/codex/AGENTS.md +3 -3
  48. package/targets-stubs/cursor/agent.md +4 -3
  49. package/targets-stubs/gemini-cli/agent.md +5 -4
  50. package/targets-stubs/opencode/neocortex-root.md +3 -3
  51. package/targets-stubs/vscode/neocortex.agent.md +5 -4
@@ -0,0 +1,476 @@
1
+ /**
2
+ * Public compatibility and release-lifecycle contracts.
3
+ *
4
+ * This module is deliberately pure. It accepts only bounded public metadata and
5
+ * never reads protected response fields, project state, clocks, or environment.
6
+ */
7
+ import { createHash } from 'node:crypto';
8
+ export const COMPATIBILITY_OFFER_SCHEMA = 'CompatibilityOffer/1.0';
9
+ export const COMPATIBILITY_RESULT_SCHEMA = 'CompatibilityResult/1.0';
10
+ export const RELEASE_LIFECYCLE_SCHEMA = 'ReleaseLifecycle/1.0';
11
+ export const RELEASE_LIFECYCLE_CONTEXT_SCHEMA = 'ReleaseLifecycleContext/1.0';
12
+ export const INVOKE_PROTOCOL_VERSION = 'invoke/1';
13
+ export const COMPATIBILITY_CAPABILITIES = Object.freeze({
14
+ INVOKE_CORE: 'invoke-core-v1',
15
+ PUBLIC_SAFE_DIAGNOSTICS: 'public-safe-diagnostics-v1',
16
+ PROTECTED_RESPONSE_GUARD: 'protected-response-guard-v1',
17
+ RELEASE_LIFECYCLE: 'release-lifecycle-v1',
18
+ RELEASE_BLOCKED_TERMINAL: 'release-blocked-terminal-v1',
19
+ REVIEW_RECONCILIATION: 'review-reconciliation-v1',
20
+ });
21
+ export const COMPATIBILITY_SCHEMAS = Object.freeze({
22
+ INVOKE_REQUEST: 'invoke-request/1',
23
+ INVOKE_RESPONSE: 'invoke-response/1',
24
+ RELEASE_LIFECYCLE: RELEASE_LIFECYCLE_SCHEMA,
25
+ RELEASE_BLOCKED: 'ReleaseBlockedResult/1.0',
26
+ REVIEW_RECONCILIATION: 'ReviewReconciliation/1',
27
+ });
28
+ export const COMPATIBILITY_REASON_CODES = Object.freeze({
29
+ COMPATIBLE: 'compatibility-compatible',
30
+ OPTIONAL_PROJECTION_OMITTED: 'compatibility-optional-projection-omitted',
31
+ LEGACY_OFFER_MISSING: 'compatibility-legacy-offer-missing',
32
+ SERVER_NEGOTIATION_MISSING: 'compatibility-server-negotiation-missing',
33
+ OFFER_MALFORMED: 'compatibility-offer-malformed',
34
+ CLIENT_VERSION_UNKNOWN: 'compatibility-client-version-unknown',
35
+ SERVER_VERSION_UNKNOWN: 'compatibility-server-version-unknown',
36
+ PROTOCOL_MISMATCH: 'compatibility-protocol-mismatch',
37
+ REQUIRED_SCHEMA_MISSING: 'compatibility-required-schema-missing',
38
+ REQUIRED_CAPABILITY_MISSING: 'compatibility-required-capability-missing',
39
+ SECURITY_CAPABILITY_MISSING: 'compatibility-security-capability-missing',
40
+ REGISTRY_VERSION_MISMATCH: 'compatibility-registry-version-mismatch',
41
+ REGISTRY_CHECKSUM_MISMATCH: 'compatibility-registry-checksum-mismatch',
42
+ RESULT_MALFORMED: 'compatibility-result-malformed',
43
+ UNNEGOTIATED_PROTECTED_FIELD: 'compatibility-unnegotiated-protected-field',
44
+ });
45
+ const VERSION = /^\d{1,6}\.\d{1,6}\.\d{1,6}(?:[-+][A-Za-z0-9.-]{1,40})?$/u;
46
+ const IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._/-]{0,79}$/u;
47
+ const REGISTRY_VERSION = /^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$/u;
48
+ const SHA256 = /^[a-f0-9]{64}$/u;
49
+ const PROJECT_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{15,127}$/u;
50
+ const MAX_NEGOTIATED_ITEMS = 32;
51
+ function uniqueSorted(values) {
52
+ return [...new Set(values)].sort((left, right) => left.localeCompare(right));
53
+ }
54
+ function hasOnlyKeys(value, allowed) {
55
+ const keys = Object.keys(value);
56
+ return keys.length <= allowed.length && keys.every((key) => allowed.includes(key));
57
+ }
58
+ function isBoundedIdentifiers(value) {
59
+ return Array.isArray(value)
60
+ && value.length <= MAX_NEGOTIATED_ITEMS
61
+ && value.every((entry) => typeof entry === 'string' && IDENTIFIER.test(entry));
62
+ }
63
+ export function isCompatibilityOfferV1(value) {
64
+ if (!value || typeof value !== 'object' || Array.isArray(value))
65
+ return false;
66
+ const offer = value;
67
+ const registry = offer.commandRegistry;
68
+ return hasOnlyKeys(offer, ['schemaVersion', 'clientVersion', 'protocolVersions', 'schemaVersions', 'capabilityIds', 'commandRegistry', 'publicSafe'])
69
+ && offer.schemaVersion === COMPATIBILITY_OFFER_SCHEMA
70
+ && typeof offer.clientVersion === 'string' && VERSION.test(offer.clientVersion)
71
+ && isBoundedIdentifiers(offer.protocolVersions) && offer.protocolVersions.length > 0
72
+ && isBoundedIdentifiers(offer.schemaVersions) && offer.schemaVersions.length > 0
73
+ && isBoundedIdentifiers(offer.capabilityIds) && offer.capabilityIds.length > 0
74
+ && !!registry && typeof registry === 'object' && !Array.isArray(registry)
75
+ && hasOnlyKeys(registry, ['version', 'checksum'])
76
+ && typeof registry.version === 'string' && REGISTRY_VERSION.test(registry.version)
77
+ && typeof registry.checksum === 'string' && SHA256.test(registry.checksum)
78
+ && offer.publicSafe === true;
79
+ }
80
+ export function createCompatibilityOffer(input) {
81
+ const offer = {
82
+ schemaVersion: COMPATIBILITY_OFFER_SCHEMA,
83
+ clientVersion: input.clientVersion,
84
+ protocolVersions: uniqueSorted(input.protocolVersions ?? [INVOKE_PROTOCOL_VERSION]),
85
+ schemaVersions: uniqueSorted(input.schemaVersions ?? Object.values(COMPATIBILITY_SCHEMAS)),
86
+ capabilityIds: uniqueSorted(input.capabilityIds ?? Object.values(COMPATIBILITY_CAPABILITIES)),
87
+ commandRegistry: { version: input.registryVersion, checksum: input.registryChecksum },
88
+ publicSafe: true,
89
+ };
90
+ if (!isCompatibilityOfferV1(offer))
91
+ throw new Error('compatibility-offer-invalid');
92
+ return Object.freeze({
93
+ ...offer,
94
+ protocolVersions: Object.freeze([...offer.protocolVersions]),
95
+ schemaVersions: Object.freeze([...offer.schemaVersions]),
96
+ capabilityIds: Object.freeze([...offer.capabilityIds]),
97
+ commandRegistry: Object.freeze({ ...offer.commandRegistry }),
98
+ });
99
+ }
100
+ function result(input) {
101
+ return Object.freeze({
102
+ schemaVersion: COMPATIBILITY_RESULT_SCHEMA,
103
+ ...input,
104
+ schemaVersions: Object.freeze([...input.schemaVersions]),
105
+ capabilityIds: Object.freeze([...input.capabilityIds]),
106
+ commandRegistry: Object.freeze({ ...input.commandRegistry }),
107
+ projection: Object.freeze({ ...input.projection, omittedFields: Object.freeze([...input.projection.omittedFields]) }),
108
+ reasonCodes: Object.freeze([...input.reasonCodes]),
109
+ publicSafe: true,
110
+ });
111
+ }
112
+ export function negotiateCompatibility(rawOffer, policy) {
113
+ const serverVersionValid = VERSION.test(policy.serverVersion);
114
+ const safeServerVersion = serverVersionValid ? policy.serverVersion : '0.0.0';
115
+ if (!isCompatibilityOfferV1(rawOffer)) {
116
+ const unknownClientVersion = !!rawOffer && typeof rawOffer === 'object' && !Array.isArray(rawOffer)
117
+ && rawOffer.schemaVersion === COMPATIBILITY_OFFER_SCHEMA
118
+ && (typeof rawOffer.clientVersion !== 'string'
119
+ || !VERSION.test(rawOffer.clientVersion));
120
+ return result({
121
+ status: 'incompatible', clientVersion: '0.0.0', serverVersion: safeServerVersion,
122
+ protocolVersion: null, schemaVersions: [], capabilityIds: [],
123
+ commandRegistry: { version: policy.commandRegistry.version, checksum: policy.commandRegistry.checksum, status: 'unknown' },
124
+ projection: { status: 'none', omittedFields: ['releaseBlocked', 'releaseLifecycle', 'reviewReconciliation'] },
125
+ reasonCodes: [unknownClientVersion
126
+ ? COMPATIBILITY_REASON_CODES.CLIENT_VERSION_UNKNOWN
127
+ : COMPATIBILITY_REASON_CODES.OFFER_MALFORMED], remediationHint: 'upgrade-client',
128
+ });
129
+ }
130
+ const offer = rawOffer;
131
+ const reasons = [];
132
+ const has = (values, expected) => values.includes(expected);
133
+ if (!serverVersionValid)
134
+ reasons.push(COMPATIBILITY_REASON_CODES.SERVER_VERSION_UNKNOWN);
135
+ if (!has(offer.protocolVersions, policy.protocolVersion))
136
+ reasons.push(COMPATIBILITY_REASON_CODES.PROTOCOL_MISMATCH);
137
+ if (policy.requiredSchemaVersions.some((schema) => !has(offer.schemaVersions, schema))) {
138
+ reasons.push(COMPATIBILITY_REASON_CODES.REQUIRED_SCHEMA_MISSING);
139
+ }
140
+ const missingRequiredCapabilities = policy.requiredCapabilityIds.filter((capability) => !has(offer.capabilityIds, capability));
141
+ if (missingRequiredCapabilities.length > 0)
142
+ reasons.push(COMPATIBILITY_REASON_CODES.REQUIRED_CAPABILITY_MISSING);
143
+ if (policy.securityCapabilityIds.some((capability) => !has(offer.capabilityIds, capability))) {
144
+ reasons.push(COMPATIBILITY_REASON_CODES.SECURITY_CAPABILITY_MISSING);
145
+ }
146
+ if (offer.commandRegistry.version !== policy.commandRegistry.version) {
147
+ reasons.push(COMPATIBILITY_REASON_CODES.REGISTRY_VERSION_MISMATCH);
148
+ }
149
+ if (offer.commandRegistry.checksum !== policy.commandRegistry.checksum) {
150
+ reasons.push(COMPATIBILITY_REASON_CODES.REGISTRY_CHECKSUM_MISMATCH);
151
+ }
152
+ const incompatible = reasons.length > 0;
153
+ const supportedSchemas = uniqueSorted(policy.requiredSchemaVersions.concat(policy.optionalSchemaVersions.filter((schema) => has(offer.schemaVersions, schema))));
154
+ const supportedCapabilities = uniqueSorted(policy.requiredCapabilityIds.concat(policy.optionalCapabilityIds.filter((capability) => has(offer.capabilityIds, capability))));
155
+ const omittedFields = [];
156
+ if (!has(offer.capabilityIds, COMPATIBILITY_CAPABILITIES.RELEASE_LIFECYCLE)
157
+ || !has(offer.schemaVersions, COMPATIBILITY_SCHEMAS.RELEASE_LIFECYCLE))
158
+ omittedFields.push('releaseLifecycle');
159
+ if (!has(offer.capabilityIds, COMPATIBILITY_CAPABILITIES.RELEASE_BLOCKED_TERMINAL)
160
+ || !has(offer.schemaVersions, COMPATIBILITY_SCHEMAS.RELEASE_BLOCKED))
161
+ omittedFields.push('releaseBlocked');
162
+ if (!has(offer.capabilityIds, COMPATIBILITY_CAPABILITIES.REVIEW_RECONCILIATION)
163
+ || !has(offer.schemaVersions, COMPATIBILITY_SCHEMAS.REVIEW_RECONCILIATION))
164
+ omittedFields.push('reviewReconciliation');
165
+ if (incompatible) {
166
+ const registryMismatch = reasons.includes(COMPATIBILITY_REASON_CODES.REGISTRY_VERSION_MISMATCH)
167
+ || reasons.includes(COMPATIBILITY_REASON_CODES.REGISTRY_CHECKSUM_MISMATCH);
168
+ return result({
169
+ status: 'incompatible', clientVersion: offer.clientVersion, serverVersion: safeServerVersion,
170
+ protocolVersion: null, schemaVersions: supportedSchemas, capabilityIds: supportedCapabilities,
171
+ commandRegistry: {
172
+ version: policy.commandRegistry.version, checksum: policy.commandRegistry.checksum,
173
+ status: registryMismatch ? 'mismatched' : 'matched',
174
+ },
175
+ projection: { status: 'none', omittedFields: ['releaseBlocked', 'releaseLifecycle', 'reviewReconciliation'] },
176
+ reasonCodes: uniqueSorted(reasons),
177
+ remediationHint: registryMismatch ? 'align-command-registry' : 'upgrade-client',
178
+ });
179
+ }
180
+ const degraded = omittedFields.length > 0;
181
+ return result({
182
+ status: degraded ? 'degraded' : 'compatible',
183
+ clientVersion: offer.clientVersion, serverVersion: safeServerVersion,
184
+ protocolVersion: policy.protocolVersion, schemaVersions: supportedSchemas,
185
+ capabilityIds: supportedCapabilities,
186
+ commandRegistry: { version: policy.commandRegistry.version, checksum: policy.commandRegistry.checksum, status: 'matched' },
187
+ projection: { status: degraded ? 'reduced' : 'full', omittedFields: uniqueSorted(omittedFields) },
188
+ reasonCodes: degraded
189
+ ? [COMPATIBILITY_REASON_CODES.OPTIONAL_PROJECTION_OMITTED]
190
+ : [COMPATIBILITY_REASON_CODES.COMPATIBLE],
191
+ remediationHint: degraded ? 'retry-supported-projection' : 'none',
192
+ });
193
+ }
194
+ export function createLegacyCompatibilityResult(input) {
195
+ return result({
196
+ status: 'degraded',
197
+ clientVersion: input.clientVersion && VERSION.test(input.clientVersion) ? input.clientVersion : '0.0.0',
198
+ serverVersion: VERSION.test(input.serverVersion) ? input.serverVersion : '0.0.0',
199
+ protocolVersion: INVOKE_PROTOCOL_VERSION,
200
+ schemaVersions: [COMPATIBILITY_SCHEMAS.INVOKE_REQUEST, COMPATIBILITY_SCHEMAS.INVOKE_RESPONSE],
201
+ capabilityIds: [COMPATIBILITY_CAPABILITIES.INVOKE_CORE, COMPATIBILITY_CAPABILITIES.PUBLIC_SAFE_DIAGNOSTICS],
202
+ commandRegistry: { version: input.registryVersion, checksum: input.registryChecksum, status: 'unknown' },
203
+ projection: { status: 'reduced', omittedFields: ['releaseBlocked', 'releaseLifecycle', 'reviewReconciliation'] },
204
+ reasonCodes: [input.reason ?? COMPATIBILITY_REASON_CODES.LEGACY_OFFER_MISSING],
205
+ remediationHint: 'retry-supported-projection',
206
+ });
207
+ }
208
+ const COMPATIBILITY_STATUSES = new Set(['compatible', 'degraded', 'incompatible']);
209
+ const PROJECTION_STATUSES = new Set(['full', 'reduced', 'none']);
210
+ const REMEDIATIONS = new Set(['none', 'upgrade-client', 'retry-supported-projection', 'align-command-registry', 'contact-support']);
211
+ const REASONS = new Set(Object.values(COMPATIBILITY_REASON_CODES));
212
+ const OPTIONAL_FIELDS = new Set(['releaseBlocked', 'releaseLifecycle', 'reviewReconciliation']);
213
+ export function isCompatibilityResultV1(value) {
214
+ if (!value || typeof value !== 'object' || Array.isArray(value))
215
+ return false;
216
+ const candidate = value;
217
+ const registry = candidate.commandRegistry;
218
+ const projection = candidate.projection;
219
+ const status = candidate.status;
220
+ const projectionStatus = projection?.status;
221
+ const remediation = candidate.remediationHint;
222
+ return hasOnlyKeys(candidate, ['schemaVersion', 'status', 'clientVersion', 'serverVersion', 'protocolVersion', 'schemaVersions', 'capabilityIds', 'commandRegistry', 'projection', 'reasonCodes', 'remediationHint', 'publicSafe'])
223
+ && candidate.schemaVersion === COMPATIBILITY_RESULT_SCHEMA
224
+ && COMPATIBILITY_STATUSES.has(candidate.status)
225
+ && typeof candidate.clientVersion === 'string' && VERSION.test(candidate.clientVersion)
226
+ && typeof candidate.serverVersion === 'string' && VERSION.test(candidate.serverVersion)
227
+ && (candidate.protocolVersion === null || typeof candidate.protocolVersion === 'string' && IDENTIFIER.test(candidate.protocolVersion))
228
+ && isBoundedIdentifiers(candidate.schemaVersions) && isBoundedIdentifiers(candidate.capabilityIds)
229
+ && !!registry && hasOnlyKeys(registry, ['version', 'checksum', 'status'])
230
+ && typeof registry.version === 'string' && REGISTRY_VERSION.test(registry.version)
231
+ && typeof registry.checksum === 'string' && SHA256.test(registry.checksum)
232
+ && ['matched', 'mismatched', 'unknown'].includes(String(registry.status))
233
+ && !!projection && hasOnlyKeys(projection, ['status', 'omittedFields'])
234
+ && PROJECTION_STATUSES.has(projectionStatus)
235
+ && Array.isArray(projection.omittedFields) && projection.omittedFields.length <= 3
236
+ && projection.omittedFields.every((field) => OPTIONAL_FIELDS.has(field))
237
+ && Array.isArray(candidate.reasonCodes) && candidate.reasonCodes.length > 0 && candidate.reasonCodes.length <= 12
238
+ && candidate.reasonCodes.every((reason) => typeof reason === 'string' && REASONS.has(reason))
239
+ && REMEDIATIONS.has(remediation)
240
+ && (status !== 'compatible' || projectionStatus === 'full' && remediation === 'none')
241
+ && (status !== 'degraded' || projectionStatus === 'reduced')
242
+ && (status !== 'incompatible' || projectionStatus === 'none')
243
+ && candidate.publicSafe === true;
244
+ }
245
+ /** Omit only explicitly optional fields. Required/security fields are never downgraded. */
246
+ export function projectInvokePayloadForCompatibility(payload, decision) {
247
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload) || decision.status === 'incompatible')
248
+ return payload;
249
+ const root = { ...payload };
250
+ if (root.metadata && typeof root.metadata === 'object' && !Array.isArray(root.metadata)) {
251
+ const metadata = { ...root.metadata };
252
+ for (const field of decision.projection.omittedFields) {
253
+ delete metadata[field];
254
+ if (field === 'releaseLifecycle')
255
+ delete metadata.release_lifecycle;
256
+ if (field === 'releaseBlocked') {
257
+ delete metadata.release_blocked;
258
+ delete metadata.yoloopReleaseBlocked;
259
+ delete metadata.releaseBlockedReason;
260
+ delete metadata.releaseBlockedResume;
261
+ }
262
+ if (field === 'reviewReconciliation') {
263
+ delete metadata.review_reconciliation;
264
+ delete metadata.reconciliationMetadata;
265
+ }
266
+ }
267
+ root.metadata = metadata;
268
+ }
269
+ for (const field of decision.projection.omittedFields) {
270
+ delete root[field];
271
+ if (field === 'releaseLifecycle')
272
+ delete root.release_lifecycle;
273
+ if (field === 'releaseBlocked')
274
+ delete root.release_blocked;
275
+ if (field === 'reviewReconciliation') {
276
+ delete root.review_reconciliation;
277
+ delete root.reconciliationMetadata;
278
+ }
279
+ }
280
+ return root;
281
+ }
282
+ function releaseLifecycleContextDigest(input) {
283
+ return createHash('sha256')
284
+ .update('release-lifecycle-context-v1\0')
285
+ .update(input.projectId)
286
+ .update('\0')
287
+ .update(input.candidateId)
288
+ .update('\0')
289
+ .update(input.lineageSha256)
290
+ .digest('hex');
291
+ }
292
+ export function createReleaseLifecycleContext(input) {
293
+ const context = {
294
+ schemaVersion: RELEASE_LIFECYCLE_CONTEXT_SCHEMA,
295
+ projectId: input.projectId,
296
+ candidateId: input.candidateId,
297
+ lineageSha256: input.lineageSha256,
298
+ contextDigestSha256: releaseLifecycleContextDigest(input),
299
+ publicSafe: true,
300
+ };
301
+ if (!isReleaseLifecycleContextV1(context))
302
+ throw new Error('release-lifecycle-context-invalid');
303
+ return Object.freeze(context);
304
+ }
305
+ export function isReleaseLifecycleContextV1(value) {
306
+ if (!value || typeof value !== 'object' || Array.isArray(value))
307
+ return false;
308
+ const context = value;
309
+ if (!hasOnlyKeys(context, [
310
+ 'schemaVersion', 'projectId', 'candidateId', 'lineageSha256', 'contextDigestSha256', 'publicSafe',
311
+ ])
312
+ || context.schemaVersion !== RELEASE_LIFECYCLE_CONTEXT_SCHEMA
313
+ || typeof context.projectId !== 'string' || !PROJECT_ID.test(context.projectId)
314
+ || typeof context.candidateId !== 'string' || !CANDIDATE_ID.test(context.candidateId)
315
+ || typeof context.lineageSha256 !== 'string' || !SHA256.test(context.lineageSha256)
316
+ || typeof context.contextDigestSha256 !== 'string' || !SHA256.test(context.contextDigestSha256)
317
+ || context.publicSafe !== true)
318
+ return false;
319
+ return context.contextDigestSha256 === releaseLifecycleContextDigest({
320
+ projectId: context.projectId,
321
+ candidateId: context.candidateId,
322
+ lineageSha256: context.lineageSha256,
323
+ });
324
+ }
325
+ export const RELEASE_LIFECYCLE_REASON_CODES = Object.freeze({
326
+ VERIFIED: 'release-evidence-verified',
327
+ NOT_SATISFIED: 'release-gate-not-satisfied',
328
+ EVIDENCE_UNAVAILABLE: 'release-evidence-unavailable',
329
+ MALFORMED: 'release-lifecycle-malformed',
330
+ CANDIDATE_MISMATCH: 'release-candidate-mismatch',
331
+ LINEAGE_MISMATCH: 'release-lineage-mismatch',
332
+ FRESHNESS_STALE: 'release-evidence-stale',
333
+ FRESHNESS_UNKNOWN: 'release-evidence-freshness-unknown',
334
+ FUTURE_OBSERVATION: 'release-evidence-future-observation',
335
+ EVIDENCE_REF_INVALID: 'release-evidence-ref-invalid',
336
+ EVIDENCE_REPLAYED: 'release-evidence-replayed',
337
+ IMPLEMENTATION_RECEIPT_MISSING: 'release-implementation-receipt-missing',
338
+ BETA_RECEIPT_MISSING: 'release-beta-receipt-missing',
339
+ RELEASE_GATE_RECEIPT_MISSING: 'release-gate-receipt-missing',
340
+ PROMOTION_RECEIPT_MISSING: 'release-promotion-receipt-missing',
341
+ RELEASE_READY_PREREQUISITE_MISSING: 'release-ready-prerequisite-missing',
342
+ PRODUCTION_PREREQUISITE_MISSING: 'release-production-prerequisite-missing',
343
+ });
344
+ const CANDIDATE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;
345
+ const EVIDENCE_REF = /^(?:local-gate|beta-receipt|release-gate|promotion-receipt|sha256):[a-f0-9]{64}$/u;
346
+ const RELEASE_REASONS = new Set(Object.values(RELEASE_LIFECYCLE_REASON_CODES));
347
+ const DIMENSIONS = Object.freeze([
348
+ 'implementationComplete', 'betaOperable', 'releaseReady', 'productionPromoted',
349
+ ]);
350
+ function validIso(value) {
351
+ return typeof value === 'string' && value.length >= 20 && value.length <= 40
352
+ && Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
353
+ }
354
+ function dimensionShape(value) {
355
+ if (!value || typeof value !== 'object' || Array.isArray(value))
356
+ return false;
357
+ const dimension = value;
358
+ return hasOnlyKeys(dimension, ['value', 'reasonCodes', 'evidenceRefs', 'candidateId', 'lineageSha256', 'observedAt', 'maxAgeSeconds', 'freshness'])
359
+ && (typeof dimension.value === 'boolean' || dimension.value === 'unknown')
360
+ && Array.isArray(dimension.reasonCodes) && dimension.reasonCodes.length > 0 && dimension.reasonCodes.length <= 8
361
+ && dimension.reasonCodes.every((reason) => typeof reason === 'string' && RELEASE_REASONS.has(reason))
362
+ && Array.isArray(dimension.evidenceRefs) && dimension.evidenceRefs.length <= 8
363
+ && dimension.evidenceRefs.every((ref) => typeof ref === 'string' && ref.length <= 96)
364
+ && typeof dimension.candidateId === 'string' && CANDIDATE_ID.test(dimension.candidateId)
365
+ && typeof dimension.lineageSha256 === 'string' && SHA256.test(dimension.lineageSha256)
366
+ && (dimension.observedAt === undefined || validIso(dimension.observedAt))
367
+ && (dimension.maxAgeSeconds === undefined
368
+ || Number.isSafeInteger(dimension.maxAgeSeconds) && dimension.maxAgeSeconds >= 1
369
+ && dimension.maxAgeSeconds <= 31_536_000)
370
+ && (dimension.freshness === undefined || ['fresh', 'stale', 'unknown'].includes(String(dimension.freshness)));
371
+ }
372
+ function freshness(dimension, evaluatedAtMs) {
373
+ if (!dimension.observedAt || !dimension.maxAgeSeconds)
374
+ return 'unknown';
375
+ const observedAtMs = Date.parse(dimension.observedAt);
376
+ if (observedAtMs > evaluatedAtMs)
377
+ return 'unknown';
378
+ return evaluatedAtMs - observedAtMs <= dimension.maxAgeSeconds * 1_000 ? 'fresh' : 'stale';
379
+ }
380
+ function hasEvidencePrefix(dimension, prefix) {
381
+ return dimension.evidenceRefs.some((ref) => ref.startsWith(`${prefix}:`));
382
+ }
383
+ /**
384
+ * Validate exact-candidate monotonic release truth without inferring any higher
385
+ * dimension. Invalid true claims are rejected rather than normalized to false.
386
+ */
387
+ export function validateReleaseLifecycle(input) {
388
+ const fail = (reasons) => Object.freeze({
389
+ accepted: false,
390
+ reasonCodes: Object.freeze(uniqueSorted(reasons)),
391
+ publicSafe: true,
392
+ });
393
+ if (!input || typeof input !== 'object' || Array.isArray(input))
394
+ return fail([RELEASE_LIFECYCLE_REASON_CODES.MALFORMED]);
395
+ const lifecycle = input;
396
+ if (!hasOnlyKeys(lifecycle, ['schemaVersion', 'candidateId', 'lineageSha256', 'evaluatedAt', ...DIMENSIONS, 'publicSafe'])
397
+ || lifecycle.schemaVersion !== RELEASE_LIFECYCLE_SCHEMA
398
+ || typeof lifecycle.candidateId !== 'string' || !CANDIDATE_ID.test(lifecycle.candidateId)
399
+ || typeof lifecycle.lineageSha256 !== 'string' || !SHA256.test(lifecycle.lineageSha256)
400
+ || !validIso(lifecycle.evaluatedAt) || lifecycle.publicSafe !== true
401
+ || DIMENSIONS.some((name) => !dimensionShape(lifecycle[name]))) {
402
+ return fail([RELEASE_LIFECYCLE_REASON_CODES.MALFORMED]);
403
+ }
404
+ const typed = lifecycle;
405
+ const evaluatedAtMs = Date.parse(typed.evaluatedAt);
406
+ const reasons = [];
407
+ const seenEvidence = new Set();
408
+ const projected = {};
409
+ for (const name of DIMENSIONS) {
410
+ const dimension = typed[name];
411
+ if (dimension.candidateId !== typed.candidateId)
412
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.CANDIDATE_MISMATCH);
413
+ if (dimension.lineageSha256 !== typed.lineageSha256)
414
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.LINEAGE_MISMATCH);
415
+ if (dimension.evidenceRefs.some((ref) => !EVIDENCE_REF.test(ref)))
416
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.EVIDENCE_REF_INVALID);
417
+ for (const ref of dimension.evidenceRefs) {
418
+ if (seenEvidence.has(ref))
419
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.EVIDENCE_REPLAYED);
420
+ seenEvidence.add(ref);
421
+ }
422
+ const evidenceFreshness = freshness(dimension, evaluatedAtMs);
423
+ const suppliedFreshness = dimension.freshness;
424
+ if (suppliedFreshness !== undefined && suppliedFreshness !== evidenceFreshness) {
425
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.MALFORMED);
426
+ }
427
+ if (dimension.observedAt && Date.parse(dimension.observedAt) > evaluatedAtMs) {
428
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.FUTURE_OBSERVATION);
429
+ }
430
+ if (dimension.value === true && evidenceFreshness === 'stale')
431
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.FRESHNESS_STALE);
432
+ if (dimension.value === true && evidenceFreshness === 'unknown')
433
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.FRESHNESS_UNKNOWN);
434
+ projected[name] = Object.freeze({
435
+ ...dimension,
436
+ reasonCodes: Object.freeze([...dimension.reasonCodes]),
437
+ evidenceRefs: Object.freeze([...dimension.evidenceRefs]),
438
+ freshness: evidenceFreshness,
439
+ });
440
+ }
441
+ if (typed.implementationComplete.value === true && !hasEvidencePrefix(typed.implementationComplete, 'local-gate')) {
442
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.IMPLEMENTATION_RECEIPT_MISSING);
443
+ }
444
+ if (typed.betaOperable.value === true && !hasEvidencePrefix(typed.betaOperable, 'beta-receipt')) {
445
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.BETA_RECEIPT_MISSING);
446
+ }
447
+ if (typed.releaseReady.value === true) {
448
+ if (typed.implementationComplete.value !== true || typed.betaOperable.value !== true) {
449
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.RELEASE_READY_PREREQUISITE_MISSING);
450
+ }
451
+ if (!hasEvidencePrefix(typed.releaseReady, 'release-gate')) {
452
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.RELEASE_GATE_RECEIPT_MISSING);
453
+ }
454
+ }
455
+ if (typed.productionPromoted.value === true) {
456
+ if (typed.releaseReady.value !== true)
457
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.PRODUCTION_PREREQUISITE_MISSING);
458
+ if (!hasEvidencePrefix(typed.productionPromoted, 'promotion-receipt')) {
459
+ reasons.push(RELEASE_LIFECYCLE_REASON_CODES.PROMOTION_RECEIPT_MISSING);
460
+ }
461
+ }
462
+ if (reasons.length > 0)
463
+ return fail(reasons);
464
+ const projection = Object.freeze({
465
+ schemaVersion: RELEASE_LIFECYCLE_SCHEMA,
466
+ candidateId: typed.candidateId,
467
+ lineageSha256: typed.lineageSha256,
468
+ evaluatedAt: typed.evaluatedAt,
469
+ implementationComplete: projected.implementationComplete,
470
+ betaOperable: projected.betaOperable,
471
+ releaseReady: projected.releaseReady,
472
+ productionPromoted: projected.productionPromoted,
473
+ publicSafe: true,
474
+ });
475
+ return Object.freeze({ accepted: true, reasonCodes: Object.freeze([]), projection, publicSafe: true });
476
+ }
@@ -177,10 +177,12 @@ export function lexInvocationEnvelope(input) {
177
177
  if (escaped) {
178
178
  const allowed = char === '\\' || char === ' ' || char === '\t' || char === '\r' || char === '\n'
179
179
  || (quote === 'single' && char === "'") || (quote === 'double' && char === '"');
180
- if (!allowed)
180
+ // A quoted Windows path such as src\win\async.c is literal user text.
181
+ // Keep unquoted shell-shaped escapes fail-closed.
182
+ if (!allowed && !quote)
181
183
  return { ok: false, reason: 'unsupported_escape', tokenCount: tokens.length };
182
184
  startSegment(i - 1, quote);
183
- value += char;
185
+ value += allowed ? char : `\\${char}`;
184
186
  escaped = false;
185
187
  continue;
186
188
  }
@@ -0,0 +1,14 @@
1
+ export function isPrivateQaStructuralAdmission(value) {
2
+ if (!value || typeof value !== 'object' || Array.isArray(value))
3
+ return false;
4
+ const r = value, checks = r.checks;
5
+ return Object.keys(r).sort().join('|') === ['schemaVersion', 'kind', 'stepId', 'generationId', 'graphRevision', 'topologyGenerationId', 'tier', 'checks', 'publicSafe'].sort().join('|')
6
+ && r.schemaVersion === 1 && r.kind === 'server-private-qa-structural-admission' && r.stepId === 'step-8721319d'
7
+ && typeof r.generationId === 'string' && /^sha256:[a-f0-9]{64}$/.test(r.generationId)
8
+ && typeof r.graphRevision === 'string' && /^[a-f0-9]{64}$/.test(r.graphRevision)
9
+ && typeof r.topologyGenerationId === 'string' && /^sha256:[a-f0-9]{64}$/.test(r.topologyGenerationId)
10
+ && ['free', 'pro', 'enterprise'].includes(String(r.tier)) && r.publicSafe === true
11
+ && !!checks && typeof checks === 'object' && !Array.isArray(checks)
12
+ && Object.keys(checks).sort().join('|') === ['classifiedAssetDelivery', 'licensedCommandAdmission', 'registeredStatusMapping', 'prerequisiteStateAdmitted'].sort().join('|')
13
+ && Object.values(checks).every(result => result === true);
14
+ }
@@ -0,0 +1,32 @@
1
+ export function isPrivateQaSkippedPredecessors(value) {
2
+ if (!Array.isArray(value) || value.length > 2)
3
+ return false;
4
+ const ids = [];
5
+ for (const item of value) {
6
+ if (isPrivateYoloSkippedPredecessors([item])) {
7
+ ids.push(item.stepId);
8
+ continue;
9
+ }
10
+ if (!item || typeof item !== 'object' || Array.isArray(item))
11
+ return false;
12
+ const r = item;
13
+ if (Object.keys(r).sort().join('|') !== ['stepId', 'featureGate', 'reason', 'tier', 'publicSafe'].sort().join('|')
14
+ || r.stepId !== 'step-b2fe7cb5' || r.featureGate !== 'validate-tests'
15
+ || r.reason !== 'subscription-tier' || r.tier !== 'free' || r.publicSafe !== true)
16
+ return false;
17
+ ids.push(r.stepId);
18
+ }
19
+ return new Set(ids).size === ids.length && (value.length < 2
20
+ || ids[0] === 'step-a8ce5c64' && ids[1] === 'step-b2fe7cb5' && value[0].tier === 'free');
21
+ }
22
+ export function isPrivateYoloSkippedPredecessors(value) {
23
+ return Array.isArray(value) && value.length <= 1 && value.every(item => {
24
+ if (!item || typeof item !== 'object' || Array.isArray(item))
25
+ return false;
26
+ const r = item;
27
+ return Object.keys(r).sort().join('|') === ['stepId', 'featureFlagId', 'enabled', 'tier', 'publicSafe'].sort().join('|')
28
+ && r.stepId === 'step-a8ce5c64' && r.featureFlagId === 'property-testing'
29
+ && typeof r.enabled === 'boolean' && ['free', 'pro', 'enterprise'].includes(String(r.tier))
30
+ && (r.enabled === false || r.tier === 'free') && r.publicSafe === true;
31
+ });
32
+ }
@@ -0,0 +1,74 @@
1
+ /** Bounded project command declarations from the submitted story/spec artifacts.
2
+ * These are planning data, never permission to execute or independent QA.
3
+ */
4
+ export const PROJECT_VALIDATION_KINDS = ['unit', 'integration', 'contract', 'bdd-example', 'e2e'];
5
+ export function readProjectValidationCommands(storyId, sources) {
6
+ const byKind = new Map();
7
+ let declared = false, invalid = false;
8
+ const allowedPaths = new Set(['story', 'spec', 'tasks'].map(suffix => `docs/stories/${storyId}.${suffix}.md`));
9
+ if (sources.length > 3 || new Set(sources.map(source => source.path)).size !== sources.length) {
10
+ return { declared: true, invalid: true, commands: [] };
11
+ }
12
+ for (const source of sources) {
13
+ if (!allowedPaths.has(source.path) || Buffer.byteLength(source.content) > 131072) {
14
+ invalid = true;
15
+ declared = true;
16
+ continue;
17
+ }
18
+ let active = false, fenced = false, headings = 0, entries = 0;
19
+ for (const raw of source.content.split(/\r?\n/)) {
20
+ const line = raw.trim();
21
+ if (/^(?:```|~~~)/.test(line)) {
22
+ fenced = !fenced;
23
+ continue;
24
+ }
25
+ if (fenced)
26
+ continue;
27
+ if (/^##\s+/.test(line)) {
28
+ if (active && entries === 0)
29
+ invalid = true;
30
+ active = line === '## Validation Commands';
31
+ if (active) {
32
+ declared = true;
33
+ headings++;
34
+ entries = 0;
35
+ if (headings > 1)
36
+ invalid = true;
37
+ }
38
+ continue;
39
+ }
40
+ if (!active || !line)
41
+ continue;
42
+ const match = /^- (unit|integration|contract|bdd-example|e2e): `([^`]{1,220})`$/.exec(line);
43
+ if (!match) {
44
+ invalid = true;
45
+ continue;
46
+ }
47
+ const kind = match[1], command = match[2];
48
+ // No shell language, quoted substitutions, inline secrets or private URLs.
49
+ // A command stays a literal argv-shaped string throughout this planner.
50
+ if (!/^[A-Za-z0-9_./-]+(?: [A-Za-z0-9_./:@%+=,-]+)*$/.test(command)
51
+ || /(?:token|password|license_key|secret|credential)=|(?:https?|ssh):\/\/|@[^ /]+\.[A-Za-z]/i.test(command)
52
+ || command.split(' ').some(arg => arg.split('/').includes('..'))) {
53
+ invalid = true;
54
+ continue;
55
+ }
56
+ entries++;
57
+ const prior = byKind.get(kind);
58
+ if (prior && prior.command !== command) {
59
+ invalid = true;
60
+ continue;
61
+ }
62
+ if (prior?.sourcePaths.includes(source.path)) {
63
+ invalid = true;
64
+ continue;
65
+ }
66
+ byKind.set(kind, { kind, command, sourcePaths: [...(prior?.sourcePaths ?? []), source.path] });
67
+ }
68
+ if (active && entries === 0)
69
+ invalid = true;
70
+ }
71
+ if (declared && !byKind.has('unit'))
72
+ invalid = true;
73
+ return { declared, invalid, commands: [...byKind.values()] };
74
+ }
@@ -6,6 +6,8 @@ export const YOLO_SPEC_TOTAL_LIMIT_BYTES = 128 * 1024;
6
6
  export const YOLO_SPEC_MAX_ARTIFACTS = 12;
7
7
  export const YOLO_SPEC_MAX_AGE_MS = 120_000;
8
8
  export const YOLO_SPEC_FUTURE_SKEW_MS = 30_000;
9
+ /** Public server capability for both mandatory top-level YOLO invoke fields. */
10
+ export const YOLO_INVOKE_ENVELOPE_CAPABILITY = 'yolo-invoke-envelope-v1';
9
11
  const HASH = /^[a-f0-9]{64}$/;
10
12
  const HEAD = /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/;
11
13
  const STORY_ID = /^[A-Za-z0-9]+(?:\.[A-Za-z0-9]+)+$/;