Skip to content

spec(gate): check-duration-unit-keys admits by DECLARATION (Duration*/EpochMs type or unit-in-name), the name list becomes a detector that refuses undeclared time-shaped numerics, dimensionless rows declare it in-schema — step ② of ruling A on #18115 #18123

Description

@os-elon-musk

Filed by the director seat (objectstack #12708, summon #23, session_01WCEaPsmKY4UyoivKkkaUHt) executing decision batch #134 item 1 — maintainer 「决裁批 #134 同意」 to A on #18115, 2026-09-14T03:44Z. Step ② of three: the census admission rule. domain:spec (the gate lives in packages/spec/scripts/); p2; pm:blocked until step ① (the types the gate must read) is on origin/main.

The ruling this card executes (verbatim from #18115, batch #134 item 1)

体检只认「用了时长类型,或键名带单位」的键;17 个无单位数自然出列;名字表退为提示。

Ruling frame — ⛔ not re-adjudicable by the dev

  1. Admission is by declaration. A numeric key enters the census's JUDGED set when it declares a unit through one of two channels: a Duration* / EpochMs type in its zod chain (identifier detection, exactly as the gate already counts declared EpochMs instant(s) today), or a unit token in its key name (the existing keyUnits reading). Prose (.describe() / JSDoc) stays a consistency channel — it can contradict a declaration and be refused for it — ⛔ never an admission channel (batch Add comprehensive test coverage for ObjectStack spec protocols - 100% coverage achieved #65's declined direction, restated by 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 ruling C).
  2. The 25-token name list is RETIRED (batch Fix test failures from schema evolution (CustomValidator.handler, TenantSchema removal) #139 item 3, maintainer 「同意」 on 「是」, 2026-09-16 — the earlier text of this item, which turned the list into a detector of undeclared time-shaped numerics, was this seat's execution draft and is withdrawn; [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 option A's definition line reads 「名字表退休。」). DURATION_SHAPED_TOKENS is deleted and isDurationShaped()'s name-shape reading stops existing; admission is by declaration only (a Duration* / EpochMs type, or a unit token in the key name via keyUnits); --list no longer surfaces name-matched rows and the baseline shrinks accordingly. A bare z.number() with no unit in its name and no duration type is not judged — the cost option A accepted. The ≥7 escaping genuine-duration rows are converted by step ③ (spec: the genuine duration rows adopt a declaration — DurationMs/DurationSeconds or a unit-suffixed name (census #18078 classes A-true ×6, B ×2, D ×≥2) — step ③ of ruling A on #18115 #18124), ⛔ not caught by any name rule.
  3. Dimensionless numbers declare that too, in the schema. The 17 rows the census classed dimensionless (11 counts, 5 backoffMultiplier, 1 instant that spec: route the 10 bare z.number() wall-clock instants to EpochMs (census #18078 class C ×4 + unit-nowhere instants ×6) — tranche 1 of ruling C on #18080 #18114 converts) are exempted by an in-schema marker the gate reads — the same mechanism as the existing externalVocabulary meta exemption (11 declared mirrors today) — ⛔ not a side ledger file (that was option B, not taken). Exact key name of the marker is the dev's (e.g. .meta({ unit: 'none' }) or dimensionless: true), chosen to sit beside externalVocabulary in the gate's own reader.

PM mechanism assumptions — measure, falsify, report

  • The gate's scanTree / isDurationShaped / keyUnits exports (census spec: measure the option-1 population batch #65 declined for being unmeasured — duration keys whose unit is named only in JSDoc, or nowhere at all (report-only census) #18078 used them) are the seams; identifier detection for EpochMs already exists and generalises to Duration* by the same reader.
  • The 17 dimensionless rows all match the current 25-token list (that is how they entered the census) — so every one of them needs the marker in THIS PR or the new refusal reds on them. Apply the marker to all 17 here (they are schema edits with no runtime change), each with a one-line describe stating what the number counts.
  • (withdrawn with frame 2: there is no detector; rows the census did not draw are step ③'s to convert if they are genuine durations, or the schema author's to mark dimensionless when they next touch the key.)

Acceptance

  • --self-test exit 0 with new cases: (a) declared DurationMs key admitted and judged; (b) a bare z.number() whose name carries no unit is NOT judged and NOT refused (the name list is gone — assert DURATION_SHAPED_TOKENS no longer exists); (c) marked-dimensionless time-shaped key exempt; (d) EpochMs path unchanged; (e) a prose-only unit still does NOT admit (batch Add comprehensive test coverage for ObjectStack spec protocols - 100% coverage achieved #65 control).
  • --list baseline updated in the same PR; the summary line reports declared durations beside declared instants.
  • Before/after counts printed in the PR body: census rows, judged rows, dimensionless exemptions (expected 17); the genuine-duration rows step ③ converts are listed by name.
  • Clause-②: no — no published symbol moves (gate + schema meta only); changeset patch on @objectstack/spec if the meta markers touch published schemas (they do), else skip-changeset.
  • ⛔ The genuine duration rows are NOT converted here — the refusal on them is expected red until step ③ lands; the PR body names them as the red step ③ clears. Land order: ① → ② and ③ in either order; if ② lands first the gate is red on main until ③ — ⛔ not acceptable: coordinate with ③'s dev so ② is enqueued only when ③ is ready to follow in the same queue window, or fold ② and ③ into one PR if the conversion population is ≤ 12 rows.

Fences

  • ⛔ No key rename here; ⛔ no type definition here (step ①); ⛔ content/docs/releases/** untouched.

Re-check before claiming

git fetch origin main && cd packages/spec
tsx scripts/check-duration-unit-keys.ts --self-test   # exit 0, note the case count
tsx scripts/check-duration-unit-keys.ts --list | tail -5   # the summary line, note `declared EpochMs instant(s)` count
git grep -n -E 'export const (DurationMs|DurationSeconds)' origin/main -- src   # step ① landed? (must be ≥1 before this card is dispatchable)

Refs

#18115 (ruling A) · #18080 (ruling C) · #18078 (census — the 17 dimensionless rows are enumerated in its §A) · #14519 (unit-nowhere shape, superseded by this) · step ① / step ③ cards · packages/spec/scripts/check-duration-unit-keys.ts

Dedup terms: check-duration-unit-keys admission, isDurationShaped detector, dimensionless marker, declared unit channel, unit-nowhere refusal


Generated by Claude Code

Activity

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