Skip to content

test(flows): pin the cold-boot re-bind so a flow can never be what an unreadable warning hides (#653) - #667

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-653-flow-rebind-diagnosis
Aug 4, 2026
Merged

test(flows): pin the cold-boot re-bind so a flow can never be what an unreadable warning hides (#653)#667
os-zhuang merged 1 commit into
mainfrom
claude/issue-653-flow-rebind-diagnosis

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #653

先说结论:前提已经过期,两个缺陷都在平台侧,其中一个已经修好了

Issue 在 17.0.0-rc.1 上测得 24 条告警。main 已于 08-03 随 #663 升到 17.0.0-rc.2。在当前 origin/main 上复测,24 条告警全部消失

$ npx objectstack dev --fresh -p 41874
$ grep -c "cold-boot flow bind" boot1.log
0

而且不是"路径没跑所以没报错"——开 --log-level info 复测,重绑定确实跑了,而且全绑上了:

INFO [Automation] Pulled 24 flow(s) from ObjectQL registry
INFO [Automation] Bound 24 flow(s) from the protocol at kernel:ready
INFO [Automation] 24 flow(s) registered, 18 bound to triggers, 0 unbound-but-triggered

本仓元数据从头到尾没有问题,这个 PR 一行 src/flows/** 都没有改。

[ 到底说的是什么

按分诊要求,先拿完整错误再谈归因。把 rc.2 在 node_modules 里的修复临时改回 rc.1 的行为(readFlowDefsFromProtocolreturn stripReadDecorations(doc)return doc,仅本地、未提交),24 条告警逐字复现

2026-08-04T00:38:50.385Z WARN [Automation] cold-boot flow bind: failed to register campaign_enrollment: [
… 24 条 …

再把那行日志里的换行换成可见字符重跑一次,它想说的话才第一次走出第一行:

[
  {
    "code": "unrecognized_keys",
    "keys": [ "_diagnostics" ],
    "path": [],
    "message": "Unrecognized key(s) on this flow: `_diagnostics`. Until #4001 these were dropped silently — the flow still parsed, so a trigger binding or config the author wrote was quietly ignored."
  }
]

被拒的键不是我们写的getMetaItems({ type: 'flow' }) 会给每个 item 打上 _diagnostics 装饰,冷启动重绑定又把这份"被服务过的文档"原样喂回 FlowSchema——#4001 关闭 metadata schema 之后未知键改为抛出,于是读取路径栽在了自己的输出上。上游在 rc.2 的 changelog 里确认了同一件事(5b843fb / cloud#971),修法是在读取缝合处 strip,而不是放宽 FlowSchema——理由与本仓的 contract-first 一致:payload 之所以畸形是因为我们自己装饰了它,生产者的注解由生产者摘除。

归因用两组对照坐实过,不是从 changelog 推的:rc.1 引擎 × 当前 flows、rc.1 引擎 × #663 之前的 flows(在 5a11631^ 上真实 build 出的 artifact),24/24 全部注册成功——说明 artifact 形态从来没被拒过,被拒的只有读取路径装饰后的协议视图。

第 2 个缺陷仍然活着,已上报上游

截断本身在 rc.2 一行未动:三个绑定点(cold-boot bind、metadata:reloaded re-sync、boot pull)都是 ${err.message} 单行插值,下一个真绑不上的 flow 还是只会给出一个 [

已按分诊要求上报 objectstack-ai/objectstack#5048,附完整错误、最小复现、根因分析与建议修法(把 Zod issues 当结构化数据交给 logger 第二参数)。这条日志属于 @objectstack/service-automation,不在本仓绕过。

值得记一笔的是因果方向:cloud#971 能横跨整条 rc.1 发布线没人发现,唯一原因就是第 2 个缺陷让第 1 个隐了身——绑定是加性的,boot pull 已注册过一遍,record-change 插件是第二条绑定路径,于是它对外的全部表现就是 24 条谁也读不懂的告警。

本仓这一半:把它钉住

平台的日志行修不了,但可以保证 HotCRM 的 flow 永远不是那条日志所隐藏的东西。新增 test/flow-cold-boot-rebind.test.ts

  • 每个 allFlows 里的 flow 过一遍真实的 AutomationEngine.registerFlow —— 重绑定调用的那个方法本身,不是它的近似。先做一次 JSON round-trip,因为重绑定看到的是存储态文档而不是 TypeScript 对象(只在内存里成立的 Date / undefined 因此不会蒙混过关)。失败时打印完整的 issue 数组:

    AssertionError: 1 of 24 flow(s) failed the cold-boot bind
    + ─── campaign_enrollment ───
    + [ { "code": "unrecognized_keys", "keys": [ "bogus_key" ], "path": [], "message": "…" } ]
    

    (上面是注入一个坏键后的实测输出——测试的失败信息本身就是这个 issue 要的那份诊断。)

  • Every one of the 24 flows fails its cold-boot re-bind with a validation error the log truncates to [ #653 的失败类别原样重建:一个被读取装饰过的 flow 必须仍然被拒(证明 schema 依然是关闭的——放宽它会同时藏起真正的作者错误,正是本仓最不想要的方向),并且必须在 stripReadDecorations 之后重新可注册(证明 rc.2 的解法仍然是解法)。断言以 METADATA_READ_DECORATIONS 为准,所以将来新增的装饰键自动被覆盖。

    它证明不了自动化服务是否还在调用那个 strip——那道缝合在上游,需要真实 kernel。但如果某次升级引入了 strip 覆盖不到的装饰键、或从 spec 里撤掉了 strip,这会在 pnpm test 里红,而不是变成 24 条渲染为 [ 的启动告警。

验证

$ npx tsc --noEmit                       # exit 0
$ npx vitest run --maxWorkers=2
  Test Files  49 passed (49)
       Tests  1168 passed | 1 skipped (1169)

node_modules 的临时插桩已还原(grep -c stripReadDecorations 回到 2),git status 干净。未触碰 #650 将要处理的 decision 节点条件。


🤖 Generated with Claude Code

https://claude.ai/code/session_01Rvtsew6XgsSjxVa59HRPRK


Generated by Claude Code

… unreadable warning hides (#653)

Through 17.0.0-rc.1 every boot emitted 24 warnings — one per flow — from the
automation service's `kernel:ready` re-bind, each rendered as the single
character `[`. Both defects were platform-side.

`registerFlow` parses with `FlowSchema`, which #4001 closed: an unrecognized key
throws instead of being dropped. `err.message` was a Zod issue array, and a
one-line `logger.warn` left only its opening bracket. The full text names a key
this app never wrote — `_diagnostics`, added by `getMetaItems` itself, fed back
into the strict schema by the bind. 17.0.0-rc.2 fixed that at the read seam
(`stripReadDecorations`, cloud#971), so #663 already cleared all 24 warnings
here; current `main` boots with `Bound 24 flow(s) from the protocol at
kernel:ready`. No HotCRM metadata was at fault and none changes.

The truncated warning is still live in rc.2 and is filed upstream
(objectstack-ai/objectstack#5048) — a log line in @objectstack/service-automation
is not this app's to fix. What is: never being the thing it hides. This adds a
test that runs every flow in `allFlows` through the exact
`AutomationEngine.registerFlow` call the re-bind makes, JSON-round-tripped as
the stored document, and reports the complete issue array on failure. It also
reconstructs the #653 class — a read-decorated flow must still be rejected, and
must become registrable again after `stripReadDecorations` — keyed off
`METADATA_READ_DECORATIONS` so a decoration added later is covered too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rvtsew6XgsSjxVa59HRPRK
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hotcrm Ignored Ignored Aug 4, 2026 12:53am

Request Review

@github-actions github-actions Bot added the ci/cd CI plumbing and the verification pipeline label Aug 4, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 4, 2026 00:55
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 4, 2026
Merged via the queue into main with commit 1e25cb7 Aug 4, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd CI plumbing and the verification pipeline

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Every one of the 24 flows fails its cold-boot re-bind with a validation error the log truncates to [

2 participants