deepline 0.3.185 → 0.3.186
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/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/types.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/launch-identity.ts +229 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/contracts.ts +16 -1
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/postgres-adapter.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-telemetry.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +7 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +238 -24
- package/dist/cli/index.js +29 -3
- package/dist/cli/index.mjs +29 -3
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/install-integrity.json +1 -0
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +1 -1
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
|
@@ -200,7 +200,7 @@ export const SDK_RELEASE = {
|
|
|
200
200
|
// getters keep their established compatibility behavior.
|
|
201
201
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
202
202
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
203
|
-
version: '0.3.
|
|
203
|
+
version: '0.3.186',
|
|
204
204
|
updateSummary:
|
|
205
205
|
'Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.',
|
|
206
206
|
packageCapabilities: {
|
|
@@ -1331,6 +1331,8 @@ export interface PlayDefinitionDetail {
|
|
|
1331
1331
|
cronTimezone?: string | null;
|
|
1332
1332
|
nextScheduledAt?: number | null;
|
|
1333
1333
|
lastScheduledAt?: number | null;
|
|
1334
|
+
blockedAt?: number | null;
|
|
1335
|
+
blockedReasonCode?: string | null;
|
|
1334
1336
|
blockedReason?: string | null;
|
|
1335
1337
|
[key: string]: unknown;
|
|
1336
1338
|
} | null;
|
|
@@ -1403,6 +1405,8 @@ export interface PlayTriggerStatus {
|
|
|
1403
1405
|
cron: string | null;
|
|
1404
1406
|
webhook: string | null;
|
|
1405
1407
|
blockedReason: string | null;
|
|
1408
|
+
blockedReasonCode?: string;
|
|
1409
|
+
blockedAt?: number;
|
|
1406
1410
|
}
|
|
1407
1411
|
|
|
1408
1412
|
export interface ProductNotificationEventDefinition {
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { sha256Hex, stableStringify } from '../plays/row-identity';
|
|
2
|
+
import { LEGACY_MAX_CONCURRENT_EXTERNAL_CALLS } from './governor/policy';
|
|
3
|
+
import type { PlaySchedulerSubmitInput } from './scheduler-backend';
|
|
4
|
+
|
|
5
|
+
/** Optional launch-envelope field used by the mixed-release admission fence. */
|
|
6
|
+
export const PLAY_LAUNCH_IDENTITY_DIGEST_FIELD = 'launchIdentityDigest';
|
|
7
|
+
const PLAY_LAUNCH_IDENTITY_DIGEST_NAMESPACE = 'deepline:play-launch-identity';
|
|
8
|
+
|
|
9
|
+
export type PlayLaunchFieldRole = 'identity' | 'detail';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Keep this list exhaustive over the launch envelope. A newly added field must
|
|
13
|
+
* be classified before it can participate in launch admission.
|
|
14
|
+
*/
|
|
15
|
+
export const PLAY_LAUNCH_ENVELOPE_FIELD_ROLES: {
|
|
16
|
+
readonly [K in keyof PlaySchedulerSubmitInput]-?: PlayLaunchFieldRole;
|
|
17
|
+
} = {
|
|
18
|
+
orgId: 'identity',
|
|
19
|
+
playName: 'identity',
|
|
20
|
+
playReference: 'identity',
|
|
21
|
+
definitionScope: 'identity',
|
|
22
|
+
revisionId: 'identity',
|
|
23
|
+
artifactStorageKey: 'identity',
|
|
24
|
+
artifactHash: 'identity',
|
|
25
|
+
graphHash: 'identity',
|
|
26
|
+
workflowFamilyKey: 'identity',
|
|
27
|
+
inputSha256: 'identity',
|
|
28
|
+
source: 'identity',
|
|
29
|
+
triggerSource: 'identity',
|
|
30
|
+
parentRunId: 'identity',
|
|
31
|
+
rootRunId: 'identity',
|
|
32
|
+
asyncLaunchKey: 'identity',
|
|
33
|
+
asyncInvocationKey: 'identity',
|
|
34
|
+
asyncRequestFingerprint: 'identity',
|
|
35
|
+
force: 'identity',
|
|
36
|
+
forceToolRefresh: 'identity',
|
|
37
|
+
maxConcurrentExternalCalls: 'identity',
|
|
38
|
+
maxConcurrentRows: 'identity',
|
|
39
|
+
integrationMode: 'identity',
|
|
40
|
+
runtimeSandboxPlacementPolicyId: 'identity',
|
|
41
|
+
input: 'identity',
|
|
42
|
+
inputFile: 'identity',
|
|
43
|
+
inlineInputFile: 'identity',
|
|
44
|
+
inlineCsv: 'identity',
|
|
45
|
+
packagedFiles: 'identity',
|
|
46
|
+
runId: 'detail',
|
|
47
|
+
existingOnly: 'detail',
|
|
48
|
+
asyncParentRunAttempt: 'detail',
|
|
49
|
+
asyncParentRunLeaseToken: 'detail',
|
|
50
|
+
asyncParentAttemptRequired: 'detail',
|
|
51
|
+
asyncAncestryPlayIds: 'detail',
|
|
52
|
+
playId: 'detail',
|
|
53
|
+
schedulerSchema: 'detail',
|
|
54
|
+
requiresRunCreatedProjection: 'detail',
|
|
55
|
+
runtimeArtifact: 'detail',
|
|
56
|
+
runtimeProtocolVersion: 'detail',
|
|
57
|
+
staticPipeline: 'detail',
|
|
58
|
+
inputSummary: 'detail',
|
|
59
|
+
inputBytes: 'detail',
|
|
60
|
+
inputFileId: 'detail',
|
|
61
|
+
replayedFromRunId: 'detail',
|
|
62
|
+
totalRows: 'detail',
|
|
63
|
+
contractSnapshot: 'detail',
|
|
64
|
+
executionPlan: 'detail',
|
|
65
|
+
preloadedDbSessions: 'detail',
|
|
66
|
+
preloadedDbSessionUnwrapKey: 'detail',
|
|
67
|
+
executorToken: 'detail',
|
|
68
|
+
runtimeAuthority: 'detail',
|
|
69
|
+
runtimeApiBaseUrl: 'detail',
|
|
70
|
+
runtimeTokenOrigin: 'detail',
|
|
71
|
+
baseUrl: 'detail',
|
|
72
|
+
coordinatorUrl: 'detail',
|
|
73
|
+
coordinatorInternalToken: 'detail',
|
|
74
|
+
runtimeDeployVersion: 'detail',
|
|
75
|
+
absurdReleaseId: 'detail',
|
|
76
|
+
absurdReleaseEnvironment: 'detail',
|
|
77
|
+
vercelProtectionBypassToken: 'detail',
|
|
78
|
+
preferredReceiptGatewayMachineId: 'detail',
|
|
79
|
+
runtimeTestFaultHeader: 'detail',
|
|
80
|
+
testPolicyOverrides: 'detail',
|
|
81
|
+
submittedAtMs: 'detail',
|
|
82
|
+
schedulerBackend: 'detail',
|
|
83
|
+
executionProfile: 'detail',
|
|
84
|
+
runtimeBackend: 'detail',
|
|
85
|
+
queueMaxDelaySeconds: 'detail',
|
|
86
|
+
queuePriority: 'detail',
|
|
87
|
+
userEmail: 'detail',
|
|
88
|
+
userId: 'detail',
|
|
89
|
+
launchIdentityDigest: 'detail',
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const PLAY_LAUNCH_IDENTITY_FIELDS_COMPARED_OUTSIDE_DIGEST: readonly string[] =
|
|
93
|
+
Object.freeze(['runtimeSandboxPlacementPolicyId']);
|
|
94
|
+
|
|
95
|
+
export const PLAY_LAUNCH_IDENTITY_FIELDS: readonly string[] = Object.freeze(
|
|
96
|
+
Object.entries(PLAY_LAUNCH_ENVELOPE_FIELD_ROLES)
|
|
97
|
+
.filter(([, role]) => role === 'identity')
|
|
98
|
+
.map(([field]) => field)
|
|
99
|
+
.sort(),
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
export const PLAY_LAUNCH_DETAIL_FIELDS: readonly string[] = Object.freeze(
|
|
103
|
+
Object.entries(PLAY_LAUNCH_ENVELOPE_FIELD_ROLES)
|
|
104
|
+
.filter(([, role]) => role === 'detail')
|
|
105
|
+
.map(([field]) => field)
|
|
106
|
+
.sort(),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
export type PlayLaunchIdentitySource = Readonly<
|
|
110
|
+
Partial<Record<keyof PlaySchedulerSubmitInput, unknown>>
|
|
111
|
+
>;
|
|
112
|
+
|
|
113
|
+
function text(value: unknown): string | null {
|
|
114
|
+
return typeof value === 'string' && value.trim() ? value.trim() : null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function flag(value: unknown): boolean {
|
|
118
|
+
return value === true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function count(value: unknown): number | null {
|
|
122
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function record(value: unknown): Record<string, unknown> | null {
|
|
126
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
127
|
+
? (value as Record<string, unknown>)
|
|
128
|
+
: null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function stagedFileIdentity(value: unknown): Record<string, unknown> | null {
|
|
132
|
+
const file = record(value);
|
|
133
|
+
if (!file) return null;
|
|
134
|
+
return {
|
|
135
|
+
logicalPath:
|
|
136
|
+
text(file.logicalPath) ?? text(file.path) ?? text(file.playPath),
|
|
137
|
+
fileName: text(file.fileName) ?? text(file.name),
|
|
138
|
+
contentType: text(file.contentType),
|
|
139
|
+
bytes: count(file.bytes),
|
|
140
|
+
contentDigest:
|
|
141
|
+
typeof file.contentBase64 === 'string'
|
|
142
|
+
? sha256Hex(file.contentBase64)
|
|
143
|
+
: typeof file.inlineText === 'string'
|
|
144
|
+
? sha256Hex(file.inlineText)
|
|
145
|
+
: null,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function stagedFileListIdentity(
|
|
150
|
+
value: unknown,
|
|
151
|
+
): Array<Record<string, unknown>> {
|
|
152
|
+
if (!Array.isArray(value)) return [];
|
|
153
|
+
return value
|
|
154
|
+
.map((entry) => stagedFileIdentity(entry))
|
|
155
|
+
.filter((entry): entry is Record<string, unknown> => entry !== null)
|
|
156
|
+
.sort((left, right) =>
|
|
157
|
+
stableStringify(left).localeCompare(stableStringify(right)),
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Return only customer intent; transport, authority, and release details are excluded. */
|
|
162
|
+
export function buildPlayLaunchIdentity(
|
|
163
|
+
launch: PlayLaunchIdentitySource,
|
|
164
|
+
): Record<string, unknown> {
|
|
165
|
+
const inlineCsv = record(launch.inlineCsv);
|
|
166
|
+
return {
|
|
167
|
+
orgId: text(launch.orgId),
|
|
168
|
+
playName: text(launch.playName),
|
|
169
|
+
playReference: text(launch.playReference) ?? text(launch.playName),
|
|
170
|
+
definitionScope: text(launch.definitionScope),
|
|
171
|
+
revisionId: text(launch.revisionId),
|
|
172
|
+
artifactStorageKey: text(launch.artifactStorageKey),
|
|
173
|
+
artifactHash: text(launch.artifactHash),
|
|
174
|
+
graphHash: text(launch.graphHash),
|
|
175
|
+
workflowFamilyKey: text(launch.workflowFamilyKey),
|
|
176
|
+
inputSha256: text(launch.inputSha256),
|
|
177
|
+
source: text(launch.source),
|
|
178
|
+
triggerSource: text(launch.triggerSource),
|
|
179
|
+
parentRunId: text(launch.parentRunId),
|
|
180
|
+
rootRunId: text(launch.rootRunId),
|
|
181
|
+
asyncLaunchKey: text(launch.asyncLaunchKey),
|
|
182
|
+
asyncInvocationKey: text(launch.asyncInvocationKey),
|
|
183
|
+
asyncRequestFingerprint: text(launch.asyncRequestFingerprint),
|
|
184
|
+
force: flag(launch.force),
|
|
185
|
+
forceToolRefresh: flag(launch.forceToolRefresh),
|
|
186
|
+
integrationMode: text(launch.integrationMode),
|
|
187
|
+
maxConcurrentExternalCalls:
|
|
188
|
+
count(launch.maxConcurrentExternalCalls) ??
|
|
189
|
+
LEGACY_MAX_CONCURRENT_EXTERNAL_CALLS,
|
|
190
|
+
maxConcurrentRows: count(launch.maxConcurrentRows),
|
|
191
|
+
inputDigest: sha256Hex(stableStringify(launch.input ?? {})),
|
|
192
|
+
inputFile: stagedFileIdentity(launch.inputFile),
|
|
193
|
+
inlineInputFile: stagedFileIdentity(launch.inlineInputFile),
|
|
194
|
+
inlineCsv: inlineCsv
|
|
195
|
+
? {
|
|
196
|
+
name: text(inlineCsv.name),
|
|
197
|
+
rowsDigest: sha256Hex(stableStringify(inlineCsv.rows ?? [])),
|
|
198
|
+
}
|
|
199
|
+
: null,
|
|
200
|
+
packagedFiles: stagedFileListIdentity(launch.packagedFiles),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export const PLAY_LAUNCH_DIGESTED_IDENTITY_FIELDS: readonly string[] =
|
|
205
|
+
Object.freeze(
|
|
206
|
+
PLAY_LAUNCH_IDENTITY_FIELDS.filter(
|
|
207
|
+
(field) =>
|
|
208
|
+
!PLAY_LAUNCH_IDENTITY_FIELDS_COMPARED_OUTSIDE_DIGEST.includes(field),
|
|
209
|
+
),
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
export function buildPlayLaunchIdentityDigest(
|
|
213
|
+
launch: PlayLaunchIdentitySource,
|
|
214
|
+
): string {
|
|
215
|
+
return sha256Hex(
|
|
216
|
+
`${PLAY_LAUNCH_IDENTITY_DIGEST_NAMESPACE}\0${stableStringify(
|
|
217
|
+
buildPlayLaunchIdentity(launch),
|
|
218
|
+
)}`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function withPlayLaunchIdentityDigest<
|
|
223
|
+
T extends PlaySchedulerSubmitInput,
|
|
224
|
+
>(launch: T): T {
|
|
225
|
+
return {
|
|
226
|
+
...launch,
|
|
227
|
+
launchIdentityDigest: buildPlayLaunchIdentityDigest(launch),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
@@ -42,16 +42,31 @@ export type PlayRunAdmissionJob = {
|
|
|
42
42
|
admit(input: PlayRunAdmissionInput): Promise<PlayRunAdmissionOutcome>;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
export type PlayRunLaunchConflictReason = 'launch_identity_mismatch';
|
|
46
|
+
|
|
45
47
|
/** A stable, machine-readable rejection for a reused run id with new intent. */
|
|
46
48
|
export class PlayRunLaunchConflictError extends Error {
|
|
47
49
|
readonly code = 'PLAY_RUN_LAUNCH_CONFLICT';
|
|
50
|
+
readonly conflictReason: PlayRunLaunchConflictReason | undefined;
|
|
51
|
+
readonly conflictingFields: string[] | undefined;
|
|
48
52
|
|
|
49
|
-
constructor(
|
|
53
|
+
constructor(
|
|
54
|
+
runId: string,
|
|
55
|
+
options?: {
|
|
56
|
+
cause?: unknown;
|
|
57
|
+
conflictReason?: PlayRunLaunchConflictReason;
|
|
58
|
+
conflictingFields?: readonly string[];
|
|
59
|
+
},
|
|
60
|
+
) {
|
|
50
61
|
super(
|
|
51
62
|
`Play run "${runId}" already exists with a different launch.`,
|
|
52
63
|
options,
|
|
53
64
|
);
|
|
54
65
|
this.name = 'PlayRunLaunchConflictError';
|
|
66
|
+
this.conflictReason = options?.conflictReason;
|
|
67
|
+
this.conflictingFields = options?.conflictingFields
|
|
68
|
+
? [...options.conflictingFields]
|
|
69
|
+
: undefined;
|
|
55
70
|
}
|
|
56
71
|
}
|
|
57
72
|
|
package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/postgres-adapter.ts
CHANGED
|
@@ -54,6 +54,9 @@ export function createPostgresPlayRunAdmissionPorts(input: {
|
|
|
54
54
|
artifactHash: admission.launch.artifactHash,
|
|
55
55
|
graphHash: admission.launch.graphHash,
|
|
56
56
|
inputSha256: admission.launch.inputSha256,
|
|
57
|
+
launchIdentityDigest: admission.launch.launchIdentityDigest,
|
|
58
|
+
conflictReason: conflict.conflictReason ?? null,
|
|
59
|
+
conflictingFields: conflict.conflictingFields ?? null,
|
|
57
60
|
error: conflict,
|
|
58
61
|
});
|
|
59
62
|
throw conflict;
|
|
@@ -41,6 +41,12 @@ export type PlayRunLaunchConflictTelemetryInput = {
|
|
|
41
41
|
artifactHash?: string | null;
|
|
42
42
|
graphHash?: string | null;
|
|
43
43
|
inputSha256?: string | null;
|
|
44
|
+
/** Named-intent digest of the incoming durable launch envelope. */
|
|
45
|
+
launchIdentityDigest?: string | null;
|
|
46
|
+
/** Admission-side conflict classification when available. */
|
|
47
|
+
conflictReason?: string | null;
|
|
48
|
+
/** Named launch-intent fields that differed, when the persisted envelope is available. */
|
|
49
|
+
conflictingFields?: readonly string[] | null;
|
|
44
50
|
error?: unknown;
|
|
45
51
|
};
|
|
46
52
|
|
|
@@ -113,6 +119,9 @@ export function buildPlayRunLaunchConflictTelemetry(
|
|
|
113
119
|
revisionId: input.revisionId ?? null,
|
|
114
120
|
artifactHash: input.artifactHash ?? null,
|
|
115
121
|
graphHash: input.graphHash ?? null,
|
|
122
|
+
launchIdentityDigest: input.launchIdentityDigest ?? null,
|
|
123
|
+
conflictReason: input.conflictReason ?? null,
|
|
124
|
+
conflictingFields: input.conflictingFields ?? null,
|
|
116
125
|
triage:
|
|
117
126
|
level === 'error'
|
|
118
127
|
? {
|
|
@@ -216,6 +216,13 @@ export type PlaySchedulerSubmitInput = {
|
|
|
216
216
|
runtimeTestFaultHeader?: string | null;
|
|
217
217
|
/** Request-scoped, dev-only runtime policy overrides for black-box durability tests. */
|
|
218
218
|
testPolicyOverrides?: RuntimeTestPolicyOverrides | null;
|
|
219
|
+
/**
|
|
220
|
+
* Digest of the named intent behind this launch. Runtime admission compares
|
|
221
|
+
* this optional field instead of treating transport and execution details as
|
|
222
|
+
* immutable identity. Older persisted rows omit it and keep the legacy
|
|
223
|
+
* comparison until they are gone.
|
|
224
|
+
*/
|
|
225
|
+
launchIdentityDigest?: string | null;
|
|
219
226
|
/** Millisecond epoch timestamp captured immediately before scheduler submit. */
|
|
220
227
|
submittedAtMs?: number;
|
|
221
228
|
/** Scheduler backend that owns orchestration for this run. */
|
|
@@ -157,6 +157,11 @@ import {
|
|
|
157
157
|
import { LEGACY_MAX_CONCURRENT_EXTERNAL_CALLS } from '../governor/policy';
|
|
158
158
|
import { requireRuntimeAuthorityDescriptor } from '../execution-capabilities';
|
|
159
159
|
import { stringifyPostgresJson } from '../postgres-json';
|
|
160
|
+
import {
|
|
161
|
+
buildPlayLaunchIdentity,
|
|
162
|
+
withPlayLaunchIdentityDigest,
|
|
163
|
+
} from '../launch-identity';
|
|
164
|
+
import { PlayRunLaunchConflictError } from '../play-runs/admission/contracts';
|
|
160
165
|
import { mintPlayRunAttemptRuntimeToken } from '../runtime-authority';
|
|
161
166
|
import { withActiveSpan } from '../../observability/tracing';
|
|
162
167
|
import type {
|
|
@@ -2198,6 +2203,99 @@ async function ensurePostgresSchedulerCronScheduleSchema(
|
|
|
2198
2203
|
`);
|
|
2199
2204
|
}
|
|
2200
2205
|
|
|
2206
|
+
/**
|
|
2207
|
+
* Install the launch-admission functions on every bootstrap path.
|
|
2208
|
+
*
|
|
2209
|
+
* These are function-body compatibility changes, not schema DDL. An already
|
|
2210
|
+
* current scheduler schema takes the fast path below, so keeping these only in
|
|
2211
|
+
* the full bootstrap leaves that estate with the old whole-envelope equality.
|
|
2212
|
+
*/
|
|
2213
|
+
async function ensurePostgresSchedulerLaunchAdmissionFunctions(
|
|
2214
|
+
client: PostgresSchedulerQueryClient,
|
|
2215
|
+
options?: Pick<PostgresSchedulerOptions, 'schema'>,
|
|
2216
|
+
): Promise<void> {
|
|
2217
|
+
const quotedSchema = quoteIdent(schemaName(options));
|
|
2218
|
+
await client.query(`
|
|
2219
|
+
CREATE OR REPLACE FUNCTION ${quotedSchema}.runtime_launch_admission_identity(
|
|
2220
|
+
launch_json jsonb
|
|
2221
|
+
) RETURNS jsonb
|
|
2222
|
+
LANGUAGE sql
|
|
2223
|
+
IMMUTABLE
|
|
2224
|
+
STRICT
|
|
2225
|
+
PARALLEL SAFE
|
|
2226
|
+
AS $$
|
|
2227
|
+
SELECT jsonb_set(
|
|
2228
|
+
jsonb_set(
|
|
2229
|
+
launch_json - ARRAY[
|
|
2230
|
+
'launchIdentityDigest',
|
|
2231
|
+
'executorToken',
|
|
2232
|
+
'inputFileId',
|
|
2233
|
+
'preloadedDbSessionUnwrapKey',
|
|
2234
|
+
'preloadedDbSessions',
|
|
2235
|
+
'submittedAtMs',
|
|
2236
|
+
'runtimeDeployVersion',
|
|
2237
|
+
'absurdReleaseId',
|
|
2238
|
+
'absurdReleaseEnvironment',
|
|
2239
|
+
'coordinatorUrl',
|
|
2240
|
+
'coordinatorInternalToken',
|
|
2241
|
+
'baseUrl',
|
|
2242
|
+
'runtimeApiBaseUrl',
|
|
2243
|
+
'vercelProtectionBypassToken'
|
|
2244
|
+
]::text[],
|
|
2245
|
+
'{maxConcurrentExternalCalls}',
|
|
2246
|
+
coalesce(
|
|
2247
|
+
launch_json->'maxConcurrentExternalCalls',
|
|
2248
|
+
to_jsonb(${LEGACY_MAX_CONCURRENT_EXTERNAL_CALLS}::integer)
|
|
2249
|
+
),
|
|
2250
|
+
true
|
|
2251
|
+
),
|
|
2252
|
+
'{maxConcurrentRows}',
|
|
2253
|
+
coalesce(launch_json->'maxConcurrentRows', 'null'::jsonb),
|
|
2254
|
+
true
|
|
2255
|
+
)
|
|
2256
|
+
$$
|
|
2257
|
+
`);
|
|
2258
|
+
await client.query(`
|
|
2259
|
+
CREATE OR REPLACE FUNCTION ${quotedSchema}.runtime_launch_admission_matches(
|
|
2260
|
+
existing_launch_json jsonb,
|
|
2261
|
+
incoming_launch_json jsonb
|
|
2262
|
+
) RETURNS boolean
|
|
2263
|
+
LANGUAGE sql
|
|
2264
|
+
IMMUTABLE
|
|
2265
|
+
STRICT
|
|
2266
|
+
PARALLEL SAFE
|
|
2267
|
+
AS $$
|
|
2268
|
+
SELECT CASE
|
|
2269
|
+
WHEN nullif(btrim(coalesce(existing_launch_json->>'launchIdentityDigest', '')), '') IS NOT NULL
|
|
2270
|
+
AND nullif(btrim(coalesce(incoming_launch_json->>'launchIdentityDigest', '')), '') IS NOT NULL
|
|
2271
|
+
THEN btrim(existing_launch_json->>'launchIdentityDigest')
|
|
2272
|
+
= btrim(incoming_launch_json->>'launchIdentityDigest')
|
|
2273
|
+
AND (
|
|
2274
|
+
NOT (
|
|
2275
|
+
existing_launch_json ? 'runtimeSandboxPlacementPolicyId'
|
|
2276
|
+
AND incoming_launch_json ? 'runtimeSandboxPlacementPolicyId'
|
|
2277
|
+
)
|
|
2278
|
+
OR existing_launch_json->'runtimeSandboxPlacementPolicyId'
|
|
2279
|
+
IS NOT DISTINCT FROM incoming_launch_json->'runtimeSandboxPlacementPolicyId'
|
|
2280
|
+
)
|
|
2281
|
+
WHEN existing_launch_json ? 'runtimeSandboxPlacementPolicyId'
|
|
2282
|
+
AND incoming_launch_json ? 'runtimeSandboxPlacementPolicyId'
|
|
2283
|
+
THEN ${quotedSchema}.runtime_launch_admission_identity(
|
|
2284
|
+
existing_launch_json - 'launchIdentityDigest'
|
|
2285
|
+
) = ${quotedSchema}.runtime_launch_admission_identity(
|
|
2286
|
+
incoming_launch_json - 'launchIdentityDigest'
|
|
2287
|
+
)
|
|
2288
|
+
ELSE ${quotedSchema}.runtime_launch_admission_identity(
|
|
2289
|
+
existing_launch_json - 'launchIdentityDigest'
|
|
2290
|
+
) - ARRAY['runtimeSandboxPlacementPolicyId', 'launchIdentityDigest']::text[] =
|
|
2291
|
+
${quotedSchema}.runtime_launch_admission_identity(
|
|
2292
|
+
incoming_launch_json - 'launchIdentityDigest'
|
|
2293
|
+
) - ARRAY['runtimeSandboxPlacementPolicyId', 'launchIdentityDigest']::text[]
|
|
2294
|
+
END
|
|
2295
|
+
$$
|
|
2296
|
+
`);
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2201
2299
|
export async function ensurePostgresSchedulerSchema(
|
|
2202
2300
|
client: PostgresSchedulerQueryClient,
|
|
2203
2301
|
options?: Pick<PostgresSchedulerOptions, 'schema'> & {
|
|
@@ -2332,6 +2430,7 @@ export async function ensurePostgresSchedulerSchema(
|
|
|
2332
2430
|
const hasLegacyAdmissionRows =
|
|
2333
2431
|
legacyAdmissionRows?.rows[0]?.present === true;
|
|
2334
2432
|
if (schemaCoreIsCurrent) {
|
|
2433
|
+
await ensurePostgresSchedulerLaunchAdmissionFunctions(client, options);
|
|
2335
2434
|
if (!schemaIsCurrent) {
|
|
2336
2435
|
await ensurePostgresSchedulerTerminalComputeBillingOutboxTrigger(
|
|
2337
2436
|
client,
|
|
@@ -3703,6 +3802,7 @@ export async function ensurePostgresSchedulerSchema(
|
|
|
3703
3802
|
[POSTGRES_SCHEDULER_SCHEMA_VERSION],
|
|
3704
3803
|
);
|
|
3705
3804
|
await ensurePostgresSchedulerCronScheduleSchema(client, options);
|
|
3805
|
+
await ensurePostgresSchedulerLaunchAdmissionFunctions(client, options);
|
|
3706
3806
|
if (hadOutbox.rows[0]?.present !== true) {
|
|
3707
3807
|
await client.query(
|
|
3708
3808
|
`
|
|
@@ -4409,6 +4509,45 @@ export async function submitPostgresAbsurdPlayRun(
|
|
|
4409
4509
|
};
|
|
4410
4510
|
}
|
|
4411
4511
|
|
|
4512
|
+
function launchIdentityConflictFields(
|
|
4513
|
+
existingLaunchJson: unknown,
|
|
4514
|
+
incomingLaunch: PlaySchedulerSubmitInput,
|
|
4515
|
+
): string[] {
|
|
4516
|
+
if (
|
|
4517
|
+
!existingLaunchJson ||
|
|
4518
|
+
typeof existingLaunchJson !== 'object' ||
|
|
4519
|
+
Array.isArray(existingLaunchJson)
|
|
4520
|
+
) {
|
|
4521
|
+
return [];
|
|
4522
|
+
}
|
|
4523
|
+
const existingIdentity = buildPlayLaunchIdentity(
|
|
4524
|
+
existingLaunchJson as Record<string, unknown>,
|
|
4525
|
+
);
|
|
4526
|
+
const incomingIdentity = buildPlayLaunchIdentity(incomingLaunch);
|
|
4527
|
+
const fields = Object.keys(incomingIdentity).filter(
|
|
4528
|
+
(field) =>
|
|
4529
|
+
stableStringify(existingIdentity[field]) !==
|
|
4530
|
+
stableStringify(incomingIdentity[field]),
|
|
4531
|
+
);
|
|
4532
|
+
if (
|
|
4533
|
+
Object.prototype.hasOwnProperty.call(
|
|
4534
|
+
existingLaunchJson,
|
|
4535
|
+
'runtimeSandboxPlacementPolicyId',
|
|
4536
|
+
) &&
|
|
4537
|
+
Object.prototype.hasOwnProperty.call(
|
|
4538
|
+
incomingLaunch,
|
|
4539
|
+
'runtimeSandboxPlacementPolicyId',
|
|
4540
|
+
) &&
|
|
4541
|
+
stableStringify(
|
|
4542
|
+
(existingLaunchJson as Record<string, unknown>)
|
|
4543
|
+
.runtimeSandboxPlacementPolicyId,
|
|
4544
|
+
) !== stableStringify(incomingLaunch.runtimeSandboxPlacementPolicyId)
|
|
4545
|
+
) {
|
|
4546
|
+
fields.push('runtimeSandboxPlacementPolicyId');
|
|
4547
|
+
}
|
|
4548
|
+
return fields.sort();
|
|
4549
|
+
}
|
|
4550
|
+
|
|
4412
4551
|
async function submitPostgresSchedulerRunTransaction(
|
|
4413
4552
|
client: PostgresSchedulerQueryClient,
|
|
4414
4553
|
input: PlaySchedulerSubmitInput,
|
|
@@ -4447,7 +4586,10 @@ async function submitPostgresSchedulerRunTransaction(
|
|
|
4447
4586
|
existingOnly: requestedExistingOnly,
|
|
4448
4587
|
...durableInput
|
|
4449
4588
|
} = input;
|
|
4450
|
-
|
|
4589
|
+
// Every scheduler writer converges through this seam, including the cron
|
|
4590
|
+
// successor path and Workpool retries. Stamp after ephemeral admission proof
|
|
4591
|
+
// fields are removed so they can never change the durable launch identity.
|
|
4592
|
+
input = withPlayLaunchIdentityDigest(durableInput);
|
|
4451
4593
|
const existingOnlySql = requestedExistingOnly === true ? 'true' : 'false';
|
|
4452
4594
|
const releaseId = input.absurdReleaseId?.trim() || null;
|
|
4453
4595
|
const legacyPreviewRelease =
|
|
@@ -4531,6 +4673,7 @@ async function submitPostgresSchedulerRunTransaction(
|
|
|
4531
4673
|
run_created: boolean;
|
|
4532
4674
|
task_created: boolean | null;
|
|
4533
4675
|
task_recovery_required: boolean;
|
|
4676
|
+
existing_launch_json: unknown | null;
|
|
4534
4677
|
}>(
|
|
4535
4678
|
`
|
|
4536
4679
|
WITH run_lock AS MATERIALIZED (
|
|
@@ -4578,6 +4721,7 @@ async function submitPostgresSchedulerRunTransaction(
|
|
|
4578
4721
|
coalesce(runs.admission_json, runs.launch_json),
|
|
4579
4722
|
$8::jsonb
|
|
4580
4723
|
) AS matches_launch,
|
|
4724
|
+
coalesce(runs.admission_json, runs.launch_json) AS launch_json,
|
|
4581
4725
|
runs.absurd_task_id,
|
|
4582
4726
|
runs.status
|
|
4583
4727
|
FROM admission_lock
|
|
@@ -4784,6 +4928,7 @@ async function submitPostgresSchedulerRunTransaction(
|
|
|
4784
4928
|
AND existing_run.absurd_task_id IS NULL
|
|
4785
4929
|
)
|
|
4786
4930
|
) AS task_recovery_required,
|
|
4931
|
+
(SELECT launch_json FROM existing_run) AS existing_launch_json,
|
|
4787
4932
|
CASE WHEN EXISTS (SELECT 1 FROM run_insert)
|
|
4788
4933
|
OR EXISTS (SELECT 1 FROM run_recovery)
|
|
4789
4934
|
THEN pg_notify($10, $11)
|
|
@@ -4840,9 +4985,13 @@ async function submitPostgresSchedulerRunTransaction(
|
|
|
4840
4985
|
);
|
|
4841
4986
|
}
|
|
4842
4987
|
if (row?.accepted === false && row.existing_run && !row.matching_existing) {
|
|
4843
|
-
throw new
|
|
4844
|
-
|
|
4845
|
-
|
|
4988
|
+
throw new PlayRunLaunchConflictError(input.runId, {
|
|
4989
|
+
conflictReason: 'launch_identity_mismatch',
|
|
4990
|
+
conflictingFields: launchIdentityConflictFields(
|
|
4991
|
+
row.existing_launch_json,
|
|
4992
|
+
input,
|
|
4993
|
+
),
|
|
4994
|
+
});
|
|
4846
4995
|
}
|
|
4847
4996
|
if (row?.accepted === false && !row?.existing_run && requestedExistingOnly) {
|
|
4848
4997
|
throw new Error(
|
|
@@ -5144,6 +5293,14 @@ export class PostgresSchedulerCronScheduleConfigurationError extends Error {
|
|
|
5144
5293
|
}
|
|
5145
5294
|
}
|
|
5146
5295
|
|
|
5296
|
+
/** A deterministic Run identity conflict cannot be repaired by retrying the same fire. */
|
|
5297
|
+
export class PostgresSchedulerCronLaunchConflictError extends PostgresSchedulerCronScheduleConfigurationError {
|
|
5298
|
+
constructor(message: string) {
|
|
5299
|
+
super(message);
|
|
5300
|
+
this.name = 'PostgresSchedulerCronLaunchConflictError';
|
|
5301
|
+
}
|
|
5302
|
+
}
|
|
5303
|
+
|
|
5147
5304
|
/**
|
|
5148
5305
|
* The timer stores the facts needed to reconstruct a pinned admission, not a
|
|
5149
5306
|
* previously prepared launch. Executor tokens, preloaded session keys,
|
|
@@ -5488,7 +5645,7 @@ function cronOccurrenceLaunch(input: {
|
|
|
5488
5645
|
`Cron schedule "${input.schedule.scheduleId}" did not receive a fresh authority for its pinned occurrence.`,
|
|
5489
5646
|
);
|
|
5490
5647
|
}
|
|
5491
|
-
return {
|
|
5648
|
+
return withPlayLaunchIdentityDigest({
|
|
5492
5649
|
...input.launch,
|
|
5493
5650
|
schedulerSchema:
|
|
5494
5651
|
input.schedulerSchema ?? input.launch.schedulerSchema ?? null,
|
|
@@ -5501,7 +5658,7 @@ function cronOccurrenceLaunch(input: {
|
|
|
5501
5658
|
),
|
|
5502
5659
|
triggerSource: 'cron',
|
|
5503
5660
|
requiresRunCreatedProjection: true,
|
|
5504
|
-
};
|
|
5661
|
+
});
|
|
5505
5662
|
}
|
|
5506
5663
|
|
|
5507
5664
|
export type FirePostgresSchedulerCronScheduleInput = {
|
|
@@ -5524,14 +5681,26 @@ export type FirePostgresSchedulerCronScheduleInput = {
|
|
|
5524
5681
|
* CTE inserts the immutable Run, its play-run task, run.created fact, next
|
|
5525
5682
|
* cron-fire task, and next cursor. A task replay after commit sees a changed
|
|
5526
5683
|
* cursor and is a harmless `superseded` no-op.
|
|
5684
|
+
*
|
|
5685
|
+
* A re-fire of the same occurrence whose deterministic Run already exists is
|
|
5686
|
+
* an idempotent re-fire, not a no-op. The cursor advances when the existing
|
|
5687
|
+
* launch identity matches, even if this statement did not create the Run.
|
|
5688
|
+
* A genuine identity mismatch is returned as `stalled` so it cannot silently
|
|
5689
|
+
* freeze the schedule behind an indistinguishable replay.
|
|
5527
5690
|
*/
|
|
5528
5691
|
export async function firePostgresSchedulerCronSchedule(
|
|
5529
5692
|
client: PostgresSchedulerQueryClient,
|
|
5530
5693
|
input: FirePostgresSchedulerCronScheduleInput,
|
|
5531
5694
|
options?: Pick<PostgresSchedulerOptions, 'schema'>,
|
|
5532
5695
|
): Promise<
|
|
5533
|
-
| {
|
|
5696
|
+
| {
|
|
5697
|
+
status: 'admitted';
|
|
5698
|
+
runId: string;
|
|
5699
|
+
successorDueAtMs: number;
|
|
5700
|
+
reused: boolean;
|
|
5701
|
+
}
|
|
5534
5702
|
| { status: 'superseded' }
|
|
5703
|
+
| { status: 'stalled'; runId: string; reason: string }
|
|
5535
5704
|
> {
|
|
5536
5705
|
assertPostgresSchedulerCronScheduleInput(input);
|
|
5537
5706
|
const schedule = await readPostgresSchedulerCronSchedule(
|
|
@@ -5598,7 +5767,11 @@ export async function firePostgresSchedulerCronSchedule(
|
|
|
5598
5767
|
orgId: launch.orgId,
|
|
5599
5768
|
});
|
|
5600
5769
|
const result = await client.query<{
|
|
5601
|
-
|
|
5770
|
+
advanced: boolean;
|
|
5771
|
+
run_created: boolean;
|
|
5772
|
+
schedule_current: boolean;
|
|
5773
|
+
existing_run: boolean;
|
|
5774
|
+
matching_existing: boolean;
|
|
5602
5775
|
release_accepting: boolean;
|
|
5603
5776
|
}>(
|
|
5604
5777
|
`
|
|
@@ -5623,16 +5796,28 @@ export async function firePostgresSchedulerCronSchedule(
|
|
|
5623
5796
|
AND release_gate.accepting
|
|
5624
5797
|
FOR UPDATE
|
|
5625
5798
|
), existing_run AS MATERIALIZED (
|
|
5626
|
-
SELECT runs.run_id
|
|
5799
|
+
SELECT runs.run_id,
|
|
5800
|
+
${quoteIdent(schemaName(options))}.runtime_launch_admission_matches(
|
|
5801
|
+
coalesce(runs.admission_json, runs.launch_json),
|
|
5802
|
+
$6::jsonb
|
|
5803
|
+
) AS matches_launch
|
|
5627
5804
|
FROM matching_schedule
|
|
5628
5805
|
JOIN ${tableName('runs', options)} AS runs ON runs.run_id = $5::text
|
|
5806
|
+
), occurrence AS MATERIALIZED (
|
|
5807
|
+
SELECT EXISTS (SELECT 1 FROM matching_schedule) AS schedule_current,
|
|
5808
|
+
EXISTS (SELECT 1 FROM existing_run) AS existing_run,
|
|
5809
|
+
coalesce(
|
|
5810
|
+
(SELECT matches_launch FROM existing_run),
|
|
5811
|
+
false
|
|
5812
|
+
) AS matching_existing
|
|
5629
5813
|
), play_task_request AS (
|
|
5630
5814
|
SELECT $7::text AS queue_name,
|
|
5631
5815
|
$8::text AS task_name,
|
|
5632
5816
|
$9::jsonb AS params,
|
|
5633
5817
|
$10::jsonb AS options
|
|
5634
|
-
|
|
5635
|
-
|
|
5818
|
+
FROM occurrence
|
|
5819
|
+
WHERE occurrence.schedule_current
|
|
5820
|
+
AND NOT occurrence.existing_run
|
|
5636
5821
|
), play_task_spawn AS MATERIALIZED (
|
|
5637
5822
|
SELECT spawned.task_id::text AS task_id
|
|
5638
5823
|
FROM play_task_request
|
|
@@ -5668,15 +5853,25 @@ export async function firePostgresSchedulerCronSchedule(
|
|
|
5668
5853
|
'coordinatorInternalToken',
|
|
5669
5854
|
'vercelProtectionBypassToken'
|
|
5670
5855
|
]::text[]
|
|
5671
|
-
|
|
5672
|
-
|
|
5856
|
+
FROM occurrence
|
|
5857
|
+
WHERE occurrence.schedule_current
|
|
5858
|
+
AND NOT occurrence.existing_run
|
|
5673
5859
|
RETURNING run_id
|
|
5860
|
+
), occurrence_admitted AS MATERIALIZED (
|
|
5861
|
+
SELECT true AS admitted
|
|
5862
|
+
FROM occurrence
|
|
5863
|
+
WHERE EXISTS (SELECT 1 FROM run_insert)
|
|
5864
|
+
OR (
|
|
5865
|
+
occurrence.schedule_current
|
|
5866
|
+
AND occurrence.existing_run
|
|
5867
|
+
AND occurrence.matching_existing
|
|
5868
|
+
)
|
|
5674
5869
|
), successor_task_request AS (
|
|
5675
5870
|
SELECT $11::text AS queue_name,
|
|
5676
5871
|
$12::text AS task_name,
|
|
5677
5872
|
$13::jsonb AS params,
|
|
5678
5873
|
$14::jsonb AS options
|
|
5679
|
-
WHERE EXISTS (SELECT 1 FROM
|
|
5874
|
+
WHERE EXISTS (SELECT 1 FROM occurrence_admitted)
|
|
5680
5875
|
), successor_task_spawn AS MATERIALIZED (
|
|
5681
5876
|
SELECT spawned.task_id::text AS task_id
|
|
5682
5877
|
FROM successor_task_request
|
|
@@ -5750,10 +5945,14 @@ export async function firePostgresSchedulerCronSchedule(
|
|
|
5750
5945
|
AND schedule.state = 'active'
|
|
5751
5946
|
AND schedule.current_due_at = to_timestamp($3::double precision / 1000.0)
|
|
5752
5947
|
AND schedule.current_fire_generation = $15::bigint
|
|
5753
|
-
AND EXISTS (SELECT 1 FROM
|
|
5948
|
+
AND EXISTS (SELECT 1 FROM occurrence_admitted)
|
|
5754
5949
|
RETURNING schedule_id
|
|
5755
5950
|
)
|
|
5756
|
-
SELECT EXISTS (SELECT 1 FROM schedule_advance) AS
|
|
5951
|
+
SELECT EXISTS (SELECT 1 FROM schedule_advance) AS advanced,
|
|
5952
|
+
EXISTS (SELECT 1 FROM run_insert) AS run_created,
|
|
5953
|
+
(SELECT schedule_current FROM occurrence) AS schedule_current,
|
|
5954
|
+
(SELECT existing_run FROM occurrence) AS existing_run,
|
|
5955
|
+
(SELECT matching_existing FROM occurrence) AS matching_existing,
|
|
5757
5956
|
coalesce(
|
|
5758
5957
|
(SELECT accepting
|
|
5759
5958
|
FROM ${tableName('runtime_release_admission', options)}
|
|
@@ -5780,19 +5979,34 @@ export async function firePostgresSchedulerCronSchedule(
|
|
|
5780
5979
|
releaseAdmissionKey,
|
|
5781
5980
|
],
|
|
5782
5981
|
);
|
|
5783
|
-
|
|
5982
|
+
const fired = result.rows[0];
|
|
5983
|
+
if (fired?.release_accepting !== true) {
|
|
5784
5984
|
throw new Error(
|
|
5785
5985
|
`Cron schedule "${schedule.scheduleId}" cannot fire because Absurd release "${releaseAdmissionKey}" is not accepting admissions.`,
|
|
5786
5986
|
);
|
|
5787
5987
|
}
|
|
5788
|
-
if (
|
|
5789
|
-
return {
|
|
5988
|
+
if (fired.advanced === true) {
|
|
5989
|
+
return {
|
|
5990
|
+
status: 'admitted',
|
|
5991
|
+
runId: launch.runId,
|
|
5992
|
+
successorDueAtMs,
|
|
5993
|
+
reused: fired.run_created !== true,
|
|
5994
|
+
};
|
|
5790
5995
|
}
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5996
|
+
if (
|
|
5997
|
+
fired.schedule_current === true &&
|
|
5998
|
+
fired.existing_run === true &&
|
|
5999
|
+
fired.matching_existing !== true
|
|
6000
|
+
) {
|
|
6001
|
+
return {
|
|
6002
|
+
status: 'stalled',
|
|
6003
|
+
runId: launch.runId,
|
|
6004
|
+
reason:
|
|
6005
|
+
`Cron schedule "${schedule.scheduleId}" generation ${schedule.generation} cannot advance past ` +
|
|
6006
|
+
`occurrence ${schedule.dueAtMs}: Run "${launch.runId}" already exists with a different launch identity.`,
|
|
6007
|
+
};
|
|
6008
|
+
}
|
|
6009
|
+
return { status: 'superseded' };
|
|
5796
6010
|
}
|
|
5797
6011
|
|
|
5798
6012
|
/** Fence a malformed/invalid timer so it cannot repeatedly consume workers. */
|
package/dist/cli/index.js
CHANGED
|
@@ -3051,7 +3051,7 @@ var SDK_RELEASE = {
|
|
|
3051
3051
|
// getters keep their established compatibility behavior.
|
|
3052
3052
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
3053
3053
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
3054
|
-
version: "0.3.
|
|
3054
|
+
version: "0.3.186",
|
|
3055
3055
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
3056
3056
|
packageCapabilities: {
|
|
3057
3057
|
updatePreferences: 1
|
|
@@ -27485,7 +27485,9 @@ function readLiveCronMetadata(play) {
|
|
|
27485
27485
|
return {
|
|
27486
27486
|
schedule: typeof metadata?.cronSchedule === "string" ? metadata.cronSchedule : null,
|
|
27487
27487
|
timezone: typeof metadata?.cronTimezone === "string" ? metadata.cronTimezone : null,
|
|
27488
|
-
nextScheduledAt: typeof metadata?.nextScheduledAt === "number" ? metadata.nextScheduledAt : null
|
|
27488
|
+
nextScheduledAt: typeof metadata?.nextScheduledAt === "number" ? metadata.nextScheduledAt : null,
|
|
27489
|
+
blockedAt: typeof metadata?.blockedAt === "number" ? metadata.blockedAt : null,
|
|
27490
|
+
blockedReasonCode: typeof metadata?.blockedReasonCode === "string" ? metadata.blockedReasonCode : null
|
|
27489
27491
|
};
|
|
27490
27492
|
}
|
|
27491
27493
|
function liveTriggerStatusLines(status, play) {
|
|
@@ -27504,6 +27506,18 @@ function liveTriggerStatusLines(status, play) {
|
|
|
27504
27506
|
}
|
|
27505
27507
|
if (status?.blockedReason) {
|
|
27506
27508
|
lines.push(` Schedule issue: ${status.blockedReason}`);
|
|
27509
|
+
if (status.blockedReasonCode || cron.blockedReasonCode) {
|
|
27510
|
+
lines.push(
|
|
27511
|
+
` Schedule issue code: ${status.blockedReasonCode ?? cron.blockedReasonCode}`
|
|
27512
|
+
);
|
|
27513
|
+
}
|
|
27514
|
+
const blockedAt = status.blockedAt ?? cron.blockedAt;
|
|
27515
|
+
if (blockedAt !== null && blockedAt !== void 0) {
|
|
27516
|
+
lines.push(` Schedule blocked at: ${formatTimestamp(blockedAt)}`);
|
|
27517
|
+
}
|
|
27518
|
+
lines.push(
|
|
27519
|
+
" Recovery: republish the live revision to re-arm this schedule after the platform issue is fixed."
|
|
27520
|
+
);
|
|
27507
27521
|
}
|
|
27508
27522
|
}
|
|
27509
27523
|
if (status?.webhook) {
|
|
@@ -27516,7 +27530,9 @@ function triggerStatusFromMetadata(value) {
|
|
|
27516
27530
|
return {
|
|
27517
27531
|
cron: typeof metadata?.cronStatus === "string" ? metadata.cronStatus : null,
|
|
27518
27532
|
webhook: typeof metadata?.webhookStatus === "string" ? metadata.webhookStatus : null,
|
|
27519
|
-
blockedReason: typeof metadata?.blockedReason === "string" ? metadata.blockedReason : null
|
|
27533
|
+
blockedReason: typeof metadata?.blockedReason === "string" ? metadata.blockedReason : null,
|
|
27534
|
+
blockedReasonCode: typeof metadata?.blockedReasonCode === "string" ? metadata.blockedReasonCode : null,
|
|
27535
|
+
blockedAt: typeof metadata?.blockedAt === "number" ? metadata.blockedAt : null
|
|
27520
27536
|
};
|
|
27521
27537
|
}
|
|
27522
27538
|
function printPublishReceipt(input2) {
|
|
@@ -29318,6 +29334,16 @@ async function handlePlayList(args) {
|
|
|
29318
29334
|
);
|
|
29319
29335
|
if (play.triggerStatus.blockedReason) {
|
|
29320
29336
|
lines.push(` schedule issue: ${play.triggerStatus.blockedReason}`);
|
|
29337
|
+
if (play.triggerStatus.blockedReasonCode) {
|
|
29338
|
+
lines.push(
|
|
29339
|
+
` schedule issue code: ${play.triggerStatus.blockedReasonCode}`
|
|
29340
|
+
);
|
|
29341
|
+
}
|
|
29342
|
+
if (play.triggerStatus.blockedAt !== void 0) {
|
|
29343
|
+
lines.push(
|
|
29344
|
+
` schedule blocked at: ${formatTimestamp(play.triggerStatus.blockedAt)}`
|
|
29345
|
+
);
|
|
29346
|
+
}
|
|
29321
29347
|
}
|
|
29322
29348
|
} else {
|
|
29323
29349
|
lines.push(" scheduled execution: not configured");
|
package/dist/cli/index.mjs
CHANGED
|
@@ -3046,7 +3046,7 @@ var SDK_RELEASE = {
|
|
|
3046
3046
|
// getters keep their established compatibility behavior.
|
|
3047
3047
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
3048
3048
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
3049
|
-
version: "0.3.
|
|
3049
|
+
version: "0.3.186",
|
|
3050
3050
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
3051
3051
|
packageCapabilities: {
|
|
3052
3052
|
updatePreferences: 1
|
|
@@ -27557,7 +27557,9 @@ function readLiveCronMetadata(play) {
|
|
|
27557
27557
|
return {
|
|
27558
27558
|
schedule: typeof metadata?.cronSchedule === "string" ? metadata.cronSchedule : null,
|
|
27559
27559
|
timezone: typeof metadata?.cronTimezone === "string" ? metadata.cronTimezone : null,
|
|
27560
|
-
nextScheduledAt: typeof metadata?.nextScheduledAt === "number" ? metadata.nextScheduledAt : null
|
|
27560
|
+
nextScheduledAt: typeof metadata?.nextScheduledAt === "number" ? metadata.nextScheduledAt : null,
|
|
27561
|
+
blockedAt: typeof metadata?.blockedAt === "number" ? metadata.blockedAt : null,
|
|
27562
|
+
blockedReasonCode: typeof metadata?.blockedReasonCode === "string" ? metadata.blockedReasonCode : null
|
|
27561
27563
|
};
|
|
27562
27564
|
}
|
|
27563
27565
|
function liveTriggerStatusLines(status, play) {
|
|
@@ -27576,6 +27578,18 @@ function liveTriggerStatusLines(status, play) {
|
|
|
27576
27578
|
}
|
|
27577
27579
|
if (status?.blockedReason) {
|
|
27578
27580
|
lines.push(` Schedule issue: ${status.blockedReason}`);
|
|
27581
|
+
if (status.blockedReasonCode || cron.blockedReasonCode) {
|
|
27582
|
+
lines.push(
|
|
27583
|
+
` Schedule issue code: ${status.blockedReasonCode ?? cron.blockedReasonCode}`
|
|
27584
|
+
);
|
|
27585
|
+
}
|
|
27586
|
+
const blockedAt = status.blockedAt ?? cron.blockedAt;
|
|
27587
|
+
if (blockedAt !== null && blockedAt !== void 0) {
|
|
27588
|
+
lines.push(` Schedule blocked at: ${formatTimestamp(blockedAt)}`);
|
|
27589
|
+
}
|
|
27590
|
+
lines.push(
|
|
27591
|
+
" Recovery: republish the live revision to re-arm this schedule after the platform issue is fixed."
|
|
27592
|
+
);
|
|
27579
27593
|
}
|
|
27580
27594
|
}
|
|
27581
27595
|
if (status?.webhook) {
|
|
@@ -27588,7 +27602,9 @@ function triggerStatusFromMetadata(value) {
|
|
|
27588
27602
|
return {
|
|
27589
27603
|
cron: typeof metadata?.cronStatus === "string" ? metadata.cronStatus : null,
|
|
27590
27604
|
webhook: typeof metadata?.webhookStatus === "string" ? metadata.webhookStatus : null,
|
|
27591
|
-
blockedReason: typeof metadata?.blockedReason === "string" ? metadata.blockedReason : null
|
|
27605
|
+
blockedReason: typeof metadata?.blockedReason === "string" ? metadata.blockedReason : null,
|
|
27606
|
+
blockedReasonCode: typeof metadata?.blockedReasonCode === "string" ? metadata.blockedReasonCode : null,
|
|
27607
|
+
blockedAt: typeof metadata?.blockedAt === "number" ? metadata.blockedAt : null
|
|
27592
27608
|
};
|
|
27593
27609
|
}
|
|
27594
27610
|
function printPublishReceipt(input2) {
|
|
@@ -29390,6 +29406,16 @@ async function handlePlayList(args) {
|
|
|
29390
29406
|
);
|
|
29391
29407
|
if (play.triggerStatus.blockedReason) {
|
|
29392
29408
|
lines.push(` schedule issue: ${play.triggerStatus.blockedReason}`);
|
|
29409
|
+
if (play.triggerStatus.blockedReasonCode) {
|
|
29410
|
+
lines.push(
|
|
29411
|
+
` schedule issue code: ${play.triggerStatus.blockedReasonCode}`
|
|
29412
|
+
);
|
|
29413
|
+
}
|
|
29414
|
+
if (play.triggerStatus.blockedAt !== void 0) {
|
|
29415
|
+
lines.push(
|
|
29416
|
+
` schedule blocked at: ${formatTimestamp(play.triggerStatus.blockedAt)}`
|
|
29417
|
+
);
|
|
29418
|
+
}
|
|
29393
29419
|
}
|
|
29394
29420
|
} else {
|
|
29395
29421
|
lines.push(" scheduled execution: not configured");
|
package/dist/index.d.mts
CHANGED
|
@@ -2207,6 +2207,8 @@ interface PlayDefinitionDetail {
|
|
|
2207
2207
|
cronTimezone?: string | null;
|
|
2208
2208
|
nextScheduledAt?: number | null;
|
|
2209
2209
|
lastScheduledAt?: number | null;
|
|
2210
|
+
blockedAt?: number | null;
|
|
2211
|
+
blockedReasonCode?: string | null;
|
|
2210
2212
|
blockedReason?: string | null;
|
|
2211
2213
|
[key: string]: unknown;
|
|
2212
2214
|
} | null;
|
|
@@ -2270,6 +2272,8 @@ interface PlayTriggerStatus {
|
|
|
2270
2272
|
cron: string | null;
|
|
2271
2273
|
webhook: string | null;
|
|
2272
2274
|
blockedReason: string | null;
|
|
2275
|
+
blockedReasonCode?: string;
|
|
2276
|
+
blockedAt?: number;
|
|
2273
2277
|
}
|
|
2274
2278
|
interface ProductNotificationEventDefinition {
|
|
2275
2279
|
id: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -2207,6 +2207,8 @@ interface PlayDefinitionDetail {
|
|
|
2207
2207
|
cronTimezone?: string | null;
|
|
2208
2208
|
nextScheduledAt?: number | null;
|
|
2209
2209
|
lastScheduledAt?: number | null;
|
|
2210
|
+
blockedAt?: number | null;
|
|
2211
|
+
blockedReasonCode?: string | null;
|
|
2210
2212
|
blockedReason?: string | null;
|
|
2211
2213
|
[key: string]: unknown;
|
|
2212
2214
|
} | null;
|
|
@@ -2270,6 +2272,8 @@ interface PlayTriggerStatus {
|
|
|
2270
2272
|
cron: string | null;
|
|
2271
2273
|
webhook: string | null;
|
|
2272
2274
|
blockedReason: string | null;
|
|
2275
|
+
blockedReasonCode?: string;
|
|
2276
|
+
blockedAt?: number;
|
|
2273
2277
|
}
|
|
2274
2278
|
interface ProductNotificationEventDefinition {
|
|
2275
2279
|
id: string;
|
package/dist/index.js
CHANGED
|
@@ -864,7 +864,7 @@ var SDK_RELEASE = {
|
|
|
864
864
|
// getters keep their established compatibility behavior.
|
|
865
865
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
866
866
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
867
|
-
version: "0.3.
|
|
867
|
+
version: "0.3.186",
|
|
868
868
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
869
869
|
packageCapabilities: {
|
|
870
870
|
updatePreferences: 1
|
package/dist/index.mjs
CHANGED
|
@@ -768,7 +768,7 @@ var SDK_RELEASE = {
|
|
|
768
768
|
// getters keep their established compatibility behavior.
|
|
769
769
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
770
770
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
771
|
-
version: "0.3.
|
|
771
|
+
version: "0.3.186",
|
|
772
772
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
773
773
|
packageCapabilities: {
|
|
774
774
|
updatePreferences: 1
|
|
@@ -209,6 +209,7 @@
|
|
|
209
209
|
"dist/bundling-sources/shared_libs/play-runtime/internal-bootstrap-token.ts",
|
|
210
210
|
"dist/bundling-sources/shared_libs/play-runtime/internal-step-ids.ts",
|
|
211
211
|
"dist/bundling-sources/shared_libs/play-runtime/lane-retirement-gate.ts",
|
|
212
|
+
"dist/bundling-sources/shared_libs/play-runtime/launch-identity.ts",
|
|
212
213
|
"dist/bundling-sources/shared_libs/play-runtime/launch-source-policy.ts",
|
|
213
214
|
"dist/bundling-sources/shared_libs/play-runtime/lease-policy.ts",
|
|
214
215
|
"dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts",
|
package/dist/release.d.mts
CHANGED
|
@@ -149,7 +149,7 @@ type SdkRelease = {
|
|
|
149
149
|
supportPolicy: SdkSupportPolicy;
|
|
150
150
|
};
|
|
151
151
|
declare const SDK_RELEASE: {
|
|
152
|
-
readonly version: "0.3.
|
|
152
|
+
readonly version: "0.3.186";
|
|
153
153
|
readonly updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.";
|
|
154
154
|
readonly packageCapabilities: {
|
|
155
155
|
readonly updatePreferences: 1;
|
package/dist/release.d.ts
CHANGED
|
@@ -149,7 +149,7 @@ type SdkRelease = {
|
|
|
149
149
|
supportPolicy: SdkSupportPolicy;
|
|
150
150
|
};
|
|
151
151
|
declare const SDK_RELEASE: {
|
|
152
|
-
readonly version: "0.3.
|
|
152
|
+
readonly version: "0.3.186";
|
|
153
153
|
readonly updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.";
|
|
154
154
|
readonly packageCapabilities: {
|
|
155
155
|
readonly updatePreferences: 1;
|
package/dist/release.js
CHANGED
|
@@ -74,7 +74,7 @@ var SDK_RELEASE = {
|
|
|
74
74
|
// getters keep their established compatibility behavior.
|
|
75
75
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
76
76
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
77
|
-
version: "0.3.
|
|
77
|
+
version: "0.3.186",
|
|
78
78
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
79
79
|
packageCapabilities: {
|
|
80
80
|
updatePreferences: 1
|
package/dist/release.mjs
CHANGED
|
@@ -48,7 +48,7 @@ var SDK_RELEASE = {
|
|
|
48
48
|
// getters keep their established compatibility behavior.
|
|
49
49
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
50
50
|
// 0.3.90 is the first deliberately versioned SDK release for API v3.
|
|
51
|
-
version: "0.3.
|
|
51
|
+
version: "0.3.186",
|
|
52
52
|
updateSummary: "Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.",
|
|
53
53
|
packageCapabilities: {
|
|
54
54
|
updatePreferences: 1
|