Skip to content

Commit c496f56

Browse files
committed
Merge branch 'claude/issue-14478-duration-unit-in-key-name' into claude/issue-15682-widen-duration-unit-keys-population
Cards 2/6..5/6 of the #14478 stack landed on the trunk as squashes, which kept their content and destroyed their ancestry, so this branch's merge base rewound to 140e0b2 and seven files conflicted. Every one resolves by taking a side whole; none is hand-merged. Group A - five files this card never touched (head blob == fork point 3351a86), resolved to the TRUNK's side, which carries cards 3/6 and 4/6's later prose corrections: .changeset/kernel-duration-keys-unit-in-key-name.md packages/spec/src/kernel/plugin-security-advanced.test.ts packages/spec/src/migrations/entries/semantic/18.kernel-plugin-security-durations-unit-in-key.ts packages/spec/src/migrations/entries/semantic/18.system-metrics-window-durations-unit-in-key.ts packages/spec/src/migrations/registry.ts Group B - two files that are this card's own work, resolved to THIS BRANCH's side. The trunk contributes nothing to either: its blob is byte-identical to this branch's fork point (check-duration-unit-keys.ts fe98c8f, conversions/registry.ts 07e13ff), so the conflict is an artifact of the rewound base alone: packages/spec/scripts/check-duration-unit-keys.ts packages/spec/src/conversions/registry.ts No merge=os-regen path is modified on both sides (all seven read `merge: unspecified`), so nothing is deferred and there is no regeneration half. The migrations registry takes the trunk's side and loses no row: both sides carry the same 180 retired-key ids, and the only textual difference is prose inside two entries' rationale strings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G4138K1EG7kQ81FNba5Kp4
2 parents 0ae5a8a + 5197579 commit c496f56

9 files changed

Lines changed: 46 additions & 21 deletions

File tree

.changeset/kernel-duration-keys-unit-in-key-name.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,15 @@ registered by exact key in `RETIRED_KEYS_BY_MAJOR`.
9191
`EventSourcingConfig.snapshotRetention` is a COUNT of snapshots and
9292
`MultiVersionSupport.rollout.percentage` is a proportion — neither is a
9393
duration, so neither has a unit to carry and both keep their names.
94-
`RuntimeConfig.resourceLimits.timeout` names no unit anywhere in its prose, so
95-
it is outside the gate's population and outside this rename; a pin test asserts
96-
that, so a later sweep cannot read the four security renames as "every timeout
97-
on that file".
94+
`RuntimeConfig.resourceLimits.timeout` names its unit only in the JSDoc above
95+
the key ("Execution timeout in milliseconds"), a channel
96+
`check:duration-unit-keys` does not read: it reads `.describe()` and
97+
`.meta({ description })`, and this key's describe ("Maximum execution time")
98+
names none. The gate therefore lists it among the duration-shaped keys but
99+
deliberately does not judge it — neither an offender nor an exemption — so it is
100+
outside this rename; that JSDoc-channel gap is filed as #15939. A pin test
101+
asserts the key still parses bare, so a later sweep cannot read the four
102+
security renames as "every timeout on that file".
98103

99104
## Readers moved in the same PR, at the same magnitude
100105

content/docs/getting-started/quick-reference.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ from the provider itself, not from hand-written spec files.
206206
|:---------|:-----------|:------------|:--------|
207207
| **[Connector](/docs/references/integration/connector)** | `connector.zod.ts` | Connector | The connector protocol — auth, sync, webhooks, rate limiting |
208208

209-
## Shared Protocol (5 of 8 schemas)
209+
## Shared Protocol (5 of 9 schemas)
210210

211211
Common utilities used across all protocols.
212212

packages/spec/llms.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ const query = {
7777

7878
---
7979

80-
## 3. Schema Inventory by Domain (207 schemas)
80+
## 3. Schema Inventory by Domain (208 schemas)
8181

8282
Counted as `*.zod.ts` modules under `packages/spec/src/<domain>/` — the sources
8383
that ship in this tarball (`files` includes `src/**/*.zod.ts`), so every number
@@ -91,7 +91,7 @@ here is verifiable from the installed package.
9191
| api | 30 | Endpoint, REST Server, Discovery, OData, Batch, WebSocket, Response Envelope, Package Lifecycle |
9292
| ui | 18 | View, App, Action, Dashboard, Page, Chart, Component, Animation |
9393
| automation | 13 | Flow, Approval, BPMN Interop, Control Flow, State Machine, Webhook |
94-
| shared | 13 | Enums, HTTP, Identifiers, Mapping, Metadata Types, Connector Auth, Retry Policy, Value Domain |
94+
| shared | 14 | Enums, HTTP, Identifiers, Mapping, Metadata Types, Connector Auth, Retry Policy, Value Domain, Epoch Instant (EpochMs) |
9595
| ai | 11 | Agent, Conversation, Knowledge Source/Document, Model Registry, MCP, Skill, Tool |
9696
| cloud | 11 | Marketplace, Developer Portal, App Store, Environment, Package, Tenant |
9797
| identity | 5 | Identity, Organization, Position, SCIM, Eval User |

packages/spec/src/api/websocket.zod.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ export type WebSocketConfigParsed = z.infer<typeof WebSocketConfigSchema>;
471471
* type: 'subscribe',
472472
* channel: 'record.account.123',
473473
* payload: { events: ['created', 'updated'] },
474-
* timestamp: Date.now()
474+
* occurredAt: Date.now()
475475
* }
476476
* ```
477477
*
@@ -481,7 +481,7 @@ export type WebSocketConfigParsed = z.infer<typeof WebSocketConfigSchema>;
481481
* type: 'data-change',
482482
* channel: 'record.account.123',
483483
* payload: { id: '123', action: 'updated', data: {...} },
484-
* timestamp: Date.now()
484+
* occurredAt: Date.now()
485485
* }
486486
* ```
487487
*/

packages/spec/src/kernel/plugin-security-advanced.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,10 @@ describe('Plugin security durations carry their unit (#15678)', () => {
393393
expect(parsed.vulnerabilityDisclosure?.bugBounty).toBe(true);
394394
});
395395

396-
// A NEGATIVE control on the same file: this key names no unit anywhere, so it
397-
// is outside the gate's population and outside this rename. Without it, a
396+
// A NEGATIVE control on the same file: this key names its unit only in the
397+
// JSDoc above it, a channel the gate does not read (it reads `.describe()` and
398+
// `.meta({ description })`) — so the gate lists it without judging it, and it
399+
// is outside this rename. The JSDoc-channel gap is #15939. Without this test, a
398400
// later sweep reads the four renames above as "every timeout on this file".
399401
it('leaves `RuntimeConfig.resourceLimits.timeout` bare — its describe names no unit', () => {
400402
const parsed = RuntimeConfigSchema.parse({

packages/spec/src/kernel/startup-orchestrator.zod.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export type StartupOptionsParsed = z.infer<typeof StartupOptionsSchema>;
9191
* @example
9292
* {
9393
* "healthy": true,
94-
* "timestamp": 1706659200000,
94+
* "checkedAt": 1706659200000,
9595
* "details": {
9696
* "databaseConnected": true,
9797
* "memoryUsage": 45.2
@@ -147,7 +147,7 @@ export type HealthStatus = z.input<typeof HealthStatusSchema>;
147147
* "durationMs": 1250,
148148
* "health": {
149149
* "healthy": true,
150-
* "timestamp": 1706659200000
150+
* "checkedAt": 1706659200000
151151
* }
152152
* }
153153
*/

packages/spec/src/migrations/entries/semantic/18.kernel-plugin-security-durations-unit-in-key.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ export const entry: SemanticMigration = {
3333
+ 'collection member or a stored sys_metadata row and the conversion chain has no seam '
3434
+ 'that would see one. That is what ruling B prescribes for a key that is not authorable '
3535
+ 'metadata. One key deliberately left alone: RuntimeConfig.resourceLimits.timeout on this '
36-
+ 'same file names no unit anywhere, so it is outside the gate\'s population and outside '
37-
+ 'this rename. #15678, #14478, ADR-0087.',
36+
+ 'same file names its unit only in the JSDoc above it ("Execution timeout in '
37+
+ 'milliseconds"), a channel the gate does not read: it reads `.describe()` and '
38+
+ '`.meta({ description })`, and that key\'s describe ("Maximum execution time") names '
39+
+ 'none. So the gate lists it among the duration-shaped keys without judging it — neither '
40+
+ 'an offender nor an exemption — and it is outside this rename; that JSDoc-channel gap is '
41+
+ '#15939. #15678, #14478, ADR-0087.',
3842
acceptanceCriteria:
3943
'Every SandboxConfigSchema.parse(…), KernelSecurityPolicySchema.parse(…) and '
4044
+ 'PluginSecurityManifestSchema.parse(…) site, and every literal handed to a plugin '

packages/spec/src/migrations/entries/semantic/18.system-metrics-window-durations-unit-in-key.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,13 @@ export const entry: SemanticMigration = {
3434
+ 'unchanged: window.durationSeconds: 300 aggregates over five minutes exactly as '
3535
+ 'size: 300 did, and the positive-integer bounds ride along with the renamed keys. Two '
3636
+ 'keys on this same file deliberately do NOT move, and a sweep that renamed either has '
37-
+ 'over-applied the rule: the error-budget burn-rate window, whose describe reads only '
38-
+ '"Window size" and names no unit anywhere, is outside the gate population entirely; '
37+
+ 'over-applied the rule: the error-budget burn-rate window '
38+
+ 'names its unit only in the JSDoc above it ("Window size in seconds"), a channel the '
39+
+ 'gate does not read: it reads `.describe()` and `.meta({ description })`, and that '
40+
+ 'key\'s describe ("Window size") names none. So the gate lists it among the '
41+
+ 'duration-shaped keys without judging it — neither an offender nor an exemption — and '
42+
+ 'it is outside this rename, not outside the gate population; that JSDoc-channel gap is '
43+
+ '#15939; '
3944
+ 'and the exporter batch size is a COUNT of records, not a duration, so it has no unit '
4045
+ 'to carry. Both keep their names.',
4146
};

packages/spec/src/migrations/registry.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7631,8 +7631,12 @@ const step18: MigrationStep = {
76317631
+ 'collection member or a stored sys_metadata row and the conversion chain has no seam '
76327632
+ 'that would see one. That is what ruling B prescribes for a key that is not authorable '
76337633
+ 'metadata. One key deliberately left alone: RuntimeConfig.resourceLimits.timeout on this '
7634-
+ 'same file names no unit anywhere, so it is outside the gate\'s population and outside '
7635-
+ 'this rename. #15678, #14478, ADR-0087.',
7634+
+ 'same file names its unit only in the JSDoc above it ("Execution timeout in '
7635+
+ 'milliseconds"), a channel the gate does not read: it reads `.describe()` and '
7636+
+ '`.meta({ description })`, and that key\'s describe ("Maximum execution time") names '
7637+
+ 'none. So the gate lists it among the duration-shaped keys without judging it — neither '
7638+
+ 'an offender nor an exemption — and it is outside this rename; that JSDoc-channel gap is '
7639+
+ '#15939. #15678, #14478, ADR-0087.',
76367640
acceptanceCriteria:
76377641
'Every SandboxConfigSchema.parse(…), KernelSecurityPolicySchema.parse(…) and '
76387642
+ 'PluginSecurityManifestSchema.parse(…) site, and every literal handed to a plugin '
@@ -8915,8 +8919,13 @@ const step18: MigrationStep = {
89158919
+ 'unchanged: window.durationSeconds: 300 aggregates over five minutes exactly as '
89168920
+ 'size: 300 did, and the positive-integer bounds ride along with the renamed keys. Two '
89178921
+ 'keys on this same file deliberately do NOT move, and a sweep that renamed either has '
8918-
+ 'over-applied the rule: the error-budget burn-rate window, whose describe reads only '
8919-
+ '"Window size" and names no unit anywhere, is outside the gate population entirely; '
8922+
+ 'over-applied the rule: the error-budget burn-rate window '
8923+
+ 'names its unit only in the JSDoc above it ("Window size in seconds"), a channel the '
8924+
+ 'gate does not read: it reads `.describe()` and `.meta({ description })`, and that '
8925+
+ 'key\'s describe ("Window size") names none. So the gate lists it among the '
8926+
+ 'duration-shaped keys without judging it — neither an offender nor an exemption — and '
8927+
+ 'it is outside this rename, not outside the gate population; that JSDoc-channel gap is '
8928+
+ '#15939; '
89208929
+ 'and the exporter batch size is a COUNT of records, not a duration, so it has no unit '
89218930
+ 'to carry. Both keep their names.',
89228931
},

0 commit comments

Comments
 (0)