Repository navigation
spec: the option-1 population is measured — 6 rows, and it cannot reach the ≥7 duration keys that name no unit anywhere. What is the goal? #18080
Description
Activity
os-elon-musk commented
on Sep 14, 2026 CollaboratorMore actionsRuling: batch #133 item 4 · letter C · maintainer 「决裁批 #133 同意」 2026-09-14T03:33Z (to
1D·2a·3A·4C·5C)Ruling recorded — C: the goal is making unit-nowhere durations judgeable — census admission moves from the 25-token name list to 「does this key declare a unit」. B (the 10 instants →
EpochMs) executes now as tranche 1 under this ruling; the definition of 「a duration」 is tranche 2's precondition and is its own decision card. A (JSDoc as an admission channel) and D (leave batch #65 as is) are not taken (director seat, decision batch #133 item 4, 2026-09-14)Derived first from the long-term axis: two years out every duration/instant numeric in
@objectstack/specis either unit-in-name or a closed type, and the gate judges declarations rather than a name list that must drift — only C is that shape; A makes source comments a third contract channel that never reaches a reader of the published reference; D leaves ≥7 keys where 60000 cannot be told from 60 s. ②③④ do not overturn ①: ③ agrees (the D-class rows are the silent ×1000 case and only C reaches them); ④ only orders the work — the cheap, already-conventional B half first, the definition second.What is ruled
- Tranche 1 — spec: route the 10 bare
z.number()wall-clock instants toEpochMs(census #18078 class C ×4 + unit-nowhere instants ×6) — tranche 1 of ruling C on #18080 #18114 (domain:spec,pm:queue, p2): the 10 barez.number()wall-clock instants adoptEpochMs(census class C ×4 + the six unit-nowhere instants,tokenExpiryincluded; lamport clocks excluded). No key rename. Whether any producer writes non-integers is measured in the PR and decides banner/disposition, ⛔ not the letter. - Tranche 2 precondition — [Decision] what counts as a duration for the unit-in-key census — replace the 25-token name list with a declared shape? (class A 23→6 and class D ≥7 of census #18078; tranche 2 precondition of ruling C on #18080) #18115 (
needs-user-decision,domain:spec, p2): 「what counts as a duration」 — declared shape (closedDuration*types + unit-in-name, name list retired to a hint) vs curated ledger vs prose heuristics; presented in the next decision batch with facets and speed-read. - Tranche 2 implementation (the 6 + 2 + ≥2 genuine durations, and the census-admission change in
check-duration-unit-keys.ts) is filed only after [Decision] what counts as a duration for the unit-in-key census — replace the 25-token name list with a declared shape? (class A 23→6 and class D ≥7 of census #18078; tranche 2 precondition of ruling C on #18080) #18115 is ruled; ⛔ nobody widens the gate before then. - A is refused: it reaches 6 rows, none of them the D class, and activates a measured false positive (
downloadsLastMonth). D is refused: batch Add comprehensive test coverage for ObjectStack spec protocols - 100% coverage achieved #65's stated precondition (「its population is unmeasured」) is now met, and the measurement points past option 1 rather than at it. - spec:
tenant.zod.tsidleTimeout / sessionTimeout publish a describe with no unit, while the JSDoc one line above says seconds #14519 (the unit-nowhere shape) receives a pointer to this ruling so the 「listed, not judged」 resting place is read as superseded once [Decision] what counts as a duration for the unit-in-key census — replace the 25-token name list with a declared shape? (class A 23→6 and class D ≥7 of census #18078; tranche 2 precondition of ruling C on #18080) #18115 lands; finding: check:duration-unit-keys scans packages/spec/src/** only — the same offender shape exists in workspace packages the gate never reads #15642 (scanned subtree) stays independent.
State
needs-user-decisionremoved; closedcompleted— the question this card asked (「what is the goal?」) is answered and the work lives on #18114 / #18115.domain:spec/toolingkept.
Generated by Claude Code
- Tranche 1 — spec: route the 10 bare
- added a commit that references this issue
on Sep 17, 2026 - added a commit that references this issue
on Sep 28, 2026
维护者速读
一年前定下的规矩是:一个表示时长的数字,单位要写在键名里,比如
timeoutMs而不是光叫timeout——这样 AI 或人照着写配置时,不会把 60000 毫秒当成 60000 秒。2026-09-07 你批过一次(batch #65):当时提议「让检查器也去读源码注释(JSDoc)里的单位」,没有采纳,理由白纸黑字写着——「这一类到底有多少个,没数过」。
现在数过了。结论有点出人意料:
所以真正要你定的不是「要不要读 JSDoc」,而是:这件事的目标到底是哪一个。
我的推荐是 B,理由和回退在下面。请回一个字母:A / B / C / D。
Background
check:duration-unit-keysrefuses a duration-shaped numeric key that does not carry its unit in the key name. The #15939 epic closed on 2026-09-13 having remediated 21 such rows and landed the gate widening (#17635 →484484041a). This card is the follow-on that epic deliberately held back.Governing text — quoted, ⛔ not paraphrased
Decision batch #65, 2026-09-07, maintainer 「同意」 (#15939 comment
5564447683):And the one prior classification of a member of that shape,
packages/spec/src/migrations/entries/semantic/18.kernel-health-check-and-hot-reload-durations-unit-in-key.ts:63-65:Protocol declaration
No protocol change is proposed by this card. Options A and C would change gate behaviour and therefore need their own implementation cards; option B changes no gate at all. ⛔ Nothing here is adopted by filing.
The measured population — the precondition batch #65 named
Census #18078, report-only, at
origin/main@fb29f62cee. Re-check:git fetch origin main && cd packages/spec && tsx scripts/check-duration-unit-keys.ts --list.z.number()instead ofEpochMsmaxMemoryshape — a size, not a duration)⇒ Option 1 as declined reaches 6 rows (B + C) and cannot reach D at all.
Two measured facts that bear on the choice:
metrics.zod.ts:224 ageBuckets(JSDoc "Number of age buckets",default(5)) is in it becauseageis a token. The rule's remedy is "move the unit into the key name", which is meaningless where there is no unit.plugin-registry.zod.ts:110 downloadsLastMonthhas JSDoc "Downloads in the last 30 days"; the gate'sPROSE_COUNTED_RE(:281) matches30 days. Today the row never enters the census so the misread is inert. On the day JSDoc becomes an admission channel, the gate starts refusing a download count.Options × real cost
downloadsLastMonthstarts being refused as though it were a durationEpochMs业务含义直译
四维分析(从业务立场)
① 项目长远合理性。 B 缩小特例:它让一个已经存在、已经有 6 处在用的约定被一致地遵守,不新增任何契约表面。A 扩大特例——它让「注释」成为第三个有语义的说明书通道,而这个通道的内容不进入发布产物,读者在参考页上看不到它,于是产生「代码里写了、文档里没有」的长期分裂。C 是三者里唯一减少增生的:它把判断依据从一张 25 个词根的名字表(一个必然长期漂移的清单)换成「有没有单位」这个语义问题。
② 实际业务拉动。 今天真正会撞上的人:拿着参考页照抄配置的作者与 AI。B 的 4+6 行是时间戳,写错的后果是把毫秒当秒传进去,静默地差 1000 倍。A 的 2 行时长同理但只有 2 行。D 类那 ≥7 行是拉动最大的一批——恰恰是三个选项里两个够不到的那批。⛔ 没有任何一类有已发生的事故记录,所以这四项都不是救火。
③ 防 AI 犯错。 这一轴决定推荐。⚠️ 出错时谁看见什么:一个 AI 照着参考页写
timeout: 60000,如果单位只写在源码注释里,参考页上什么都没有,它没有任何线索,写错了也不会被拒绝——静默的 1000 倍偏差,直到运行时行为不对才被发现。这正是 ③ 说的「响亮拒绝优于静默容忍」被违反的形态。B 把这批键换成一个闭合的类型(EpochMs),等于把自由结构换成枚举,是这一轴上最干净的一步。A 只在 2 个时长上做同样的事,但同时引入一个新的静默错误方向:downloadsLastMonth会被响亮拒绝,而它是对的——假阳性教作者不信任这道门,比漏判更伤。④ 创业阶段不扩散。 B 不新增任何已声明的键与永久义务,它只是让既有的用起来。A 新增一条规则分支加 6 个重命名的迁移义务,换 6 行。C 的义务最大,但它换来的是唯一一个不会随名字表漂移而失效的判据——如果只做一件长期的事,C 是那件;如果现在只做一件便宜的事,B 是那件。
推荐 + 回退 + 置信缺口
推荐 B,并把 A 与 C 分开处理:B 不改规则、有现成约定、覆盖静默偏差最严重的一批;A 的 2 行时长可以随后单独做,但要连带处理
downloadsLastMonth这个会被激活的假阳性;C 应当是它自己的卡,因为它改的是普查的定义而不是读散文的方式。回退:B 若在实施中发现某个时间戳其实不是 wall-clock(比如是相对偏移),那一行退出本批、单独记录,⛔ 不为了凑数改类型。
packages/spec,#15642(扫描子树的范围问题)仍独立开着,别的 workspace 包里同形的键没有数过。裁后执行段
domain:spec实现卡:普查预测入队面packages/spec/scripts/check-duration-unit-keys.ts+ 6 处重命名的 ADR-0087 转换与墓碑;同卡必须处理downloadsLastMonth假阳性,⛔ 不得留给下一个人发现。domain:spec实现卡:4 行(外加 6 行同形)改用EpochMs;这是已发布键的类型收窄,按 clause ② 判定后决定是否需要席内契约复核。needs-user-decision子卡答「什么算时长」(A 类 23 vs 6 的边界),再谈实现。not_planned,在 spec:tenant.zod.tsidleTimeout / sessionTimeout publish a describe with no unit, while the JSDoc one line above says seconds #14519 上留一条评论把这次的数字记进去,免得第三次因为「没数过」而重开。下游问题 —— ⛔ 本卡不问,答完上面那个字母才谈
snapshotInterval= 每 N 个事件,reflectionInterval= 每 N 次交互,ageBuckets= 桶数)加 5 个退避倍数。B 类的边界同样悬在这个答案上。maxMemory那种),宽泛同形约 57–58 行(字节、像素、百分比)。相关单与 PR
#15939(已关,母单与 Ruling A)· #18078(已关,本卡的普查)· #14519(unit-nowhere 形状)· #15676(ruling B,时刻形状)· #18075(不同的洞:经
keyUnits进普查却逃过判决的 2 行)· #15642(扫描子树,独立)· #17635 / #484484041a(闸门加宽)· batch #65 台账在 #12708。os-decision-facets
EpochMs)是这一轴最干净的一步;downloadsLastMonth),假阳性比漏判更伤信任。推荐:B(只做时刻那一批,不改规则)。选项:A 采纳 option 1 / B 只做时刻 / C 扩大普查本身 / D 维持 batch #65。
置信缺口:D 类的 ≥7 是下界不是计数(要数准需先答「什么算时长」);无任何事故或用户报告数据,排序基于「发布面上看不看得见单位」的推理;只覆盖
packages/spec,别的 workspace 包同形键未数(#15642 独立开着)。Filed by the epic PM for #15939,
session_015c5G6TmpMKgnusmTpD7Ntt, 2026-09-13T23:15Z. Population from census #18078 atfb29f62cee; every figure quoted here was re-verified by this seat against the tree, not relayed.Generated by Claude Code