Commit fc28c1d
Fixes #17784
Clause-②: yes
Executes director-seat **ruling A on #15939** (2026-09-11, maintainer
「同意」, decision batch #115) — the per-file remediation of the #14478
duration-unit rule. This card owns exactly one row, in
`packages/spec/src/system/tenant.zod.ts`. The gate PR (#17635) is
sequenced to land LAST and is untouched here.
⚠️ The declaration reads `yes`, not the `no` ruling A wrote: the PM
corrected it on the card (comment `5652103109`) under the mechanical
floor in `references/contract-review.md` — a new key on a published
payload is always `yes` — and a rename is a removal plus a new key.
`needs:contract-review` is hung on card and PR; the changeset is graded
`minor` accordingly, matching the four sibling duration-rename
changesets of this same rule (#15677 · #15678 · #15679 · #15680), every
one of which shipped as `feat(spec)!` under `## 17.4.0`.
## What changed
`SchemaLevelIsolationStrategy.performance.schemaCacheTTL` named its unit
in a source JSDoc — "Schema cache TTL in seconds" — and nowhere else.
The `.describe()` that `content/docs/references/system/tenant.mdx`
renders said "Schema cache TTL" and named no unit at all, so the reader
of the published reference page could not tell 3600 seconds from 3600
milliseconds.
| | before | after |
|:--|:--|:--|
| authored key | `performance.schemaCacheTTL: 3600` |
`performance.schemaCacheTtlSeconds: 3600` |
| published describe | `Schema cache TTL` | `Schema cache TTL in
seconds` |
| value + default | seconds, `3600` | unchanged |
The new spelling is `Ttl`, not `TTL`, derived from how the suffixed
family already spells itself on this tree rather than from the dispatch:
`cacheTtlSeconds` 11, `ttlSeconds` 3, `defaultCacheTtlSeconds` 1, and no
key-position `TTLSeconds` variant anywhere.
The kit, following the #15678 / #15679 shape the ruling names:
- a `retiredKey()` tombstone on the old spelling — `tsc` types it
`never` and a value reaching the parse raises the rename prescription
instead of being silently stripped (the nested `performance` object is
not `.strict()`)
- ADR-0087 **D3** semantic entry `tenant-schema-cache-ttl-unit-in-key`
and the `RETIRED_KEYS_BY_MAJOR[18]` row
`system/SchemaLevelIsolationStrategy:performance.schemaCacheTTL`, both
as `migrations/entries/` files with `registry.ts` regenerated by
`gen:migration-registry` (never hand-merged)
- **no D2 conversion**: `stack.zod.ts` declares no tenancy collection
and a tenant isolation strategy is not a stored metadata row, so the
chain has no seam that runs on it — the same reading
`tenant-timeouts-unit-in-key` recorded for the two sibling keys on this
same file
- pin tests on `SchemaLevelIsolationStrategySchema`: the refusal carries
the rename prescription, the suffixed key parses at the magnitude the
retired one carried with the same 3600 default, and the describe
publishes the unit
- `content/docs/references/system/tenant.mdx` regenerated by `gen:docs`
— all four rows move and the tombstone prescription renders in place of
the old describe
- a `minor` changeset carrying the FROM to TO mapping and the ADR-0087
disposition
## The measurement this card was dispatched to produce
This is the first of six renames, so the mechanical clause-② reading
matters for the other five.
**`node scripts/pm/check-widening-tells.mjs --declaration no` over this
PR's own diff — exit 4, exactly one tell:**
```
✗ T1 packages/spec/src/system/tenant.zod.ts:454 — a new key on a Zod object schema — the accept set gains a spelling an author may now write
+ schemaCacheTTL: retiredKey(
```
The tell is **not** on the rename. It is on the **tombstone**. Two
synthetic probes separate the two halves on the same instrument:
| probe | exit | tells |
|:--|--:|:--|
| the rename alone (one key line removed, one added, one change block) |
0 | none — the #16943 REPLACEMENT budget absorbs it |
| an added `retiredKey(` key line with no paired removal | 4 | T1 on the
tombstone line |
So the accounting is exact: the removed `schemaCacheTTL:` line buys one
T1 unit, the added `schemaCacheTtlSeconds:` line spends it, and the
added `schemaCacheTTL: retiredKey(` line is the surplus. Every
`retiredKey()` retirement raises this, and the line it raises on is the
one that makes the accept set strictly **narrower** — the key becomes
`never`. That is the same inversion this file's own header records for
`#17300` (T2 on the retirement ledger's rows) and `#17618` (T1 on a
narrowed in-shape key), one door further along. Filed as **#17955**; the
diff was **not** reshaped to silence it and no gate was weakened.
⚠️ Read the two readings apart, because they agree on the verdict for
different reasons: the mechanical tell is a **false positive on the
tombstone line**, while the `yes` this PR now declares rests on the
contract-review floor (the rename really does add a key an author may
write). `check-clause2-carriers --pair 17954` read exit 4 / C5 against
the original `no` and reads **exit 0** against the corrected `yes`.
## Verification
Heavy runs through `scripts/pm/os-verify-lock.sh`, verdicts read from
its own `VERDICT` line; every gate's exit code captured before any pipe.
- `pnpm --filter '@objectstack/spec^...' build` — exit 0, **empty
closure** (`No projects matched`): `packages/spec` has no workspace
dependencies, so step ① is a documented no-op
- `pnpm --filter @objectstack/spec build` — `VERDICT command-exit 0`,
run before every dist-reading gate and re-run after the last source edit
- `pnpm --filter @objectstack/spec test` — **475 test files / 13507
tests passed**
- `pnpm --filter @objectstack/spec typecheck` — exit 0 (`tsc --noEmit` +
`check:scripts-typecheck` + `check:test-typecheck`)
- `pnpm --filter @objectstack/spec check:generated` — **all 15 generated
artifacts up to date** after `gen:docs`; `check:authorable-surface`,
`check:api-surface`, `check:migration-registry`, `check:spec-changes`
and `check:upgrade-guide` among them
- `check:authorable-surface` does not move for this key and that is
correct: the ratchet records top-level keys per def and this one is
nested under `performance` (0 hits for the key across
`authorable-surface/` and `authorable-surface.base.json`, against 4 for
the `system/MigrationPlan:` lit control)
- `check:duration-unit-keys` (the gate as it stands on `main`, not
#17635's) — exit 0
- `check:objectui-pin-citations` — exit 0, 16 asserting pin citations
match `.objectui-sha`
- cross-repo, per the ruling's execution note and AGENTS.md post-task
step 4: `git grep` of the **pinned** objectui checkout at
`.objectui-sha` = `53ded82bf7a494f54e344e19099dbf00854b8694` (re-read
from this tree) — `schemaCacheTTL` **0** occurrences across 6409 tracked
files, beside lit controls `TTL` 112, `Ttl` 11, `tenant` 819, `cacheTTL`
1 and a dark control at 0, so the zero is a reading
Gate set derived at the actual change set with `node
scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`; full per-gate exit codes, including the
ones that could not run in this container, are in the round report on
#17784.
## Acceptance notes
- noted, not filed: the two in-file sibling renames landed under #14478
/ #14519 registered a D3 semantic entry but **no**
`RETIRED_KEYS_BY_MAJOR` row, while #15679's nested duration renames on
`system/metrics.zod.ts` and `system/cache.zod.ts` registered both. This
card follows #15679 (the shape ruling A names) and registers both.
Successor: whoever lands the remaining four rename cards in this epic,
who meets the same choice.
- ⛔ Not touched, deliberately:
`packages/spec/scripts/check-duration-unit-keys.ts` and its self-test
(PR #17635, sequenced last, red by construction), the five sibling files
owned by #17780 #17781 #17782 #17783 #17785, and
`content/docs/releases/`.
⛔ Draft on purpose: the in-seat clause-② review this PR now declares is
owed before it may turn ready or enqueue. That is the PM's step, not
this round's.
Round report, with every reading above and its exit code: the
`os-dev-report` comment on #17784.
---
_Generated by [Claude
Code](https://claude.ai/code/session_015c5G6TmpMKgnusmTpD7Ntt)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 65767d2 commit fc28c1d
7 files changed
Lines changed: 220 additions & 8 deletions
File tree
- .changeset
- content/docs/references/system
- packages/spec/src
- migrations
- entries
- retired-keys
- semantic
- system
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
151 | 151 | | |
152 | 152 | | |
153 | 153 | | |
154 | | - | |
| 154 | + | |
155 | 155 | | |
156 | 156 | | |
157 | 157 | | |
| |||
175 | 175 | | |
176 | 176 | | |
177 | 177 | | |
178 | | - | |
| 178 | + | |
| 179 | + | |
179 | 180 | | |
180 | 181 | | |
181 | 182 | | |
| |||
278 | 279 | | |
279 | 280 | | |
280 | 281 | | |
281 | | - | |
| 282 | + | |
282 | 283 | | |
283 | 284 | | |
284 | 285 | | |
| |||
302 | 303 | | |
303 | 304 | | |
304 | 305 | | |
305 | | - | |
| 306 | + | |
| 307 | + | |
306 | 308 | | |
307 | 309 | | |
308 | 310 | | |
| |||
Lines changed: 13 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
Lines changed: 39 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10479 | 10479 | | |
10480 | 10480 | | |
10481 | 10481 | | |
| 10482 | + | |
| 10483 | + | |
| 10484 | + | |
| 10485 | + | |
| 10486 | + | |
| 10487 | + | |
| 10488 | + | |
| 10489 | + | |
| 10490 | + | |
| 10491 | + | |
| 10492 | + | |
| 10493 | + | |
| 10494 | + | |
| 10495 | + | |
| 10496 | + | |
| 10497 | + | |
| 10498 | + | |
| 10499 | + | |
| 10500 | + | |
| 10501 | + | |
| 10502 | + | |
| 10503 | + | |
| 10504 | + | |
| 10505 | + | |
| 10506 | + | |
| 10507 | + | |
| 10508 | + | |
| 10509 | + | |
| 10510 | + | |
| 10511 | + | |
| 10512 | + | |
| 10513 | + | |
| 10514 | + | |
| 10515 | + | |
| 10516 | + | |
10482 | 10517 | | |
10483 | 10518 | | |
10484 | 10519 | | |
| |||
13198 | 13233 | | |
13199 | 13234 | | |
13200 | 13235 | | |
| 13236 | + | |
| 13237 | + | |
| 13238 | + | |
| 13239 | + | |
| 13240 | + | |
| 13241 | + | |
| 13242 | + | |
| 13243 | + | |
| 13244 | + | |
| 13245 | + | |
| 13246 | + | |
13201 | 13247 | | |
13202 | 13248 | | |
13203 | 13249 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
271 | 271 | | |
272 | 272 | | |
273 | 273 | | |
274 | | - | |
| 274 | + | |
275 | 275 | | |
276 | 276 | | |
277 | 277 | | |
| |||
754 | 754 | | |
755 | 755 | | |
756 | 756 | | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
441 | 441 | | |
442 | 442 | | |
443 | 443 | | |
444 | | - | |
445 | | - | |
446 | | - | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
447 | 462 | | |
448 | 463 | | |
449 | 464 | | |
| |||
0 commit comments