/** * [ref] S1([ref] 决策卡死墙攻关):进程内 per-task「turn 最后活性时刻」——running 形 409 与 * GET /v1/runs/:id 读面的判别材料 `msSinceLastActivity` 的唯一数据源。 * * 【为什么需要它】run 行的 `updatedAt` 由 liveness heartbeat(独立 `setInterval`,runs.ts)推进—— * 它只证明 **server 进程**活着;turn 卡死在某个 await 上时心跳照走([ref] 推理缺陷的公开更正)。 * 「turn 真在推进」的证据 = ledger sink 的 durable append(text/tool/status/park/done 全族都过那一条 * 单写串行链)。cli 的 running 形保守臂([ref] C3)缺的就是这一维:没有它,「真忙的后台 run」与 * 「断连僵局」在 wire 上不可分辨,只能猜。 * * 【语义边界(与消费端约定,勿漂)】 * - **同副本 best-effort**:记录只活在本进程。跨副本命中(claim 持有者在别的副本)或本副本重启后 * ⇒ 读不到 ⇒ wire 键**诚实缺席**——缺席 = 「无法证明」,不是「不活」。绝不铸 0(0 会被读成 * 「刚刚还活着」,错误方向与 [ref] 「宁缺毋假」纪律同族)。 * - 不落库、不进 SQL 面:这是分诊提示,不是状态机输入;任何门/CAS/resume 判定都不许读它。 * * 【生命周期】终局**不主动清**——409 只在 `running` 行上消费本记录,终局行不进那个分支,残留无害; * 主动清反而制造「done append 已打点、行还没翻终态」窗口里的缺席假象。有界性由插入序近似 LRU 兜底 * (CAP 条,超限逐最老;每条 ≈ 60B,上限 ≈ 0.5MB,常驻可接受)。 * 🔴 但**新世代必须清**(codex S1-F2,2026-08-13):session purge 删行后客户端合法复用自带 taskId 重 * 提交——不清的话新 run 首次打点前会读到旧 run 的时刻 = 假「刚有活性」证据。清点 = 三个 createRun * 成功分支(routes/runs.ts + routes/tasks.ts×2,接线锚在 session-active-conflict-materials 测试)。 */ import type { RunBrainStatusSnapshot } from "./plugins/store-contracts.js"; /** 一次打点的读数。`kind` = 触发这次打点的 durable 事件类型;打点方拿不到类型(core 的 onActivity * 第五席、resume 腿的手动打点)⇒ 缺席,**绝不铸占位词** —— [ref] 的 `cancelContext.lastEventKind` * 会原样上 wire,一个编出来的 `"unknown"` 会被消费端读成「引擎真发过一条叫 unknown 的事件」。 * * `brainStatus` = 本 run 账本尾**最后一条** `status` 帧的判别五键([ref]/[ref]:重试相位早已在 * wire 上,server 侧不需要 core 新钩就能回答「已重试几次 / 在等什么」)。它是 **sticky** 的 —— * 后续别的事件(text/tool)打点**不清**它:问题是「上次大脑说了什么」,不是「上一条事件是不是大脑说的」。 */ export interface TurnActivity { at: number; kind?: string; brainStatus?: RunBrainStatusSnapshot; } /** * ledger sink 每次 durable append 时打点(装配点:runs.ts / routes/tasks.ts 的 createLedgerSink)。 * * @param kind 账本写口传得出事件类型就传([ref] 件3 的判别材料),传不出就省。 * @param statusData `status` 帧的**已投影**载荷(`trace/project.ts` 的 `brainStatusEventData` 产物)。 * 只有 `status` 那一路传;本函数从中挑出五键存起来,并 **sticky 保留**到下一条 status 帧到来。 * 之所以在这里挑而不是在 sink 里挑:挑法与存法同一个属主,sink 不必认识这个类型。 */ export declare function recordTurnActivity(taskId: string, kind?: string, statusData?: Record): void; /** * `brainStatusEventData` 的投影产物 → {@link RunBrainStatusSnapshot} 的五键子集。 * * 逐键**按型收**(不是整只透传):投影产物是给账本行用的宽面(还带 `detail` / `retryInMs` / * `eventId` / 身份键),而 `cancelContext` 是分诊便签 —— `detail` 是**模型/provider 的自由文本** * (已过 redactSecrets,但仍是宽面),不进这只小快照。非期望型的值一律丢(不铸)。 */ export declare function pickRunBrainStatus(data: Record | undefined): RunBrainStatusSnapshot | undefined; /** 最后活性时刻(epoch ms);无记录 ⇒ undefined(缺席语义见顶注)。 */ export declare function readTurnActivityMs(taskId: string): number | undefined; /** 最后一次打点的完整读数(时刻 + 事件类型);无记录 ⇒ undefined。[ref] 件3 的数据源。 */ export declare function readTurnActivity(taskId: string): TurnActivity | undefined; /** 测试隔离用(生产路径不调:终局不清的理由见顶注)。 */ export declare function clearTurnActivity(taskId: string): void; //# sourceMappingURL=turn-activity.d.ts.map