@sema-agent/server 7.141.0 → 7.142.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/MIGRATION.md +215 -0
- package/USAGE.md +67 -12
- package/dist/approval-ask-audit-store.d.ts +54 -38
- package/dist/approval-ask-audit-store.js +58 -39
- package/dist/approval-card.d.ts +8 -8
- package/dist/approval-crash-convergence.d.ts +17 -7
- package/dist/approval-crash-convergence.js +94 -22
- package/dist/approval-deny-reasons.d.ts +34 -30
- package/dist/approval-deny-reasons.js +21 -6
- package/dist/approval-policy-settlement.d.ts +1 -1
- package/dist/approval-reconciler.d.ts +33 -1
- package/dist/approval-reconciler.js +43 -40
- package/dist/auth-bridge.d.ts +9 -6
- package/dist/auth-bridge.js +9 -3
- package/dist/boot/adoption.js +2 -1
- package/dist/boot/budget-tracing.d.ts +16 -0
- package/dist/boot/budget-tracing.js +10 -6
- package/dist/boot/device-lane.d.ts +1 -1
- package/dist/boot/execution-env.d.ts +24 -4
- package/dist/boot/execution-env.js +26 -23
- package/dist/boot/execution-lane.js +2 -1
- package/dist/boot/exit-boundary.js +5 -4
- package/dist/boot/memory-consolidation.js +2 -1
- package/dist/boot/parked-revive-gate.js +2 -1
- package/dist/boot/permission-rules-audit.d.ts +0 -28
- package/dist/boot/permission-rules-audit.js +2 -1
- package/dist/boot/read-deny-anchor-audit.js +2 -1
- package/dist/boot/reapers.js +4 -3
- package/dist/boot/resolve-spec.js +11 -2
- package/dist/boot/retention-lane.js +5 -3
- package/dist/boot/runner-deps.js +16 -13
- package/dist/boot/runtime-caps.js +3 -2
- package/dist/boot/session-faces.js +4 -3
- package/dist/boot/shutdown.js +3 -2
- package/dist/boot/stage-04-stores.js +3 -2
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.js +8 -6
- package/dist/boot/stage-06-runners.d.ts +1 -1
- package/dist/boot/stage-06-runners.js +2 -1
- package/dist/boot/stage-07-capability-layer.d.ts +1 -1
- package/dist/boot/stage-07-capability-layer.js +2 -1
- package/dist/boot/stage-08-reapers.d.ts +1 -1
- package/dist/boot/stage-08-reapers.js +3 -2
- package/dist/boot/stage-09-leader.d.ts +1 -1
- package/dist/boot/stage-10-http-server.d.ts +1 -1
- package/dist/boot/stage-10-http-server.js +5 -4
- package/dist/boot/stores.js +3 -2
- package/dist/boot/web-admin.js +17 -17
- package/dist/boot/webfetch-summarize-lane.js +2 -1
- package/dist/boot/workflow-orchestration.js +3 -2
- package/dist/capabilities/builtin-tools.d.ts +2 -1
- package/dist/capabilities/builtin-tools.js +2 -4
- package/dist/capabilities/composite-members.d.ts +2 -1
- package/dist/capabilities/composite-members.js +2 -1
- package/dist/capability-facts.d.ts +24 -0
- package/dist/capability-facts.js +23 -0
- package/dist/config-catalog.js +1 -0
- package/dist/config-types.d.ts +15 -4
- package/dist/config.d.ts +6 -0
- package/dist/config.js +17 -3
- package/dist/execution-lane-caps.d.ts +2 -1
- package/dist/fleet/fleet-bus.d.ts +6 -3
- package/dist/hooks/hook-runner.d.ts +6 -0
- package/dist/hooks/hook-runner.js +30 -1
- package/dist/http/dispatch.js +4 -2
- package/dist/http/execution-context.d.ts +2 -2
- package/dist/http/idempotency.d.ts +1 -1
- package/dist/http/principal-gate.d.ts +3 -1
- package/dist/http/principal-gate.js +17 -8
- package/dist/http/resume-legs.js +5 -9
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/attachments.js +18 -0
- package/dist/http/routes/capabilities.js +5 -2
- package/dist/http/routes/memory-policy.js +26 -6
- package/dist/http/routes/runs.js +3 -3
- package/dist/http/routes/session-memory-sync.d.ts +63 -0
- package/dist/http/routes/session-memory-sync.js +157 -0
- package/dist/http/routes/sessions-list.d.ts +2 -1
- package/dist/http/routes/tasks.js +7 -5
- package/dist/http/run-read-face.d.ts +7 -0
- package/dist/http/run-read-face.js +9 -3
- package/dist/http/send.d.ts +5 -0
- package/dist/http/send.js +9 -2
- package/dist/http/server.d.ts +14 -8
- package/dist/http/server.js +2 -4
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +2 -2
- package/dist/http/sync-submit-body.d.ts +21 -4
- package/dist/http/sync-submit-body.js +13 -0
- package/dist/identity-source.d.ts +21 -2
- package/dist/identity-source.js +6 -0
- package/dist/memory-incident-sink.d.ts +19 -6
- package/dist/memory-incident-sink.js +8 -4
- package/dist/memory-sync-client.d.ts +21 -21
- package/dist/memory-sync-client.js +50 -42
- package/dist/memory-sync-identity.d.ts +24 -0
- package/dist/memory-sync-identity.js +57 -0
- package/dist/memory-sync.d.ts +7 -1
- package/dist/memory-sync.js +6 -3
- package/dist/observability/fail-open.d.ts +27 -10
- package/dist/observability/fail-open.js +20 -7
- package/dist/observability/run-terminal.d.ts +92 -34
- package/dist/observability/run-terminal.js +167 -162
- package/dist/plugins/approval-ask-store-file.d.ts +14 -4
- package/dist/plugins/approval-ask-store-file.js +48 -7
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -1
- package/dist/plugins/approval-ask-store-memory.js +9 -8
- package/dist/plugins/approval-ask-store-sql.d.ts +42 -10
- package/dist/plugins/approval-ask-store-sql.js +49 -19
- package/dist/plugins/file-run-store.d.ts +6 -1
- package/dist/plugins/file-run-store.js +11 -1
- package/dist/plugins/local-session-store.d.ts +36 -7
- package/dist/plugins/local-session-store.js +76 -32
- package/dist/plugins/local-task-attachment-store.d.ts +12 -2
- package/dist/plugins/local-task-attachment-store.js +67 -43
- package/dist/plugins/memory-key-guards.d.ts +3 -3
- package/dist/plugins/memory-run-store.d.ts +6 -1
- package/dist/plugins/memory-run-store.js +11 -1
- package/dist/plugins/one-time-migrations.d.ts +27 -1
- package/dist/plugins/one-time-migrations.js +57 -3
- package/dist/plugins/remote-env-e2b.d.ts +23 -4
- package/dist/plugins/remote-env-e2b.js +111 -28
- package/dist/plugins/remote-env-k8s.d.ts +31 -5
- package/dist/plugins/remote-env-k8s.js +86 -19
- package/dist/plugins/remote-env-local-docker.d.ts +15 -3
- package/dist/plugins/remote-env-local-docker.js +40 -12
- package/dist/plugins/run-store-sql.d.ts +9 -1
- package/dist/plugins/run-store-sql.js +9 -1
- package/dist/plugins/store-backend.d.ts +10 -7
- package/dist/plugins/store-backend.js +1 -0
- package/dist/plugins/store-contracts.d.ts +26 -1
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/task-attachment-store.d.ts +112 -14
- package/dist/plugins/task-attachment-store.js +221 -28
- package/dist/plugins/workspace-fill.d.ts +60 -0
- package/dist/plugins/workspace-fill.js +106 -0
- package/dist/project-bundle.d.ts +38 -0
- package/dist/project-bundle.js +609 -0
- package/dist/run-local.js +2 -8
- package/dist/runs.js +1 -2
- package/dist/sandbox-egress-policy.d.ts +4 -1
- package/dist/sandbox-egress-policy.js +3 -1
- package/dist/sandbox-git-plane.d.ts +31 -12
- package/dist/sandbox-git-plane.js +24 -4
- package/dist/security.d.ts +9 -0
- package/dist/security.js +8 -0
- package/dist/session-error-wire.d.ts +24 -0
- package/dist/session-error-wire.js +7 -0
- package/dist/task-settings.d.ts +10 -2
- package/dist/task-settings.js +15 -2
- package/dist/terminal.d.ts +39 -19
- package/dist/terminal.js +65 -22
- package/dist/tool-approval.d.ts +4 -3
- package/dist/tool-approval.js +12 -14
- package/dist/trace/core-keyset-guard.d.ts +123 -6
- package/dist/trace/engine-notice-wire.d.ts +8 -2
- package/dist/trace/engine-notice-wire.js +4 -2
- package/dist/trace/exit-seat.d.ts +2 -1
- package/dist/trace/ledger-sink.d.ts +8 -4
- package/dist/trace/ledger-sink.js +2 -2
- package/dist/trace/project.d.ts +18 -1
- package/dist/trace/project.js +16 -0
- package/dist/trace/self-minted-wire.d.ts +251 -2
- package/dist/trace/self-minted-wire.js +82 -0
- package/dist/trace/wire-projection-faces.d.ts +1 -1
- package/dist/trace/wire-projection-faces.js +1 -1
- package/dist/web-admin-client/apply-effective.js +21 -1
- package/dist/web-admin-client/effective-keys.js +2 -0
- package/dist/web-admin-client/types.d.ts +4 -0
- package/package.json +1 -1
- package/wire-changes/server@7.142.0.json +639 -0
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
* 当时:local 车道 ask 账进程内易失(`InMemoryApprovalAskStore`),活卡窗内崩溃 = **零痕迹**:重启后
|
|
10
10
|
* `/v1/approvals` 两数组空,那次审批连一条审计行都没有。**[ref] 起 local 的 ask 账已是持久的**
|
|
11
11
|
* (`FileApprovalAskStore`),所以「零痕迹」那句不再成立;本店今天还在的理由收窄成它**独有**的那一格:
|
|
12
|
-
* `crashConverged` 这个 local-only 的 additive 读面(孤儿行的 `orphanState` / `resumeSafe` 两位)——
|
|
13
|
-
* (`legTracked` / `leg_closed` /
|
|
12
|
+
* `crashConverged` 这个 local-only 的 additive 读面(孤儿行的 `orphanState` / `resumeSafe` 两位)—— **腿证据与有序关停的进程事实只在这里**
|
|
13
|
+
* (`legTracked` / `leg_closed` / 进程级关停记录),ask 账没有。🔴 **「这一问还能不能决」不归本店答**:答案源是 ask 账的行状态
|
|
14
14
|
* (决断口只读它)。启动收敛是**一只**函数(`approval-crash-convergence.ts`):先跑本店的收敛(下面「boot 收敛判据」),再把 ask 账里
|
|
15
|
-
* 前世留下的 `STREAM_PENDING` 行收成 `VOID
|
|
16
|
-
*
|
|
15
|
+
* 前世留下的 `STREAM_PENDING` 行、以及本店判为孤儿的 `PARKING` 行收成 `VOID`,判定与成因词取本店对同一 `approvalId` 的
|
|
16
|
+
* {@link FileApprovalAskAuditStore.holderGoneVerdict} —— 成因判一次、写两处(ask 行 `ending_cause` 与本店收敛行 `cause` 同词)。并账(把腿证据搬上 ask 行、本店退役)不是本形:本店在
|
|
17
17
|
* 协议不上场的 local 部署上也在,那里没有 ask 行可并。本店把 ask **铸造 / 决议 / 腿闭**三类事件
|
|
18
18
|
* append 进磁盘账本(挂线点 = `ToolApprovalCoordinator`,见 `askAudit` ctor opt),boot 时收敛器把
|
|
19
19
|
* 孤儿行标 `crashed_before_park` 终态成因注,`GET /v1/approvals` 的 additive 键 `crashConverged` 供
|
|
@@ -44,10 +44,12 @@
|
|
|
44
44
|
* `leg_closed` 腿闭点(`runWithContext` finally;只为铸过审计行的 taskId 落,防账本膨胀):
|
|
45
45
|
* 「决议之后腿有没有闭」是 decided 臂唯一的机械证据面 —— 没有它,「批完跑完」与
|
|
46
46
|
* 「批了、执行窗内崩」在账本字节上同形,收敛器只能二选一地撒谎。
|
|
47
|
-
* `interrupted_by_shutdown`
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
47
|
+
* `interrupted_by_shutdown` **有序关停记录**([ref] 引入;[ref] 起是**进程**的事实):`{kind, atMs}`,每一世至多一行 —— 审批收尾等待结束的那一拍
|
|
48
|
+
* (`drainForShutdown`:未决卡全部结清,或关停宽限窗到期),条件 = 本世铸过至少一张卡(零卡的一世不铸账本文件)。
|
|
49
|
+
* 「这一世走完了有序收尾」—— 此刻还没结清的卡是被**有序关停**截断的,不是进程崩了。它**不是** `leg_closed`(腿没闭:工具可能正执行到一半),
|
|
50
|
+
* 所以不改变收敛判据,只改变收敛行的 `cause`(`"shutdown_before_park"` 而不是 `"crashed_before_park"`)—— `resumeSafe:false`
|
|
51
|
+
* 那句「确认上次操作再续跑」的提醒不许因为关停是有序的就丢掉。≤7.141.x 写的同名记录带 `taskId`(按腿、同一拍落):照读,`taskId` 不读 ——
|
|
52
|
+
* 旧写点就在同一拍,每一条旧记号都是「这一世走完了有序收尾」的真实例(零迁移、零读臂)。
|
|
51
53
|
* `crash_converged` 收敛记录(boot 收敛器落,幂等锚):orphanState 两值分臂。
|
|
52
54
|
* `late_settle` **迟到人工结算点**([ref];两条 HTTP decide 腿在**权威受理之后**落,受理谓词 =
|
|
53
55
|
* `HTTP 200 ∧ errorCode ≠ "cancelled"`,[ref] 件②起 —— 见下):
|
|
@@ -94,18 +96,20 @@
|
|
|
94
96
|
* **decided 臂**:批了、执行窗内崩,工具可能有半截副作用 ⇒ `resumeSafe:false`(留人工确认)。
|
|
95
97
|
* 判据方向刻意**保守**:腿闭是「本进程对该腿的守护结束」,晚于工具真完成 —— 误差方向是「把可能
|
|
96
98
|
* 干净的批注成待人工确认」,绝不反向。
|
|
97
|
-
* - **腿证据只对被追踪行作数**([ref],[ref]):`leg_closed`
|
|
98
|
-
* 委派 / 后台子代 ask 行的 taskId 是宿主 run,宿主腿的记录不证明子代那次调用的任何事(
|
|
99
|
+
* - **腿证据只对被追踪行作数**([ref],[ref];[ref] 收窄射程):`leg_closed` 只按 taskId 落,只对 `ask.legTracked` 的行作证据 ——
|
|
100
|
+
* 委派 / 后台子代 ask 行的 taskId 是宿主 run,宿主腿的记录不证明子代那次调用的任何事(腿闭反证门 / decided 臂 / `resumeSafe` 都经这一口读)。
|
|
101
|
+
* 有序关停**不是**腿证据:它是进程的事实,对这一世的全部卡作数(见下「收敛行的 `cause`」)。
|
|
99
102
|
* - **腿闭反证门**(codex R1-F1 部分采):有 `ask`(被追踪)、无 `settle`、却有本 taskId 的后继 `leg_closed` ⇒
|
|
100
103
|
* 这不是崩溃孤儿(settle 恒先于 ask() 返回、腿闭恒在其后),只能是「settle 行写丢在一条跑完了的
|
|
101
104
|
* 腿上」的审计断档组 —— **不收敛**(标 pending = 把可能已执行的批注成 resumeSafe:true,方向反;
|
|
102
105
|
* 标 decided = 凭空断言人批了),`inconsistent` 计数进 boot 日志。
|
|
103
|
-
* - **收敛行的 `cause`**([ref]
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
+
* - **收敛行的 `cause`**([ref];[ref] 起一处判、不看腿,{@link holderGoneCauseOf}):该组最后一个事件行(settle 行,缺席则 ask 行)之后、它的收敛行(重投影时)
|
|
107
|
+
* 之前,有一行 `interrupted_by_shutdown` 记录 ⇒ `"shutdown_before_park"`(这一世走完了有序收尾,这张卡是被它截断的);否则 `"crashed_before_park"`。
|
|
108
|
+
* 上界保证后几世的关停不改写前世已收敛组的词(起服收敛排在本进程铸出第一问之前,前世的孤儿组在下一世任何记录之前就已收敛)。
|
|
109
|
+
* 记录**只改成因注,不改收敛判据**:有序关停下已批而腿未闭,工具照样可能半截副作用(decided 臂 `resumeSafe:false` 照留)。
|
|
106
110
|
* 有序关停下的**未决**活卡由 `drainForShutdown` 先落 settle(`cause:"shutdown_before_park"`)⇒ 不再是 pending 孤儿(本就不收敛);
|
|
107
111
|
* park 路由的卡须等**观察到 core 已处置这次调用**(停车行提交 / 承载它的腿退场)才落(F1)—— 宽限窗满仍两者皆无 ⇒ 无 settle 行 ⇒ 照样按 pending 孤儿收敛(有序关停中未提交的 park
|
|
108
|
-
*
|
|
112
|
+
* 与崩溃同路,证据不丢;成因 `shutdown_before_park`,被追踪腿与零活流 / 子代腿同一个词 —— 收尾等待走完是进程的事实)。
|
|
109
113
|
* - 其余(denied / expired / park 路由 / 已收敛)⇒ 不收敛。三条成文残留(fail-safe 方向,宁漏不误):
|
|
110
114
|
* ① `legTracked:false` 的 decided 行拿不到腿闭信号 ⇒ decided 臂对它不收(pending 臂不受此限 —— 但也因此没有腿闭反证门护着:
|
|
111
115
|
* 子代卡照列 pending 孤儿但 `resumeSafe:false` —— 没有腿证据就不作「零执行」正断言([ref] ⑧,车 SO codex r2 [high];修前 true = 方向反))。
|
|
@@ -143,7 +147,7 @@
|
|
|
143
147
|
* 本身,不是静默降级。本店的静默降级臂有两条:① 运行期 append 失败(审批可用性不押在审计盘上),已按
|
|
144
148
|
* [ref] 律走 `recordFailOpen("server.approval-ask-audit.append-failed")`(census 第 53 行);② boot 重放跳过中间坏行
|
|
145
149
|
* ([ref] 起由重放属主逐条披露 + `server.approval-ask-audit.corrupt-record-skipped`,census 第 106 行;此前只计 `corruptLines`)。
|
|
146
|
-
* boot 期(mkdir
|
|
150
|
+
* boot 期(mkdir/重放的读错;起服收敛写收敛行,[ref] 起 —— 见 {@link FileApprovalAskAuditStore.convergeCrashedAsks})失败则**拒启**(与 File 店族同律:`FileStorageBackend` ctor 同 root 同姿态)——
|
|
147
151
|
* 一台「审计写不进却继续批」的机器 = [ref] 换个皮回来。
|
|
148
152
|
*
|
|
149
153
|
* ## 追加 / 重放口([ref]:一只追加日志实现,不留两份)
|
|
@@ -169,7 +173,8 @@
|
|
|
169
173
|
* 只在真出卡时写(人批一次 = 3 行),量级 = 人的手速。保留 = 审批账本的留存律(律一处成文在 `approval-ask-retention.ts`;维护 tick 按
|
|
170
174
|
* `APPROVAL_ASK_RETENTION_MS` 调 {@link FileApprovalAskAuditStore.rotateOlderThan}):**整问**删 —— 一问不再欠下一次起服收敛一个答案
|
|
171
175
|
* (下面的收敛判官此刻不会把它收成孤儿)且它所有记录里最晚的时刻早于 cutoff,它的全部行(铸造 / 决议 / 收敛 / 迟到结算)一起离开文件;
|
|
172
|
-
*
|
|
176
|
+
* 腿闭记录(按 taskId)只在没有任何留下的问还认它、且它自己也过窗时才删;有序关停记录(进程级)只在它自己过窗、且没有任何留下的问的末事件行在它之前时才删
|
|
177
|
+
* —— 于是留下的问的收敛投影(成因 / `resumeSafe`)一字不变;
|
|
173
178
|
* 认不出的行证不出到期,原样留;发起它的 run 还能动(跑着 / 停驻)的问也留。**只删不改**:留下的行逐字节写回(原子换文件,0o600),删了多少进读数行。
|
|
174
179
|
* 读面列表按收敛时刻新前旧后、上限 {@link CRASH_CONVERGED_LIST_MAX}(有界 wire)。
|
|
175
180
|
*/
|
|
@@ -222,7 +227,7 @@ export type AuditSettleInput = (AuditSettleBase & {
|
|
|
222
227
|
cause: SettleCause;
|
|
223
228
|
});
|
|
224
229
|
/** 收敛行 `cause` 的闭集(`GET /v1/approvals` `crashConverged[].cause`):崩溃孤儿 / 有序关停截断的腿([ref] +1;与 `crashed_before_park` 同形)。
|
|
225
|
-
* 🔴 **词表属主 = `approval-deny-reasons.ts` 的 {@link HolderGoneCause}**(本表两词的子集):启动收敛把同一问的问账行收成 VOID 时 `
|
|
230
|
+
* 🔴 **词表属主 = `approval-deny-reasons.ts` 的 {@link HolderGoneCause}**(本表两词的子集):启动收敛把同一问的问账行收成 VOID 时 `ending_cause` 写的就是这两个词 ——
|
|
226
231
|
* 同一问在 `crashConverged` 与决断口 410 体上只有一个成因词。wire 值闭集登记在 `trace/self-minted-wire.ts` 的 `crashConvergedCause`
|
|
227
232
|
* (`satisfies Record<HolderGoneCause, …>` 双向绑定 ⇒ 加词不登记 = tsc 红,wire 变更清单从那张表 diff —— F3)。 */
|
|
228
233
|
/**
|
|
@@ -265,9 +270,8 @@ export interface ApprovalAskAuditSink {
|
|
|
265
270
|
recordSettle(input: AuditSettleInput): void;
|
|
266
271
|
/** 腿闭点(`runWithContext` finally)。只为铸过审计行的 taskId 真落行(店内去重)。 */
|
|
267
272
|
noteLegClosed(taskId: string): void;
|
|
268
|
-
/** [ref]
|
|
269
|
-
|
|
270
|
-
noteLegsInterruptedByShutdown(): void;
|
|
273
|
+
/** 有序关停记录点([ref] 起进程级;`drainForShutdown` 收尾等待结束那一拍调):本世铸过卡 ⇒ 落一行 `interrupted_by_shutdown {atMs}`;再调幂等。 */
|
|
274
|
+
noteInterruptedByShutdown(): void;
|
|
271
275
|
/** [ref] 迟到人工结算点(HTTP decide 两腿)。**纯观察**:自吞一切失败,不返回受否,绝不改变结算面。 */
|
|
272
276
|
recordLateSettle(input: AuditLateSettleInput): void;
|
|
273
277
|
}
|
|
@@ -296,7 +300,7 @@ export interface CrashConvergedRow {
|
|
|
296
300
|
ts: number;
|
|
297
301
|
expiresAtMs: number;
|
|
298
302
|
/**
|
|
299
|
-
* 收敛行的判别常量:这张卡**已不可再决**(wire 形不变)。⚠️ 协议上场的部署上,同一问在 ask 账里是 `VOID` + `
|
|
303
|
+
* 收敛行的判别常量:这张卡**已不可再决**(wire 形不变)。⚠️ 协议上场的部署上,同一问在 ask 账里是 `VOID` + `ending_cause` = 本行 `cause`
|
|
300
304
|
* (决断口 410 `gone.ask` 读的是那一行)—— 「能不能决」两面一致,但终态的**名字**这里是 `denied`、ask 行是 `VOID`:这是登记在案的残留,
|
|
301
305
|
* 不是语义(改这个值会让把它当闭集判别式读的消费端整行丢弃,须与消费端同窗改)。
|
|
302
306
|
*/
|
|
@@ -339,14 +343,16 @@ export declare class FileApprovalAskAuditStore implements ApprovalAskAuditSink,
|
|
|
339
343
|
private readonly replayed;
|
|
340
344
|
/** 前世账本里的腿闭事件(taskId + 行序;decided 臂按「决议行之后」判)。 */
|
|
341
345
|
private readonly replayedLegClosed;
|
|
342
|
-
/**
|
|
343
|
-
private readonly
|
|
346
|
+
/** 前世账本里的进程级有序关停记录的行序(收敛行 `cause` 的判据,见 {@link holderGoneCauseOf})。 */
|
|
347
|
+
private readonly replayedShutdownLines;
|
|
344
348
|
/** 已收敛行(读面数据源;含前世已收敛 + 本次 boot 新收敛)。owner 只做 scope 门,不上 wire。 */
|
|
345
349
|
private readonly convergedRows;
|
|
346
350
|
/** 本进程铸过审计行、且腿闭信号可达的 taskId(腿闭去重 + 防无关腿刷账本)。 */
|
|
347
351
|
private readonly openLegTasks;
|
|
348
|
-
/**
|
|
349
|
-
private
|
|
352
|
+
/** 本世铸过卡(有序关停记录的落行条件:零卡的一世不铸账本文件)。 */
|
|
353
|
+
private mintedThisProcess;
|
|
354
|
+
/** 本世已落过有序关停记录(一世一行;再调幂等)。 */
|
|
355
|
+
private shutdownNoted;
|
|
350
356
|
private convergedOnce;
|
|
351
357
|
/**
|
|
352
358
|
* [ref] 反查索引 ①:**checkpoint 锚 → 铸造行身份**。与 {@link replayed} 刻意分家 —— 那张表是
|
|
@@ -390,6 +396,8 @@ export declare class FileApprovalAskAuditStore implements ApprovalAskAuditSink,
|
|
|
390
396
|
* {@link recordSettle})。没有这个返回值,索引会把一条**只在内存里**的 ask/park 事实当证据,
|
|
391
397
|
* 后来铸出的 `late_settle` 行在同一个账本文件里无法复核。 */
|
|
392
398
|
private append;
|
|
399
|
+
/** 写口本体(append + fsync),失败照抛。失败方向由调用方按阶段定、只有两处:运行期 {@link append}(响亮不阻断)· 起服收敛 {@link convergeCrashedAsks}(拒启)。 */
|
|
400
|
+
private appendOrThrow;
|
|
393
401
|
/** [ref] 锚键 A(精确):会话 + 工具调用 id。会话轴登记**两把** —— 见 {@link indexAsk}。 */
|
|
394
402
|
private static callAnchorKey;
|
|
395
403
|
/**
|
|
@@ -405,11 +413,11 @@ export declare class FileApprovalAskAuditStore implements ApprovalAskAuditSink,
|
|
|
405
413
|
recordAsk(input: AuditAskInput): void;
|
|
406
414
|
recordSettle(input: AuditSettleInput): void;
|
|
407
415
|
noteLegClosed(taskId: string): void;
|
|
408
|
-
/** [ref]
|
|
409
|
-
*
|
|
410
|
-
* (codex r1 F1 [high]
|
|
411
|
-
*
|
|
412
|
-
|
|
416
|
+
/** [ref]:这一世走完了有序收尾 ⇒ 落**一行**进程级 `interrupted_by_shutdown {atMs}`(收尾等待结束那一拍;本世没铸过卡就不落;再调幂等,位先置后写 ——
|
|
417
|
+
* 写失败走 append 的 F 类留痕,不重试)。腿追踪集 `openLegTasks` **不动**:进程在这一行之后仍可能活几秒(server / backend 收尾),期间真跑完的腿照常落
|
|
418
|
+
* `leg_closed`(codex r1 F1 [high]:吞掉这份真实证据会让「settle 写丢 + 腿跑完」的组被投影成 pending / `resumeSafe:true`)。迟到的腿闭落在这一行之后 ⇒
|
|
419
|
+
* 收敛判据照常认它(腿跑完了,不是孤儿)。 */
|
|
420
|
+
noteInterruptedByShutdown(): void;
|
|
413
421
|
/**
|
|
414
422
|
* [ref] **迟到人工结算点**(判据的唯一属主;两条 HTTP decide 腿只交锚,不自己推)。
|
|
415
423
|
*
|
|
@@ -436,6 +444,9 @@ export declare class FileApprovalAskAuditStore implements ApprovalAskAuditSink,
|
|
|
436
444
|
/**
|
|
437
445
|
* boot 崩溃收敛器的**本店半场**(由 `approval-crash-convergence.ts` 的启动收敛在任何卡开始之前调一次;幂等跨 boot)。
|
|
438
446
|
* 判据 = 头注「boot 收敛判据」段(一处成文,不复述)。返回两分臂计数 + 坏行数供 boot 日志。
|
|
447
|
+
* 🔴 收敛行写不进 ⇒ **抛**(调用方拒启;[ref] codex r1 F4):它不只是幂等锚,还是这一组成因判据的**上界**({@link holderGoneCauseOf})—— 写丢了,之后任何一世的
|
|
448
|
+
* 有序关停记录都落在这一组「末事件之后、无收敛行」的窗里,重投影就把它改写成 `shutdown_before_park`,而问账行早已按这一拍的词收了 `VOID`,两本账分家。
|
|
449
|
+
* 这是 boot 期写(头注「boot 期失败则拒启」同律),不是运行期的「审计不押审批」那一类;抛在问账半场之前 ⇒ 问账一字未动,盘修好再起照收、同一个词。
|
|
439
450
|
*/
|
|
440
451
|
convergeCrashedAsks(): {
|
|
441
452
|
pending: number;
|
|
@@ -444,14 +455,18 @@ export declare class FileApprovalAskAuditStore implements ApprovalAskAuditSink,
|
|
|
444
455
|
corruptLines: number;
|
|
445
456
|
};
|
|
446
457
|
/**
|
|
447
|
-
*
|
|
448
|
-
* {@link
|
|
449
|
-
*
|
|
458
|
+
* 一问的**持有者没了**判定(启动收敛的唯一判点,`approval-crash-convergence.ts` 读它决定收哪些问账行、写什么词;本店收敛行的 `cause` 走同一只
|
|
459
|
+
* {@link holderGoneCauseOf}):
|
|
460
|
+
* · `orphan` = 这一组是本店的崩溃收敛孤儿(`crashConverged` 列出的那些:前几次起服已收敛的,或此刻 {@link judgeOrphan} 判 pending / decided 的)——
|
|
461
|
+
* 问账里它的 `PARKING` 行由启动收敛收(审计断档组 `inconsistent` 不算:它没被收敛,不作「持有者没了」的断言);
|
|
462
|
+
* · `cause` = 成因词。前世账本里没有这只 `approvalId` 的铸造行(崩在 ask 账落行之后、本店铸造行之前,或本店那时不在)⇒ `{orphan:false, crashed_before_park}`:
|
|
463
|
+
* 没有有序关停的证据,就不说它是有序关停。
|
|
464
|
+
* 判据读的是构造时冻结的前世账本(纯函数,不依赖 {@link convergeCrashedAsks} 先跑没跑)⇒ 同一份账本跨几次启动恒得同一个判定、同一个词。
|
|
450
465
|
*/
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
466
|
+
holderGoneVerdict(approvalId: string): {
|
|
467
|
+
orphan: boolean;
|
|
468
|
+
cause: HolderGoneCause;
|
|
469
|
+
};
|
|
455
470
|
private projectRow;
|
|
456
471
|
/** scope 门与 `listLivePending` 逐字同律(同一只 checkpoint scope 解码):`undefined` = operator 全量(含 owner null 行);
|
|
457
472
|
* `_` = 匿名那一组 = owner null 的行;其余串 = 只见 `owner === scope` 的行(null-owner 行对具名主体不列,宁少列不超范围)。 */
|
|
@@ -464,7 +479,8 @@ export declare class FileApprovalAskAuditStore implements ApprovalAskAuditSink,
|
|
|
464
479
|
* 后台子代账列出)∧ {@link judgeOrphan} 此刻不欠它答案 —— 停驻 run / 能动子代的问(窗到期转 durable、迟到结算还要这组前置事实)、活卡
|
|
465
480
|
* (铸了没决)与批了腿没闭的问多老都留。删的单位是**整问**:
|
|
466
481
|
* · 一问的最后动静 = 它所有记录(铸造 / 决议 / 收敛 / 迟到结算)里最晚的时刻;早于 cutoff ∧ 不欠答案 ⇒ 这一问的全部行删;
|
|
467
|
-
* ·
|
|
482
|
+
* · 腿闭记录(按 taskId)只在它自己也早于 cutoff ∧ 没有任何留下的问是这个 taskId ∧ 这个 taskId 不在挂靠集时才删 —— 留下的问的 `resumeSafe` 读得到的腿证据一条不少;
|
|
483
|
+
* · 有序关停记录(进程级)只在它自己也早于 cutoff ∧ 没有任何留下的问的末事件行({@link lastEventLineOf})在它之前时才删 —— 留下的问的成因读得到的关停事实一条不少;
|
|
468
484
|
* · 身份说不清的迟到结算(`approvalId:null`)按它自己的时刻;认不出的行(腐行 / 词表外)证不出到期 ⇒ 原样留;
|
|
469
485
|
* 末尾没换行的那一段原样留在末尾(不补换行),由追加口下次打开时按 core 的同一只判词修(解析成对象补换行、撕尾截断)。
|
|
470
486
|
* 只删不改:留下的每一行按**原字节**写回(按换行字节切段,不经解码 —— 非 UTF-8 的字节一个不变),原子换文件({@link replaceFileBytes}:
|
|
@@ -5,7 +5,7 @@ import { AppendLog, ensureDir, isHostDecider, writeThenLink } from "@sema-agent/
|
|
|
5
5
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
6
6
|
import { ownerOfCheckpointScope } from "./security.js";
|
|
7
7
|
import { replayJsonlSkipping } from "./observability/corrupt-read-seat.js";
|
|
8
|
-
import { isSettleCause, SETTLE_OUTCOME } from "./approval-deny-reasons.js";
|
|
8
|
+
import { APPROVAL_ENDING_CAUSES, isSettleCause, SETTLE_OUTCOME } from "./approval-deny-reasons.js";
|
|
9
9
|
export const APPROVAL_ASK_AUDIT_DIR = "approval-ask-audit";
|
|
10
10
|
export const APPROVAL_ASK_AUDIT_LEDGER = "ledger.jsonl";
|
|
11
11
|
export const CRASH_CONVERGED_LIST_MAX = 200;
|
|
@@ -98,11 +98,10 @@ function readLedgerRecord(u, noteOutOfSetSeat) {
|
|
|
98
98
|
return { kind: "leg_closed", taskId, closedAtMs };
|
|
99
99
|
}
|
|
100
100
|
case "interrupted_by_shutdown": {
|
|
101
|
-
const taskId = s("taskId");
|
|
102
101
|
const atMs = num("atMs");
|
|
103
|
-
if (
|
|
102
|
+
if (atMs === undefined)
|
|
104
103
|
return undefined;
|
|
105
|
-
return { kind: "interrupted_by_shutdown",
|
|
104
|
+
return { kind: "interrupted_by_shutdown", atMs };
|
|
106
105
|
}
|
|
107
106
|
case "crash_converged": {
|
|
108
107
|
const approvalId = s("approvalId");
|
|
@@ -173,7 +172,7 @@ const LEDGER_SHAPE = {
|
|
|
173
172
|
function foldLedger(records) {
|
|
174
173
|
const groups = new Map();
|
|
175
174
|
const legClosed = [];
|
|
176
|
-
const
|
|
175
|
+
const shutdownLines = [];
|
|
177
176
|
const group = (approvalId, line) => {
|
|
178
177
|
let g = groups.get(approvalId);
|
|
179
178
|
if (!g) {
|
|
@@ -206,7 +205,7 @@ function foldLedger(records) {
|
|
|
206
205
|
legClosed.push({ taskId: rec.taskId, line });
|
|
207
206
|
break;
|
|
208
207
|
case "interrupted_by_shutdown":
|
|
209
|
-
|
|
208
|
+
shutdownLines.push(line);
|
|
210
209
|
break;
|
|
211
210
|
case "crash_converged": {
|
|
212
211
|
const g = group(rec.approvalId, line);
|
|
@@ -220,13 +219,21 @@ function foldLedger(records) {
|
|
|
220
219
|
}
|
|
221
220
|
}
|
|
222
221
|
}
|
|
223
|
-
return { groups, legClosed,
|
|
222
|
+
return { groups, legClosed, shutdownLines };
|
|
224
223
|
}
|
|
225
|
-
function legEvidenceOf(g,
|
|
224
|
+
function legEvidenceOf(g, legClosed, afterLine) {
|
|
226
225
|
const ask = g.ask;
|
|
227
226
|
if (!ask.legTracked)
|
|
228
227
|
return undefined;
|
|
229
|
-
return
|
|
228
|
+
return legClosed.some((r) => r.taskId === ask.taskId && r.line > afterLine);
|
|
229
|
+
}
|
|
230
|
+
function lastEventLineOf(g) {
|
|
231
|
+
return g.settleLine ?? g.askLine ?? g.firstLine;
|
|
232
|
+
}
|
|
233
|
+
function holderGoneCauseOf(g, shutdownLines) {
|
|
234
|
+
const after = lastEventLineOf(g);
|
|
235
|
+
const before = g.convergedLine ?? Number.POSITIVE_INFINITY;
|
|
236
|
+
return shutdownLines.some((l) => l > after && l < before) ? APPROVAL_ENDING_CAUSES.SHUTDOWN_BEFORE_PARK : APPROVAL_ENDING_CAUSES.CRASHED_BEFORE_PARK;
|
|
230
237
|
}
|
|
231
238
|
function judgeOrphan(g, legClosed) {
|
|
232
239
|
if (g.ask === undefined || g.converged !== undefined)
|
|
@@ -323,10 +330,11 @@ export class FileApprovalAskAuditStore {
|
|
|
323
330
|
fsyncDir;
|
|
324
331
|
replayed = new Map();
|
|
325
332
|
replayedLegClosed = [];
|
|
326
|
-
|
|
333
|
+
replayedShutdownLines = [];
|
|
327
334
|
convergedRows = [];
|
|
328
335
|
openLegTasks = new Set();
|
|
329
|
-
|
|
336
|
+
mintedThisProcess = false;
|
|
337
|
+
shutdownNoted = false;
|
|
330
338
|
convergedOnce = false;
|
|
331
339
|
askByCallAnchor = new Map();
|
|
332
340
|
askBySessionOnly = new Map();
|
|
@@ -349,8 +357,8 @@ export class FileApprovalAskAuditStore {
|
|
|
349
357
|
this.replayed.set(approvalId, g);
|
|
350
358
|
for (const r of fold.legClosed)
|
|
351
359
|
this.replayedLegClosed.push(r);
|
|
352
|
-
for (const
|
|
353
|
-
this.
|
|
360
|
+
for (const l of fold.shutdownLines)
|
|
361
|
+
this.replayedShutdownLines.push(l);
|
|
354
362
|
for (const { rec } of records) {
|
|
355
363
|
if (rec.kind === "ask")
|
|
356
364
|
this.indexAsk(rec);
|
|
@@ -360,8 +368,7 @@ export class FileApprovalAskAuditStore {
|
|
|
360
368
|
}
|
|
361
369
|
append(rec) {
|
|
362
370
|
try {
|
|
363
|
-
this.
|
|
364
|
-
this.log.append(rec, true);
|
|
371
|
+
this.appendOrThrow(rec);
|
|
365
372
|
return true;
|
|
366
373
|
}
|
|
367
374
|
catch (err) {
|
|
@@ -369,6 +376,10 @@ export class FileApprovalAskAuditStore {
|
|
|
369
376
|
return false;
|
|
370
377
|
}
|
|
371
378
|
}
|
|
379
|
+
appendOrThrow(rec) {
|
|
380
|
+
this.log ??= this.openLog(this.ledgerPath);
|
|
381
|
+
this.log.append(rec, true);
|
|
382
|
+
}
|
|
372
383
|
static callAnchorKey(session, toolCallId) {
|
|
373
384
|
return `${session}\u0000${toolCallId}`;
|
|
374
385
|
}
|
|
@@ -395,6 +406,7 @@ export class FileApprovalAskAuditStore {
|
|
|
395
406
|
this.parkExpired.add(rec.approvalId);
|
|
396
407
|
}
|
|
397
408
|
recordAsk(input) {
|
|
409
|
+
this.mintedThisProcess = true;
|
|
398
410
|
if (input.legTracked)
|
|
399
411
|
this.openLegTasks.add(input.taskId);
|
|
400
412
|
if (this.append({ kind: "ask", ...input }))
|
|
@@ -410,14 +422,11 @@ export class FileApprovalAskAuditStore {
|
|
|
410
422
|
this.openLegTasks.delete(taskId);
|
|
411
423
|
this.append({ kind: "leg_closed", taskId, closedAtMs: Date.now() });
|
|
412
424
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
this.shutdownMarkedLegs.add(taskId);
|
|
419
|
-
this.append({ kind: "interrupted_by_shutdown", taskId, atMs });
|
|
420
|
-
}
|
|
425
|
+
noteInterruptedByShutdown() {
|
|
426
|
+
if (!this.mintedThisProcess || this.shutdownNoted)
|
|
427
|
+
return;
|
|
428
|
+
this.shutdownNoted = true;
|
|
429
|
+
this.append({ kind: "interrupted_by_shutdown", atMs: Date.now() });
|
|
421
430
|
}
|
|
422
431
|
recordLateSettle(input) {
|
|
423
432
|
const candidates = input.toolCallId !== undefined
|
|
@@ -454,7 +463,7 @@ export class FileApprovalAskAuditStore {
|
|
|
454
463
|
if (g.ask === undefined)
|
|
455
464
|
continue;
|
|
456
465
|
if (g.converged !== undefined) {
|
|
457
|
-
this.convergedRows.push({ row: this.projectRow(g, g.converged.orphanState, g.converged.convergedAtMs, this.
|
|
466
|
+
this.convergedRows.push({ row: this.projectRow(g, g.converged.orphanState, g.converged.convergedAtMs, holderGoneCauseOf(g, this.replayedShutdownLines)), owner: g.ask.owner });
|
|
458
467
|
continue;
|
|
459
468
|
}
|
|
460
469
|
const verdict = judgeOrphan(g, this.replayedLegClosed);
|
|
@@ -466,8 +475,15 @@ export class FileApprovalAskAuditStore {
|
|
|
466
475
|
if (orphanState === undefined)
|
|
467
476
|
continue;
|
|
468
477
|
const convergedAtMs = Date.now();
|
|
469
|
-
|
|
470
|
-
|
|
478
|
+
try {
|
|
479
|
+
this.appendOrThrow({ kind: "crash_converged", approvalId, orphanState, convergedAtMs });
|
|
480
|
+
}
|
|
481
|
+
catch (err) {
|
|
482
|
+
throw new Error(`approval ask audit: could not write the crash convergence record of approval ${approvalId} to ${this.ledgerPath}: ${err instanceof Error ? err.message : String(err)} — ` +
|
|
483
|
+
"refusing to start, because the record is this approval's convergence anchor and the upper bound of its cause word (without it a later process's orderly " +
|
|
484
|
+
"shutdown record would re-attribute it while its ask row keeps this boot's word). Fix the data root (disk full / read-only?) and start again.");
|
|
485
|
+
}
|
|
486
|
+
this.convergedRows.push({ row: this.projectRow(g, orphanState, convergedAtMs, holderGoneCauseOf(g, this.replayedShutdownLines)), owner: g.ask.owner });
|
|
471
487
|
if (orphanState === "pending")
|
|
472
488
|
pending += 1;
|
|
473
489
|
else
|
|
@@ -477,14 +493,12 @@ export class FileApprovalAskAuditStore {
|
|
|
477
493
|
this.convergedRows.length = Math.min(this.convergedRows.length, CRASH_CONVERGED_LIST_MAX);
|
|
478
494
|
return { pending, decided, inconsistent, corruptLines: this.corruptLines };
|
|
479
495
|
}
|
|
480
|
-
|
|
496
|
+
holderGoneVerdict(approvalId) {
|
|
481
497
|
const g = this.replayed.get(approvalId);
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
const before = g.convergedLine ?? Number.POSITIVE_INFINITY;
|
|
487
|
-
return legEvidenceOf(g, this.replayedShutdownMarks, after, before) === true ? "shutdown_before_park" : "crashed_before_park";
|
|
498
|
+
if (g?.ask === undefined)
|
|
499
|
+
return { orphan: false, cause: APPROVAL_ENDING_CAUSES.CRASHED_BEFORE_PARK };
|
|
500
|
+
const verdict = judgeOrphan(g, this.replayedLegClosed);
|
|
501
|
+
return { orphan: g.converged !== undefined || verdict === "pending" || verdict === "decided", cause: holderGoneCauseOf(g, this.replayedShutdownLines) };
|
|
488
502
|
}
|
|
489
503
|
projectRow(g, orphanState, convergedAtMs, cause) {
|
|
490
504
|
const ask = g.ask;
|
|
@@ -556,10 +570,14 @@ export class FileApprovalAskAuditStore {
|
|
|
556
570
|
dropped.add(id);
|
|
557
571
|
}
|
|
558
572
|
const claimedTasks = new Set();
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
573
|
+
let earliestKeptLastEvent = Number.POSITIVE_INFINITY;
|
|
574
|
+
for (const [id, g] of fold.groups) {
|
|
575
|
+
if (dropped.has(id) || g.ask === undefined)
|
|
576
|
+
continue;
|
|
577
|
+
claimedTasks.add(g.ask.taskId);
|
|
578
|
+
earliestKeptLastEvent = Math.min(earliestKeptLastEvent, lastEventLineOf(g));
|
|
579
|
+
}
|
|
580
|
+
const keep = (rec, line) => {
|
|
563
581
|
if (rec === undefined)
|
|
564
582
|
return true;
|
|
565
583
|
switch (rec.kind) {
|
|
@@ -570,15 +588,16 @@ export class FileApprovalAskAuditStore {
|
|
|
570
588
|
case "late_settle":
|
|
571
589
|
return rec.approvalId !== null ? !dropped.has(rec.approvalId) : rec.settledAtMs >= cutoffMs;
|
|
572
590
|
case "leg_closed":
|
|
591
|
+
return rec.closedAtMs >= cutoffMs || claimedTasks.has(rec.taskId) || keepAnchors.has(rec.taskId);
|
|
573
592
|
case "interrupted_by_shutdown":
|
|
574
|
-
return
|
|
593
|
+
return rec.atMs >= cutoffMs || earliestKeptLastEvent < line;
|
|
575
594
|
default: {
|
|
576
595
|
const unreachable = rec;
|
|
577
596
|
throw new Error(`approval-ask-audit rotate: unreachable record ${String(unreachable)}`);
|
|
578
597
|
}
|
|
579
598
|
}
|
|
580
599
|
};
|
|
581
|
-
const kept = entries.filter((e) => keep(e.rec));
|
|
600
|
+
const kept = entries.filter((e, i) => keep(e.rec, i + 1));
|
|
582
601
|
const droppedRecords = entries.length - kept.length;
|
|
583
602
|
if (droppedRecords === 0)
|
|
584
603
|
return { droppedAsks: 0, droppedRecords: 0, keptRecords: entries.length };
|
package/dist/approval-card.d.ts
CHANGED
|
@@ -86,9 +86,9 @@ export declare const RuleOfferSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
86
86
|
host: "host";
|
|
87
87
|
name: "name";
|
|
88
88
|
path: "path";
|
|
89
|
+
pattern: "pattern";
|
|
89
90
|
tool: "tool";
|
|
90
91
|
exact: "exact";
|
|
91
|
-
pattern: "pattern";
|
|
92
92
|
prefix: "prefix";
|
|
93
93
|
wildcard: "wildcard";
|
|
94
94
|
subpath: "subpath";
|
|
@@ -105,9 +105,9 @@ export declare const RuleOfferSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
105
105
|
host: "host";
|
|
106
106
|
name: "name";
|
|
107
107
|
path: "path";
|
|
108
|
+
pattern: "pattern";
|
|
108
109
|
tool: "tool";
|
|
109
110
|
exact: "exact";
|
|
110
|
-
pattern: "pattern";
|
|
111
111
|
prefix: "prefix";
|
|
112
112
|
wildcard: "wildcard";
|
|
113
113
|
subpath: "subpath";
|
|
@@ -571,12 +571,12 @@ export declare const ApprovalCardSchema: z.ZodObject<{
|
|
|
571
571
|
question: "question";
|
|
572
572
|
plan: "plan";
|
|
573
573
|
skill: "skill";
|
|
574
|
-
workflow: "workflow";
|
|
575
574
|
"file-edit": "file-edit";
|
|
576
575
|
"file-write": "file-write";
|
|
577
576
|
"notebook-edit": "notebook-edit";
|
|
578
577
|
shell: "shell";
|
|
579
578
|
fetch: "fetch";
|
|
579
|
+
workflow: "workflow";
|
|
580
580
|
generic: "generic";
|
|
581
581
|
}>>;
|
|
582
582
|
inputHasBidi: z.ZodOptional<z.ZodLiteral<true>>;
|
|
@@ -598,9 +598,9 @@ export declare const ApprovalCardSchema: z.ZodObject<{
|
|
|
598
598
|
host: "host";
|
|
599
599
|
name: "name";
|
|
600
600
|
path: "path";
|
|
601
|
+
pattern: "pattern";
|
|
601
602
|
tool: "tool";
|
|
602
603
|
exact: "exact";
|
|
603
|
-
pattern: "pattern";
|
|
604
604
|
prefix: "prefix";
|
|
605
605
|
wildcard: "wildcard";
|
|
606
606
|
subpath: "subpath";
|
|
@@ -617,9 +617,9 @@ export declare const ApprovalCardSchema: z.ZodObject<{
|
|
|
617
617
|
host: "host";
|
|
618
618
|
name: "name";
|
|
619
619
|
path: "path";
|
|
620
|
+
pattern: "pattern";
|
|
620
621
|
tool: "tool";
|
|
621
622
|
exact: "exact";
|
|
622
|
-
pattern: "pattern";
|
|
623
623
|
prefix: "prefix";
|
|
624
624
|
wildcard: "wildcard";
|
|
625
625
|
subpath: "subpath";
|
|
@@ -725,12 +725,12 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
|
|
|
725
725
|
question: "question";
|
|
726
726
|
plan: "plan";
|
|
727
727
|
skill: "skill";
|
|
728
|
-
workflow: "workflow";
|
|
729
728
|
"file-edit": "file-edit";
|
|
730
729
|
"file-write": "file-write";
|
|
731
730
|
"notebook-edit": "notebook-edit";
|
|
732
731
|
shell: "shell";
|
|
733
732
|
fetch: "fetch";
|
|
733
|
+
workflow: "workflow";
|
|
734
734
|
generic: "generic";
|
|
735
735
|
}>>;
|
|
736
736
|
inputHasBidi: z.ZodOptional<z.ZodLiteral<true>>;
|
|
@@ -752,9 +752,9 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
|
|
|
752
752
|
host: "host";
|
|
753
753
|
name: "name";
|
|
754
754
|
path: "path";
|
|
755
|
+
pattern: "pattern";
|
|
755
756
|
tool: "tool";
|
|
756
757
|
exact: "exact";
|
|
757
|
-
pattern: "pattern";
|
|
758
758
|
prefix: "prefix";
|
|
759
759
|
wildcard: "wildcard";
|
|
760
760
|
subpath: "subpath";
|
|
@@ -771,9 +771,9 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
|
|
|
771
771
|
host: "host";
|
|
772
772
|
name: "name";
|
|
773
773
|
path: "path";
|
|
774
|
+
pattern: "pattern";
|
|
774
775
|
tool: "tool";
|
|
775
776
|
exact: "exact";
|
|
776
|
-
pattern: "pattern";
|
|
777
777
|
prefix: "prefix";
|
|
778
778
|
wildcard: "wildcard";
|
|
779
779
|
subpath: "subpath";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ApprovalAskStore } from "./plugins/approval-ask-store-sql.js";
|
|
2
2
|
import { FileApprovalAskAuditStore } from "./approval-ask-audit-store.js";
|
|
3
3
|
import { type HolderGoneCause } from "./approval-deny-reasons.js";
|
|
4
|
+
import { type ReconcileCheckpointPort } from "./approval-reconciler.js";
|
|
4
5
|
import { type RunStoreReader } from "./user-input-ledger.js";
|
|
5
6
|
import type { Logger } from "./observability/logger.js";
|
|
6
7
|
/** 启动收敛的读数(进启动日志)。 */
|
|
@@ -10,17 +11,19 @@ export interface CrashConvergenceReport {
|
|
|
10
11
|
readonly decided: number;
|
|
11
12
|
readonly inconsistent: number;
|
|
12
13
|
readonly corruptLines: number;
|
|
13
|
-
/** ask 账半场:按成因词计的、本次收成 VOID 的前世 `STREAM_PENDING` 行数。 */
|
|
14
|
+
/** ask 账半场:按成因词计的、本次收成 VOID 的前世 `STREAM_PENDING` 行与审计判孤儿的 `PARKING` 行数。 */
|
|
14
15
|
readonly asksVoided: Readonly<Record<HolderGoneCause, number>>;
|
|
16
|
+
/** 审计判孤儿的 `PARKING` 行里判据 ① 命中、收成 `PARKED` 的行数(停车行其实已提交;每行另有一行 warn 点名)。 */
|
|
17
|
+
readonly parkingBound: number;
|
|
15
18
|
/** 其中卡信封读不出、成因词是回落(`crashed_before_park`)的行数(同时记 fail-open tag)。 */
|
|
16
19
|
readonly causeUnreadable: number;
|
|
17
20
|
}
|
|
18
21
|
/** 本次收成 VOID 的行数合计 —— 由成因闭集派生(对 `asksVoided` 的每个词求和;闭集加词不需要改这里)。 */
|
|
19
22
|
export declare function totalAsksVoided(report: Pick<CrashConvergenceReport, "asksVoided">): number;
|
|
20
|
-
/** 本函数读写的那几口(窄形:测试可以直给一只内存店)
|
|
21
|
-
export type CrashConvergenceAskPort = Pick<ApprovalAskStore, "listByState" | "transitionAsk">;
|
|
22
|
-
/** 审计店的两口(收敛半场 +
|
|
23
|
-
export type CrashConvergenceAuditPort = Pick<FileApprovalAskAuditStore, "convergeCrashedAsks" | "
|
|
23
|
+
/** 本函数读写的那几口(窄形:测试可以直给一只内存店)。`getBatch` / `bindBatch` 是判据 ① 执行体的两口。 */
|
|
24
|
+
export type CrashConvergenceAskPort = Pick<ApprovalAskStore, "listByState" | "transitionAsk" | "getBatch" | "bindBatch">;
|
|
25
|
+
/** 审计店的两口(收敛半场 + 持有者没了的判点)。 */
|
|
26
|
+
export type CrashConvergenceAuditPort = Pick<FileApprovalAskAuditStore, "convergeCrashedAsks" | "holderGoneVerdict">;
|
|
24
27
|
/**
|
|
25
28
|
* 启动收敛读哪一份**审计证据**:活的审计店在场就用它;不在场(这一世 `TOOL_APPROVAL_ENABLED` 关着 ⇒ 装配三合取不成立)而盘上有前世的审计账本
|
|
26
29
|
* ⇒ 开一只读它 —— 成因是盘上证据的函数,不随这一世的开关变(否则前世有序关停截断的问在这一世被写成 `crashed_before_park`,审批重新打开那天审计读面
|
|
@@ -32,12 +35,16 @@ export declare function openAuditEvidenceForConvergence(live: CrashConvergenceAu
|
|
|
32
35
|
release: () => void;
|
|
33
36
|
};
|
|
34
37
|
/**
|
|
35
|
-
* 启动收敛(见文件头)
|
|
36
|
-
*
|
|
38
|
+
* 启动收敛(见文件头)。只在数据根独占的车道上调,且必须在本进程铸出第一问之前。幂等跨启动:收过的行已不在 `STREAM_PENDING` / `PARKING`,
|
|
39
|
+
* 审计半场有自己的收敛锚;判定与成因读冻结的前世审计账 ⇒ 半途崩溃再启,剩下的行得到与第一次相同的判定与词。
|
|
40
|
+
* `checkpoints` = 判据 ① 的候选读口,必填、不可缺席(装配点交后端的只读口 `checkpointReadView()`;没有 checkpoint 店的后端交恒空读口):缺席会让判据 ① 恒不命中、
|
|
41
|
+
* 把已提交的停车行收成 VOID,所以既不给缺省,也不收 `undefined`。
|
|
37
42
|
*/
|
|
38
43
|
export declare function convergeCrashedAsksAtBoot(input: {
|
|
39
44
|
askStore: CrashConvergenceAskPort | undefined;
|
|
40
45
|
audit: CrashConvergenceAuditPort | undefined;
|
|
46
|
+
checkpoints: ReconcileCheckpointPort;
|
|
47
|
+
logger: Pick<Logger, "warn">;
|
|
41
48
|
now?: () => number;
|
|
42
49
|
}): Promise<CrashConvergenceReport>;
|
|
43
50
|
/**
|
|
@@ -45,12 +52,15 @@ export declare function convergeCrashedAsksAtBoot(input: {
|
|
|
45
52
|
* · 只在数据根独占的车道上跑 —— 车道事实与用户输入受理账本同一只 `writerGoneEvidenceFor`(local ⇒ `exclusive_data_root`);SQL 车道整步不做。
|
|
46
53
|
* · ask 店取 `backend.approvalAsk()`,**不看协议开关**:前世开着协议留下的行,今世关着也照收(否则重新打开协议那天它们又变得可决)。
|
|
47
54
|
* · 审计证据经 {@link openAuditEvidenceForConvergence}(这一世的审批开关不改变成因)。
|
|
55
|
+
* · 判据 ① 的候选读口 = 后端的只读口 `backend.checkpointReadView()`,**不看 `DURABLE_APPROVAL`**(前世已提交的停驻不因这一世的开关消失;local 车道它与 durable 装配的那只是同一只店,
|
|
56
|
+
* 只是不接 run 店的收割探针)。
|
|
48
57
|
* · 有任何收敛 / 坏行 ⇒ 一行 warn `approval_ask_audit_crash_converged`(零动作不打)。收敛写入抛错 ⇒ 抛出 ⇒ 拒启。
|
|
49
58
|
*/
|
|
50
59
|
export declare function runBootCrashConvergence(ctx: {
|
|
51
60
|
backend: {
|
|
52
61
|
readonly kind: "mysql" | "pg" | "local";
|
|
53
62
|
approvalAsk(): CrashConvergenceAskPort;
|
|
63
|
+
checkpointReadView(): ReconcileCheckpointPort;
|
|
54
64
|
} | undefined;
|
|
55
65
|
runStore: RunStoreReader | undefined;
|
|
56
66
|
liveAudit: CrashConvergenceAuditPort | undefined;
|