@opengeni/db 4.0.0-canary.1 → 4.0.0-canary.2
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/canonical-human-identities.js +3 -3
- package/dist/{chunk-2HGYCAXN.js → chunk-B5Y3TCSP.js} +2 -2
- package/dist/{chunk-A5RFBEZR.js → chunk-CQF6G4IF.js} +3 -3
- package/dist/{chunk-FVZINOBB.js → chunk-DUB3LUVM.js} +21 -9
- package/dist/chunk-DUB3LUVM.js.map +1 -0
- package/dist/{chunk-YVDQDD33.js → chunk-L2QFSPFP.js} +2 -2
- package/dist/{chunk-47LKLIIK.js → chunk-NPKBYGAK.js} +2 -2
- package/dist/{chunk-XAKQCOF3.js → chunk-PWJJKCTF.js} +11 -1
- package/dist/chunk-PWJJKCTF.js.map +1 -0
- package/dist/{chunk-I6YPQMAL.js → chunk-VU2IK37Y.js} +2 -2
- package/dist/{chunk-ZQ32COTC.js → chunk-XIYAXH47.js} +2 -2
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +6 -0
- package/dist/index.js +191 -16
- package/dist/index.js.map +1 -1
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/schema.d.ts +51 -0
- package/dist/schema.js +1 -1
- package/dist/session-background-commands.d.ts +6 -0
- package/dist/session-background-commands.js +4 -4
- package/dist/session-command-output.js +4 -4
- package/dist/session-event-slices.js +2 -2
- package/dist/session-tenancy.js +3 -3
- package/dist/video-generation.js +3 -3
- package/drizzle/0419_background_command_launch_authority.sql +56 -0
- package/package.json +6 -6
- package/src/index.ts +264 -10
- package/src/schema.ts +10 -0
- package/src/session-background-commands.ts +33 -0
- package/dist/chunk-FVZINOBB.js.map +0 -1
- package/dist/chunk-XAKQCOF3.js.map +0 -1
- /package/dist/{chunk-2HGYCAXN.js.map → chunk-B5Y3TCSP.js.map} +0 -0
- /package/dist/{chunk-A5RFBEZR.js.map → chunk-CQF6G4IF.js.map} +0 -0
- /package/dist/{chunk-YVDQDD33.js.map → chunk-L2QFSPFP.js.map} +0 -0
- /package/dist/{chunk-47LKLIIK.js.map → chunk-NPKBYGAK.js.map} +0 -0
- /package/dist/{chunk-I6YPQMAL.js.map → chunk-VU2IK37Y.js.map} +0 -0
- /package/dist/{chunk-ZQ32COTC.js.map → chunk-XIYAXH47.js.map} +0 -0
|
@@ -20,9 +20,9 @@ import {
|
|
|
20
20
|
reapManagedAuthIsolatedSessions,
|
|
21
21
|
releaseManagedAuthActorMutationLease,
|
|
22
22
|
validateManagedAuthActorMutationLease
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
25
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-VU2IK37Y.js";
|
|
24
|
+
import "./chunk-XIYAXH47.js";
|
|
25
|
+
import "./chunk-PWJJKCTF.js";
|
|
26
26
|
import "./chunk-PZ5AY32C.js";
|
|
27
27
|
export {
|
|
28
28
|
ManagedAuthActorMutationInFlightError,
|
package/dist/schema.d.ts
CHANGED
|
@@ -41096,6 +41096,57 @@ export declare const sessionBackgroundCommands: import("drizzle-orm/pg-core").Pg
|
|
|
41096
41096
|
identity: undefined;
|
|
41097
41097
|
generated: undefined;
|
|
41098
41098
|
}, {}, {}>;
|
|
41099
|
+
launchTurnId: import("drizzle-orm/pg-core").PgColumn<{
|
|
41100
|
+
name: "launch_turn_id";
|
|
41101
|
+
tableName: "session_background_commands";
|
|
41102
|
+
dataType: "string";
|
|
41103
|
+
columnType: "PgUUID";
|
|
41104
|
+
data: string;
|
|
41105
|
+
driverParam: string;
|
|
41106
|
+
notNull: false;
|
|
41107
|
+
hasDefault: false;
|
|
41108
|
+
isPrimaryKey: false;
|
|
41109
|
+
isAutoincrement: false;
|
|
41110
|
+
hasRuntimeDefault: false;
|
|
41111
|
+
enumValues: undefined;
|
|
41112
|
+
baseColumn: never;
|
|
41113
|
+
identity: undefined;
|
|
41114
|
+
generated: undefined;
|
|
41115
|
+
}, {}, {}>;
|
|
41116
|
+
launchAttemptId: import("drizzle-orm/pg-core").PgColumn<{
|
|
41117
|
+
name: "launch_attempt_id";
|
|
41118
|
+
tableName: "session_background_commands";
|
|
41119
|
+
dataType: "string";
|
|
41120
|
+
columnType: "PgUUID";
|
|
41121
|
+
data: string;
|
|
41122
|
+
driverParam: string;
|
|
41123
|
+
notNull: false;
|
|
41124
|
+
hasDefault: false;
|
|
41125
|
+
isPrimaryKey: false;
|
|
41126
|
+
isAutoincrement: false;
|
|
41127
|
+
hasRuntimeDefault: false;
|
|
41128
|
+
enumValues: undefined;
|
|
41129
|
+
baseColumn: never;
|
|
41130
|
+
identity: undefined;
|
|
41131
|
+
generated: undefined;
|
|
41132
|
+
}, {}, {}>;
|
|
41133
|
+
launchExecutionGeneration: import("drizzle-orm/pg-core").PgColumn<{
|
|
41134
|
+
name: "launch_execution_generation";
|
|
41135
|
+
tableName: "session_background_commands";
|
|
41136
|
+
dataType: "number";
|
|
41137
|
+
columnType: "PgInteger";
|
|
41138
|
+
data: number;
|
|
41139
|
+
driverParam: string | number;
|
|
41140
|
+
notNull: false;
|
|
41141
|
+
hasDefault: false;
|
|
41142
|
+
isPrimaryKey: false;
|
|
41143
|
+
isAutoincrement: false;
|
|
41144
|
+
hasRuntimeDefault: false;
|
|
41145
|
+
enumValues: undefined;
|
|
41146
|
+
baseColumn: never;
|
|
41147
|
+
identity: undefined;
|
|
41148
|
+
generated: undefined;
|
|
41149
|
+
}, {}, {}>;
|
|
41099
41150
|
controlWorkspaceId: import("drizzle-orm/pg-core").PgColumn<{
|
|
41100
41151
|
name: "control_workspace_id";
|
|
41101
41152
|
tableName: "session_background_commands";
|
package/dist/schema.js
CHANGED
|
@@ -47,6 +47,9 @@ export declare function insertManagedSessionBackgroundCommandInTransaction(db: D
|
|
|
47
47
|
commandId: string;
|
|
48
48
|
retainedProcessId: string;
|
|
49
49
|
command: string;
|
|
50
|
+
turnId?: string;
|
|
51
|
+
attemptId?: string;
|
|
52
|
+
executionGeneration?: number;
|
|
50
53
|
}): Promise<SessionBackgroundCommand>;
|
|
51
54
|
/** @internal Caller must already hold the canonical exact-attempt fence. */
|
|
52
55
|
export declare function insertConnectedMachineSessionBackgroundCommandInTransaction(db: Database, input: {
|
|
@@ -59,6 +62,9 @@ export declare function insertConnectedMachineSessionBackgroundCommandInTransact
|
|
|
59
62
|
connectionInstanceId: string;
|
|
60
63
|
opId: string;
|
|
61
64
|
command: string;
|
|
65
|
+
turnId?: string;
|
|
66
|
+
attemptId?: string;
|
|
67
|
+
executionGeneration?: number;
|
|
62
68
|
}): Promise<SessionBackgroundCommand>;
|
|
63
69
|
/** Claim exact Connected Machine locators globally for provider reconciliation.
|
|
64
70
|
* The SECURITY DEFINER SQL function owns the bounded SKIP LOCKED inventory;
|
|
@@ -22,10 +22,10 @@ import {
|
|
|
22
22
|
settleClaimedConnectedMachineBackgroundCommandWithMutation,
|
|
23
23
|
settleConnectedMachineSessionBackgroundCommandWithMutation,
|
|
24
24
|
settleSessionBackgroundCommandForRetainedProcessInTransaction
|
|
25
|
-
} from "./chunk-
|
|
26
|
-
import "./chunk-
|
|
27
|
-
import "./chunk-
|
|
28
|
-
import "./chunk-
|
|
25
|
+
} from "./chunk-DUB3LUVM.js";
|
|
26
|
+
import "./chunk-CQF6G4IF.js";
|
|
27
|
+
import "./chunk-XIYAXH47.js";
|
|
28
|
+
import "./chunk-PWJJKCTF.js";
|
|
29
29
|
import "./chunk-PZ5AY32C.js";
|
|
30
30
|
export {
|
|
31
31
|
COMMAND_OUTPUT_DEFAULT_BYTES,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
lockSessionEventWriteRows
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-DUB3LUVM.js";
|
|
4
|
+
import "./chunk-CQF6G4IF.js";
|
|
5
5
|
import {
|
|
6
6
|
withSessionActivityRlsContext
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XIYAXH47.js";
|
|
8
8
|
import {
|
|
9
9
|
fromPostgresLosslessJson,
|
|
10
10
|
sandboxRetainedProcesses,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
sessionEvents,
|
|
13
13
|
sessions,
|
|
14
14
|
withLosslessContentWriteVersion
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-PWJJKCTF.js";
|
|
16
16
|
import "./chunk-PZ5AY32C.js";
|
|
17
17
|
|
|
18
18
|
// src/session-command-output.ts
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
rawRows,
|
|
3
3
|
withWorkspaceRls
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XIYAXH47.js";
|
|
5
5
|
import {
|
|
6
6
|
LOSSLESS_JSON_STRING_PREFIX,
|
|
7
7
|
fromPostgresLosslessJson,
|
|
8
8
|
sessionEvents,
|
|
9
9
|
sessionTurns
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PWJJKCTF.js";
|
|
11
11
|
import "./chunk-PZ5AY32C.js";
|
|
12
12
|
|
|
13
13
|
// src/session-event-slices.ts
|
package/dist/session-tenancy.js
CHANGED
|
@@ -14,9 +14,9 @@ import {
|
|
|
14
14
|
replayAppliedSessionFork,
|
|
15
15
|
sessionTenancyProductActivated,
|
|
16
16
|
transitionSessionVisibility
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
17
|
+
} from "./chunk-B5Y3TCSP.js";
|
|
18
|
+
import "./chunk-XIYAXH47.js";
|
|
19
|
+
import "./chunk-PWJJKCTF.js";
|
|
20
20
|
import "./chunk-PZ5AY32C.js";
|
|
21
21
|
export {
|
|
22
22
|
SessionTenancyAccessError,
|
package/dist/video-generation.js
CHANGED
|
@@ -29,9 +29,9 @@ import {
|
|
|
29
29
|
settleVideoGenerationFailure,
|
|
30
30
|
settleVideoGenerationReady,
|
|
31
31
|
updateWorkspaceVideoGenerationPolicy
|
|
32
|
-
} from "./chunk-
|
|
33
|
-
import "./chunk-
|
|
34
|
-
import "./chunk-
|
|
32
|
+
} from "./chunk-CQF6G4IF.js";
|
|
33
|
+
import "./chunk-XIYAXH47.js";
|
|
34
|
+
import "./chunk-PWJJKCTF.js";
|
|
35
35
|
import "./chunk-PZ5AY32C.js";
|
|
36
36
|
export {
|
|
37
37
|
ACTIVE_VIDEO_GENERATION_STATUSES,
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- New adoption writers freeze their already-fenced launch attempt. Older
|
|
3
|
+
-- writers leave this tuple absent; never invent authority for legacy commands.
|
|
4
|
+
ALTER TABLE session_background_commands
|
|
5
|
+
ADD COLUMN launch_turn_id uuid,
|
|
6
|
+
ADD COLUMN launch_attempt_id uuid,
|
|
7
|
+
ADD COLUMN launch_execution_generation integer,
|
|
8
|
+
ADD CONSTRAINT session_background_commands_launch_identity_check CHECK (
|
|
9
|
+
(launch_turn_id IS NULL AND launch_attempt_id IS NULL AND launch_execution_generation IS NULL)
|
|
10
|
+
OR (launch_turn_id IS NOT NULL AND launch_attempt_id IS NOT NULL AND launch_execution_generation IS NOT NULL AND launch_execution_generation > 0)
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
CREATE FUNCTION fence_background_command_launch_identity()
|
|
14
|
+
RETURNS trigger LANGUAGE plpgsql SET search_path = pg_catalog, public AS $$
|
|
15
|
+
DECLARE matches_launch boolean;
|
|
16
|
+
BEGIN
|
|
17
|
+
IF TG_OP = 'UPDATE' THEN
|
|
18
|
+
IF ROW(NEW.launch_turn_id, NEW.launch_attempt_id, NEW.launch_execution_generation,
|
|
19
|
+
NEW.account_id, NEW.workspace_id, NEW.session_id, NEW.provider,
|
|
20
|
+
NEW.retained_process_id, NEW.control_workspace_id, NEW.enrollment_id,
|
|
21
|
+
NEW.connection_instance_id, NEW.op_id)
|
|
22
|
+
IS DISTINCT FROM
|
|
23
|
+
ROW(OLD.launch_turn_id, OLD.launch_attempt_id, OLD.launch_execution_generation,
|
|
24
|
+
OLD.account_id, OLD.workspace_id, OLD.session_id, OLD.provider,
|
|
25
|
+
OLD.retained_process_id, OLD.control_workspace_id, OLD.enrollment_id,
|
|
26
|
+
OLD.connection_instance_id, OLD.op_id) THEN
|
|
27
|
+
RAISE EXCEPTION 'background command launch identity is immutable' USING ERRCODE = '23514';
|
|
28
|
+
END IF;
|
|
29
|
+
RETURN NEW;
|
|
30
|
+
END IF;
|
|
31
|
+
IF NEW.launch_turn_id IS NOT NULL AND NEW.launch_attempt_id IS NOT NULL
|
|
32
|
+
AND NEW.launch_execution_generation IS NOT NULL THEN
|
|
33
|
+
-- The migrator also supports dedicated data schemas. Never resolve an
|
|
34
|
+
-- unrelated public table when this trigger belongs to another schema.
|
|
35
|
+
EXECUTE format(
|
|
36
|
+
'SELECT EXISTS (
|
|
37
|
+
SELECT 1 FROM %I.session_turn_attempts a
|
|
38
|
+
JOIN %I.session_turns t ON t.id = a.turn_id AND t.workspace_id = a.workspace_id
|
|
39
|
+
AND t.session_id = a.session_id AND t.account_id = a.account_id
|
|
40
|
+
WHERE a.id = $1 AND a.turn_id = $2
|
|
41
|
+
AND a.workspace_id = $3 AND a.session_id = $4
|
|
42
|
+
AND a.account_id = $5 AND a.execution_generation = $6
|
|
43
|
+
)', TG_TABLE_SCHEMA, TG_TABLE_SCHEMA
|
|
44
|
+
) INTO matches_launch USING NEW.launch_attempt_id, NEW.launch_turn_id,
|
|
45
|
+
NEW.workspace_id, NEW.session_id, NEW.account_id, NEW.launch_execution_generation;
|
|
46
|
+
IF NOT matches_launch THEN
|
|
47
|
+
RAISE EXCEPTION 'background command launch attempt does not match session' USING ERRCODE = '23514';
|
|
48
|
+
END IF;
|
|
49
|
+
END IF;
|
|
50
|
+
RETURN NEW;
|
|
51
|
+
END;
|
|
52
|
+
$$;
|
|
53
|
+
REVOKE ALL ON FUNCTION fence_background_command_launch_identity() FROM PUBLIC;
|
|
54
|
+
CREATE TRIGGER session_background_commands_launch_identity_fence
|
|
55
|
+
BEFORE INSERT OR UPDATE ON session_background_commands
|
|
56
|
+
FOR EACH ROW EXECUTE FUNCTION fence_background_command_launch_identity();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/db",
|
|
3
|
-
"version": "4.0.0-canary.
|
|
3
|
+
"version": "4.0.0-canary.2",
|
|
4
4
|
"description": "OpenGeni persistence: Drizzle schema, RLS-scoped query layer, the SQL migration runner, and role provisioning.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -86,11 +86,11 @@
|
|
|
86
86
|
"prepublishOnly": "bash ../../scripts/prepublish-guard"
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
|
-
"@opengeni/codemode": "^0.4.27-canary.
|
|
90
|
-
"@opengeni/codex": "^0.2.21-canary.
|
|
91
|
-
"@opengeni/config": "^1.0.0-canary.
|
|
92
|
-
"@opengeni/contracts": "^2.13.0-canary.
|
|
93
|
-
"@opengeni/network": "^0.3.0-canary.
|
|
89
|
+
"@opengeni/codemode": "^0.4.27-canary.2",
|
|
90
|
+
"@opengeni/codex": "^0.2.21-canary.2",
|
|
91
|
+
"@opengeni/config": "^1.0.0-canary.2",
|
|
92
|
+
"@opengeni/contracts": "^2.13.0-canary.2",
|
|
93
|
+
"@opengeni/network": "^0.3.0-canary.2",
|
|
94
94
|
"drizzle-orm": "^0.45.2",
|
|
95
95
|
"postgres": "^3.4.7"
|
|
96
96
|
},
|
package/src/index.ts
CHANGED
|
@@ -38395,6 +38395,9 @@ export async function adoptManagedSessionBackgroundCommand(
|
|
|
38395
38395
|
commandId: input.processId,
|
|
38396
38396
|
retainedProcessId: input.processId,
|
|
38397
38397
|
command: input.command,
|
|
38398
|
+
turnId: input.turnId,
|
|
38399
|
+
attemptId: input.attemptId,
|
|
38400
|
+
executionGeneration: input.executionGeneration,
|
|
38398
38401
|
});
|
|
38399
38402
|
}),
|
|
38400
38403
|
);
|
|
@@ -61784,7 +61787,9 @@ function systemUpdateCausalHumanTurnId(
|
|
|
61784
61787
|
: null;
|
|
61785
61788
|
const value = isChildLifecycleSystemUpdateKind(update.kind)
|
|
61786
61789
|
? lineage?.parentTurnId
|
|
61787
|
-
: update.kind === "goal_continuation"
|
|
61790
|
+
: update.kind === "goal_continuation" ||
|
|
61791
|
+
update.kind === "background_command_result" ||
|
|
61792
|
+
update.kind === "session_wait_timeout"
|
|
61788
61793
|
? lineage?.causalTurnId
|
|
61789
61794
|
: null;
|
|
61790
61795
|
if (typeof value !== "string" || !/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/iu.test(value)) {
|
|
@@ -61829,7 +61834,12 @@ function systemUpdateCausalExecutionKey(
|
|
|
61829
61834
|
): string | null {
|
|
61830
61835
|
const targetTurnId = systemUpdateCausalHumanTurnId(update);
|
|
61831
61836
|
if (targetTurnId) return `target-turn:${targetTurnId}`;
|
|
61832
|
-
if (
|
|
61837
|
+
if (
|
|
61838
|
+
isChildLifecycleSystemUpdateKind(update.kind) ||
|
|
61839
|
+
update.kind === "goal_continuation" ||
|
|
61840
|
+
update.kind === "background_command_result" ||
|
|
61841
|
+
update.kind === "session_wait_timeout"
|
|
61842
|
+
) {
|
|
61833
61843
|
// Malformed historical authority-bearing rows still own distinct claims.
|
|
61834
61844
|
// They may carry ordinary authority-neutral context, but they must never
|
|
61835
61845
|
// borrow another child, goal, or Steer's causal principal.
|
|
@@ -66376,6 +66386,10 @@ async function settleSessionInputWaitInActivity(
|
|
|
66376
66386
|
}
|
|
66377
66387
|
const deadlineAt = expected.inputWaitUntil.toISOString();
|
|
66378
66388
|
const reason = expected.inputWaitReason;
|
|
66389
|
+
const causalAuthority = await sameSessionCausalAuthorityTx(db as unknown as Database, {
|
|
66390
|
+
...input,
|
|
66391
|
+
turnId: input.waitTurnId,
|
|
66392
|
+
});
|
|
66379
66393
|
try {
|
|
66380
66394
|
const result = await addSessionSystemUpdateWithSourceMutation(
|
|
66381
66395
|
db,
|
|
@@ -66384,6 +66398,11 @@ async function settleSessionInputWaitInActivity(
|
|
|
66384
66398
|
workspaceId: input.workspaceId,
|
|
66385
66399
|
sessionId: input.sessionId,
|
|
66386
66400
|
kind: "session_wait_timeout",
|
|
66401
|
+
personalConnectionDelegations: causalAuthority?.personalConnectionDelegations ?? [],
|
|
66402
|
+
xaiProviderAccountAuthoritySnapshot:
|
|
66403
|
+
causalAuthority?.xaiProviderAccountAuthoritySnapshot ??
|
|
66404
|
+
WORKSPACE_XAI_PROVIDER_ACCOUNT_AUTHORITY_SNAPSHOT_V1,
|
|
66405
|
+
lineage: causalAuthority?.lineage ?? {},
|
|
66387
66406
|
classification: "info",
|
|
66388
66407
|
sourceId: input.waitTurnId,
|
|
66389
66408
|
dedupeKey: `session-input-wait-timeout:${input.waitTurnId}`,
|
|
@@ -66572,6 +66591,11 @@ export type FailSessionWorkBeforeAttemptClaimInput = {
|
|
|
66572
66591
|
workflowId: string;
|
|
66573
66592
|
trigger: SessionWorkTrigger;
|
|
66574
66593
|
error: string;
|
|
66594
|
+
/** Already-classified admission facts from the failed worker activity. */
|
|
66595
|
+
admissionFailure?: {
|
|
66596
|
+
disposition: "retryable" | "permanent";
|
|
66597
|
+
code: "db_deadlock" | "db_serialization_failure" | "db_failure" | "claim_invariant";
|
|
66598
|
+
};
|
|
66575
66599
|
};
|
|
66576
66600
|
|
|
66577
66601
|
export type FailSessionWorkBeforeAttemptClaimResult =
|
|
@@ -66955,6 +66979,8 @@ export async function failSessionWorkBeforeAttemptClaim(
|
|
|
66955
66979
|
payload: {
|
|
66956
66980
|
status: "failed",
|
|
66957
66981
|
code: "pre_claim_failure",
|
|
66982
|
+
error: input.error,
|
|
66983
|
+
...(input.admissionFailure ? { admissionFailure: input.admissionFailure } : {}),
|
|
66958
66984
|
...(!turn ? { failedSystemUpdateIds } : {}),
|
|
66959
66985
|
},
|
|
66960
66986
|
turnId: turn?.id ?? null,
|
|
@@ -67284,6 +67310,8 @@ export async function recoverSessionWorkFailedBeforeAttemptClaim(
|
|
|
67284
67310
|
.select({
|
|
67285
67311
|
id: schema.sessionSystemUpdates.id,
|
|
67286
67312
|
kind: schema.sessionSystemUpdates.kind,
|
|
67313
|
+
sourceId: schema.sessionSystemUpdates.sourceId,
|
|
67314
|
+
dedupeKey: schema.sessionSystemUpdates.dedupeKey,
|
|
67287
67315
|
lineage: schema.sessionSystemUpdates.lineage,
|
|
67288
67316
|
deliveredTurnId: schema.sessionSystemUpdates.deliveredTurnId,
|
|
67289
67317
|
deliveredHistoryItemId: schema.sessionSystemUpdates.deliveredHistoryItemId,
|
|
@@ -67388,22 +67416,71 @@ export async function recoverSessionWorkFailedBeforeAttemptClaim(
|
|
|
67388
67416
|
}
|
|
67389
67417
|
|
|
67390
67418
|
const causalTurnIds = new Set<string>();
|
|
67419
|
+
const repairedAuthorities = new Map<
|
|
67420
|
+
string,
|
|
67421
|
+
NonNullable<Awaited<ReturnType<typeof sameSessionCausalAuthorityTx>>>
|
|
67422
|
+
>();
|
|
67391
67423
|
for (const update of failedUpdates) {
|
|
67392
|
-
|
|
67424
|
+
let causalTurnId = systemUpdateCausalHumanTurnId(update);
|
|
67393
67425
|
const lineage =
|
|
67394
67426
|
update.lineage && typeof update.lineage === "object" && !Array.isArray(update.lineage)
|
|
67395
67427
|
? (update.lineage as Record<string, unknown>)
|
|
67396
67428
|
: null;
|
|
67397
67429
|
if (
|
|
67398
|
-
!isChildLifecycleSystemUpdateKind(update.kind) ||
|
|
67399
|
-
!causalTurnId ||
|
|
67400
|
-
lineage?.parentSessionId !== input.sessionId ||
|
|
67401
67430
|
update.deliveredTurnId !== null ||
|
|
67402
67431
|
update.deliveredHistoryItemId !== null ||
|
|
67403
67432
|
update.deliveredAt !== null
|
|
67404
|
-
)
|
|
67433
|
+
)
|
|
67405
67434
|
return { action: "stale", event: null } as const;
|
|
67406
|
-
|
|
67435
|
+
if (isChildLifecycleSystemUpdateKind(update.kind)) {
|
|
67436
|
+
if (!causalTurnId || lineage?.parentSessionId !== input.sessionId) {
|
|
67437
|
+
return { action: "stale", event: null } as const;
|
|
67438
|
+
}
|
|
67439
|
+
} else if (update.kind === "background_command_result") {
|
|
67440
|
+
if (
|
|
67441
|
+
!update.sourceId ||
|
|
67442
|
+
!UUID_PATTERN.test(update.sourceId) ||
|
|
67443
|
+
update.dedupeKey !== `background-command-result:${update.sourceId}`
|
|
67444
|
+
) {
|
|
67445
|
+
return { action: "stale", event: null } as const;
|
|
67446
|
+
}
|
|
67447
|
+
const authority = await backgroundCommandCausalAuthorityTx(tx as unknown as Database, {
|
|
67448
|
+
accountId: session.accountId,
|
|
67449
|
+
workspaceId,
|
|
67450
|
+
sessionId: input.sessionId,
|
|
67451
|
+
commandId: update.sourceId,
|
|
67452
|
+
});
|
|
67453
|
+
if (!authority) return { action: "stale", event: null } as const;
|
|
67454
|
+
repairedAuthorities.set(update.id, authority);
|
|
67455
|
+
causalTurnId = authority.lineage.causalTurnId;
|
|
67456
|
+
} else if (update.kind === "session_wait_timeout") {
|
|
67457
|
+
if (
|
|
67458
|
+
!update.sourceId ||
|
|
67459
|
+
!UUID_PATTERN.test(update.sourceId) ||
|
|
67460
|
+
update.dedupeKey !== `session-input-wait-timeout:${update.sourceId}`
|
|
67461
|
+
) {
|
|
67462
|
+
return { action: "stale", event: null } as const;
|
|
67463
|
+
}
|
|
67464
|
+
const [timeoutProof] = await tx.execute(sql`
|
|
67465
|
+
select id from session_events
|
|
67466
|
+
where workspace_id = ${workspaceId} and session_id = ${input.sessionId}
|
|
67467
|
+
and type = 'session.wait.finished'
|
|
67468
|
+
and payload ->> 'waitTurnId' = ${update.sourceId}
|
|
67469
|
+
and payload ->> 'outcome' = 'timeout'
|
|
67470
|
+
and sequence < ${input.expectedFailureEventSequence}
|
|
67471
|
+
limit 1`);
|
|
67472
|
+
if (!timeoutProof) return { action: "stale", event: null } as const;
|
|
67473
|
+
const authority = await sameSessionCausalAuthorityTx(tx as unknown as Database, {
|
|
67474
|
+
accountId: session.accountId,
|
|
67475
|
+
workspaceId,
|
|
67476
|
+
sessionId: input.sessionId,
|
|
67477
|
+
turnId: update.sourceId,
|
|
67478
|
+
});
|
|
67479
|
+
if (!authority) return { action: "stale", event: null } as const;
|
|
67480
|
+
repairedAuthorities.set(update.id, authority);
|
|
67481
|
+
causalTurnId = authority.lineage.causalTurnId;
|
|
67482
|
+
} else return { action: "stale", event: null } as const;
|
|
67483
|
+
if (!causalTurnId) return { action: "stale", event: null } as const;
|
|
67407
67484
|
causalTurnIds.add(causalTurnId);
|
|
67408
67485
|
}
|
|
67409
67486
|
const causalTurns = await tx
|
|
@@ -67432,6 +67509,27 @@ export async function recoverSessionWorkFailedBeforeAttemptClaim(
|
|
|
67432
67509
|
return { action: "stale", event: null } as const;
|
|
67433
67510
|
}
|
|
67434
67511
|
|
|
67512
|
+
// Only after every exact failed member and causal receipt passes do
|
|
67513
|
+
// we repair typed authority; message/event content is never rewritten.
|
|
67514
|
+
for (const update of failedUpdates) {
|
|
67515
|
+
const authority = repairedAuthorities.get(update.id);
|
|
67516
|
+
if (!authority) continue;
|
|
67517
|
+
await tx
|
|
67518
|
+
.update(schema.sessionSystemUpdates)
|
|
67519
|
+
.set({
|
|
67520
|
+
personalConnectionDelegations: authority.personalConnectionDelegations,
|
|
67521
|
+
xaiProviderAccountAuthoritySnapshot: authority.xaiProviderAccountAuthoritySnapshot,
|
|
67522
|
+
lineage: { ...update.lineage, ...authority.lineage },
|
|
67523
|
+
})
|
|
67524
|
+
.where(
|
|
67525
|
+
and(
|
|
67526
|
+
eq(schema.sessionSystemUpdates.id, update.id),
|
|
67527
|
+
eq(schema.sessionSystemUpdates.workspaceId, workspaceId),
|
|
67528
|
+
eq(schema.sessionSystemUpdates.sessionId, input.sessionId),
|
|
67529
|
+
eq(schema.sessionSystemUpdates.state, "failed"),
|
|
67530
|
+
),
|
|
67531
|
+
);
|
|
67532
|
+
}
|
|
67435
67533
|
const restored = await tx
|
|
67436
67534
|
.update(schema.sessionSystemUpdates)
|
|
67437
67535
|
.set({ state: "pending" })
|
|
@@ -67622,6 +67720,7 @@ export async function settleSessionIdleWithParentOutbox(
|
|
|
67622
67720
|
action: "settled";
|
|
67623
67721
|
changed: boolean;
|
|
67624
67722
|
episodeKey: string;
|
|
67723
|
+
notifyParent: boolean;
|
|
67625
67724
|
events: SessionEvent[];
|
|
67626
67725
|
}
|
|
67627
67726
|
| { action: "stale"; episodeKey: null; events: [] }
|
|
@@ -67717,11 +67816,30 @@ export async function settleSessionIdleWithParentOutbox(
|
|
|
67717
67816
|
// notification to the newest non-status event, not to the idle status
|
|
67718
67817
|
// event this settlement just appended (or a prior identical idle event).
|
|
67719
67818
|
const episodeKey = String(Number(episodeSequence));
|
|
67720
|
-
|
|
67819
|
+
// Workflow closure is not work completion. Input waits (including a
|
|
67820
|
+
// due timeout not yet materialized) and active goals retain obligations
|
|
67821
|
+
// even while their workflow run truthfully parks the session as idle.
|
|
67822
|
+
const waitState = await sessionInputWaitStateTx(tx, workspaceId, sessionId, session);
|
|
67823
|
+
const [goal] = await tx
|
|
67824
|
+
.select({ status: schema.sessionGoals.status })
|
|
67825
|
+
.from(schema.sessionGoals)
|
|
67826
|
+
.where(
|
|
67827
|
+
and(
|
|
67828
|
+
eq(schema.sessionGoals.workspaceId, workspaceId),
|
|
67829
|
+
eq(schema.sessionGoals.sessionId, sessionId),
|
|
67830
|
+
),
|
|
67831
|
+
)
|
|
67832
|
+
.limit(1);
|
|
67833
|
+
const ongoingWork =
|
|
67834
|
+
waitState.disposition === "held" ||
|
|
67835
|
+
waitState.disposition === "timeout" ||
|
|
67836
|
+
goal?.status === "active";
|
|
67837
|
+
if (!session.parentSessionId || ongoingWork) {
|
|
67721
67838
|
return {
|
|
67722
67839
|
action: "settled",
|
|
67723
67840
|
changed: events.length > 0,
|
|
67724
67841
|
episodeKey,
|
|
67842
|
+
notifyParent: false,
|
|
67725
67843
|
events,
|
|
67726
67844
|
} as const;
|
|
67727
67845
|
}
|
|
@@ -67741,6 +67859,7 @@ export async function settleSessionIdleWithParentOutbox(
|
|
|
67741
67859
|
action: "settled",
|
|
67742
67860
|
changed: events.length > 0,
|
|
67743
67861
|
episodeKey,
|
|
67862
|
+
notifyParent: true,
|
|
67744
67863
|
events,
|
|
67745
67864
|
} as const;
|
|
67746
67865
|
});
|
|
@@ -72799,6 +72918,129 @@ export async function addSessionSystemUpdateWithSourceMutation<
|
|
|
72799
72918
|
)) as AddSessionSystemUpdateResult<RequireIdleSession>;
|
|
72800
72919
|
}
|
|
72801
72920
|
|
|
72921
|
+
async function sameSessionCausalAuthorityTx(
|
|
72922
|
+
tx: Database,
|
|
72923
|
+
input: { accountId: string; workspaceId: string; sessionId: string; turnId: string },
|
|
72924
|
+
) {
|
|
72925
|
+
const [turn] = await tx
|
|
72926
|
+
.select()
|
|
72927
|
+
.from(schema.sessionTurns)
|
|
72928
|
+
.where(
|
|
72929
|
+
and(
|
|
72930
|
+
eq(schema.sessionTurns.accountId, input.accountId),
|
|
72931
|
+
eq(schema.sessionTurns.workspaceId, input.workspaceId),
|
|
72932
|
+
eq(schema.sessionTurns.sessionId, input.sessionId),
|
|
72933
|
+
eq(schema.sessionTurns.id, input.turnId),
|
|
72934
|
+
),
|
|
72935
|
+
)
|
|
72936
|
+
.limit(1);
|
|
72937
|
+
if (!turn) return null;
|
|
72938
|
+
const personalConnectionDelegations = personalConnectionDelegationsForSameSessionSuccessor(
|
|
72939
|
+
parsedPersonalConnectionDelegations(
|
|
72940
|
+
turn.personalConnectionDelegations,
|
|
72941
|
+
`session_turns:${turn.id}`,
|
|
72942
|
+
),
|
|
72943
|
+
input.sessionId,
|
|
72944
|
+
);
|
|
72945
|
+
const xaiProviderAccountAuthoritySnapshot = XaiProviderAccountAuthoritySnapshotV1.parse(
|
|
72946
|
+
turn.xaiProviderAccountAuthoritySnapshot,
|
|
72947
|
+
);
|
|
72948
|
+
const human =
|
|
72949
|
+
turn.initiatingHumanSubjectId ??
|
|
72950
|
+
(turn.initiatorKind === "subject" ? turn.initiatorSubjectId : null);
|
|
72951
|
+
if (
|
|
72952
|
+
!human &&
|
|
72953
|
+
(personalConnectionDelegations.some((d) => d.userDelegation) ||
|
|
72954
|
+
xaiProviderAccountAuthoritySnapshot.scope === "user")
|
|
72955
|
+
) {
|
|
72956
|
+
throw new SessionControlInvariantError("Causal turn lost its personal execution authority");
|
|
72957
|
+
}
|
|
72958
|
+
return {
|
|
72959
|
+
personalConnectionDelegations,
|
|
72960
|
+
xaiProviderAccountAuthoritySnapshot,
|
|
72961
|
+
lineage: {
|
|
72962
|
+
causalTurnId: turn.id,
|
|
72963
|
+
...(human && personalConnectionDelegations.some((d) => d.userDelegation)
|
|
72964
|
+
? { connectionAuthoritySubjectId: human }
|
|
72965
|
+
: {}),
|
|
72966
|
+
...(human && xaiProviderAccountAuthoritySnapshot.scope === "user"
|
|
72967
|
+
? { xaiAuthoritySubjectId: human }
|
|
72968
|
+
: {}),
|
|
72969
|
+
},
|
|
72970
|
+
};
|
|
72971
|
+
}
|
|
72972
|
+
|
|
72973
|
+
/** Resolve only the immutable launch receipt, including pre-0419 managed rows.
|
|
72974
|
+
* Legacy Connected Machine rows have no durable launch identity and stay
|
|
72975
|
+
* unattributed. Neither a current session owner nor its latest turn is a substitute. */
|
|
72976
|
+
async function backgroundCommandCausalAuthorityTx(
|
|
72977
|
+
tx: Database,
|
|
72978
|
+
input: { accountId: string; workspaceId: string; sessionId: string; commandId: string },
|
|
72979
|
+
) {
|
|
72980
|
+
const [command] = await tx
|
|
72981
|
+
.select()
|
|
72982
|
+
.from(schema.sessionBackgroundCommands)
|
|
72983
|
+
.where(
|
|
72984
|
+
and(
|
|
72985
|
+
eq(schema.sessionBackgroundCommands.accountId, input.accountId),
|
|
72986
|
+
eq(schema.sessionBackgroundCommands.workspaceId, input.workspaceId),
|
|
72987
|
+
eq(schema.sessionBackgroundCommands.sessionId, input.sessionId),
|
|
72988
|
+
eq(schema.sessionBackgroundCommands.id, input.commandId),
|
|
72989
|
+
),
|
|
72990
|
+
)
|
|
72991
|
+
.limit(1);
|
|
72992
|
+
if (!command || !["exited", "lost"].includes(command.state) || !command.settledAt) return null;
|
|
72993
|
+
let turnId = command.launchTurnId;
|
|
72994
|
+
let attemptId = command.launchAttemptId;
|
|
72995
|
+
let generation = command.launchExecutionGeneration;
|
|
72996
|
+
if (!turnId && command.provider === "managed" && command.retainedProcessId) {
|
|
72997
|
+
const [process] = await tx
|
|
72998
|
+
.select()
|
|
72999
|
+
.from(schema.sandboxRetainedProcesses)
|
|
73000
|
+
.where(
|
|
73001
|
+
and(
|
|
73002
|
+
eq(schema.sandboxRetainedProcesses.id, command.retainedProcessId),
|
|
73003
|
+
eq(schema.sandboxRetainedProcesses.accountId, input.accountId),
|
|
73004
|
+
eq(schema.sandboxRetainedProcesses.workspaceId, input.workspaceId),
|
|
73005
|
+
eq(schema.sandboxRetainedProcesses.sessionId, input.sessionId),
|
|
73006
|
+
),
|
|
73007
|
+
)
|
|
73008
|
+
.limit(1);
|
|
73009
|
+
if (process?.ownerActorKind === "turn" && process.ownerActorId === process.ownerAttemptId) {
|
|
73010
|
+
turnId = process.ownerTurnId;
|
|
73011
|
+
attemptId = process.ownerAttemptId;
|
|
73012
|
+
generation = process.ownerExecutionGeneration;
|
|
73013
|
+
}
|
|
73014
|
+
}
|
|
73015
|
+
if (!turnId || !attemptId || !generation) return null;
|
|
73016
|
+
const [attempt] = await tx
|
|
73017
|
+
.select({ id: schema.sessionTurnAttempts.id })
|
|
73018
|
+
.from(schema.sessionTurnAttempts)
|
|
73019
|
+
.where(
|
|
73020
|
+
and(
|
|
73021
|
+
eq(schema.sessionTurnAttempts.id, attemptId),
|
|
73022
|
+
eq(schema.sessionTurnAttempts.accountId, input.accountId),
|
|
73023
|
+
eq(schema.sessionTurnAttempts.workspaceId, input.workspaceId),
|
|
73024
|
+
eq(schema.sessionTurnAttempts.sessionId, input.sessionId),
|
|
73025
|
+
eq(schema.sessionTurnAttempts.turnId, turnId),
|
|
73026
|
+
eq(schema.sessionTurnAttempts.executionGeneration, generation),
|
|
73027
|
+
),
|
|
73028
|
+
)
|
|
73029
|
+
.limit(1);
|
|
73030
|
+
if (!attempt) return null;
|
|
73031
|
+
const authority = await sameSessionCausalAuthorityTx(tx, { ...input, turnId });
|
|
73032
|
+
return authority
|
|
73033
|
+
? {
|
|
73034
|
+
...authority,
|
|
73035
|
+
lineage: {
|
|
73036
|
+
...authority.lineage,
|
|
73037
|
+
causalAttemptId: attemptId,
|
|
73038
|
+
causalExecutionGeneration: generation,
|
|
73039
|
+
},
|
|
73040
|
+
}
|
|
73041
|
+
: null;
|
|
73042
|
+
}
|
|
73043
|
+
|
|
72802
73044
|
function backgroundCommandTerminalMutation(input: {
|
|
72803
73045
|
accountId: string;
|
|
72804
73046
|
workspaceId: string;
|
|
@@ -72934,6 +73176,10 @@ function backgroundCommandTerminalMutation(input: {
|
|
|
72934
73176
|
...(command.failure ? { failure: command.failure } : {}),
|
|
72935
73177
|
outputLocator,
|
|
72936
73178
|
};
|
|
73179
|
+
const causalAuthority = await backgroundCommandCausalAuthorityTx(tx as unknown as Database, {
|
|
73180
|
+
...input,
|
|
73181
|
+
commandId: command.id,
|
|
73182
|
+
});
|
|
72937
73183
|
const [insertedUpdate] = await tx
|
|
72938
73184
|
.insert(schema.sessionSystemUpdates)
|
|
72939
73185
|
.values(
|
|
@@ -72949,7 +73195,15 @@ function backgroundCommandTerminalMutation(input: {
|
|
|
72949
73195
|
dedupeKey: `background-command-result:${command.id}`,
|
|
72950
73196
|
summary,
|
|
72951
73197
|
payload,
|
|
72952
|
-
|
|
73198
|
+
personalConnectionDelegations: causalAuthority?.personalConnectionDelegations ?? [],
|
|
73199
|
+
xaiProviderAccountAuthoritySnapshot:
|
|
73200
|
+
causalAuthority?.xaiProviderAccountAuthoritySnapshot ??
|
|
73201
|
+
WORKSPACE_XAI_PROVIDER_ACCOUNT_AUTHORITY_SNAPSHOT_V1,
|
|
73202
|
+
lineage: {
|
|
73203
|
+
commandId: command.id,
|
|
73204
|
+
provider: command.provider,
|
|
73205
|
+
...causalAuthority?.lineage,
|
|
73206
|
+
},
|
|
72953
73207
|
state: "pending",
|
|
72954
73208
|
},
|
|
72955
73209
|
"summary",
|