从 #5526 拆出的**止血单**(其路线 C)。根因 —— `values: string[]` 往返编码对非字符串类型有损,路线 A(tagged 编码)/ B(内部表示改 `unknown[]`)—— 在 #5526 等维护者拍板;**本单不裁根因**,只挡住已实测的真实业务形状(零填充订单号 / SKU / 邮编、带尾零的价格串)。 ## 位置 `packages/services/service-analytics/src/strategies/filter-normalizer.ts`:`recoverNumber` 的正则 `/^-?\d+(\.\d+)?$/` 及其在 `coerceFilterValueForSql` / `coerceFilterValueForObjectQL` 中的消费。 ## 改法 仅当字符串是**规范数字形**(`String(Number(s)) === s`)才还原为数字: - `'7'` → `7`、`'1.5'` → `1.5`(真数字往返不回退); - `'007'`、`'0912'`、`'1.50'` **保持字符串**(它们保留了 `Number()` 往返会丢失的原写法信息,只可能是作者笔下的字符串); - `'null'` / `'true'` / `'false'` 的 token 撞车**不在本单**(那是编码层面的根因,#5526 裁)。 ## 验收 - #5526 实测表:`{code: {$eq: '007'}}` 两条路径(SQL 绑定 + 引擎比较数)都绑 `'007'` 字符串;`'1.50'` 同理; - 行集用例:文本列存 `'007'` 的行能被 `{$eq: '007'}` 取到(现状零行); - 真数字比较数(`{$eq: 7}` 经 stringify → `'7'`)行为不变; - 两个 coercer 同步改、同步测。 Blocked-by: https://github.com/objectstack-ai/objectstack/pull/5525(同文件 `filter-normalizer.ts`,按同文件串行规则先等它落地) Part of #5526
Activity
os-zhuang commentedon Aug 5, 2026
认领:PM 循环第 3 轮(services 车道)。Blocked-by 已解除:PR #5525(#5332)已 MERGED。
会话:
session_01BWS4heBoAitLmzCLhcYdbK分支:
claude/issue-5528-recover-number-canonicalWorktree:
objectstack-issue-5528域:
domain:services文件面:
packages/services/service-analytics/src/strategies/filter-normalizer.ts(recoverNumber与两个 coercer)、同包测试、.changeset/*.md注:同包 #5333(
objectql-strategy.ts)继续按同包串行规则排下一轮,本单不碰它。根因单 #5526 在决策收件箱,本单不裁根因。Generated by Claude Code
style(service-analytics): fix two stray indents in the #5528 test file
os-zhuang commentedon Aug 5, 2026
复核:ACCEPT → PR #5547(CI 绿后转 ready 入合并队列)。
已核项:
null比较数是 null 谓词,不是= ''(#5332) #5525 合入后的基上逐行复现(analytics 的string[]值往返对字符串比较数也有损:{code: {$eq: '007'}}绑成数字7、'null'绑成真 NULL、'true'绑成1—— 文本列静默取到错行 #5526 表格),且实测出更糟的真实症状:SQLite 的 TEXT affinity 让{$eq: '007'}改前取到存'7'的错行(不是零行)—— 行集用例特意放了r_7/r_15两行来钉住这一点,这正是现场会报的形状;'1e+21'这类规范形但被正则拒的串有专门用例);顺手纳入 issue 未列的'-0'(丢符号)与超双精度位数(丢精度)两个同族;两个 coercer 共规则由专门守卫钉住;objectql-strategy.ts未碰(/analytics/sql回显的 SQL 丢掉$startsWith/$endsWith谓词:回显比实际执行的查询更宽,无法复现结果 #5333)、编码方向未碰(analytics 的string[]值往返对字符串比较数也有损:{code: {$eq: '007'}}绑成数字7、'null'绑成真 NULL、'true'绑成1—— 文本列静默取到错行 #5526)、token 撞车「钉住不背书」防止误读为已修;check-type-check-coverage台账条数漂移追评到既有 [finding] DEBT ledger counts in check-type-check-coverage.mjs drift silently — @objectstack/metadata-protocol records 28, actually reports 63 #5278(同一发现,不开孪生单),两处样本互为佐证;string[]值往返对字符串比较数也有损:{code: {$eq: '007'}}绑成数字7、'null'绑成真 NULL、'true'绑成1—— 文本列静默取到错行 #5526。排程提醒:本单落地后,同包 #5333 解锁;#5526(根因 B)按裁决评论仍需先核实
values: string[]的 spec 归属再派。Generated by Claude Code
fix(service-analytics): `recoverNumber` 只还原规范数字串 —— `'007'` / `'1.50'…
fix(service-analytics): carry filter comparands at their own type, no…