feat(admin): 时间轴只读权威键 + 自排筛选轴 + browser 面板图标(Y2+Y3+Y4 前端一并落)
- 时间轴:页首「已过保留期」的**唯一**判据改为 retentionBoundaryReached === true(truncated 只出
「未显示」);缺席(老后端)一句话都不说;删掉旧的 truncated+retentionEnabled+翻到底 启发式
- Backthink:筛选轴接上服务端 ?trigger=(客户端筛选保留作兜底)+ 自排闸用量行(三态文案)
- plugin/nav.ts 加 browser 图标
- 真机(隔离实例,46/46):翻页不重不漏、三种「必须 false」的权威键语义、**重启后 round 不重复**
⚠️ 未验:真机上没构造出权威键 true(需真有更早轮次被清扫)——别读成「真机验过 true」
This commit is contained in:
1 parent
e0a6bca501
commit
57d0e8c543
11 files changed
+490
-102
No files matched your search
@@ -125,6 +125,7 @@ export {
|
||||
adminObservabilityLogs,
|
||||
adminObservabilityMetrics,
|
||||
adminObservabilityTrace,
|
||||
adminSelfWakeStatus,
|
||||
adminSystemBackup,
|
||||
adminSystemRestore,
|
||||
adminSystemRevokeKeys,
|
||||
@@ -137,4 +138,6 @@ export type {
|
||||
AdminFlowTimelineResponse,
|
||||
AdminFlowTimelineRound,
|
||||
AdminFlowTurn,
|
||||
AdminSelfWakeGate,
|
||||
AdminSelfWakeStatus,
|
||||
} from "./api/adminSystem";
|
||||
@@ -43,9 +43,69 @@ export function adminObservabilityLogs(
|
||||
return request<AdminLogLine[]>(`/admin/observability/logs${q ? `?${q}` : ""}`);
|
||||
}
|
||||
|
||||
/** GET /api/v1/admin/backthink — persisted background-think records (newest first). */
|
||||
export function adminBackthink(limit?: number): Promise<BackthinkItem[]> {
|
||||
return request<BackthinkItem[]>(`/admin/backthink${limitQuery(limit)}`);
|
||||
/** GET /api/v1/admin/backthink?limit=&trigger= — persisted background-think records
|
||||
* (newest first).
|
||||
*
|
||||
* `trigger` 是**服务端**筛选(契约 v0.82,切片 C2;`design/12 §C.6`):取值域 =
|
||||
* 既有触发源 + `self_wake`(`heartbeat` / `startup` / `self_wake` / 事件主题
|
||||
* `iot.device_update` / `reminder.trigger` / `system.event`)。⚠️ 后端对白名单外的
|
||||
* 取值**如实 400**(`error.code = "invalid_trigger"`),**不静默忽略** —— 因此调用方
|
||||
* 只能传自己确实认识的值;省略 = 不过滤(返回全部,老行为逐字不变)。
|
||||
*
|
||||
* ⚠️ 历史拉取的筛选结果**不含**实时帧:WS 的 `backthink` 事件始终是全量的,
|
||||
* 面板必须**保留客户端筛选**兜住那一部分(见 Backthink.tsx)。 */
|
||||
export function adminBackthink(limit?: number, trigger?: string): Promise<BackthinkItem[]> {
|
||||
const qs = new URLSearchParams();
|
||||
if (limit && limit > 0) qs.set("limit", String(limit));
|
||||
if (trigger) qs.set("trigger", trigger);
|
||||
const q = qs.toString();
|
||||
return request<BackthinkItem[]>(`/admin/backthink${q ? `?${q}` : ""}`);
|
||||
}
|
||||
|
||||
/** 自排闸的**进程生效**口径与代码默认值(契约 v0.82 §4.10(e))。
|
||||
*
|
||||
* ⚠️ `limitIsDefault` / `windowIsDefault` 只表示「生效值**恰好等于**代码默认值」,
|
||||
* **不是**「`backthink.json` 里没写这个键」的断言(网关不读那个文件)。 */
|
||||
export interface AdminSelfWakeGate {
|
||||
/** 容量 1 的待跑槽是否被占用(有一轮自排排着队还没跑)。 */
|
||||
pending: boolean;
|
||||
/** 本窗口已用额度(与工具收据的 `used` 同一口径)。 */
|
||||
used: number;
|
||||
limit: number;
|
||||
windowSec: number;
|
||||
defaultLimit: number;
|
||||
defaultWindowSec: number;
|
||||
limitIsDefault: boolean;
|
||||
windowIsDefault: boolean;
|
||||
}
|
||||
|
||||
/** GET /api/v1/admin/backthink/self-wake 的响应(契约 v0.82 新增;只读、不审计,
|
||||
* owner/admin 档)。
|
||||
*
|
||||
* 三态**必须分开显示**(把「看不到」画成「已用 0 / 上限 0」就是把猜当事实):
|
||||
* - `available:false` ⇒ 本进程给不出快照(服务未接线 / 实现不提供读口 / 闸不在):
|
||||
* `gate` **缺席**、`reason` 说明原因;
|
||||
* - `available:true, running:false` ⇒ 已接线但不在运行(未启动或已停止):`gate`
|
||||
* 仍带配置面数字(上限/窗口/默认值),但此刻排不出新的一轮 —— `reason` 说明;
|
||||
* - `available:true, running:true` ⇒ 正常态。
|
||||
*
|
||||
* ⚠️ 它**不是写口**:调这两个旋钮要改 `$DATA_DIR/config/backthink.json` + 重启
|
||||
* (启动期读一次);`configFile` 只是相对落点(`config/backthink.json`)。 */
|
||||
export interface AdminSelfWakeStatus {
|
||||
available: boolean;
|
||||
running: boolean;
|
||||
reason?: string;
|
||||
configFile?: string;
|
||||
gate?: AdminSelfWakeGate;
|
||||
}
|
||||
|
||||
/** GET /api/v1/admin/backthink/self-wake — 自排闸的只读快照(本窗口已用 N / 上限 M)。
|
||||
*
|
||||
* 为什么有它:这个数字此前只出现在被拒那一轮的审计文案里(`backthink.self_wake.capped`
|
||||
* 的 result),也就是「已经被拒过一次」才第一次看得见。它是纯读:不写库、不落审计、
|
||||
* 读它不改变闸的状态。 */
|
||||
export function adminSelfWakeStatus(): Promise<AdminSelfWakeStatus> {
|
||||
return request<AdminSelfWakeStatus>("/admin/backthink/self-wake");
|
||||
}
|
||||
|
||||
/** 一条**已落盘轮次**的摘要(契约 v0.73 §4.11 的 `turns[]`)。面板用它渲染历史轮
|
||||
@@ -116,13 +176,13 @@ export interface AdminFlowTimelineRound {
|
||||
lanes: AdminFlowLane[];
|
||||
}
|
||||
|
||||
/** 链路**时间轴**端点的响应(契约 v0.80 §4.11.1;W1 的新出口)。
|
||||
/** 链路**时间轴**端点的响应(契约 v0.80 §4.11.1;v0.81 增量)。
|
||||
*
|
||||
* 🔴 **`truncated` 不等于「已过保留期」**(契约 §4.11.1(b).3 的原话):它的含义是
|
||||
* **「本次不是全部」** = `hasMore`(分页未到底)**或** 落盘源未接线(只剩内存最近一轮)。
|
||||
* 「更早的回合已过保留期」这句话的判据只能是 `retentionEnabled` + `retentionHours` +
|
||||
* `truncated` **三者一起读**,**不得**因为「返回的回合比想象中少」就断言被清扫了
|
||||
* —— 否则面板会对着一页**仍然可翻**的历史说「已过保留期」(本切片核出的成对契约缺陷)。 */
|
||||
* 🔴 **`truncated` 不等于「已过保留期」**(契约 v0.81 §4.11.1(a) 的定稿口径):它的含义
|
||||
* 是 **「本次不是全部」** = `hasMore`(分页未到底)**或** 落盘源未接线(只剩内存最近一轮)。
|
||||
* 「更早的回合已过保留期」这句话的判据**只能是** `retentionBoundaryReached === true`
|
||||
* ——🔴 **不得**再拿 `truncated` + `retentionEnabled` + 「翻到底了没」三者自己拼(那正是
|
||||
* v0.81 修掉的缺陷:一页还没拉完时面板会对着**仍然可翻**的历史说「已过保留期」)。 */
|
||||
export interface AdminFlowTimelineResponse {
|
||||
/** 解析后的会话(回显)。取数只认调用时给的 `sessionId`,不依赖这一键。 */
|
||||
sessionId?: string;
|
||||
@@ -137,11 +197,22 @@ export interface AdminFlowTimelineResponse {
|
||||
/** 库里**还有更早的回合**没被本次返回(= 还能继续翻页)。**这是唯一权威的翻页判据**;
|
||||
* 面板不要用「本页是否满页」去猜(满页的最后一页会被猜成「还有更早」,白打一次请求)。 */
|
||||
hasMore?: boolean;
|
||||
/** 本次**不是全部**:`hasMore`(分页未到底)或落盘源未接线。**不是**「已过保留期」。 */
|
||||
/** 本次**不是全部**:`hasMore`(分页未到底)或落盘源未接线。**不是**「已过保留期」
|
||||
* —— 面板据此标注「更早的轮次**未显示**」,说「已过保留期」请看下一行。 */
|
||||
truncated: boolean;
|
||||
/** 🆕 **v0.81**(契约 §4.11.1(a)):**该会话确有更早的轮次已被保留期清扫删掉**,
|
||||
* 且本次已取到它现存最早的一端。**只有它为 `true` 时**才可以说「更早的轮次已过保留期」,
|
||||
* 其余情形(含它 `false`)一律说「更早的轮次未显示」(`truncated`)或「只拿到最近一轮」
|
||||
* (`source:"live"`)。
|
||||
*
|
||||
* ⚠️ 缺席(老后端)= **不知道** —— 一律按最保守话术处理(不说过期),**不**拿别的键回推。
|
||||
* ⚠️ 它**少说也不说谎**:`false` **不等于**「没被清扫」(整段历史都被清扫 / 有轮次号未知
|
||||
* 的老行 / 最早那一轮落盘失败,三种盲区见契约 §4.11.1(a) 表)。 */
|
||||
retentionBoundaryReached?: boolean;
|
||||
/** `flow_graphs` 的保留期(小时,**下取整**)。`≤0` = 后端配置为不回收。 */
|
||||
retentionHours: number;
|
||||
/** 保留期清扫**是否启用**。`false` ⇒ 「更早的回合」**不是**被清扫掉的,别说成过期。 */
|
||||
/** 保留期清扫**是否启用**。`false` ⇒ 「更早的回合」**不是**被清扫掉的,别说成过期。
|
||||
* ⚠️ 它只说明「清扫开着」,**不说明「发生过清扫」**(判据见 `retentionBoundaryReached`)。 */
|
||||
retentionEnabled?: boolean;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user