deepline 0.3.285 → 0.3.287
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/client.ts +48 -26
- package/dist/bundling-sources/sdk/src/index.ts +4 -0
- package/dist/bundling-sources/sdk/src/release.ts +7 -1
- package/dist/bundling-sources/sdk/src/types.ts +36 -0
- package/dist/bundling-sources/shared_libs/play-runtime/cell-provenance.ts +16 -0
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +21 -0
- package/dist/bundling-sources/shared_libs/play-runtime/live-state-contract.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/job.ts +18 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-semantics.ts +16 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +38 -3
- package/dist/bundling-sources/shared_libs/play-runtime/run-observation.ts +12 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +43 -1
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +28 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +88 -1
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +243 -90
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-event-search.ts +53 -25
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +40 -7
- package/dist/bundling-sources/shared_libs/play-runtime/step-progress.ts +83 -1
- package/dist/bundling-sources/shared_libs/play-runtime/test-async-batching.ts +4 -1
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +68 -0
- package/dist/bundling-sources/shared_libs/play-runtime/worker-api-types.ts +2 -0
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +10 -1
- package/dist/bundling-sources/shared_libs/plays/enrich-compat-adapter.ts +2 -0
- package/dist/cli/index.js +30615 -34474
- package/dist/cli/index.mjs +30310 -34181
- package/dist/{client-T2jVnZrq.d.ts → client-FR_u0dxT.d.ts} +40 -4
- package/dist/{client-Cl-zj2oS.d.mts → client-phK1Ixcl.d.mts} +40 -4
- package/dist/{compiler-manifest-B1zo3igW.d.mts → compiler-manifest-9SQtUuKb.d.mts} +1 -1
- package/dist/{compiler-manifest-B1zo3igW.d.ts → compiler-manifest-9SQtUuKb.d.ts} +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +57 -28
- package/dist/index.mjs +57 -28
- package/dist/install-integrity.json +4 -4
- package/dist/plays/bundle-play-file.d.mts +2 -2
- package/dist/plays/bundle-play-file.d.ts +2 -2
- package/dist/plays/bundle-play-file.mjs +8 -1
- package/dist/plays/run-request.d.mts +2 -2
- package/dist/plays/run-request.d.ts +2 -2
- package/dist/release.d.mts +5 -1
- package/dist/release.d.ts +5 -1
- package/dist/release.js +6 -1
- package/dist/release.mjs +6 -1
- package/package.json +1 -1
package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-event-search.ts
CHANGED
|
@@ -22,6 +22,11 @@ const EVENTS_TABLE = 'runtime_observability.events';
|
|
|
22
22
|
const RUNTIME_EVENT_LOG_DEDUPE_INDEX = 'runtime_events_log_attempt_digest_idx';
|
|
23
23
|
const RUNTIME_EVENT_LOG_POSITION_INDEX =
|
|
24
24
|
'runtime_events_log_attempt_position_idx';
|
|
25
|
+
const RUNTIME_EVENT_LOG_POSITION_CHANNELS = [
|
|
26
|
+
'worker',
|
|
27
|
+
'replay',
|
|
28
|
+
'envelope',
|
|
29
|
+
] as const;
|
|
25
30
|
const RUNTIME_EVENT_LOG_LEGACY_INDEX =
|
|
26
31
|
'runtime_events_legacy_log_normalize_idx';
|
|
27
32
|
const RUNTIME_EVENT_LOG_BODY_PAGE_INDEX = 'runtime_events_run_log_body_seq_idx';
|
|
@@ -51,7 +56,7 @@ const RUNTIME_EVENT_LOG_POSITION_EXPRESSION = `jsonb_set(
|
|
|
51
56
|
// Migration readiness tracks this projection body independently of scheduler
|
|
52
57
|
// wire and schema versions. Bump when a changed trigger must be reinstalled.
|
|
53
58
|
export const RUNTIME_EVENT_SEARCH_OUTBOX_PROJECTION_MARKER =
|
|
54
|
-
'runtime-event-search-log-context-
|
|
59
|
+
'runtime-event-search-log-context-v14-btree-position';
|
|
55
60
|
export const RUNTIME_EVENT_CANONICAL_RETENTION_INDEX_READY_MARKER =
|
|
56
61
|
'runtime-event-canonical-retention-v1';
|
|
57
62
|
export const RUNTIME_EVENTS_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
|
|
@@ -1263,10 +1268,7 @@ export async function attachRuntimeEventSearchTriggers(
|
|
|
1263
1268
|
'logPositions', jsonb_build_object(log_channel, log_position));
|
|
1264
1269
|
position_alias := jsonb_build_object(
|
|
1265
1270
|
'producerAttempt', (item->>'producerAttempt')::integer,
|
|
1266
|
-
|
|
1267
|
-
'_orgId:' || run_org, true,
|
|
1268
|
-
'_runId:' || observation.run_id, true)
|
|
1269
|
-
|| jsonb_build_object(log_channel, log_position);
|
|
1271
|
+
log_channel, log_position);
|
|
1270
1272
|
matched_event_id := NULL;
|
|
1271
1273
|
position_event_ids := ARRAY[
|
|
1272
1274
|
legacy_position_prefix || log_position::text,
|
|
@@ -1293,24 +1295,26 @@ export async function attachRuntimeEventSearchTriggers(
|
|
|
1293
1295
|
ORDER BY event.event_id
|
|
1294
1296
|
LIMIT 1;
|
|
1295
1297
|
IF matched_event_id IS NULL THEN
|
|
1296
|
-
--
|
|
1297
|
-
--
|
|
1298
|
-
--
|
|
1299
|
-
-- immutable-position check below. Materialize the scoped
|
|
1300
|
-
-- position lookup before applying run filters: otherwise
|
|
1301
|
-
-- the planner can choose the run-history index and inspect
|
|
1302
|
-
-- every old log for each incoming position, even with a
|
|
1303
|
-
-- custom plan. The indexed document already binds scope,
|
|
1304
|
-
-- org, run, attempt and channel position; retain the outer
|
|
1305
|
-
-- identity checks as defense in depth.
|
|
1298
|
+
-- Pack scope, organization and run into one indexed key.
|
|
1299
|
+
-- The materialization keeps generic plans from choosing a
|
|
1300
|
+
-- run-history scan based on the outer identity checks.
|
|
1306
1301
|
WITH position_matches AS MATERIALIZED (
|
|
1302
|
+
${RUNTIME_EVENT_LOG_POSITION_CHANNELS.map(
|
|
1303
|
+
(channel) => `
|
|
1307
1304
|
SELECT event.event_id, event.source_digest, event.search_doc,
|
|
1308
|
-
event.
|
|
1305
|
+
event.log_seq, event.runtime_scope, event.org_id, event.run_id
|
|
1309
1306
|
FROM runtime_observability.events AS event
|
|
1310
|
-
WHERE
|
|
1307
|
+
WHERE log_channel = '${channel}'
|
|
1308
|
+
AND ARRAY[event.runtime_scope, event.org_id, event.run_id]
|
|
1309
|
+
= ARRAY[${quoteLiteral(scope)}, run_org, observation.run_id]
|
|
1310
|
+
AND event.kind = ${RUN_EVENT_KIND_SQL_LITERAL.logAppended}
|
|
1311
1311
|
AND event.search_doc ? 'producerAttempt'
|
|
1312
1312
|
AND event.search_doc ? 'logPositions'
|
|
1313
|
-
AND (
|
|
1313
|
+
AND (event.search_doc->'logPositions') ? '${channel}'
|
|
1314
|
+
AND event.search_doc->'producerAttempt' = position_alias->'producerAttempt'
|
|
1315
|
+
AND event.search_doc->'logPositions'->'${channel}' = position_alias->'${channel}'
|
|
1316
|
+
`,
|
|
1317
|
+
).join(' UNION ALL ')}
|
|
1314
1318
|
)
|
|
1315
1319
|
SELECT event.event_id, event.source_digest, event.search_doc
|
|
1316
1320
|
INTO matched_event_id, existing_digest, matched_doc
|
|
@@ -2034,8 +2038,27 @@ const RUNTIME_EVENT_LOG_POSITION_INDEX_SPEC: RuntimeEventIndexExpectation = {
|
|
|
2034
2038
|
WHERE ${RUNTIME_EVENT_LOG_POSITION_PREDICATE}`,
|
|
2035
2039
|
};
|
|
2036
2040
|
|
|
2041
|
+
const RUNTIME_EVENT_LOG_CHANNEL_POSITION_INDEXES: RuntimeEventIndexExpectation[] =
|
|
2042
|
+
RUNTIME_EVENT_LOG_POSITION_CHANNELS.map((channel) => ({
|
|
2043
|
+
name: `runtime_events_log_${channel}_position_idx`,
|
|
2044
|
+
keys: [
|
|
2045
|
+
'ARRAY[runtime_scope, org_id, run_id]',
|
|
2046
|
+
"(search_doc -> 'producerAttempt'::text)",
|
|
2047
|
+
`(search_doc -> 'logPositions'::text) -> '${channel}'::text`,
|
|
2048
|
+
],
|
|
2049
|
+
predicate: `${RUNTIME_EVENT_LOG_POSITION_PREDICATE}
|
|
2050
|
+
AND (search_doc->'logPositions') ? '${channel}'`,
|
|
2051
|
+
createSql: `CREATE INDEX CONCURRENTLY IF NOT EXISTS runtime_events_log_${channel}_position_idx
|
|
2052
|
+
ON runtime_observability.events
|
|
2053
|
+
((ARRAY[runtime_scope, org_id, run_id]), (search_doc->'producerAttempt'),
|
|
2054
|
+
(search_doc->'logPositions'->'${channel}'))
|
|
2055
|
+
WHERE ${RUNTIME_EVENT_LOG_POSITION_PREDICATE}
|
|
2056
|
+
AND (search_doc->'logPositions') ? '${channel}'`,
|
|
2057
|
+
}));
|
|
2058
|
+
|
|
2037
2059
|
const RUNTIME_EVENT_QUERY_INDEXES: RuntimeEventIndexExpectation[] = [
|
|
2038
2060
|
RUNTIME_EVENT_LOG_POSITION_INDEX_SPEC,
|
|
2061
|
+
...RUNTIME_EVENT_LOG_CHANNEL_POSITION_INDEXES,
|
|
2039
2062
|
{
|
|
2040
2063
|
name: RUNTIME_EVENT_LOG_DEDUPE_INDEX,
|
|
2041
2064
|
keys: [
|
|
@@ -2167,20 +2190,25 @@ async function prepareRuntimeEventQueryIndex(
|
|
|
2167
2190
|
export async function hasRuntimeEventLogPositionIndex(
|
|
2168
2191
|
client: PostgresSchedulerQueryClient,
|
|
2169
2192
|
): Promise<boolean> {
|
|
2170
|
-
|
|
2171
|
-
client,
|
|
2193
|
+
for (const expected of [
|
|
2172
2194
|
RUNTIME_EVENT_LOG_POSITION_INDEX_SPEC,
|
|
2173
|
-
|
|
2195
|
+
...RUNTIME_EVENT_LOG_CHANNEL_POSITION_INDEXES,
|
|
2196
|
+
]) {
|
|
2197
|
+
if (!(await hasRuntimeEventQueryIndex(client, expected))) return false;
|
|
2198
|
+
}
|
|
2199
|
+
return true;
|
|
2174
2200
|
}
|
|
2175
2201
|
|
|
2176
|
-
/** Prepare
|
|
2202
|
+
/** Prepare old and new position indexes before replacing the projection body. */
|
|
2177
2203
|
export async function prepareRuntimeEventLogPositionIndex(
|
|
2178
2204
|
client: PostgresSchedulerQueryClient,
|
|
2179
2205
|
): Promise<void> {
|
|
2180
|
-
|
|
2181
|
-
client,
|
|
2206
|
+
for (const expected of [
|
|
2182
2207
|
RUNTIME_EVENT_LOG_POSITION_INDEX_SPEC,
|
|
2183
|
-
|
|
2208
|
+
...RUNTIME_EVENT_LOG_CHANNEL_POSITION_INDEXES,
|
|
2209
|
+
]) {
|
|
2210
|
+
await prepareRuntimeEventQueryIndex(client, expected);
|
|
2211
|
+
}
|
|
2184
2212
|
}
|
|
2185
2213
|
|
|
2186
2214
|
/** Build only operator-owned indexes, concurrently and outside a transaction. */
|
|
@@ -337,7 +337,6 @@ export async function reserveRuntimeSandboxCapacityLease(
|
|
|
337
337
|
AND operation.state = $4
|
|
338
338
|
AND lease.released_at IS NULL
|
|
339
339
|
AND lease.sandbox_id IS NULL
|
|
340
|
-
AND lease.expires_at > clock_timestamp()
|
|
341
340
|
ORDER BY operation.created_at ASC
|
|
342
341
|
LIMIT 2`,
|
|
343
342
|
[orgId, runId, input.provider, RuntimeSandboxOperationState.Reserved],
|
|
@@ -770,7 +769,10 @@ export async function bindRuntimeSandboxCapacityLease(
|
|
|
770
769
|
`
|
|
771
770
|
UPDATE ${leases}
|
|
772
771
|
SET provider = $2, sandbox_id = $3, routing_domain = $4
|
|
773
|
-
WHERE lease_id = $1 AND released_at IS NULL AND
|
|
772
|
+
WHERE lease_id = $1 AND released_at IS NULL AND provider = $2
|
|
773
|
+
AND (expires_at > clock_timestamp() OR sandbox_id = $3)
|
|
774
|
+
AND (sandbox_id IS NULL OR sandbox_id = $3)
|
|
775
|
+
AND (sandbox_id IS NULL OR routing_domain IS NOT DISTINCT FROM $4)
|
|
774
776
|
RETURNING lease_id
|
|
775
777
|
`,
|
|
776
778
|
[
|
|
@@ -793,7 +795,7 @@ export async function releaseRuntimeSandboxCapacityLease(
|
|
|
793
795
|
`
|
|
794
796
|
UPDATE ${leases}
|
|
795
797
|
SET released_at = clock_timestamp()
|
|
796
|
-
WHERE lease_id = $1 AND released_at IS NULL
|
|
798
|
+
WHERE lease_id = $1 AND released_at IS NULL AND sandbox_id IS NULL
|
|
797
799
|
RETURNING lease_id
|
|
798
800
|
`,
|
|
799
801
|
[assertId(input.leaseId, 'leaseId')],
|
|
@@ -811,15 +813,29 @@ export async function abandonRuntimeSandboxOperationReservation(
|
|
|
811
813
|
input: { operationKey: string },
|
|
812
814
|
options?: Pick<PostgresSchedulerOptions, 'schema'>,
|
|
813
815
|
): Promise<boolean> {
|
|
814
|
-
const { leases, operations } = schemaTables(options);
|
|
816
|
+
const { leases, operations, runs } = schemaTables(options);
|
|
815
817
|
const result = await client.query<{ operation_key: string }>(
|
|
816
818
|
`
|
|
817
|
-
WITH
|
|
819
|
+
WITH custody_run AS MATERIALIZED (
|
|
820
|
+
SELECT run_id FROM ${runs}
|
|
821
|
+
WHERE run_id = (SELECT run_id FROM ${operations} WHERE operation_key = $1)
|
|
822
|
+
FOR NO KEY UPDATE
|
|
823
|
+
), custody_attempts AS MATERIALIZED (
|
|
824
|
+
SELECT attempt.* FROM ${quoteIdent(options?.schema ?? 'runtime_scheduler')}."attempts" AS attempt
|
|
825
|
+
WHERE attempt.run_id IN (SELECT run_id FROM custody_run)
|
|
826
|
+
ORDER BY attempt.attempt FOR UPDATE
|
|
827
|
+
), eligible_lease AS MATERIALIZED (
|
|
828
|
+
SELECT lease.lease_id FROM ${leases} AS lease
|
|
829
|
+
CROSS JOIN (SELECT count(*) FROM custody_attempts) AS attempt_locks
|
|
830
|
+
WHERE lease_id = $1 AND sandbox_id IS NULL AND released_at IS NULL
|
|
831
|
+
FOR UPDATE OF lease
|
|
832
|
+
), abandoned AS (
|
|
818
833
|
UPDATE ${operations} AS operation
|
|
819
834
|
SET state = $2,
|
|
820
835
|
updated_at = clock_timestamp()
|
|
821
836
|
WHERE operation.operation_key = $1
|
|
822
837
|
AND operation.state = $3
|
|
838
|
+
AND EXISTS (SELECT 1 FROM eligible_lease)
|
|
823
839
|
RETURNING operation.operation_key
|
|
824
840
|
), released AS (
|
|
825
841
|
UPDATE ${leases} AS lease
|
|
@@ -898,14 +914,31 @@ export async function recordRecoveredDaytonaCancellationSandbox(
|
|
|
898
914
|
const { operations, leases, cleanup } = schemaTables(options);
|
|
899
915
|
const schema = quoteIdent(options?.schema ?? 'runtime_scheduler');
|
|
900
916
|
const recorded = await client.query<{ operation_key: string }>(
|
|
901
|
-
`WITH
|
|
917
|
+
`WITH custody_run AS MATERIALIZED (
|
|
918
|
+
SELECT run.run_id FROM ${schema}."runs" AS run
|
|
919
|
+
WHERE run.run_id = (SELECT run_id FROM ${operations} WHERE operation_key = $1)
|
|
920
|
+
FOR NO KEY UPDATE
|
|
921
|
+
), custody_attempts AS MATERIALIZED (
|
|
922
|
+
SELECT attempt.* FROM ${schema}."attempts" AS attempt
|
|
923
|
+
WHERE attempt.run_id IN (SELECT run_id FROM custody_run)
|
|
924
|
+
ORDER BY attempt.attempt FOR UPDATE
|
|
925
|
+
), custody_lease AS MATERIALIZED (
|
|
926
|
+
SELECT lease.lease_id FROM ${leases} AS lease
|
|
927
|
+
CROSS JOIN (SELECT count(*) FROM custody_attempts) AS attempt_locks
|
|
928
|
+
WHERE lease.lease_id = $1 FOR UPDATE OF lease
|
|
929
|
+
), custody_operation AS MATERIALIZED (
|
|
930
|
+
SELECT operation.operation_key FROM ${operations} AS operation
|
|
931
|
+
CROSS JOIN (SELECT count(*) FROM custody_lease) AS lease_locks
|
|
932
|
+
WHERE operation.operation_key = $1 FOR UPDATE OF operation
|
|
933
|
+
), promoted AS (
|
|
902
934
|
UPDATE ${operations} AS operation
|
|
903
935
|
SET state = 'deleting',
|
|
904
936
|
sandbox_id = $2,
|
|
905
937
|
routing_domain = $3,
|
|
906
938
|
provider_created_at = clock_timestamp(),
|
|
907
939
|
updated_at = clock_timestamp()
|
|
908
|
-
|
|
940
|
+
FROM custody_operation
|
|
941
|
+
WHERE operation.operation_key = custody_operation.operation_key
|
|
909
942
|
AND operation.provider = 'daytona'
|
|
910
943
|
AND operation.state = 'reserved'
|
|
911
944
|
RETURNING operation.operation_key, operation.run_id, operation.attempt,
|
|
@@ -1,4 +1,17 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
getTopLevelPipelineSubsteps,
|
|
3
|
+
type PlayStaticPipeline,
|
|
4
|
+
type PlayStaticSubstep,
|
|
5
|
+
} from '../plays/static-pipeline';
|
|
6
|
+
import {
|
|
7
|
+
docflowOutputRoots,
|
|
8
|
+
flattenSubsteps,
|
|
9
|
+
resolveDocflowOwnerDataset,
|
|
10
|
+
} from '../plays/docflow-binding-owner';
|
|
11
|
+
import {
|
|
12
|
+
normalizePlayConditionCounts,
|
|
13
|
+
type PlayConditionCounts,
|
|
14
|
+
} from './cell-provenance';
|
|
2
15
|
import {
|
|
3
16
|
normalizePlayDocflowNodeIoState,
|
|
4
17
|
type PlayDocflowNodeIoState,
|
|
@@ -32,6 +45,7 @@ export type PlayVisualNodeProgress = {
|
|
|
32
45
|
completedAt?: number | null;
|
|
33
46
|
artifactTableNamespace?: string | null;
|
|
34
47
|
nodeIo?: PlayDocflowNodeIoState;
|
|
48
|
+
conditionCounts?: PlayConditionCounts;
|
|
35
49
|
};
|
|
36
50
|
|
|
37
51
|
export type PlayVisualNodeState = {
|
|
@@ -162,6 +176,9 @@ export function normalizePlayVisualNodeProgressMap(
|
|
|
162
176
|
? null
|
|
163
177
|
: undefined;
|
|
164
178
|
const nodeIo = normalizePlayDocflowNodeIoState(rawProgress.nodeIo);
|
|
179
|
+
const conditionCounts = normalizePlayConditionCounts(
|
|
180
|
+
rawProgress.conditionCounts,
|
|
181
|
+
);
|
|
165
182
|
|
|
166
183
|
normalized[nodeId] = {
|
|
167
184
|
...(completed !== undefined ? { completed } : {}),
|
|
@@ -180,11 +197,76 @@ export function normalizePlayVisualNodeProgressMap(
|
|
|
180
197
|
? { artifactTableNamespace }
|
|
181
198
|
: {}),
|
|
182
199
|
...(nodeIo ? { nodeIo } : {}),
|
|
200
|
+
...(conditionCounts ? { conditionCounts } : {}),
|
|
183
201
|
};
|
|
184
202
|
}
|
|
185
203
|
return normalized;
|
|
186
204
|
}
|
|
187
205
|
|
|
206
|
+
/** Join observed predicates to authored decision nodes by their owning column. */
|
|
207
|
+
export function projectDocflowConditionCounts(
|
|
208
|
+
pipeline: PlayStaticPipeline | null | undefined,
|
|
209
|
+
sheets: readonly {
|
|
210
|
+
tableNamespace: string;
|
|
211
|
+
conditions?: Record<string, PlayConditionCounts>;
|
|
212
|
+
}[],
|
|
213
|
+
): Record<string, PlayConditionCounts> {
|
|
214
|
+
if (!pipeline?.docflow) return {};
|
|
215
|
+
const substeps = getTopLevelPipelineSubsteps(pipeline);
|
|
216
|
+
const namespaces = flattenSubsteps(substeps)
|
|
217
|
+
.filter((step) => step.type === 'dataset' || step.type === 'csv')
|
|
218
|
+
.map((step) =>
|
|
219
|
+
step.type === 'dataset'
|
|
220
|
+
? (step.tableNamespace ?? step.field)
|
|
221
|
+
: step.field,
|
|
222
|
+
)
|
|
223
|
+
.sort((a, b) => b.length - a.length);
|
|
224
|
+
const decisions = new Set(
|
|
225
|
+
pipeline.docflow.nodes
|
|
226
|
+
.filter((node) => node.kind === 'decision' && !node.sketch)
|
|
227
|
+
.map((node) => node.id),
|
|
228
|
+
);
|
|
229
|
+
const result: Record<string, PlayConditionCounts> = {};
|
|
230
|
+
for (const binding of pipeline.docflow.bindings) {
|
|
231
|
+
if (!decisions.has(binding.nodeId)) continue;
|
|
232
|
+
const owner = resolveDocflowOwnerDataset(binding, substeps).substep;
|
|
233
|
+
if (!owner) continue;
|
|
234
|
+
const namespace = owner.tableNamespace ?? owner.field;
|
|
235
|
+
const roots = docflowOutputRoots(binding);
|
|
236
|
+
// Several output columns can carry different predicates. Do not combine them.
|
|
237
|
+
if (roots.length !== 1) continue;
|
|
238
|
+
const root = roots[0]!;
|
|
239
|
+
const column = owner.sheetContract?.columns.find(
|
|
240
|
+
(candidate) =>
|
|
241
|
+
candidate.field === root ||
|
|
242
|
+
candidate.id === root ||
|
|
243
|
+
candidate.sqlName === root,
|
|
244
|
+
);
|
|
245
|
+
const key = column?.sqlName ?? root;
|
|
246
|
+
for (const sheet of sheets) {
|
|
247
|
+
const sheetOwner = namespaces.find(
|
|
248
|
+
(candidate) =>
|
|
249
|
+
sheet.tableNamespace === candidate ||
|
|
250
|
+
sheet.tableNamespace.startsWith(`${candidate}_`),
|
|
251
|
+
);
|
|
252
|
+
if (sheetOwner !== namespace) continue;
|
|
253
|
+
const counts = normalizePlayConditionCounts(
|
|
254
|
+
sheet.conditions?.[key] ?? sheet.conditions?.[root],
|
|
255
|
+
);
|
|
256
|
+
if (!counts) continue;
|
|
257
|
+
const current = result[`docflow:${binding.nodeId}`] ?? {
|
|
258
|
+
true: 0,
|
|
259
|
+
false: 0,
|
|
260
|
+
};
|
|
261
|
+
result[`docflow:${binding.nodeId}`] = {
|
|
262
|
+
true: current.true + counts.true,
|
|
263
|
+
false: current.false + counts.false,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
|
|
188
270
|
export function applyVisualNodeProgress(input: {
|
|
189
271
|
nodeStates: readonly PlayVisualNodeState[];
|
|
190
272
|
progressByNode: PlayVisualNodeProgressMap;
|
|
@@ -87,7 +87,10 @@ export const testAsyncContractLookupBatchStrategy: BatchOperationStrategy<
|
|
|
87
87
|
const first = payloads[0]!;
|
|
88
88
|
const items = payloads.map((payload) => ({
|
|
89
89
|
itemKey: payload.key,
|
|
90
|
-
payload: {
|
|
90
|
+
payload: {
|
|
91
|
+
key: payload.key,
|
|
92
|
+
row_number: payload.row_number,
|
|
93
|
+
},
|
|
91
94
|
}));
|
|
92
95
|
return {
|
|
93
96
|
batchOperation: 'test_async_contract_start',
|
|
@@ -2159,3 +2159,71 @@ export function cloneToolExecuteResultWithExecution<TResult>(
|
|
|
2159
2159
|
execution,
|
|
2160
2160
|
}) as ToolExecuteResult<TResult>;
|
|
2161
2161
|
}
|
|
2162
|
+
|
|
2163
|
+
/**
|
|
2164
|
+
* Native splitters return the logical source response; the historical adapter
|
|
2165
|
+
* stores it inside an extra `{ data }` layer. Keep that immutable receipt and
|
|
2166
|
+
* its legacy raw/getter projections, and select the source response only at a
|
|
2167
|
+
* newly admitted Play's boundary. This is one provenance-backed projection,
|
|
2168
|
+
* never recursive provider-envelope unwrapping.
|
|
2169
|
+
*/
|
|
2170
|
+
export function projectNativeBatchToolResponse(
|
|
2171
|
+
value: ToolExecuteResult,
|
|
2172
|
+
policy: 'legacy_envelope' | 'logical_response' = 'logical_response',
|
|
2173
|
+
): ToolExecuteResult {
|
|
2174
|
+
const stored = value.toolResponse.rawV2;
|
|
2175
|
+
const materialized = value.meta?.nativeBatchResponseMaterialized === true;
|
|
2176
|
+
if (policy === 'legacy_envelope' && !materialized) return value;
|
|
2177
|
+
if (policy === 'logical_response' && materialized) return value;
|
|
2178
|
+
if (!materialized && (!isRecord(stored) || !Object.hasOwn(stored, 'data')))
|
|
2179
|
+
return value;
|
|
2180
|
+
const recordedView = value.meta?.nativeBatchResponseView;
|
|
2181
|
+
let view: ToolResponseView | undefined =
|
|
2182
|
+
recordedView === 'data' || recordedView === 'rawV2'
|
|
2183
|
+
? recordedView
|
|
2184
|
+
: undefined;
|
|
2185
|
+
if (view !== 'data' && view !== 'rawV2') {
|
|
2186
|
+
// Retained BounceBan receipts predate the provenance fact. Its scalar
|
|
2187
|
+
// action returns `{ data: verdict }`; only the old batch adapter adds
|
|
2188
|
+
// `{ data: { data: verdict } }`. Do not apply this repair to other tools
|
|
2189
|
+
// or infer it from a provider's arbitrary `data` field.
|
|
2190
|
+
const source = (stored as Record<string, unknown>).data;
|
|
2191
|
+
const verdict = isRecord(source) ? source.data : undefined;
|
|
2192
|
+
if (
|
|
2193
|
+
value._metadata.toolId !== 'bounceban_verify_single' ||
|
|
2194
|
+
!isRecord(source) ||
|
|
2195
|
+
!isRecord(verdict) ||
|
|
2196
|
+
typeof verdict.email !== 'string' ||
|
|
2197
|
+
(verdict.status !== undefined && verdict.status !== 'success') ||
|
|
2198
|
+
!['deliverable', 'undeliverable', 'risky', 'unknown'].includes(
|
|
2199
|
+
String(verdict.result),
|
|
2200
|
+
)
|
|
2201
|
+
) {
|
|
2202
|
+
return value;
|
|
2203
|
+
}
|
|
2204
|
+
view = 'data';
|
|
2205
|
+
}
|
|
2206
|
+
const response = {
|
|
2207
|
+
...value.toolResponse,
|
|
2208
|
+
rawV2: materialized
|
|
2209
|
+
? { data: stored }
|
|
2210
|
+
: (stored as Record<string, unknown>).data,
|
|
2211
|
+
view: materialized ? ('data' as const) : view,
|
|
2212
|
+
};
|
|
2213
|
+
// Preserve non-enumerable metadata/aliases and live list/getter accessors.
|
|
2214
|
+
// Do not mutate a result shared with another artifact or the receipt cache.
|
|
2215
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
2216
|
+
descriptors.toolResponse = { ...descriptors.toolResponse, value: response };
|
|
2217
|
+
descriptors.toolOutput = { ...descriptors.toolOutput, value: response };
|
|
2218
|
+
descriptors.meta = {
|
|
2219
|
+
value: {
|
|
2220
|
+
...value.meta,
|
|
2221
|
+
nativeBatchResponseView: view,
|
|
2222
|
+
nativeBatchResponseMaterialized: !materialized,
|
|
2223
|
+
},
|
|
2224
|
+
writable: true,
|
|
2225
|
+
enumerable: true,
|
|
2226
|
+
configurable: true,
|
|
2227
|
+
};
|
|
2228
|
+
return Object.create(Object.getPrototypeOf(value), descriptors);
|
|
2229
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PlayDocflowNodeIoState } from './docflow-node-io';
|
|
2
2
|
import type { PlayMapRowActivitySource } from './run-ledger';
|
|
3
|
+
import type { PlayConditionCounts } from './cell-provenance';
|
|
3
4
|
|
|
4
5
|
export type PlayStagedFileRef = {
|
|
5
6
|
storageKind: 'r2';
|
|
@@ -33,6 +34,7 @@ export type PlayVisualNodeProgress = {
|
|
|
33
34
|
completedAt?: number;
|
|
34
35
|
artifactTableNamespace?: string | null;
|
|
35
36
|
nodeIo?: PlayDocflowNodeIoState;
|
|
37
|
+
conditionCounts?: PlayConditionCounts;
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
export type PlayVisualNodeProgressMap = Record<string, PlayVisualNodeProgress>;
|
|
@@ -7,10 +7,12 @@ import type { ToolExecutionErrorSchemaVersion } from './tool-execution-error';
|
|
|
7
7
|
import type { PlayDataset, PlayDatasetInput, PlayDatasetRow } from './dataset';
|
|
8
8
|
|
|
9
9
|
export const LEGACY_PLAY_AUTHORING_CONTRACT_EDITION = 1 as const;
|
|
10
|
+
// Reader-first rollout: accept edition 9, but keep new bundles on edition 8
|
|
11
|
+
// until the edition-9 runtime reader has completed deployment.
|
|
10
12
|
export const PLAY_AUTHORING_CONTRACT_EDITION = 8 as const;
|
|
11
13
|
export const PLAY_AUTHORING_INPUT_SCHEMA_SNAPSHOT_EDITION = 3 as const;
|
|
12
14
|
export const SUPPORTED_PLAY_AUTHORING_CONTRACT_EDITIONS = [
|
|
13
|
-
1, 2, 3, 4, 5, 6, 7, 8,
|
|
15
|
+
1, 2, 3, 4, 5, 6, 7, 8, 9,
|
|
14
16
|
] as const;
|
|
15
17
|
|
|
16
18
|
export type PlayAuthoringContractEdition =
|
|
@@ -75,6 +77,13 @@ const PLAY_AUTHORING_CONTRACT_CHANGELOG_DETAILS = [
|
|
|
75
77
|
newWritesEnd: null,
|
|
76
78
|
readerRemoval: null,
|
|
77
79
|
},
|
|
80
|
+
{
|
|
81
|
+
changed:
|
|
82
|
+
'Projects native-batch rawV2 to the logical source response at the Play boundary. Editions 1–8 retain their admitted response nesting; completed tool receipts and provider identities are unchanged.',
|
|
83
|
+
compatibilityOwner: 'Plays Runtime',
|
|
84
|
+
newWritesEnd: null,
|
|
85
|
+
readerRemoval: null,
|
|
86
|
+
},
|
|
78
87
|
] as const;
|
|
79
88
|
|
|
80
89
|
export const PLAY_AUTHORING_CONTRACT_CHANGELOG =
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export const ENRICH_COMPAT_DEFAULT_PLAY_NAME = 'deepline-enrich-v1-compat';
|
|
2
2
|
export const ENRICH_COMPAT_DEFAULT_MAP_NAME = 'deepline_enrich_rows';
|
|
3
|
+
export const ENRICH_COMMAND_DEPRECATION_MESSAGE =
|
|
4
|
+
'The `deepline enrich` command is deprecated. Deepline Plays gives much better results. Run `deepline plays --help` to get started. If you still need the legacy command, submit feedback explaining why.';
|
|
3
5
|
|
|
4
6
|
export type EnrichCompatibilityOptions = {
|
|
5
7
|
playName?: string;
|