---
name: unidesk-kafka
description: UniDesk Kafka 调试与事件链校对技能，覆盖 platform-infra Kafka 状态、topic/offset/group、codex stdio、AgentRun/HWLAB 事件映射、debug topic、离线 regenerate、隔离 replay、SSE/reducer 对账和事件丢失分层定位。用户提到 Kafka、topic、offset、consumer lag、Kafka replay/重放、离线重放、stdio event、agentrun.event、hwlab.event、事件丢失或要求用 CLI 校对事件链时使用。
---

# UniDesk Kafka 调试与重放

## 核心边界

- Kafka 运行事实由 `config/platform-infra/kafka.yaml` 与目标运行面共同拥有。
- 产品链路 topic 固定只读调查：
  - `codex-stdio.raw.v1`；
  - `agentrun.event.v1`；
  - `hwlab.event.v1`。
- 调试重建只能写隔离 topic：
  - `agentrun.event.debug.v1`；
  - `hwlab.event.debug.v1`。
- replay/regenerate 不得向产品 topic 追加事件，不得重置产品 consumer group，不得把 debug group 冒充产品消费证据。
- 同一个全局输入 topic 到同一个全局输出 topic 的 direct projector：
  - 跨 lane 实例必须使用同一个 consumer group；
  - 各 lane 面向自身客户端的 SSE fanout 必须使用彼此独立的 consumer group；
  - 禁止用 lane 专属 direct-projector group 重复消费全局输入并向全局输出写入同一事件。
- 优先使用应用生产 reducer/mapper 的 regenerate CLI；平台 `kafka tail` 只返回 hash/bytes，不能证明 payload 语义。
- 调查结论必须区分：
  - 源 stdio 未产生；
  - stdio→AgentRun reducer 丢失或降维；
  - AgentRun durable event→Kafka producer 丢失；
  - AgentRun→HWLAB mapper 丢失；
  - Kafka→SSE/reducer/read model 丢失或滞后。
- 版本、commit、schema/provenance 漂移只能作为 `warning`，不得阻塞用户业务或覆盖 durable terminal authority。

## Kafka-only 第二权威审计

- 声明产品链路为 Kafka-only 前，必须同时审计事件入口、终态来源和配置来源；SSE 已连接或收到一个 topic event 不能单独证明通过。
- 使用一次有界源码检索覆盖应用、renderer 和 owning YAML，再对命中做语义分类：

  ```bash
  rg -n -S \
    '(/events|/result|waitForTerminal|projectTerminal|runnerTrace|snapshot|terminalAuthority|POLL_INTERVAL|TERMINAL_TIMEOUT)' \
    <workbench-source-path> <renderer-source-path> <owning-yaml-path>
  ```

- 允许的路径：
  - 提交接纳与 cancel 使用有界 `POST`，只返回 session/trace/run/command identity 和接纳状态；
  - 非 UI 诊断读取 result/snapshot 时，必须与产品 reducer 隔离，不能写回消息、Trace 或 terminal 状态。
- 禁止的第二权威：
  - 轮询 AgentRun `/events` 或 `/result` 后补 UI event；
  - 从 `runnerTrace.events`、session/turn snapshot、read model 或 terminal result 合成 assistant、tool、terminal、final；
  - 把 `agentrun-command-result`、HTTP result、snapshot 或 projection read 声明为 Kafka-only UI terminal authority；
  - 在 owning YAML、renderer 或进程环境保留仅服务于 result/events polling 的 timeout、interval 或开关。
- 通过判定必须同时满足：
  - UI assistant、tool、terminal、final 只由产品 Kafka envelope 经 SSE 和同一 reducer 产生；
  - 正式 CLI 只从产品 SSE 路由观察业务 event；
  - 运行配置不存在 polling 参数，进程环境不存在对应 polling 变量；
  - AgentRun 或 CI/CD 不可用时明确报告 source blocker，不得启用 REST、snapshot、read-model 或 terminal-result fallback。

## 调查顺序

1. 固定 identity：记录 node/lane、business trace、OTel trace、session、run、command 和时间窗口。
2. 查 OTel stdio：统计 `codex_stdio.notification`、`tool_call.started|completed`、assistant delta 和 diff notification。
3. 查 AgentRun durable events：按 seq 分页，精确下钻 tool/diff/terminal event；不得只看默认前 20 条。
4. 查 Kafka control plane：确认 broker、topic ready、end offset 和相关 fixed group lag。
5. 怀疑重复投影时，先按同一 `sourceEventId` 聚合 `hwlab.event.v1`：
   - 一条 AgentRun durable event 对应多个 HWLAB envelope，且 `source`/producer 不同，直接判为多 projector 重复消费；
   - 同一 producer 重复出现时，再调查 offset commit、重试和幂等；
   - 上游 `agentrun.event.v1` 的 event id 唯一时，不再重复调查 provider、runner 或前端 reducer。
6. 先执行 `--no-publish`/`--dry-run` regenerate，对照源 frame 数、解析数、产出 event 数、拒绝原因和 lineage。
7. 需要跨 mapper 校对时，才把结果写入 debug topic，再由下一层从 debug topic regenerate；每层保存 count/hash/seq/type/tool identity。
8. 需要浏览器产品 reducer 校对时，使用 Workbench 隔离 debug replay；不得直接操作产品 SSE group。
9. 输出首个发生差异的层级和缺失 identity，不用后层缺失反推前层未产生。

## 受控 CLI

本技能遵循 `Skill(cli-spec)`。

平台状态与只读元数据：

```bash
bun scripts/cli.ts platform-infra kafka status --node NC01
bun scripts/cli.ts platform-infra kafka offsets --node NC01 --topic codex-stdio.raw.v1
bun scripts/cli.ts platform-infra kafka offsets --node NC01 --topic agentrun.event.v1 --group <group>
bun scripts/cli.ts platform-infra kafka tail --node NC01 --topic hwlab.event.v1 --limit 20
```

AgentRun 生产 reducer 重建：

```bash
bun scripts/cli.ts platform-infra kafka replay agentrun \
  --node NC01 \
  --lane nc01-v02 \
  --session-id <ses_agentrun_...> \
  --trace-id <trc_...> \
  --no-publish \
  -o json
```

- 该入口自动进入 YAML 选中的 AgentRun manager Pod：
  - 使用运行中 commit 自带的正式 `./scripts/agentrun kafka regenerate agentrun`；
  - 复用生产 reducer；
  - 同时读取源 topic 的 partition earliest/end offset；
  - 不要求 host 解析 cluster DNS；
  - 不创建 port-forward。
- 默认输出紧凑文本；机器读取使用 `-o json|yaml`。
- scan limit、应用读取 timeout 和短连接 grace 由 `config/platform-infra/kafka.yaml#management.replay` 控制。
- 当前只接受 `--no-publish` 或同义 `--dry-run`：
  - `mutation=false`；
  - `topicAppended=false`；
  - `valuesPrinted=false`。

HWLAB 生产 mapper 重建：

```bash
hwlab-cli kafka regenerate hwlab \
  --from kafka \
  --session-id <session> \
  --trace-id <trc_...>
```

Workbench 隔离 replay：

```bash
bun scripts/cli.ts web-probe observe command <observerId> \
  --type validateWorkbenchKafkaDebugReplay
bun scripts/cli.ts web-probe observe status <observerId> \
  --command-id <commandId>
```

## 网络平面

- Kafka cluster DNS 只在目标 k3s 网络内解析；host workspace 报 `getaddrinfo ENOTFOUND` 只说明网络平面错误，不是 topic 或事件缺失。
- 优先使用 `platform-infra kafka replay agentrun`：
  - CLI 从 `config/platform-infra/kafka.yaml` 选择 Kafka target；
  - CLI 从 `config/agentrun.yaml` 选择同 node 的 AgentRun lane；
  - CLI 在 manager 应用 Pod 内运行正式 replay。
- 运行镜像未携带应用 CLI 时，允许 operator 侧通过 `trans <node>:k3s kubectl ... port-forward` 建立有界临时诊断通道，再从同一 node 的 source workspace 使用显式 `--brokers 127.0.0.1:<port>` 调用正式 CLI：
  - 先确认端口只监听 loopback；
  - 只用于当前只读或 debug-topic 调试；
  - 完成或失败后立即关闭；
  - 不把 port-forward 作为长期入口或验收 authority。
- 禁止因 host 无法解析 cluster DNS 而改写 `/etc/hosts`、暴露 broker 公网端口或添加第二套 Kafka endpoint。

## Replay 校对字段

- stdio 层：frame count、method/type、tool name、call id、started/completed、exit、diff notification、source seq。
- AgentRun 层：event id、run seq、type、phase、command/tool identity、output hash/bytes、terminal。
- HWLAB 层：source event id/seq、mapped envelope id/type、trace/session/command lineage、terminal/final response。
- 浏览器层：server scanned/matched/delivered，client received/decoded/applied，deduplicated，timeline 与 terminal seal。
- 每层同时给出：
  - 输入数；
  - 接受数；
  - 拒绝数及 typed reason；
  - 输出数；
  - 首个缺失/不一致 identity；
  - `mutation`、`topicAppended` 和 `valuesPrinted`。

## 判定规则

- `classification` 必须使用 typed reason：
  - `matched`：生产 reducer 已生成调试事件；
  - `producer-not-written`：源 topic 从未有记录；
  - `retention-offset-empty-window`：partition 有历史 offset，但当前保留窗口为空；
  - `filter-mismatch`：读取到记录，但 session/trace/direction/method 不匹配；
  - `decode-schema-rejection`：记录存在，但 JSON 或 schema 无法解析；
  - `network-or-runtime-error`：集群网络面、broker Pod、应用 workload 或命令执行失败。

- stdio 有完整 tool/diff，但 regenerate 未产出对应 AgentRun event：归因 reducer/mapping。
- regenerate 能产出，但 durable `agentrun.event.v1` 缺失：归因 producer/durable append。
- AgentRun 产品 event 存在，而 HWLAB debug mapper不产出：归因 HWLAB mapper。
- 同一 AgentRun `eventId` 在 `hwlab.event.v1` 对应多个不同 producer 的 envelope：
  - 归因 direct projector consumer group 所有权错误；
  - owning YAML 中共享 projector group 是修复点；
  - 前端按 event id 去重只能作为显示层防御，不能作为根因修复。
- `hwlab.event.v1` 存在且 direct publish/fanout 数相等，但 UI/read model 缺失：归因 SSE/reducer/projection。
- `turn/diff/updated` 只保留 phase/correlation、不保留文件或变更摘要时，应报告为源映射降维；不能把它描述成“后续展示偶然漏了一条”。
- 直接答复没有工具调用时，不要求合成 tool event。

## 配合技能

- OTel trace 与跨服务 identity：`$unidesk-otel`。
- AgentRun durable resource/events：`$unidesk-agentrun`。
- Workbench 隔离 replay：`$unidesk-webdev`。
- 跨 host/k3s 临时诊断通道：`$unidesk-trans` 与 `$unidesk-daddev`。
- Kafka/YAML owner 或 Secret 变更：`$unidesk-ymalops`；本技能默认只读，不从运行面反解 Secret。
