# Widget 与概览新鲜度

> 核验版本：1.1.0；通道：stable；文档 ID：clients.widgets

Viat Widget 展示精简的**平台/项目运维概览**，不是任意应用仪表盘、实验室任务查看器、持续运行的监控代理，也不能用于执行脚本。本页覆盖稳定 **0.1 客户端 / server 1.1.0** 的 HTTP 读取路径。

**加密 APNs 概览快照不属于本稳定基线。** 普通 APNs 告警通知已经存在，但收到告警不代表实现了尚未发布的快照功能。稳定版客户端中不应寻找“接口/推送”Widget 数据来源选择器。

## 前置条件与首次设置

1. 按[客户端安装](../installation/clients.md)安装正确签名的应用及内嵌 Widget 扩展。Mac 应使用已安装应用，不是随意运行挂载 DMG 内的一份副本。
2. 打开 Viat，添加实例，以平台用户登录并选择自己所属项目。
3. 在 Home 成功加载概览，核对实例、项目和时间戳，再添加系统 Widget。
4. 通过操作系统的 Widget 界面添加 Viat。若提供实例选择器，选择目标保存实例。项目来自该实例在应用中的选择，不是独立的自定义业务查询编辑器。
5. 对比 Widget 与 Home 的标签、时间窗和时间戳。缓存值可能比当前界面旧。

设备或 Widget 进程必须能通过 HTTP(S) 访问实例。内网部署需要获准的网络/VPN 路径；不要仅为刷新 Widget 而开放未经认证的公网接口。

## 各字段的含义

| 字段 | 含义与限制 |
| --- | --- |
| 实例/项目标签 | 所选保存实例和项目；标签变化不是新服务端样本。显示时会缩短项目/实例名称。 |
| Window | 后台读取固定 `24h`；前台 Home 可选择其他窗口，不要把不同窗口的数字当同一测量比较。 |
| Requests | 服务端概览在该窗口统计的请求数，不是业务任务数或成功工作流步骤数。 |
| Server errors | 服务端错误数；紧凑载荷刻意不包含客户端错误数。 |
| p95 latency | 毫秒；没有请求时缺失。横线不是测得零延迟。 |
| Failing endpoints | 服务端失败端点列表的数量，不是所有曾经失败的端点。 |
| Failing schedules | 已启用且连续失败次数非零的调度数，不是所有历史失败次数。 |
| 更新时间 | 样本接收时间，以 Unix 时间记录、本地显示相对时间；仅重绘缓存不能推进此时间。 |

外部集群的业务任务仍在运行时，平台概览可能完全健康。这类任务应另建经过认证的状态 API/页面；Widget 概览令牌不能调用该业务接口。

## 刷新是调度请求，不是保证

Apple Widget 请求 **15 分钟**后生成下个 timeline，实际执行时机由 WidgetKit 决定；后台限制、网络、电量和系统策略均可能推迟。读取器使用受限概览凭据，请求 `GET /projects/{slug}/overview?window=24h`。

Apple 网络请求上限 **10 秒**，但 timeline 交付最多等待 **4 秒**。较短期限先到时，回调返回缓存，并丢弃迟到结果。这避免缓慢内网请求长期占住 Widget，不代表缓存是实时的。

Mac 的签名应用还有后台刷新 helper/LaunchAgent，请求的周期为 **900 秒**。安装位置和系统后台项目权限都重要。不要为掩盖旧数据而注册多个临时刷新循环，应先排查安装、权限以及设备到服务端的真实连接。Android 使用独立原生调度，Apple WidgetKit 时限不是 Android 的服务级保证。

刷新周期不是可用性 SLA。Widget 可见、应用登录成功或曾经取得成功样本，都不证明实例现在可达；操作前先看时间戳。

## 凭据边界

控制台登录为该次登录签发不透明的 `vso_` 概览令牌。Widget 读取器使用这个范围很窄的只读凭据，不使用普通 access/refresh token 对。服务端只允许它访问**项目概览路由**，仍要求该登录的用户属于目标项目。它不能列举所有项目、运行脚本、修改资源或调用任意业务 API。

显示 catalog 不含凭据；Apple reader 描述文件独立存在，包含应用共享组中的令牌，因为扩展不能使用应用普通的凭据访问路径。不要复制、公开或将此文件附到支持请求中。最小权限不代表令牌不是秘密。

读取结果刻意区分：

| 结果 | 读取器动作 | 用户恢复 |
| --- | --- | --- |
| 成功且合法的概览 | 接受新样本 | 核对项目、窗口和时间。 |
| `401` | 删除该 reader 条目 | 打开应用重新登录，取得有效新登录。 |
| `403` | 保留 reader 身份，清除所选项目指针 | 恢复成员关系，或在应用中选择其他可访问项目。 |
| 网络/超时/5xx/429 或无效响应 | 使用缓存回退 | 恢复网络/服务健康并等待后续刷新；不要为掩盖故障而重置凭据。 |

服务端登录退出/撤销会使其 reader 凭据失效。CLI 的 `auth logout` 是另一种操作：1.1.0 中只清理本地 CLI 状态，不撤销服务端会话，不能据此推断手机 Widget 的登录已经退役。

## 不暴露 Widget 令牌的排查

已有获准 CLI 平台会话时，用实际项目 slug 执行：

```sh
viat call --console --method GET '/projects/hello-lab/overview?window=24h'
```

命令先输出 HTTP 状态，再输出概览正文。检查 `project_slug`、`window` 和 `traffic` 对象。这是管理会话诊断，**不是**验证 Widget 独立 `vso_` 令牌仍有效。只能检查自己获准读取的项目，并按需替换 `hello-lab`。

| 现象 | 检查方向 |
| --- | --- |
| 现场 Wi-Fi 应用正常，离开后 Widget 旧 | 手机/Widget 没有到内网的路由。稳定模式不能仅靠 APNs 获取新概览。 |
| p95 显示横线 | 窗口可能没有请求，不要替换成零延迟。 |
| 数字合理但时间戳旧 | 可能是缓存回退或系统延迟刷新，不是新响应。 |
| 权限变化后项目不对 | 重新打开应用，核对实例、项目成员关系并重新选择。 |
| Mac 找不到 Widget 或从不更新 | 检查签名内嵌扩展、`/Applications` 安装及后台项目权限；按升级流程重装，不要覆盖运行中的扩展。 |
| 告警到了但概览旧 | 告警投递和 HTTP 概览刷新是不同路径。 |

## 退役 Widget 或账号

从桌面移除 Widget 不等于撤销服务端会话。退役账号/设备时，在应用中退出、按需移除实例，并通过平台会话控件撤销泄露会话。原生缓存/reader 清理用于阻止后续获权读取，但系统已经渲染的图像可能保留到重绘。

不要手工编辑缓存伪造新时间戳。设备泄露时，在实际签发方轮换/撤销凭据；删除本地 catalog 不足以完成处置。

## 核验依据

源码 `03751a67`：`client/src-tauri/src/{widget,widget_reader,widget_refresh,instances}.rs`、`client/src-tauri/gen/apple/ViatWidget/ViatWidget.swift`、`client/scripts/widget-refresh.plist` 及服务端 overview/auth handlers。原生时序与系统调度需要设备验收；本页记录源码核实的限制，不承诺刷新周期，也不代表本次新做了真机测试。
