Repository navigation
[#14478 stack 4/6] system/: the 15 remaining duration keys carry their unit in the key name — ADR-0087 conversions with readers; metrics.zod.ts size needs an honest name, not the mechanical one #15679
Description
Activity
- addedenhancementNew feature or requestNew feature or requestpriority:p2Medium: important, M3Medium: important, M3
on Sep 5, 2026 分诊 ·
pm:blocked/domain:spec/priority:p2/enhancement⛔ 本席位只分诊:不认领、不派单、不写码、不合并、不裁决 decision-box 卡。方向已由维护者裁决 B(#14478
5548763981,batch #43)定下。Blocked-by: #15676(栈 1/6)
Restart-when: 1/6 的 PR 存在(分支已推、base 指向 #15626)—— ⛔ 不是「1/6 已合并」。整条栈一起落地。为什么是
pm:blocked,且本卡尤其不能抢跑system/是 external-vocabulary 豁免最密集的目录:1/6 列出的 13 个标记候选里有 4 个在system/——object-storage.zod.ts:258 maxAge(CORS on bucket rules)、:197 expiresIn(S3 预签名)、auth-config.zod.ts:308/330/550的三个 better-auth 键、disaster-recovery.zod.ts:127 ttl(DNS TTL)。⇒ 在 marker 约定存在之前动手,最可能把这些键错误地改名,而它们本该保持与外部标准一致的拼法。⭐ 人口切分已交叉验证(详见 #15676 上的分诊评论)
12 + 14 + 13 + 7 = 46= 1/6 声明的预期余量(65 − 6 − 13)。本卡的 13 与其余三张无重叠、无缺口。
⚠️ 佐证而已——裁决 (1):门的谓词才是人口的定义,⛔ 不得用另一套规则重数。⭐ 本卡特有的一条,值得单独标出
标题自己写了:
metrics.zod.ts的size需要一个诚实的名字,而不是机械的那个。⇒ 这一条 ⛔ 不能按模板机械套用*Ms/*Seconds——它要的是先判断这个键到底在度量什么,再给名字。这是本卡里唯一一个「改名规则给不出答案」的位置,⛔ 请勿让它悄悄变成一次模板替换。锚定 / 定级 / 类型
落点
packages/spec/src/system/**⇒domain:spec。整条栈同级 p2(一个落地单元)。重命名已发布键 ⇒ Feature 侧、manual floor;Clause-②: yes,⛔needs:contract-review由 PR 创建时同笔贴,本席位不代贴。通用三条
- ⛔ 绝不
Fixes #14478;首行Part of #14478,次行指名本卡、不带关闭关键字。分支叠在上一张卡的 head,PR base 指向它,draft。 ⚠️ 门今天不在main上(本席位实测:全树 0 命中,阳性对照packages/spec/scripts125 个文件)—— 它在 PR feat(spec)!: duration-shaped number keys carry their unit in the key name — no-baseline gate + seven ADR-0087 renames (timeoutMs, ttlSeconds/ttlMs, *TimeoutSeconds) #15626 的草稿分支。读数只能在叠加 head 上取。- ⛔ 1/6 正文里那 13 条的「标准」归属是读来的,需逐条对照 schema 自己的 docblock 核实;核实下来不镜像任何标准的键,回落为本卡的一次重命名,不是 marker。本目录占了其中 4 条,这条提醒对本卡权重最大。
分诊席位 ·
claude-opus-5· 本轮 R+156
Generated by Claude Code
- ⛔ 绝不
- changed the title
[-][#14478 stack 4/6] `system/`: the 13 remaining duration keys carry their unit in the key name — ADR-0087 conversions with readers; `metrics.zod.ts` `size` needs an honest name, not the mechanical one[/-][+][#14478 stack 4/6] `system/`: the 15 remaining duration keys carry their unit in the key name — ADR-0087 conversions with readers; `metrics.zod.ts` `size` needs an honest name, not the mechanical one[/+]on Sep 5, 2026 Title corrected: 13 → 15 — measured, and the two extra keys arrive by two different routes
Still
pm:blocked. The stack is serial (2 → 3 → 4 → 5 → 6) and card 2/6 (#15677) was dispatched at2026-09-05T09:16Z; this card waits for 3/6.The correction comes from an independent run of
pnpm --filter @objectstack/spec check:duration-unit-keyson card 1/6's headc1949b9ac(exit 1, exit code captured before any pipe), enumerated rather than recounted. Full reconciliation: PR #15814 comment5550822721.system/measured 15, against 20 on the stack base140e0b266. The gap to this card's original 13 is +2, from two unrelated causes:- A filing-time disagreement, +1. Card 1/6's attribution table names six
system/keys among its thirteen external-vocabulary candidates (object-storage.zod.ts:258maxAge,auth-config.zod.ts:308/:330/:550,object-storage.zod.ts:197expiresIn,disaster-recovery.zod.ts:127ttl).20 − 6 = 14, but this card was filed at 13. The two cards never agreed on the exemption set — that is the seat's filing error, not anything a dev did. - A verification demotion, +1. Card 1/6's dev marked only five of those six.
system/AccessControlConfig.maxAgewas left an offender because every bucket-CORS standard spells the field with its unit (S3MaxAgeSeconds, GCSmaxAgeSeconds, AzureMaxAgeInSeconds), so marking it would have exempted a deviation from the cited standard rather than a mirror of it.20 − 5 = 15.
⚠️ Note the asymmetry with its twin, and preserve it:shared/CorsConfig.maxAgedid get the marker, because the Fetch headerAccess-Control-Max-Agegenuinely carries no unit token. TwomaxAgekeys, opposite sides of the line.AccessControlConfig.maxAgeis a rename here — the gate itself suggestsmaxAgeSeconds.This card's 15 keys
CacheTier.ttl·CacheAvalanchePrevention.resetTimeout·CollaborationSessionConfig.idleTimeout·CollaborationSessionConfig.interval·FailoverConfig.healthCheckInterval·MetricAggregationConfig.window.size·ServiceLevelIndicator.size·ServiceLevelObjective.duration·AccessControlConfig.maxAge·StorageConnection.timeout·RegistryUpstream.syncInterval·RegistryUpstream.timeout·RegistryConfig.cache.ttl·Span.duration·QueueConfig.duration⛔ Line numbers are deliberately omitted: cards 2/6 and 3/6 land first and will move them. Re-derive from the gate on the stacked head at dispatch time — ruling (1) makes the gate's own predicate the population's definition.
The
metrics.zod.tssizeproblem this card's title names is still live and now has a second instance: bothMetricAggregationConfig.window.sizeandServiceLevelIndicator.sizeare in the population, and neither wants the mechanicalsizeSeconds. They are window lengths; the honest name says so.
Generated by Claude Code
- A filing-time disagreement, +1. Card 1/6's attribution table names six
Dispatched —
pm:blocked→pm:dispatchedClaim: session
session_01G4138K1EG7kQ81FNba5Kp4,domain:specseat,2026-09-05T14:19Z. Label swap as one read-modify-write with a comparison read-back; nothing else stripped.Base:
claude/issue-15678-kernel-duration-unit-in-key-name@8f2b8f389f44862bfa7ca899a3cc4a580d5f0afb(card 3/6's head), ⛔ notmain, ⛔ not any earlier card's branch.Card 3/6 is verified by independent enumeration:
22 offender(s) among 215 … in 805 source file(s),kernel/at 0, and every non-kernel/bucket byte-for-byte unchanged. Its gate family is green (doc-authoring 0 findings, skill-examples 257/257, generated 15/15, 12786 tests, typecheck).⚠️ This card's table has 14 rows. The population is 15.Measured on the stacked head. The missing row is
system/AccessControlConfig.maxAge(src/system/object-storage.zod.ts:261).Why it is missing: this card's table was built by subtracting card 1/6's intended exemptions, and it names
object-storage.zod.ts:258among them. But card 1/6's dev demoted that key rather than marking it — every bucket-CORS standard spells the field with its unit (S3MaxAgeSeconds, GCSmaxAgeSeconds, AzureMaxAgeInSeconds), so marking it would have exempted a deviation from the cited standard rather than a mirror of it.⚠️ Note its twinshared/CorsConfig.maxAgedid get the marker, because the Fetch headerAccess-Control-Max-Agegenuinely carries no unit token. TwomaxAgekeys, opposite sides of the line — preserve that asymmetry.This is the same mechanism that returned
intervalto card 2/6, and it is why the title was corrected 13 → 15 earlier today.The population — 15 rows, enumerated on
8f2b8f389# gate path:line key describe unit 1 src/system/cache.zod.ts:55ttlseconds 2 src/system/cache.zod.ts:130resetTimeoutseconds 3 src/system/collaboration.zod.ts:469idleTimeoutms 4 src/system/collaboration.zod.ts:474intervalms 5 src/system/disaster-recovery.zod.ts:115healthCheckIntervalseconds 6 src/system/metrics.zod.ts:335sizeseconds 7 src/system/metrics.zod.ts:420sizeseconds 8 src/system/metrics.zod.ts:481durationseconds 9 src/system/object-storage.zod.ts:261maxAgeseconds 10 src/system/object-storage.zod.ts:450timeoutms 11 src/system/registry-config.zod.ts:42syncIntervalseconds 12 src/system/registry-config.zod.ts:69timeoutms 13 src/system/registry-config.zod.ts:164ttlseconds 14 src/system/tracing.zod.ts:214durationms 15 src/system/worker.zod.ts:277durationms ⛔ Re-derive from the gate on your own head before editing — line numbers have shifted three times across this stack.
system/must read 0 and the whole tree must fall 22 → 7.The card's own
metrics.zod.tssizenote stands and now has two instances (rows 6 and 7): a windowsizein seconds is a duration, butsizeSecondsnames a byte count's unit. Propose the honest name and say why.⚠️ Correction to the earlier dispatches' gate invocations — my error, not a dev'scheck:doc-authoringandcheck:quick-reference-countsare root-package scripts. Thepnpm --filter @objectstack/spec check:doc-authoringspelling I used in earlier briefs returnsERR_PNPM_RECURSIVE_RUN_NO_SCRIPT— a non-reading that a hurried run could mistake for a failure. Use the root form:pnpm check:doc-authoring,pnpm check:quick-reference-counts.Also:
check:skill-examplesneeds@objectstack/client-reactbuilt or it refuses with a prerequisite-not-met;pnpm --filter "@objectstack/spec..." buildalone is not sufficient.Two reds you will inherit, already fixed upstream — ⛔ not yours
check:llms-txtandcheck:quick-reference-countsare red on your base with three findings (llms.txtshared 13→14 and total 207→208;quick-reference.mdx"Shared Protocol" 8→9). Confirmed inherited: byte-identical output on card 3/6's head and its base, traceable to card 1/6's commits. They are already fixed on card 1/6's branch (head5b1b5308e) and will clear when the stack integrates in order. ⛔ Do not repair them here — that is another card's diff.Carry forward
⛔ No internal issue id in a
retiredKey()prescription (check:doc-authoring). ⛔ Run the whole gate family, not the headline gate — heavy CI does not run on a stacked PR, so nothing else catches you.⚠️ check:skill-examplestype-checks prose, so hand-written pages that teach a key must move, not just regenerated ones.⚠️ An exit 3 or a 254 is a NON-reading, never a pass. ⛔ Anchored substitution with abort-on-count-mismatch.⛔ Do not touch
api/,kernel/,data/ui/ai/integration(7, card 5/6), the gate's declared population (card 6/6), any other PR's diff, orcontent/docs/releases/.
Generated by Claude Code
10 remaining items
- added a commit that references this issue
on Sep 8, 2026 - added a commit that references this issue
on Sep 13, 2026 - added 6 commits that reference this issue
on Sep 17, 2026 - added a commit that references this issue
on Sep 28, 2026
Part of #14478 — follow-on card 4 of 6, filed by the
domain:specseat (session_01M59rPZZFzqhfMUPFqqZTkf, 2026-09-05T02:55Z) under the maintainer ruling B on #14478 (5548763981, batch #43, 「同意」). Dispatched after stack cards 1/6–3/6 have PRs to stack on.Ruling text this card executes (verbatim)
The predicate
Run
pnpm --filter @objectstack/spec check:duration-unit-keyson the stacked head; a property whose value is az.number()/z.int()/z.coerce.number()chain and whose.describe()names a time unit must carry that unit as a token of its key name (Ms/Seconds/Minutes/Hours/Days, plusMillis), and the token must agree with the prose. ⛔ The list below is the gate's own output one68ae2b58, filtered tosrc/system/**minus card 1/6's marked keys (auth-config.zod.ts:308/:330/:550,object-storage.zod.ts:197/:258,disaster-recovery.zod.ts:127); re-derive on the stacked head before editing.e68ae2b58)src/system/cache.zod.ts:55ttlttlSecondssrc/system/cache.zod.ts:130resetTimeoutresetTimeoutSecondssrc/system/collaboration.zod.ts:469idleTimeoutidleTimeoutMsidleTimeout(seconds) that #15626 already renamed — the reason the population was ruled, on the authorable surfacesrc/system/collaboration.zod.ts:474intervalintervalMssrc/system/disaster-recovery.zod.ts:115healthCheckIntervalhealthCheckIntervalSecondssrc/system/metrics.zod.ts:335sizesizeSecondssizein seconds is a duration, butsizeSecondsnames a byte count's unit; the dev proposes the honest name (e.g.windowSeconds) and states why in the PRsrc/system/metrics.zod.ts:420sizesizeSecondssrc/system/metrics.zod.ts:481durationdurationSecondssrc/system/object-storage.zod.ts:447timeouttimeoutMssrc/system/registry-config.zod.ts:42syncIntervalsyncIntervalSecondssrc/system/registry-config.zod.ts:69timeouttimeoutMssrc/system/registry-config.zod.ts:164ttlttlSecondssrc/system/tracing.zod.ts:214durationdurationMsTraceSpan.duration)src/system/worker.zod.ts:277durationdurationMs(14 rows; the seat's "13" in the title is corroboration only — the gate's count on the stacked head is the reading.)
Execution notes
retiredKey()tombstone and aRETIRED_KEYS_BY_MAJORrow where on the authorable surface; emitted ⇒ semantic ADR-0087 entry, emitter and every reader renamed in the same PR at the same magnitude. Readers by TYPE across every workspace package; liveness ledgers, forms, i18n bundles, docs andskills/**prose where they name a key (askills/**hit makes the PR governed: keep it).Part of #14478, this card named without a closing keyword. ⛔ NeverFixes #14478.Clause-②: yes⇒needs:contract-reviewon PR and card at creation. Changeset:@objectstack/specminor, BREAKING banner naming every renamed key,adr-0087: registeredwith the ids; readers' packages as derived.packages/spec/src/migrations/registry.tsis written by this stack only; serial order 2 → 3 → 4 → 5 → 6.Related: #14478 · PR #15626 · stack 1/6 · #14519 (the tenant keys, already in #15626).