dsh-kingdom 2.0.0 → 3.2.0
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/ASSETS_NOTICE.md +22 -22
- package/README.md +246 -243
- package/THIRD_PARTY_NOTICES.md +92 -92
- package/docs/DSH-KINGDOM-3.0-ANNOUNCEMENT.md +13 -0
- package/docs/V2.0-RELEASE-NOTES.md +30 -30
- package/docs/V2.0-USER-GUIDE.md +74 -74
- package/docs/V3.0-RELEASE-NOTES.md +21 -0
- package/docs/V3.0-USER-GUIDE.md +33 -0
- package/docs/V3.1-RELEASE-NOTES.md +76 -0
- package/docs/V3.2-RELEASE-NOTES.md +103 -0
- package/lib/core/binding.js +167 -60
- package/lib/core/binding.js.map +1 -1
- package/lib/core/db.js +582 -546
- package/lib/core/db.js.map +1 -1
- package/lib/core/delivery-ack.js +1356 -0
- package/lib/core/delivery-ack.js.map +1 -0
- package/lib/core/delivery-change.js +1237 -0
- package/lib/core/delivery-change.js.map +1 -0
- package/lib/core/owner-binding-intent.js +14 -25
- package/lib/core/owner-binding-intent.js.map +1 -1
- package/lib/core/owner-window.js +698 -23
- package/lib/core/owner-window.js.map +1 -1
- package/lib/core/task-service.js +144 -5
- package/lib/core/task-service.js.map +1 -1
- package/lib/core/territory.js +43 -9
- package/lib/core/territory.js.map +1 -1
- package/lib/gui/assets/characters/chancellor-idle.svg +67 -67
- package/lib/gui/assets/characters/chancellor-sleeping.svg +67 -67
- package/lib/gui/assets/characters/chancellor-thinking.svg +67 -67
- package/lib/gui/assets/characters/chancellor-working.svg +67 -67
- package/lib/gui/assets/characters/knight-redraw-r1-idle.svg +67 -67
- package/lib/gui/assets/characters/knight-redraw-r1-sleeping.svg +67 -67
- package/lib/gui/assets/characters/knight-redraw-r1-thinking.svg +67 -67
- package/lib/gui/assets/characters/knight-redraw-r1-working.svg +67 -67
- package/lib/gui/assets/characters/supervisor-idle.svg +67 -67
- package/lib/gui/assets/characters/supervisor-sleeping.svg +67 -67
- package/lib/gui/assets/characters/supervisor-thinking.svg +67 -67
- package/lib/gui/assets/characters/supervisor-working.svg +67 -67
- package/lib/gui/console-app.js +7 -1
- package/lib/gui/console-app.js.map +1 -1
- package/lib/gui/contract.js +6 -0
- package/lib/gui/contract.js.map +1 -1
- package/lib/gui/control-contract.js +3 -2
- package/lib/gui/control-contract.js.map +1 -1
- package/lib/gui/owner-control.js +114 -4
- package/lib/gui/owner-control.js.map +1 -1
- package/lib/gui/owner-ui.js +645 -183
- package/lib/gui/owner-ui.js.map +1 -1
- package/lib/gui/server.js +109 -109
- package/lib/gui/snapshot.js +127 -4
- package/lib/gui/snapshot.js.map +1 -1
- package/lib/gui/visual-assets.js +37 -21
- package/lib/gui/visual-assets.js.map +1 -1
- package/lib/gui/visual-system.js +269 -269
- package/lib/gui/workbench-ui.js +549 -136
- package/lib/gui/workbench-ui.js.map +1 -1
- package/lib/gui/workbench.js +133 -0
- package/lib/gui/workbench.js.map +1 -1
- package/lib/index.js +392 -40
- package/lib/index.js.map +1 -1
- package/lib/types/core/binding.d.ts +29 -0
- package/lib/types/core/db.d.ts +14 -0
- package/lib/types/core/delivery-ack.d.ts +688 -0
- package/lib/types/core/delivery-change.d.ts +381 -0
- package/lib/types/core/owner-binding-intent.d.ts +9 -1
- package/lib/types/core/owner-window.d.ts +237 -3
- package/lib/types/core/task-service.d.ts +22 -0
- package/lib/types/core/territory.d.ts +18 -3
- package/lib/types/gui/contract.d.ts +162 -1
- package/lib/types/gui/owner-control.d.ts +61 -1
- package/lib/types/gui/snapshot.d.ts +8 -0
- package/lib/types/gui/visual-assets.d.ts +16 -0
- package/lib/types/gui/workbench.d.ts +47 -1
- package/lib/types/index.d.ts +60 -1
- package/lib/types/worker/governed-executor.d.ts +15 -0
- package/lib/worker/governed-executor.js +21 -0
- package/lib/worker/governed-executor.js.map +1 -1
- package/package.json +80 -75
package/lib/core/db.js
CHANGED
|
@@ -44,118 +44,118 @@ import { asExecutionState, isTerminalExecutionState, transitionExecution, } from
|
|
|
44
44
|
* - v4 DDL 不进 SCHEMA_SQL bootstrap(避免迁移事务语义失效;见 ensureSchemaV4 头注)。
|
|
45
45
|
*/
|
|
46
46
|
export const SCHEMA_VERSION = 4;
|
|
47
|
-
export const SCHEMA_SQL = `
|
|
48
|
-
CREATE TABLE IF NOT EXISTS kingdoms (
|
|
49
|
-
kingdom_id TEXT PRIMARY KEY,
|
|
50
|
-
name TEXT NOT NULL,
|
|
51
|
-
created_at TEXT NOT NULL,
|
|
52
|
-
owner_id TEXT NOT NULL,
|
|
53
|
-
owner_name TEXT NOT NULL,
|
|
54
|
-
schema_version INTEGER NOT NULL DEFAULT 1
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
CREATE TABLE IF NOT EXISTS territories (
|
|
58
|
-
territory_id TEXT PRIMARY KEY,
|
|
59
|
-
kingdom_id TEXT NOT NULL,
|
|
60
|
-
name TEXT NOT NULL,
|
|
61
|
-
workspace_path TEXT,
|
|
62
|
-
summary TEXT,
|
|
63
|
-
supervisor_binding_id TEXT,
|
|
64
|
-
status TEXT NOT NULL DEFAULT 'ACTIVE',
|
|
65
|
-
created_at TEXT NOT NULL
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
CREATE TABLE IF NOT EXISTS role_bindings (
|
|
69
|
-
binding_id TEXT PRIMARY KEY,
|
|
70
|
-
kingdom_id TEXT NOT NULL,
|
|
71
|
-
role_type TEXT NOT NULL CHECK(role_type IN ('OWNER','CHANCELLOR','SUPERVISOR','WORKER')),
|
|
72
|
-
role_name TEXT NOT NULL,
|
|
73
|
-
runtime_type TEXT NOT NULL DEFAULT 'dsh',
|
|
74
|
-
session_id TEXT,
|
|
75
|
-
model_name TEXT,
|
|
76
|
-
agent_name TEXT,
|
|
77
|
-
session_meta TEXT,
|
|
78
|
-
principal_id TEXT,
|
|
79
|
-
created_at TEXT NOT NULL,
|
|
80
|
-
updated_at TEXT NOT NULL
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
CREATE TABLE IF NOT EXISTS tasks (
|
|
84
|
-
task_id TEXT PRIMARY KEY,
|
|
85
|
-
territory_id TEXT NOT NULL,
|
|
86
|
-
parent_task_id TEXT,
|
|
87
|
-
title TEXT NOT NULL,
|
|
88
|
-
description TEXT,
|
|
89
|
-
assigned_binding_id TEXT,
|
|
90
|
-
status TEXT NOT NULL DEFAULT 'CREATED',
|
|
91
|
-
acceptance_criteria TEXT,
|
|
92
|
-
result_summary TEXT,
|
|
93
|
-
created_at TEXT NOT NULL,
|
|
94
|
-
updated_at TEXT NOT NULL
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
CREATE TABLE IF NOT EXISTS events (
|
|
98
|
-
event_id TEXT PRIMARY KEY,
|
|
99
|
-
kingdom_id TEXT NOT NULL,
|
|
100
|
-
event_type TEXT NOT NULL,
|
|
101
|
-
actor_role TEXT,
|
|
102
|
-
actor_id TEXT,
|
|
103
|
-
target_type TEXT,
|
|
104
|
-
target_id TEXT,
|
|
105
|
-
payload_json TEXT NOT NULL DEFAULT '{}',
|
|
106
|
-
created_at TEXT NOT NULL
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
CREATE TABLE IF NOT EXISTS worker_results (
|
|
110
|
-
result_id TEXT PRIMARY KEY,
|
|
111
|
-
task_id TEXT NOT NULL,
|
|
112
|
-
attempt_no INTEGER NOT NULL,
|
|
113
|
-
worker_binding_id TEXT,
|
|
114
|
-
session_id TEXT,
|
|
115
|
-
outcome TEXT NOT NULL,
|
|
116
|
-
result_json TEXT NOT NULL DEFAULT '{}',
|
|
117
|
-
created_at TEXT NOT NULL,
|
|
118
|
-
UNIQUE(task_id, attempt_no)
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
CREATE UNIQUE INDEX IF NOT EXISTS territories_kingdom_name_uk
|
|
122
|
-
ON territories(kingdom_id, name);
|
|
123
|
-
|
|
124
|
-
CREATE TABLE IF NOT EXISTS executions (
|
|
125
|
-
execution_id TEXT PRIMARY KEY,
|
|
126
|
-
task_id TEXT NOT NULL,
|
|
127
|
-
attempt_no INTEGER NOT NULL,
|
|
128
|
-
worker_binding_id TEXT,
|
|
129
|
-
session_id TEXT,
|
|
130
|
-
state TEXT NOT NULL,
|
|
131
|
-
detail TEXT,
|
|
132
|
-
started_at TEXT NOT NULL,
|
|
133
|
-
heartbeat_at TEXT,
|
|
134
|
-
ended_at TEXT,
|
|
135
|
-
pause_requested_at TEXT,
|
|
136
|
-
UNIQUE(task_id, attempt_no)
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
CREATE INDEX IF NOT EXISTS executions_task_idx ON executions(task_id);
|
|
140
|
-
|
|
141
|
-
CREATE TABLE IF NOT EXISTS task_assignments (
|
|
142
|
-
assignment_id TEXT PRIMARY KEY,
|
|
143
|
-
task_id TEXT NOT NULL,
|
|
144
|
-
territory_id TEXT NOT NULL,
|
|
145
|
-
worker_binding_id TEXT NOT NULL,
|
|
146
|
-
assigned_by TEXT NOT NULL,
|
|
147
|
-
assigned_at TEXT NOT NULL,
|
|
148
|
-
ended_at TEXT,
|
|
149
|
-
end_reason TEXT,
|
|
150
|
-
previous_assignment_id TEXT,
|
|
151
|
-
handoff_reason TEXT,
|
|
152
|
-
created_at TEXT NOT NULL
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
CREATE UNIQUE INDEX IF NOT EXISTS one_active_assignment_per_task
|
|
156
|
-
ON task_assignments(task_id) WHERE ended_at IS NULL;
|
|
157
|
-
|
|
158
|
-
CREATE INDEX IF NOT EXISTS task_assignments_task_idx ON task_assignments(task_id);
|
|
47
|
+
export const SCHEMA_SQL = `
|
|
48
|
+
CREATE TABLE IF NOT EXISTS kingdoms (
|
|
49
|
+
kingdom_id TEXT PRIMARY KEY,
|
|
50
|
+
name TEXT NOT NULL,
|
|
51
|
+
created_at TEXT NOT NULL,
|
|
52
|
+
owner_id TEXT NOT NULL,
|
|
53
|
+
owner_name TEXT NOT NULL,
|
|
54
|
+
schema_version INTEGER NOT NULL DEFAULT 1
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
CREATE TABLE IF NOT EXISTS territories (
|
|
58
|
+
territory_id TEXT PRIMARY KEY,
|
|
59
|
+
kingdom_id TEXT NOT NULL,
|
|
60
|
+
name TEXT NOT NULL,
|
|
61
|
+
workspace_path TEXT,
|
|
62
|
+
summary TEXT,
|
|
63
|
+
supervisor_binding_id TEXT,
|
|
64
|
+
status TEXT NOT NULL DEFAULT 'ACTIVE',
|
|
65
|
+
created_at TEXT NOT NULL
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
CREATE TABLE IF NOT EXISTS role_bindings (
|
|
69
|
+
binding_id TEXT PRIMARY KEY,
|
|
70
|
+
kingdom_id TEXT NOT NULL,
|
|
71
|
+
role_type TEXT NOT NULL CHECK(role_type IN ('OWNER','CHANCELLOR','SUPERVISOR','WORKER')),
|
|
72
|
+
role_name TEXT NOT NULL,
|
|
73
|
+
runtime_type TEXT NOT NULL DEFAULT 'dsh',
|
|
74
|
+
session_id TEXT,
|
|
75
|
+
model_name TEXT,
|
|
76
|
+
agent_name TEXT,
|
|
77
|
+
session_meta TEXT,
|
|
78
|
+
principal_id TEXT,
|
|
79
|
+
created_at TEXT NOT NULL,
|
|
80
|
+
updated_at TEXT NOT NULL
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
CREATE TABLE IF NOT EXISTS tasks (
|
|
84
|
+
task_id TEXT PRIMARY KEY,
|
|
85
|
+
territory_id TEXT NOT NULL,
|
|
86
|
+
parent_task_id TEXT,
|
|
87
|
+
title TEXT NOT NULL,
|
|
88
|
+
description TEXT,
|
|
89
|
+
assigned_binding_id TEXT,
|
|
90
|
+
status TEXT NOT NULL DEFAULT 'CREATED',
|
|
91
|
+
acceptance_criteria TEXT,
|
|
92
|
+
result_summary TEXT,
|
|
93
|
+
created_at TEXT NOT NULL,
|
|
94
|
+
updated_at TEXT NOT NULL
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
98
|
+
event_id TEXT PRIMARY KEY,
|
|
99
|
+
kingdom_id TEXT NOT NULL,
|
|
100
|
+
event_type TEXT NOT NULL,
|
|
101
|
+
actor_role TEXT,
|
|
102
|
+
actor_id TEXT,
|
|
103
|
+
target_type TEXT,
|
|
104
|
+
target_id TEXT,
|
|
105
|
+
payload_json TEXT NOT NULL DEFAULT '{}',
|
|
106
|
+
created_at TEXT NOT NULL
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
CREATE TABLE IF NOT EXISTS worker_results (
|
|
110
|
+
result_id TEXT PRIMARY KEY,
|
|
111
|
+
task_id TEXT NOT NULL,
|
|
112
|
+
attempt_no INTEGER NOT NULL,
|
|
113
|
+
worker_binding_id TEXT,
|
|
114
|
+
session_id TEXT,
|
|
115
|
+
outcome TEXT NOT NULL,
|
|
116
|
+
result_json TEXT NOT NULL DEFAULT '{}',
|
|
117
|
+
created_at TEXT NOT NULL,
|
|
118
|
+
UNIQUE(task_id, attempt_no)
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
CREATE UNIQUE INDEX IF NOT EXISTS territories_kingdom_name_uk
|
|
122
|
+
ON territories(kingdom_id, name);
|
|
123
|
+
|
|
124
|
+
CREATE TABLE IF NOT EXISTS executions (
|
|
125
|
+
execution_id TEXT PRIMARY KEY,
|
|
126
|
+
task_id TEXT NOT NULL,
|
|
127
|
+
attempt_no INTEGER NOT NULL,
|
|
128
|
+
worker_binding_id TEXT,
|
|
129
|
+
session_id TEXT,
|
|
130
|
+
state TEXT NOT NULL,
|
|
131
|
+
detail TEXT,
|
|
132
|
+
started_at TEXT NOT NULL,
|
|
133
|
+
heartbeat_at TEXT,
|
|
134
|
+
ended_at TEXT,
|
|
135
|
+
pause_requested_at TEXT,
|
|
136
|
+
UNIQUE(task_id, attempt_no)
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
CREATE INDEX IF NOT EXISTS executions_task_idx ON executions(task_id);
|
|
140
|
+
|
|
141
|
+
CREATE TABLE IF NOT EXISTS task_assignments (
|
|
142
|
+
assignment_id TEXT PRIMARY KEY,
|
|
143
|
+
task_id TEXT NOT NULL,
|
|
144
|
+
territory_id TEXT NOT NULL,
|
|
145
|
+
worker_binding_id TEXT NOT NULL,
|
|
146
|
+
assigned_by TEXT NOT NULL,
|
|
147
|
+
assigned_at TEXT NOT NULL,
|
|
148
|
+
ended_at TEXT,
|
|
149
|
+
end_reason TEXT,
|
|
150
|
+
previous_assignment_id TEXT,
|
|
151
|
+
handoff_reason TEXT,
|
|
152
|
+
created_at TEXT NOT NULL
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
CREATE UNIQUE INDEX IF NOT EXISTS one_active_assignment_per_task
|
|
156
|
+
ON task_assignments(task_id) WHERE ended_at IS NULL;
|
|
157
|
+
|
|
158
|
+
CREATE INDEX IF NOT EXISTS task_assignments_task_idx ON task_assignments(task_id);
|
|
159
159
|
`;
|
|
160
160
|
export class KingdomStore {
|
|
161
161
|
db;
|
|
@@ -163,6 +163,11 @@ export class KingdomStore {
|
|
|
163
163
|
existed;
|
|
164
164
|
/** 库的 schema 版本(经 kingdoms.schema_version 收敛;v4 判定用)。 */
|
|
165
165
|
schemaVersion;
|
|
166
|
+
/**
|
|
167
|
+
* withImmediateTransaction 的重入深度。
|
|
168
|
+
* 0 = 无事务在跑;>0 = 已有外层事务,内层调用只加入、不再 BEGIN/COMMIT/ROLLBACK。
|
|
169
|
+
*/
|
|
170
|
+
transactionDepth = 0;
|
|
166
171
|
constructor(dbPath, options = {}) {
|
|
167
172
|
mkdirSync(dirname(dbPath), { recursive: true });
|
|
168
173
|
const existed = isExistingDatabase(dbPath);
|
|
@@ -335,13 +340,13 @@ export class KingdomStore {
|
|
|
335
340
|
.prepare(`SELECT COUNT(*) AS n FROM role_bindings WHERE role_type = 'SUPERVISOR' AND status = 'ACTIVE'`)
|
|
336
341
|
.get();
|
|
337
342
|
if (supervisorCount.n === 1) {
|
|
338
|
-
this.db.exec(`
|
|
339
|
-
UPDATE territories
|
|
340
|
-
SET supervisor_binding_id = (
|
|
341
|
-
SELECT binding_id FROM role_bindings
|
|
342
|
-
WHERE role_type = 'SUPERVISOR' AND status = 'ACTIVE' LIMIT 1
|
|
343
|
-
)
|
|
344
|
-
WHERE supervisor_binding_id IS NULL AND status = 'ACTIVE'
|
|
343
|
+
this.db.exec(`
|
|
344
|
+
UPDATE territories
|
|
345
|
+
SET supervisor_binding_id = (
|
|
346
|
+
SELECT binding_id FROM role_bindings
|
|
347
|
+
WHERE role_type = 'SUPERVISOR' AND status = 'ACTIVE' LIMIT 1
|
|
348
|
+
)
|
|
349
|
+
WHERE supervisor_binding_id IS NULL AND status = 'ACTIVE'
|
|
345
350
|
`);
|
|
346
351
|
}
|
|
347
352
|
// verify:全部预期列/表/索引存在,缺失即失败(fail-loud)
|
|
@@ -386,351 +391,351 @@ export class KingdomStore {
|
|
|
386
391
|
// 既有 v3 库开库瞬间就被建出 v4 表,ensureSchemaV4 的"单事务迁移 + 失败 ROLLBACK"
|
|
387
392
|
// 语义失效。因此 v4 全部 DDL 只在 ensureSchemaV4 的 BEGIN IMMEDIATE 事务内落地。
|
|
388
393
|
/** v4 Ledger 表(affinity/lease/decision)+ 各自索引与 trigger(不含 executions 重建与 dispatch)。 */
|
|
389
|
-
static V4_LEDGER_SQL = `
|
|
390
|
-
CREATE TABLE IF NOT EXISTS session_territory_affinities (
|
|
391
|
-
affinity_id TEXT PRIMARY KEY,
|
|
392
|
-
kingdom_id TEXT NOT NULL,
|
|
393
|
-
worker_binding_id TEXT NOT NULL,
|
|
394
|
-
runtime_type TEXT NOT NULL,
|
|
395
|
-
runtime_instance_ref TEXT NOT NULL,
|
|
396
|
-
session_ref TEXT NOT NULL,
|
|
397
|
-
territory_id TEXT NOT NULL,
|
|
398
|
-
established_at TEXT NOT NULL,
|
|
399
|
-
retired_at TEXT,
|
|
400
|
-
is_current INTEGER NOT NULL DEFAULT 1,
|
|
401
|
-
created_at TEXT NOT NULL,
|
|
402
|
-
UNIQUE (runtime_type, runtime_instance_ref, session_ref),
|
|
403
|
-
CHECK (
|
|
404
|
-
(is_current = 1 AND retired_at IS NULL)
|
|
405
|
-
OR
|
|
406
|
-
(is_current = 0 AND retired_at IS NOT NULL)
|
|
407
|
-
)
|
|
408
|
-
);
|
|
409
|
-
CREATE UNIQUE INDEX IF NOT EXISTS affinity_one_current_per_worker
|
|
410
|
-
ON session_territory_affinities(kingdom_id, worker_binding_id)
|
|
411
|
-
WHERE is_current = 1;
|
|
412
|
-
CREATE TRIGGER IF NOT EXISTS affinity_identity_immutable
|
|
413
|
-
BEFORE UPDATE OF kingdom_id, worker_binding_id, runtime_type,
|
|
414
|
-
runtime_instance_ref, session_ref, territory_id,
|
|
415
|
-
established_at, created_at
|
|
416
|
-
ON session_territory_affinities
|
|
417
|
-
BEGIN SELECT RAISE(ABORT, 'AFFINITY_IDENTITY_IMMUTABLE'); END;
|
|
418
|
-
CREATE TRIGGER IF NOT EXISTS affinity_retire
|
|
419
|
-
BEFORE UPDATE OF is_current, retired_at
|
|
420
|
-
ON session_territory_affinities
|
|
421
|
-
BEGIN
|
|
422
|
-
SELECT RAISE(ABORT, 'AFFINITY_RETIRE_ONLY_JOINT')
|
|
423
|
-
WHERE NOT (
|
|
424
|
-
OLD.is_current = 1 AND OLD.retired_at IS NULL
|
|
425
|
-
AND NEW.is_current = 0 AND NEW.retired_at IS NOT NULL
|
|
426
|
-
);
|
|
427
|
-
SELECT RAISE(ABORT, 'AFFINITY_ALREADY_RETIRED')
|
|
428
|
-
WHERE OLD.retired_at IS NOT NULL;
|
|
429
|
-
END;
|
|
430
|
-
CREATE TRIGGER IF NOT EXISTS affinity_no_delete
|
|
431
|
-
BEFORE DELETE ON session_territory_affinities
|
|
432
|
-
BEGIN SELECT RAISE(ABORT, 'AFFINITY_NO_DELETE'); END;
|
|
433
|
-
|
|
434
|
-
CREATE TABLE IF NOT EXISTS execution_leases (
|
|
435
|
-
lease_id TEXT PRIMARY KEY,
|
|
436
|
-
kingdom_id TEXT NOT NULL,
|
|
437
|
-
worker_binding_id TEXT NOT NULL,
|
|
438
|
-
runtime_type TEXT NOT NULL,
|
|
439
|
-
runtime_instance_ref TEXT NOT NULL,
|
|
440
|
-
session_ref TEXT NOT NULL,
|
|
441
|
-
territory_id TEXT NOT NULL,
|
|
442
|
-
task_id TEXT NOT NULL,
|
|
443
|
-
attempt_no INTEGER NOT NULL,
|
|
444
|
-
state TEXT NOT NULL CHECK(state IN
|
|
445
|
-
('ACQUIRED','PREPARING','MATERIALIZING','DISPATCH_READY',
|
|
446
|
-
'EXECUTING','SETTLING','RELEASING','RECOVERING','RELEASED')),
|
|
447
|
-
capability_decision_id TEXT,
|
|
448
|
-
enforcement_plan_snapshot TEXT,
|
|
449
|
-
release_evidence_json TEXT,
|
|
450
|
-
release_reason TEXT,
|
|
451
|
-
acquired_at TEXT NOT NULL,
|
|
452
|
-
released_at TEXT,
|
|
453
|
-
updated_at TEXT NOT NULL,
|
|
454
|
-
UNIQUE (task_id, attempt_no),
|
|
455
|
-
UNIQUE (runtime_type, runtime_instance_ref, session_ref, task_id, attempt_no)
|
|
456
|
-
);
|
|
457
|
-
CREATE UNIQUE INDEX IF NOT EXISTS lease_one_active_per_session
|
|
458
|
-
ON execution_leases(runtime_type, runtime_instance_ref, session_ref)
|
|
459
|
-
WHERE state <> 'RELEASED';
|
|
460
|
-
CREATE TRIGGER IF NOT EXISTS lease_requires_matching_affinity
|
|
461
|
-
BEFORE INSERT ON execution_leases
|
|
462
|
-
BEGIN
|
|
463
|
-
SELECT RAISE(ABORT, 'LEASE_REQUIRES_MATCHING_CURRENT_AFFINITY')
|
|
464
|
-
WHERE NOT EXISTS (
|
|
465
|
-
SELECT 1
|
|
466
|
-
FROM session_territory_affinities a
|
|
467
|
-
JOIN tasks t ON t.task_id = NEW.task_id
|
|
468
|
-
WHERE a.kingdom_id = NEW.kingdom_id
|
|
469
|
-
AND a.worker_binding_id = NEW.worker_binding_id
|
|
470
|
-
AND a.runtime_type = NEW.runtime_type
|
|
471
|
-
AND a.runtime_instance_ref = NEW.runtime_instance_ref
|
|
472
|
-
AND a.session_ref = NEW.session_ref
|
|
473
|
-
AND a.is_current = 1 AND a.retired_at IS NULL
|
|
474
|
-
AND a.territory_id = NEW.territory_id
|
|
475
|
-
AND t.territory_id = NEW.territory_id
|
|
476
|
-
);
|
|
477
|
-
END;
|
|
478
|
-
CREATE TRIGGER IF NOT EXISTS lease_identity_immutable
|
|
479
|
-
BEFORE UPDATE OF kingdom_id, worker_binding_id, runtime_type, runtime_instance_ref,
|
|
480
|
-
session_ref, territory_id, task_id, attempt_no, acquired_at
|
|
481
|
-
ON execution_leases
|
|
482
|
-
BEGIN SELECT RAISE(ABORT, 'LEASE_IDENTITY_IMMUTABLE'); END;
|
|
483
|
-
CREATE TRIGGER IF NOT EXISTS lease_plan_once
|
|
484
|
-
BEFORE UPDATE OF enforcement_plan_snapshot
|
|
485
|
-
ON execution_leases
|
|
486
|
-
WHEN OLD.enforcement_plan_snapshot IS NOT NULL
|
|
487
|
-
BEGIN SELECT RAISE(ABORT, 'LEASE_PLAN_ALREADY_SET'); END;
|
|
488
|
-
CREATE TRIGGER IF NOT EXISTS lease_decision_once
|
|
489
|
-
BEFORE UPDATE OF capability_decision_id
|
|
490
|
-
ON execution_leases
|
|
491
|
-
WHEN OLD.capability_decision_id IS NOT NULL
|
|
492
|
-
BEGIN SELECT RAISE(ABORT, 'LEASE_DECISION_ALREADY_BOUND'); END;
|
|
493
|
-
CREATE TRIGGER IF NOT EXISTS lease_release_evidence_once
|
|
494
|
-
BEFORE UPDATE OF release_evidence_json, release_reason
|
|
495
|
-
ON execution_leases
|
|
496
|
-
WHEN OLD.release_evidence_json IS NOT NULL
|
|
497
|
-
BEGIN SELECT RAISE(ABORT, 'LEASE_RELEASE_EVIDENCE_ALREADY_SET'); END;
|
|
498
|
-
CREATE TRIGGER IF NOT EXISTS lease_state_guard
|
|
499
|
-
BEFORE UPDATE OF state ON execution_leases
|
|
500
|
-
WHEN NEW.state <> OLD.state
|
|
501
|
-
BEGIN
|
|
502
|
-
SELECT RAISE(ABORT, 'ILLEGAL_LEASE_TRANSITION') WHERE NOT (
|
|
503
|
-
(OLD.state='ACQUIRED' AND NEW.state IN ('PREPARING','RECOVERING'))
|
|
504
|
-
OR (OLD.state='PREPARING' AND NEW.state IN ('MATERIALIZING','RECOVERING'))
|
|
505
|
-
OR (OLD.state='MATERIALIZING' AND NEW.state IN ('DISPATCH_READY','RECOVERING','RELEASED'))
|
|
506
|
-
OR (OLD.state='DISPATCH_READY' AND NEW.state IN ('EXECUTING','RECOVERING'))
|
|
507
|
-
OR (OLD.state='EXECUTING' AND NEW.state IN ('SETTLING','RECOVERING'))
|
|
508
|
-
OR (OLD.state='SETTLING' AND NEW.state IN ('RELEASING','RECOVERING'))
|
|
509
|
-
OR (OLD.state='RELEASING' AND NEW.state IN ('RELEASED','RECOVERING'))
|
|
510
|
-
OR (OLD.state='RECOVERING' AND NEW.state IN ('RELEASED','RECOVERING'))
|
|
511
|
-
);
|
|
512
|
-
SELECT RAISE(ABORT, 'LEASE_MATERIALIZING_REQUIRES_PLAN')
|
|
513
|
-
WHERE NEW.state='MATERIALIZING' AND (NEW.enforcement_plan_snapshot IS NULL OR json_valid(NEW.enforcement_plan_snapshot)=0);
|
|
514
|
-
SELECT RAISE(ABORT, 'LEASE_DISPATCH_READY_REQUIRES_DECISION')
|
|
515
|
-
WHERE NEW.state='DISPATCH_READY' AND NOT EXISTS (
|
|
516
|
-
SELECT 1 FROM capability_decisions d
|
|
517
|
-
WHERE d.decision_id = NEW.capability_decision_id
|
|
518
|
-
AND d.decision='GRANTED' AND d.enforcement_status='ENFORCED'
|
|
519
|
-
AND d.enforcement_evidence_json IS NOT NULL
|
|
520
|
-
);
|
|
521
|
-
SELECT RAISE(ABORT, 'LEASE_RELEASED_REQUIRES_EVIDENCE')
|
|
522
|
-
WHERE NEW.state='RELEASED' AND (NEW.release_evidence_json IS NULL OR NEW.released_at IS NULL);
|
|
523
|
-
END;
|
|
524
|
-
CREATE TRIGGER IF NOT EXISTS lease_insert_state_guard
|
|
525
|
-
BEFORE INSERT ON execution_leases
|
|
526
|
-
WHEN NEW.state <> 'ACQUIRED'
|
|
527
|
-
BEGIN SELECT RAISE(ABORT, 'LEASE_INSERT_MUST_BE_ACQUIRED'); END;
|
|
528
|
-
CREATE TRIGGER IF NOT EXISTS lease_no_delete
|
|
529
|
-
BEFORE DELETE ON execution_leases
|
|
530
|
-
BEGIN SELECT RAISE(ABORT, 'LEASE_NO_DELETE'); END;
|
|
531
|
-
|
|
532
|
-
CREATE TABLE IF NOT EXISTS capability_decisions (
|
|
533
|
-
decision_id TEXT PRIMARY KEY,
|
|
534
|
-
kingdom_id TEXT NOT NULL,
|
|
535
|
-
task_id TEXT NOT NULL,
|
|
536
|
-
worker_binding_id TEXT,
|
|
537
|
-
supervisor_binding_id TEXT,
|
|
538
|
-
requirement_snapshot TEXT,
|
|
539
|
-
ceiling_snapshot TEXT,
|
|
540
|
-
proposed_grant_snapshot TEXT,
|
|
541
|
-
scope_snapshot TEXT,
|
|
542
|
-
effective_snapshot TEXT,
|
|
543
|
-
decision TEXT NOT NULL,
|
|
544
|
-
enforcement_status TEXT NOT NULL,
|
|
545
|
-
enforcement_evidence_json TEXT,
|
|
546
|
-
requirement_coverage TEXT NOT NULL DEFAULT 'NONE'
|
|
547
|
-
CHECK(requirement_coverage IN ('FULL','PARTIAL','NONE')),
|
|
548
|
-
reason_code TEXT,
|
|
549
|
-
execution_id TEXT,
|
|
550
|
-
created_at TEXT NOT NULL,
|
|
551
|
-
CHECK (
|
|
552
|
-
(decision = 'GRANTED' AND enforcement_status = 'ENFORCED')
|
|
553
|
-
OR
|
|
554
|
-
(decision = 'DENIED' AND enforcement_status IN
|
|
555
|
-
('NOT_ATTEMPTED','UNAVAILABLE','FAILED'))
|
|
556
|
-
),
|
|
557
|
-
CHECK (decision <> 'GRANTED' OR
|
|
558
|
-
(enforcement_evidence_json IS NOT NULL AND json_valid(enforcement_evidence_json)=1))
|
|
559
|
-
);
|
|
560
|
-
CREATE UNIQUE INDEX IF NOT EXISTS capability_decision_execution_uk
|
|
561
|
-
ON capability_decisions(execution_id) WHERE execution_id IS NOT NULL;
|
|
562
|
-
CREATE TRIGGER IF NOT EXISTS capability_decision_immutable
|
|
563
|
-
BEFORE UPDATE OF kingdom_id, task_id, worker_binding_id, supervisor_binding_id,
|
|
564
|
-
requirement_snapshot, ceiling_snapshot, proposed_grant_snapshot,
|
|
565
|
-
scope_snapshot, effective_snapshot, decision, enforcement_status,
|
|
566
|
-
enforcement_evidence_json, requirement_coverage, reason_code, created_at
|
|
567
|
-
ON capability_decisions
|
|
568
|
-
BEGIN SELECT RAISE(ABORT, 'CAPABILITY_DECISION_IMMUTABLE'); END;
|
|
569
|
-
CREATE TRIGGER IF NOT EXISTS capability_decision_execution_bind
|
|
570
|
-
BEFORE UPDATE OF execution_id
|
|
571
|
-
ON capability_decisions
|
|
572
|
-
WHEN NEW.execution_id IS NOT NULL
|
|
573
|
-
BEGIN
|
|
574
|
-
SELECT RAISE(ABORT, 'CAPABILITY_DECISION_EXECUTION_ALREADY_BOUND')
|
|
575
|
-
WHERE OLD.execution_id IS NOT NULL;
|
|
576
|
-
SELECT RAISE(ABORT, 'CAPABILITY_DECISION_BIND_REQUIRES_GRANTED')
|
|
577
|
-
WHERE NOT (OLD.decision='GRANTED' AND OLD.enforcement_status='ENFORCED');
|
|
578
|
-
END;
|
|
579
|
-
CREATE TRIGGER IF NOT EXISTS capability_decision_no_delete
|
|
580
|
-
BEFORE DELETE ON capability_decisions
|
|
581
|
-
BEGIN SELECT RAISE(ABORT, 'CAPABILITY_DECISION_NO_DELETE'); END;
|
|
394
|
+
static V4_LEDGER_SQL = `
|
|
395
|
+
CREATE TABLE IF NOT EXISTS session_territory_affinities (
|
|
396
|
+
affinity_id TEXT PRIMARY KEY,
|
|
397
|
+
kingdom_id TEXT NOT NULL,
|
|
398
|
+
worker_binding_id TEXT NOT NULL,
|
|
399
|
+
runtime_type TEXT NOT NULL,
|
|
400
|
+
runtime_instance_ref TEXT NOT NULL,
|
|
401
|
+
session_ref TEXT NOT NULL,
|
|
402
|
+
territory_id TEXT NOT NULL,
|
|
403
|
+
established_at TEXT NOT NULL,
|
|
404
|
+
retired_at TEXT,
|
|
405
|
+
is_current INTEGER NOT NULL DEFAULT 1,
|
|
406
|
+
created_at TEXT NOT NULL,
|
|
407
|
+
UNIQUE (runtime_type, runtime_instance_ref, session_ref),
|
|
408
|
+
CHECK (
|
|
409
|
+
(is_current = 1 AND retired_at IS NULL)
|
|
410
|
+
OR
|
|
411
|
+
(is_current = 0 AND retired_at IS NOT NULL)
|
|
412
|
+
)
|
|
413
|
+
);
|
|
414
|
+
CREATE UNIQUE INDEX IF NOT EXISTS affinity_one_current_per_worker
|
|
415
|
+
ON session_territory_affinities(kingdom_id, worker_binding_id)
|
|
416
|
+
WHERE is_current = 1;
|
|
417
|
+
CREATE TRIGGER IF NOT EXISTS affinity_identity_immutable
|
|
418
|
+
BEFORE UPDATE OF kingdom_id, worker_binding_id, runtime_type,
|
|
419
|
+
runtime_instance_ref, session_ref, territory_id,
|
|
420
|
+
established_at, created_at
|
|
421
|
+
ON session_territory_affinities
|
|
422
|
+
BEGIN SELECT RAISE(ABORT, 'AFFINITY_IDENTITY_IMMUTABLE'); END;
|
|
423
|
+
CREATE TRIGGER IF NOT EXISTS affinity_retire
|
|
424
|
+
BEFORE UPDATE OF is_current, retired_at
|
|
425
|
+
ON session_territory_affinities
|
|
426
|
+
BEGIN
|
|
427
|
+
SELECT RAISE(ABORT, 'AFFINITY_RETIRE_ONLY_JOINT')
|
|
428
|
+
WHERE NOT (
|
|
429
|
+
OLD.is_current = 1 AND OLD.retired_at IS NULL
|
|
430
|
+
AND NEW.is_current = 0 AND NEW.retired_at IS NOT NULL
|
|
431
|
+
);
|
|
432
|
+
SELECT RAISE(ABORT, 'AFFINITY_ALREADY_RETIRED')
|
|
433
|
+
WHERE OLD.retired_at IS NOT NULL;
|
|
434
|
+
END;
|
|
435
|
+
CREATE TRIGGER IF NOT EXISTS affinity_no_delete
|
|
436
|
+
BEFORE DELETE ON session_territory_affinities
|
|
437
|
+
BEGIN SELECT RAISE(ABORT, 'AFFINITY_NO_DELETE'); END;
|
|
438
|
+
|
|
439
|
+
CREATE TABLE IF NOT EXISTS execution_leases (
|
|
440
|
+
lease_id TEXT PRIMARY KEY,
|
|
441
|
+
kingdom_id TEXT NOT NULL,
|
|
442
|
+
worker_binding_id TEXT NOT NULL,
|
|
443
|
+
runtime_type TEXT NOT NULL,
|
|
444
|
+
runtime_instance_ref TEXT NOT NULL,
|
|
445
|
+
session_ref TEXT NOT NULL,
|
|
446
|
+
territory_id TEXT NOT NULL,
|
|
447
|
+
task_id TEXT NOT NULL,
|
|
448
|
+
attempt_no INTEGER NOT NULL,
|
|
449
|
+
state TEXT NOT NULL CHECK(state IN
|
|
450
|
+
('ACQUIRED','PREPARING','MATERIALIZING','DISPATCH_READY',
|
|
451
|
+
'EXECUTING','SETTLING','RELEASING','RECOVERING','RELEASED')),
|
|
452
|
+
capability_decision_id TEXT,
|
|
453
|
+
enforcement_plan_snapshot TEXT,
|
|
454
|
+
release_evidence_json TEXT,
|
|
455
|
+
release_reason TEXT,
|
|
456
|
+
acquired_at TEXT NOT NULL,
|
|
457
|
+
released_at TEXT,
|
|
458
|
+
updated_at TEXT NOT NULL,
|
|
459
|
+
UNIQUE (task_id, attempt_no),
|
|
460
|
+
UNIQUE (runtime_type, runtime_instance_ref, session_ref, task_id, attempt_no)
|
|
461
|
+
);
|
|
462
|
+
CREATE UNIQUE INDEX IF NOT EXISTS lease_one_active_per_session
|
|
463
|
+
ON execution_leases(runtime_type, runtime_instance_ref, session_ref)
|
|
464
|
+
WHERE state <> 'RELEASED';
|
|
465
|
+
CREATE TRIGGER IF NOT EXISTS lease_requires_matching_affinity
|
|
466
|
+
BEFORE INSERT ON execution_leases
|
|
467
|
+
BEGIN
|
|
468
|
+
SELECT RAISE(ABORT, 'LEASE_REQUIRES_MATCHING_CURRENT_AFFINITY')
|
|
469
|
+
WHERE NOT EXISTS (
|
|
470
|
+
SELECT 1
|
|
471
|
+
FROM session_territory_affinities a
|
|
472
|
+
JOIN tasks t ON t.task_id = NEW.task_id
|
|
473
|
+
WHERE a.kingdom_id = NEW.kingdom_id
|
|
474
|
+
AND a.worker_binding_id = NEW.worker_binding_id
|
|
475
|
+
AND a.runtime_type = NEW.runtime_type
|
|
476
|
+
AND a.runtime_instance_ref = NEW.runtime_instance_ref
|
|
477
|
+
AND a.session_ref = NEW.session_ref
|
|
478
|
+
AND a.is_current = 1 AND a.retired_at IS NULL
|
|
479
|
+
AND a.territory_id = NEW.territory_id
|
|
480
|
+
AND t.territory_id = NEW.territory_id
|
|
481
|
+
);
|
|
482
|
+
END;
|
|
483
|
+
CREATE TRIGGER IF NOT EXISTS lease_identity_immutable
|
|
484
|
+
BEFORE UPDATE OF kingdom_id, worker_binding_id, runtime_type, runtime_instance_ref,
|
|
485
|
+
session_ref, territory_id, task_id, attempt_no, acquired_at
|
|
486
|
+
ON execution_leases
|
|
487
|
+
BEGIN SELECT RAISE(ABORT, 'LEASE_IDENTITY_IMMUTABLE'); END;
|
|
488
|
+
CREATE TRIGGER IF NOT EXISTS lease_plan_once
|
|
489
|
+
BEFORE UPDATE OF enforcement_plan_snapshot
|
|
490
|
+
ON execution_leases
|
|
491
|
+
WHEN OLD.enforcement_plan_snapshot IS NOT NULL
|
|
492
|
+
BEGIN SELECT RAISE(ABORT, 'LEASE_PLAN_ALREADY_SET'); END;
|
|
493
|
+
CREATE TRIGGER IF NOT EXISTS lease_decision_once
|
|
494
|
+
BEFORE UPDATE OF capability_decision_id
|
|
495
|
+
ON execution_leases
|
|
496
|
+
WHEN OLD.capability_decision_id IS NOT NULL
|
|
497
|
+
BEGIN SELECT RAISE(ABORT, 'LEASE_DECISION_ALREADY_BOUND'); END;
|
|
498
|
+
CREATE TRIGGER IF NOT EXISTS lease_release_evidence_once
|
|
499
|
+
BEFORE UPDATE OF release_evidence_json, release_reason
|
|
500
|
+
ON execution_leases
|
|
501
|
+
WHEN OLD.release_evidence_json IS NOT NULL
|
|
502
|
+
BEGIN SELECT RAISE(ABORT, 'LEASE_RELEASE_EVIDENCE_ALREADY_SET'); END;
|
|
503
|
+
CREATE TRIGGER IF NOT EXISTS lease_state_guard
|
|
504
|
+
BEFORE UPDATE OF state ON execution_leases
|
|
505
|
+
WHEN NEW.state <> OLD.state
|
|
506
|
+
BEGIN
|
|
507
|
+
SELECT RAISE(ABORT, 'ILLEGAL_LEASE_TRANSITION') WHERE NOT (
|
|
508
|
+
(OLD.state='ACQUIRED' AND NEW.state IN ('PREPARING','RECOVERING'))
|
|
509
|
+
OR (OLD.state='PREPARING' AND NEW.state IN ('MATERIALIZING','RECOVERING'))
|
|
510
|
+
OR (OLD.state='MATERIALIZING' AND NEW.state IN ('DISPATCH_READY','RECOVERING','RELEASED'))
|
|
511
|
+
OR (OLD.state='DISPATCH_READY' AND NEW.state IN ('EXECUTING','RECOVERING'))
|
|
512
|
+
OR (OLD.state='EXECUTING' AND NEW.state IN ('SETTLING','RECOVERING'))
|
|
513
|
+
OR (OLD.state='SETTLING' AND NEW.state IN ('RELEASING','RECOVERING'))
|
|
514
|
+
OR (OLD.state='RELEASING' AND NEW.state IN ('RELEASED','RECOVERING'))
|
|
515
|
+
OR (OLD.state='RECOVERING' AND NEW.state IN ('RELEASED','RECOVERING'))
|
|
516
|
+
);
|
|
517
|
+
SELECT RAISE(ABORT, 'LEASE_MATERIALIZING_REQUIRES_PLAN')
|
|
518
|
+
WHERE NEW.state='MATERIALIZING' AND (NEW.enforcement_plan_snapshot IS NULL OR json_valid(NEW.enforcement_plan_snapshot)=0);
|
|
519
|
+
SELECT RAISE(ABORT, 'LEASE_DISPATCH_READY_REQUIRES_DECISION')
|
|
520
|
+
WHERE NEW.state='DISPATCH_READY' AND NOT EXISTS (
|
|
521
|
+
SELECT 1 FROM capability_decisions d
|
|
522
|
+
WHERE d.decision_id = NEW.capability_decision_id
|
|
523
|
+
AND d.decision='GRANTED' AND d.enforcement_status='ENFORCED'
|
|
524
|
+
AND d.enforcement_evidence_json IS NOT NULL
|
|
525
|
+
);
|
|
526
|
+
SELECT RAISE(ABORT, 'LEASE_RELEASED_REQUIRES_EVIDENCE')
|
|
527
|
+
WHERE NEW.state='RELEASED' AND (NEW.release_evidence_json IS NULL OR NEW.released_at IS NULL);
|
|
528
|
+
END;
|
|
529
|
+
CREATE TRIGGER IF NOT EXISTS lease_insert_state_guard
|
|
530
|
+
BEFORE INSERT ON execution_leases
|
|
531
|
+
WHEN NEW.state <> 'ACQUIRED'
|
|
532
|
+
BEGIN SELECT RAISE(ABORT, 'LEASE_INSERT_MUST_BE_ACQUIRED'); END;
|
|
533
|
+
CREATE TRIGGER IF NOT EXISTS lease_no_delete
|
|
534
|
+
BEFORE DELETE ON execution_leases
|
|
535
|
+
BEGIN SELECT RAISE(ABORT, 'LEASE_NO_DELETE'); END;
|
|
536
|
+
|
|
537
|
+
CREATE TABLE IF NOT EXISTS capability_decisions (
|
|
538
|
+
decision_id TEXT PRIMARY KEY,
|
|
539
|
+
kingdom_id TEXT NOT NULL,
|
|
540
|
+
task_id TEXT NOT NULL,
|
|
541
|
+
worker_binding_id TEXT,
|
|
542
|
+
supervisor_binding_id TEXT,
|
|
543
|
+
requirement_snapshot TEXT,
|
|
544
|
+
ceiling_snapshot TEXT,
|
|
545
|
+
proposed_grant_snapshot TEXT,
|
|
546
|
+
scope_snapshot TEXT,
|
|
547
|
+
effective_snapshot TEXT,
|
|
548
|
+
decision TEXT NOT NULL,
|
|
549
|
+
enforcement_status TEXT NOT NULL,
|
|
550
|
+
enforcement_evidence_json TEXT,
|
|
551
|
+
requirement_coverage TEXT NOT NULL DEFAULT 'NONE'
|
|
552
|
+
CHECK(requirement_coverage IN ('FULL','PARTIAL','NONE')),
|
|
553
|
+
reason_code TEXT,
|
|
554
|
+
execution_id TEXT,
|
|
555
|
+
created_at TEXT NOT NULL,
|
|
556
|
+
CHECK (
|
|
557
|
+
(decision = 'GRANTED' AND enforcement_status = 'ENFORCED')
|
|
558
|
+
OR
|
|
559
|
+
(decision = 'DENIED' AND enforcement_status IN
|
|
560
|
+
('NOT_ATTEMPTED','UNAVAILABLE','FAILED'))
|
|
561
|
+
),
|
|
562
|
+
CHECK (decision <> 'GRANTED' OR
|
|
563
|
+
(enforcement_evidence_json IS NOT NULL AND json_valid(enforcement_evidence_json)=1))
|
|
564
|
+
);
|
|
565
|
+
CREATE UNIQUE INDEX IF NOT EXISTS capability_decision_execution_uk
|
|
566
|
+
ON capability_decisions(execution_id) WHERE execution_id IS NOT NULL;
|
|
567
|
+
CREATE TRIGGER IF NOT EXISTS capability_decision_immutable
|
|
568
|
+
BEFORE UPDATE OF kingdom_id, task_id, worker_binding_id, supervisor_binding_id,
|
|
569
|
+
requirement_snapshot, ceiling_snapshot, proposed_grant_snapshot,
|
|
570
|
+
scope_snapshot, effective_snapshot, decision, enforcement_status,
|
|
571
|
+
enforcement_evidence_json, requirement_coverage, reason_code, created_at
|
|
572
|
+
ON capability_decisions
|
|
573
|
+
BEGIN SELECT RAISE(ABORT, 'CAPABILITY_DECISION_IMMUTABLE'); END;
|
|
574
|
+
CREATE TRIGGER IF NOT EXISTS capability_decision_execution_bind
|
|
575
|
+
BEFORE UPDATE OF execution_id
|
|
576
|
+
ON capability_decisions
|
|
577
|
+
WHEN NEW.execution_id IS NOT NULL
|
|
578
|
+
BEGIN
|
|
579
|
+
SELECT RAISE(ABORT, 'CAPABILITY_DECISION_EXECUTION_ALREADY_BOUND')
|
|
580
|
+
WHERE OLD.execution_id IS NOT NULL;
|
|
581
|
+
SELECT RAISE(ABORT, 'CAPABILITY_DECISION_BIND_REQUIRES_GRANTED')
|
|
582
|
+
WHERE NOT (OLD.decision='GRANTED' AND OLD.enforcement_status='ENFORCED');
|
|
583
|
+
END;
|
|
584
|
+
CREATE TRIGGER IF NOT EXISTS capability_decision_no_delete
|
|
585
|
+
BEFORE DELETE ON capability_decisions
|
|
586
|
+
BEGIN SELECT RAISE(ABORT, 'CAPABILITY_DECISION_NO_DELETE'); END;
|
|
582
587
|
`;
|
|
583
588
|
/**
|
|
584
589
|
* executions 重建形态(暂存名 executions_v4,迁移后 RENAME 回 executions)。
|
|
585
590
|
* = 旧 executions 全部列(含 v2 证据列)+ 新增 3 列(v6 §8.1)。
|
|
586
591
|
*/
|
|
587
|
-
static V4_EXECUTIONS_STAGING_SQL = `
|
|
588
|
-
CREATE TABLE IF NOT EXISTS executions_v4 (
|
|
589
|
-
execution_id TEXT PRIMARY KEY,
|
|
590
|
-
task_id TEXT NOT NULL,
|
|
591
|
-
attempt_no INTEGER NOT NULL,
|
|
592
|
-
worker_binding_id TEXT,
|
|
593
|
-
session_id TEXT,
|
|
594
|
-
state TEXT NOT NULL CHECK(state IN
|
|
595
|
-
('STARTING','RUNNING','PAUSED','RECOVERING','COMPLETED','FAILED','ABORTED')),
|
|
596
|
-
detail TEXT,
|
|
597
|
-
started_at TEXT NOT NULL,
|
|
598
|
-
heartbeat_at TEXT,
|
|
599
|
-
ended_at TEXT,
|
|
600
|
-
pause_requested_at TEXT,
|
|
601
|
-
executor_kind TEXT,
|
|
602
|
-
provider TEXT,
|
|
603
|
-
provider_source TEXT,
|
|
604
|
-
requested_model TEXT,
|
|
605
|
-
resolved_model TEXT,
|
|
606
|
-
model_source TEXT,
|
|
607
|
-
execution_profile_json TEXT,
|
|
608
|
-
execution_contract TEXT NOT NULL DEFAULT 'LEGACY_COMPAT'
|
|
609
|
-
CHECK(execution_contract IN ('LEGACY_COMPAT','GOVERNED_PERSISTENT')),
|
|
610
|
-
lease_id TEXT,
|
|
611
|
-
capability_decision_id TEXT,
|
|
612
|
-
UNIQUE (task_id, attempt_no),
|
|
613
|
-
CHECK (
|
|
614
|
-
execution_contract = 'LEGACY_COMPAT'
|
|
615
|
-
OR (
|
|
616
|
-
execution_contract = 'GOVERNED_PERSISTENT'
|
|
617
|
-
AND lease_id IS NOT NULL
|
|
618
|
-
AND capability_decision_id IS NOT NULL
|
|
619
|
-
)
|
|
620
|
-
),
|
|
621
|
-
FOREIGN KEY (lease_id) REFERENCES execution_leases(lease_id),
|
|
622
|
-
FOREIGN KEY (capability_decision_id) REFERENCES capability_decisions(decision_id)
|
|
623
|
-
);
|
|
592
|
+
static V4_EXECUTIONS_STAGING_SQL = `
|
|
593
|
+
CREATE TABLE IF NOT EXISTS executions_v4 (
|
|
594
|
+
execution_id TEXT PRIMARY KEY,
|
|
595
|
+
task_id TEXT NOT NULL,
|
|
596
|
+
attempt_no INTEGER NOT NULL,
|
|
597
|
+
worker_binding_id TEXT,
|
|
598
|
+
session_id TEXT,
|
|
599
|
+
state TEXT NOT NULL CHECK(state IN
|
|
600
|
+
('STARTING','RUNNING','PAUSED','RECOVERING','COMPLETED','FAILED','ABORTED')),
|
|
601
|
+
detail TEXT,
|
|
602
|
+
started_at TEXT NOT NULL,
|
|
603
|
+
heartbeat_at TEXT,
|
|
604
|
+
ended_at TEXT,
|
|
605
|
+
pause_requested_at TEXT,
|
|
606
|
+
executor_kind TEXT,
|
|
607
|
+
provider TEXT,
|
|
608
|
+
provider_source TEXT,
|
|
609
|
+
requested_model TEXT,
|
|
610
|
+
resolved_model TEXT,
|
|
611
|
+
model_source TEXT,
|
|
612
|
+
execution_profile_json TEXT,
|
|
613
|
+
execution_contract TEXT NOT NULL DEFAULT 'LEGACY_COMPAT'
|
|
614
|
+
CHECK(execution_contract IN ('LEGACY_COMPAT','GOVERNED_PERSISTENT')),
|
|
615
|
+
lease_id TEXT,
|
|
616
|
+
capability_decision_id TEXT,
|
|
617
|
+
UNIQUE (task_id, attempt_no),
|
|
618
|
+
CHECK (
|
|
619
|
+
execution_contract = 'LEGACY_COMPAT'
|
|
620
|
+
OR (
|
|
621
|
+
execution_contract = 'GOVERNED_PERSISTENT'
|
|
622
|
+
AND lease_id IS NOT NULL
|
|
623
|
+
AND capability_decision_id IS NOT NULL
|
|
624
|
+
)
|
|
625
|
+
),
|
|
626
|
+
FOREIGN KEY (lease_id) REFERENCES execution_leases(lease_id),
|
|
627
|
+
FOREIGN KEY (capability_decision_id) REFERENCES capability_decisions(decision_id)
|
|
628
|
+
);
|
|
624
629
|
`;
|
|
625
630
|
/** executions 重建后的 trigger(RENAME 回 executions 之后创建;不依赖 RENAME 自动改写)。 */
|
|
626
|
-
static V4_EXECUTIONS_TRIGGERS_SQL = `
|
|
627
|
-
CREATE TRIGGER IF NOT EXISTS execution_governed_consistency
|
|
628
|
-
BEFORE INSERT ON executions
|
|
629
|
-
WHEN NEW.execution_contract = 'GOVERNED_PERSISTENT'
|
|
630
|
-
BEGIN
|
|
631
|
-
SELECT RAISE(ABORT, 'EXECUTION_GOVERNED_REQUIRES_MATCHING_LEASE')
|
|
632
|
-
WHERE NOT EXISTS (
|
|
633
|
-
SELECT 1
|
|
634
|
-
FROM execution_leases l
|
|
635
|
-
JOIN capability_decisions d ON d.decision_id = NEW.capability_decision_id
|
|
636
|
-
WHERE l.lease_id = NEW.lease_id
|
|
637
|
-
AND l.task_id = NEW.task_id
|
|
638
|
-
AND l.attempt_no = NEW.attempt_no
|
|
639
|
-
AND l.capability_decision_id = NEW.capability_decision_id
|
|
640
|
-
AND l.kingdom_id = d.kingdom_id
|
|
641
|
-
AND d.task_id = NEW.task_id
|
|
642
|
-
AND d.decision='GRANTED' AND d.enforcement_status='ENFORCED'
|
|
643
|
-
AND (d.execution_id IS NULL OR d.execution_id = NEW.execution_id)
|
|
644
|
-
);
|
|
645
|
-
END;
|
|
646
|
-
CREATE TRIGGER IF NOT EXISTS execution_contract_immutable
|
|
647
|
-
BEFORE UPDATE OF execution_contract ON executions
|
|
648
|
-
BEGIN SELECT RAISE(ABORT, 'EXECUTION_CONTRACT_IMMUTABLE'); END;
|
|
631
|
+
static V4_EXECUTIONS_TRIGGERS_SQL = `
|
|
632
|
+
CREATE TRIGGER IF NOT EXISTS execution_governed_consistency
|
|
633
|
+
BEFORE INSERT ON executions
|
|
634
|
+
WHEN NEW.execution_contract = 'GOVERNED_PERSISTENT'
|
|
635
|
+
BEGIN
|
|
636
|
+
SELECT RAISE(ABORT, 'EXECUTION_GOVERNED_REQUIRES_MATCHING_LEASE')
|
|
637
|
+
WHERE NOT EXISTS (
|
|
638
|
+
SELECT 1
|
|
639
|
+
FROM execution_leases l
|
|
640
|
+
JOIN capability_decisions d ON d.decision_id = NEW.capability_decision_id
|
|
641
|
+
WHERE l.lease_id = NEW.lease_id
|
|
642
|
+
AND l.task_id = NEW.task_id
|
|
643
|
+
AND l.attempt_no = NEW.attempt_no
|
|
644
|
+
AND l.capability_decision_id = NEW.capability_decision_id
|
|
645
|
+
AND l.kingdom_id = d.kingdom_id
|
|
646
|
+
AND d.task_id = NEW.task_id
|
|
647
|
+
AND d.decision='GRANTED' AND d.enforcement_status='ENFORCED'
|
|
648
|
+
AND (d.execution_id IS NULL OR d.execution_id = NEW.execution_id)
|
|
649
|
+
);
|
|
650
|
+
END;
|
|
651
|
+
CREATE TRIGGER IF NOT EXISTS execution_contract_immutable
|
|
652
|
+
BEFORE UPDATE OF execution_contract ON executions
|
|
653
|
+
BEGIN SELECT RAISE(ABORT, 'EXECUTION_CONTRACT_IMMUTABLE'); END;
|
|
649
654
|
`;
|
|
650
655
|
/** Dispatch Ledger(executions 重建完成后创建;FK 直接指向最终名 executions)。 */
|
|
651
|
-
static V4_DISPATCH_SQL = `
|
|
652
|
-
CREATE TABLE IF NOT EXISTS dispatch_records (
|
|
653
|
-
dispatch_id TEXT PRIMARY KEY,
|
|
654
|
-
kingdom_id TEXT NOT NULL,
|
|
655
|
-
lease_id TEXT NOT NULL,
|
|
656
|
-
execution_id TEXT NOT NULL,
|
|
657
|
-
task_id TEXT NOT NULL,
|
|
658
|
-
attempt_no INTEGER NOT NULL,
|
|
659
|
-
runtime_type TEXT NOT NULL,
|
|
660
|
-
runtime_instance_ref TEXT NOT NULL,
|
|
661
|
-
session_ref TEXT NOT NULL,
|
|
662
|
-
state TEXT NOT NULL CHECK(state IN
|
|
663
|
-
('INTENDED','DISPATCHED','RECEIVED','CORRELATED','TERMINAL','FAILED','RECOVERING')),
|
|
664
|
-
dispatch_request_snapshot TEXT NOT NULL,
|
|
665
|
-
dispatch_input_ref_json TEXT NOT NULL,
|
|
666
|
-
dispatch_payload_hash TEXT NOT NULL,
|
|
667
|
-
runtime_dispatch_ref TEXT,
|
|
668
|
-
runtime_execution_ref TEXT,
|
|
669
|
-
receipt_json TEXT,
|
|
670
|
-
terminal_evidence_json TEXT,
|
|
671
|
-
output_ref_json TEXT,
|
|
672
|
-
dispatched_at TEXT,
|
|
673
|
-
receipt_at TEXT,
|
|
674
|
-
terminal_at TEXT,
|
|
675
|
-
created_at TEXT NOT NULL,
|
|
676
|
-
updated_at TEXT NOT NULL,
|
|
677
|
-
FOREIGN KEY (lease_id) REFERENCES execution_leases(lease_id),
|
|
678
|
-
FOREIGN KEY (execution_id) REFERENCES executions(execution_id),
|
|
679
|
-
UNIQUE (lease_id),
|
|
680
|
-
UNIQUE (execution_id)
|
|
681
|
-
);
|
|
682
|
-
CREATE TRIGGER IF NOT EXISTS dispatch_request_immutable
|
|
683
|
-
BEFORE UPDATE OF dispatch_id, kingdom_id, lease_id, execution_id, task_id, attempt_no,
|
|
684
|
-
runtime_type, runtime_instance_ref, session_ref,
|
|
685
|
-
dispatch_request_snapshot, dispatch_input_ref_json, dispatch_payload_hash,
|
|
686
|
-
created_at
|
|
687
|
-
ON dispatch_records
|
|
688
|
-
BEGIN SELECT RAISE(ABORT, 'DISPATCH_REQUEST_IMMUTABLE'); END;
|
|
689
|
-
CREATE TRIGGER IF NOT EXISTS dispatch_requires_ready_lease
|
|
690
|
-
BEFORE INSERT ON dispatch_records
|
|
691
|
-
BEGIN
|
|
692
|
-
SELECT RAISE(ABORT, 'DISPATCH_REQUIRES_MATCHING_READY_LEASE')
|
|
693
|
-
WHERE NOT EXISTS (
|
|
694
|
-
SELECT 1
|
|
695
|
-
FROM execution_leases l
|
|
696
|
-
JOIN executions e ON e.execution_id = NEW.execution_id
|
|
697
|
-
WHERE l.lease_id = NEW.lease_id
|
|
698
|
-
AND l.state = 'DISPATCH_READY'
|
|
699
|
-
AND l.kingdom_id = NEW.kingdom_id
|
|
700
|
-
AND l.task_id = NEW.task_id
|
|
701
|
-
AND l.attempt_no = NEW.attempt_no
|
|
702
|
-
AND l.runtime_type = NEW.runtime_type
|
|
703
|
-
AND l.runtime_instance_ref = NEW.runtime_instance_ref
|
|
704
|
-
AND l.session_ref = NEW.session_ref
|
|
705
|
-
AND e.task_id = NEW.task_id
|
|
706
|
-
AND e.attempt_no = NEW.attempt_no
|
|
707
|
-
);
|
|
708
|
-
END;
|
|
709
|
-
CREATE TRIGGER IF NOT EXISTS dispatch_state_guard
|
|
710
|
-
BEFORE UPDATE OF state ON dispatch_records
|
|
711
|
-
WHEN NEW.state <> OLD.state
|
|
712
|
-
BEGIN
|
|
713
|
-
SELECT RAISE(ABORT, 'ILLEGAL_DISPATCH_TRANSITION') WHERE NOT (
|
|
714
|
-
(OLD.state='INTENDED' AND NEW.state IN ('DISPATCHED','FAILED','RECOVERING'))
|
|
715
|
-
OR (OLD.state='DISPATCHED' AND NEW.state IN ('RECEIVED','RECOVERING'))
|
|
716
|
-
OR (OLD.state='RECEIVED' AND NEW.state IN ('CORRELATED','RECOVERING'))
|
|
717
|
-
OR (OLD.state='CORRELATED' AND NEW.state IN ('TERMINAL','RECOVERING'))
|
|
718
|
-
OR (OLD.state='RECOVERING' AND NEW.state IN ('TERMINAL','FAILED','RECOVERING'))
|
|
719
|
-
);
|
|
720
|
-
SELECT RAISE(ABORT, 'DISPATCH_RECEIVED_REQUIRES_REF_RECEIPT')
|
|
721
|
-
WHERE NEW.state='RECEIVED' AND (NEW.runtime_dispatch_ref IS NULL OR NEW.receipt_json IS NULL OR NEW.receipt_at IS NULL);
|
|
722
|
-
SELECT RAISE(ABORT, 'DISPATCH_CORRELATED_REQUIRES_EXEC_REF')
|
|
723
|
-
WHERE NEW.state='CORRELATED' AND NEW.runtime_execution_ref IS NULL;
|
|
724
|
-
SELECT RAISE(ABORT, 'DISPATCH_TERMINAL_REQUIRES_EVIDENCE')
|
|
725
|
-
WHERE NEW.state='TERMINAL' AND (NEW.terminal_evidence_json IS NULL OR NEW.terminal_at IS NULL);
|
|
726
|
-
END;
|
|
727
|
-
CREATE TRIGGER IF NOT EXISTS dispatch_insert_state_guard
|
|
728
|
-
BEFORE INSERT ON dispatch_records
|
|
729
|
-
WHEN NEW.state <> 'INTENDED'
|
|
730
|
-
BEGIN SELECT RAISE(ABORT, 'DISPATCH_INSERT_MUST_BE_INTENDED'); END;
|
|
731
|
-
CREATE TRIGGER IF NOT EXISTS dispatch_no_delete
|
|
732
|
-
BEFORE DELETE ON dispatch_records
|
|
733
|
-
BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
656
|
+
static V4_DISPATCH_SQL = `
|
|
657
|
+
CREATE TABLE IF NOT EXISTS dispatch_records (
|
|
658
|
+
dispatch_id TEXT PRIMARY KEY,
|
|
659
|
+
kingdom_id TEXT NOT NULL,
|
|
660
|
+
lease_id TEXT NOT NULL,
|
|
661
|
+
execution_id TEXT NOT NULL,
|
|
662
|
+
task_id TEXT NOT NULL,
|
|
663
|
+
attempt_no INTEGER NOT NULL,
|
|
664
|
+
runtime_type TEXT NOT NULL,
|
|
665
|
+
runtime_instance_ref TEXT NOT NULL,
|
|
666
|
+
session_ref TEXT NOT NULL,
|
|
667
|
+
state TEXT NOT NULL CHECK(state IN
|
|
668
|
+
('INTENDED','DISPATCHED','RECEIVED','CORRELATED','TERMINAL','FAILED','RECOVERING')),
|
|
669
|
+
dispatch_request_snapshot TEXT NOT NULL,
|
|
670
|
+
dispatch_input_ref_json TEXT NOT NULL,
|
|
671
|
+
dispatch_payload_hash TEXT NOT NULL,
|
|
672
|
+
runtime_dispatch_ref TEXT,
|
|
673
|
+
runtime_execution_ref TEXT,
|
|
674
|
+
receipt_json TEXT,
|
|
675
|
+
terminal_evidence_json TEXT,
|
|
676
|
+
output_ref_json TEXT,
|
|
677
|
+
dispatched_at TEXT,
|
|
678
|
+
receipt_at TEXT,
|
|
679
|
+
terminal_at TEXT,
|
|
680
|
+
created_at TEXT NOT NULL,
|
|
681
|
+
updated_at TEXT NOT NULL,
|
|
682
|
+
FOREIGN KEY (lease_id) REFERENCES execution_leases(lease_id),
|
|
683
|
+
FOREIGN KEY (execution_id) REFERENCES executions(execution_id),
|
|
684
|
+
UNIQUE (lease_id),
|
|
685
|
+
UNIQUE (execution_id)
|
|
686
|
+
);
|
|
687
|
+
CREATE TRIGGER IF NOT EXISTS dispatch_request_immutable
|
|
688
|
+
BEFORE UPDATE OF dispatch_id, kingdom_id, lease_id, execution_id, task_id, attempt_no,
|
|
689
|
+
runtime_type, runtime_instance_ref, session_ref,
|
|
690
|
+
dispatch_request_snapshot, dispatch_input_ref_json, dispatch_payload_hash,
|
|
691
|
+
created_at
|
|
692
|
+
ON dispatch_records
|
|
693
|
+
BEGIN SELECT RAISE(ABORT, 'DISPATCH_REQUEST_IMMUTABLE'); END;
|
|
694
|
+
CREATE TRIGGER IF NOT EXISTS dispatch_requires_ready_lease
|
|
695
|
+
BEFORE INSERT ON dispatch_records
|
|
696
|
+
BEGIN
|
|
697
|
+
SELECT RAISE(ABORT, 'DISPATCH_REQUIRES_MATCHING_READY_LEASE')
|
|
698
|
+
WHERE NOT EXISTS (
|
|
699
|
+
SELECT 1
|
|
700
|
+
FROM execution_leases l
|
|
701
|
+
JOIN executions e ON e.execution_id = NEW.execution_id
|
|
702
|
+
WHERE l.lease_id = NEW.lease_id
|
|
703
|
+
AND l.state = 'DISPATCH_READY'
|
|
704
|
+
AND l.kingdom_id = NEW.kingdom_id
|
|
705
|
+
AND l.task_id = NEW.task_id
|
|
706
|
+
AND l.attempt_no = NEW.attempt_no
|
|
707
|
+
AND l.runtime_type = NEW.runtime_type
|
|
708
|
+
AND l.runtime_instance_ref = NEW.runtime_instance_ref
|
|
709
|
+
AND l.session_ref = NEW.session_ref
|
|
710
|
+
AND e.task_id = NEW.task_id
|
|
711
|
+
AND e.attempt_no = NEW.attempt_no
|
|
712
|
+
);
|
|
713
|
+
END;
|
|
714
|
+
CREATE TRIGGER IF NOT EXISTS dispatch_state_guard
|
|
715
|
+
BEFORE UPDATE OF state ON dispatch_records
|
|
716
|
+
WHEN NEW.state <> OLD.state
|
|
717
|
+
BEGIN
|
|
718
|
+
SELECT RAISE(ABORT, 'ILLEGAL_DISPATCH_TRANSITION') WHERE NOT (
|
|
719
|
+
(OLD.state='INTENDED' AND NEW.state IN ('DISPATCHED','FAILED','RECOVERING'))
|
|
720
|
+
OR (OLD.state='DISPATCHED' AND NEW.state IN ('RECEIVED','RECOVERING'))
|
|
721
|
+
OR (OLD.state='RECEIVED' AND NEW.state IN ('CORRELATED','RECOVERING'))
|
|
722
|
+
OR (OLD.state='CORRELATED' AND NEW.state IN ('TERMINAL','RECOVERING'))
|
|
723
|
+
OR (OLD.state='RECOVERING' AND NEW.state IN ('TERMINAL','FAILED','RECOVERING'))
|
|
724
|
+
);
|
|
725
|
+
SELECT RAISE(ABORT, 'DISPATCH_RECEIVED_REQUIRES_REF_RECEIPT')
|
|
726
|
+
WHERE NEW.state='RECEIVED' AND (NEW.runtime_dispatch_ref IS NULL OR NEW.receipt_json IS NULL OR NEW.receipt_at IS NULL);
|
|
727
|
+
SELECT RAISE(ABORT, 'DISPATCH_CORRELATED_REQUIRES_EXEC_REF')
|
|
728
|
+
WHERE NEW.state='CORRELATED' AND NEW.runtime_execution_ref IS NULL;
|
|
729
|
+
SELECT RAISE(ABORT, 'DISPATCH_TERMINAL_REQUIRES_EVIDENCE')
|
|
730
|
+
WHERE NEW.state='TERMINAL' AND (NEW.terminal_evidence_json IS NULL OR NEW.terminal_at IS NULL);
|
|
731
|
+
END;
|
|
732
|
+
CREATE TRIGGER IF NOT EXISTS dispatch_insert_state_guard
|
|
733
|
+
BEFORE INSERT ON dispatch_records
|
|
734
|
+
WHEN NEW.state <> 'INTENDED'
|
|
735
|
+
BEGIN SELECT RAISE(ABORT, 'DISPATCH_INSERT_MUST_BE_INTENDED'); END;
|
|
736
|
+
CREATE TRIGGER IF NOT EXISTS dispatch_no_delete
|
|
737
|
+
BEFORE DELETE ON dispatch_records
|
|
738
|
+
BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
734
739
|
`;
|
|
735
740
|
/** v4 对象是否已存在(execution_leases 表是 v4 迁移完成的地标)。 */
|
|
736
741
|
hasV4Objects() {
|
|
@@ -771,20 +776,20 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
771
776
|
this.db.exec(KingdomStore.V4_LEDGER_SQL);
|
|
772
777
|
// c. executions 重建:暂存表 → 复制(LEGACY_COMPAT backfill)→ 行数校验
|
|
773
778
|
this.db.exec(KingdomStore.V4_EXECUTIONS_STAGING_SQL);
|
|
774
|
-
this.db.exec(`
|
|
775
|
-
INSERT INTO executions_v4
|
|
776
|
-
(execution_id, task_id, attempt_no, worker_binding_id, session_id, state,
|
|
777
|
-
detail, started_at, heartbeat_at, ended_at, pause_requested_at,
|
|
778
|
-
executor_kind, provider, provider_source, requested_model, resolved_model,
|
|
779
|
-
model_source, execution_profile_json,
|
|
780
|
-
execution_contract, lease_id, capability_decision_id)
|
|
781
|
-
SELECT
|
|
782
|
-
execution_id, task_id, attempt_no, worker_binding_id, session_id, state,
|
|
783
|
-
detail, started_at, heartbeat_at, ended_at, pause_requested_at,
|
|
784
|
-
executor_kind, provider, provider_source, requested_model, resolved_model,
|
|
785
|
-
model_source, execution_profile_json,
|
|
786
|
-
'LEGACY_COMPAT', NULL, NULL
|
|
787
|
-
FROM executions
|
|
779
|
+
this.db.exec(`
|
|
780
|
+
INSERT INTO executions_v4
|
|
781
|
+
(execution_id, task_id, attempt_no, worker_binding_id, session_id, state,
|
|
782
|
+
detail, started_at, heartbeat_at, ended_at, pause_requested_at,
|
|
783
|
+
executor_kind, provider, provider_source, requested_model, resolved_model,
|
|
784
|
+
model_source, execution_profile_json,
|
|
785
|
+
execution_contract, lease_id, capability_decision_id)
|
|
786
|
+
SELECT
|
|
787
|
+
execution_id, task_id, attempt_no, worker_binding_id, session_id, state,
|
|
788
|
+
detail, started_at, heartbeat_at, ended_at, pause_requested_at,
|
|
789
|
+
executor_kind, provider, provider_source, requested_model, resolved_model,
|
|
790
|
+
model_source, execution_profile_json,
|
|
791
|
+
'LEGACY_COMPAT', NULL, NULL
|
|
792
|
+
FROM executions
|
|
788
793
|
`);
|
|
789
794
|
const oldCount = this.db.prepare('SELECT COUNT(*) AS n FROM executions').get();
|
|
790
795
|
const newCount = this.db.prepare('SELECT COUNT(*) AS n FROM executions_v4').get();
|
|
@@ -895,7 +900,7 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
895
900
|
...row,
|
|
896
901
|
};
|
|
897
902
|
this.db
|
|
898
|
-
.prepare(`INSERT INTO kingdoms (kingdom_id, name, created_at, owner_id, owner_name, schema_version)
|
|
903
|
+
.prepare(`INSERT INTO kingdoms (kingdom_id, name, created_at, owner_id, owner_name, schema_version)
|
|
899
904
|
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
900
905
|
.run(full.kingdom_id, full.name, full.created_at, full.owner_id, full.owner_name, full.schema_version);
|
|
901
906
|
return full;
|
|
@@ -921,8 +926,8 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
921
926
|
}
|
|
922
927
|
insertTerritory(row) {
|
|
923
928
|
this.db
|
|
924
|
-
.prepare(`INSERT INTO territories
|
|
925
|
-
(territory_id, kingdom_id, name, workspace_path, summary, supervisor_binding_id, status, created_at)
|
|
929
|
+
.prepare(`INSERT INTO territories
|
|
930
|
+
(territory_id, kingdom_id, name, workspace_path, summary, supervisor_binding_id, status, created_at)
|
|
926
931
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
927
932
|
.run(row.territory_id, row.kingdom_id, row.name, row.workspace_path, row.summary, row.supervisor_binding_id, row.status, row.created_at);
|
|
928
933
|
return row;
|
|
@@ -958,16 +963,16 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
958
963
|
}
|
|
959
964
|
/** Owner topology guards include RECOVERING and unknown future nonterminal states. */
|
|
960
965
|
listUnsettledOwnerExecutions(kingdomId) {
|
|
961
|
-
return this.db.prepare(`SELECT e.* FROM executions e JOIN tasks t ON t.task_id = e.task_id
|
|
962
|
-
JOIN territories te ON te.territory_id = t.territory_id WHERE te.kingdom_id = ?
|
|
966
|
+
return this.db.prepare(`SELECT e.* FROM executions e JOIN tasks t ON t.task_id = e.task_id
|
|
967
|
+
JOIN territories te ON te.territory_id = t.territory_id WHERE te.kingdom_id = ?
|
|
963
968
|
AND e.state NOT IN ('COMPLETED', 'FAILED', 'ABORTED') ORDER BY e.started_at`).all(kingdomId);
|
|
964
969
|
}
|
|
965
970
|
// ── task_assignments(v0.7.0 M2-B Assignment Ledger)──────────
|
|
966
971
|
insertTaskAssignment(row) {
|
|
967
972
|
this.db
|
|
968
|
-
.prepare(`INSERT INTO task_assignments
|
|
969
|
-
(assignment_id, task_id, territory_id, worker_binding_id, assigned_by, assigned_at,
|
|
970
|
-
ended_at, end_reason, previous_assignment_id, handoff_reason, created_at)
|
|
973
|
+
.prepare(`INSERT INTO task_assignments
|
|
974
|
+
(assignment_id, task_id, territory_id, worker_binding_id, assigned_by, assigned_at,
|
|
975
|
+
ended_at, end_reason, previous_assignment_id, handoff_reason, created_at)
|
|
971
976
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
972
977
|
.run(row.assignment_id, row.task_id, row.territory_id, row.worker_binding_id, row.assigned_by, row.assigned_at, row.ended_at, row.end_reason, row.previous_assignment_id, row.handoff_reason, row.created_at);
|
|
973
978
|
return row;
|
|
@@ -1036,10 +1041,10 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1036
1041
|
}
|
|
1037
1042
|
insertBinding(row) {
|
|
1038
1043
|
this.db
|
|
1039
|
-
.prepare(`INSERT INTO role_bindings
|
|
1040
|
-
(binding_id, kingdom_id, role_type, role_name, runtime_type,
|
|
1041
|
-
session_id, model_name, agent_name, session_meta, execution_profile_json,
|
|
1042
|
-
status, retired_at, retired_reason, principal_id, created_at, updated_at)
|
|
1044
|
+
.prepare(`INSERT INTO role_bindings
|
|
1045
|
+
(binding_id, kingdom_id, role_type, role_name, runtime_type,
|
|
1046
|
+
session_id, model_name, agent_name, session_meta, execution_profile_json,
|
|
1047
|
+
status, retired_at, retired_reason, principal_id, created_at, updated_at)
|
|
1043
1048
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
1044
1049
|
.run(row.binding_id, row.kingdom_id, row.role_type, row.role_name, row.runtime_type, row.session_id, row.model_name ?? null, row.agent_name ?? null, row.session_meta ?? null, row.execution_profile_json ?? null, row.status ?? 'ACTIVE', row.retired_at ?? null, row.retired_reason ?? null, row.principal_id, row.created_at, row.updated_at);
|
|
1045
1050
|
return row;
|
|
@@ -1108,8 +1113,8 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1108
1113
|
*/
|
|
1109
1114
|
listDispatchesForTaskAttempt(taskId, attemptNo) {
|
|
1110
1115
|
return this.db
|
|
1111
|
-
.prepare(`SELECT * FROM dispatch_records
|
|
1112
|
-
WHERE task_id = ? AND attempt_no = ?
|
|
1116
|
+
.prepare(`SELECT * FROM dispatch_records
|
|
1117
|
+
WHERE task_id = ? AND attempt_no = ?
|
|
1113
1118
|
ORDER BY created_at ASC`)
|
|
1114
1119
|
.all(taskId, attemptNo);
|
|
1115
1120
|
}
|
|
@@ -1129,11 +1134,11 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1129
1134
|
|| dispatch.attempt_no !== attemptNo)
|
|
1130
1135
|
return null;
|
|
1131
1136
|
const rows = this.db
|
|
1132
|
-
.prepare(`SELECT * FROM events
|
|
1133
|
-
WHERE kingdom_id = ?
|
|
1134
|
-
AND event_type = 'DISPATCH_TERMINAL_INTEGRITY_INCIDENT'
|
|
1135
|
-
AND target_type = 'dispatch'
|
|
1136
|
-
AND target_id = ?
|
|
1137
|
+
.prepare(`SELECT * FROM events
|
|
1138
|
+
WHERE kingdom_id = ?
|
|
1139
|
+
AND event_type = 'DISPATCH_TERMINAL_INTEGRITY_INCIDENT'
|
|
1140
|
+
AND target_type = 'dispatch'
|
|
1141
|
+
AND target_id = ?
|
|
1137
1142
|
ORDER BY seq ASC`)
|
|
1138
1143
|
.all(kingdomId, dispatchId);
|
|
1139
1144
|
for (const row of rows) {
|
|
@@ -1165,13 +1170,13 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1165
1170
|
}
|
|
1166
1171
|
/** Observations and future admission/window policy cannot change an in-flight Runner relation. */
|
|
1167
1172
|
runnerContextRevision(kingdomId, scope) {
|
|
1168
|
-
const rows = this.db.prepare(`SELECT * FROM events
|
|
1169
|
-
WHERE kingdom_id = ? AND event_type NOT IN (
|
|
1170
|
-
'RUNTIME_ROLE_USAGE_OBSERVED', 'RUNTIME_PROMPT_COST_OBSERVED', 'DISPATCH_USAGE_OBSERVED',
|
|
1171
|
-
'BUDGET_POLICY_UPDATED', 'BUDGET_ADMISSION_RESERVED', 'BUDGET_ADMISSION_BOUND', 'BUDGET_ADMISSION_CANCELLED',
|
|
1172
|
-
'OWNER_DECISION_CREATED', 'OWNER_DECISION_REVOKED', 'OWNER_DECISION_CONSUMED'
|
|
1173
|
-
) AND NOT (event_type = 'OWNER_OPERATION_APPLIED' AND COALESCE(
|
|
1174
|
-
CASE WHEN json_valid(payload_json) THEN json_extract(payload_json, '$.action') = 'budget.policy' ELSE 0 END, 0
|
|
1173
|
+
const rows = this.db.prepare(`SELECT * FROM events
|
|
1174
|
+
WHERE kingdom_id = ? AND event_type NOT IN (
|
|
1175
|
+
'RUNTIME_ROLE_USAGE_OBSERVED', 'RUNTIME_PROMPT_COST_OBSERVED', 'DISPATCH_USAGE_OBSERVED',
|
|
1176
|
+
'BUDGET_POLICY_UPDATED', 'BUDGET_ADMISSION_RESERVED', 'BUDGET_ADMISSION_BOUND', 'BUDGET_ADMISSION_CANCELLED',
|
|
1177
|
+
'OWNER_DECISION_CREATED', 'OWNER_DECISION_REVOKED', 'OWNER_DECISION_CONSUMED'
|
|
1178
|
+
) AND NOT (event_type = 'OWNER_OPERATION_APPLIED' AND COALESCE(
|
|
1179
|
+
CASE WHEN json_valid(payload_json) THEN json_extract(payload_json, '$.action') = 'budget.policy' ELSE 0 END, 0
|
|
1175
1180
|
)) ORDER BY seq DESC`).all(kingdomId);
|
|
1176
1181
|
if (!scope)
|
|
1177
1182
|
return rows[0]?.seq ?? 0;
|
|
@@ -1233,9 +1238,37 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1233
1238
|
/**
|
|
1234
1239
|
* v0.7.0(M2):外层事务包装——HANDOFF 等**原子治理操作**(多步写 + 事件)整体提交/回滚。
|
|
1235
1240
|
* appendEvent 的内层 BEGIN 在事务中会抛错,由 appendEvent 的嵌套容忍逻辑接管(见下)。
|
|
1241
|
+
*
|
|
1242
|
+
* v3.2.0:**支持真正的嵌套**。直接 Slash 的 ownerWrite 与 Owner GUI 窗口的 apply 各自已经开了
|
|
1243
|
+
* 一层事务,而领域函数(如「建主管席位 + 设领地主理」)还要求自己的原子边界:
|
|
1244
|
+
* - 外层:`BEGIN IMMEDIATE` / `COMMIT` / `ROLLBACK`;
|
|
1245
|
+
* - 内层:`SAVEPOINT` / `RELEASE` / `ROLLBACK TO`——**内层失败只回滚内层写入**,
|
|
1246
|
+
* 异常照常向上抛(若无人接管,最外层仍会整体 ROLLBACK)。
|
|
1247
|
+
* 这一点是必须的:如果内层只是"加入外层",那么内层捕获异常并返回错误文案时,
|
|
1248
|
+
* 它已经写下的行会留在外层事务里被 COMMIT,原子性就名存实亡。
|
|
1249
|
+
* 用自持深度计数(而非"BEGIN 失败即视为嵌套")避免把真正的加锁失败误判成嵌套。
|
|
1236
1250
|
*/
|
|
1237
1251
|
withImmediateTransaction(fn) {
|
|
1252
|
+
if (this.transactionDepth > 0) {
|
|
1253
|
+
const savepoint = `kingdom_nested_${this.transactionDepth}`;
|
|
1254
|
+
this.db.exec(`SAVEPOINT ${savepoint}`);
|
|
1255
|
+
this.transactionDepth += 1;
|
|
1256
|
+
try {
|
|
1257
|
+
const result = fn();
|
|
1258
|
+
this.db.exec(`RELEASE ${savepoint}`);
|
|
1259
|
+
return result;
|
|
1260
|
+
}
|
|
1261
|
+
catch (error) {
|
|
1262
|
+
this.db.exec(`ROLLBACK TO ${savepoint}`);
|
|
1263
|
+
this.db.exec(`RELEASE ${savepoint}`);
|
|
1264
|
+
throw error;
|
|
1265
|
+
}
|
|
1266
|
+
finally {
|
|
1267
|
+
this.transactionDepth -= 1;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1238
1270
|
this.db.exec('BEGIN IMMEDIATE');
|
|
1271
|
+
this.transactionDepth += 1;
|
|
1239
1272
|
try {
|
|
1240
1273
|
const result = fn();
|
|
1241
1274
|
this.db.exec('COMMIT');
|
|
@@ -1245,6 +1278,9 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1245
1278
|
this.db.exec('ROLLBACK');
|
|
1246
1279
|
throw error;
|
|
1247
1280
|
}
|
|
1281
|
+
finally {
|
|
1282
|
+
this.transactionDepth -= 1;
|
|
1283
|
+
}
|
|
1248
1284
|
}
|
|
1249
1285
|
/**
|
|
1250
1286
|
* 追加事件并分配单调 seq。
|
|
@@ -1269,8 +1305,8 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1269
1305
|
.get();
|
|
1270
1306
|
const seq = (next?.n ?? 0) + 1;
|
|
1271
1307
|
this.db
|
|
1272
|
-
.prepare(`INSERT INTO events
|
|
1273
|
-
(event_id, kingdom_id, event_type, actor_role, actor_id, target_type, target_id, payload_json, created_at, seq)
|
|
1308
|
+
.prepare(`INSERT INTO events
|
|
1309
|
+
(event_id, kingdom_id, event_type, actor_role, actor_id, target_type, target_id, payload_json, created_at, seq)
|
|
1274
1310
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
1275
1311
|
.run(row.event_id, row.kingdom_id, row.event_type, row.actor_role, row.actor_id, row.target_type, row.target_id, row.payload_json, row.created_at, seq);
|
|
1276
1312
|
if (!outer)
|
|
@@ -1306,9 +1342,9 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1306
1342
|
params.push(filter.status);
|
|
1307
1343
|
}
|
|
1308
1344
|
return this.db
|
|
1309
|
-
.prepare(`SELECT t.* FROM tasks t
|
|
1310
|
-
JOIN territories te ON te.territory_id = t.territory_id
|
|
1311
|
-
WHERE ${clauses.join(' AND ')}
|
|
1345
|
+
.prepare(`SELECT t.* FROM tasks t
|
|
1346
|
+
JOIN territories te ON te.territory_id = t.territory_id
|
|
1347
|
+
WHERE ${clauses.join(' AND ')}
|
|
1312
1348
|
ORDER BY t.created_at`)
|
|
1313
1349
|
.all(...params);
|
|
1314
1350
|
}
|
|
@@ -1323,9 +1359,9 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1323
1359
|
const columns = hasRequirementColumn ? ', capability_requirement_json' : '';
|
|
1324
1360
|
const values = hasRequirementColumn ? ', ?' : '';
|
|
1325
1361
|
this.db
|
|
1326
|
-
.prepare(`INSERT INTO tasks
|
|
1327
|
-
(task_id, territory_id, parent_task_id, title, description, assigned_binding_id,
|
|
1328
|
-
status, acceptance_criteria, result_summary, created_at, updated_at${columns})
|
|
1362
|
+
.prepare(`INSERT INTO tasks
|
|
1363
|
+
(task_id, territory_id, parent_task_id, title, description, assigned_binding_id,
|
|
1364
|
+
status, acceptance_criteria, result_summary, created_at, updated_at${columns})
|
|
1329
1365
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?${values})`)
|
|
1330
1366
|
.run(row.task_id, row.territory_id, row.parent_task_id, row.title, row.description, row.assigned_binding_id, row.status, row.acceptance_criteria, row.result_summary, row.created_at, row.updated_at, ...(hasRequirementColumn ? [row.capability_requirement_json ?? null] : []));
|
|
1331
1367
|
return row;
|
|
@@ -1351,7 +1387,7 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1351
1387
|
: patch.assigned_binding_id;
|
|
1352
1388
|
const summary = patch.result_summary === undefined ? task.result_summary : patch.result_summary;
|
|
1353
1389
|
this.db
|
|
1354
|
-
.prepare(`UPDATE tasks SET status = ?, assigned_binding_id = ?, result_summary = ?, updated_at = ?
|
|
1390
|
+
.prepare(`UPDATE tasks SET status = ?, assigned_binding_id = ?, result_summary = ?, updated_at = ?
|
|
1355
1391
|
WHERE task_id = ?`)
|
|
1356
1392
|
.run(next, assigned, summary, now, task.task_id);
|
|
1357
1393
|
return { ...task, status: next, assigned_binding_id: assigned, result_summary: summary, updated_at: now };
|
|
@@ -1387,17 +1423,17 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1387
1423
|
}
|
|
1388
1424
|
/** Complete exact budget ledger; display event windows must never be used as accounting history. */
|
|
1389
1425
|
listBudgetEvents(kingdomId) {
|
|
1390
|
-
return this.db.prepare(`SELECT * FROM events WHERE kingdom_id = ? AND event_type IN
|
|
1391
|
-
('BUDGET_POLICY_UPDATED', 'BUDGET_ADMISSION_RESERVED', 'BUDGET_ADMISSION_BOUND', 'BUDGET_ADMISSION_CANCELLED', 'DISPATCH_INTENDED')
|
|
1426
|
+
return this.db.prepare(`SELECT * FROM events WHERE kingdom_id = ? AND event_type IN
|
|
1427
|
+
('BUDGET_POLICY_UPDATED', 'BUDGET_ADMISSION_RESERVED', 'BUDGET_ADMISSION_BOUND', 'BUDGET_ADMISSION_CANCELLED', 'DISPATCH_INTENDED')
|
|
1392
1428
|
ORDER BY seq ASC`).all(kingdomId);
|
|
1393
1429
|
}
|
|
1394
1430
|
listWorkspaceAdmissionEvents(kingdomId) {
|
|
1395
|
-
return this.db.prepare(`SELECT * FROM events WHERE kingdom_id = ? AND event_type IN
|
|
1396
|
-
('WORKSPACE_ADMISSION_RESERVED', 'WORKSPACE_ADMISSION_BOUND', 'WORKSPACE_ADMISSION_CANCELLED')
|
|
1431
|
+
return this.db.prepare(`SELECT * FROM events WHERE kingdom_id = ? AND event_type IN
|
|
1432
|
+
('WORKSPACE_ADMISSION_RESERVED', 'WORKSPACE_ADMISSION_BOUND', 'WORKSPACE_ADMISSION_CANCELLED')
|
|
1397
1433
|
ORDER BY seq ASC`).all(kingdomId);
|
|
1398
1434
|
}
|
|
1399
1435
|
listRuntimeCostEvents(kingdomId) {
|
|
1400
|
-
return this.db.prepare(`SELECT * FROM events WHERE kingdom_id = ? AND event_type IN
|
|
1436
|
+
return this.db.prepare(`SELECT * FROM events WHERE kingdom_id = ? AND event_type IN
|
|
1401
1437
|
('RUNTIME_ROLE_USAGE_OBSERVED', 'RUNTIME_PROMPT_COST_OBSERVED') ORDER BY seq ASC`).all(kingdomId);
|
|
1402
1438
|
}
|
|
1403
1439
|
listActorEventsSince(kingdomId, actorId, afterSeq) {
|
|
@@ -1435,8 +1471,8 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1435
1471
|
}
|
|
1436
1472
|
insertWorkerResult(row) {
|
|
1437
1473
|
this.db
|
|
1438
|
-
.prepare(`INSERT INTO worker_results
|
|
1439
|
-
(result_id, task_id, attempt_no, worker_binding_id, session_id, outcome, result_json, created_at)
|
|
1474
|
+
.prepare(`INSERT INTO worker_results
|
|
1475
|
+
(result_id, task_id, attempt_no, worker_binding_id, session_id, outcome, result_json, created_at)
|
|
1440
1476
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
1441
1477
|
.run(row.result_id, row.task_id, row.attempt_no, row.worker_binding_id, row.session_id, row.outcome, row.result_json, row.created_at);
|
|
1442
1478
|
return row;
|
|
@@ -1462,21 +1498,21 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1462
1498
|
/** 王国内所有未终结的 Execution(人物应当在场的那些)。 */
|
|
1463
1499
|
listLiveExecutions(kingdomId) {
|
|
1464
1500
|
return this.db
|
|
1465
|
-
.prepare(`SELECT e.* FROM executions e
|
|
1466
|
-
JOIN tasks t ON t.task_id = e.task_id
|
|
1467
|
-
JOIN territories te ON te.territory_id = t.territory_id
|
|
1468
|
-
WHERE te.kingdom_id = ?
|
|
1469
|
-
AND e.state IN ('STARTING', 'RUNNING', 'PAUSED')
|
|
1501
|
+
.prepare(`SELECT e.* FROM executions e
|
|
1502
|
+
JOIN tasks t ON t.task_id = e.task_id
|
|
1503
|
+
JOIN territories te ON te.territory_id = t.territory_id
|
|
1504
|
+
WHERE te.kingdom_id = ?
|
|
1505
|
+
AND e.state IN ('STARTING', 'RUNNING', 'PAUSED')
|
|
1470
1506
|
ORDER BY e.started_at`)
|
|
1471
1507
|
.all(kingdomId);
|
|
1472
1508
|
}
|
|
1473
1509
|
insertExecution(row) {
|
|
1474
1510
|
this.db
|
|
1475
|
-
.prepare(`INSERT INTO executions
|
|
1476
|
-
(execution_id, task_id, attempt_no, worker_binding_id, session_id, state, detail,
|
|
1477
|
-
started_at, heartbeat_at, ended_at, pause_requested_at,
|
|
1478
|
-
executor_kind, provider, provider_source, requested_model, resolved_model, model_source,
|
|
1479
|
-
execution_profile_json, execution_contract, lease_id, capability_decision_id)
|
|
1511
|
+
.prepare(`INSERT INTO executions
|
|
1512
|
+
(execution_id, task_id, attempt_no, worker_binding_id, session_id, state, detail,
|
|
1513
|
+
started_at, heartbeat_at, ended_at, pause_requested_at,
|
|
1514
|
+
executor_kind, provider, provider_source, requested_model, resolved_model, model_source,
|
|
1515
|
+
execution_profile_json, execution_contract, lease_id, capability_decision_id)
|
|
1480
1516
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
1481
1517
|
.run(row.execution_id, row.task_id, row.attempt_no, row.worker_binding_id, row.session_id, row.state, row.detail, row.started_at, row.heartbeat_at, row.ended_at, row.pause_requested_at, row.executor_kind, row.provider, row.provider_source, row.requested_model, row.resolved_model, row.model_source, row.execution_profile_json, row.execution_contract ?? 'LEGACY_COMPAT', row.lease_id ?? null, row.capability_decision_id ?? null);
|
|
1482
1518
|
return row;
|
|
@@ -1509,8 +1545,8 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1509
1545
|
? execution.pause_requested_at
|
|
1510
1546
|
: patch.pauseRequestedAt;
|
|
1511
1547
|
this.db
|
|
1512
|
-
.prepare(`UPDATE executions
|
|
1513
|
-
SET state = ?, detail = ?, session_id = ?, heartbeat_at = ?, ended_at = ?, pause_requested_at = ?
|
|
1548
|
+
.prepare(`UPDATE executions
|
|
1549
|
+
SET state = ?, detail = ?, session_id = ?, heartbeat_at = ?, ended_at = ?, pause_requested_at = ?
|
|
1514
1550
|
WHERE execution_id = ?`)
|
|
1515
1551
|
.run(next, detail, sessionId, now, ended, pauseRequestedAt, execution.execution_id);
|
|
1516
1552
|
return {
|
|
@@ -1533,9 +1569,9 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1533
1569
|
// session_territory_affinities ────────────────────────────────
|
|
1534
1570
|
insertAffinity(row) {
|
|
1535
1571
|
this.db
|
|
1536
|
-
.prepare(`INSERT INTO session_territory_affinities
|
|
1537
|
-
(affinity_id, kingdom_id, worker_binding_id, runtime_type, runtime_instance_ref,
|
|
1538
|
-
session_ref, territory_id, established_at, retired_at, is_current, created_at)
|
|
1572
|
+
.prepare(`INSERT INTO session_territory_affinities
|
|
1573
|
+
(affinity_id, kingdom_id, worker_binding_id, runtime_type, runtime_instance_ref,
|
|
1574
|
+
session_ref, territory_id, established_at, retired_at, is_current, created_at)
|
|
1539
1575
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
1540
1576
|
.run(row.affinity_id, row.kingdom_id, row.worker_binding_id, row.runtime_type, row.runtime_instance_ref, row.session_ref, row.territory_id, row.established_at, row.retired_at ?? null, row.is_current ?? 1, row.created_at);
|
|
1541
1577
|
return row;
|
|
@@ -1546,7 +1582,7 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1546
1582
|
}
|
|
1547
1583
|
getAffinityBySession(session) {
|
|
1548
1584
|
const rows = this.db
|
|
1549
|
-
.prepare(`SELECT * FROM session_territory_affinities
|
|
1585
|
+
.prepare(`SELECT * FROM session_territory_affinities
|
|
1550
1586
|
WHERE runtime_type = ? AND runtime_instance_ref = ? AND session_ref = ?`)
|
|
1551
1587
|
.all(session.runtimeType, session.runtimeInstanceRef, session.sessionRef);
|
|
1552
1588
|
return rows[0] ?? null;
|
|
@@ -1559,7 +1595,7 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1559
1595
|
/** Worker 当前(未退役)Affinity;DB 部分唯一索引保证至多一条。 */
|
|
1560
1596
|
getCurrentAffinityForWorker(kingdomId, workerBindingId) {
|
|
1561
1597
|
const rows = this.db
|
|
1562
|
-
.prepare(`SELECT * FROM session_territory_affinities
|
|
1598
|
+
.prepare(`SELECT * FROM session_territory_affinities
|
|
1563
1599
|
WHERE kingdom_id = ? AND worker_binding_id = ? AND is_current = 1 LIMIT 1`)
|
|
1564
1600
|
.all(kingdomId, workerBindingId);
|
|
1565
1601
|
return rows[0] ?? null;
|
|
@@ -1577,11 +1613,11 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1577
1613
|
// execution_leases ────────────────────────────────────────────
|
|
1578
1614
|
insertLease(row) {
|
|
1579
1615
|
this.db
|
|
1580
|
-
.prepare(`INSERT INTO execution_leases
|
|
1581
|
-
(lease_id, kingdom_id, worker_binding_id, runtime_type, runtime_instance_ref,
|
|
1582
|
-
session_ref, territory_id, task_id, attempt_no, state,
|
|
1583
|
-
capability_decision_id, enforcement_plan_snapshot, release_evidence_json, release_reason,
|
|
1584
|
-
acquired_at, released_at, updated_at)
|
|
1616
|
+
.prepare(`INSERT INTO execution_leases
|
|
1617
|
+
(lease_id, kingdom_id, worker_binding_id, runtime_type, runtime_instance_ref,
|
|
1618
|
+
session_ref, territory_id, task_id, attempt_no, state,
|
|
1619
|
+
capability_decision_id, enforcement_plan_snapshot, release_evidence_json, release_reason,
|
|
1620
|
+
acquired_at, released_at, updated_at)
|
|
1585
1621
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
1586
1622
|
.run(row.lease_id, row.kingdom_id, row.worker_binding_id, row.runtime_type, row.runtime_instance_ref, row.session_ref, row.territory_id, row.task_id, row.attempt_no, row.state, row.capability_decision_id ?? null, row.enforcement_plan_snapshot ?? null, row.release_evidence_json ?? null, row.release_reason ?? null, row.acquired_at, row.released_at ?? null, row.updated_at);
|
|
1587
1623
|
return row;
|
|
@@ -1604,8 +1640,8 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1604
1640
|
/** 某 Session 当前未释放的 Lease(部分唯一索引保证至多一条非 RELEASED)。 */
|
|
1605
1641
|
getActiveLeaseForSession(session) {
|
|
1606
1642
|
const rows = this.db
|
|
1607
|
-
.prepare(`SELECT * FROM execution_leases
|
|
1608
|
-
WHERE runtime_type = ? AND runtime_instance_ref = ? AND session_ref = ? AND state <> 'RELEASED'
|
|
1643
|
+
.prepare(`SELECT * FROM execution_leases
|
|
1644
|
+
WHERE runtime_type = ? AND runtime_instance_ref = ? AND session_ref = ? AND state <> 'RELEASED'
|
|
1609
1645
|
LIMIT 1`)
|
|
1610
1646
|
.all(session.runtimeType, session.runtimeInstanceRef, session.sessionRef);
|
|
1611
1647
|
return rows[0] ?? null;
|
|
@@ -1653,11 +1689,11 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1653
1689
|
// capability_decisions ────────────────────────────────────────
|
|
1654
1690
|
insertCapabilityDecision(row) {
|
|
1655
1691
|
this.db
|
|
1656
|
-
.prepare(`INSERT INTO capability_decisions
|
|
1657
|
-
(decision_id, kingdom_id, task_id, worker_binding_id, supervisor_binding_id,
|
|
1658
|
-
requirement_snapshot, ceiling_snapshot, proposed_grant_snapshot, scope_snapshot, effective_snapshot,
|
|
1659
|
-
decision, enforcement_status, enforcement_evidence_json, requirement_coverage,
|
|
1660
|
-
reason_code, execution_id, created_at)
|
|
1692
|
+
.prepare(`INSERT INTO capability_decisions
|
|
1693
|
+
(decision_id, kingdom_id, task_id, worker_binding_id, supervisor_binding_id,
|
|
1694
|
+
requirement_snapshot, ceiling_snapshot, proposed_grant_snapshot, scope_snapshot, effective_snapshot,
|
|
1695
|
+
decision, enforcement_status, enforcement_evidence_json, requirement_coverage,
|
|
1696
|
+
reason_code, execution_id, created_at)
|
|
1661
1697
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
1662
1698
|
.run(row.decision_id, row.kingdom_id, row.task_id, row.worker_binding_id ?? null, row.supervisor_binding_id ?? null, row.requirement_snapshot ?? null, row.ceiling_snapshot ?? null, row.proposed_grant_snapshot ?? null, row.scope_snapshot ?? null, row.effective_snapshot ?? null, row.decision, row.enforcement_status, row.enforcement_evidence_json ?? null, row.requirement_coverage ?? 'NONE', row.reason_code ?? null, row.execution_id ?? null, row.created_at);
|
|
1663
1699
|
return row;
|
|
@@ -1679,12 +1715,12 @@ BEGIN SELECT RAISE(ABORT, 'DISPATCH_NO_DELETE'); END;
|
|
|
1679
1715
|
// dispatch_records ────────────────────────────────────────────
|
|
1680
1716
|
insertDispatchIntent(row) {
|
|
1681
1717
|
this.db
|
|
1682
|
-
.prepare(`INSERT INTO dispatch_records
|
|
1683
|
-
(dispatch_id, kingdom_id, lease_id, execution_id, task_id, attempt_no,
|
|
1684
|
-
runtime_type, runtime_instance_ref, session_ref, state,
|
|
1685
|
-
dispatch_request_snapshot, dispatch_input_ref_json, dispatch_payload_hash,
|
|
1686
|
-
runtime_dispatch_ref, runtime_execution_ref, receipt_json, terminal_evidence_json,
|
|
1687
|
-
output_ref_json, dispatched_at, receipt_at, terminal_at, created_at, updated_at)
|
|
1718
|
+
.prepare(`INSERT INTO dispatch_records
|
|
1719
|
+
(dispatch_id, kingdom_id, lease_id, execution_id, task_id, attempt_no,
|
|
1720
|
+
runtime_type, runtime_instance_ref, session_ref, state,
|
|
1721
|
+
dispatch_request_snapshot, dispatch_input_ref_json, dispatch_payload_hash,
|
|
1722
|
+
runtime_dispatch_ref, runtime_execution_ref, receipt_json, terminal_evidence_json,
|
|
1723
|
+
output_ref_json, dispatched_at, receipt_at, terminal_at, created_at, updated_at)
|
|
1688
1724
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
1689
1725
|
.run(row.dispatch_id, row.kingdom_id, row.lease_id, row.execution_id, row.task_id, row.attempt_no, row.runtime_type, row.runtime_instance_ref, row.session_ref, row.state, row.dispatch_request_snapshot, row.dispatch_input_ref_json, row.dispatch_payload_hash, row.runtime_dispatch_ref ?? null, row.runtime_execution_ref ?? null, row.receipt_json ?? null, row.terminal_evidence_json ?? null, row.output_ref_json ?? null, row.dispatched_at ?? null, row.receipt_at ?? null, row.terminal_at ?? null, row.created_at, row.updated_at);
|
|
1690
1726
|
return row;
|