@zhushanwen/subagent-core 0.8.0 → 0.9.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/dist/{chunk-OL5BK4VN.js → chunk-LZJOEDGQ.js} +455 -203
- package/dist/engine-discovery-scan-Da4Dkzsi.d.cts +818 -0
- package/dist/engine-discovery-scan-Da4Dkzsi.d.ts +818 -0
- package/dist/execution/engine/engine-discovery-scan.cjs +216 -155
- package/dist/execution/engine/engine-discovery-scan.d.cts +1 -2
- package/dist/execution/engine/engine-discovery-scan.d.ts +1 -2
- package/dist/execution/engine/engine-discovery-scan.js +1 -1
- package/dist/execution/relay-env.js +5 -4
- package/dist/index.cjs +7686 -5894
- package/dist/index.d.cts +1876 -1360
- package/dist/index.d.ts +1876 -1360
- package/dist/index.js +7048 -5493
- package/dist.bundle/index.cjs +7747 -5957
- package/package.json +4 -4
- package/src/__tests__/manifest-store.test.ts +16 -15
- package/src/__tests__/robustness-medium-batch1.test.ts +10 -14
- package/src/__tests__/robustness-medium-batch2.test.ts +7 -2
- package/src/execution/__tests__/alive-store.test.ts +117 -1
- package/src/execution/__tests__/batch-finalized.test.ts +206 -0
- package/src/execution/__tests__/chat-engine-routing.test.ts +117 -1
- package/src/execution/__tests__/{cold-resurrect.test.ts → cold-lookup.test.ts} +133 -33
- package/src/execution/__tests__/collect-coordinator-service.test.ts +7 -5
- package/src/execution/__tests__/conversation-continuation.test.ts +1452 -0
- package/src/execution/__tests__/delivery-methods.test.ts +90 -176
- package/src/execution/__tests__/dialog-queue.test.ts +70 -3
- package/src/execution/__tests__/dispose-manifest-recovery.test.ts +475 -0
- package/src/execution/__tests__/execute-and-await-worktree.test.ts +3 -3
- package/src/execution/__tests__/execute-nesting.test.ts +8 -5
- package/src/execution/__tests__/execution-record.test.ts +8 -148
- package/src/execution/__tests__/finalize-record.test.ts +295 -129
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +21 -29
- package/src/execution/__tests__/helpers/fake-engine-port.ts +13 -68
- package/src/execution/__tests__/helpers/legacy-sidecar.ts +33 -0
- package/src/execution/__tests__/helpers/subagent-service-mocks.ts +9 -5
- package/src/execution/__tests__/idle-gc.test.ts +60 -0
- package/src/execution/__tests__/lifecycle-manager.test.ts +3 -254
- package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +43 -22
- package/src/execution/__tests__/model-config-service.test.ts +111 -0
- package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +10 -6
- package/src/execution/__tests__/notify-ledger.test.ts +42 -1
- package/src/execution/__tests__/rebuild-indexes.test.ts +329 -0
- package/src/execution/__tests__/record-binding.test.ts +613 -0
- package/src/execution/__tests__/record-origin.test.ts +318 -0
- package/src/execution/__tests__/record-store-intent-api.test.ts +600 -0
- package/src/execution/__tests__/record-store-orphan-revive.test.ts +71 -3
- package/src/execution/__tests__/record-store.test.ts +72 -54
- package/src/execution/__tests__/recursive-visibility-baseline.test.ts +8 -5
- package/src/execution/__tests__/round-supervisor-workflow-origin.test.ts +205 -0
- package/src/execution/__tests__/run-orchestration-write-lease.test.ts +293 -0
- package/src/execution/__tests__/run-orchestration.test.ts +199 -0
- package/src/execution/__tests__/session-file-gc.test.ts +35 -4
- package/src/execution/__tests__/session-reconstructor.test.ts +78 -0
- package/src/execution/__tests__/state-marker.test.ts +288 -0
- package/src/execution/__tests__/stream-sink-retirement.test.ts +8 -5
- package/src/execution/__tests__/subagent-actions-core.test.ts +67 -16
- package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +0 -1
- package/src/execution/__tests__/subagent-service-notify-gate.test.ts +27 -11
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +17 -11
- package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +130 -53
- package/src/execution/__tests__/subagent-service.test.ts +17 -215
- package/src/execution/__tests__/subprocess-agent-runner-no-progress-killall.test.ts +138 -0
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +105 -660
- package/src/execution/__tests__/sync-collect-recovery.test.ts +23 -16
- package/src/execution/__tests__/terminal-write-latency.test.ts +79 -0
- package/src/execution/__tests__/workflow-agent-dispatch.test.ts +782 -0
- package/src/execution/alive-store.ts +37 -28
- package/src/execution/{cold-resurrect.ts → cold-lookup.ts} +48 -45
- package/src/execution/config.ts +1 -1
- package/src/execution/conversation-continuation.ts +541 -0
- package/src/execution/dialog-queue.ts +60 -12
- package/src/execution/engine/__tests__/common/capability-gate.test.ts +1 -1
- package/src/execution/engine/__tests__/common/journal-wiring.test.ts +16 -1
- package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/fake-engine-protocol.mjs +17 -51
- package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/smoke-run.fixture.json +0 -5
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +1 -1
- package/src/execution/engine/__tests__/conformance/protocol-blackbox.test.ts +5 -9
- package/src/execution/engine/__tests__/engine-discovery-scan.test.ts +0 -3
- package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -3
- package/src/execution/engine/__tests__/model-prompt.test.ts +0 -3
- package/src/execution/engine/__tests__/registry.test.ts +0 -1
- package/src/execution/engine/__tests__/routing.test.ts +0 -1
- package/src/execution/engine/__tests__/run-failure-worktree-cleanup.test.ts +0 -3
- package/src/execution/engine/client/__tests__/__fixtures__/fake-engine.mjs +0 -3
- package/src/execution/engine/client/__tests__/engine-client-reap.test.ts +212 -0
- package/src/execution/engine/client/__tests__/mirror.test.ts +73 -1
- package/src/execution/engine/client/__tests__/protocol-closure.test.ts +2 -9
- package/src/execution/engine/client/__tests__/remote-engine.test.ts +46 -12
- package/src/execution/engine/client/engine-client.ts +81 -25
- package/src/execution/engine/client/mirror.ts +9 -0
- package/src/execution/engine/client/remote-engine.ts +52 -34
- package/src/execution/engine/client/reverse-router.ts +6 -27
- package/src/execution/engine/common/__tests__/run-signals.test.ts +79 -0
- package/src/execution/engine/common/capability-gate.ts +27 -0
- package/src/execution/engine/common/data-dir.ts +3 -2
- package/src/execution/engine/common/errors.ts +1 -1
- package/src/execution/engine/common/journal-wiring.ts +18 -9
- package/src/execution/engine/common/run-signals.ts +83 -0
- package/src/execution/engine/d8-compat.ts +1 -1
- package/src/execution/engine/host/__tests__/host-bridge.test.ts +3 -18
- package/src/execution/engine/host/host-bridge.ts +19 -41
- package/src/execution/engine/host/pi-host-binding.ts +5 -5
- package/src/execution/engine/port.ts +34 -54
- package/src/execution/engine/types.ts +11 -14
- package/src/execution/execution-record.ts +15 -47
- package/src/execution/finalize-record.ts +94 -197
- package/src/execution/idle-gc.ts +9 -3
- package/src/execution/lifecycle-manager.ts +25 -361
- package/src/execution/lifecycle-predicates.ts +22 -19
- package/src/execution/manifest-store.ts +40 -42
- package/src/execution/model-config-service.ts +1 -1
- package/src/execution/notifier.ts +39 -1
- package/src/execution/notify-host.ts +13 -4
- package/src/execution/record-entry.ts +20 -2
- package/src/execution/record-store.ts +925 -160
- package/src/execution/relay-env.ts +8 -3
- package/src/execution/round-supervisor/domain.ts +17 -5
- package/src/execution/round-supervisor/service-binding.test.ts +89 -53
- package/src/execution/round-supervisor/service-binding.ts +71 -21
- package/src/execution/round-supervisor/supervisor.ts +23 -9
- package/src/execution/service/record-access.ts +547 -0
- package/src/execution/service/record-lifecycle.ts +542 -0
- package/src/execution/service/run-orchestration.ts +1647 -0
- package/src/execution/service/service-bootstrap.ts +111 -0
- package/src/execution/service/service-constants.ts +27 -0
- package/src/execution/service/session-baselines.ts +401 -0
- package/src/execution/service/sync-collect-domain.ts +442 -0
- package/src/execution/service/workflow-dispatch.ts +567 -0
- package/src/execution/session-file-gc.ts +11 -8
- package/src/execution/session-reconstructor.ts +44 -1
- package/src/execution/sessions-index.ts +20 -3
- package/src/execution/settled-watchdog.ts +86 -43
- package/src/execution/state-marker.ts +516 -0
- package/src/execution/stream-sink.ts +1 -1
- package/src/execution/subagent-actions-core.ts +53 -31
- package/src/execution/subagent-service.ts +643 -2980
- package/src/execution/subprocess-agent-runner.ts +46 -323
- package/src/execution/types.ts +60 -43
- package/src/execution/ui-request-handler-factory.ts +5 -0
- package/src/execution/worktree-manager.ts +1 -1
- package/src/execution/worktree-registry.ts +1 -1
- package/src/index.ts +6 -5
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +2 -3
- package/src/orchestration/__tests__/agent-call-stream.test.ts +24 -49
- package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +4 -4
- package/src/orchestration/__tests__/file-run-store.test.ts +5 -7
- package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +2 -3
- package/src/orchestration/__tests__/run-snapshot.test.ts +27 -43
- package/src/orchestration/__tests__/worker-message-pump-workflow-dispatch.test.ts +274 -0
- package/src/orchestration/execute-agent-call.ts +1 -1
- package/src/orchestration/file-run-store.ts +1 -1
- package/src/orchestration/models/ports.ts +20 -13
- package/src/orchestration/models/types.ts +11 -13
- package/src/orchestration/run-snapshot.ts +18 -22
- package/src/orchestration/worker-message-pump.ts +33 -57
- package/src/shared/atomic-write.ts +10 -8
- package/dist/chunk-T2SYBW3I.js +0 -24
- package/dist/engine-discovery-scan-BXLA8y-z.d.cts +0 -1624
- package/dist/engine-discovery-scan-BXLA8y-z.d.ts +0 -1624
- package/src/execution/__tests__/chat-round-first-round-watchdog.test.ts +0 -255
- package/src/execution/__tests__/finalized-marker.test.ts +0 -104
- package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -488
- package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +0 -75
- package/src/execution/__tests__/tombstone-store.test.ts +0 -73
- package/src/execution/engine/__tests__/conformance/chat-round-protocol.test.ts +0 -230
- package/src/execution/finalized-marker.ts +0 -70
- package/src/execution/tombstone-store.ts +0 -72
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
// [H3/R2] SyncCollectDomain 聚合(域 #5:sync 批缓冲 + E9 dispose 转账 + E1 崩溃恢复)
|
|
2
|
+
// ——自 SubagentService 上帝类 strangler 抽取的第二个聚合(设计
|
|
3
|
+
// docs/design/subagent-service-decomposition.md §2.1 域 #5 / §3.3 D1 v3;成员归属以
|
|
4
|
+
// r0-inventory.md 清单① #26-#28 + 域 #5 分区为准)。
|
|
5
|
+
//
|
|
6
|
+
// 单一职责:自闭合批语义(设计 §3.1.4/§3.1.5)——collectCoordinator 装配(sync 批
|
|
7
|
+
// 缓冲 + 闭合检测 + flush 分流)、E9 dispose 转账(放弃攒批逐条转 async)、E1 崩溃
|
|
8
|
+
// 恢复(末条 entry 扫描 → 补发 + 落标)、settled 有界重扫、collectSync 配置读取。
|
|
9
|
+
//
|
|
10
|
+
// [D1 v3 红线 → U3 批写归口] 本聚合原直调的批写面已归口 store.markBatchFinalized
|
|
11
|
+
//(r0-inventory 清单②「不得改道」行随 record 持久化收敛设计 §3.1 markBatchFinalized
|
|
12
|
+
// 统一写点而终结):批终态三写(manifest 屏障 + batchFinalized 落标)全部经 store
|
|
13
|
+
// 意图原语;E1 重建投影 sync-rebuild.ts 模块函数(D 通道)、scanLastRecordEntries
|
|
14
|
+
// 读——保持 store 直调/模块函数直调,不经任何中转。
|
|
15
|
+
|
|
16
|
+
// [R1 打样模式——R2 落地](模式权威定义见 session-baselines.ts 文件头)
|
|
17
|
+
// 1. 依赖注入形态:deps 全晚绑定闭包(构造期零求值),聚合持过期引用会破 session
|
|
18
|
+
// 复活(dispose → initSession 翻转 disposed / pi / mainSessionFile 等),一切运行时
|
|
19
|
+
// 可变态断言/调用时现读。
|
|
20
|
+
// [检查点①] flushBatch 依赖 service 闭包(原壳构造器装配闭包经 this.* 读 store/
|
|
21
|
+
// notifyHost/sessionRootId)改为本 deps 接口显式注入——service 整实例零注入,
|
|
22
|
+
// flushBatch 闭包随聚合迁移,闭包内读的聚合私有成员(e9ConvertedIds/屏障/落标/
|
|
23
|
+
// 预算)走聚合 this,外部状态走 deps 现读 getter。
|
|
24
|
+
// 2. 转发壳写法:壳保留同名私有 getter(collectCoordinator)与同名 public 方法
|
|
25
|
+
// (recoverSyncCollectBatch/getCollectSyncDefault,D3 对外签名不变)单行转发;
|
|
26
|
+
// 纯内部方法(屏障/落标/预算等)壳内零转发(壳内无消费点)。
|
|
27
|
+
// 3. 跨聚合边收敛:他域直写本域字段的写点收敛为本聚合显式接口方法(G2 聚合间零
|
|
28
|
+
// 直写)——resetSettledRescan()(C-2:SessionBaselines.initSession 复活重置,
|
|
29
|
+
// R1 打样时以 deps.resetSettledRescan 回调留的对接点,本聚合交付后改指此处);
|
|
30
|
+
// lazyDispose()(C-1:壳 dispose 惰化 settled 重扫 handler,原直改
|
|
31
|
+
// settledRescanState.disposed)。
|
|
32
|
+
// 4. 深绑测试:本域测试面(sync-collect-recovery / collect-coordinator-service /
|
|
33
|
+
// collect-mixed-dispatch 等)的深绑点全部指向留壳字段(store/manifestStore/
|
|
34
|
+
// modelService/notifyHost)或壳转发 getter——晚绑定 deps 现读使 FR 字段替换语义
|
|
35
|
+
// 保持,聚合实例经壳 getter 读取与直读字段同一对象,断言零改写。
|
|
36
|
+
|
|
37
|
+
import { getLogger } from "../../core/logger.ts";
|
|
38
|
+
|
|
39
|
+
import { CollectCoordinator } from "../collect-coordinator.ts";
|
|
40
|
+
import { DEFAULT_COLLECT_SYNC } from "../config.ts";
|
|
41
|
+
import type { BatchBudgetParams, BgNotifyRecord } from "../notifier.ts";
|
|
42
|
+
import { bufferedMemberFallbackRecord, syncRebuildToNotifyMember } from "../sync-rebuild.ts";
|
|
43
|
+
import type { CollectSyncConfig, ExecutionRecord, SubagentRecord } from "../types.ts";
|
|
44
|
+
|
|
45
|
+
const logger = getLogger("subagents");
|
|
46
|
+
|
|
47
|
+
/** [v2 D4] E1 等待分支 settled 有界重扫上限。无上限重扫 = 泄漏(设计 §3.3 D4 被否
|
|
48
|
+
* 谱系);8 次覆盖重启后主 agent 对 resumable 成员的典型续跑轮次,达限仍有
|
|
49
|
+
* running → disposed,交下次 session_start 收敛。
|
|
50
|
+
* [R2] 常量 SSOT 随唯一消费主体(armSettledRescan)自壳文件迁入本聚合。 */
|
|
51
|
+
const SETTLED_RESCAN_LIMIT = 8;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* [R1 打样模式 1] 聚合协作 deps——**全部晚绑定闭包,构造期零求值**。
|
|
55
|
+
*
|
|
56
|
+
* 窄结构类型只声明聚合真实消费的通道(不整实例注入)。全 getter 形态(零回调):
|
|
57
|
+
* 本聚合自闭合批语义,无跨域编排——dispose 侧 E9 转账/惰化由壳编排调用本聚合
|
|
58
|
+
* 显式方法(正向),聚合对他域零反向写(settledRescanState 复活重置由他域经
|
|
59
|
+
* resetSettledRescan 显式接口回调,见 C-2)。
|
|
60
|
+
*/
|
|
61
|
+
export interface SyncCollectDomainDeps {
|
|
62
|
+
/** RecordStore 窄门面(E1 扫描读 / flushBatch 冷路径重建 / 批终态写 / 闭合判定扫描)。
|
|
63
|
+
* [U3 批写归口] manifest 屏障 + batchFinalized 落标合一进 markBatchFinalized(store
|
|
64
|
+
* 唯一写入口,设计 §3.1);reportSubagentRecord 直调通道随落标归口消亡。 */
|
|
65
|
+
readonly getStore: () => {
|
|
66
|
+
listAllActive(): ExecutionRecord[];
|
|
67
|
+
getFullRecord(id: string): SubagentRecord | undefined;
|
|
68
|
+
markBatchFinalized(records: readonly SubagentRecord[]): Promise<void>;
|
|
69
|
+
scanLastRecordEntries(mainSessionFile: string | undefined): SubagentRecord[];
|
|
70
|
+
};
|
|
71
|
+
/** NotifyHost 窄门面(async 直通 / 快照映射 / 单条直发 / 批投递)。晚绑定现读:
|
|
72
|
+
* 测试的 notifyHost 字段替换(FR 深绑形态)经壳字段现读保持生效。 */
|
|
73
|
+
readonly getNotifyHost: () => {
|
|
74
|
+
toNotifyRecord(record: ExecutionRecord): BgNotifyRecord | undefined;
|
|
75
|
+
notify(record: BgNotifyRecord): void;
|
|
76
|
+
notifyBatch(records: readonly BgNotifyRecord[], budget?: BatchBudgetParams): boolean;
|
|
77
|
+
};
|
|
78
|
+
/** pi 句柄(armSettledRescan 注册 agent_settled 订阅;initSession 时点晚绑定)。 */
|
|
79
|
+
readonly getPi: () => { on?(event: "agent_settled", handler: () => void): void } | null;
|
|
80
|
+
/** 所属根 session ID(flushBatch 兜底落标归属 / E1 候选 root 过滤;#2 聚合字段现读)。 */
|
|
81
|
+
readonly getSessionRootId: () => string | null;
|
|
82
|
+
/** 主 session 文件(E1 扫描读 pi 当前值,非注册时快照——旧 handler 语义,见
|
|
83
|
+
* settledRescanState 注释;#2 聚合字段现读)。 */
|
|
84
|
+
readonly getMainSessionFile: () => string | undefined;
|
|
85
|
+
/** collectSync 配置节热读(budget/default 同一读取点,modelService 留壳——窄化
|
|
86
|
+
* 为节读取,聚合不感知 ModelConfigService)。 */
|
|
87
|
+
readonly getCollectSyncSection: () => CollectSyncConfig | undefined;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 域 #5 聚合:sync 批(E9/E1)自闭合批语义(R2 自 SubagentService 抽取)。
|
|
92
|
+
*
|
|
93
|
+
* 字段所有权(r0-inventory 清单① #26-#28 全部 3 个):本聚合唯一写者;壳经
|
|
94
|
+
* collectCoordinator getter 只读透传(route 调用点),其余字段壳零感知。
|
|
95
|
+
*/
|
|
96
|
+
export class SyncCollectDomain {
|
|
97
|
+
private readonly deps: SyncCollectDomainDeps;
|
|
98
|
+
|
|
99
|
+
/** collectCoordinator(subagent-sync-collect U2):sync 批缓冲 + 闭合检测 + flush 分流。
|
|
100
|
+
* 构造期装配后不可变(readonly),壳经 getter 只读透传。 */
|
|
101
|
+
private readonly _collectCoordinator: CollectCoordinator;
|
|
102
|
+
|
|
103
|
+
/** [E9] dispose 时已转 async 写账的成员 id(revive 后 flushBatch 防御过滤用)。
|
|
104
|
+
* 背景:dispose 后同进程 revive(/resume /fork /new)时协调器内部缓冲仍持有已转换
|
|
105
|
+
* 成员快照(协调器无 drain API,U5 领地不含 collect-coordinator.ts)——若后续新
|
|
106
|
+
* sync 成员触发闭合,陈旧快照会随批重投(新成员集新 hash,账本跨键不拦)→ 双重
|
|
107
|
+
* 通知。flushBatch 闭包按本集过滤,陈旧成员零重投。id 唯一 per spawn,无误伤面。 */
|
|
108
|
+
private readonly e9ConvertedIds = new Set<string>();
|
|
109
|
+
|
|
110
|
+
/** [v2 D4] E1 等待分支的 settled 有界重扫状态(null = 未注册)。disposed 后保持
|
|
111
|
+
* 非 null——同 session 内不再重复注册(补发完成/达限后 settled 边沿已无事可做,
|
|
112
|
+
* 单注册即单重扫);initSession(revive)经 resetSettledRescan() 置 null 允许新
|
|
113
|
+
* session 重新注册。pi.on 无 off(见 armSettledRescan):旧 handler 闭包捕获旧
|
|
114
|
+
* state,未 disposed 时遇 settled 边沿仍会执行,扫描主 session 文件当前值
|
|
115
|
+
* (handler 不绑定注册时的文件域);dispose 的惰化处置见 lazyDispose()。 */
|
|
116
|
+
private settledRescanState: { disposed: boolean; scans: number } | null = null;
|
|
117
|
+
|
|
118
|
+
constructor(deps: SyncCollectDomainDeps) {
|
|
119
|
+
this.deps = deps;
|
|
120
|
+
// collectCoordinator(subagent-sync-collect U2):notifyComplete 唯一路由入口——
|
|
121
|
+
// async 直通(字节不变)/ sync 批缓冲 + 闭合检测。[U3 接线点] 已接线:flush =
|
|
122
|
+
// store.markBatchFinalized(manifest 屏障 + batchFinalized 落标合一原语,屏障
|
|
123
|
+
// await 全部落盘——出口①,见下方闭包注释)先于 notifier.notifyBatch 单条批
|
|
124
|
+
// 投递(幂等键 sync-batch:<hash> ledger 写账 → attemptDeliver 边沿投递);
|
|
125
|
+
// 闭合触发排程合批 flush:同宏任务去抖窗口收纳背靠背 route——U8 拆批盲窗修复。
|
|
126
|
+
// 屏障先于写账 = 「通知可达 ⇒ 索引就位」的构造性保证(时序竞态修复,见
|
|
127
|
+
// flushBatch 闭包注释)。
|
|
128
|
+
// [U8] 排程与 E9/E1 交互:dispose 经 convertPendingSyncBufferToAsync 先取消挂起
|
|
129
|
+
// 排程(取消而非同步 flush——双通道并发写账防护,见该函数注释);E1 只在
|
|
130
|
+
// session_start 编排处运行(此前 dispose 已取消排程,补发直走 notifyBatch 不经
|
|
131
|
+
// 协调器),异常时序相撞由账本 sync-batch:<hash> 幂等拒绝兜底。
|
|
132
|
+
// [检查点①] 闭包依赖显式化:闭包内聚合私有成员走 this,外部状态(notifyHost/
|
|
133
|
+
// store/sessionRootId)经 deps 晚绑定 getter 现读——不持引用、不整实例注入。
|
|
134
|
+
this._collectCoordinator = new CollectCoordinator({
|
|
135
|
+
notifyAsync: (record) => {
|
|
136
|
+
const notify = this.deps.getNotifyHost().toNotifyRecord(record);
|
|
137
|
+
if (notify) this.deps.getNotifyHost().notify(notify);
|
|
138
|
+
},
|
|
139
|
+
toNotifyRecord: (record) => this.deps.getNotifyHost().toNotifyRecord(record),
|
|
140
|
+
// 闭合判定数据源:listAllActive(原始 ExecutionRecord 内存态,携带 collectMode/
|
|
141
|
+
// batchFinalized 原始值)。[U3 修正] 原接 collectRecords——其经 recordToSubagent
|
|
142
|
+
// 投影丢 collectMode(U2 披露的投影缺口)→ 真链上闭合判定恒立即闭合、跨轮续累
|
|
143
|
+
// 失效(真链 trace 实证)。非终态 sync 成员必在内存(archive 只删终态;磁盘重建
|
|
144
|
+
// 残留属孤儿恢复域),内存视图语义完整。
|
|
145
|
+
listRecords: (limit) => this.deps.getStore().listAllActive().slice(0, limit),
|
|
146
|
+
flushBatch: async (members) => {
|
|
147
|
+
// [E9 防御过滤] 排除 dispose 时已转 async 写账的成员(同进程 revive 后协调器
|
|
148
|
+
// 缓冲残留的陈旧快照,见 e9ConvertedIds 字段注释);全被排除 → 空批零副作用
|
|
149
|
+
// 返回(成员已单独写账+落标,无需再动)。
|
|
150
|
+
const live = members.filter((m) => !this.e9ConvertedIds.has(m.id));
|
|
151
|
+
if (live.length === 0) return;
|
|
152
|
+
// 成员全量快照:getFullRecord 冷路径重建(成员在 notifyComplete 前已 archive,
|
|
153
|
+
// 内存无;闭合判定 hasRunningSync 的 listRecords 扫描已建 idToFile 索引,此处
|
|
154
|
+
// 命中)。快照在屏障前一次取定,屏障写与落标共用同一份(manifest 与落标 entry
|
|
155
|
+
// 字段同源)。
|
|
156
|
+
// [S11] getFullRecord 不可达(子 session 文件缺失/已 GC 的窗口)的成员改用
|
|
157
|
+
// 缓冲快照兜底落标,不再跳过——该成员仍随 live 进批写账(成员集 hash 含它),
|
|
158
|
+
// 跳过落标的旧行为会在重启后让 E1 重新收集它(无标记候选),以异成员集 hash
|
|
159
|
+
// 重新补发 → 同成员双投递(异 hash 不触发账本 sync-batch 幂等;旧注释「该
|
|
160
|
+
// 窗口下 E1 本也收不到该成员」不成立:E1 走主 session 文件末条 entry 扫描,
|
|
161
|
+
// 与 getFullRecord 的 manifest/子文件通路相互独立,manifest 屏障 best-effort
|
|
162
|
+
// 写失败同样制造此窗口)。
|
|
163
|
+
const fulls: SubagentRecord[] = [];
|
|
164
|
+
const fullMissed: BgNotifyRecord[] = [];
|
|
165
|
+
for (const m of live) {
|
|
166
|
+
const full = this.deps.getStore().getFullRecord(m.id);
|
|
167
|
+
if (full) fulls.push(full);
|
|
168
|
+
else fullMissed.push(m);
|
|
169
|
+
}
|
|
170
|
+
// [U3 批写归口] manifest 屏障 + batchFinalized 落标合一进 store.markBatchFinalized
|
|
171
|
+
//(唯一写入口;内部序 = manifest 落盘**完成**先于落标 entry,manifestDir 接线后
|
|
172
|
+
// 同步落盘无 fire-and-forget),整体先于 notifyBatch 写账投递——「通知可达 ⇒
|
|
173
|
+
// 索引就位」构造性保持(D4②/D5,缓存降级下 barrier 不可删)。miss 成员(S11)
|
|
174
|
+
// 以缓冲快照兜底同批落标——markBatchFinalized 会为其多写一笔 manifest(投影
|
|
175
|
+
// sessionFile undefined 自然缺省),较旧路径(miss 成员零 manifest)只多不少,
|
|
176
|
+
// 反查落空本就由 session-reader 绝对路径兜底承接。
|
|
177
|
+
await this.deps.getStore().markBatchFinalized([
|
|
178
|
+
...fulls,
|
|
179
|
+
...fullMissed.map((m) => bufferedMemberFallbackRecord(m, this.deps.getSessionRootId() ?? undefined)),
|
|
180
|
+
]);
|
|
181
|
+
// 单条批投递:空批/dispose → 零副作用返回(设计 §3.1.3 出口①)。
|
|
182
|
+
// [U3 源序变化] 落标已随 markBatchFinalized 前置到写账前——合一原语形态下
|
|
183
|
+
// 「屏障 → 写账 → 落标」三段不可兼得,构造性 barrier 优先(设计钉死不可删);
|
|
184
|
+
// accepted=false(同成员集批已在账——重复 flush / E1 重建重发形态)时已落标
|
|
185
|
+
// 属幂等覆写(appendEntry last-writer-wins,该批此前成功投递时已落标),无
|
|
186
|
+
// 行为差异。
|
|
187
|
+
this.deps.getNotifyHost().notifyBatch(live, this.getCollectSyncBudget());
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ── 壳只读透传面(getter)──
|
|
193
|
+
// [R1 打样模式 2] 壳侧同名私有 getter 透传(route 调用点零改动);写路径无——
|
|
194
|
+
// 构造期 readonly 装配后不可变。
|
|
195
|
+
|
|
196
|
+
get collectCoordinator(): CollectCoordinator {
|
|
197
|
+
return this._collectCoordinator;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ── 跨聚合边显式接口(G2 聚合间零直写)──
|
|
201
|
+
|
|
202
|
+
/** [C-2 显式接口] settled 重扫状态复活重置(置 null 允许新 session 重新注册)。
|
|
203
|
+
* SessionBaselines.initSession 的 revive 编排步经壳 deps 回调调到本方法(R1 打样
|
|
204
|
+
* 时以 deps.resetSettledRescan 留的对接点,本聚合交付后改指此处——聚合间零直写)。
|
|
205
|
+
* 语义注释(v2 D4):新 session 的 E1 若再判「仍有 running」可重新注册。旧
|
|
206
|
+
* handler 闭包捕获旧 state:正常时序(session_shutdown → session_start)下已随
|
|
207
|
+
* dispose() 惰化;未经 dispose 的时序残留仍会在 settled 边沿执行——其扫描主
|
|
208
|
+
* sessionFile 当前值(非注册时的旧文件),行为等价于新 session 多注册一次扫描,
|
|
209
|
+
* 由账本 sync-batch:<hash> 幂等 + batchFinalized 候选过滤收敛,无跨 session 污染面。 */
|
|
210
|
+
resetSettledRescan(): void {
|
|
211
|
+
this.settledRescanState = null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** [C-1 显式接口] dispose 惰化:settled 重扫 handler 置 disposed(幂等)。
|
|
215
|
+
* 原壳 dispose 直改本聚合内部态 settledRescanState.disposed(r0-inventory 清单①
|
|
216
|
+
* C-1 跨聚合边,R0 登记、本单元兑现收敛)。时序契约(原壳 dispose 注释):dispose
|
|
217
|
+
* 后 trailing settled 边沿若仍触发,旧 handler 不得再跑扫描——notifier 随后将
|
|
218
|
+
* dispose,notifyBatch 短路返回 false 且不写账,而 E1 dispatched 段不判 accepted
|
|
219
|
+
* 仍统一落标 → 批被标 batchFinalized 而通知从未写账(永久丢失,不可逆)。惰化后
|
|
220
|
+
* 通知由下次重启的 E1 首扫兑现(成员无标记,候选可达)。与 initSession revive
|
|
221
|
+
* 重置不冲突:dispose 是终态置 disposed,revive 置 null 是新 session 的重新注册,
|
|
222
|
+
* 旧 state 对象随旧 handler 闭包保持 disposed 永久惰化。 */
|
|
223
|
+
lazyDispose(): void {
|
|
224
|
+
if (this.settledRescanState !== null) this.settledRescanState.disposed = true;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ── E9:dispose 转账(壳 dispose 编排调用,时序见壳 dispose 注释)──
|
|
228
|
+
|
|
229
|
+
/** [E9] dispose 时批未闭合:缓冲中已终态未通知成员逐条转 async 语义写账(放弃攒批)
|
|
230
|
+
* + 落 batchFinalized 标记(E1 重建扫描据此排除,防双重通知),交由既有 shutdown
|
|
231
|
+
* flush / resume 重放兑底;仍在跑的成员走现有退出路径(disposeAllRecords 关闭,
|
|
232
|
+
* 与 async 一致)。写账用 notifier.notify 现有通路(ledger.record + attemptDeliver)。
|
|
233
|
+
* 源序:写账先于落标——写账后崩溃 → E1 重建收该成员,但 async notifyId 与批 hash
|
|
234
|
+
* 跨键不拦的重发属设计披露的 E9 残余窗(at-least-once 良性,PS-17 同族,v1 接受)。 */
|
|
235
|
+
convertPendingSyncBufferToAsync(): void {
|
|
236
|
+
// [U8 拆批修复·E9 交互] 挂起的合批排程先取消——dispose 已选「放弃攒批转 async」
|
|
237
|
+
// 语义(最简语义 = 取消而非同步 flush):放任排程触发会让 flushBatch(批 hash
|
|
238
|
+
// 通道)与下方逐条 notify(async id 通道)双通道并发写账 → 同成员双投递,且触发
|
|
239
|
+
// 点可能落在 notifier/store dispose 之后。取消后缓冲原样保留,本函数既有单通路
|
|
240
|
+
// 完整接管(协调器侧幂等:无排程时 no-op)。
|
|
241
|
+
this._collectCoordinator.cancelScheduledFlush();
|
|
242
|
+
const members = this._collectCoordinator.pendingMembers();
|
|
243
|
+
if (members.length === 0) return;
|
|
244
|
+
for (const member of members) {
|
|
245
|
+
this.e9ConvertedIds.add(member.id);
|
|
246
|
+
this.deps.getNotifyHost().notify(member);
|
|
247
|
+
}
|
|
248
|
+
this.markMembersBatchFinalized(members.map((m) => m.id));
|
|
249
|
+
logger.warn(
|
|
250
|
+
`[subagents] E9 dispose: converted ${members.length} buffered sync member(s) to async notify`,
|
|
251
|
+
{ ids: members.map((m) => m.id) },
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ── E1:崩溃恢复(壳 public 转发,index.ts session_start 编排处调用)──
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* [E1] sync 批崩溃恢复钩子(设计 §3.1.5 E1,index.ts session_start 恢复编排处调用,
|
|
259
|
+
* 须晚于 initSession——孤儿终态恢复先行收敛 running 成员,「全员终态」判定才可达):
|
|
260
|
+
*
|
|
261
|
+
* - 扫描主 session 文件每 id 末条 subagent-record entry(store.scanLastRecordEntries,
|
|
262
|
+
* collectLastRecordEntries 同构 + 投影扩展含 collectMode/batchFinalized + 终态五
|
|
263
|
+
* 字段;禁走 collectRecords light 路径——主 session 落标 entry 对它不可见);
|
|
264
|
+
* - 只收 collectMode=sync 且无 batchFinalized 的成员(排除已通过批 flush 或 E9
|
|
265
|
+
* 转换离场的,防双重通知),按 rootSessionId 过滤当前根;
|
|
266
|
+
* - 全员终态且账本无同成员集批记录 → manifest 屏障(await 落盘,「通知可达 ⇒
|
|
267
|
+
* 索引就位」构造性保证,与 flushBatch 同款)→ notifyBatch 补发(内容 = 末条
|
|
268
|
+
* entry 终态快照;账本 record 同 hash 幂等拒绝 = 已投递/已在账,两种结局都算
|
|
269
|
+
* 「已处理」);
|
|
270
|
+
* - 仍有 running → 本次不动,注册 settled 有界重扫(D4,见 armSettledRescan)——
|
|
271
|
+
* 成员延迟终态(主 agent 冷路径 resume → 正常流落 entry)由 settled 边沿驱动
|
|
272
|
+
* 重扫收敛,不再依赖「下次 session_start」作唯一再驱动(v2 §2.4 断链 4);
|
|
273
|
+
* running 口径与协调器同构
|
|
274
|
+
* (resumable 豁免,v2 D3——覆写不可达的防御分支残余不被误判「仍在跑」);
|
|
275
|
+
* - 补发尝试后统一补 batchFinalized 标记(账本拒绝也算已投递;直接用末条重建快照
|
|
276
|
+
* 落标不经 getFullRecord——子文件缺失/已 GC 时标记仍可落盘,窗口自愈不依赖二次
|
|
277
|
+
* 重启;补标自身崩溃重入幂等收敛,末条 entry last-writer-wins)。
|
|
278
|
+
*
|
|
279
|
+
* async 化(时序屏障修复):返回 Promise 但**内部自捕获不外抛**——宿主 index.ts
|
|
280
|
+
* session_start 以同步 try/catch 调用(其 catch 兑现不到 promise 内的异常),
|
|
281
|
+
* 自捕获维持同款 warn 容错语义,浮动调用零适配、不产生 unhandled rejection。
|
|
282
|
+
*
|
|
283
|
+
* [U8 拆批修复] 与协调器合批排程无交集:E1 只在 session_start 编排处运行(此前
|
|
284
|
+
* dispose 已取消挂起排程),补发直走 notifier.notifyBatch 不经协调器;异常时序
|
|
285
|
+
* 相撞由账本 sync-batch:<hash> 幂等拒绝兜底。
|
|
286
|
+
*/
|
|
287
|
+
async recoverSyncCollectBatch(): Promise<void> {
|
|
288
|
+
try {
|
|
289
|
+
const { outcome } = await this.runSyncCollectRecoveryScan();
|
|
290
|
+
// [v2 D4] 断链 4:等待分支不再死等——挂 settled 有界重扫(幂等单注册)。
|
|
291
|
+
if (outcome === "waiting") {
|
|
292
|
+
this.armSettledRescan();
|
|
293
|
+
}
|
|
294
|
+
} catch (err) {
|
|
295
|
+
// 与 index.ts 调用点原 try/catch 的 warn 容错同语义(该处 catch 对 async 化后
|
|
296
|
+
// 的 promise 异常兑现不到,容错收敛到本方法内部)。
|
|
297
|
+
logger.warn("[subagents] sync collect batch recovery failed", {
|
|
298
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ── collectSync 配置读取(壳 public 转发 getCollectSyncDefault)──
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* collectSync.default 当前生效值(subagent-sync-collect U2,偏差#3 接线:
|
|
307
|
+
* startHandler 缺省 collect 解析用)。
|
|
308
|
+
* config 未配/读失败 → DEFAULT_COLLECT_SYNC.default 兜底(E5 不炸启动)。
|
|
309
|
+
* 新 session 生效语义与 engine 配置一致(globalConfig 由 ModelConfigService
|
|
310
|
+
* reloadGlobalConfig 刷新)。
|
|
311
|
+
*/
|
|
312
|
+
/** collectSync 节单读取点(S9,code-simplify):「读节」一处,「投影成 default 或
|
|
313
|
+
* budget」各自 accessor 负责(getCollectSyncDefault / getCollectSyncBudget)。 */
|
|
314
|
+
private collectSyncSection(): CollectSyncConfig | undefined {
|
|
315
|
+
return this.deps.getCollectSyncSection();
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
getCollectSyncDefault(): "async" | "sync" {
|
|
319
|
+
return this.collectSyncSection()?.default ?? DEFAULT_COLLECT_SYNC.default;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** [U4 deviation #8 接线] collectSync 预算热读(flush 时读值,与 getCollectSyncDefault
|
|
323
|
+
* 同款访问链)。节缺失/读失败 → undefined → notifyBatch 落 buildBatchLlmContent
|
|
324
|
+
* 设计默认值(4000/24000,E5 不炸启动)。sanitizeCollectSync 保证节存在时两字段
|
|
325
|
+
* 必有合法正整数。 */
|
|
326
|
+
private getCollectSyncBudget(): BatchBudgetParams | undefined {
|
|
327
|
+
const cs = this.collectSyncSection();
|
|
328
|
+
return cs !== undefined ? { perItemChars: cs.perItemChars, totalChars: cs.totalChars } : undefined;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// ── 批投递内部通路(flushBatch / E1 / E9 共用)──
|
|
332
|
+
|
|
333
|
+
/** [E9 专用] batchFinalized 落标 + manifest 写(设计 §3.1.5 E9)——已归口
|
|
334
|
+
* store.markBatchFinalized(U3 批写归口)。批通知路径(flush/E1)的「manifest
|
|
335
|
+
* 屏障 → 写账 → 落标」序列见各自调用点;E9 转换的成员走 async 单条通知(全文
|
|
336
|
+
* 注入、无指针行消费),manifest 无时序要求,且 dispose 编排中写账(逐条 notify)
|
|
337
|
+
* 先于本调用——「写账先于落标」源序在此路径保持。
|
|
338
|
+
* 路径 = getFullRecord 冷路径重建 → markBatchFinalized(manifestDir 接线后 manifest
|
|
339
|
+
* 同步落盘,dispose 同步链内完成——D8 停机窗方向;落标 entry 随原语后半落)。
|
|
340
|
+
* getFullRecord 不可达(子 session 文件缺失/已 GC)→ 跳过该成员(详见 flushBatch
|
|
341
|
+
* 闭包注释)。 */
|
|
342
|
+
private markMembersBatchFinalized(memberIds: readonly string[]): void {
|
|
343
|
+
const fulls: SubagentRecord[] = [];
|
|
344
|
+
for (const id of memberIds) {
|
|
345
|
+
const full = this.deps.getStore().getFullRecord(id);
|
|
346
|
+
if (full) fulls.push(full);
|
|
347
|
+
}
|
|
348
|
+
// 反查索引缺失只影响指针行反查(session-reader 错误文案已指引绝对路径兜底),
|
|
349
|
+
// 不构成落标失败(原语内部 best-effort 同源语义)。
|
|
350
|
+
void this.deps.getStore().markBatchFinalized(fulls);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ── E1 内部:扫描 → 判定 → 补发(E1 首扫与 settled 重扫共用)──
|
|
354
|
+
|
|
355
|
+
/** [E1/D4] 单次「扫描→判定→可达则补发+落标」,E1 首扫与 settled 重扫共用同一实现
|
|
356
|
+
* (防两处复制粘贴分岔)。三态返回:idle(无 sync 候选——已全部落标/E9 转换/异根,
|
|
357
|
+
* 无事可等)/ waiting(仍有 running 成员,本次不动)/ dispatched(全员终态,已补发
|
|
358
|
+
* +统一落标)。async:补发前有 manifest 屏障 await(见函数头 E1 注释)。 */
|
|
359
|
+
/** 返回 outcome + waitingIds(达限 warn 需滞留成员 id,D6 #7b——仅 waiting 态非空)。 */
|
|
360
|
+
private async runSyncCollectRecoveryScan(): Promise<{
|
|
361
|
+
outcome: "idle" | "waiting" | "dispatched";
|
|
362
|
+
waitingIds: string[];
|
|
363
|
+
}> {
|
|
364
|
+
const lastRecords = this.deps.getStore().scanLastRecordEntries(this.deps.getMainSessionFile());
|
|
365
|
+
if (lastRecords.length === 0) return { outcome: "idle", waitingIds: [] };
|
|
366
|
+
const rootFilter = this.deps.getSessionRootId();
|
|
367
|
+
const candidates = lastRecords.filter(
|
|
368
|
+
(r) =>
|
|
369
|
+
r.collectMode === "sync" &&
|
|
370
|
+
r.batchFinalized !== true &&
|
|
371
|
+
(rootFilter === undefined || r.rootSessionId === rootFilter),
|
|
372
|
+
);
|
|
373
|
+
if (candidates.length === 0) return { outcome: "idle", waitingIds: [] };
|
|
374
|
+
// [v2 D3] 与协调器 hasRunningSync 同构口径(collect-coordinator.ts):running+
|
|
375
|
+
// resumable 视为已完成、不阻止补发——成功成员崩溃时的末条 entry 恒为轮终
|
|
376
|
+
// running+resumable(SP-5 有意语义),旧口径只看 status !== "closed" 会把主场景
|
|
377
|
+
// (批内含成功成员)顶死在「等自然终态」永不补发(v2 §2.3 断链 3)。
|
|
378
|
+
const running = candidates.filter((r) => r.resumable !== true && r.status !== "closed");
|
|
379
|
+
if (running.length > 0) {
|
|
380
|
+
logger.debug(
|
|
381
|
+
`[subagents] E1 sync batch recovery: ${running.length} member(s) still running, wait for natural completion`,
|
|
382
|
+
{ ids: running.map((r) => r.id) },
|
|
383
|
+
);
|
|
384
|
+
return { outcome: "waiting", waitingIds: running.map((r) => r.id) };
|
|
385
|
+
}
|
|
386
|
+
// [U3 批写归口 / 时序屏障] manifest 屏障 + 统一落标合一进 store.markBatchFinalized,
|
|
387
|
+
// 整体先于写账投递——E1 补发同样是批通知(指针行消费依赖反查索引),「通知可达 ⇒
|
|
388
|
+
// 索引就位」的构造性保证与 flushBatch 同款。落标前置后「账本拒绝(accepted=false)
|
|
389
|
+
// 也统一补标」的 E1 既有语义不变(合一原语内落标无条件)。
|
|
390
|
+
await this.deps.getStore().markBatchFinalized(candidates);
|
|
391
|
+
// 全员终态:单条批补发(budget 热读与 flushBatch 同源);账本同 hash 幂等拒绝也算
|
|
392
|
+
// 已投递(批已在账/已销账,重放由账本承接)——两种结局统一补标。
|
|
393
|
+
const members = candidates.map((r) => syncRebuildToNotifyMember(r));
|
|
394
|
+
const accepted = this.deps.getNotifyHost().notifyBatch(members, this.getCollectSyncBudget());
|
|
395
|
+
logger.warn(
|
|
396
|
+
`[subagents] E1 sync batch recovery: re-notified ${members.length} member(s) (ledger accepted=${accepted})`,
|
|
397
|
+
{ ids: members.map((m) => m.id) },
|
|
398
|
+
);
|
|
399
|
+
return { outcome: "dispatched", waitingIds: [] };
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/** [v2 D4] 注册 agent_settled 有界重扫(幂等:settledRescanState 非 null 不叠加注册
|
|
403
|
+
* ——E1 现仅 session_start 单调用点,守卫是防第二入口引入时的注册叠加断言面)。
|
|
404
|
+
* 每次 settled 边沿重跑同一 E1 扫描(runSyncCollectRecoveryScan):dispatched
|
|
405
|
+
* (补发+落标完成,scan 的 warn 已留痕)或 idle(候选已被其他通路落标)→ disposed;
|
|
406
|
+
* 累计 SETTLED_RESCAN_LIMIT 次仍在等 → disposed + warn 留痕(D6 #7b / SC-2:达限
|
|
407
|
+
* 放弃重扫意味着滞留成员的批通知要等下次 session_start 才收敛,含滞留 id 的 warn
|
|
408
|
+
* 是唯一线索,debug 级排障不可见;后续事件零处理,下次 session_start 再收敛)。
|
|
409
|
+
* pi.on 无 off(0.84.4 实装)——disposed 标志包装兑现退订(scheduler extension
|
|
410
|
+
* index.ts subscribeSettled 同款先例)。P-settled 定谳(0.84.4 dist 实装证据):
|
|
411
|
+
* pi.on 为 per-extension 列表分发——loader.js `on()` 把 handler push 进
|
|
412
|
+
* extension.handlers.get(event) 数组(非覆盖),runner.js `emit()` 对全部
|
|
413
|
+
* extension 的全部 handler 逐一 await;故本注册与 ledger host 经
|
|
414
|
+
* piAdapter.onAgentSettled 注册的 settled 分发互不干扰,无需降级并入 host 链。 */
|
|
415
|
+
private armSettledRescan(): void {
|
|
416
|
+
if (this.settledRescanState !== null) return;
|
|
417
|
+
const state = { disposed: false, scans: 0 };
|
|
418
|
+
this.settledRescanState = state;
|
|
419
|
+
this.deps.getPi()?.on?.("agent_settled", async () => {
|
|
420
|
+
if (state.disposed) return;
|
|
421
|
+
state.scans += 1;
|
|
422
|
+
// await 完整补发序列(manifest 屏障 → 写账 → 落标):pi emit 对 handler 逐一
|
|
423
|
+
// await(P-settled 定谳,0.84.4 dist runner.js),async 化不改变分发语义。
|
|
424
|
+
const { outcome, waitingIds } = await this.runSyncCollectRecoveryScan();
|
|
425
|
+
if (outcome === "waiting" && state.scans < SETTLED_RESCAN_LIMIT) return;
|
|
426
|
+
state.disposed = true;
|
|
427
|
+
if (outcome === "waiting") {
|
|
428
|
+
// D6 #7b / SC-2:warn + 滞留成员 id(debug 级排障不可见——达限即批通知挂起至下次 session_start)
|
|
429
|
+
logger.warn(
|
|
430
|
+
`[subagents] E1 settled rescan: reached limit (${SETTLED_RESCAN_LIMIT}) with member(s) still running, disposed until next session_start`,
|
|
431
|
+
{ ids: waitingIds },
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// [E1 语义对齐 toNotifyRecord] 补发成员映射 syncRebuildToNotifyMember 拆至
|
|
438
|
+
// sync-rebuild.ts(变化轴:恢复批通知语义):one-shot 成功成员末条恒
|
|
439
|
+
// running+resumable(SP-5),直通 status 会让恢复批批头「0 finished」且丢
|
|
440
|
+
// patchFile 的 git-apply 指针——对齐后补发记录为 closed + outcome 物化 +
|
|
441
|
+
// patchFile 透传。调用点:runSyncCollectRecoveryScan。
|
|
442
|
+
}
|