@xioflow/kernel 0.1.4 → 0.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.
Files changed (39) hide show
  1. package/README.md +27 -8
  2. package/dist/domain.d.ts +40 -6
  3. package/dist/domain.d.ts.map +1 -1
  4. package/dist/domain.js +388 -24
  5. package/dist/domain.js.map +1 -1
  6. package/dist/driver/node-driver.d.ts +11 -9
  7. package/dist/driver/node-driver.d.ts.map +1 -1
  8. package/dist/driver/node-driver.js +224 -225
  9. package/dist/driver/node-driver.js.map +1 -1
  10. package/dist/driver/process-facts.d.ts +25 -0
  11. package/dist/driver/process-facts.d.ts.map +1 -0
  12. package/dist/driver/process-facts.js +164 -0
  13. package/dist/driver/process-facts.js.map +1 -0
  14. package/dist/driver/sampler.d.ts +51 -0
  15. package/dist/driver/sampler.d.ts.map +1 -0
  16. package/dist/driver/sampler.js +224 -0
  17. package/dist/driver/sampler.js.map +1 -0
  18. package/dist/driver/types.d.ts +29 -1
  19. package/dist/driver/types.d.ts.map +1 -1
  20. package/dist/recovery/engine.d.ts +2 -0
  21. package/dist/recovery/engine.d.ts.map +1 -1
  22. package/dist/recovery/engine.js +137 -14
  23. package/dist/recovery/engine.js.map +1 -1
  24. package/dist/store/sqlite.d.ts +12 -0
  25. package/dist/store/sqlite.d.ts.map +1 -1
  26. package/dist/store/sqlite.js +162 -12
  27. package/dist/store/sqlite.js.map +1 -1
  28. package/dist/supervisor/supervisor.d.ts +15 -0
  29. package/dist/supervisor/supervisor.d.ts.map +1 -1
  30. package/dist/supervisor/supervisor.js +619 -214
  31. package/dist/supervisor/supervisor.js.map +1 -1
  32. package/dist/testing/contract-suite.d.ts.map +1 -1
  33. package/dist/testing/contract-suite.js +301 -11
  34. package/dist/testing/contract-suite.js.map +1 -1
  35. package/dist/types.d.ts +37 -0
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/types.js +29 -0
  38. package/dist/types.js.map +1 -1
  39. package/package.json +2 -2
@@ -15,5 +15,7 @@ export declare class RecoveryEngine {
15
15
  * 恢复协议:对未终结操作现场核查并安全推进至终态或保留隔离
16
16
  */
17
17
  recover(): Promise<RecoveryReport>;
18
+ /** 进程组是否仍存在(僵尸也算存在;具体是否"能工作"由驱动的 terminateGroup 判定)。 */
19
+ private isGroupAlive;
18
20
  }
19
21
  //# sourceMappingURL=engine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/recovery/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGpD,MAAM,WAAW,cAAc;IAC7B,mBAAmB,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,mBAAmB,GAAG,uBAAuB,GAAG,aAAa,GAAG,wBAAwB,CAAC;QACjG,iBAAiB,EAAE,OAAO,CAAC;KAC5B,EAAE,CAAC;CACL;AAED,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFzB,YACmB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,cAAc,EACrC;IAEJ;;OAEG;IACU,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC,CAqH9C;CACF"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/recovery/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGpD,MAAM,WAAW,cAAc;IAC7B,mBAAmB,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,mBAAmB,GAAG,uBAAuB,GAAG,aAAa,GAAG,wBAAwB,CAAC;QACjG,iBAAiB,EAAE,OAAO,CAAC;KAC5B,EAAE,CAAC;CACL;AAED,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFzB,YACmB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,cAAc,EAGxC;IAED;;OAEG;IACU,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC,CAqO9C;IAED,wDAAwD;IACxD,OAAO,CAAC,YAAY;CAWrB"}
@@ -4,6 +4,7 @@ export class RecoveryEngine {
4
4
  constructor(domain, driver) {
5
5
  this.domain = domain;
6
6
  this.driver = driver;
7
+ this.domain.setDriver?.(driver);
7
8
  }
8
9
  /**
9
10
  * 恢复协议:对未终结操作现场核查并安全推进至终态或保留隔离
@@ -29,7 +30,7 @@ export class RecoveryEngine {
29
30
  completedAt: new Date().toISOString(),
30
31
  };
31
32
  store.recordOperationResult(op.id, failResult, true);
32
- this.domain.releaseResources(op.id, op.requiredResources);
33
+ this.domain.internalReleaseResources(op.id, op.requiredResources);
33
34
  report.recoveredOperations.push({
34
35
  opId: op.id,
35
36
  action: 'cleaned_unspawned',
@@ -38,26 +39,31 @@ export class RecoveryEngine {
38
39
  continue;
39
40
  }
40
41
  if (op.processIdentity) {
42
+ const spawnTimeMs = op.processIdentity.spawnTime
43
+ ? new Date(op.processIdentity.spawnTime).getTime()
44
+ : NaN;
45
+ const calcDurationMs = () => (!isNaN(spawnTimeMs) ? Math.max(0, Date.now() - spawnTimeMs) : 0);
41
46
  // 场景 2-5:存在进程身份,现场向驱动核实身份
42
47
  const verification = await this.driver.verifyIdentity(op.processIdentity);
43
48
  if (verification === 'is_original_process') {
44
49
  // 进程依然存活,发送停止确认流水线
45
50
  const stopResult = await this.driver.terminate(op.processIdentity, 2000);
46
- if (stopResult.stopped) {
51
+ if (stopResult.stopped === 'confirmed_stopped') {
47
52
  const cancelResult = {
48
53
  kind: 'process',
49
54
  status: 'cancelled',
50
55
  exitCode: null,
51
- signal: 'SIGKILL',
56
+ signal: null,
52
57
  stdout: '',
53
- stderr: 'Alive process safely terminated and recovered',
58
+ stderr: '',
59
+ evidence: 'unobserved',
54
60
  isTruncated: false,
55
61
  identityVerification: 'is_original_process',
56
- durationMs: 0,
62
+ durationMs: calcDurationMs(),
57
63
  completedAt: new Date().toISOString(),
58
64
  };
59
65
  store.recordOperationResult(op.id, cancelResult, true);
60
- this.domain.releaseResources(op.id, op.requiredResources);
66
+ this.domain.internalReleaseResources(op.id, op.requiredResources);
61
67
  report.recoveredOperations.push({
62
68
  opId: op.id,
63
69
  action: 'stopped_alive_process',
@@ -71,7 +77,7 @@ export class RecoveryEngine {
71
77
  status: 'indeterminate',
72
78
  reason: 'Alive process failed to stop during recovery',
73
79
  recoveryGuidance: 'Residual PID detected. Check system processes manually.',
74
- durationMs: 0,
80
+ durationMs: calcDurationMs(),
75
81
  completedAt: new Date().toISOString(),
76
82
  };
77
83
  store.recordOperationResult(op.id, indetResult, false);
@@ -83,21 +89,107 @@ export class RecoveryEngine {
83
89
  }
84
90
  }
85
91
  else if (verification === 'not_original_process') {
86
- // 进程已确定死亡,核定终态并结清资源
92
+ // 进程已确定死亡。但"leader 死了"不等于"组空了":被 SIGKILL 的 leader 会
93
+ // 变成僵尸,它 fork 出来的后代可能还在运行,而这些进程已经没有 owner。
94
+ // 先做 N2 证据核验(bootId + 成员启动时间),证据不足或异常时绝不盲目发信号,判 indeterminate 保留租约;
95
+ // 证据齐全时才按 pgid 定向清场;清不掉如实隔离。
96
+ const pgid = op.processIdentity.pgid;
97
+ let reapedOrphans = false;
98
+ if (pgid !== undefined && this.isGroupAlive(pgid)) {
99
+ // N2 检查项 1:bootId 跨宿主重启核验
100
+ if (op.processIdentity.bootId && this.driver.readBootId) {
101
+ const currentBootId = await this.driver.readBootId();
102
+ if (currentBootId && op.processIdentity.bootId !== currentBootId) {
103
+ // 宿主在崩溃后已发生重启,当前同号 pgid 属于重启后的全新无关进程组,严禁发送信号
104
+ const indetResult = {
105
+ kind: 'indeterminate',
106
+ status: 'indeterminate',
107
+ reason: `Host bootId changed (recorded: '${op.processIdentity.bootId}', current: '${currentBootId}'); process group ${pgid} belongs to a different boot session`,
108
+ recoveryGuidance: 'Host was rebooted after the crash. Do not terminate external process groups; manual inspection required.',
109
+ durationMs: calcDurationMs(),
110
+ completedAt: new Date().toISOString(),
111
+ };
112
+ store.recordOperationResult(op.id, indetResult, false);
113
+ report.recoveredOperations.push({
114
+ opId: op.id,
115
+ action: 'isolated_indeterminate',
116
+ resourcesReleased: false,
117
+ });
118
+ continue;
119
+ }
120
+ }
121
+ // N2 检查项 2:成员启动时间核验(防同一次 boot 下的 PGID 复用)
122
+ if (this.driver.getGroupEvidence) {
123
+ const members = await this.driver.getGroupEvidence(pgid);
124
+ if (members.length > 0) {
125
+ const opSpawnMs = Date.parse(op.processIdentity.spawnTime);
126
+ if (!isNaN(opSpawnMs)) {
127
+ let hasEarlierProcess = false;
128
+ for (const m of members) {
129
+ if (m.startTimeMs !== null && m.startTimeMs < opSpawnMs - 1000) {
130
+ hasEarlierProcess = true;
131
+ break;
132
+ }
133
+ }
134
+ if (hasEarlierProcess) {
135
+ // 组成员启动时间早于该 op 启动时间,说明当前 pgid 属于外部更早创建的无关进程组
136
+ const indetResult = {
137
+ kind: 'indeterminate',
138
+ status: 'indeterminate',
139
+ reason: `Process group ${pgid} membership start time is earlier than operation spawn time; suspected PGID reuse`,
140
+ recoveryGuidance: 'External process group occupies the recorded PGID. Do not terminate; verify process ownership manually.',
141
+ durationMs: calcDurationMs(),
142
+ completedAt: new Date().toISOString(),
143
+ };
144
+ store.recordOperationResult(op.id, indetResult, false);
145
+ report.recoveredOperations.push({
146
+ opId: op.id,
147
+ action: 'isolated_indeterminate',
148
+ resourcesReleased: false,
149
+ });
150
+ continue;
151
+ }
152
+ }
153
+ }
154
+ }
155
+ const reaped = this.driver.terminateGroup
156
+ ? await this.driver.terminateGroup(pgid, 2000)
157
+ : { stopped: 'not_stopped', scope: 'unknown' };
158
+ if (reaped.stopped !== 'confirmed_stopped') {
159
+ const indetResult = {
160
+ kind: 'indeterminate',
161
+ status: 'indeterminate',
162
+ reason: 'Owner is dead but its process group could not be confirmed stopped',
163
+ recoveryGuidance: 'Residual processes from the crashed owner are still alive; inspect them before retrying.',
164
+ durationMs: calcDurationMs(),
165
+ completedAt: new Date().toISOString(),
166
+ };
167
+ store.recordOperationResult(op.id, indetResult, false);
168
+ report.recoveredOperations.push({
169
+ opId: op.id,
170
+ action: 'isolated_indeterminate',
171
+ resourcesReleased: false,
172
+ });
173
+ continue;
174
+ }
175
+ reapedOrphans = true;
176
+ }
87
177
  const deadResult = {
88
178
  kind: 'process',
89
179
  status: 'failed',
90
- exitCode: 137,
91
- signal: 'SIGKILL',
180
+ exitCode: null,
181
+ signal: null,
92
182
  stdout: '',
93
- stderr: 'Process terminated due to system crash',
183
+ stderr: reapedOrphans ? 'orphaned descendants were reaped during recovery' : '',
184
+ evidence: 'unobserved',
185
+ residualProcessesReaped: reapedOrphans,
94
186
  isTruncated: false,
95
187
  identityVerification: 'not_original_process',
96
- durationMs: 0,
188
+ durationMs: calcDurationMs(),
97
189
  completedAt: new Date().toISOString(),
98
190
  };
99
191
  store.recordOperationResult(op.id, deadResult, true);
100
- this.domain.releaseResources(op.id, op.requiredResources);
192
+ this.domain.internalReleaseResources(op.id, op.requiredResources);
101
193
  report.recoveredOperations.push({
102
194
  opId: op.id,
103
195
  action: 'marked_dead',
@@ -111,7 +203,7 @@ export class RecoveryEngine {
111
203
  status: 'indeterminate',
112
204
  reason: 'Cannot determine process identity after restart',
113
205
  recoveryGuidance: 'Manual inspection required. Resource isolation remains active.',
114
- durationMs: 0,
206
+ durationMs: calcDurationMs(),
115
207
  completedAt: new Date().toISOString(),
116
208
  };
117
209
  store.recordOperationResult(op.id, indetResult, false);
@@ -123,7 +215,38 @@ export class RecoveryEngine {
123
215
  }
124
216
  }
125
217
  }
218
+ // 5. [Run 状态收敛] (ARCHITECTURE §3.2 第 5 步)
219
+ // 本轮裁决后,所属 Run 若已无未终结操作:
220
+ // 存在 indeterminate ⇒ Run 置 indeterminate;
221
+ // 否则置 failed(terminationReason = crash_detected)。禁止让 Run 永久停留在 running
222
+ const activeRuns = store.getActiveRuns(this.domain.domainId);
223
+ for (const run of activeRuns) {
224
+ const runOps = store.getOperationsByRun(run.id);
225
+ const hasUnfinished = runOps.some((o) => o.status !== 'done');
226
+ if (!hasUnfinished) {
227
+ const hasIndeterminate = runOps.some((o) => o.result?.status === 'indeterminate');
228
+ if (hasIndeterminate) {
229
+ store.updateRunStatus(run.id, 'indeterminate', undefined, new Date().toISOString());
230
+ }
231
+ else {
232
+ store.updateRunStatus(run.id, 'failed', 'crash_detected', new Date().toISOString());
233
+ }
234
+ }
235
+ }
126
236
  return report;
127
237
  }
238
+ /** 进程组是否仍存在(僵尸也算存在;具体是否"能工作"由驱动的 terminateGroup 判定)。 */
239
+ isGroupAlive(pgid) {
240
+ if (typeof this.driver.isGroupAlive === 'function') {
241
+ return this.driver.isGroupAlive(pgid);
242
+ }
243
+ try {
244
+ process.kill(-pgid, 0);
245
+ return true;
246
+ }
247
+ catch (err) {
248
+ return err?.code === 'EPERM';
249
+ }
250
+ }
128
251
  }
129
252
  //# sourceMappingURL=engine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/recovery/engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/recovery/engine.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,10 @@ export declare class SqliteStore {
7
7
  private initSchema;
8
8
  private inTransaction;
9
9
  transaction<T>(fn: () => T): T;
10
+ /**
11
+ * 触发代际栅栏,永久阻断后续所有写操作 (P0-11)
12
+ */
13
+ fence(): void;
10
14
  /**
11
15
  * @internal 仅供测试套件模拟跨代/代际穿透场景,严禁在生产运行时直接调用
12
16
  */
@@ -30,8 +34,12 @@ export declare class SqliteStore {
30
34
  */
31
35
  reportRunSucceeded(runId: string): void;
32
36
  reportRunFailed(runId: string, reason?: TerminationReason): void;
37
+ reportRunCancelled(runId: string, reason?: TerminationReason): void;
38
+ getActiveRuns(domainId: string): Run[];
33
39
  registerOperationIntent(op: Operation, domainId: string): void;
40
+ recordPreIntentCancelledOperation(op: Operation, domainId: string, result: OperationResult): void;
34
41
  updateOperationStatus(opId: string, status: OperationStatus, processIdentity?: Operation['processIdentity'], outputRef?: string): void;
42
+ updateOperationResult(opId: string, result: OperationResult): void;
35
43
  recordOperationResult(opId: string, result: OperationResult, releaseResources?: boolean): void;
36
44
  getOperation(id: string): (Operation & {
37
45
  domainId: string;
@@ -42,12 +50,16 @@ export declare class SqliteStore {
42
50
  getUnfinishedOperations(domainId: string): (Operation & {
43
51
  domainId: string;
44
52
  })[];
53
+ getAllOperations(domainId: string): (Operation & {
54
+ domainId: string;
55
+ })[];
45
56
  getPersistedResourceLeases(domainId: string): (ResourceLease & {
46
57
  budget?: ResourceBudget;
47
58
  })[];
48
59
  releaseResourceLease(operationId: string, resourceId?: string): void;
49
60
  recordEventAndTransitionState(event: Omit<JournalEvent, 'seq'>): number;
50
61
  getJournalEvents(domainId: string, fromSeq?: number): JournalEvent[];
62
+ getEventsByRun(runId: string): JournalEvent[];
51
63
  close(): void;
52
64
  }
53
65
  //# sourceMappingURL=sqlite.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/store/sqlite.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/store/sqlite.ts"],"names":[],"mappings":"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"}
@@ -38,6 +38,12 @@ export class SqliteStore {
38
38
  this.inTransaction = false;
39
39
  }
40
40
  }
41
+ /**
42
+ * 触发代际栅栏,永久阻断后续所有写操作 (P0-11)
43
+ */
44
+ fence() {
45
+ this.currentEpoch = -1;
46
+ }
41
47
  /**
42
48
  * @internal 仅供测试套件模拟跨代/代际穿透场景,严禁在生产运行时直接调用
43
49
  */
@@ -174,6 +180,12 @@ export class SqliteStore {
174
180
  }
175
181
  saveRun(run) {
176
182
  this.verifyEpochFencing(run.domainId);
183
+ const existing = this.getRun(run.id);
184
+ if (existing && (existing.status === 'succeeded' || existing.status === 'failed' || existing.status === 'cancelled' || existing.status === 'indeterminate')) {
185
+ if (existing.status !== run.status) {
186
+ throw new Error(`Cannot transition Run "${run.id}" from terminal status "${existing.status}" to "${run.status}".`);
187
+ }
188
+ }
177
189
  const sanitizedConfig = sanitizeConfigSnapshot(run.configSnapshotWhiteList);
178
190
  const stmt = this.db.prepare(`
179
191
  INSERT INTO runs (id, task_id, domain_id, owner, status, termination_reason, started_at, ended_at, config_snapshot)
@@ -208,6 +220,12 @@ export class SqliteStore {
208
220
  const run = this.getRun(runId);
209
221
  if (run) {
210
222
  this.verifyEpochFencing(run.domainId);
223
+ if (run.status === 'succeeded' || run.status === 'failed' || run.status === 'cancelled' || run.status === 'indeterminate') {
224
+ if (run.status === status) {
225
+ return;
226
+ }
227
+ throw new Error(`Cannot transition Run "${runId}" from terminal status "${run.status}" to "${status}".`);
228
+ }
211
229
  }
212
230
  const stmt = this.db.prepare(`
213
231
  UPDATE runs
@@ -235,6 +253,11 @@ export class SqliteStore {
235
253
  if (!run)
236
254
  throw new Error(`Run '${runId}' not found`);
237
255
  this.verifyEpochFencing(run.domainId);
256
+ if (run.status === 'succeeded')
257
+ return;
258
+ if (run.status === 'failed' || run.status === 'cancelled' || run.status === 'indeterminate') {
259
+ throw new Error(`Cannot report run '${runId}' succeeded: already finalized with status '${run.status}'`);
260
+ }
238
261
  const ops = this.getOperationsByRun(runId);
239
262
  const unfinished = ops.filter((op) => op.status !== 'done');
240
263
  if (unfinished.length > 0) {
@@ -242,7 +265,8 @@ export class SqliteStore {
242
265
  }
243
266
  const indeterminate = ops.filter((op) => op.result?.status === 'indeterminate');
244
267
  if (indeterminate.length > 0) {
245
- this.updateRunStatus(runId, 'indeterminate', 'crash_detected', new Date().toISOString());
268
+ const indetReason = indeterminate[0].result?.terminationReason || undefined;
269
+ this.updateRunStatus(runId, 'indeterminate', indetReason, new Date().toISOString());
246
270
  return;
247
271
  }
248
272
  this.updateRunStatus(runId, 'succeeded', 'completed', new Date().toISOString());
@@ -254,32 +278,68 @@ export class SqliteStore {
254
278
  if (!run)
255
279
  throw new Error(`Run '${runId}' not found`);
256
280
  this.verifyEpochFencing(run.domainId);
281
+ if (run.status === 'failed')
282
+ return;
283
+ if (run.status === 'succeeded' || run.status === 'cancelled' || run.status === 'indeterminate') {
284
+ throw new Error(`Cannot report run '${runId}' failed: already finalized with status '${run.status}'`);
285
+ }
257
286
  this.updateRunStatus(runId, 'failed', reason, new Date().toISOString());
258
287
  });
259
288
  }
289
+ reportRunCancelled(runId, reason = 'user_cancelled') {
290
+ this.transaction(() => {
291
+ const run = this.getRun(runId);
292
+ if (!run)
293
+ throw new Error(`Run '${runId}' not found`);
294
+ this.verifyEpochFencing(run.domainId);
295
+ if (run.status === 'succeeded' || run.status === 'failed' || run.status === 'cancelled' || run.status === 'indeterminate') {
296
+ throw new Error(`Cannot report run '${runId}' cancelled: already finalized with status '${run.status}'`);
297
+ }
298
+ this.updateRunStatus(runId, 'cancelled', reason, new Date().toISOString());
299
+ });
300
+ }
301
+ getActiveRuns(domainId) {
302
+ const stmt = this.db.prepare('SELECT * FROM runs WHERE domain_id = ? AND status = ?');
303
+ const rows = stmt.all(domainId, 'running');
304
+ return rows.map((row) => ({
305
+ id: row.id,
306
+ taskId: row.task_id,
307
+ domainId: row.domain_id,
308
+ owner: row.owner,
309
+ status: row.status,
310
+ terminationReason: row.termination_reason,
311
+ startedAt: row.started_at,
312
+ endedAt: row.ended_at || undefined,
313
+ configSnapshotWhiteList: row.config_snapshot ? JSON.parse(row.config_snapshot) : undefined,
314
+ }));
315
+ }
260
316
  registerOperationIntent(op, domainId) {
261
- // 边界校验:Operation 必须挂在已登记的 Run 上。这里提前抛出可执行的错误,
262
- // 而不是把 SQLite 的 FOREIGN KEY constraint failed 直接丢给调用方。
263
- if (!this.getRun(op.runId)) {
317
+ const run = this.getRun(op.runId);
318
+ if (!run) {
264
319
  throw new Error(`Run "${op.runId}" is not registered in domain "${domainId}". ` +
265
320
  'Register the task and run first (store.saveTask() + store.saveRun()), then execute operations for that run.');
266
321
  }
322
+ if (run.status === 'succeeded' || run.status === 'failed' || run.status === 'cancelled' || run.status === 'indeterminate') {
323
+ throw new Error(`Cannot register operation "${op.id}" for Run "${op.runId}" because the Run is already finalized with status "${run.status}".`);
324
+ }
267
325
  this.transaction(() => {
268
326
  this.verifyEpochFencing(domainId);
327
+ const now = new Date().toISOString();
269
328
  // 1. 写入 operation 记录,初始状态 intent_registered
270
329
  const opStmt = this.db.prepare(`
271
330
  INSERT INTO operations (id, run_id, domain_id, kind, name, input_fingerprint, status, required_resources, timeout_ms, resource_budget, output_ref, process_identity, result)
272
331
  VALUES (?, ?, ?, ?, ?, ?, 'intent_registered', ?, ?, ?, ?, ?, ?)
273
332
  `);
274
- opStmt.run(op.id, op.runId, domainId, op.kind, op.name, op.inputFingerprint, JSON.stringify(op.requiredResources), op.timeoutMs || null, op.resourceBudget ? JSON.stringify(op.resourceBudget) : null, op.outputRef || null, op.processIdentity ? JSON.stringify(op.processIdentity) : null, op.result ? JSON.stringify(op.result) : null);
333
+ opStmt.run(op.id, op.runId, domainId, op.kind, op.name, op.inputFingerprint, JSON.stringify(op.requiredResources || []), op.timeoutMs || null, op.resourceBudget ? JSON.stringify(op.resourceBudget) : null, op.outputRef || null, op.processIdentity ? JSON.stringify(op.processIdentity) : null, op.result ? JSON.stringify(op.result) : null);
275
334
  // 2. 写入 resource_leases 表记录排他资源占用
276
- const leaseStmt = this.db.prepare(`
277
- INSERT INTO resource_leases (resource_id, operation_id, domain_id, acquired_at, budget)
278
- VALUES (?, ?, ?, ?, ?)
279
- `);
280
- const now = new Date().toISOString();
281
- for (const res of op.requiredResources) {
282
- leaseStmt.run(res, op.id, domainId, now, op.resourceBudget ? JSON.stringify(op.resourceBudget) : null);
335
+ if (op.requiredResources && op.requiredResources.length > 0) {
336
+ const leaseStmt = this.db.prepare(`
337
+ INSERT INTO resource_leases (resource_id, operation_id, domain_id, acquired_at, budget)
338
+ VALUES (?, ?, ?, ?, ?)
339
+ `);
340
+ for (const res of op.requiredResources) {
341
+ leaseStmt.run(res, op.id, domainId, now, op.resourceBudget ? JSON.stringify(op.resourceBudget) : null);
342
+ }
283
343
  }
284
344
  // 3. 记录领域事件
285
345
  this.recordEventAndTransitionState({
@@ -298,6 +358,39 @@ export class SqliteStore {
298
358
  });
299
359
  });
300
360
  }
361
+ recordPreIntentCancelledOperation(op, domainId, result) {
362
+ const run = this.getRun(op.runId);
363
+ if (!run) {
364
+ throw new Error(`Run "${op.runId}" is not registered in domain "${domainId}". ` +
365
+ 'Register the task and run first (store.saveTask() + store.saveRun()), then execute operations for that run.');
366
+ }
367
+ if (run.status === 'succeeded' ||
368
+ run.status === 'failed' ||
369
+ run.status === 'cancelled' ||
370
+ run.status === 'indeterminate') {
371
+ throw new Error(`Cannot register operation "${op.id}" for Run "${op.runId}" because the Run is already finalized with status "${run.status}".`);
372
+ }
373
+ this.transaction(() => {
374
+ this.verifyEpochFencing(domainId);
375
+ const existing = this.getOperation(op.id);
376
+ if (existing) {
377
+ throw new Error(`Operation "${op.id}" already exists`);
378
+ }
379
+ const opStmt = this.db.prepare(`
380
+ INSERT INTO operations (id, run_id, domain_id, kind, name, input_fingerprint, status, required_resources, timeout_ms, resource_budget, output_ref, process_identity, result)
381
+ VALUES (?, ?, ?, ?, ?, ?, 'done', ?, ?, ?, ?, ?, ?)
382
+ `);
383
+ opStmt.run(op.id, op.runId, domainId, op.kind, op.name, op.inputFingerprint, JSON.stringify(op.requiredResources || []), op.timeoutMs || null, op.resourceBudget ? JSON.stringify(op.resourceBudget) : null, op.outputRef || null, op.processIdentity ? JSON.stringify(op.processIdentity) : null, JSON.stringify(result));
384
+ this.recordEventAndTransitionState({
385
+ domainId,
386
+ runId: op.runId,
387
+ operationId: op.id,
388
+ type: 'OPERATION_RESULT_RECORDED',
389
+ payload: { result, releaseResources: false },
390
+ timestamp: result.completedAt || new Date().toISOString(),
391
+ });
392
+ });
393
+ }
301
394
  updateOperationStatus(opId, status, processIdentity, outputRef) {
302
395
  this.transaction(() => {
303
396
  const op = this.getOperation(opId);
@@ -322,6 +415,20 @@ export class SqliteStore {
322
415
  }
323
416
  });
324
417
  }
418
+ updateOperationResult(opId, result) {
419
+ this.transaction(() => {
420
+ const op = this.getOperation(opId);
421
+ if (!op)
422
+ throw new Error(`Operation ${opId} not found`);
423
+ this.verifyEpochFencing(op.domainId);
424
+ const stmt = this.db.prepare(`
425
+ UPDATE operations
426
+ SET result = ?
427
+ WHERE id = ?
428
+ `);
429
+ stmt.run(JSON.stringify(result), opId);
430
+ });
431
+ }
325
432
  recordOperationResult(opId, result, releaseResources = true) {
326
433
  this.transaction(() => {
327
434
  const op = this.getOperation(opId);
@@ -329,6 +436,9 @@ export class SqliteStore {
329
436
  throw new Error(`Operation ${opId} not found`);
330
437
  }
331
438
  this.verifyEpochFencing(op.domainId);
439
+ if (op.status === 'done') {
440
+ throw new Error(`Cannot record result for operation "${opId}": operation is already finalized with status "done"`);
441
+ }
332
442
  const stmt = this.db.prepare(`
333
443
  UPDATE operations
334
444
  SET status = 'done', result = ?, output_ref = COALESCE(?, output_ref)
@@ -413,6 +523,28 @@ export class SqliteStore {
413
523
  result: row.result ? JSON.parse(row.result) : undefined,
414
524
  }));
415
525
  }
526
+ getAllOperations(domainId) {
527
+ const stmt = this.db.prepare(`
528
+ SELECT * FROM operations
529
+ WHERE domain_id = ?
530
+ `);
531
+ const rows = stmt.all(domainId);
532
+ return rows.map((row) => ({
533
+ id: row.id,
534
+ runId: row.run_id,
535
+ domainId: row.domain_id,
536
+ kind: row.kind,
537
+ name: row.name,
538
+ inputFingerprint: row.input_fingerprint,
539
+ requiredResources: JSON.parse(row.required_resources),
540
+ timeoutMs: row.timeout_ms || undefined,
541
+ resourceBudget: row.resource_budget ? JSON.parse(row.resource_budget) : undefined,
542
+ outputRef: row.output_ref || undefined,
543
+ status: row.status,
544
+ processIdentity: row.process_identity ? JSON.parse(row.process_identity) : undefined,
545
+ result: row.result ? JSON.parse(row.result) : undefined,
546
+ }));
547
+ }
416
548
  getPersistedResourceLeases(domainId) {
417
549
  const stmt = this.db.prepare('SELECT * FROM resource_leases WHERE domain_id = ?');
418
550
  const rows = stmt.all(domainId);
@@ -435,6 +567,7 @@ export class SqliteStore {
435
567
  }
436
568
  }
437
569
  recordEventAndTransitionState(event) {
570
+ this.verifyEpochFencing(event.domainId);
438
571
  const stmt = this.db.prepare(`
439
572
  INSERT INTO journal_events (domain_id, run_id, operation_id, type, payload, timestamp)
440
573
  VALUES (?, ?, ?, ?, ?, ?)
@@ -459,6 +592,23 @@ export class SqliteStore {
459
592
  timestamp: row.timestamp,
460
593
  }));
461
594
  }
595
+ getEventsByRun(runId) {
596
+ const stmt = this.db.prepare(`
597
+ SELECT * FROM journal_events
598
+ WHERE run_id = ?
599
+ ORDER BY seq ASC
600
+ `);
601
+ const rows = stmt.all(runId);
602
+ return rows.map((row) => ({
603
+ seq: row.seq,
604
+ domainId: row.domain_id,
605
+ runId: row.run_id || undefined,
606
+ operationId: row.operation_id || undefined,
607
+ type: row.type,
608
+ payload: JSON.parse(row.payload),
609
+ timestamp: row.timestamp,
610
+ }));
611
+ }
462
612
  close() {
463
613
  this.db.close();
464
614
  }