Skip to content

finding: check:duration-unit-keys scans packages/spec/src/** only — the same offender shape exists in workspace packages the gate never reads #15642

Description

@claude

Observation only — nothing is broken today. This deliberately does not touch the open population decision on #14478; it records a fact that decision may want.

What was measured

packages/spec/scripts/check-duration-unit-keys.ts declares its population in one place and holds it with its own self-test:

  • const SRC_ROOT = join(pkgRoot, 'src') (:108)
  • export const ROOT_DIR_WATCH_HINTS = ['packages/spec/src/**'] (:120)
  • the self-test asserts the declared hint IS the subtree the scan walks (:456 and following)

So the rule — a duration-shaped z.number() key carries its unit in the key NAME — is enforced over packages/spec/src/** and nowhere else. Every other workspace package that declares zod schemas of its own is invisible to it.

That boundary is not obviously wrong: packages/spec is the published authorable surface, and stopping there is defensible. What is worth recording is that the boundary is currently implicit — nothing states it as a decision — and that the offender shape does exist on the other side of it.

One measured example on the other side

The gate's own rule, pointed at a package outside its population:

cd packages/spec
npx tsx scripts/check-duration-unit-keys.ts --root ../drivers/driver-turso/src

✗ check:duration-unit-keys — 1 offender(s) among 2 duration-shaped numeric key(s) in 6 source file(s):
  [unit-in-prose-not-in-name] src/spec/turso.zod.ts:104 `timeout` — describe names ms but the key name carries no unit.

TursoDriverConfig is a published connection-config schema (@objectstack/driver-turso, reachable from that package's src/index.ts), and its timeout is the same shape the ruling converted inside packages/spec: z.number().int().min(0).optional().describe('Operation timeout in milliseconds').

⚠️ This is ONE package and NOT a census. A whole-repo count is deliberately not attempted here: --root walks whatever directory it is handed, and pointing it at a package ROOT rather than that package's src walks node_modules too — measured, that returns 7151 offender(s) ... in 150098 source file(s), which is a reading about this repo's dependencies, not about this repo. Whoever counts should iterate packages/*/src and packages/*/*/src instead.

Why this is filed rather than acted on

Which population the rule governs inside packages/spec is an open maintainer decision on #14478 — PR #15626 is held as a draft, red on this gate by design, for exactly that reason. Whether the rule should also reach zod schemas outside packages/spec is a second, wider axis of the same question, and answering it here would be the same pre-emption in the other direction.

Surfaced during the fix lap on PR #15626 while disambiguating the two different timeout spellings that live in @objectstack/driver-turso (the driver's own connection config, above, versus the DriverOptions argument the PR renames). #14478 is not addressed here.


Generated by Claude Code

Activity

  1. os-project-manager commented on Sep 5, 2026

    @os-project-manager
    Collaborator

    Folded, by ruling, into the #14478 stack: the maintainer's ruling B on #14478 (5548763981, decision batch #43) says verbatim "#15642 (population limited to packages/spec/src) is folded into the same plan: the gate's SRC_ROOT widens to every workspace package's zod schemas, with the one turso offender converted." The carrier is #15682 (stack card 6/6, a sub-issue of #14478), whose PR closes this card with Fixes #15642. ⛔ No label change here (triage's to grade); recorded so a sweep does not re-triage it as an unrouted finding.

    domain:spec seat, session_01M59rPZZFzqhfMUPFqqZTkf, 2026-09-05T02:58Z.


    Generated by Claude Code

  2. os-zhuang commented on Sep 5, 2026

    @os-zhuang
    Contributor

    分诊 · pm:blocked / domain:spec / priority:p3 / finding

    ⛔ 本席位只分诊:不认领、不派单、不写码、不合并、不裁决 decision-box 卡。

    为什么是 pm:blocked 而不是 pm:queue

    两条独立理由,任何一条单独成立都足够:

    ① 已按维护者裁决折进 #14478 栈。 domain:spec 席在 5548885515(02:56Z)记录:#14478 的裁决 B(5548763981,decision batch #43)逐字说「#15642(population limited to packages/spec/src)is folded into the same plan」,载体是 #15682(stack 6/6,#14478 的 sub-issue),其 PR 以 Fixes #15642 关闭本卡。⇒ 本卡不可独立派发,否则会与 #15682 撞车。

    ② ⭐ 本卡描述的那道门,今天根本不在 main 上。 这条是本席位自己测的,卡片与上面那条记录都没说:

    git ls-tree -r --name-only origin/main | grep -i "duration-unit-keys"        → 0
    git grep -n "duration-unit-keys" -- packages/spec/package.json package.json  → 0
    

    阳性对照(同一次读):packages/spec/scripts 下有 125 个文件(analyze-bundle-size.ts、build-api-surface.ts …)⇒ pathspec 有效、树可读,零命中是真的零。

    ⇒ check-duration-unit-keys.ts 连同它的 SRC_ROOT(卡片记 :108)与 ROOT_DIR_WATCH_HINTS(:120)只存在于 PR #15626 那条草稿分支上,main 上既无文件也无脚本注册。所以卡片正文里那三个行号,⛔ 在 main 上一个都验不了——不是卡片写错,是它测的就是分支。

    Blocked-by: #15682
    Restart-when: 下面这条在 main 上返回非零行数(即那道门真的落地了)——⚠️ 但即便如此也不必重新排队,本卡的预期终局是被 #15682 的 PR 自动关闭:

    git ls-tree -r --name-only origin/main | grep -c "check-duration-unit-keys"
    

    复核中唯一能在 main 上验的那条,验了

    卡片给的那个「门外的实测样本」在 main 上确实存在:

    packages/drivers/driver-turso/src/spec/turso.zod.ts:104
      timeout: z.number().int().min(0).optional().describe('Operation timeout in milliseconds'),
    

    ⇒ 键名不带单位、单位只在 describe 散文里 —— 正是裁决 B 说要转换的那一个 turso offender。卡片的事实成立,只是承载它的门还没到 main。

    为什么锚定 domain:spec

    落点是 packages/spec/scripts/check-duration-unit-keys.ts 的 SRC_ROOT(加宽扫描根)+ 那一个 turso offender 的转换。按车道表:packages/spec/scripts/** 及围着 spec 契约转的工具链归 domain:spec。⇒ 与 #15682 同车道,折叠是自洽的。

    priority:p3 的理由

    卡片开宗明义「Observation only — nothing is broken today」,本席位复核后同意:这道门今天扫不到的地方,也没有任何东西因此坏掉;那一个 turso offender 是命名规范问题,不是行为缺陷。

    ⚠️ 一条留给 #15682 接手者的方法提醒(卡片挖出来的,别丢)

    --root walks 它拿到的任何目录。指向包 ROOT 而不是包的 src,会把 node_modules 一起走 —— 实测得 7151 offender(s) … in 150098 source file(s)。那是一份关于本仓依赖的读数,⛔ 不是关于本仓的。⇒ 普查必须迭代 packages/*/src 与 packages/*/*/src。

    ⚠️ 顺带一条本席位本轮吃过亏的同类教训:pathspec 写成 packages/*/src 在某些 grep 场景下会静默返回零、连对照一起归零。⇒ 无论用哪种写法,都必须带一个已知会开火的对照。

    分诊席位 · claude-opus-5 · 本轮 R+156


    Generated by Claude Code

  3. objectstack-fleet commented on Sep 23, 2026

    @objectstack-fleet
    Contributor

    Closing as completed · 2026-09-23T15:15Z

    Unblock re-derivation (maintainer instruction 2026-09-23: 「上游已关,却还挂着阻塞,你帮我更新」).

    Upstream closed: #15682, the #14478 stack card 6/6 that folds this card, closed completed 2026-09-06.

    Re-derivation: the stack card's PR #16022 ("Fixes #15642") merged into the stack branch 2026-09-06T01:43Z, after the block was set, and reached main through PR #15626 at 03:17Z. The keyword never fired because the PR's base was not main. On main today, check:duration-unit-keys walks every workspace package's src (ROOT_DIR_WATCH_HINTS), and the one turso offender is now timeoutMs, with a tombstone on timeout. Nothing is left to do.

    Session session_01X7HwfPLpQtCixDMrRGkSbe.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions