@optima-chat/dev-skills 0.16.2 → 0.16.4
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/.claude/commands/logs.md +60 -3
- package/.claude/commands/trace-user.md +18 -6
- package/.claude/skills/cn-deploy/SKILL.md +5 -3
- package/.claude/skills/gateway-admin/SKILL.md +15 -0
- package/.claude/skills/logs/SKILL.md +10 -2
- package/.claude/skills/reset-onboarding/SKILL.md +116 -0
- package/.claude/skills/yzsgo-e2e/SKILL.md +51 -0
- package/.claude/skills/yzsgo-e2e/SYNC.md +10 -0
- package/.claude/skills/yzsgo-e2e/chat_driver.py +659 -0
- package/.claude/skills/yzsgo-e2e/judge_outcome.js +11 -0
- package/.claude/skills/yzsgo-e2e/judge_workflow.js +100 -0
- package/.claude/skills/yzsgo-e2e/preflight.py +44 -0
- package/.claude/skills/yzsgo-e2e/prep_conversation.py +21 -0
- package/.claude/skills/yzsgo-e2e/pull_wire.py +312 -0
- package/.claude/skills/yzsgo-e2e/run_e2e.py +122 -0
- package/.claude/skills/yzsgo-e2e/verify_drift.py +42 -0
- package/.codex/skills/cn-deploy/SKILL.md +5 -3
- package/.codex/skills/reset-onboarding/SKILL.md +116 -0
- package/.codex/skills/yzsgo-e2e/SKILL.md +51 -0
- package/.codex/skills/yzsgo-e2e/SYNC.md +10 -0
- package/.codex/skills/yzsgo-e2e/chat_driver.py +659 -0
- package/.codex/skills/yzsgo-e2e/judge_outcome.js +11 -0
- package/.codex/skills/yzsgo-e2e/judge_workflow.js +100 -0
- package/.codex/skills/yzsgo-e2e/preflight.py +44 -0
- package/.codex/skills/yzsgo-e2e/prep_conversation.py +21 -0
- package/.codex/skills/yzsgo-e2e/pull_wire.py +312 -0
- package/.codex/skills/yzsgo-e2e/run_e2e.py +122 -0
- package/.codex/skills/yzsgo-e2e/verify_drift.py +42 -0
- package/AGENTS.md +12 -6
- package/README.md +74 -61
- package/bin/helpers/cn-deploy.ts +44 -37
- package/bin/helpers/logs.ts +464 -31
- package/dist/bin/helpers/cn-deploy.js +43 -37
- package/dist/bin/helpers/logs.js +410 -31
- package/docs/superpowers/plans/2026-08-31-yzsgo-e2e.md +969 -0
- package/docs/superpowers/specs/2026-08-31-yzsgo-e2e-design.md +154 -0
- package/package.json +1 -1
package/.claude/commands/logs.md
CHANGED
|
@@ -218,7 +218,7 @@ aws logs get-log-events --log-group-name /ecs/commerce-backend-prod --log-stream
|
|
|
218
218
|
**访问方式**: ✅ **用 `optima-logs` CLI 直连阿里云 SLS**,不再经 buildbox。
|
|
219
219
|
|
|
220
220
|
> ✅ 现状更新(2026-06-16):cn-prod / cn-stage 全部服务**已接 SLS**(含 ECI 的 `agent-runtime`)。
|
|
221
|
-
> SLS `
|
|
221
|
+
> SLS `GetLogsV2` 是公网控制面 API,本机 `aliyun-optima` profile 直连即可,支持**历史检索 + 时间窗 + 关键词**——
|
|
222
222
|
> 旧的「SSH buildbox → SAE `DescribeInstanceLog` 取当前缓冲」流程已弃用(缓冲式、重启即丢、不能检索)。
|
|
223
223
|
|
|
224
224
|
**推荐用法(首选)**:
|
|
@@ -234,14 +234,71 @@ optima-logs gateway-core --since 30m --json | jq . # 机器可读
|
|
|
234
234
|
`service` == SLS logstore 名(同名)。列全部 logstore:
|
|
235
235
|
`aliyun sls ListLogStores --project optima-cn-prod-1911493506120573 --region cn-beijing --profile aliyun-optima`
|
|
236
236
|
|
|
237
|
+
#### 🔴 读数纪律(#75 / #57 两次误导生产级排障的直接病根)
|
|
238
|
+
|
|
239
|
+
前三条都属于「**看起来拿到了全部,其实只拿到一角**」——不是查错了,是**看不出被截断**;第 4 条是同一病根的另一面:查询被悄悄换了语义:
|
|
240
|
+
|
|
241
|
+
1. **`-n` 取满 ≠ 窗内只有这么多。** SLS 单次请求服务端硬顶 **100 条**(`GetLogs` / `GetLogsV2` 都是)(`--line 3000` 也只回 100)。`optima-logs` 已自动 `--offset` 翻页到 `-n` 要的条数,但**取满 `-n` 时会打 ⚠**:此时真实总数未知。
|
|
242
|
+
**两个都返回上限的查询相除,比值是纯噪声**——实测拿 30d 的 `timed out` / `dispatching` 相除得「100/100」,看着像 100% 失败率,缩窄到两边都 <100 后真数是 7/60 与 16/70。要计数就缩窄 `--since` 直到不再报 ⚠。
|
|
243
|
+
2. **请求 `--since 24h` ≠ 覆盖了 24h。** 取满 `-n` 时窗口被截在最新那一段。cn 侧**只要取到了行**,stderr 就会打**实际覆盖窗**(由 `__time__` 反算,北京时间),以它为准,别以 `--since` 为准。(零结果时没有覆盖窗可算,只打「无日志」;AWS 侧无此概念。)
|
|
244
|
+
3. **`--grep` 走 SLS 索引,不是本地正则**——正文没进索引的 logstore 上,搜正文里的词会**静默少回**:零命中不代表「没有报错」,非零命中也不是真实出现次数。
|
|
245
|
+
已知 **cn-stage 的 `agent-runtime`**:`content` 被建成 JSON 型索引且 `index_all: false`,只索引 26 个白名单键,**`message` 不在其中** ⇒ 正文里的词一个都搜不到。
|
|
246
|
+
**⚠ 盲区只覆盖「词出现在正文里」这一种。** 白名单键的**值**是进了索引的(`userId` / `sessionId` / `turnId` / `level` 都在里面),搜这些值命中数是准的——**工具替你判断不了你搜的词属于哪一种**,所以它只告诉你盲区存在,不替你下结论。
|
|
247
|
+
`optima-logs` 用了 `--grep` 会先查 `GetIndex`(权威直源,不靠试词猜),搜不到正文就**在结果之前**告警并列出索引键;**整条 query 只按索引键过滤时不告警**(那种查询与本盲区无关)。零命中**不会**被断言成「这个词不存在」——见下面「零命中能说明什么」。
|
|
248
|
+
|
|
249
|
+
<details><summary>本条的实测取数(钉死窗口,可原样复跑)</summary>
|
|
250
|
+
|
|
251
|
+
采样 2026-08-07,`cn-stage`/`agent-runtime`,窗口钉死 `from=1786029531 to=1786036731`(北京时间 08-06 23:18:51 ~ 08-07 01:18:51)。
|
|
252
|
+
```bash
|
|
253
|
+
P="--project optima-cn-stage-1911493506120573 --logstore agent-runtime --region cn-beijing --profile aliyun-optima"
|
|
254
|
+
W='"from":1786029531,"to":1786036731'
|
|
255
|
+
# a) 窗内真实总行数(分析语句,权威) → 166
|
|
256
|
+
aliyun sls GetLogsV2 $P --body "{$W,\"line\":1,\"offset\":0,\"query\":\"* | select count(*) as c\"}"
|
|
257
|
+
# b) --grep warm 命中 → 4
|
|
258
|
+
aliyun sls GetLogsV2 $P --body "{$W,\"line\":100,\"offset\":0,\"reverse\":true,\"query\":\"warm\"}"
|
|
259
|
+
# c) 按未索引键查 message → 0(message 不在白名单里)
|
|
260
|
+
aliyun sls GetLogsV2 $P --body "{$W,\"line\":100,\"offset\":0,\"reverse\":true,\"query\":\"content.message: warm\"}"
|
|
261
|
+
# d) 索引键白名单(26 个,无 message)
|
|
262
|
+
aliyun sls GetIndex $P | jq -r '.keys.content | .type, .index_all, (.json_keys|keys|join(","))'
|
|
263
|
+
```
|
|
264
|
+
b 的 **4** 对上 a 的 **166**:仅取最新 100 行的样本里就已有 **27 行**含 `warm`(本地统计,非索引)。
|
|
265
|
+
反向对照(**同一个钉死窗**,验证「按键查是准的」)——用 SQL 数以绕开单次 100 条上限:
|
|
266
|
+
```bash
|
|
267
|
+
# e) 按索引键查 level: info → 150;同窗 166 行本地统计 level=="info" 也是 150
|
|
268
|
+
aliyun sls GetLogsV2 $P --body "{$W,\"line\":1,\"offset\":0,\"query\":\"content.level: info | select count(*) as c\"}"
|
|
269
|
+
# f) 裸搜一个 userId(在白名单里) → 24;content.userId: <U> 也是 24;本地统计也是 24
|
|
270
|
+
U=54afca02-cb4c-4022-9e5b-b8dc3cda17d0
|
|
271
|
+
aliyun sls GetLogsV2 $P --body "{$W,\"line\":1,\"offset\":0,\"query\":\"$U | select count(*) as c\"}"
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
> **别把这组数抄进别处。** 同一组数曾在三份文件里手抄、已经漂成四个版本(24/22、28/26、27/16,以及 PR 正文那版 28——它数的是**不区分大小写**,多出的一行是 `Warm pool: session initialized`)。差异来自「窗内 100 行」其实只是 166 行里最新的 100 行,以及「只出现在 message」有好几种数法。**这里是唯一权威**;`SKILL.md`、`trace-user.md`、`--help` 只引用不复制,`logs.ts` 与测试里的注释可以引用具体数字,但必须与这里同源(同一钉死窗)。
|
|
275
|
+
</details>
|
|
276
|
+
|
|
277
|
+
**零命中能说明什么**(工具的措辞就到这一步,不再往前一步):索引正常时它只说「正文已进全文索引 ⇒ 不是『索引搜不到』那一类」,并提醒 SLS 按**完整 token** 匹配(分词表不含 `-` `_` `.`)——实测 `gateway-core`:`reconciler` **0 条**、`session-reconciler` **100+ 条**。要断定「真没有」请换完整 token,或去掉 `--grep` 拉原始行本地过滤复核。`GetIndex` 调不通时判 `unknown`,**既不告警也不背书**。
|
|
278
|
+
|
|
279
|
+
其它 logstore:cn-prod 的 `agent-runtime` 只有全文索引,正文可搜;cn-stage 的 `gateway-core` 是 `text` 型,也可搜。
|
|
280
|
+
|
|
281
|
+
4. **`--grep` 里的 `|` 不是「或」。** SLS 拿 `|` 分隔「检索 | 分析(SQL)」两段,`--grep 'timeout|error'` 会被 SLS 判成 SQL 并报错(工具会在 SLS 原文之下补一句人话说明;它**只给陈述、不生成可照抄的命令**——生成式处方要同时满足 bash 与 SLS 两套语法,试过两次都在「命令跑得通、查的却是另一条 query」上翻车)。要「或」写 `--grep 'timeout or error'`;要把整串当一个短语写 `--grep '"timeout|error"'`(带引号是合法检索,`meta.hasSQL=false`);要真跑 SQL 写 `--grep '… | select …'`,此时 SLS 规定 `line`/`offset` 失效 ⇒ `-n` 不起作用,翻页要用 SQL 自己的 `LIMIT`。
|
|
282
|
+
|
|
283
|
+
**数记录数不要用 `wc -l`**:`--json` 是 pretty-print 数组,一条记录就是十几到二十行(实测 `gateway-core` 100 条 = 1502 行,`agent-runtime` 约 18 行/条)。用 `grep -c '__time__'`。
|
|
284
|
+
|
|
285
|
+
**已知未覆盖**:SLS 全文索引有 `max_text_len` 截断,超长单行超出部分不进索引 ⇒ 超长日志行尾部的词仍可能搜不到,本工具不检测这一种。该值在 `GetIndex` 的**顶层**(不在 `.line` 里),可直接复核:
|
|
286
|
+
```bash
|
|
287
|
+
aliyun sls GetIndex --project optima-cn-stage-1911493506120573 --logstore gateway-core \
|
|
288
|
+
--region cn-beijing --profile aliyun-optima | jq .max_text_len # → 16384(2026-08-07 采样)
|
|
289
|
+
```
|
|
290
|
+
(`progress: Incomplete`「查询未扫完」已覆盖:改用 `GetLogsV2` 后 `meta.progress` 可读,非 `Complete` 会打 ⚠;**响应里读不到这个字段时判 unknown 并单独打 ⚠**,不当成「扫完了」。)
|
|
291
|
+
|
|
237
292
|
**底层(仅参考,正常用 `optima-logs` 即可)**:
|
|
238
293
|
- SLS project:`optima-cn-prod-1911493506120573` / `optima-cn-stage-1911493506120573`(`optima-<env>-<accountId>`)。
|
|
239
294
|
- logstore = service 名;日志正文在 `content` 字段。
|
|
295
|
+
- **直连要用 `GetLogsV2`**:只有它返回 `meta.progress` / `meta.count`。V1 的 `GetLogs` 拿不到「本次查询扫完没有」,`Incomplete` 与「窗内就这么多」在 V1 下完全无法区分。
|
|
240
296
|
```bash
|
|
241
297
|
NOW=$(date +%s); FROM=$((NOW-3600))
|
|
242
|
-
aliyun sls
|
|
243
|
-
--from
|
|
298
|
+
aliyun sls GetLogsV2 --project optima-cn-prod-1911493506120573 --logstore gateway-core \
|
|
299
|
+
--body "{\"from\":$FROM,\"to\":$NOW,\"line\":100,\"offset\":0,\"reverse\":true,\"query\":\"error\"}" \
|
|
244
300
|
--region cn-beijing --profile aliyun-optima
|
|
301
|
+
# 单次仍硬顶 100 条 → 要更多就 offset 递增翻页;每次都看一眼 meta.progress 是不是 Complete
|
|
245
302
|
```
|
|
246
303
|
|
|
247
304
|
## 完整示例脚本
|
|
@@ -117,9 +117,14 @@ aws logs start-query \
|
|
|
117
117
|
|
|
118
118
|
### 2. cn-stage / cn-prod(阿里云 SLS,首选 `optima-logs`)
|
|
119
119
|
|
|
120
|
-
> SLS `
|
|
120
|
+
> SLS `GetLogsV2` 是公网控制面 API,本机 `aliyun-optima` profile 直连即可,支持历史检索+时间窗+关键词。
|
|
121
121
|
> SLS project:`optima-cn-stage-1911493506120573` / `optima-cn-prod-1911493506120573`;logstore == service 名;正文在 `content`。
|
|
122
122
|
|
|
123
|
+
> 🔴 **本节的一切计数/求和/平均,先读 `optima-logs` 打在 stderr 上的那几行再用**(完整规则见 `.claude/commands/logs.md` 第 3 节「读数纪律」,即 `/logs` 命令文档;那里是唯一权威,不是 `--help` 输出)。三条与本 runbook 直接相关的:
|
|
124
|
+
> 1. **SLS 单次请求硬顶 100 条**(`--line 3000` 也只回 100)。`optima-logs` 已自动 `--offset` 翻页到 `-n`,但**取满 `-n` 时会打 ⚠ = 真实总数未知**。下面那些 `-n 1200` / `-n 2000` 的统计配方,见到 ⚠ 就说明分母被截断了——**此时「调用次数 / token 合计 / 平均延迟 / stop 分布」全是在一个截断样本上算的**,缩窄 `--since` 到不再报 ⚠ 再用。(本文档 2026-08-07 之前的版本写于翻页修好之前,那时这些配方**实际只拿得到 100 条**。)
|
|
125
|
+
> 2. **请求 `--since 1h` ≠ 覆盖了 1h**:以 stderr 打出的**实际覆盖窗**为准。
|
|
126
|
+
> 3. **`--grep` 是 SLS 服务端索引检索,不是本地正则**:cn-stage 的 `agent-runtime` 正文(`message`)没进索引,搜正文里的词会静默少回;工具会在结果前告警。**但 `userId` / `sessionId` / `turnId` / `level` 都在索引白名单里,下面这些按 ID 查的配方不受影响**(实测钉死窗 `1786029531..1786036731`:`--grep <userId>` 回 24 条 == 同窗本地统计 24 条;复跑命令见上述唯一权威处)。
|
|
127
|
+
|
|
123
128
|
```bash
|
|
124
129
|
# 第一步(核心):agent-runtime —— 拉该用户全部 LLM/tool/turn 结构化日志
|
|
125
130
|
optima-logs agent-runtime --env {cn-stage|cn-prod} --since {TIME_RANGE} --grep "USER_ID" -n 500 --json
|
|
@@ -135,14 +140,17 @@ optima-logs agent-runtime --env cn-stage --since 1h --grep "turn-xxxx-xxxx" -n 2
|
|
|
135
140
|
optima-logs agent-runtime --env cn-stage --since 1h --grep "USER_ID" -n 500 --json \
|
|
136
141
|
| jq '.[] | (.content|fromjson?) | select(.level=="error" or .level=="warn")'
|
|
137
142
|
|
|
138
|
-
#
|
|
139
|
-
#
|
|
143
|
+
# 底层(一般不用,且拿不到 optima-logs 的翻页/告警):--line 传多少都只回 100 条,
|
|
144
|
+
# 要更多必须自己 --offset 翻页;且必须用 GetLogsV2——只有它返回 meta.progress
|
|
145
|
+
# (「本次查询扫完没有」),V1 的 GetLogs 下 Incomplete 与「窗内就这么多」无法区分。
|
|
146
|
+
# aliyun sls GetLogsV2 --project optima-cn-stage-1911493506120573 --logstore agent-runtime \
|
|
147
|
+
# --body "{\"from\":$FROM,\"to\":$NOW,\"line\":100,\"offset\":0,\"reverse\":true,\"query\":\"USER_ID\"}" \
|
|
140
148
|
# --region cn-beijing --profile aliyun-optima
|
|
141
149
|
```
|
|
142
150
|
|
|
143
151
|
> **解析 `--json` 输出(重要)**:`optima-logs ... --json` 返回**一个 JSON 数组**,每个元素是 SLS 记录(带 `__source__`/`eci_id`/`_image_name_` 等元字段),**结构化日志正文是 `.content` 字段里的 JSON 字符串**。所以解析模式固定是 `.[] | (.content|fromjson?)`,再 select 业务字段。元字段 `_image_name_` 还能顺带看是哪个镜像 digest 的容器在服务。
|
|
144
152
|
|
|
145
|
-
**一条龙拼装 + 统计的 canonical
|
|
153
|
+
**一条龙拼装 + 统计的 canonical 配方**(形状实测可用;🔴 **下面第二条是聚合统计,用之前先看 stderr 有没有 ⚠ 取满 `-n`**——有就说明分母被截断,这些数不能当真实总量,缩窄 `--since` 重跑):
|
|
146
154
|
```bash
|
|
147
155
|
U=<USER_ID>
|
|
148
156
|
# 时间线:每次 LLM 调用一行(model / token / 延迟 / cache / stopReason),按 turn
|
|
@@ -164,7 +172,10 @@ optima-logs agent-runtime --env cn-stage --since 1h --grep "$U" -n 2000 --json \
|
|
|
164
172
|
```
|
|
165
173
|
|
|
166
174
|
> ⚠️ cn 多数 agent-runtime 日志只带 `userId` 不带 `userEmail`。若输入 email,先去 user-auth 换 userId(见 query-db / account 技能),再用 userId 查。
|
|
167
|
-
> ⚠️ `--grep` 是 SLS
|
|
175
|
+
> ⚠️ `--grep` 是 **SLS 服务端索引检索**(不是全文正则、也不是本地过滤)。userId/sessionId/turnId 都是高区分度**完整 token** 且都在 cn-stage `agent-runtime` 的索引白名单里,直接 grep 即可精确命中。
|
|
176
|
+
> ⚠️ 但**别拿它搜日志正文里的词**(`message` 里的 `warm` / `timeout` 之类)——那个 logstore 的正文没进索引,会静默少回;`optima-logs` 会在结果前告警。要按正文过滤就去掉 `--grep`、拉原始行本地 `jq` / `grep`。
|
|
177
|
+
> ⚠️ SLS 按**完整 token** 匹配(分词表不含 `-` `_` `.`),搜子串必然零命中——`reconciler` 命不中 `session-reconciler`。零命中先怀疑这个,别急着下「没发生」。
|
|
178
|
+
> ⚠️ `--grep` 里的 `|` 不是「或」(SLS 拿它分隔「检索 | 分析(SQL)」)。要或写 `--grep 'a or b'`。
|
|
168
179
|
|
|
169
180
|
---
|
|
170
181
|
|
|
@@ -273,7 +284,8 @@ token: 输入 12,840 输出 4,210 缓存命中率 99.3%
|
|
|
273
284
|
|
|
274
285
|
## ⭐ 错误视图(最高频需求)
|
|
275
286
|
|
|
276
|
-
> **核心技术**:`optima-logs --grep <kw>` 是 **SLS
|
|
287
|
+
> **核心技术**:`optima-logs --grep <kw>` 是 **SLS 服务端过滤**,检索范围是整个 `--since` 窗口。日志正文是 `"level":"error"` 这样的 JSON,`level` 在两侧 `agent-runtime` 都可搜,所以 `--grep error` / `--grep warn` 命中的是 level 字段。
|
|
288
|
+
> 🔴 **但「检索全窗」≠「拿回全窗」**:SLS 单次请求硬顶 **100 条**,`optima-logs` 靠 `--offset` 翻页补到 `-n`,**取满 `-n` 时会打 ⚠ = 还有没拿回来的**。所以下面这些 `-n 300` 的查询,见到 ⚠ 就**不是**「全窗 error/warn 全抓到了」,而是「最新 300 条」。要断言「一共出了 N 个错」必须先缩窄 `--since` 到不再报 ⚠,或改用分析语句 `--grep '<kw> | select count(*)'` 让 SLS 自己数。
|
|
277
289
|
> **降噪**:以下属基础设施噪声,默认过滤掉(除非排查它们):`CLI binary name collision`、`Multi-source cache all-miss`、`Runtime other than "optima" is deprecated`、`cache.load miss: ENOENT`。
|
|
278
290
|
|
|
279
291
|
### 查询 A:给一个用户 → 他出过哪些错
|
|
@@ -30,7 +30,7 @@ optima-cn-deploy --list # 列出全部可发服务
|
|
|
30
30
|
7. **build-only 服务(`agent-runtime`)**:非 SAE 常驻(gateway-core 按 session 拉起的镜像)。成功标准不是 SAE ImageUrl,而是流水线绿即可——release 段自动把 ACR digest 回写 Infisical `/services/gateway-core/ALIYUN_AGENT_RUNTIME_IMAGE`(#807) 并滚动重启 gateway-core(任一步失败即 exit 非 0)。工具最后一行为 `✓ 流水线 SUCCESS(build-only)…` —— CLI 以流水线终态为准,未独立校验 Infisical/gateway-core(digest 与重启变更单见 run『发版』段日志)。
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
## cn-prod vtag
|
|
33
|
+
## cn-prod vtag 发版(通路已跑通;清单外的服务仍算首发)
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
36
|
optima-cn-deploy <service> --vtag cn-v1.2.3 # 先 stage 同 tag 验证
|
|
@@ -38,9 +38,11 @@ optima-cn-deploy <service> --env prod --vtag cn-v1.2.3 # prod 发版
|
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
- prod 是 vtag 制:必须先 `git tag cn-vX.Y.Z && git push`,工具拒绝无 vtag / 裸 v* / 带 --branch 的 prod 请求
|
|
41
|
-
- prod
|
|
41
|
+
- 🔴 prod 流水线**没有人工卡点**:构建 → DB 迁移 → digest 钉死部署一路自动走完,不会停下来等谁审批。**敲下命令那一刻就是最终决策点**;触发后要中止只能去云效 run 页面手动取消(实测 2026-08-09,见 #89)
|
|
42
42
|
- 成功标准:prod SAE ImageUrl 为 `@sha256:` digest 寻址(工具最后一行校验)
|
|
43
|
+
- ⚠️ **老路径会盖掉 digest**:云效 prod 钉的是 `@sha256:` digest,buildbox `cn-deploy.sh` 发的是 `:<sha>` tag,后发的覆盖先发的。发版后隔天复查一次 SAE ImageUrl:已从 digest 变回 tag 形态即为被老路径覆盖,需重跑云效 prod 流水线(2026-07-31 一天内见 3 例,`cn-deploy.sh` 下线前一直存在)
|
|
43
44
|
- 用户请求发 cn-prod 时:确认已有 stage 验证过的 cn-v tag;没有则先引导走 stage
|
|
45
|
+
- **已发过 prod 的服务**(2026-07-14 起,截至 2026-07-31):`commerce-backend`、`optima-scout`、`optima-generation`、`optima-generation-worker`、`browser-backend`(最近一次 2026-07-30 browser-backend cn-v1.0.0 全绿)。**不在此列的一律当首发处理**:避开业务高峰、**触发之前**找 xbfool/svenyang 人工确认(没有卡点可以事后补,见上条)、发完立刻校验 ImageUrl
|
|
44
46
|
|
|
45
47
|
## 前置依赖
|
|
46
48
|
|
|
@@ -49,5 +51,5 @@ optima-cn-deploy <service> --env prod --vtag cn-v1.2.3 # prod 发版
|
|
|
49
51
|
|
|
50
52
|
## 边界
|
|
51
53
|
|
|
52
|
-
- cn-prod 仅走 vtag
|
|
54
|
+
- cn-prod 仅走 vtag 制(见上);**没有人工卡点闸门** —— 工具侧那道 vtag 校验(拒绝无 vtag / 裸 `v*` / 带 `--branch` 的 prod 请求)就是最后一道闸。日常无 vtag 的构建只发 cn-stage。
|
|
53
55
|
- 服务注册表是 optima-terraform `alicloud/stacks/cn-prod-buildbox/yunxiao/` 的快照;新增服务先在那边 gen-pipelines 建好流水线,再同步本工具的 SERVICES 表。
|
|
@@ -7,6 +7,21 @@ description: 当用户请求操作 gateway 管理面时使用——COO kill/软
|
|
|
7
7
|
|
|
8
8
|
当用户要求「杀掉某用户的 COO / 软杀容器 / drain warm pool / 查 gateway 配置 / 调 llm 费率 / 管理 provider key」等 gateway 管理面操作时,使用 `optima-gateway-admin` CLI。
|
|
9
9
|
|
|
10
|
+
## 🔴🔴 warm-pool `drain?mode=hard` = 掐正在服务的用户会话(禁止用于发布验证)
|
|
11
|
+
|
|
12
|
+
`POST /admin/warm-pool/drain?mode=hard` 退的**不是**空闲 pod,是**连 ready + assigned + active 一起退**——即**正在服务用户的会话容器**。active 容器不在 60s 自退 → OrphanDetector `cleanup retire-stuck` → `deleteContainerGroup` 强删 → **在飞 turn 当场 abort(含 HITL 提问被打断)**,用户侧表现为「agent 停了」。
|
|
13
|
+
- 实证(gw#2357):2026-08-31 cn-prod 6 次 hard drain 每次掐 **7–12 个真实用户会话**;另 07:26/07:28Z 的网关重启抖动亦冲掉真实在飞会话(本 skill 作者用 conversation-IQ 实锤,gw#1842/#1227)。
|
|
14
|
+
- ⇒ **hard drain 仅事故止血用,日常与发布验证一律禁用。** 真要 drain 也先 `mode=soft`(只退空闲、不碰在跑会话)。cn-prod 上 hard drain 前必须先 `GET /admin/warm-pool/tasks` 数一眼有多少 active(带 sessionId 的即真实会话),确认要掐几个用户再决定。
|
|
15
|
+
|
|
16
|
+
## ✅ 发布 skill 后如何验证「最新版已生效」——**不要 recycle / drain warm pool**
|
|
17
|
+
|
|
18
|
+
🔴 **skill 不是 warm pod 的属性**:marketplace skill 在会话 **claim 之后**(`task_connected`)由 gateway 现算 desired 下发,agent 按用户 NAS 里的 `.plugin-version` 比对、不同才重下;ready 状态的 warm pod 里**没有任何用户 skill**。
|
|
19
|
+
⇒ **publish 后下一次新建会话就会拉到新版,drain/recycle 完全无关**(且会误伤在跑用户)。验证走这三个只读入口:
|
|
20
|
+
- 镜像(烘死的 builtin pack)换代:`optima-gateway-admin GET /admin/runtime/images --env cn-prod`(看 `rotationComplete` / `@sha256`)
|
|
21
|
+
- 某会话实际派了哪版 skill:`optima-logs gateway-core --env cn-prod --grep "Skill sync dispatched"`(看 `plugins:[...]` 版本)
|
|
22
|
+
- 最直接:**新开一个会话**、load 目标 skill,看拿到的版本号。
|
|
23
|
+
- 长寿会话内热换代靠 `SKILL_SYNC_REFRESH_TTL_MS`(默认 0=关),不是靠 drain。
|
|
24
|
+
|
|
10
25
|
## 用法
|
|
11
26
|
|
|
12
27
|
```bash
|
|
@@ -184,9 +184,17 @@ INFO - Database query took 3200ms: SELECT * FROM products WHERE...
|
|
|
184
184
|
|
|
185
185
|
**特点**:
|
|
186
186
|
- 阿里云 **SLS**(日志服务,cn-beijing),不是 AWS CloudWatch
|
|
187
|
-
- ✅ 用 `optima-logs <svc> --env cn-prod` **直连 SLS**(`aliyun sls
|
|
187
|
+
- ✅ 用 `optima-logs <svc> --env cn-prod` **直连 SLS**(`aliyun sls GetLogsV2`,公网控制面 API)——免 buildbox 跳板,支持历史检索 + 时间窗(`--since`)+ 关键词(`--grep`)
|
|
188
188
|
- 前置:本机需装 `aliyun` CLI + `aliyun-optima` profile(cn-beijing)
|
|
189
|
-
- 旧的「buildbox → SAE `DescribeInstanceLog` 取当前缓冲」已弃用(缓冲式、重启即丢、不能检索);技术细节见 `/logs
|
|
189
|
+
- 旧的「buildbox → SAE `DescribeInstanceLog` 取当前缓冲」已弃用(缓冲式、重启即丢、不能检索);技术细节见 `.claude/commands/logs.md`(即 `/logs` 命令文档)第 3 节
|
|
190
|
+
|
|
191
|
+
**🔴 cn 侧读数纪律(下结论前必看,详见 `.claude/commands/logs.md` 第 3 节;`--help` 里只有摘要)**:
|
|
192
|
+
|
|
193
|
+
- **`-n` 取满 ≠ 窗内只有这么多**:SLS 单次请求硬顶 100 条,工具已自动翻页,但取满 `-n` 时会打 ⚠——此时真实总数未知,**别拿这批数做计数或算比值**(两个都触顶的查询相除,比值是纯噪声)。要计数就缩窄 `--since` 到不再报 ⚠。
|
|
194
|
+
- **请求 `--since 24h` ≠ 覆盖了 24h**:以 stderr 打出的**实际覆盖窗**为准,不是以 `--since` 为准。
|
|
195
|
+
- **`--grep` 走 SLS 索引、不是本地正则**:正文没进索引的 logstore 上搜正文里的词会**静默少回**——零命中不代表「没有报错」,非零命中也不是真实次数(已知 **cn-stage 的 `agent-runtime`**:`content` 是 JSON 型索引、只覆盖 26 个白名单键,`message` 搜不到)。**但盲区只覆盖「词出现在正文里」这一种**:白名单键的值(`userId` / `sessionId` / `turnId` / `level`)搜起来是准的。工具用 `GetIndex` 直查后会在结果前告警,**看它给的结论**;纯按键查(`--grep 'content.level: error'`)不受影响、也不告警。实测取数与复跑命令**只维护在** `.claude/commands/logs.md` 第 3 节「读数纪律」第 3 条(即 `/logs` 命令文档,不是 `--help` 输出),本页不复制(同一组数曾三处手抄、漂成多个版本)。
|
|
196
|
+
- **`--grep` 里的 `|` 不是「或」**:SLS 拿它分隔「检索 | 分析(SQL)」。要或写 `'a or b'`,要整串当短语写 `'"a|b"'`,要 SQL 写 `'… | select …'`(此时 `-n` 失效,用 SQL `LIMIT`)。
|
|
197
|
+
- **数记录数用 `grep -c '__time__'`,不要用 `wc -l`**(`--json` 是 pretty-print,一条记录十几到二十行)。
|
|
190
198
|
|
|
191
199
|
## 支持的服务列表
|
|
192
200
|
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "reset-onboarding"
|
|
3
|
+
description: "当用户请求重置某账号的 onboarding 资格、让账号重新体验新手引导/问卷、再触发一次 onboarding、重开引导运行(guided run)、重置 guided_run_grant 时,使用此技能。支持 cn-prod、cn-stage 两个环境;标识符支持手机号/邮箱/userId。"
|
|
4
|
+
allowed-tools: ["Bash"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 重置 onboarding 资格(让账号重新触发新手引导问卷)
|
|
8
|
+
|
|
9
|
+
让某账号「进入页面再次自动弹出 onboarding 问卷」。cn-prod 与 cn-stage 机制相同,只换环境参数与前端域名(cn-prod = `https://app.yzsgo.com`,cn-stage = `https://app.stage.optima.chat`)。
|
|
10
|
+
|
|
11
|
+
## 门控机制(缺一不弹)
|
|
12
|
+
|
|
13
|
+
前端 `useShowOnboardingTree`(agentic-chat)要求**全部**满足:
|
|
14
|
+
|
|
15
|
+
1. 服务端资格:billing 库 `guided_run_grant` 判出 `sponsorshipAvailable === true`,公式 `(granted - used) > 0 && spent_credits < cap_credits`(cap 默认 2000)
|
|
16
|
+
|
|
17
|
+
2. 有 userId
|
|
18
|
+
3. **当前打开的会话无 user 消息**——开个新会话即满足,无需删旧会话
|
|
19
|
+
4. 客户端浏览器 localStorage 无「已提交/已跳过」锁
|
|
20
|
+
|
|
21
|
+
> ### ⏳ optima-gateway#1998 换档中——本文所有 SQL 有两版,按现网是否已建列选
|
|
22
|
+
>
|
|
23
|
+
> `optima-gateway#1998` 给 billing 加了两列装 **LLM 花费**:`guided_run_grant.spent_credits_llm`、`sponsored_window.window_spent_credits_llm`。**列建好之后**,cap 判据口径变成两列相加,本 skill 的 SQL 全部要跟着改,否则会看到 `spent_credits=0` 以为重置成功、而资格依旧开不出来。
|
|
24
|
+
>
|
|
25
|
+
> **先判断现网建列了没**(一条命令,两个环境各跑各的):
|
|
26
|
+
> ```bash
|
|
27
|
+
> optima-query-db billing "SELECT COUNT(*) FROM information_schema.columns WHERE column_name='spent_credits_llm'" <env>
|
|
28
|
+
> ```
|
|
29
|
+
> - 返回 **0** → 用本文正文里的 SQL(当前状态,2026-08-07 两环境均为 0)
|
|
30
|
+
> - 返回 **1** → 每条 SQL 都按其下方的「🆕 建列后版本」替换
|
|
31
|
+
>
|
|
32
|
+
> ⚠️ 列建好后 cap 默认值也会从 **2000** 换成 **8000**(配一条把存量 `cap_credits=2000` 抬上去的 migration)。**以查出来的 `cap_credits` 实际值为准**,别照记默认数。
|
|
33
|
+
|
|
34
|
+
所以重置分**两层**:服务端 SQL(我方执行)+ 客户端 localStorage(只能操作浏览器的人自清)。
|
|
35
|
+
|
|
36
|
+
## 执行步骤(服务端)
|
|
37
|
+
|
|
38
|
+
全程用 `optima-query-db`,`<env>` 取 `cn-stage` / `cn-prod`,作为第 3 个位置参数(如 `optima-query-db billing "..." cn-stage`)。
|
|
39
|
+
|
|
40
|
+
**凭证按 `query-db` skill 的方式准备即可,本技能不需要额外 `source` / `export`**:本机若有 `~/.infisical_cn_creds` 和 `~/.buildbox_pw`,工具会自己读取(`bin/helpers/db-utils.ts` 的 `loadCredsFileIntoEnv()` / `readBuildboxPwFile()`,文件不存在即无操作);没有则从 1Password 取 `INFISICAL_CN_EMAIL`、`INFISICAL_CN_PASSWORD`、`OPTIMA_CN_BUILDBOX_PASSWORD` 三个值 `export` 到当前 session(推荐,不落盘)。缺哪个命令会自己报错并提示来源。
|
|
41
|
+
|
|
42
|
+
**① 标识符 → uid,同时拿到可供人工核对的身份**(手机号/邮箱查 user-auth)。注意 cn-prod 与 cn-stage 是独立库,同一手机号两边 uid 不同:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
optima-query-db user-auth "SELECT id, phone, email FROM users WHERE phone='<手机号>'" <env>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
> **用户直接给了 uid 也不要跳过 ①**,改成按 uid 反查、把手机号/邮箱拿到手——②(`guided_run_grant`)的回显只有 `user_id`,自己证明不了自己是谁:
|
|
49
|
+
>
|
|
50
|
+
> ```bash
|
|
51
|
+
> optima-query-db user-auth "SELECT id, phone, email FROM users WHERE id='<uid>'" <env>
|
|
52
|
+
> ```
|
|
53
|
+
|
|
54
|
+
**② 查 grant 现状**(确认目标账号,防止重置错人):
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
optima-query-db billing "SELECT user_id, granted, used, cap_credits, spent_credits, updated_at FROM guided_run_grant WHERE user_id='<uid>'" <env>
|
|
58
|
+
# 🆕 建列后版本:把选择列表换成 ..., spent_credits, spent_credits_llm, updated_at ...
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
> 回显里同时确认 `granted > 0`——若 `granted=0`,重置本身就是无效的(资格公式 `(granted-used)>0` 仍不成立),③ 的 `AND granted > 0` 会让 UPDATE 影响 0 行。若查不到行或 `granted=0`:该账号从未被授予引导资格,不属「重置」范畴——发放 grant 走 billing 侧逻辑,找 billing owner 确认。
|
|
62
|
+
|
|
63
|
+
**③ 重置——`used` 和 `spent_credits` 都要清、缺一不可**(只清 `used`、若 `spent_credits` 已烧到 cap 则资格仍是 false)。
|
|
64
|
+
> 🔴 **建列后要清三个**:`optima-gateway#1998` 的 `spent_credits_llm` **终身累计、无任何自动 reset 点**,而反复重跑的 QA/回归号正是最容易把它烧满的一批。漏清它 = 你会看到 `spent_credits=0` 以为成功、而资格依然开不出来——与上面这句告警一模一样,只是换了个列名。
|
|
65
|
+
|
|
66
|
+
> 🔴 **跑这条 UPDATE 前必须完成的两条硬性前置**(写操作不可撤销,`cn-prod` 是生产库尤其如此;cn-stage 一样照做,别把下面两条当 cn-prod 专属):
|
|
67
|
+
>
|
|
68
|
+
> 1. 已跑 ① 拿到该 uid 的手机号/邮箱,**并念给用户、拿到明确确认「就是这个账号」**——用户直接给 uid 时同样要做。
|
|
69
|
+
> 2. 已跑 ② 看到该 uid 确有行且 `granted > 0`。
|
|
70
|
+
>
|
|
71
|
+
> 缺任何一条就停下来问,不要先跑 UPDATE。
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
optima-query-db billing "UPDATE guided_run_grant SET used=0, spent_credits=0, updated_at=now() WHERE user_id='<uid>' AND granted > 0 RETURNING user_id, granted, used, cap_credits, spent_credits" <env>
|
|
75
|
+
# 🆕 建列后版本(缺了 spent_credits_llm=0 就等于没重置干净):
|
|
76
|
+
# optima-query-db billing "UPDATE guided_run_grant SET used=0, spent_credits=0, spent_credits_llm=0, updated_at=now() WHERE user_id='<uid>' AND granted > 0 RETURNING user_id, granted, used, cap_credits, spent_credits, spent_credits_llm" <env>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
> `AND granted > 0` 是机械自保:打到从未被授予引导资格的账号时影响 0 行,而不是静默写一个无效重置。
|
|
80
|
+
>
|
|
81
|
+
> ⚠️ **护栏触发时回显是完全空白**——`optima-query-db` 走 `psql -t -A --quiet`,0 行既没有 tuple、也不会打 `UPDATE 0` 标签(实测输出长度为 0)。**空回显 = 重置没有发生,不是成功**:回到 ①/② 核对 uid 是否贴错,然后重新走前置,**绝不要把 `AND granted > 0` 去掉重跑**——那正好绕过这道自保。成功时一定有一行形如 `<uid>|1|0|2000|0` 的回显。
|
|
82
|
+
>
|
|
83
|
+
> **已知不足**:它挡不住「uid 打错、恰好打到另一个真有 grant 的账号」——那种情况唯一的防线是上面第 1 条的人工核对,没有第二道。本技能不包 CLI 反查确认(对比 `optima-account ban` 的 `🎯 目标账号` 回显 + `--yes`),要补属另一个 issue 的量级。
|
|
84
|
+
|
|
85
|
+
**④ 复核 `sponsored_window`**:`CLOSED_*` 状态无需处理(下次进 onboarding 时 lazy-open 自动新开);仅异常残留的 `OPEN` 窗需要关注——等 reaper 约 30 分钟自动收即可,别手动改它的 status(未验证过的写路径)。该表**无 `created_at` 列**,按 `opened_at` 排序:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
optima-query-db billing "SELECT id, status, window_spent_credits, opened_at, closed_at FROM sponsored_window WHERE user_id='<uid>' ORDER BY opened_at DESC LIMIT 5" <env>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 客户端一层(服务端做不了,转告操作浏览器的人)
|
|
92
|
+
|
|
93
|
+
把 ① 查到的 uid 一并告知对方(拼下面的键名要用),然后:
|
|
94
|
+
|
|
95
|
+
1. 清 localStorage 锁——在对应环境前端域名下删三个键(DevTools → Application → Local Storage),或直接用**无痕窗口/换浏览器**登录(天然无锁):
|
|
96
|
+
- `onboarding_intake_submitted:<uid>`
|
|
97
|
+
- `onboarding_intake_dismissed:<uid>`
|
|
98
|
+
- `onboarding_intake_draft:<uid>`
|
|
99
|
+
2. 登录后点「开始新对话」落到空会话,问卷即自动弹出。
|
|
100
|
+
|
|
101
|
+
## 别白清的东西(不是 gate)
|
|
102
|
+
|
|
103
|
+
- gateway 库 `user_configs.intake_dismissed`:「我是老手跳过整树」的持久化,不是"已体验过"标记。
|
|
104
|
+
- agentic-chat 库 `onboarding_results` / `user_preferences.onboardingCompletedAt`:cn 环境无写入方,查了是空。
|
|
105
|
+
|
|
106
|
+
## 安全提醒
|
|
107
|
+
|
|
108
|
+
1. `cn-prod` 是生产库写操作,真正的护栏写在 **③ 正文的两条硬性前置**里(人工核对身份 + `granted > 0`),不在本节——别只扫这节就动手。
|
|
109
|
+
2. 清 `spent_credits`(建列后还有 `spent_credits_llm`)**不会退回真实花费**——真扣费永久留在 `usage_records`(`metadata->>'actorUserId'` = uid)与 CLOSED 窗的 `window_spent_credits`,清零只是把 lifetime 计数器归零、重开满 cap 预算。
|
|
110
|
+
3. onboarding 门控在高频演进(COO epic 等):若按本流程重置后仍不弹,先对 agentic-chat `origin/main` 的 `useShowOnboardingTree` / `intakeLocal` 重验门控是否有变,再排查。
|
|
111
|
+
|
|
112
|
+
## 相关命令
|
|
113
|
+
|
|
114
|
+
- `optima-query-db` - 本技能全部查询/更新的载体
|
|
115
|
+
- `optima-grant-credits` / `optima-grant-subscription` - 积分/订阅发放(与 onboarding 赞助额度是两回事)
|
|
116
|
+
- `optima-account` - 账号状态查询
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "yzsgo-e2e"
|
|
3
|
+
description: "当用户请求端到端测试鸭嘴兽、e2e 测 yzsgo 对话、用浏览器真机测鸭嘴兽整个流程、驱动对话再拉 wire 核对前后端、测网关/agent 端到端有没有问题时,使用此技能。playwright attach 调试端口 Chrome 驱 www.yzsgo.com 对话 → 拉 gateway wire → conversation-iq 语义管线判定 → confirmed 自动提 issue。"
|
|
4
|
+
allowed-tools: ["Bash", "Read", "Write", "Agent", "Workflow"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# yzsgo-e2e — 鸭嘴兽通用端到端测试
|
|
8
|
+
|
|
9
|
+
用浏览器真机驱动鸭嘴兽完成一段对话,同时拿浏览器侧结果 + 拉 gateway wire,判前后端一致性与网关缺陷,confirmed 自动提 issue。
|
|
10
|
+
|
|
11
|
+
## 何时用
|
|
12
|
+
- 「端到端测一下鸭嘴兽」「e2e 测这段对话」「用浏览器真机测整个流程有没有问题」
|
|
13
|
+
|
|
14
|
+
## 用户说人话 → 我怎么映射(用户不敲 CLI)
|
|
15
|
+
- 用户给的对话内容 → 逐轮 `--message`(按序)。
|
|
16
|
+
- 用户提到「遇到它问 X 就答 Y / 测某个反问」→ `--answer "X=Y"`。
|
|
17
|
+
- 用户说「重点看有没有 Z」→ `--expect "Z"`。
|
|
18
|
+
|
|
19
|
+
## 四段流程
|
|
20
|
+
1. **preflight**:`python3 preflight.py <env>`;缺项按提示准备(一次性登录/充值见 store-skills `setting-up-yzsgo-test-env`,我不替做)。
|
|
21
|
+
2. **驱动 + 拉 wire + 备料**:`python3 run_e2e.py --env <env> --user <测试账号userId> --message ... [--answer k=v] [--expect ...] --out <dir>` → 出 `prepped.md` + `meta.json`。
|
|
22
|
+
3. **判定**:`gh issue list --repo Optima-Chat/optima-gateway --state open --json number,title` 拉已知 issue 文本,`Workflow({scriptPath:"<skill>/judge_workflow.js", args:{base:"<dir>", sids:["prepped"], knownIssues:"<文本>"}})`。
|
|
23
|
+
4. **报告 + 提 issue**:
|
|
24
|
+
判定跑完后,先把 judge_workflow 输出 + meta.json 组装成 render_report 的入参(两者字段形状不同,别直接传):
|
|
25
|
+
- `confirmed` = 各 sid 的 `confirmed` 里取 `finding` → `{what, evidence}`,跨 sid 合并
|
|
26
|
+
- `needs_review` = 各 sid 的 `needsReview` 里取 `finding` → `{what, evidence}`
|
|
27
|
+
- `env` / `started_ts` / `first_message` 从 `<out>/meta.json` 读
|
|
28
|
+
- `blocked` = 环境类阻断原因(浏览器 state=service_error / 积分不足 / 桌面没连…),否则 None
|
|
29
|
+
- `coverage` = 本次覆盖边界(单次对话 / skeptic 读源码 / 去重挡已知 等,如实写)
|
|
30
|
+
再调 `run_e2e.render_report(result)` 出报告。**confirmed 直接 `gh issue create --repo Optima-Chat/optima-gateway --label needs-triage`**(证据=前端输出+wire transcript+repro 对话),提错可改可删;判定为纯前端缺陷(前端渲染问题、非 agent/网关逻辑)→ 提到对应前端 repo(而非 gateway);拿不准就默认 gateway。**needs_review 不自动提**,报告单列待人工;**环境类标 blocked 不提**。
|
|
31
|
+
|
|
32
|
+
## 诚实边界(照搬 conversation-iq)
|
|
33
|
+
- 「0 confirmed」≠「没问题」;needs_review 绝不静默毙。
|
|
34
|
+
- 对抗验证必须让 skeptic 读**真实 runtime 源码**,默认判假。
|
|
35
|
+
- 报告固定含「覆盖边界」+「判断修正」两节。
|
|
36
|
+
|
|
37
|
+
## 前后端对照(本 skill 独有)
|
|
38
|
+
判定要核对**前端渲染的** vs **wire 里 agent 真实产出的**:前端丢内容/半截/报错但 wire 成功(或反之)= 缺陷。
|
|
39
|
+
|
|
40
|
+
## vendor 同步纪律
|
|
41
|
+
`chat_driver.py`/`pull_wire.py` 上游权威 = optima-store-skills;`prep_conversation.py`/`judge_workflow.js` 改编自 optima-gateway conversation-iq。见 `SYNC.md`。驱动异常先怀疑前端 DOM 漂移 → 去上游同步。可跑 `python3 verify_drift.py` 比对。只有 `chat_driver.py` 是逐字 vendored、应与上游一致;`pull_wire.py`(在上游基础上追加了 emit_conversation_index/locate_conversation)、`prep_conversation.py`、`judge_workflow.js` 都是改编,`verify_drift.py` 对它们标「⚠️(改编·预期)」是提醒去看上游有无新变更,非「必须一致」。
|
|
42
|
+
|
|
43
|
+
## 两环境
|
|
44
|
+
`--env cn-prod`(已打通)/ `cn-stage`(wire 取法待核实,脚本会告警)。
|
|
45
|
+
|
|
46
|
+
## 真机 smoke(改完先跑这个验管道通)
|
|
47
|
+
```bash
|
|
48
|
+
python3 run_e2e.py --env cn-prod --user <测试账号userId> --message "你好" --out /tmp/yzsgo-smoke
|
|
49
|
+
# 期望:/tmp/yzsgo-smoke/prepped.md 含「前端所见」节 + wire transcript;meta.json 的 located 命中本次对话。
|
|
50
|
+
# 只验四段接线通,不追判定质量。
|
|
51
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# vendored 文件上游台账
|
|
2
|
+
|
|
3
|
+
| 本文件 | 上游 repo · 路径 | commit | 同步日期 |
|
|
4
|
+
|---|---|---|---|
|
|
5
|
+
| chat_driver.py | optima-store-skills · .claude/skills/operating-yzsgo-chat/chat_driver.py | 7a1685a | 2026-08-31 |
|
|
6
|
+
| pull_wire.py | optima-store-skills · .claude/skills/pulling-yzsgo-session-wire/pull_wire.py | 7a1685a | 2026-08-31 |
|
|
7
|
+
| prep_conversation.py | optima-gateway · .claude/skills/conversation-iq/prep_session.py(改编:+浏览器证据合并) | b75f575c | 2026-08-31 |
|
|
8
|
+
| judge_workflow.js | optima-gateway · .claude/skills/conversation-iq/workflow.js(改编:+前后端一致性维度) | b75f575c | 2026-08-31 |
|
|
9
|
+
|
|
10
|
+
> 注:judge_workflow.js 内联的 decideOutcome 是 judge_outcome.js(有 node 单测)的副本,改逻辑需同步两处。
|