feat(spec)!: the four system/tracing.zod.ts duration keys carry their unit in the key name (#17785) - #18016
Conversation
…th their unit Claude-Session: https://claude.ai/code/session_015c5G6TmpMKgnusmTpD7Ntt Co-authored-by: Claude <noreply@anthropic.com>
…ir unit in the key name Ruling A on #15939 (2026-09-11, maintainer 「同意」, decision batch #115), per-file remediation of the #14478 rule — the seventh and last card. `exporter.timeout`, `exporter.batch.exportTimeout`, `exporter.batch.scheduledDelay` and `performance.exportInterval` each named milliseconds in a source JSDoc and carried no `.describe()` at all, so the published reference row was a bare integer with no unit anywhere on it. Each is renamed with the `Ms` suffix, tombstoned with `retiredKey()`, and registered as an ADR-0087 D3 semantic entry plus a `RETIRED_KEYS_BY_MAJOR[18]` row. All four are nested, so the authorable-surface / authorable-defaults ratchets move nothing. Claude-Session: https://claude.ai/code/session_015c5G6TmpMKgnusmTpD7Ntt Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check4 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. What this run could not see
Coarse fallback — 136 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin a9d1149341a5cd3ba342e2ac44a9434d0c7b7834 && git checkout a9d1149341a5cd3ba342e2ac44a9434d0c7b7834
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin ff1e7716c5680938fdaa8d100ad3a2156c5d87e0 1de92aba380312d8f83d0b16b384249fbb6776ca && git checkout -B drift-repro ff1e7716c5680938fdaa8d100ad3a2156c5d87e0 && git merge --no-ff 1de92aba380312d8f83d0b16b384249fbb6776ca
node scripts/docs-audit/affected-docs.mjs --json ff1e7716c5680938fdaa8d100ad3a2156c5d87e0 |
…to its ref A count in a migration entry ships to consumers through the upgrade guide and is permanent published prose, so a number a future reader cannot reproduce is the same defect class this epic exists to remove. Every family count now names `98bd7986fe` and its corpus, and the objectui readings name the pinned sha. Claude-Session: https://claude.ai/code/session_015c5G6TmpMKgnusmTpD7Ntt Co-authored-by: Claude <noreply@anthropic.com>
|
Contract review
Isolated at-tier review for the ① Derived judgments
|
…k:cli-command-ids `check-cli-command-ids` matches a bin name that is the FIRST thing inside a quoted run and is followed by one or two bare lowercase words. The count prose broke its string concatenation so that a line began `'objectstack 10171 and`, which that pair reads as a quoted CLI invocation resolving to no command path. Reworded, not dropped: both counts and the measurement sha stay, and the two control tokens are still named. The new spelling is out on either half of the rule alone — the token is neither first in its quoted run nor followed by a bare lowercase word — so a later reflow of the concatenation cannot reintroduce the match. The mirror in `migrations/registry.ts` is regenerated, not edited. Claude-Session: https://claude.ai/code/session_015c5G6TmpMKgnusmTpD7Ntt Co-authored-by: Claude <noreply@anthropic.com>
…ased package version Two corrections from the in-seat contract review of PR #18016. The ADR-0087 entry's lit control said 20875 Schema occurrences on a corpus it described as the tree excluding `packages/spec` AND the generated reference pages. 20875 is the count with `content/docs/references` still in; the corpus the sentence names reads 18920. Both numbers now come from one `git grep -o` over `98bd7986fe` carrying both pathspec exclusions, and the sentence names that corpus exactly. The four tombstone prescriptions said `@objectstack/spec 18`. That conflates two axes: the prose names the released PACKAGE version, which is 17 (this ships in 17.5.0), while `RETIRED_KEYS_BY_MAJOR[18]` names the PROTOCOL major. A reader told "18" would look in a v18 that does not carry it. The tree spells it 17 in 265 places against 14, and this file's own `Span.duration` precedent says 17. `registry.ts` and the reference page are regenerated, not edited. Claude-Session: https://claude.ai/code/session_015c5G6TmpMKgnusmTpD7Ntt Co-authored-by: Claude <noreply@anthropic.com>
Contract review — delta
Isolated at-tier delta review for the Delta reviewed
The three fixes1. 2. The count vs its corpus — DISCHARGED. Re-measured at 3. Tombstone version wording — DISCHARGED, and the settlement is right. Measured with literals joined ( My own judgement of 17-vs-18, with the case for 18 considered: strict semver would put a breaking removal in a major, and the registry does record these four under step 18. But the two numbers answer different questions and the sources say which one the prose owes. Readings I re-measuredAll UTC 2026-09-13, in
Taken on trust (not re-run): everything the baseline passed — the four renames, the Escalated: (a) the PR body's 20875 (pre-landing body edit); (b) the 14 Implemented-by: branch claude/issue-17785-tracing-duration-units VERDICT: PASS — the diff at Generated by Claude Code |
Contract review — deltaThis comment supersedes 5653880451 for machine-readability only — the
Isolated at-tier delta review for the Delta reviewed
The three fixes1. 2. The count vs its corpus — DISCHARGED. Re-measured at 3. Tombstone version wording — DISCHARGED, and the settlement is right. Measured with literals joined ( My own judgement of 17-vs-18, with the case for 18 considered: strict semver would put a breaking removal in a major, and the registry does record these four under step 18. But the two numbers answer different questions and the sources say which one the prose owes. Readings I re-measuredAll UTC 2026-09-13, in
Taken on trust (not re-run): everything the baseline passed — the four renames, the Escalated: (a) the PR body's 20875 (pre-landing body edit, reported in flight); (b) the 14 Implemented-by: claude/issue-17785-tracing-duration-units VERDICT: PASS — the diff at Generated by Claude Code |
Contract review — deltaHead-sha: This comment supersedes 5653922476 for machine-readability only — the head sha there sat inside a code span together with its label, which Isolated at-tier delta review for the Delta reviewed
The three fixes1. 2. The count vs its corpus — DISCHARGED. Re-measured at 3. Tombstone version wording — DISCHARGED, and the settlement is right. Measured with literals joined ( My own judgement of 17-vs-18, with the case for 18 considered: strict semver would put a breaking removal in a major, and the registry does record these four under step 18. But the two numbers answer different questions and the sources say which one the prose owes. Readings I re-measuredAll UTC 2026-09-13, in
Taken on trust (not re-run): everything the baseline passed — the four renames, the Escalated: the 14 Implemented-by: claude/issue-17785-tracing-duration-units VERDICT: PASS — the diff at Generated by Claude Code |
Carriers cleared — provenance
That last row is the one this PR was actually waiting on: The three fixes, each verified independently by the review
The
|
…acing-duration-units # Conflicts: # packages/spec/src/migrations/registry.ts
`registry.ts` is generated from `src/migrations/entries/` and is deliberately NOT_DRIVER_MANAGED, so it conflicts textually on every pair of parallel registrations — #18007 (#17783, metrics) landed 9 rows and 4 semantic entries while this branch carried 5 of its own. The entries directory itself merged clean at 579 rows with zero conflict markers, which is what that directory exists for, so the conflict is resolved by regeneration, never by hand. Set difference over the entry set, by exact path: 0 lost / 13 gained against this branch's pre-merge head, 0 lost / 5 gained against origin/main. The generator's own line reads 215 semantic, 186 retired-key, 178 retired-def. Claude-Session: https://claude.ai/code/session_015c5G6TmpMKgnusmTpD7Ntt Co-authored-by: Claude <noreply@anthropic.com>
Contract review — deltaHead-sha: Isolated at-tier delta review for the Delta reviewed
Primary — sibling rows survived?Yes — by four independent instruments, and I did not accept the round's decomposition. 1. The occurrence table, The 6s do not decompose as "quoted-exact 2 + prefix-of-suffixed 2" — that sums to 4. Read by context with 2. The whole-set difference over 3. The generator's own check at all four trees, not one. 4. A line-set proof on The conflict resolutionFacts. The merge commit's (a) Is the resolution sound, and is a green (b) The script's "NON-generated, resolve by hand" line. The three earlier fixes survived the mergeMeasured at head with concatenated literals joined first (
The ratchet moves nothing
Readings I re-measuredAll UTC 2026-09-13, in
Taken on trust (not re-run): everything the two earlier reviews passed — the four renames, the Escalated: the Implemented-by: claude/issue-17785-tracing-duration-units VERDICT: PASS — the delta at Generated by Claude Code |
Carriers cleared — provenance
Full acceptance, including the four instruments that proved the sibling's rows survived and one number I relayed wrongly, is on the card: #17785 comment
⛔ No approval is given or implied. The clause-② review clears the queue gate; it is not a review approval, and this seat neither approves nor merges. Generated by Claude Code |
Fixes #17785
Clause-②: yes— each rename puts a spelling onOpenTelemetryCompatibilityandTracingConfigthat no author could write before.minor,feat(spec)!, with anadr-0087: registereddisposition (epic settlement on #15939, correcting Ruling A'sown
patch).Executes director-seat ruling A on #15939 (2026-09-11, maintainer 「同意」, decision
batch #115), the per-file remediation of the #14478 rule — the seventh and last of
that ruling's seven cards.
The four rows
Re-located by symbol path on
origin/main@98bd7986fe; line numbers came from PR#17635's enumeration and are re-derived here, not trusted.
OpenTelemetryCompatibility.exportertimeouttimeoutMsOpenTelemetryCompatibility.exporter.batchexportTimeoutexportTimeoutMsOpenTelemetryCompatibility.exporter.batchscheduledDelayscheduledDelayMsTracingConfig.performanceexportIntervalexportIntervalMsEach declared exactly once in key position, lit control
z.number20 on the file, darkcontrol 0. All four carried no
.describe()at all — not "a describe that names nounit", but none — so the published reference row was a bare integer with no unit anywhere
on the page. Values, defaults and
int().positive()bounds are unchanged.The suffix is
Ms, settled from tree countsKey position across
packages/spec/src: 281*Msdeclarations over 42 distinctnames —
timeoutMs65,intervalMs14,durationMs73 — against 0 key-positiontimeoutSecondsand 77*Secondsof any name.exportTimeoutMs/scheduledDelayMs/exportIntervalMshave 0 competing spellings of any form. The Delay-plus-Mspairing isalready attested (
maxDelayMs,initialDelayMs,retryDelayMs,delayMs,debounceDelayMs). This file's own landed precedent isSpan.durationtodurationMs(#15679) — the opposite of the sibling metrics card, whose rows were seconds; every
JSDoc here was read individually and every one says milliseconds.
The two
*TimeoutMskeys one nesting level apart — accepted, and why. The near-duplicatepre-exists the rename: the
batchsub-object is the OpenTelemetry batch span processor's ownfour knobs (max batch size, max queue size, scheduled delay, export timeout) sitting beside the
exporter's own request deadline. Renaming either to something more distinctive would depart from
the vocabulary this shape mirrors, and the nesting already disambiguates every read point —
exporter.timeoutMsversusexporter.batch.exportTimeoutMs, never interchangeable because theylive in different objects. Rejected alternative:
requestTimeoutMsfor the outer one, whichwould have invented a spelling OTel does not use to solve a problem the nesting already solves.
The ratchet moves nothing — and that is the correct outcome, not an omission
Verified from the generator source, not assumed.
packages/spec/scripts/build-schemas.ts:852reads
schema.propertiesone level deep and records${defKey}:${name}, so onlytop-level keys per def ever enter
authorable-surface/orauthorable-defaults/.Corroborated on the committed artifacts:
system/OpenTelemetryCompatibility:exporteris asingle row (the whole nested object), there are 0 dotted keys anywhere in
authorable-surface/system.jsonand 0 inauthorable-defaults/system.jsonagainst 247total keys there, and the lit control
system/Span:duration [RETIRED]is present.All four of my rows are nested.
check:authorable-surfaceis green without anyregeneration, and
git diff --name-onlyagainst the base matches 0 files underauthorable-surfaceorauthorable-defaults. This is the #17954 reading, not #17986's.The pin guard this card was written to trip
packages/spec/src/system/tracing.test.ts:545—it('leaves the OTel exporter timeout alone — its describe names no unit, so it is outside the population'). It succeeds by failing: its key, its "names no unit" clause and its"outside the population" clause all go false here. It is neither deleted, skipped, weakened
nor fixed green — it is replaced and relocated out of a
describeheadedSpan.duration carries its unit (#15679), which is no longer its subject, into a new#17785block carrying the three-part shape #15679 itself set on this file: a refusal pinper row asserting the issue code (
not.toBe('unrecognized_keys')) and the FROM to TOprescription, an acceptance pin at each retired key's magnitude with the same default, a
bounds pin, and a describe pin proving the unit now reaches the published channel.
Stale-prose sweep (
file:line)Swept
packages/spec/src,packages/spec/scriptsandcontent/docsfor sentences thiscard falsifies (
outside the population·names no unit·no unit at all·left alone·leaves ... alone·untouched here·stays bare), then narrowed tohits whose SUBJECT is one of my four keys. Lit control
unit2308 on that corpus, darkcontrol 0.
file:linepackages/spec/src/system/tracing.test.ts:545packages/spec/CHANGELOG.md:2866ServiceLevelObjective.errorBudget's burn-ratewindowand the OpenTelemetry exportertimeoutname no unit anywhere in their prose, so both are outside the gate's population entirely." Two limbs go false — mine here, thewindowone at #17783.packages/*/CHANGELOG.mdis RELEASE-OWNED (AGENTS.md): never edited in a code PR; a factual error in a released entry is amended in a dedicated docs-only PR. It is also jointly owned by a sibling card, so it is not this PR's sentence to rewrite. Raised in the report.packages/spec/src/migrations/entries/semantic/18.system-tracing-span-duration-unit-in-key.tsConsumers
Zero in-repo readers outside
packages/spec.OpenTelemetryCompatibility,TracingConfig,exportTimeout,scheduledDelayandexportIntervaleach occur 0times across the whole tree at
98bd7986feexcludingpackages/specandcontent/docs/references, against a lit control of 18920Schemaoccurrences onexactly that corpus — both counts from one
git grep -oover that ref carrying bothpathspec exclusions — and a dark control of 0. The named consumer packages were each run anyway rather than reasoned
about — including the package being edited, the #17986 lesson.
Pinned objectui,
.objectui-sha=53ded82bf7a494f54e344e19099dbf00854b8694, 6409tracked files: all 37 exports of
tracing.zod.tsand each of the four key names occur0 times. The 404
Spanand 40SpanSchemaraw hits are objectui's own HTML text-spancomponent (
TextSpanSchema) — a different name, read rather than counted. Lit controlsobjectstack10171 and@objectstack/spec3479 on the same corpus; dark control 0.Rollback is therefore consumer-free: reverting this PR restores the four bare spellings
and drops four tombstones no caller in this repo, and none in the pinned sibling, reads.
The kit
retiredKey()tombstone per row — none of these shapes is.strict(), sounrecognized_keyswas never the alternative: a bare deletion is an ADR-0049 silentstrip landing a default on an exporter deadline and a background export period
system-tracing-otel-exporter-durations-unit-in-keyplusfour
RETIRED_KEYS_BY_MAJOR[18]rows (the epic settlement: both, every time)registry.tsregenerated withgen:migration-registry, never hand-mergedcontent/docs/references/system/tracing.mdxregenerated withgen:docsminorchangeset with the BREAKING banner, the FROM to TO mapping for all four andthe
adr-0087: registereddispositionAcceptance notes
os migrate metasentence, matching spec: 1 duration key(s) insystem/tenant.zod.tsname their unit only in JSDoc — #15939 Ruling A remediation (1 of the 21-row delta) #17784 and spec: 3 duration key(s) inkernel/plugin-lifecycle-advanced.zod.tsname their unit only in JSDoc — #15939 Ruling A remediation (3 of the 21-row delta) #17780:the sentence belongs to a surface an ADR-0087 conversion covers, and these are D3
semantic entries with no D2 conversion (
stack.zod.tsdeclares no tracing collection;a tracing config is never a stored
sys_metadatarow). The class pinretired-key-migrate-sentence.test.tsdeliberately does not judge a prescription thatnames no command.
const, whichis the feat(spec)!: tenant
schemaCacheTTLcarries its unit in the key name (#17784) #17954 shape on a nested key and sidesteps theOS_EAGER_SCHEMAS=1temporal-dead-zonetrap feat(spec)!: RuntimeConfig
resourceLimits.timeoutcarries its unit in the key name (#17781) #17983 hit by construction — there is no const to order.acceptRetiredDefaultResidue()was considered and not used: all four keys aredefaulted, but every landed sibling of this epic tombstoned a defaulted key with plain
retiredKey(). Noted, not filed — raised as an open question rather than decided here.content/docs/references/system/tracing.mdxgains aTracingConfig.performancenested-shapesection it did not have; the
exporter.batchdescribes do not render a row because thegenerator's nested-shape rendering stops one level shallower. Generator behaviour, unchanged
by this PR. Noted, not filed.
Authored by the
os-devseat for the #15939 epic PM, sessionsession_015c5G6TmpMKgnusmTpD7Ntt(https://claude.ai/code/session_015c5G6TmpMKgnusmTpD7Ntt).Generated by Claude Code