deepline 0.1.200 → 0.1.201
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/apps/play-runner-workers/src/entry.ts +19 -4
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +43 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +102 -2
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.mjs +2 -2
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
|
@@ -6173,7 +6173,20 @@ function createMinimalWorkerCtx(
|
|
|
6173
6173
|
? ` cells=${totalStepCells}/${totalStepCellsCompleted}/${totalStepCellsSkipped}`
|
|
6174
6174
|
: '';
|
|
6175
6175
|
await flushQueuedMapProgressUpdates();
|
|
6176
|
-
|
|
6176
|
+
// Ordering invariant (progress-before-terminal): the authoritative final
|
|
6177
|
+
// progress bump MUST land in the live progress map and reach the ledger
|
|
6178
|
+
// BEFORE `onMapCompleted` emits the map node's `step.completed`
|
|
6179
|
+
// transition. The reducer's `step.completed` event carries no progress of
|
|
6180
|
+
// its own — it inherits `current.progress` (run-ledger.ts step.completed
|
|
6181
|
+
// case). If we emitted `step.completed` first (as this used to), the step
|
|
6182
|
+
// could settle on the last mid-flight throttled bump (e.g. completed=2 of
|
|
6183
|
+
// a 10-row hint) while the reconciled terminal bump was still pending on
|
|
6184
|
+
// the throttled ledger channel, persisting the run forever as completed
|
|
6185
|
+
// with a stale "2/10" fraction. Draining the final bump first makes that
|
|
6186
|
+
// lost-update race structurally impossible: by the time `step.completed`
|
|
6187
|
+
// is enqueued, `stepProgressByNodeId[mapNodeId]` already holds
|
|
6188
|
+
// `completed=finalizedRowsWritten`, `total=completed+failed`, so the
|
|
6189
|
+
// settled step inherits truthful counts (`completed + failed === total`).
|
|
6177
6190
|
await updateMapProgress({
|
|
6178
6191
|
completed: finalizedRowsWritten,
|
|
6179
6192
|
total: finalizedRowsWritten + totalRowsFailed,
|
|
@@ -6188,6 +6201,7 @@ function createMinimalWorkerCtx(
|
|
|
6188
6201
|
finalizedRowsWritten,
|
|
6189
6202
|
),
|
|
6190
6203
|
});
|
|
6204
|
+
callbacks?.onMapCompleted?.(mapNodeId, completedAt);
|
|
6191
6205
|
emitEvent({
|
|
6192
6206
|
type: 'log',
|
|
6193
6207
|
level: totalRowsFailed > 0 ? 'warn' : 'info',
|
|
@@ -7011,9 +7025,10 @@ function createMinimalWorkerCtx(
|
|
|
7011
7025
|
options?.timeoutMs == null && !childNeedsWorkflowScheduler,
|
|
7012
7026
|
body: {
|
|
7013
7027
|
name: resolvedName,
|
|
7014
|
-
childIdempotencyKey:
|
|
7015
|
-
|
|
7016
|
-
|
|
7028
|
+
childIdempotencyKey:
|
|
7029
|
+
wasFailed && receiptContext.leaseId
|
|
7030
|
+
? `${receiptKey}:claim:${receiptContext.leaseId}`
|
|
7031
|
+
: receiptKey,
|
|
7017
7032
|
input: isRecord(input) ? input : {},
|
|
7018
7033
|
orgId: req.orgId,
|
|
7019
7034
|
callbackUrl: req.callbackUrl,
|
|
@@ -106,10 +106,10 @@ export const SDK_RELEASE = {
|
|
|
106
106
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
107
107
|
// fields shipped in 0.1.153.
|
|
108
108
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
109
|
-
version: '0.1.
|
|
109
|
+
version: '0.1.201',
|
|
110
110
|
apiContract: '2026-06-dataset-handle-results-hard-cutover',
|
|
111
111
|
supportPolicy: {
|
|
112
|
-
latest: '0.1.
|
|
112
|
+
latest: '0.1.201',
|
|
113
113
|
minimumSupported: '0.1.53',
|
|
114
114
|
deprecatedBelow: '0.1.53',
|
|
115
115
|
commandMinimumSupported: [
|
|
@@ -31,6 +31,32 @@ export type PlayRunLedgerEventSource =
|
|
|
31
31
|
| 'coordinator'
|
|
32
32
|
| 'system';
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Live progress for a single step/node.
|
|
36
|
+
*
|
|
37
|
+
* Verified producer semantics (workers_edge map executor —
|
|
38
|
+
* `apps/play-runner-workers/src/entry.ts`):
|
|
39
|
+
*
|
|
40
|
+
* - `completed` counts SUCCESSFULLY written rows ONLY, never failures/skips.
|
|
41
|
+
* In-flight it is `min(total, totalRowsWritten + completedExecutedRows)`
|
|
42
|
+
* where `completedExecutedRows` increments on success only (entry.ts:5635);
|
|
43
|
+
* failures increment the separate `failedExecutedRows` (entry.ts:5684).
|
|
44
|
+
* At map finalize it is set to `finalizedRowsWritten` (successes).
|
|
45
|
+
* - `failed` counts settled-but-failed rows (row-failure isolation persists
|
|
46
|
+
* these; they re-execute on the next run).
|
|
47
|
+
* - `total` is the settled-row denominator. In-flight it is the row-count
|
|
48
|
+
* estimate (`rowCountHint`); at map finalize it is reconciled to
|
|
49
|
+
* `completed + failed` and CAN SHRINK from the initial estimate when rows are
|
|
50
|
+
* filtered/skipped. So `total` is monotonic-up during flight but is corrected
|
|
51
|
+
* down to the settled count at terminal.
|
|
52
|
+
*
|
|
53
|
+
* Terminal invariant: once the step is settled, `completed + failed === total`.
|
|
54
|
+
* Because `completed` is successes-only (NOT all-settled), readers must NOT
|
|
55
|
+
* assume `completed === total` at terminal — a truthful terminal render is
|
|
56
|
+
* `{total} rows` when `failed === 0`, else a `completed`/`failed`/`total`
|
|
57
|
+
* breakdown. See `settleRunningStepsOnTerminal` for why the reducer does not
|
|
58
|
+
* force `completed = total`.
|
|
59
|
+
*/
|
|
34
60
|
export type PlayRunLedgerStepProgress = {
|
|
35
61
|
completed?: number;
|
|
36
62
|
total?: number;
|
|
@@ -775,6 +801,23 @@ function retryablePlatformDeployFailureSnapshot(
|
|
|
775
801
|
);
|
|
776
802
|
}
|
|
777
803
|
|
|
804
|
+
// Force-settles steps still marked `running` when the RUN reaches a terminal
|
|
805
|
+
// status (the fallback for steps that never emitted their own step.completed,
|
|
806
|
+
// e.g. a crash between the last progress bump and the terminal event). This
|
|
807
|
+
// only flips status and stamps `completedAt`; it deliberately does NOT
|
|
808
|
+
// reconcile `progress.completed` to `progress.total`.
|
|
809
|
+
//
|
|
810
|
+
// Why not reconcile: per PlayRunLedgerStepProgress semantics, `completed`
|
|
811
|
+
// counts SUCCESSES ONLY, so `completed === total` is NOT a valid invariant at
|
|
812
|
+
// terminal — a run can legitimately settle with failed/skipped rows (row-
|
|
813
|
+
// failure isolation). Forcing `completed = total` here would fabricate
|
|
814
|
+
// successes that never happened and falsify the persisted counts. The truthful
|
|
815
|
+
// terminal counts are carried by the producer's final reconciled bump, which
|
|
816
|
+
// the workers_edge finalize path now drains BEFORE emitting step.completed
|
|
817
|
+
// (entry.ts finalize ordering invariant). This settle path is the last-resort
|
|
818
|
+
// heal for the missing-final-bump case, where the honest thing is "we know it
|
|
819
|
+
// stopped, we do not know it fully succeeded" — leave the last observed
|
|
820
|
+
// counts, just mark it settled so the UI stops rendering a live ticker.
|
|
778
821
|
function settleRunningStepsOnTerminal(
|
|
779
822
|
snapshot: PlayRunLedgerSnapshot,
|
|
780
823
|
status: Extract<PlayRunLedgerStepStatus, 'completed' | 'failed'>,
|
|
@@ -726,6 +726,75 @@ async function isRuntimeSheetSchemaReady(
|
|
|
726
726
|
}
|
|
727
727
|
}
|
|
728
728
|
|
|
729
|
+
/**
|
|
730
|
+
* Report exactly what the scoped runtime role can see for the sheet table, from
|
|
731
|
+
* the same connection the readiness probe uses. When ensure_sheet reports the
|
|
732
|
+
* table as provisioned but the runner probe still returns not-ready, the cause
|
|
733
|
+
* is almost always that the runtime role lacks a privilege on the freshly
|
|
734
|
+
* created table (so information_schema.columns hides the attempt columns) or a
|
|
735
|
+
* schema/table-name mismatch. This turns the previously blind "still not ready"
|
|
736
|
+
* error into an actionable one that names the concrete missing piece.
|
|
737
|
+
*/
|
|
738
|
+
async function readRuntimeSheetSchemaDiagnostic(
|
|
739
|
+
session: RuntimePostgresSession,
|
|
740
|
+
): Promise<Record<string, unknown>> {
|
|
741
|
+
const query = async (
|
|
742
|
+
client: RuntimeQueryClient,
|
|
743
|
+
): Promise<Record<string, unknown>> => {
|
|
744
|
+
const visibleColumns = await client.query<{ column_name: string }>(
|
|
745
|
+
`
|
|
746
|
+
SELECT column_name
|
|
747
|
+
FROM information_schema.columns
|
|
748
|
+
WHERE table_schema = $1
|
|
749
|
+
AND table_name = $2
|
|
750
|
+
ORDER BY ordinal_position
|
|
751
|
+
`,
|
|
752
|
+
[session.postgres.schema, session.postgres.sheetTable],
|
|
753
|
+
);
|
|
754
|
+
const privileges = await client.query<Record<string, unknown>>(
|
|
755
|
+
`
|
|
756
|
+
SELECT
|
|
757
|
+
current_user AS probe_role,
|
|
758
|
+
to_regclass($3) IS NOT NULL AS regclass_visible,
|
|
759
|
+
has_table_privilege(current_user, $3, 'SELECT') AS can_select,
|
|
760
|
+
has_table_privilege(current_user, $3, 'INSERT') AS can_insert,
|
|
761
|
+
has_table_privilege(current_user, $3, 'UPDATE') AS can_update
|
|
762
|
+
`,
|
|
763
|
+
[
|
|
764
|
+
session.postgres.schema,
|
|
765
|
+
session.postgres.sheetTable,
|
|
766
|
+
`${quoteIdentifier(session.postgres.schema)}.${quoteIdentifier(session.postgres.sheetTable)}`,
|
|
767
|
+
],
|
|
768
|
+
);
|
|
769
|
+
const visible = new Set(visibleColumns.rows.map((row) => row.column_name));
|
|
770
|
+
return {
|
|
771
|
+
schema: session.postgres.schema,
|
|
772
|
+
table: session.postgres.sheetTable,
|
|
773
|
+
probeRole: privileges.rows[0]?.probe_role ?? null,
|
|
774
|
+
regclassVisible: privileges.rows[0]?.regclass_visible ?? null,
|
|
775
|
+
canSelect: privileges.rows[0]?.can_select ?? null,
|
|
776
|
+
canInsert: privileges.rows[0]?.can_insert ?? null,
|
|
777
|
+
canUpdate: privileges.rows[0]?.can_update ?? null,
|
|
778
|
+
visibleColumnCount: visible.size,
|
|
779
|
+
missingAttemptColumns: RUNTIME_SHEET_ATTEMPT_COLUMNS.filter(
|
|
780
|
+
(column) => !visible.has(column),
|
|
781
|
+
),
|
|
782
|
+
};
|
|
783
|
+
};
|
|
784
|
+
try {
|
|
785
|
+
if (isRuntimeOneShotQueryFactoryRegistered()) {
|
|
786
|
+
return await withRuntimeOneShotPostgres(session, query);
|
|
787
|
+
}
|
|
788
|
+
return await withRuntimePostgres(session, query);
|
|
789
|
+
} catch (error) {
|
|
790
|
+
return {
|
|
791
|
+
schema: session.postgres.schema,
|
|
792
|
+
table: session.postgres.sheetTable,
|
|
793
|
+
diagnosticError: error instanceof Error ? error.message : String(error),
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
729
798
|
async function waitForRuntimeSheetSchemaReadyAfterEnsure(
|
|
730
799
|
session: RuntimePostgresSession,
|
|
731
800
|
input: {
|
|
@@ -839,7 +908,7 @@ async function ensureRuntimeSheetForPreloadedSession(
|
|
|
839
908
|
phase: 'ensure_sheet_for_preloaded_session',
|
|
840
909
|
ms: Date.now() - ensureStartedAt,
|
|
841
910
|
});
|
|
842
|
-
|
|
911
|
+
let readyAfterEnsure = await waitForRuntimeSheetSchemaReadyAfterEnsure(
|
|
843
912
|
input.session,
|
|
844
913
|
{
|
|
845
914
|
sheetContract: input.sheetContract,
|
|
@@ -847,8 +916,39 @@ async function ensureRuntimeSheetForPreloadedSession(
|
|
|
847
916
|
},
|
|
848
917
|
);
|
|
849
918
|
if (!readyAfterEnsure) {
|
|
919
|
+
// ensure_sheet provisions the sheet as the tenant admin role, but the
|
|
920
|
+
// preloaded session probes as the scoped runtime role. When the tenant
|
|
921
|
+
// role contract was only partially applied (e.g. role-membership grants
|
|
922
|
+
// skipped on a data plane where the owner cannot administer roles), the
|
|
923
|
+
// runtime role never inherits access to the freshly created table, so its
|
|
924
|
+
// information_schema view hides the attempt columns and the probe stays
|
|
925
|
+
// not-ready even though the table exists. Re-apply the storage grants
|
|
926
|
+
// through the same self-heal the pre-ensure probe uses, then re-check
|
|
927
|
+
// once. This is a grant repair, not a blind retry: if the runtime role
|
|
928
|
+
// still cannot see the sheet, we fail loudly below with the concrete
|
|
929
|
+
// runtime-role view.
|
|
930
|
+
const repairStartedAt = Date.now();
|
|
931
|
+
await repairRuntimeStorageGrants(context, {
|
|
932
|
+
playName: context.playName,
|
|
933
|
+
});
|
|
934
|
+
input.timings?.push({
|
|
935
|
+
phase: 'repair_storage_grants_after_preloaded_session_ensure',
|
|
936
|
+
ms: Date.now() - repairStartedAt,
|
|
937
|
+
retried: true,
|
|
938
|
+
});
|
|
939
|
+
readyAfterEnsure = await waitForRuntimeSheetSchemaReadyAfterEnsure(
|
|
940
|
+
input.session,
|
|
941
|
+
{
|
|
942
|
+
sheetContract: input.sheetContract,
|
|
943
|
+
timings: input.timings,
|
|
944
|
+
},
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
if (!readyAfterEnsure) {
|
|
948
|
+
const diagnostic = await readRuntimeSheetSchemaDiagnostic(input.session);
|
|
850
949
|
throw new Error(
|
|
851
|
-
`Runtime sheet schema for ctx.dataset("${input.tableNamespace}") is still not ready after ensure_sheet
|
|
950
|
+
`Runtime sheet schema for ctx.dataset("${input.tableNamespace}") is still not ready after ensure_sheet. ` +
|
|
951
|
+
`Runtime-role view: ${JSON.stringify(diagnostic)}`,
|
|
852
952
|
);
|
|
853
953
|
}
|
|
854
954
|
})();
|
package/dist/cli/index.js
CHANGED
|
@@ -623,10 +623,10 @@ var SDK_RELEASE = {
|
|
|
623
623
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
624
624
|
// fields shipped in 0.1.153.
|
|
625
625
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
626
|
-
version: "0.1.
|
|
626
|
+
version: "0.1.201",
|
|
627
627
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
628
628
|
supportPolicy: {
|
|
629
|
-
latest: "0.1.
|
|
629
|
+
latest: "0.1.201",
|
|
630
630
|
minimumSupported: "0.1.53",
|
|
631
631
|
deprecatedBelow: "0.1.53",
|
|
632
632
|
commandMinimumSupported: [
|
package/dist/cli/index.mjs
CHANGED
|
@@ -608,10 +608,10 @@ var SDK_RELEASE = {
|
|
|
608
608
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
609
609
|
// fields shipped in 0.1.153.
|
|
610
610
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
611
|
-
version: "0.1.
|
|
611
|
+
version: "0.1.201",
|
|
612
612
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
613
613
|
supportPolicy: {
|
|
614
|
-
latest: "0.1.
|
|
614
|
+
latest: "0.1.201",
|
|
615
615
|
minimumSupported: "0.1.53",
|
|
616
616
|
deprecatedBelow: "0.1.53",
|
|
617
617
|
commandMinimumSupported: [
|
package/dist/index.js
CHANGED
|
@@ -422,10 +422,10 @@ var SDK_RELEASE = {
|
|
|
422
422
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
423
423
|
// fields shipped in 0.1.153.
|
|
424
424
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
425
|
-
version: "0.1.
|
|
425
|
+
version: "0.1.201",
|
|
426
426
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
427
427
|
supportPolicy: {
|
|
428
|
-
latest: "0.1.
|
|
428
|
+
latest: "0.1.201",
|
|
429
429
|
minimumSupported: "0.1.53",
|
|
430
430
|
deprecatedBelow: "0.1.53",
|
|
431
431
|
commandMinimumSupported: [
|
package/dist/index.mjs
CHANGED
|
@@ -352,10 +352,10 @@ var SDK_RELEASE = {
|
|
|
352
352
|
// 0.1.154 removes the short-lived generated enrich StepOptions recompute
|
|
353
353
|
// fields shipped in 0.1.153.
|
|
354
354
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
355
|
-
version: "0.1.
|
|
355
|
+
version: "0.1.201",
|
|
356
356
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
357
357
|
supportPolicy: {
|
|
358
|
-
latest: "0.1.
|
|
358
|
+
latest: "0.1.201",
|
|
359
359
|
minimumSupported: "0.1.53",
|
|
360
360
|
deprecatedBelow: "0.1.53",
|
|
361
361
|
commandMinimumSupported: [
|