Skip to content

fix(spec): tombstones for keys live in @objectstack/spec 17.7.0 name 18 as their removal version - #23186

Merged
objectstack-fleet[bot] merged 14 commits into
mainfrom
claude/issue-23145-tombstone-removal-version
Oct 13, 2026
Merged

objectstack-fleet[bot] merged 14 commits into
mainfrom
claude/issue-23145-tombstone-removal-version

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #23145
Clause-②: no (prescription text only: no key, value or shape is accepted or refused differently)

Block lifted. check:future-spec-major went green when the Version Packages pull request #21988 merged and packages/spec/package.json read 18.0.0-next.0.

Fix round (seat notes 6144192235 and 6144323612)

  • Why. main gained two retiredAfter: '17.7.0' entries after the last merge. Unjoined, they trip the pin's completeness guard; on the previous head CI's Test Core (1/6) failed in packages/spec pnpm run test (its annotation; the job log is not readable from this container). main also gained a string of this class, view.data.provider: 'api' "removed in @objectstack/spec 17" (1912af47b, D3-only).
  • Joined. page-action-row-navigation-executor-to-url: the 'navigation' refusal on all four row shapes. cbp-master-detail-required-defaulted: the parse's refusal at sharingModel.
  • Corrected (text only; the literal pins follow):
    • The 'navigation' refusal named no release. It now says the alias is "refused on page action rows since @objectstack/spec 18".
    • The controlled-by-parent refusal named no release. It now says "ADR-0055 §1: since @objectstack/spec 18, …".
    • view.data.provider: 'api' now says "removed in @objectstack/spec 18".
    • The two-master refusal (same function, not on the D2 entry's surface) is unedited and names no release.
  • Measured liveness (parse probes against each tarball, controls accepted):
    • all three shapes, including every controlled_by_parent variant (no master, optional master, required lookup, two masters), are accepted by 17.7.0 and by 18.0.0-next.0;
    • the HEAD build refuses each one with its prescription.
    • So the changeset names next.0 only for its first table. These three rows sit in a second table: 18.0.0-next.0 still accepts them, so the first release that refuses them is the one after it.
  • Release pins. view-data-api-provider-retirement.test.ts pins "@objectstack/spec 18"; view.test.ts and object-storage.test.ts gain one line each.
  • Pending-changeset quotes, corrected in place. 23082:25 (provider: 'api', byte-equal to the emitted string) and 23103:36 (the 'navigation' first sentence, equal to the emitted one). pre/22876:29,31 stay byte-equal.
  • check-empty-changeset stays red by design (DELIBERATE CORRECTION). Verdict at 38728b3e1, verbatim:
This PR changes a changeset it did not add:

   .changeset/23082-view-data-api-provider-retired.md
     present on the merge base and CHANGED by this PR -- this is somebody else's release note
   .changeset/23103-page-action-row-on-success-and-executor.md
     present on the merge base and CHANGED by this PR -- this is somebody else's release note
   .changeset/pre/22876-email-template-category-is-system-retired.md
     present on the merge base and CHANGED by this PR -- this is somebody else's release note

Each note quotes a prescription this PR corrects, and each corrected quote is equal to the emitted text. Restoring any of them from the base would publish a false sentence.

  • Ablation, each leg restored to blob == HEAD:
    • ⑥ the 'navigation' refusal without its release: red, 1 failed / 18 passed, "names no release". The first try was refused by the tool (the replacement was a substring of the anchor; nothing ran).
    • ⑦ the controlled-by-parent refusal without its release: red, 1/18.
  • main since: 9 commits to 6d7f4df3c. None touches packages/spec or adds a retiredAfter line; git merge-tree with it is clean.
  • Not swept: two other new D3 narrowings (page-default-record-page-one-per-object-refused, ui-page-action-row-on-success-shape-closed) whose refusals name no release. They are outside this surface.

Patch round (seat note 6143582707)

  • @objectstack/spec@18.0.0-next.0 reached npm next at 2026-10-13T08:35:43Z, so the changeset's "17.7.0, the newest published release" was false where it is read. It now names 17.7.0 as the newest 17.x release (npm latest) and names 18.0.0-next.0 (56d63b4e7; the fix round split that sentence per table).
  • The next.0 tarball (npm pack into its own directory; integrity sha512-ASTh6…2Ow== matches the packument) refuses all 16 first-table rows with the text this PR replaces, and the sub-day intervals too. Its CHANGELOG.md:2091 and :2093 quote the email_template prescriptions as "…17".
  • Gates at 56d63b4e7: 20 derived, 20 run, 19 exit 0, 1 exit 1 (check-empty-changeset, by design).

Landing round (seat review 6140670883)

  • Merge 071dbdb24 (parents 1ee37155d and d889448b9, the 18.0.0-next.0 version commit), no conflict. The release moved 22876 to .changeset/pre/; git followed the rename, so the two-line correction sits there.
  • Kept (decision A, seat-confirmed). At changeset pre exit the consumed pre/ changesets are read again into the stable 18.0.0 CHANGELOG: @changesets/read@1.0.1 dist/index.mjs:29, @changesets/assemble-release-plan@7.0.0 dist/index.mjs:328 (drops pre/ only while preState.mode !== "exit"), @changesets/apply-release-plan@8.1.1 dist/index.mjs:301-319.
  • RETIRED_SUB_DAY_INTERVALS TSDoc (data/analytics.zod.ts:104, shipped in the .d.ts) now reads "declared through @objectstack/spec 17.4.0; 17.5.0 removed them". Docblock text, not a row.
  • check-issue-citations: the one added citation (#17296) resolves locally ("1 resolves"); the CI annotation was exit 3, the could-not-measure class.

Patch round (seat answer 6139390852)

  • Merge. 7bfd6b035 (parents 936750950 and 20949e7a7), no conflicts, via scripts/pm/os-regen-merge.sh; check:generated green at 1ee37155d.
  • Row 236, the opposite direction. TimeUpdateInterval accepts second / minute / hour in the 17.4.0 tarball (src/data/analytics.zod.ts:53-55) and refuses them in 17.5.0 (:145-148); its D2 cube-sub-day-granularities-removed is retiredAfter: '17.4.0'. The refusal said "retired in protocol 18"; it now says "was removed in @objectstack/spec 17.5.0". It is joined to the pin; its two literal pins follow (spec/src/data/analytics.test.ts, drivers/driver-memory/src/memory-analytics-time-granularity.test.ts).
  • Pending-changeset quotes, BEFORE → AFTER. Every quote the sweep read, against each row's verdict. Paths are as read at e81cae014; the 18.0.0-next.0 release has since moved each of these files into .changeset/pre/:
changeset quote before after
22876-email-template-category-is-system-retired.md:29 (email_template.category) removed in @objectstack/spec 17 edited: removed in @objectstack/spec 18; now byte-equal to the emitted prescription
22876-…md:31 (email_template.isSystem) removed in @objectstack/spec 17 edited: removed in @objectstack/spec 18; byte-equal to the emitted prescription
22161-lint-slice-6-one-line.md:17 (element:filter) removed in @objectstack/spec 17 true as written: element-filter-removed is retiredAfter: '17.0.0', first retired in the 17.1.0 tarball (census), and the tag carries the same prescription (ui/page.zod.ts:114)
22876-…md:36 "(protocol 18, retired from the load path)" true as written: it names the D2 entry's toMajor, not a release
22340-registry-allow-environment-overlay.md:37 "(protocol 18)" true as written: it names the D3 entry's registration major, not a release
22130-protocol-18.md:10 the ADR-0087 marker's id list (cube-sub-day-granularities-removed) an id, not a quote: untouched byte-for-byte
23082-view-data-api-provider-retired.md:25 (fix round) removed in @objectstack/spec 17 edited: removed in @objectstack/spec 18; byte-equal to the emitted string
23103-page-action-row-on-success-and-executor.md:36 (fix round) the 'navigation' refusal's first sentence, no release edited: equal to the emitted first sentence, which now names 18
pre/22340-s3-governed-text-rename.md:9 (landing-round re-sweep) "renamed to allowEnvironmentOverlay in protocol 18" true as written: a paraphrase of the rename naming the protocol major (PROTOCOL_VERSION 18.0.0), not a quote of the prescription

No other changeset quotes a changed prescription. The landing round re-swept the remaining root stock and .changeset/pre/. The sweep covered every .changeset/*.md for each changed sentence and for "17.8.0", "retired in protocol 18", "renamed to allowEnvironmentOverlay" and "legacy form of a package manifest". 22876's frontmatter and marker block are byte-identical (first 12 lines, same md5). This PR's own changeset gains the interval correction.

check-empty-changeset stays red by design (ruling D on #17712, DELIBERATE CORRECTION class): the consumed pre/22876 note still feeds the stable 18.0.0 notes at pre exit, so restoring it from the base would put a false sentence into them. Decision A, seat-confirmed. The current three-file verdict is in the fix-round section.

What changed

Eleven prescription strings named the wrong removal release, or none. Ten are for shapes the @objectstack/spec@17.7.0 tarball still accepts, and they now name 18. The eleventh is the interval refusal above.

  • elementFlatBindingRetired (ui/component.zod.ts): one shared string rendering ten tombstones (element:number object / filter; element:record_picker and element:repeater object / filter / sort / limit). Was 17.
  • object-grid defaultFilters (ui/component.zod.ts). Was 17.
  • email_template.category and email_template.isSystem (system/email-template.zod.ts). Was 17.
  • The flat permission-string list on a package manifest (kernel/manifest.zod.ts, the union arm ManifestPermissionsSchema dropped; D2 manifest-permissions-string-list-removed, retiredAfter: '17.7.0'). Was 17.
  • public in StorageScope (system/object-storage.zod.ts, enumWithRetiredValues; D3 storage-scope-public-retired). Was 17.8.0, a release this train will not cut.
  • MetadataTypeRegistryEntry.allowOrgOverride → allowEnvironmentOverlay (kernel/metadata-plugin.zod.ts). Named no release, an omission against the governing text ("the version that removed it"). The seat ratified the edit.
  • Fix round: the 'navigation' row-executor refusal and the controlled-by-parent no-required-master refusal (both named no release), and view.data.provider: 'api' (was 17).

Every os migrate meta --from 17 sentence is unchanged and correct (H6 below). The test files that pinned the old literals follow. The content/docs/references/** projection is regenerated (14 rows). One changeset, @objectstack/spec patch. One new pin, packages/spec/src/shared/retired-key-removal-version.pin.test.ts. The two non-retiredKey renderers (manifest list, StorageScope.public) and the interval message are seat-ratified surface additions (6139390852).

The enumeration

Population (H2): every RETIRED_KEYS_BY_MAJOR[18] id (232), joined by position (category/Def:key) to its tombstone. Added to those:

  • the three non-key renderers of the five unpublished D2 entries, and the one major-18 D3 value tombstone;
  • the 17.x-shipped interval refusal (row 236, patch round);
  • the fix round's three rows (237–239): two new retiredAfter: '17.7.0' entries and the D3-only view.data.provider: 'api'.

239 rows: 20 edited, 219 unchanged. Edited rows render 11 strings; the 10 element rows share one. Entries at retiredAfter: '17.7.0': 7.

How each column was read:

  • before: the release the guidance names at 121847a7d (row 236: at 936750950).
  • live at the tag: read against the @objectstack/spec@17.7.0 tarball, integrity-verified against the packument, and against tag commit 4e4e88142. Paths are relative to packages/spec/ at 4e4e88142; tarball json-schema/… is the published JSON Schema.
  • yes rows cite the live declaration. no rows cite a [RETIRED] authorable-surface line, a [REMOVED] describe, the tombstone's source line, or the def's retired-defs entry.
  • D2 entry: the conversion the retired-keys entry file names. For the comment-derived join, every row with retiredAfter: '17.7.0' is LIVE at the tag and every earlier stamp is tombstoned there: zero disagreements.
    | # | key (type:key) | registry entry (D2 named in the retired-keys entry file) | toMajor | retiredAfter | live at the tag | before | after |
    | --- | --- | --- | --- | --- | --- | --- | --- |
    | 1 | ai/Agent:lifecycle | agent-lifecycle-removed | 18 | 17.6.0 | no · authorable-surface/ai.json:29 [RETIRED] | 17.7.0 | unchanged |
    | 2 | ai/Agent:memory.longTerm.store | agent-memory-long-term-store-removed | 18 | 17.6.0 | no · tarball json-schema/ai/Agent.json:140 [REMOVED] | 17.7.0 | unchanged |
    | 3 | ai/ConversationAnalytics:duration | retired-keys only | — | — | no · authorable-surface/ai.json:96 [RETIRED] | 17 | unchanged |
    | 4 | api/ApiEndpoint:cacheTtl | api-endpoint-cache-ttl-to-cache-ttl-seconds | 18 | 17.3.0 | no · authorable-surface/api.json:120 [RETIRED] | 17 | unchanged |
    | 5 | api/BatchEndpointsConfig:defaultAtomic | retired-keys only | — | — | no · authorable-surface/api.json:262 [RETIRED] | 17 | unchanged |
    | 6 | api/BatchEndpointsConfig:operations.upsertMany | retired-keys only | — | — | no · tarball json-schema/api/BatchEndpointsConfig.json:37 [REMOVED] | 17 | unchanged |
    | 7 | api/CrudEndpointsConfig:objectParamStyle | retired-keys only | — | — | no · authorable-surface/api.json:425 [RETIRED] | 17 | unchanged |
    | 8 | api/CrudEndpointsConfig:patterns | retired-keys only | — | — | no · authorable-surface/api.json:427 [RETIRED] | 17 | unchanged |
    | 9 | api/DataLoaderConfig:cacheTtl | retired-keys only | — | — | no · authorable-surface/api.json:453 [RETIRED] | 17 | unchanged |
    | 10 | api/DeviceRequestResponse:interval | retired-keys only | — | — | no · authorable-surface/api.json:514 [RETIRED] | 17 | unchanged |
    | 11 | api/EnhancedApiError:retryAfter | retired-keys only | — | — | no · authorable-surface/api.json:603 [RETIRED] | 17 | unchanged |
    | 12 | api/ListInstalledPackagesRequest:cursor | retired-keys only | — | — | no · authorable-surface/api.json:998 [RETIRED] | 17.5.0 | unchanged |
    | 13 | api/ListInstalledPackagesRequest:limit | retired-keys only | — | — | no · authorable-surface/api.json:1000 [RETIRED] | 17.5.0 | unchanged |
    | 14 | api/ListRunsRequest:cursor | retired-keys only | — | — | no · authorable-surface/api.json:1025 [RETIRED] | 17.5.0 | unchanged |
    | 15 | api/MetadataEndpointsConfig:cacheTtl | retired-keys only | — | — | no · authorable-surface/api.json:1073 [RETIRED] | 17 | unchanged |
    | 16 | api/MetadataEndpointsConfig:endpoints.schema | retired-keys only | — | — | no · tarball json-schema/api/MetadataEndpointsConfig.json:49 [REMOVED] | 17 | unchanged |
    | 17 | api/RestApiConfig:documentation.enabled | retired-keys only | — | — | no · tarball json-schema/api/RestApiConfig.json:79 [REMOVED] | 17.5.0 | unchanged |
    | 18 | api/RestApiConfig:documentation.version | retired-keys only | — | — | no · tarball json-schema/api/RestApiConfig.json:91 [REMOVED] | 17.5.0 | unchanged |
    | 19 | api/RestApiConfig:responseFormat | retired-keys only | — | — | no · authorable-surface/api.json:1437 [RETIRED] | 17.5.0 | unchanged |
    | 20 | api/RestApiEndpoint:cacheTtl | retired-keys only | — | — | no · authorable-surface/api.json:1439 [RETIRED] | 17 | unchanged |
    | 21 | api/RestApiEndpoint:handlerStatus | retired-keys only | — | — | no · authorable-surface/api.json:1445 [RETIRED] | 17 | unchanged |
    | 22 | api/RestApiEndpoint:timeout | retired-keys only | — | — | no · authorable-surface/api.json:1455 [RETIRED] | 17 | unchanged |
    | 23 | api/RestApiPluginConfig:performance.defaultCacheTtl | retired-keys only | — | — | no · tarball json-schema/api/RestApiPluginConfig.json:812 [REMOVED] | 17 | unchanged |
    | 24 | api/RouteDefinition:timeout | retired-keys only | — | — | no · authorable-surface/api.json:1512 [RETIRED] | 17 | unchanged |
    | 25 | api/RouteGenerationConfig:excludeObjects | retired-keys only | — | — | no · authorable-surface/api.json:1514 [RETIRED] | 17 | unchanged |
    | 26 | api/RouteGenerationConfig:includeObjects | retired-keys only | — | — | no · authorable-surface/api.json:1515 [RETIRED] | 17 | unchanged |
    | 27 | api/RouteGenerationConfig:nameTransform | retired-keys only | — | — | no · authorable-surface/api.json:1516 [RETIRED] | 17 | unchanged |
    | 28 | api/RouteGenerationConfig:overrides | retired-keys only | — | — | no · authorable-surface/api.json:1517 [RETIRED] | 17 | unchanged |
    | 29 | api/SessionUser:language | retired-keys only | — | — | no · authorable-surface/api.json:1600 [RETIRED] | 17.4.0 | unchanged |
    | 30 | api/SimplePresenceState:lastSeen | retired-keys only | — | — | no · authorable-surface/api.json:1615 [RETIRED] | 17 | unchanged |
    | 31 | api/WebSocketConfig:pingInterval | retired-keys only | — | — | no · authorable-surface/api.json:1771 [RETIRED] | 17 | unchanged |
    | 32 | api/WebSocketConfig:reconnectInterval | retired-keys only | — | — | no · authorable-surface/api.json:1775 [RETIRED] | 17 | unchanged |
    | 33 | api/WebSocketConfig:timeout | retired-keys only | — | — | no · authorable-surface/api.json:1777 [RETIRED] | 17 | unchanged |
    | 34 | api/WebSocketEvent:timestamp | retired-keys only | — | — | no · authorable-surface/api.json:1783 [RETIRED] | 17 | unchanged |
    | 35 | api/WebSocketServerConfig:heartbeatInterval | retired-keys only | — | — | no · authorable-surface/api.json:1787 [RETIRED] | 17 | unchanged |
    | 36 | data/AutoPersistenceConfig:autoSaveInterval | memory-persistence-auto-save-interval-to-ms | 18 | 17.3.0 | no · authorable-surface/data.json:38 [RETIRED] | 17 | unchanged |
    | 37 | data/Cube:refreshKey | cube-refresh-key-removed | 18 | 17.5.0 | no · authorable-surface/data.json:100 [RETIRED] | 17 | unchanged |
    | 38 | data/CubeJoin:relationship | cube-join-sql-and-relationship-removed | 18 | 17.4.0 | no · src/data/analytics.zod.ts:573 | 17 | unchanged |
    | 39 | data/CubeJoin:sql | cube-join-sql-and-relationship-removed | 18 | 17.4.0 | no · src/data/analytics.zod.ts:572 | 17 | unchanged |
    | 40 | data/CurrencyConfig:precision | currency-config-precision-removed | 18 | 17.4.0 | no · src/data/field.zod.ts:453 | 17.5.0 | unchanged |
    | 41 | data/Dimension:name | cube-member-inner-name-removed | 18 | 17.4.0 | no · authorable-surface/data.json:197 [RETIRED] | 17.5.0 | unchanged |
    | 42 | data/DriverOptions:timeout | retired-keys only | — | — | no · authorable-surface/data.json:279 [RETIRED] | 17 | unchanged |
    | 43 | data/ESignatureConfig:expirationDays | retired-keys only | — | — | no · authorable-surface/data.json:288 [RETIRED] | n/a (def retired at HEAD) | unchanged |
    | 44 | data/ESignatureConfig:reminderDays | retired-keys only | — | — | no · authorable-surface/data.json:290 [RETIRED] | n/a (def retired at HEAD) | unchanged |
    | 45 | data/FilePersistenceConfig:autoSaveInterval | memory-persistence-auto-save-interval-to-ms | 18 | 17.3.0 | no · authorable-surface/data.json:444 [RETIRED] | 17 | unchanged |
    | 46 | data/FileValue:duration | retired-keys only | — | — | no · authorable-surface/data.json:449 [RETIRED] | 17 | unchanged |
    | 47 | data/Metric:filters | metric-filters-removed | 18 | 17.1.0 | no · src/data/analytics.zod.ts:367 | 17 | unchanged |
    | 48 | data/Metric:name | cube-member-inner-name-removed | 18 | 17.4.0 | no · authorable-surface/data.json:602 [RETIRED] | 17.5.0 | unchanged |
    | 49 | data/NoSQLQueryOptions:timeout | retired-keys only | — | — | no · authorable-surface/data.json:663 [RETIRED] | 17 | unchanged |
    | 50 | data/TenancyConfig:organizationField | object-tenancy-organization-field-removed | 18 | 17.4.0 | no · src/data/object.zod.ts:543 | 17 | unchanged |
    | 51 | data/TursoConfig:timeout | turso-config-timeout-to-timeout-ms | 18 | 17.3.0 | no · authorable-surface/data.json:1014 [RETIRED] | 17 | unchanged |
    | 52 | integration/CircuitBreakerConfig:monitoringWindow | connector-resilience-keys-removed | 18 | 17.4.0 | no · def retired whole: src/migrations/entries/retired-defs/18.integration__CircuitBreakerConfig.ts | n/a (def retired at HEAD) | unchanged |
    | 53 | integration/Connector:connectionTimeoutMs | connector-connection-timeout-ms-removed | 18 | 17.4.0 | no · authorable-surface/integration.json:15 [RETIRED] | 17 | unchanged |
    | 54 | integration/Connector:errorMapping | connector-error-mapping-removed | 18 | 17.3.0 | no · authorable-surface/integration.json:18 [RETIRED] | 17 | unchanged |
    | 55 | integration/Connector:fieldMappings | retired-keys only | — | — | no · authorable-surface/integration.json:19 [RETIRED] | 17 | unchanged |
    | 56 | integration/Connector:health | connector-resilience-keys-removed | 18 | 17.4.0 | no · authorable-surface/integration.json:20 [RETIRED] | 17 | unchanged |
    | 57 | integration/Connector:status | connector-resilience-keys-removed | 18 | 17.4.0 | no · authorable-surface/integration.json:30 [RETIRED] | 17 | unchanged |
    | 58 | integration/Connector:syncConfig | connector-sync-keys-removed | 18 | 17.5.0 | no · authorable-surface/integration.json:31 [RETIRED] | 17 | unchanged |
    | 59 | integration/Connector:triggers | connector-triggers-removed | 18 | 17.5.0 | no · authorable-surface/integration.json:32 [RETIRED] | 17 | unchanged |
    | 60 | integration/Connector:webhooks | connector-resilience-keys-removed | 18 | 17.4.0 | no · authorable-surface/integration.json:34 [RETIRED] | 17 | unchanged |
    | 61 | integration/ConnectorTrigger:interval | connector-triggers-removed | 18 | 17.5.0 | no · def retired whole: src/migrations/entries/retired-defs/18.integration__ConnectorTrigger.ts | n/a (def retired at HEAD) | unchanged |
    | 62 | integration/DeclarativeConnectorEntry:connectionTimeoutMs | retired-keys only | — | — | no · authorable-surface/integration.json:61 [RETIRED] | 17 | unchanged |
    | 63 | integration/DeclarativeConnectorEntry:errorMapping | retired-keys only | — | — | no · authorable-surface/integration.json:64 [RETIRED] | 17 | unchanged |
    | 64 | integration/DeclarativeConnectorEntry:fieldMappings | retired-keys only | — | — | no · authorable-surface/integration.json:65 [RETIRED] | 17 | unchanged |
    | 65 | integration/DeclarativeConnectorEntry:health | retired-keys only | — | — | no · authorable-surface/integration.json:66 [RETIRED] | 17 | unchanged |
    | 66 | integration/DeclarativeConnectorEntry:status | retired-keys only | — | — | no · authorable-surface/integration.json:76 [RETIRED] | 17 | unchanged |
    | 67 | integration/DeclarativeConnectorEntry:syncConfig | retired-keys only | — | — | no · authorable-surface/integration.json:77 [RETIRED] | 17 | unchanged |
    | 68 | integration/DeclarativeConnectorEntry:triggers | retired-keys only | — | — | no · authorable-surface/integration.json:78 [RETIRED] | 17 | unchanged |
    | 69 | integration/DeclarativeConnectorEntry:webhooks | retired-keys only | — | — | no · authorable-surface/integration.json:80 [RETIRED] | 17 | unchanged |
    | 70 | kernel/CompatibilityMatrixEntry:estimatedMigrationTime | retired-keys only | — | — | no · authorable-surface/kernel.json:33 [RETIRED] | 17 | unchanged |
    | 71 | kernel/EventPersistence:retention | retired-keys only | — | — | no · authorable-surface/kernel.json:130 [RETIRED] | 17 | unchanged |
    | 72 | kernel/EventSourcingConfig:retention | retired-keys only | — | — | no · authorable-surface/kernel.json:149 [RETIRED] | 17 | unchanged |
    | 73 | kernel/HealthStatus:timestamp | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.kernel__HealthStatus.ts | n/a (def retired at HEAD) | unchanged |
    | 74 | kernel/HotReloadConfig:debounceDelay | retired-keys only | — | — | no · authorable-surface/kernel.json:212 [RETIRED] | 17 | unchanged |
    | 75 | kernel/HotReloadConfig:watchPatterns | retired-keys only | — | — | no · authorable-surface/kernel.json:218 [RETIRED] | 17.3.0 | unchanged |
    | 76 | kernel/KernelContext:previewMode | retired-keys only | — | — | no · authorable-surface/kernel.json:243 [RETIRED] | 17 | unchanged |
    | 77 | kernel/KernelContext:startTime | retired-keys only | — | — | no · authorable-surface/kernel.json:244 [RETIRED] | 17 | unchanged |
    | 78 | kernel/KernelSecurityPolicy:auditLog.retention | retired-keys only | — | — | no · tarball json-schema/kernel/KernelSecurityPolicy.json:195 [REMOVED] | 17 | unchanged |
    | 79 | kernel/KernelSecurityPolicy:authentication.tokenExpiration | retired-keys only | — | — | no · tarball json-schema/kernel/KernelSecurityPolicy.json:134 [REMOVED] | 17 | unchanged |
    | 80 | kernel/Manifest:capabilities | retired-keys only | — | — | no · authorable-surface/kernel.json:259 [RETIRED] | 17 | unchanged |
    | 81 | kernel/Manifest:configuration | retired-keys only | — | — | no · authorable-surface/kernel.json:260 [RETIRED] | 17 | unchanged |
    | 82 | kernel/Manifest:contributes.actions | retired-keys only | — | — | no · tarball json-schema/kernel/Manifest.json:180 [REMOVED] | 17 | unchanged |
    | 83 | kernel/Manifest:contributes.commands | retired-keys only | — | — | no · tarball json-schema/kernel/Manifest.json:200 [REMOVED] | 17 | unchanged |
    | 84 | kernel/Manifest:contributes.drivers | retired-keys only | — | — | no · tarball json-schema/kernel/Manifest.json:184 [REMOVED] | 17 | unchanged |
    | 85 | kernel/Manifest:contributes.events | retired-keys only | — | — | no · tarball json-schema/kernel/Manifest.json:164 [REMOVED] | 17 | unchanged |
    | 86 | kernel/Manifest:contributes.fieldTypes | retired-keys only | — | — | no · tarball json-schema/kernel/Manifest.json:188 [REMOVED] | 17 | unchanged |
    | 87 | kernel/Manifest:contributes.functions | retired-keys only | — | — | no · tarball json-schema/kernel/Manifest.json:192 [REMOVED] | 17 | unchanged |
    | 88 | kernel/Manifest:contributes.kinds.globs | retired-keys only | — | — | no · tarball json-schema/kernel/Manifest.json:149 [REMOVED] | 17 | unchanged |
    | 89 | kernel/Manifest:contributes.menus | retired-keys only | — | — | no · tarball json-schema/kernel/Manifest.json:168 [REMOVED] | 17 | unchanged |
    | 90 | kernel/Manifest:contributes.routes | retired-keys only | — | — | no · tarball json-schema/kernel/Manifest.json:196 [REMOVED] | 17 | unchanged |
    | 91 | kernel/Manifest:contributes.themes | retired-keys only | — | — | no · tarball json-schema/kernel/Manifest.json:172 [REMOVED] | 17 | unchanged |
    | 92 | kernel/Manifest:contributes.translations | retired-keys only | — | — | no · tarball json-schema/kernel/Manifest.json:176 [REMOVED] | 17 | unchanged |
    | 93 | kernel/Manifest:extensions | retired-keys only | — | — | no · authorable-surface/kernel.json:269 [RETIRED] | 17 | unchanged |
    | 94 | kernel/MetadataManagerConfig:cache.enabled | retired-keys only | — | — | no · tarball json-schema/kernel/MetadataManagerConfig.json:52 [REMOVED] | 17 | unchanged |
    | 95 | kernel/MetadataManagerConfig:cache.maxSize | retired-keys only | — | — | no · tarball json-schema/kernel/MetadataManagerConfig.json:64 [REMOVED] | 17 | unchanged |
    | 96 | kernel/MetadataManagerConfig:cache.ttl | retired-keys only | — | — | no · tarball json-schema/kernel/MetadataManagerConfig.json:60 [REMOVED] | 17 | unchanged |
    | 97 | kernel/MetadataManagerConfig:cache.ttlSeconds | retired-keys only | — | — | no · tarball json-schema/kernel/MetadataManagerConfig.json:56 [REMOVED] | 17 | unchanged |
    | 98 | kernel/MetadataManagerConfig:persistence.overlayWritable | retired-keys only | — | — | no · tarball json-schema/kernel/MetadataManagerConfig.json:177 [REMOVED] | 17 | unchanged |
    | 99 | kernel/MetadataPluginConfig:additionalTypes | retired-keys only | — | — | no · authorable-surface/kernel.json:310 [RETIRED] | 17 | unchanged |
    | 100 | kernel/MetadataPluginConfig:customizationPolicies | retired-keys only | — | — | no · authorable-surface/kernel.json:313 [RETIRED] | 17 | unchanged |
    | 101 | kernel/MetadataPluginConfig:mergeStrategy | retired-keys only | — | — | no · authorable-surface/kernel.json:316 [RETIRED] | 17 | unchanged |
    | 102 | kernel/MetadataTypeRegistryEntry:allowOrgOverride | retired-keys only | — | — | yes · src/kernel/metadata-plugin.zod.ts:267 | none | 18 |
    | 103 | kernel/MultiVersionSupport:rollout.duration | retired-keys only | — | — | no · tarball json-schema/kernel/MultiVersionSupport.json:139 [REMOVED] | 17 | unchanged |
    | 104 | kernel/PackageDependencyResolutionResult:resolvedIn | retired-keys only | — | — | no · authorable-surface/kernel.json:397 [RETIRED] | 17 | unchanged |
    | 105 | kernel/PluginHealthCheck:autoRestart | retired-keys only | — | — | no · authorable-surface/kernel.json:439 [RETIRED] | 17.3.0 | unchanged |
    | 106 | kernel/PluginHealthCheck:interval | retired-keys only | — | — | no · authorable-surface/kernel.json:442 [RETIRED] | 17 | unchanged |
    | 107 | kernel/PluginHealthCheck:maxRestartAttempts | retired-keys only | — | — | no · authorable-surface/kernel.json:444 [RETIRED] | 17.3.0 | unchanged |
    | 108 | kernel/PluginHealthCheck:restartBackoff | retired-keys only | — | — | no · authorable-surface/kernel.json:445 [RETIRED] | 17.3.0 | unchanged |
    | 109 | kernel/PluginHealthCheck:timeout | retired-keys only | — | — | no · authorable-surface/kernel.json:447 [RETIRED] | 17 | unchanged |
    | 110 | kernel/PluginHealthReport:metrics.responseTime | retired-keys only | — | — | no · tarball json-schema/kernel/PluginHealthReport.json:57 [REMOVED] | 17 | unchanged |
    | 111 | kernel/PluginHealthReport:metrics.uptime | retired-keys only | — | — | no · tarball json-schema/kernel/PluginHealthReport.json:53 [REMOVED] | 17 | unchanged |
    | 112 | kernel/PluginQualityMetrics:securityScan | retired-keys only | — | — | no · authorable-surface/kernel.json:511 [RETIRED] | 17 | unchanged |
    | 113 | kernel/PluginSecurityManifest:scanResults | retired-keys only | — | — | no · authorable-surface/kernel.json:552 [RETIRED] | 17 | unchanged |
    | 114 | kernel/PluginSecurityManifest:vulnerabilities | retired-keys only | — | — | no · authorable-surface/kernel.json:555 [RETIRED] | 17 | unchanged |
    | 115 | kernel/PluginSecurityManifest:vulnerabilityDisclosure.responseTime | retired-keys only | — | — | no · tarball json-schema/kernel/PluginSecurityManifest.json:824 [REMOVED] | 17 | unchanged |
    | 116 | kernel/PluginStartupResult:duration | retired-keys only | — | — | no · authorable-surface/kernel.json:557 [RETIRED] | 17 | unchanged |
    | 117 | kernel/PluginStartupResult:health | retired-keys only | — | — | no · authorable-surface/kernel.json:560 [RETIRED] | 17 | unchanged |
    | 118 | kernel/PluginStartupResult:plugin | retired-keys only | — | — | no · authorable-surface/kernel.json:561 [RETIRED] | 17 | unchanged |
    | 119 | kernel/PluginStartupResult:startTime | retired-keys only | — | — | no · authorable-surface/kernel.json:563 [RETIRED] | 17 | unchanged |
    | 120 | kernel/RuntimeConfig:resourceLimits.timeout | retired-keys only | — | — | no · tarball json-schema/kernel/RuntimeConfig.json:146 [REMOVED] | 17 | unchanged |
    | 121 | kernel/SandboxConfig:process.timeout | retired-keys only | — | — | no · tarball json-schema/kernel/SandboxConfig.json:165 [REMOVED] | 17 | unchanged |
    | 122 | kernel/StartupOptions:timeout | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.kernel__StartupOptions.ts | n/a (def retired at HEAD) | unchanged |
    | 123 | kernel/StartupOrchestrationResult:totalDuration | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.kernel__StartupOrchestrationResult.ts | n/a (def retired at HEAD) | unchanged |
    | 124 | kernel/TenantRuntimeContext:previewMode | retired-keys only | — | — | no · authorable-surface/kernel.json:732 [RETIRED] | 17 | unchanged |
    | 125 | kernel/TenantRuntimeContext:startTime | retired-keys only | — | — | no · authorable-surface/kernel.json:733 [RETIRED] | 17 | unchanged |
    | 126 | kernel/UpgradePlan:estimatedDuration | retired-keys only | — | — | no · authorable-surface/kernel.json:763 [RETIRED] | 17 | unchanged |
    | 127 | qa/TestScenario:requires.plugins | retired-keys only | — | — | no · tarball json-schema/qa/TestScenario.json:403 [REMOVED] | 17.5.0 | unchanged |
    | 128 | security/EffectiveObjectPermission:allowPurge | permission-allow-restore-purge-removed | 18 | 17.2.0 | no · authorable-surface/security.json:56 [RETIRED] | 17 | unchanged |
    | 129 | security/EffectiveObjectPermission:allowRestore | permission-allow-restore-purge-removed | 18 | 17.2.0 | no · authorable-surface/security.json:58 [RETIRED] | 17 | unchanged |
    | 130 | security/ObjectPermission:allowPurge | permission-allow-restore-purge-removed | 18 | 17.2.0 | no · authorable-surface/security.json:101 [RETIRED] | 17 | unchanged |
    | 131 | security/ObjectPermission:allowRestore | permission-allow-restore-purge-removed | 18 | 17.2.0 | no · authorable-surface/security.json:103 [RETIRED] | 17 | unchanged |
    | 132 | security/RowLevelSecurityPolicy:tags | permission-rls-tags-removed | 18 | 17.4.0 | no · authorable-surface/security.json:153 [RETIRED] | 17.5.0 | unchanged |
    | 133 | system/AccessControlConfig:maxAge | retired-keys only | — | — | no · authorable-surface/system.json:13 [RETIRED] | 17 | unchanged |
    | 134 | system/CacheAvalanchePrevention:circuitBreaker.resetTimeout | retired-keys only | — | — | no · tarball json-schema/system/CacheAvalanchePrevention.json:46 [REMOVED] | 17 | unchanged |
    | 135 | system/CacheTier:ttl | retired-keys only | — | — | no · authorable-surface/system.json:193 [RETIRED] | 17 | unchanged |
    | 136 | system/ChangeImpact:downtime.durationMinutes | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__ChangeImpact.ts | n/a (def retired at HEAD) | unchanged |
    | 137 | system/ChangeRequest:implementation.steps.estimatedMinutes | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__ChangeRequest.ts | n/a (def retired at HEAD) | unchanged |
    | 138 | system/CollaborationSessionConfig:idleTimeout | retired-keys only | — | — | no · authorable-surface/system.json:223 [RETIRED] | 17 | unchanged |
    | 139 | system/CollaborationSessionConfig:snapshot.interval | retired-keys only | — | — | no · tarball json-schema/system/CollaborationSessionConfig.json:77 [REMOVED] | 17 | unchanged |
    | 140 | system/EmailTemplateDefinition:category | email-template-category-is-system-removed | 18 | 17.7.0 | yes · src/system/email-template.zod.ts:106 | 17 | 18 |
    | 141 | system/EmailTemplateDefinition:isSystem | email-template-category-is-system-removed | 18 | 17.7.0 | yes · src/system/email-template.zod.ts:193 | 17 | 18 |
    | 142 | system/FailoverConfig:healthCheckInterval | retired-keys only | — | — | no · authorable-surface/system.json:426 [RETIRED] | 17 | unchanged |
    | 143 | system/HttpDestinationConfig:batch.flushInterval | retired-keys only | — | — | no · tarball json-schema/system/HttpDestinationConfig.json:79 [REMOVED] | 17 | unchanged |
    | 144 | system/HttpDestinationConfig:retry.initialDelay | retired-keys only | — | — | no · tarball json-schema/system/HttpDestinationConfig.json:106 [REMOVED] | 17 | unchanged |
    | 145 | system/HttpDestinationConfig:timeout | retired-keys only | — | — | no · authorable-surface/system.json:466 [RETIRED] | 17 | unchanged |
    | 146 | system/IncidentNotificationMatrix:escalationTimeoutMinutes | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__IncidentNotificationMatrix.ts | n/a (def retired at HEAD) | unchanged |
    | 147 | system/IncidentNotificationRule:regulatorDeadlineHours | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__IncidentNotificationRule.ts | n/a (def retired at HEAD) | unchanged |
    | 148 | system/IncidentNotificationRule:withinMinutes | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__IncidentNotificationRule.ts | n/a (def retired at HEAD) | unchanged |
    | 149 | system/IncidentResponsePhase:targetHours | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__IncidentResponsePhase.ts | n/a (def retired at HEAD) | unchanged |
    | 150 | system/IncidentResponsePolicy:retentionDays | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__IncidentResponsePolicy.ts | n/a (def retired at HEAD) | unchanged |
    | 151 | system/IncidentResponsePolicy:triageDeadlineHours | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__IncidentResponsePolicy.ts | n/a (def retired at HEAD) | unchanged |
    | 152 | system/Job:timeout | job-timeout-to-timeout-ms | 18 | 17.3.0 | no · authorable-surface/system.json:488 [RETIRED] | 17 | unchanged |
    | 153 | system/LoggingConfig:buffer.flushInterval | retired-keys only | — | — | no · tarball json-schema/system/LoggingConfig.json:408 [REMOVED] | 17 | unchanged |
    | 154 | system/MetricAggregationConfig:window.size | retired-keys only | — | — | no · tarball json-schema/system/MetricAggregationConfig.json:34 [REMOVED] | 17 | unchanged |
    | 155 | system/MetricDefinition:summary.maxAge | retired-keys only | — | — | no · tarball json-schema/system/MetricDefinition.json:174 [REMOVED] | 17 | unchanged |
    | 156 | system/MetricExportConfig:interval | retired-keys only | — | — | no · authorable-surface/system.json:739 [RETIRED] | 17 | unchanged |
    | 157 | system/MetricsConfig:collectionInterval | retired-keys only | — | — | no · authorable-surface/system.json:744 [RETIRED] | 17 | unchanged |
    | 158 | system/MetricsConfig:retention.period | retired-keys only | — | — | no · tarball json-schema/system/MetricsConfig.json:737 [REMOVED] | 17 | unchanged |
    | 159 | system/OpenTelemetryCompatibility:exporter.batch.exportTimeout | retired-keys only | — | — | no · tarball json-schema/system/OpenTelemetryCompatibility.json:96 [REMOVED] | 17 | unchanged |
    | 160 | system/OpenTelemetryCompatibility:exporter.batch.scheduledDelay | retired-keys only | — | — | no · tarball json-schema/system/OpenTelemetryCompatibility.json:100 [REMOVED] | 17 | unchanged |
    | 161 | system/OpenTelemetryCompatibility:exporter.timeout | retired-keys only | — | — | no · tarball json-schema/system/OpenTelemetryCompatibility.json:55 [REMOVED] | 17 | unchanged |
    | 162 | system/QueueConfig:rateLimit.duration | retired-keys only | — | — | no · tarball json-schema/system/QueueConfig.json:33 [REMOVED] | 17 | unchanged |
    | 163 | system/RegistryConfig:cache.ttl | retired-keys only | — | — | no · tarball json-schema/system/RegistryConfig.json:236 [REMOVED] | 17 | unchanged |
    | 164 | system/RegistryUpstream:syncInterval | retired-keys only | — | — | no · authorable-surface/system.json:930 [RETIRED] | 17 | unchanged |
    | 165 | system/RegistryUpstream:timeout | retired-keys only | — | — | no · authorable-surface/system.json:933 [RETIRED] | 17 | unchanged |
    | 166 | system/RollbackPlan:steps.estimatedMinutes | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__RollbackPlan.ts | n/a (def retired at HEAD) | unchanged |
    | 167 | system/SchemaLevelIsolationStrategy:performance.schemaCacheTTL | retired-keys only | — | — | no · tarball json-schema/system/SchemaLevelIsolationStrategy.json:94 [REMOVED] | 17 | unchanged |
    | 168 | system/ServiceLevelIndicator:window.size | retired-keys only | — | — | no · tarball json-schema/system/ServiceLevelIndicator.json:76 [REMOVED] | 17 | unchanged |
    | 169 | system/ServiceLevelObjective:errorBudget.burnRateWindows.window | retired-keys only | — | — | no · tarball json-schema/system/ServiceLevelObjective.json:91 [REMOVED] | 17 | unchanged |
    | 170 | system/ServiceLevelObjective:period.duration | retired-keys only | — | — | no · tarball json-schema/system/ServiceLevelObjective.json:46 [REMOVED] | 17 | unchanged |
    | 171 | system/Span:duration | retired-keys only | — | — | no · authorable-surface/system.json:1062 [RETIRED] | 17 | unchanged |
    | 172 | system/StorageConnection:timeout | retired-keys only | — | — | no · authorable-surface/system.json:1125 [RETIRED] | 17 | unchanged |
    | 173 | system/TracingConfig:performance.exportInterval | retired-keys only | — | — | no · tarball json-schema/system/TracingConfig.json:608 [REMOVED] | 17 | unchanged |
    | 174 | system/TrainingCourse:durationMinutes | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__TrainingCourse.ts | n/a (def retired at HEAD) | unchanged |
    | 175 | system/TrainingCourse:validityDays | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__TrainingCourse.ts | n/a (def retired at HEAD) | unchanged |
    | 176 | system/TrainingPlan:gracePeriodDays | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__TrainingPlan.ts | n/a (def retired at HEAD) | unchanged |
    | 177 | system/TrainingPlan:recertificationIntervalDays | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__TrainingPlan.ts | n/a (def retired at HEAD) | unchanged |
    | 178 | system/TrainingPlan:reminderDaysBefore | retired-keys only | — | — | no · def retired whole: src/migrations/entries/retired-defs/18.system__TrainingPlan.ts | n/a (def retired at HEAD) | unchanged |
    | 179 | ui/Action:aria | action-aria-removed | 18 | 17.4.0 | no · authorable-surface/ui.json:13 [RETIRED] | 17.5.0 | unchanged |
    | 180 | ui/ChartConfig:aria | chart-config-aria-removed | 18 | 17.4.0 | no · authorable-surface/ui.json:262 [RETIRED] | 17 | unchanged |
    | 181 | ui/Dashboard:refreshInterval | dashboard-refresh-interval-to-refresh-interval-seconds | 18 | 17.3.0 | no · authorable-surface/ui.json:327 [RETIRED] | 17 | unchanged |
    | 182 | ui/DashboardWidgetChartConfig:series | dashboard-widget-chart-config-structure-removed | 18 | 17.4.0 | no · authorable-surface/ui.json:377 [RETIRED] | 17.5.0 | unchanged |
    | 183 | ui/DashboardWidgetChartConfig:type | dashboard-widget-chart-config-structure-removed | 18 | 17.4.0 | no · authorable-surface/ui.json:382 [RETIRED] | 17.5.0 | unchanged |
    | 184 | ui/DashboardWidgetChartConfig:xAxis | dashboard-widget-chart-config-structure-removed | 18 | 17.4.0 | no · authorable-surface/ui.json:383 [RETIRED] | 17.5.0 | unchanged |
    | 185 | ui/DashboardWidgetChartConfig:yAxis | dashboard-widget-chart-config-structure-removed | 18 | 17.4.0 | no · authorable-surface/ui.json:384 [RETIRED] | 17.5.0 | unchanged |
    | 186 | ui/ElementFilterProps:aria | element-filter-removed | 18 | 17.0.0 | no · authorable-surface/ui.json:448 [RETIRED] | 17 | unchanged |
    | 187 | ui/ElementFilterProps:fields | element-filter-removed | 18 | 17.0.0 | no · authorable-surface/ui.json:449 [RETIRED] | 17 | unchanged |
    | 188 | ui/ElementFilterProps:layout | element-filter-removed | 18 | 17.0.0 | no · authorable-surface/ui.json:450 [RETIRED] | 17 | unchanged |
    | 189 | ui/ElementFilterProps:object | element-filter-removed | 18 | 17.0.0 | no · authorable-surface/ui.json:451 [RETIRED] | 17 | unchanged |
    | 190 | ui/ElementFilterProps:showSearch | element-filter-removed | 18 | 17.0.0 | no · authorable-surface/ui.json:452 [RETIRED] | 17 | unchanged |
    | 191 | ui/ElementFilterProps:targetVariable | element-filter-removed | 18 | 17.0.0 | no · authorable-surface/ui.json:453 [RETIRED] | 17 | unchanged |
    | 192 | ui/ElementFormProps:aria | element-form-removed | 18 | 17.2.0 | no · authorable-surface/ui.json:454 [RETIRED] | 17 | unchanged |
    | 193 | ui/ElementFormProps:fields | element-form-removed | 18 | 17.2.0 | no · authorable-surface/ui.json:455 [RETIRED] | 17 | unchanged |
    | 194 | ui/ElementFormProps:mode | element-form-removed | 18 | 17.2.0 | no · authorable-surface/ui.json:456 [RETIRED] | 17 | unchanged |
    | 195 | ui/ElementFormProps:object | element-form-removed | 18 | 17.2.0 | no · authorable-surface/ui.json:457 [RETIRED] | 17 | unchanged |
    | 196 | ui/ElementFormProps:onSubmit | element-form-removed | 18 | 17.2.0 | no · authorable-surface/ui.json:458 [RETIRED] | 17 | unchanged |
    | 197 | ui/ElementFormProps:submitLabel | element-form-removed | 18 | 17.2.0 | no · authorable-surface/ui.json:459 [RETIRED] | 17 | unchanged |
    | 198 | ui/ElementNumberProps:filter | element-flat-data-binding-to-data-source | 18 | 17.7.0 | yes · src/ui/component.zod.ts:2606 | 17 | 18 |
    | 199 | ui/ElementNumberProps:object | element-flat-data-binding-to-data-source | 18 | 17.7.0 | yes · src/ui/component.zod.ts:2585 | 17 | 18 |
    | 200 | ui/ElementRecordPickerProps:filter | element-flat-data-binding-to-data-source | 18 | 17.7.0 | yes · src/ui/component.zod.ts:3041 | 17 | 18 |
    | 201 | ui/ElementRecordPickerProps:limit | element-flat-data-binding-to-data-source | 18 | 17.7.0 | yes · src/ui/component.zod.ts:3064 | 17 | 18 |
    | 202 | ui/ElementRecordPickerProps:object | element-flat-data-binding-to-data-source | 18 | 17.7.0 | yes · src/ui/component.zod.ts:2995 | 17 | 18 |
    | 203 | ui/ElementRecordPickerProps:sort | element-flat-data-binding-to-data-source | 18 | 17.7.0 | yes · src/ui/component.zod.ts:3054 | 17 | 18 |
    | 204 | ui/ElementRecordPickerProps:targetVariable | element-input-target-variable-removed | 18 | 17.0.0 | no · authorable-surface/ui.json:491 [RETIRED] | 17 | unchanged |
    | 205 | ui/ElementRepeaterProps:filter | element-flat-data-binding-to-data-source | 18 | 17.7.0 | yes · src/ui/component.zod.ts:4093 | 17 | 18 |
    | 206 | ui/ElementRepeaterProps:limit | element-flat-data-binding-to-data-source | 18 | 17.7.0 | yes · src/ui/component.zod.ts:4097 | 17 | 18 |
    | 207 | ui/ElementRepeaterProps:object | element-flat-data-binding-to-data-source | 18 | 17.7.0 | yes · src/ui/component.zod.ts:4075 | 17 | 18 |
    | 208 | ui/ElementRepeaterProps:sort | element-flat-data-binding-to-data-source | 18 | 17.7.0 | yes · src/ui/component.zod.ts:4095 | 17 | 18 |
    | 209 | ui/ElementTextInputProps:targetVariable | element-input-target-variable-removed | 18 | 17.0.0 | no · authorable-surface/ui.json:509 [RETIRED] | 17 | unchanged |
    | 210 | ui/FormField:publicPicker | form-field-public-picker-removed | 18 | 17.5.0 | no · authorable-surface/ui.json:538 [RETIRED] | 17.6.0 | unchanged |
    | 211 | ui/JoinedReportBlock:chart | report-joined-chart-removed | 18 | 17.4.0 | no · src/ui/report.zod.ts:289 | 17.5.0 | unchanged |
    | 212 | ui/ListView:pageName | view-page-mount-removed | 18 | 17.4.0 | no · authorable-surface/ui.json:757 [RETIRED] | 17.5.0 | unchanged |
    | 213 | ui/ListView:tabs | view-list-tabs-removed | 18 | 17.4.0 | no · authorable-surface/ui.json:771 [RETIRED] | 17.5.0 | unchanged |
    | 214 | ui/NavigationConfig:view | retired-keys only | — | — | no · authorable-surface/ui.json:787 [RETIRED] | 17.5.0 | unchanged |
    | 215 | ui/ObjectGridProps:defaultFilters | object-grid-default-filters-removed | 18 | 17.7.0 | yes · src/ui/component.zod.ts:4498 | 17 | 18 |
    | 216 | ui/ObjectGridProps:defaultSort | object-grid-default-sort-removed | 18 | 17.2.0 | no · authorable-surface/ui.json:867 [RETIRED] | 17 | unchanged |
    | 217 | ui/ObjectGridProps:resizableColumns | object-grid-resizable-columns-removed | 18 | 17.6.0 | no · authorable-surface/ui.json:885 [RETIRED] | 17.7.0 | unchanged |
    | 218 | ui/ObjectKanbanProps:quickAdd | object-kanban-quick-add-removed | 18 | 17.4.0 | no · authorable-surface/ui.json:911 [RETIRED] | 17 | unchanged |
    | 219 | ui/ObjectListView:pageName | view-page-mount-removed | 18 | 17.4.0 | no · authorable-surface/ui.json:943 [RETIRED] | 17.5.0 | unchanged |
    | 220 | ui/ObjectListView:tabs | view-list-tabs-removed | 18 | 17.4.0 | no · authorable-surface/ui.json:957 [RETIRED] | 17.5.0 | unchanged |
    | 221 | ui/ObjectMasterDetailFormProps:details.sortField | object-master-detail-form-detail-sort-field-removed | 18 | 17.6.0 | no · tarball json-schema/ui/ObjectMasterDetailFormProps.json:1321 [REMOVED] | 17 | unchanged |
    | 222 | ui/Page:assignedProfiles | page-assigned-profiles-removed | 18 | 17.4.0 | no · authorable-surface/ui.json:1053 [RETIRED] | 17.5.0 | unchanged |
    | 223 | ui/PageComponent:responsive | page-component-responsive-removed | 18 | 17.2.0 | no · authorable-surface/ui.json:1087 [RETIRED] | 17 | unchanged |
    | 224 | ui/PageHeaderProps:breadcrumb | page-header-breadcrumb-removed | 18 | 17.5.0 | no · authorable-surface/ui.json:1096 [RETIRED] | 17 | unchanged |
    | 225 | ui/RecordHighlightsField:icon | record-highlights-field-icon-removed | 18 | 17.1.0 | no · src/ui/component.zod.ts:1626 | 17 | unchanged |
    | 226 | ui/ReportChart:aria | chart-config-aria-removed | 18 | 17.4.0 | no · authorable-surface/ui.json:1251 [RETIRED] | 17 | unchanged |
    | 227 | ui/ViewItem:hidden | view-item-owner-hidden-removed | 18 | 17.4.0 | no · tarball json-schema/ui/ViewItem.json:2355 [REMOVED] | 17.5.0 | unchanged |
    | 228 | ui/ViewItem:owner | view-item-owner-hidden-removed | 18 | 17.4.0 | no · tarball json-schema/ui/ViewItem.json:2351 [REMOVED] | 17.5.0 | unchanged |
    | 229 | ui/ViewItemWire:hidden | view-item-owner-hidden-removed | 18 | 17.4.0 | no · tarball json-schema/ui/ViewItemWire.json:2355 [REMOVED] | 17.5.0 | unchanged |
    | 230 | ui/ViewItemWire:owner | view-item-owner-hidden-removed | 18 | 17.4.0 | no · tarball json-schema/ui/ViewItemWire.json:2351 [REMOVED] | 17.5.0 | unchanged |
    | 231 | ui/ViewMetadata:hidden | view-overlay-owner-hidden-removed | 18 | 17.4.0 | no · src/ui/view.zod.ts:5025 | 17.5.0 | unchanged |
    | 232 | ui/ViewMetadata:owner | view-overlay-owner-hidden-removed | 18 | 17.4.0 | no · src/ui/view.zod.ts:5024 | 17.5.0 | unchanged |
    | 233 | manifest permissions as a string list (union arm; ManifestPermissionsSchema) | manifest-permissions-string-list-removed | 18 | 17.7.0 | yes · src/kernel/manifest.zod.ts:94-95 | 17 | 18 |
    | 234 | StorageScope value public (enumWithRetiredValues) | D3 storage-scope-public-retired | — | — | yes · src/system/object-storage.zod.ts:40 | 17.8.0 | 18 |
    | 235 | indexes[].unique: true (value; IndexSchema.unique) | declared-index-unique-scope | 18 | 17.7.0 | yes · src/data/object.zod.ts:490 | protocol 18 | unchanged |
    | 236 | TimeUpdateInterval members second / minute / hour (value; its error map) — patch round | cube-sub-day-granularities-removed | 18 | 17.4.0 | no · src/data/analytics.zod.ts:169 already refuses; 17.4.0 tarball src/data/analytics.zod.ts:53-55 accepts them, 17.5.0 tarball :145-148 refuses | protocol 18 | 17.5.0 |
    | 237 | 'navigation' as a page action row's executor (action:button / action:icon actionType, action:group / action:menu member type) — fix round | page-action-row-navigation-executor-to-url | 18 | 17.7.0 | yes · accepted by the 17.7.0 tarball (measured) and by 18.0.0-next.0 | none | 18 |
    | 238 | controlled_by_parent object with no master_detail declared required: true — fix round | cbp-master-detail-required-defaulted | 18 | 17.7.0 | yes · accepted by the 17.7.0 tarball (measured; the tag has no one-master refusal) and by 18.0.0-next.0 | none | 18 |
    | 239 | view.data.provider: 'api' (union arm; D3 only, out of the pin's reach) — fix round | D3 view-data-api-provider-retired | — | — | yes · src/ui/view.zod.ts:190 (provider: z.literal('api')); accepted by the 17.7.0 tarball and by 18.0.0-next.0 | 17 | 18 |

Zero-hit controls on the join:

  • No HEAD tombstone names 18: 0 of 226 visible in the JSON Schema tree.
  • No tombstone a 17.x tarball carries names a release inconsistent with the first tarball carrying it: 0 of 212, against the 17.0.0–17.7.0 tarballs, all integrity-verified.
  • retiredAfter stamps disagreeing with the tarballs: 0 of 117.
  • git diff 4e4e88142 936750950: added non-comment retiredKey( lines are exactly the 14 LIVE rows, and the one added enumWithRetiredValues( is StorageScope.
  • Positive control: the 17.4.0 tarball's retired ids equal the committed census's 17.4.0 row (73).

Controls kept at 17, all toMajor: 18: page-header-breadcrumb-removed (17.5.0), object-grid-default-sort-removed (17.2.0) and object-kanban-quick-add-removed (17.4.0).

Zone 2, measured

  • H1: falsified on the count. conversions/registry.ts holds 5 entries with retiredAfter: '17.7.0', not 4; the fifth is declared-index-unique-scope, whose prescription already says "protocol 18" and is unchanged. (At the fix-round head: 7, after main added the two entries the fix round joins.) The tag @objectstack/spec@17.7.0 peels to 4e4e88142, and defaultFilters is live there at src/ui/component.zod.ts:4498.
  • H2: holds. Only the conversion registry carries retiredAfter. The retired-keys registry holds ids only, under one major 18 for both shipped and unshipped keys.
  • H3: holds. All 117 retired stamps agree with the tarballs, including 17.5.0–17.7.0, which the census has not recorded. The 5 unpublished entries are exactly the 17.7.0 set and are all live at the tag.
  • H4: no reader exists, so the pin derives the newest stable release instead of hard-coding 17.7.0. The census trails at 17.4.0, and the census test's helpers are test-local. The pin reads the highest stable version the tree records: census, stamps, and the label when it is stable. It takes the next major from PROTOCOL_MAJOR. Simulated facts pin four windows: a stable 17.x label on the v18 train, a prerelease label, label 18.0.0, and the 17.x minor line.
  • H5: holds. All ten element keys are live at the tag (rows 198–208).
  • H6: holds; nothing to change. composeMigrationChain keeps majors above N, so --from 17 replays step 18. The pin asserts --from equals toMajor - 1.

The pin

For each joined retired conversion, the pin derives the removal major from retiredAfter. It then reads every tombstone parse refusal and [REMOVED] describe (or the refusal, for a value or arm) and asserts they name that major and nothing else. Two guards:

  • every entry retired after the newest published stable release must be joined;
  • the rows must derive both PROTOCOL_MAJOR and an older major.

Joined: the seven unpublished entries, three 17.x controls, and cube-sub-day-granularities-removed: 19 cases. Out of reach by construction: a retirement with no D2 entry (allowOrgOverride, StorageScope.public, view.data.provider: 'api'); the last two carry a one-line literal release pin instead.

Ablation via node scripts/ablation-replace.mjs … -- vitest run on the pin, each leg from committed state and restored to blob == HEAD with git diff HEAD empty:

  • ① defaultFilters 18→17: red, 1 failed / 15 passed. Head 8d3a9c21b.
  • ② the shared element string 18→17: red, 1/15. Head 8d3a9c21b.
  • ③ the control breadcrumb 17→18: red, 1/15. Head 8d3a9c21b. The first try was an anchor miss the tool refused (exit 3, nothing written).
  • ④ unjoin the manifest row: red, 4/12. Head 8d3a9c21b.
  • ⑤ (patch round, head 1ee37155d) the interval string back to "was retired in protocol 18": red, 1 failed / 16 passed, on cube-sub-day-granularities-removed: "retiredAfter 17.4.0 (newest published stable 17.7.0) derives @objectstack/spec 17, but the prescription names 18". Restored to blob b7e1a037def1 == HEAD.
  • ⑥ and ⑦ (fix round, head 38728b3e1): the 'navigation' and controlled-by-parent refusals without their release: red, 1 failed / 18 passed each. Restored to blobs fb3ad73747ac and 6347359316f2 == HEAD.

Verification (head 38728b3e1, fix round)

  • Merge b24018c07 (parents 56d63b4e7 and 197fbe2c0) via os-regen-merge.sh. content/docs/references/ui/component.mdx merged without a text merge; it was regenerated (gen:schema + gen:docs, d0b4cfd1a) and differs from origin/main by exactly this branch's 11 rows.
  • Turbo builds: the spec closure, then the workspace, 74/74. check:generated: "All 14 generated artifacts are up to date". The provider: 'api' text lives in an error map, so there is no references row to regenerate.
  • Tests:
    • spec --project local: 668 files, 20229 passed, 1 todo (the pin's 19 cases included);
    • spec --project repo, all src/** members plus references-banner: 35 files, 473 passed;
    • lint: 138 files, 6679 passed;
    • verify parent-write-reach.test.ts: 10 passed.
  • typecheck: spec and lint exit 0.
  • dispatch-gates --commands: 113, all run.
    • 112 exit 0, 3 of them after a workspace build (PREREQUISITE NOT MET on the first pass).
    • 1 exit 1: check-empty-changeset, by design (see the fix-round section).
    • --ran: "113 derived, 113 run, 0 NOT-MEASURED, 0 UNRUN".
  • check:future-spec-major: "✓ … no @objectstack/spec citation names a major above 18".
  • CI on 38728b3e1: TypeScript Type Check (4/4 lanes), Test Core, Build Core and Lint & Repo Gates are green; Check Changeset is red by design.

Acceptance notes

  • NOT MEASURED locally:
    • the 23 scripts/** members of spec's repo project (none reads an edited file);
    • the CI-only jobs and type-check lanes outside the derived list and the source-gates lane.
    • Value-level prescriptions naming no release were not swept.
  • retired-after.census.json trails the published line (17.5.0–17.7.0, and now 18.0.0-next.0, which the census never records as a prerelease). No live defect: every stamp agrees with the tarballs.

Generated by Claude Code

…18 as their removal version

The v18 train runs in Changesets pre mode, so the first release that refuses a
retirement stamped `retiredAfter: '17.7.0'` is 18.0.0, not a 17.x minor. Seven
prescriptions named 17 (or 17.8.0, or no version) for shapes the 17.7.0
tarball still accepts: the ten element flat-binding keys (one shared string),
object-grid `defaultFilters`, email_template `category` / `isSystem`, the
package-manifest permission-string list, StorageScope `public`, and the
`allowOrgOverride` rename. Tests pinning the literal follow.

Claude-Session: https://claude.ai/code/session_012uFegdfR6K6uqvLzt7XsdZ
Co-authored-by: Claude <noreply@anthropic.com>
…e its registry entry derives

The pin reads `retiredAfter` off each joined ADR-0087 conversion, the newest
published stable release off the tree (the census, every stamp, a stable
label) and the next release's major off PROTOCOL_MAJOR, and asserts every
tombstone or refusal for that surface names that major, and that its
`os migrate meta --from N` is toMajor - 1. Every entry retired after the
newest published stable release must be joined, so a future retirement cannot
ship its prescription unjudged.

Claude-Session: https://claude.ai/code/session_012uFegdfR6K6uqvLzt7XsdZ
Co-authored-by: Claude <noreply@anthropic.com>
…apes 17.7.0 still accepts

Claude-Session: https://claude.ai/code/session_012uFegdfR6K6uqvLzt7XsdZ
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 11 documentable anchor(s).

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx (via allowOrgOverride (symbol, a field of const object MetadataTypeRegistryEntryBaseSchema, an authorable key of kernel/MetadataTypeRegistryEntry))
What this run could not see
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 141 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 6f4c518b012a3959ba6c7d414b5fa085ad135c17 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from fadfc9acc8ec12a7ecaaa8b55feac525596b8df0 — the merge of head 38728b3e1b37ed00bed9da54be08198fd7fe1bd8 into base 6f4c518b012a3959ba6c7d414b5fa085ad135c17, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin fadfc9acc8ec12a7ecaaa8b55feac525596b8df0 && git checkout fadfc9acc8ec12a7ecaaa8b55feac525596b8df0
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6f4c518b012a3959ba6c7d414b5fa085ad135c17 38728b3e1b37ed00bed9da54be08198fd7fe1bd8 && git checkout -B drift-repro 6f4c518b012a3959ba6c7d414b5fa085ad135c17 && git merge --no-ff 38728b3e1b37ed00bed9da54be08198fd7fe1bd8

node scripts/docs-audit/affected-docs.mjs --json 6f4c518b012a3959ba6c7d414b5fa085ad135c17

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 6f4c518b012a3959ba6c7d414b5fa085ad135c17 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

…e that removed it

`TimeUpdateInterval` accepted `second` / `minute` / `hour` through the 17.4.0
tarball and refuses them from 17.5.0 (the D2 entry
`cube-sub-day-granularities-removed` is `retiredAfter: '17.4.0'`), but the
refusal said "retired in protocol 18". It now says "was removed in
@objectstack/spec 17.5.0", and the derived removal-version pin joins the entry,
so it guards the 17.x-shipped direction too.

Claude-Session: https://claude.ai/code/session_012uFegdfR6K6uqvLzt7XsdZ
Co-authored-by: Claude <noreply@anthropic.com>
…criptions as they now read (deliberate correction)

`.changeset/22876-email-template-category-is-system-retired.md` lines 29 and 31
quote the two `email_template` prescriptions, which now name
@objectstack/spec 18; the quotes said 17. Nothing else in that file changes.
This PR's own changeset records the sub-day time-interval correction too.

Claude-Session: https://claude.ai/code/session_012uFegdfR6K6uqvLzt7XsdZ
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

DELIBERATE CORRECTION: check-empty-changeset is red by design on this PR (ruling D on #17712; the Check Changeset lane, node scripts/check-empty-changeset.mjs --base origin/main).

What changed. This PR changes .changeset/22876-email-template-category-is-system-retired.md, a pending release note it did not add. Only lines 29 and 31 move. Those lines quote the email_template.category and email_template.isSystem prescriptions, which this PR corrects from "removed in @objectstack/spec 17" to "removed in @objectstack/spec 18". Each quote is now byte-equal to the prescription the schema emits. The frontmatter and the marker block are byte-identical.

Why it is not restored. .changeset/pre.json has consumed nothing, so the note compiles into the 18.0.0-next.0 CHANGELOG. It is corrected in place, before #21988 merges. Restoring it from the merge base would republish a sentence this PR makes false. The seat ruled this correction on #23145 (comment 6139390852).

The gate's verdict at head 1ee37155d, verbatim:

This PR changes a changeset it did not add:
   .changeset/22876-email-template-category-is-system-retired.md
     present on the merge base and CHANGED by this PR -- this is somebody else's release note

The other by-design red, check:future-spec-major, is covered in the PR body's "Blocked on #21988" section.


Generated by Claude Code

…ared and removed them

`RETIRED_SUB_DAY_INTERVALS`' TSDoc, which ships in the `.d.ts`, said the enum
declared the three names "until protocol 18". The 17.4.0 tarball is the last
release declaring them, and 17.5.0 removed them. This PR's changeset also notes
that the 18.0.0-next.0 release notes quoted the two email_template
prescriptions with the earlier version.

Claude-Session: https://claude.ai/code/session_012uFegdfR6K6uqvLzt7XsdZ
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Supersedes the gate-and-reason note 6140567986. check-empty-changeset is still red by design (DELIBERATE CORRECTION), now on the pre/ path (ruling D on #17712; the Check Changeset lane, node scripts/check-empty-changeset.mjs --base origin/main).

What moved. The 18.0.0-next.0 release did not delete 22876; it moved it, like every consumed prerelease changeset, to .changeset/pre/22876-email-template-category-is-system-retired.md. This PR's merge (071dbdb24) followed the rename. So the correction (lines 29 and 31: "removed in @objectstack/spec 17" → "18", each quote byte-equal to the emitted prescription) now sits in that file. Nothing else in it changes.

Why it is kept (seat decision A). At changeset pre exit, the pre/ changesets are read again and aggregated into the stable 18.0.0 CHANGELOG. Measured in the installed packages:

  • @changesets/read@1.0.1 dist/index.mjs:29 reads .changeset/pre/;
  • @changesets/assemble-release-plan@7.0.0 dist/index.mjs:328 drops pre/ changesets only while preState.mode !== "exit";
  • @changesets/apply-release-plan@8.1.1 dist/index.mjs:301-319 moves them into pre/ under pre mode and removes them at the stable cut.

So the correction reaches the stable 18.0.0 notes. Restoring the file from the base would put "removed in @objectstack/spec 17" into them, a false sentence. The 18.0.0-next.0 notes already printed the old quote; this PR's own changeset says so in one sentence.

The gate's verdict at head 90cfa7ace, verbatim:

This PR changes a changeset it did not add:
   .changeset/pre/22876-email-template-category-is-system-retired.md
     present on the merge base and CHANGED by this PR -- this is somebody else's release note

check-future-spec-major is green on this head ("no @objectstack/spec citation names a major above 18"), so that block is lifted.


Generated by Claude Code

…0 the first that refuses these shapes

`@objectstack/spec@18.0.0-next.0` was published after this changeset was
written, so "17.7.0, the newest published release" stopped being true where
the sentence is read. Every shape in the table is refused by the published
18.0.0-next.0 tarball and accepted by 17.7.0.

Claude-Session: https://claude.ai/code/session_012uFegdfR6K6uqvLzt7XsdZ
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Supersedes 6143438580. check-empty-changeset is still red by design (DELIBERATE CORRECTION) on .changeset/pre/22876-email-template-category-is-system-retired.md; nothing about it changed at head 56d63b4e7. (Ruling D on #17712; the Check Changeset lane.)

  • Why it stays. Lines 29 and 31 of that consumed prerelease changeset quote the email_template prescriptions; this PR corrects them from 17 to 18, byte-equal to what the schema emits. At changeset pre exit the pre/ files are read again into the stable 18.0.0 notes (@changesets/read@1.0.1 dist/index.mjs:29; @changesets/assemble-release-plan@7.0.0 :328; @changesets/apply-release-plan@8.1.1 :301-319). Restoring the file would print the false "17" there. The 18.0.0-next.0 notes already printed it: the tarball's CHANGELOG.md:2091 and :2093.
  • This head. It changes one changeset sentence. 18.0.0-next.0 is now published, so 17.7.0 is "the newest 17.x release (npm latest)", and 18.0.0-next.0 "the first release that refuses" the table's shapes. Every row was measured refused in that tarball, with its old text.

Verdict at 56d63b4e7, verbatim:

This PR changes a changeset it did not add:
   .changeset/pre/22876-email-template-category-is-system-retired.md
     present on the merge base and CHANGED by this PR -- this is somebody else's release note

Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 56d63b4e79e18dbb7311d97dda88ab2c54b906e0
Local-runs: probe — npm pack @objectstack/spec@18.0.0-next.0 into a new empty scratch directory, read with grep/sed only (its integrity matches the packument), to verify the release claims the changeset and the DELIBERATE CORRECTION rest on: tarball CHANGELOG.md:2091 and :2093, and that the published next.0 refuses every table row and the sub-day members with the text this PR replaces.

Verdict in one paragraph. Everything this head's own diff changes is right: the seven strings and the interval refusal name the release that actually stops accepting each shape, the pin derives that release correctly in both directions under the prerelease label, the changeset is true sentence by sentence at patch / Clause-②: no, the RETIRED_SUB_DAY_INTERVALS TSDoc is true, and the DELIBERATE CORRECTION on .changeset/pre/22876 is CONFIRMED. The FAIL is about the tree this head will land on, not the diff: origin/main moved after the dev's last sweep (merge base d889448b9), and it now carries two more retiredAfter: '17.7.0' conversions (page-action-row-navigation-executor-to-url, cbp-master-detail-required-defaulted; 7 such entries, the PR's enumeration counts 5) and one new prescription of exactly this card's class, packages/spec/src/ui/view.zod.ts:193 "view.data.provider: 'api' was removed in @objectstack/spec 17", for a shape that is live at the 17.7.0 tag (view.zod.ts:190, provider: z.literal('api'), commit 1912af47b landed 2026-10-13T08:47Z, after next.0 published). On the merged tree the pin's completeness guard ("every entry retired after the newest published stable release is joined") refuses the two unjoined ids, and ci.yml runs Test Core on merge_group, so this head cannot land green through the queue; and the card's nail ("fix all of them in one PR") is no longer met on main. The remedy is one round: merge origin/main; join the two new ids to JOIN with the prescriptions their surfaces render and correct any that name 17; correct view.zod.ts:193 (and any literal pin on it) to 18; re-count the enumeration; re-request the at-tier review on the new head. Everything below carries over to that head unchanged.

Inputs read. Card #23145 body and all 10 comments; PR #23186 body in full, its 4 comments, its 21-file list and the net diff against main; the 50 check-runs on the head; origin/main at 01a3421f4/197fbe2c0 and the head tree read-only (the shared checkout's FETCH_HEAD was moved by another fetch mid-review, so every head read was re-pinned to the 40-hex sha, and one early merge-base reading taken off the moved ref was discarded); the 17.7.0 tag tree 4e4e88142, which is on origin/main's history (the clone is shallow below it, so 17.4.0 and 17.5.0 trees are not readable here); the npm packument (latest 17.7.0, next 18.0.0-next.0 published 2026-10-13T08:35:43Z, no 17.8.0 exists, nothing published between 17.7.0 and next.0). /home/user/objectstack has no node_modules, so the three @changesets/* citations were read from the lockfile-pinned copies (pnpm-lock.yaml on origin/main pins read@1.0.1, assemble-release-plan@7.0.0, apply-release-plan@8.1.1) in a sibling worktree's pnpm store.

Check-runs on the head. First read (about 10:55Z): 50 runs — 28 success, 10 skipped, 3 failure (all Check Changeset, the by-design red below), 9 in_progress. Second read (about 11:10Z, after the coordinator's notice): 51 runs — 35 success, 10 skipped, 4 failure, 2 in_progress (Test Core (3/6), Test Core (4/6)). The fourth failure is Test Core (1/6), job 115256817478, completed 2026-10-13T11:06:01Z: by the seat's reading of its log (card comment 6144192235), the PR's own pin fails its completeness guard at retired-key-removal-version.pin.test.ts:248 on the two unjoined retiredAfter: '17.7.0' entries named in the verdict paragraph — which is exactly what the merged-tree reading below predicts, so I take it as read. Build Core, Test Core 2/5/6, all four Type Check lanes (source gates included), every Lint lane, Lint & Repo Gates, Spec property liveness and Governed Surface Queue Guard are green. The contract is judged on the diff; the red is judged in ① and in the verdict.

① Derived judgments

Accept set: unchanged — verified, not only claimed. The diff edits string literals and one TSDoc sentence: elementFlatBindingRetired's shared template and the defaultFilters guidance (ui/component.zod.ts), EMAIL_TEMPLATE_CATEGORY_REMOVED / EMAIL_TEMPLATE_IS_SYSTEM_REMOVED, PLUGIN_PERMISSIONS_LIST_FORM, STORAGE_SCOPE_PUBLIC_RETIRED, the allowOrgOverride guidance, timeUpdateIntervalRefusalMessage. No retiredKey(, enumWithRetiredValues(, enum, union or .strict() construct moves; the file list touches neither conversions/registry.ts nor migrations/**; PROTOCOL_VERSION stays 18.0.0. Nothing is accepted or refused differently. RIGHT.

Public surface that does change, each named right:

  • Shipped refusal text, 7 strings rendering 17 prescriptions. All 16 table rows are LIVE at the 17.7.0 tag tree (4e4e88142: defaultFilters as z.array(…) at component.zod.ts:4498; the ten element keys at :2585/:2606, :2995/:3041/:3054/:3064, :4075/:4093/:4095/:4097; category/isSystem at email-template.zod.ts:106/:193; the string-list arm at manifest.zod.ts:94-95; 'public' at object-storage.zod.ts:40; allowOrgOverride: z.boolean() at metadata-plugin.zod.ts:267) and REFUSED in the published 18.0.0-next.0 (probe: dist carries the old text for every row — 56 hits of removed in @objectstack/spec 17 (ADR-0087 D2), 16 each of the two email_template strings, 20 of the manifest list string, 6 of 17.8.0, 18 of the release-less allowOrgOverride string, 0 of removed in @objectstack/spec 18; the [REMOVED] describes sit in json-schema/ui/ObjectGridProps.json, json-schema/system/EmailTemplateDefinition.json, json-schema/ui/ElementRepeaterProps.json, json-schema/kernel/MetadataTypeRegistryEntry.json). No release lies between 17.7.0 and 18.0.0-next.0. So "removed in @objectstack/spec 18" / "renamed … in @objectstack/spec 18" names the release that stops accepting each shape. RIGHT, all 16 rows.
  • The sub-day TimeUpdateInterval refusal, "retired in protocol 18" to "removed in @objectstack/spec 17.5.0": the retirement (TimeUpdateInterval declares eight intervals while driver-memory answers 501 for three — the ADR-0049 enforce-or-remove question #17206's changeset promises a card for #17296, 9c44eed) is an entry of the ## 17.5.0 section of packages/spec/CHANGELOG.md (line 18689 under the header at 7980); the committed census's 17.4.0 row (73 ids) does not carry cube-sub-day-granularities-removed; the registry stamps it retiredAfter: '17.4.0'; the refusal is already present at the 17.7.0 tag (analytics.zod.ts:164-169). 17.4.0 accepts, 17.5.0 refuses. RIGHT.
  • JSON Schema [REMOVED] descriptions: retiredKey() describes as [REMOVED] ${guidance} (retired-key.ts:186), so the 14 key tombstones' describes carry the corrected text; the three regenerated content/docs/references/** pages (1 + 2 + 11 = 14 rows) follow byte-for-byte. RIGHT.
  • .d.ts text: the RETIRED_SUB_DAY_INTERVALS TSDoc now reads "declared through @objectstack/spec 17.4.0; 17.5.0 removed them" — TRUE by the three readings above. The (#17296) citation was already there, resolves per the dev's diff-scoped check-issue-citations run, and check:doc-authoring governs runtime strings, not comments.
  • Every os migrate meta --from 17 sentence is untouched and right: --from N replays the majors above N, so --from 17 replays the step-18 chain (the next.0 notes say the same at CHANGELOG.md:468).

The 219 unchanged rows, sampled adversarially — on the head. packages/spec/src/** (non-test) at the head has 0 hits for 17.8.0, 0 for retired in protocol 18, exactly 7 for @objectstack/spec 18 (the seven edited strings) and 202 for removed in @objectstack/spec 17. The discriminator for this class is whether a tombstone landed after the 17.7.0 cut. git diff from the main commit at the 17.7.0 publish time (1c563af40, 2026-10-06T12:06Z) to the head, spec sources non-test, adds exactly these retiredKey( / enumWithRetiredValues( lines: allowOrgOverride, category, isSystem, StorageScopeSchema, the ten element keys, defaultFilters — the rows this PR edits and nothing else; the only added lines naming a 17 release are the new 17.5.0 interval line and a relocated 'pdf' exportOptions refusal that already existed at the tag (view.zod.ts:2351-2364), so it is 17.x-shipped and outside this class. The three controls (breadcrumb 17.5.0, defaultSort 17.2.0, quickAdd 17.4.0) keep "17" and are pin-joined; the fifth 17.7.0 entry at the merge base, declared-index-unique-scope, says "retired at protocol 18" (major 18) and is pin-joined. On the head, no string the diff leaves alone names a wrong release for a shape of this class.

The same sample on origin/main — WRONG, and the reason for the verdict. Since the merge base, main added view.zod.ts:193 "view.data.provider: 'api' was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove)" (1912af47b, "retire the view-level api data source", 2026-10-13T08:47Z). The shape is live at the 17.7.0 tag (view.zod.ts:190) and no 17.x release after 17.7.0 exists, so the string must name 18; it is a D3-only retirement (migrations/entries/semantic/18.view-data-api-provider-retired.ts), so the derived pin cannot reach it. main also added two D2 conversions stamped retiredAfter: '17.7.0' (page-action-row-navigation-executor-to-url, cbp-master-detail-required-defaulted, both toMajor: 18), which the pin's completeness guard requires joined and which JOIN does not name — a RED on the merged tree, not a passing one.

The pin (shared/retired-key-removal-version.pin.test.ts).

  • Derivation: removalMajor(retiredAfter) gives PROTOCOL_MAJOR when retiredAfter is at or above the newest recorded stable release, else the line's major when a later release on that line is recorded, else the next major. "Newest published stable" is the maximum over the census releases (which trail at 17.4.0), every retiredAfter stamp (maximum 17.7.0) and the package label only when the label is stable — under 18.0.0-next.0 the label is excluded, so the answer is 17.7.0, which is right today (npm latest); PROTOCOL_MAJOR is 18 (protocol-version.ts:22-25, lockstep-tested against the package major). Checked by hand: the five 17.7.0 stamps derive 18; 17.5.0 / 17.2.0 / 17.4.0 derive 17; the simulated-facts cases cover a stable 17.x label on the v18 train, the prerelease label, the 18.0.0 label and the 17.x line; once 18.0.0 is the label a 17.7.0 stamp still derives 18. A non-stable stamp throws at module load — loud, not silent.
  • Both directions: a joined prescription fails if any named major differs from the derived one (named.every), if it names no release at all (named.length must exceed 0), or if its --from is not toMajor − 1. So a 17.7.0-stamped string reverting to 17 fails (the dev's ablations ① ②) and a 17.x-shipped string naming 18 fails (③ ⑤); the construction supports those reported reds, which I did not re-run (read-only).
  • Completeness: every retired entry stamped at or above the newest stable must be joined (ablation ④). This is the guard that refuses the merged tree today (Test Core (1/6)), which is the pin working as designed.
  • Is a guard that makes every future retirement PR edit this pin file an acceptable ratchet? Yes, judged on three points. (1) The failure text is self-explanatory: it names the newest stable release, each offending id with its retiredAfter, the map to extend (JOIN) and what a row holds ("the tombstones or refusals an author meets for its surface"); vitest prints the file path and line beside it. A dev who has never seen the file can act on it, as the seat's fix round shows. (2) The merge-conflict surface is real but marginal: a retirement PR already edits two shared registries (conversions/registry.ts and the ADR-0087 retired-keys entries) and the liveness ledger, so one more shared file changes little; two concurrent retirement PRs that both append to JOIN conflict textually at most on adjacent lines, and the resolution is "keep both rows". The repo's stated preference for per-file registration (AGENTS.md on ADR anchors: one file per anchor, no index) names the lower-conflict shape — a per-entry locator on the conversion itself, from which the join is derived with no hand-kept map — but that is a registry type change outside this card, a follow-up and not a defect. (3) The guard refuses only a retirement PR that ships its prescription unjudged, which is the defect this card exists for; it cannot red an unrelated PR. One trap to carry into the fix round: the guard keys on retiredAfter being at or above the newest stable, so after 18.0.0 ships, every entry stamped 18.0.0 must be joined too — the ratchet tightens by design, not by accident.
  • Should the verdict on 56d63b4e7 be FAIL on this alone? Yes. A PASS record exists to lift the landing, and the landing rule needs every check green; this head's own instrument reds its required test lane on the tree it would land on, and the red is substantive (two prescriptions unjudged), not cosmetic. The diff is not at fault — the same diff on a head that has merged main and joined both ids passes this section — but the record is rendered on a head, and this head is not the one to land. The provider: 'api' string in ① is a second, independent reason.
  • Where it can pass while a string is wrong (named; acceptable for this PR): (1) it compares majors only — "17.6.0" for the sub-day row would pass; the exact 17.5.0 is held by the literal pins in data/analytics.test.ts and driver-memory/src/memory-analytics-time-granularity.test.ts; (2) rows older than the newest stable are joined only by hand (four are); (3) a retirement with no D2 entry has no retiredAfter to derive from — allowOrgOverride and StorageScope.public as the PR says, every "retired-keys only" row, and now view.data.provider: 'api'. allowOrgOverride's "18" is literal-pinned in metadata-type-registry-allow-org-override-retirement.test.ts; the StorageScope string has no literal pin on its release (object-storage.test.ts:59 matches the text without the version). That gap is small — the string is right and the next.0 notes record the removal under ## 18.0.0-next.0 — and the card's nail asks a derived pin only of entries with a toMajor: 18 registry row, which a D3-only value has none of; a one-line literal pin would close it in the patch round.

② Semver level

@objectstack/spec patch, Clause-②: no in both the changeset body and the PR body — RIGHT. No key, value, arm or shape is accepted or refused differently (① above); a wrong release name in shipped prescription text is a bug fix in a released package, which AGENTS.md Post-Task #3 gives a patch. Under pre mode this moves the fixed group from 18.0.0-next.0 to 18.0.0-next.1. No ADR-0087 marker is owed (nothing breaks, nothing registers).

The changeset, sentence by sentence against the head and the published line:

  • Line 9: "17.7.0, the newest 17.x release (npm latest), still accepts every shape below, and 18.0.0-next.0 is the first release that refuses them." — TRUE: latest is 17.7.0 and no 17.8.0 exists; every row is live at the tag tree; every row is refused in the next.0 tarball; nothing was published between them.
  • "No 17.x release removes them: the 18 line does." — TRUE.
  • The six Was/Now table rows match the diff, including 17.8.0 to 18 and "renamed (no release named)" to "renamed in @objectstack/spec 18".
  • "The 18.0.0-next.0 release notes quoted the two email_template prescriptions with the earlier version, 17; from this release on they name 18." — TRUE: tarball CHANGELOG.md:2091 and :2093 are those two quotes, inside ## 18.0.0-next.0 (header at line 3; packages/spec/CHANGELOG.md on origin/main reads the same there). The next release's notes carry this entry, and the stable 18.0.0 aggregate re-renders 22876 with 18 (③ below).
  • The sub-day sentence (17.4.0 accepts, 17.5.0 refuses; "retired in protocol 18" to "removed in @objectstack/spec 17.5.0") — TRUE (①).
  • "The os migrate meta --from 17 sentence in each prescription is unchanged and was already right" — TRUE; "A prescription for a key that a 17.x release already refuses keeps naming 17." — TRUE (controls untouched); "Text only: no key, value or shape is accepted or refused differently." — TRUE.
  • One sentence will need re-reading on the next head: "every shape below" is still true, but the table (and the PR body's 236 rows / 5 entries at 17.7.0) is now short of main by the provider: 'api' row and the two new entries.

③ Boundary flags

The DELIBERATE CORRECTION on .changeset/pre/22876-email-template-category-is-system-retired.md — CONFIRMED.

  • Only lines 29 and 31 differ from the merge base (2 insertions, 2 deletions, nothing else in the file). Each is byte-equal to > followed by the string the head's email-template.zod.ts emits (assembled from EMAIL_TEMPLATE_CATEGORY_REMOVED / EMAIL_TEMPLATE_IS_SYSTEM_REMOVED and compared as bytes).
  • The file is live text, not dead: .changeset/pre.json on main is { "mode": "pre", "tag": "next" } with no consumed list, because @changesets/cli@3 keeps the consumed set on disk — @changesets/read@1.0.1 dist/index.mjs:29 reads .changeset/pre/ and ids its files pre/…; @changesets/assemble-release-plan@7.0.0 dist/index.mjs:328 drops pre/ ids only while preState.mode !== "exit"; @changesets/apply-release-plan@8.1.1 dist/index.mjs:301-319 renames a consumed changeset into pre/ under pre mode and fs.rms it otherwise. So at changeset pre exit the 507 pre/ files, this one included, are aggregated into the stable 18.0.0 CHANGELOG entry, and restoring the base text would print "removed in @objectstack/spec 17" there, under a package that has refused the keys since 18.0.0-next.0. Keeping the correction is right.
  • Check Changeset (pr-automation.yml) triggers on pull_request only — the workflow has no merge_group trigger — so the red does not reach the queue; the gate's own remedy for this class (check-empty-changeset.mjs:551/:563: "do NOT restore it -- say so on the PR and get it confirmed") is met by PR comment 6143855611 and by this record. The three Check Changeset failures on the head are that one red, run three times.
  • PR comment 6143855611 is accurate on every checkable sentence: the two lines, byte-equality, the three citations, the tarball lines, and the gate's class text (check-empty-changeset.mjs:570, the M row: "present on the merge base and CHANGED by this PR -- this is somebody else's release note"). The one earlier inaccuracy ("corrected in place, before chore: version packages (next) #21988 merges", 6140567986) was superseded on the card and is not on the live note.
  • This confirmation carries to the patched head provided the two lines stay byte-equal to what the schema emits.

Dev flags, each answered.

  • Round 1 deviation, surface addition (kernel/manifest.zod.ts, system/object-storage.zod.ts, its pinned test): in class — both live at the tag, both refused in next.0 with the old text; the seat's amendment is right.
  • Round 1 deviation, allowOrgOverride edited for omission: right — the governing @param guidance asks for "the version that removed it"; the key is live at the tag and refused in next.0; 18 is that version.
  • Round 1 deviation, H1 count (5 entries at retiredAfter: '17.7.0', not 4): true at the merge base (registry.ts:7040, 7457, 8515, 9514, 9840); false on main today (7) — the verdict's reason.
  • Round 1 open question (who corrects 22876): answered A by the seat, executed, and confirmed above.
  • Round 1 out-of-scope 1 (interval refusal said "protocol 18"): folded, fixed, verified (①).
  • Round 1/3 out-of-scope 2 and the acceptance note on retired-after.census.json trailing the published line (last censused 17.4.0): no live defect, and the pin does not depend on it — it reads the stamps, so 17.7.0 is derived without a refresh. A refresh is owed after the next stable publish by the census's own rule; no card from this review.
  • Round 2 deviations (not re-merged after feat(lint)!: component-props-invalid refuses a retired page-component prop as an error at os validate, os build and os lint #23140; TSDoc left; future-spec-major red carried): each closed by a later round — the merge, the TSDoc edit, and Type Check · source gates green on this head.
  • Round 3 deviation (the seat's "take the deletion" instruction not followed because its premise was false): the dev was right; see the CONFIRMED block.
  • Round 3 / 4 deviations on lock contention, worktree re-creation and the card-read transport: process notes with no contract bearing.
  • "Not re-merged after 44e2d505c": superseded — main is 19 first-parent commits past the merge base now (d889448b9 to 197fbe2c0), including the two that make this verdict (1912af47b, and the one that added the two D2 entries); GitHub still reports mergeable: true, which only says the textual merge is clean.
  • Acceptance note "Value-level prescriptions naming no release were not swept": outside this card's class (it names the WRONG release); an omission sweep is a separate card if the seat wants one.
  • NOT MEASURED locally (23 scripts/** members of spec's repo project; CI-only lanes): the finished CI lanes are green; the pending ones do not bear on the contract judged here.

The docs-drift advisory (content/docs/concepts/metadata-lifecycle.mdx via allowOrgOverride). The page names the old key once, at line 107: "MetadataTypeRegistryEntry.allowEnvironmentOverlay … (spelled allowOrgOverride before protocol 18; …)". It states a protocol major for the rename, not an npm release, and that statement agrees with "renamed in @objectstack/spec 18". No edit is owed. The seat's ACCEPT read the page as naming "only allowEnvironmentOverlay" and "no release"; both halves of that reading are wrong, the conclusion is right.

What the fix round owes before the next at-tier review (the FAIL's remedy, in full). The seat's dispatched round (card comment 6144192235) covers items 1, 2 and 5; its amended surface is "the prescription string of each of these two entries only", which does not reach item 3 — the seat should widen it in the same act, or the next review fails on the same ground.

  1. Merge origin/main (the textual merge is clean per GitHub).
  2. Join page-action-row-navigation-executor-to-url and cbp-master-detail-required-defaulted to JOIN with the refusals or tombstones their surfaces render, and correct any of those prescriptions that name 17 (the pin then judges them: both derive 18). The seat's limit "if a prescription names no release at all, report how the pin judges it" has one answer in advance: the pin fails a joined prescription that names no release (named.length must exceed 0), so a release-less prescription on either entry cannot be joined unchanged — it must gain "18", which the governing @param guidance text requires anyway, exactly as allowOrgOverride did.
  3. Correct packages/spec/src/ui/view.zod.ts:193 to "removed in @objectstack/spec 18", with its literal pins and the regenerated content/docs/references/** row; it is D3-only (18.view-data-api-provider-retired.ts), so note it beside allowOrgOverride and StorageScope.public as out of the pin's reach, and add a literal release pin for it and for StorageScope.public while there.
  4. Re-count the enumeration (rows, entries at 17.7.0, edited/unchanged) and the changeset table; add the provider: 'api' row and the two new entries' rows to the changeset's table.
  5. Keep .changeset/pre/22876 lines 29/31 byte-equal to the emitted strings; the CONFIRMED block above then stands for the new head.

Implemented-by: claude/issue-23145-tombstone-removal-version
Reviewed-by: session_012uFegdfR6K6uqvLzt7XsdZ

VERDICT: FAIL

`content/docs/references/ui/component.mdx` merged without a text merge (both
sides changed it); regenerated with gen:schema + gen:docs from the merged
source. It differs from origin/main by exactly this branch's eleven corrected
rows.

Claude-Session: https://claude.ai/code/session_012uFegdfR6K6uqvLzt7XsdZ
Co-authored-by: Claude <noreply@anthropic.com>
…; the pin joins two new retirements

Two retirements reached main with `retiredAfter: '17.7.0'`
(`page-action-row-navigation-executor-to-url`,
`cbp-master-detail-required-defaulted`), and the derived removal-version pin
refused them as unjoined. They are joined now. Their prescriptions named no
release: the page action rows' `'navigation'` refusal now says the alias is
"refused on page action rows since @objectstack/spec 18", and the
controlled-by-parent refusal says the one-required-master rule holds "since
@objectstack/spec 18". `view.data.provider: 'api'` (D3-only, outside the pin)
said "removed in @objectstack/spec 17" for a shape 17.7.0 accepts; it now
says 18. 17.7.0 and 18.0.0-next.0 both accept all three shapes. The literal
pins follow; `view.data.provider: 'api'` and `StorageScope.public` gain a
one-line release pin. The pending changesets 23082 and 23103 quote the
corrected text as it now reads (deliberate correction).

Claude-Session: https://claude.ai/code/session_012uFegdfR6K6uqvLzt7XsdZ
Co-authored-by: Claude <noreply@anthropic.com>
… second table for the three it still accepts

`view.data.provider: 'api'`, the page action rows' `'navigation'` executor and
the controlled-by-parent one-required-master rule are accepted by both
17.7.0 and the published 18.0.0-next.0, so the first release that refuses
them is the one after next.0. They get their own table, and the first
table's sentence names next.0 for its own rows only.

Claude-Session: https://claude.ai/code/session_012uFegdfR6K6uqvLzt7XsdZ
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Supersedes 6143855611. check-empty-changeset is red by design (DELIBERATE CORRECTION) on three pending release notes at head 38728b3e1. (Ruling D on #17712; the Check Changeset lane.) Each note quotes a prescription this PR corrects, and each corrected quote is equal to the text the schema now emits. Restoring any of them from the base would publish a sentence this PR made false.

  • .changeset/23082-view-data-api-provider-retired.md:25 (new this round). It quotes view.data.provider: 'api' "was removed in @objectstack/spec 17". This PR changes the refusal (ui/view.zod.ts:193) to 18: the 17.7.0 and 18.0.0-next.0 tarballs both still accept provider: 'api' (measured). The quote now reads 18, byte-equal to the emitted string.
  • .changeset/23103-page-action-row-on-success-and-executor.md:36 (new this round). It quotes the first sentence of the 'navigation' row-executor refusal, which named no release. That refusal now says "refused on page action rows since @objectstack/spec 18" (both tarballs still accept 'navigation' on all four row shapes), and the quote equals the new first sentence.
  • .changeset/pre/22876-email-template-category-is-system-retired.md:29 and :31 (unchanged since the landing round). The email_template quotes, 17 to 18, byte-equal. At changeset pre exit the pre/ files are read again into the stable 18.0.0 notes (@changesets/read@1.0.1 dist/index.mjs:29; @changesets/assemble-release-plan@7.0.0 :328; @changesets/apply-release-plan@8.1.1 :301-319). Decision A, seat-confirmed.

Verdict at 38728b3e1, verbatim:

This PR changes a changeset it did not add:

   .changeset/23082-view-data-api-provider-retired.md
     present on the merge base and CHANGED by this PR -- this is somebody else's release note
   .changeset/23103-page-action-row-on-success-and-executor.md
     present on the merge base and CHANGED by this PR -- this is somebody else's release note
   .changeset/pre/22876-email-template-category-is-system-retired.md
     present on the merge base and CHANGED by this PR -- this is somebody else's release note

No other gate at this head is red: 113 derived, 112 exit 0, this one exit 1; CI's TypeScript Type Check, Test Core, Build Core and Lint & Repo Gates are green.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 38728b3e1b37ed00bed9da54be08198fd7fe1bd8
Local-runs: probe — npm tarball @objectstack/spec@18.0.0-next.0 unpacked into a new empty scratch directory and read with grep/sed only (integrity sha512-ASTh6…2Ow== matches the packument), to establish that the published next.0 still ACCEPTS the three fix-round shapes the changeset's second table names and still REFUSES the sixteen first-table rows with the text this PR replaces.

Verdict in one paragraph. Round 2 on the fix-round head. The round-1 FAIL (6144306153) was about the tree, not the diff; this head removes both grounds. The merge of origin/main (b24018c07) and the regenerated content/docs/references/ui/component.mdx (d0b4cfd1a) carry only this branch's rows relative to main, verified per file. The pin now joins page-action-row-navigation-executor-to-url and cbp-master-detail-required-defaulted with the refusals an author meets on their surfaces, its completeness guard holds on the merged tree (the seven retiredAfter: '17.7.0' ids at the head and at today's origin/main are exactly the seven stamped ids in JOIN), and CI Test Core 1/6 through 6/6 is green on this head. The three strings corrected this round name 18 for shapes that are live at the 17.7.0 tag tree, live in the published 18.0.0-next.0 tarball, and refused at the head, and each is still a well-formed prescription. view.zod.ts:193 goes 17 to 18, true. The changeset split is true sentence by sentence, and the enumeration counts in the PR body reconcile with the head. All three DELIBERATE CORRECTIONS are CONFIRMED. A fresh sweep of the head and of origin/main at 6d7f4df3c finds no other in-class string and no unjoined stamp. The overlap with PR #23244 is textually clean in both landing orders and semantically clean on every assertion either head carries; what the second lander owes is named in ③. Every round-1 judgment on the diff carries over unchanged (listed in ①.9). PASS.

Inputs read. Card #23145: body and all 13 comments (seat notes 6144192235 and 6144323612, dev report 6146077819 included). PR #23186: body in full (59230 bytes), all 6 comments (docs-drift bot, the three superseded notes, round-1 record 6144306153, the live designed-red note 6146032386), the 30-file list, the net diff against main at the head (+422/−46), and the round delta 56d63b4e7...38728b3e1 (23 commits: 19 from main, 4 the branch's own; 243 files). The 48 check-runs on the head. PR #23244 at 80db1670d (43 files) and its diff, for ①.8 only. Read-only git by 40-hex sha: origin/main at 6d7f4df3c (merge base with the head 197fbe2c0), the 17.7.0 tag tree 4e4e88142 (on origin/main's history), the version commit d889448b9. The npm packument (latest 17.7.0, next 18.0.0-next.0 published 2026-10-13T08:35:43Z, no 17.8.0, nothing between). The one probe above.

Check-runs on the head (48). 39 success, 7 skipped, 2 failure. The two failures are Check Changeset (jobs 115274569507 at 11:34Z and 115308151637 at 12:57Z after the body edit): the by-design red of ③, run twice. Green: Test Core and all six shards (1/6 completed 11:51:36Z), Build Core, TypeScript Type Check and its four lanes (source gates included), Lint & Repo Gates and its eight lanes, Spec property liveness, Governed Surface Queue Guard, Build Docs, Check Documentation Links, and the four PR-body-scoped guards (each ran twice, both success). Skipped: the opt-in and paths-filtered jobs. No in_progress.

① Derived judgments

1. The merge and the regeneration carry only this branch's rows — RIGHT. git diff --stat 197fbe2c0 b24018c07 touches exactly the 21 files the branch carried before the merge and nothing else. For 20 of them the patch-id of d889448b9..56d63b4e7 (the branch before the merge) equals the patch-id of 197fbe2c0..b24018c07 (the branch after it), so the merge changed nothing of the branch's content on those files. The 21st, component.mdx, differed: the merge commit alone carried the branch's older copy of that generated page, which would have reverted main's actionType and onSuccess rows from 4d1e4a80c — that is what d0b4cfd1a repaired. At the head, component.mdx differs from main by exactly 11 lines removed and 11 added, every one a removed in @objectstack/spec 17 row becoming 18, and zero other changed lines; the 11-row set is byte-identical to the one on the pre-merge head 56d63b4e7, so the regeneration reproduced the branch's rows rather than hand-editing them. The content/docs/references tree at the head differs from main in exactly the three generated pages this branch owns (kernel/metadata-plugin.mdx 1 row, system/email-template.mdx 2 rows, ui/component.mdx 11 rows). The CI gate for this class, check:docs in lint.yml ("Check generated reference docs are in sync with the spec", a regenerate-and-diff with no paths filter), ran green in Lint & Repo Gates on this head.

2. The pin joins both new entries and the completeness guard holds — RIGHT. conversions/registry.ts at the head carries seven retiredAfter: '17.7.0' entries: cbp-master-detail-required-defaulted, declared-index-unique-scope, element-flat-data-binding-to-data-source, email-template-category-is-system-removed, manifest-permissions-string-list-removed, object-grid-default-filters-removed, page-action-row-navigation-executor-to-url. JOIN in retired-key-removal-version.pin.test.ts names exactly those seven plus the four older rows (page-header-breadcrumb-removed, object-grid-default-sort-removed, object-kanban-quick-add-removed, cube-sub-day-granularities-removed): 11 keys, 19 cases. The guard at :268-277 (cmp(retiredAfter, NEWEST_STABLE) >= 0 && !(id in JOIN)) therefore reports nothing. The same seven ids, and no retiredAfter: '18…', are on origin/main at 6d7f4df3c — none of main's nine commits since the merge base touches packages/spec at all, and git merge-tree of the head onto that main is clean — so the guard holds against today's tree, not only the one CI merged. The joined renderers are the refusals an author meets: four parses of 'navigation' at the executor key on action:button / action:icon (actionType) and action:group / action:menu members (type), matching the D2 entry's declared surface line for line; and one raw ObjectSchema.safeParse of a controlled_by_parent object whose single master_detail omits required, filtered to the sharingModel issue by the new at parameter of refusal(), which is the entry's own surface ("MASTER being the one master_detail of a controlled_by_parent object"). CI Test Core (1/6), which carried the pin's red on 56d63b4e7, completed success at 11:51:36Z on this head.

3. The two prescriptions that named no release now name 18 — TRUE for each, and each is still a well-formed prescription.

  • Liveness, read at the 17.7.0 tag tree 4e4e88142: component.zod.ts has no refuseRowUrlExecutorAlias and no "local alias" text (0 hits), actionType is a bare z.string().optional() at :3440 and :3535, so 'navigation' is accepted on every row; object.zod.ts has no refuseControlledByParentWithoutOneMaster and no "but no required" text (0 hits), so a controlled_by_parent object with no required master parses. In the published 18.0.0-next.0 tarball (probe): the same two readings (0 hits each; actionType: z.string().optional() at src/ui/component.zod.ts:4082), and none of page-action-row-navigation-executor-to-url, cbp-master-detail-required-defaulted, cbp-master-relation-tiers-retired or view-data-api-provider-retired appears anywhere in the package. The retiring commits 4d1e4a80c (09:06Z) and 76815b901 (09:05Z) are descendants of the version commit d889448b9 (07:37Z) that next.0 was cut from. At the head both are refused with the new text, and the pin's majorsNamed would fail either row on "names no release" (the dev's ablation legs ⑥ and ⑦ report that red). So the first release refusing each shape is the one after next.0, and its major is 18. The bare major is this repo's house form for a v18-train prescription (the comment at view-data-api-provider-retirement.test.ts:56-58 says why: a minted minor would name a version that never ships); the changeset's second table makes the next.0 nuance explicit.
  • Well-formed, the navigation refusal: the inserted clause is parenthetical between two unchanged clauses — "… is the console runner's local alias of 'url', refused on page action rows since @objectstack/spec 18, and the url executor has one spelling." The rename sentence that follows ("Write actionType: 'url': on a page action row the alias runs the same navigator on the same target and openIn, so nothing else changes …") is untouched and still true. The first sentence still ends at "spelling." — the boundary the spec test's firstSentence() and the lint test's toContain read.
  • Well-formed, the controlled-by-parent refusal: "ADR-0055 §1: since @objectstack/spec 18, a controlled-by-parent object derives its master from exactly one master_detail field declared required: true, and from nothing else, so as declared the platform derives no master …". The clause scopes the derivation rule, and that rule IS an 18-line change: the function's own doc block says the two runtime fallbacks (any master_detail, then a required lookup) "both retired with this rule" through the step-18 D3 cbp-master-relation-tiers-retired, which is absent from the tag tree and from next.0. The remaining sentences (the per-field findings, "If the rows must outlive their parent …") are unchanged and unaffected.
  • The two-master refusal, left unedited in the same function: the dev's reading is right by the entry's own text. cbp-master-detail-required-defaulted converts only the one-master-with-required-omitted shape (apply returns the object untouched when masters.length !== 1; its summary says "two masters … are not converted"), and its surface names "the one master_detail". The pin's row parses the one-master shape and receives the sharingModel issue, which is the only message on that entry's surface; the two-master branch emits a different message at fields. So that refusal is outside the amended surface. It is, however, a release-less prescription for a shape 17.7.0 accepts (two required masters parsed at the tag; the dev measured ACCEPTED there and in next.0), of the same class as the two D3 narrowings the dev names — flagged in ③, not a defect of this head under the card's class.

4. view.data.provider: 'api' — RIGHT. view.zod.ts:190 at the tag is provider: z.literal('api') (live); next.0 src/ui/view.zod.ts:199 is the same literal with no VIEW_DATA_API_PROVIDER_RETIRED (live); 1912af47b (08:47Z) is a descendant of d889448b9; the head refuses the arm with "… was removed in @objectstack/spec 18 (ADR-0049 enforce-or-remove) — …". Literal release pins: view-data-api-provider-retirement.test.ts:59 (PRESCRIPTION regex, 17 to 18), view.test.ts:131 (new toContain('was removed in @objectstack/spec 18 (')), and for StorageScope.public object-storage.test.ts:60 (new toContain('in @objectstack/spec 18 (ADR-0049')) — the gap round 1 named is closed. Every occurrence of the provider string in the tree names 18: view.zod.ts:193, the two tests, .changeset/23082…:25. There is no reference row to regenerate for it: the string lives in a union-arm error map, not a describe, and content/docs/references at the head carries no occurrence (the three generated pages that do change are ①.1's). The pin cannot reach it (D3 only, no retiredAfter), as the PR body and the pin's header say.

5. The changeset split — TRUE sentence by sentence; counts consistent.

  • Line 9: "17.7.0, the newest 17.x release (npm latest), still accepts every shape in the two tables below." TRUE: the 16 first-table rows are live at the tag tree (round 1, by line), the three second-table rows per ①.3/①.4. "No 17.x release removes them: the 18 line does." TRUE (no 17.8.0; latest is 17.7.0). "18.0.0-next.0 is the first release that refuses the shapes in this first table." TRUE for each of ITS rows: the probe's dist carries the old text for every first-table row (56 hits of removed in @objectstack/spec 17 (ADR-0087 D2), 6 of 17.8.0, the two email_template strings, the manifest-list string, the release-less allowOrgOverride string; 0 of removed in @objectstack/spec 18), and nothing was published between 17.7.0 and next.0.
  • Line 20 (the next.0 notes quoted the two email_template prescriptions with 17): TRUE — tarball CHANGELOG.md:2091 and :2093, inside ## 18.0.0-next.0 (header at line 3).
  • Line 22: "18.0.0-next.0 still accepts the shapes in this second table, so the first release that refuses them is the one after it. Their refusals named 17, or no release at all." TRUE on all three (①.3, ①.4; provider named 17, the other two none).
  • Table 2's Now cells: rows 1 and 2 quote the emitted text; row 3 ("the one-required-master rule holds since @objectstack/spec 18") is a paraphrase of the emitted "since @objectstack/spec 18, a controlled-by-parent object derives its master from exactly one …" — true as a paraphrase; a nit, not a defect.
  • Line 30 (the sub-day interval, 17.4.0 accepts, 17.5.0 refuses) and line 32 (--from 17 unchanged and right; 17.x-refused keys keep 17; text only): TRUE, carried from round 1; none of the three new strings carries a --from sentence.
  • Counts: RETIRED_KEYS_BY_MAJOR[18] has 232 entry files at the head, at d889448b9 and at origin/main; 232 + 3 non-key renderers + 1 interval row + 3 fix-round rows = 239. Edited: 10 element + defaultFilters + 2 email_template + manifest + StorageScope + allowOrgOverride + interval + navigation + cbp + provider = 20; 219 unchanged. Strings: @objectstack/spec 18 has exactly 10 sites in spec sources (non-test) at the head — the ten this PR owns — plus the 17.5.0 interval string = 11. Entries at retiredAfter: '17.7.0': 7. All five figures in the PR body reconcile.

6. The three DELIBERATE CORRECTIONS — each CONFIRMED.

  • .changeset/23082-view-data-api-provider-retired.md:25 — CONFIRMED. The diff against the merge base 197fbe2c0 is one line (25) removed and one added; the first six lines (frontmatter) hash identically on both sides; the head's line 25 is byte-equal to > followed by the string view.zod.ts assembles for VIEW_DATA_API_PROVIDER_RETIRED (the concatenation reassembled from the source and compared as bytes). Pending: absent at the version commit d889448b9, added by 1912af47b after the next.0 cut, sits in root .changeset/ (16 notes) with .changeset/pre.json holding only mode/tag — unconsumed, so it compiles into the next prerelease.
  • .changeset/23103-page-action-row-on-success-and-executor.md:36 — CONFIRMED. One line (36) changed; frontmatter hash identical; the quoted sentence equals the first sentence refuseRowUrlExecutorAlias emits for the action:button subject at component.zod.ts:4261 and :4091 ("An action:button's actionType: 'navigation' is the console runner's local alias of 'url', refused on page action rows since @objectstack/spec 18, and the url executor has one spelling."), character for character. Pending: absent at d889448b9, added by 4d1e4a80c, root .changeset/, unconsumed.
  • .changeset/pre/22876-email-template-category-is-system-retired.md:29 and :31 — CONFIRMED (round 1's confirmation re-verified on this head). Two lines changed; frontmatter hash identical; each byte-equal to > plus EMAIL_TEMPLATE_CATEGORY_REMOVED / EMAIL_TEMPLATE_IS_SYSTEM_REMOVED as the head assembles them. The file still sits in .changeset/pre/ (507 notes there), re-read at changeset pre exit per the three @changesets/* citations round 1 verified.
  • Check Changeset lives in pr-automation.yml, whose on: block is pull_request: types: [opened, synchronize, reopened, labeled, unlabeled, edited] and nothing else (0 merge_group occurrences), so the red does not reach the queue; scripts/check-empty-changeset.mjs is unchanged since the round-1 base, so its remedy for this class (:551, "do NOT restore it -- say so on the PR and get it confirmed") still applies and is met by note 6146032386 and by this record.
  • Comment 6146032386 is accurate on every checkable sentence: the three files and lines, byte-equality, "both tarballs still accept provider: 'api'" and "'navigation' on all four row shapes" (①.3, ①.4), the pre-exit citations, the verbatim three-file verdict (the gate's M row text at :570), and "CI's TypeScript Type Check, Test Core, Build Core and Lint & Repo Gates are green" (the check-runs above).

7. Sweep, head and origin/main — clean; release-less prescriptions noted. Lines added to spec sources (non-test) since the 17.7.0 tag that name a 17 release or "protocol 18": at the head, the only runtime strings are the 17.5.0 interval refusal (right, round 1) and the relocated 'pdf' exportOptions refusal at 17.0.0 (pre-existing at the tag, 17.x-shipped, outside the class) — everything else is a doc comment, or the indexes[].unique: true "retired at protocol 18" string, which is joined and derives 18. Whole-tree counts at the head: 17.8.0 0, retired in protocol 18 0, removed in @objectstack/spec 17 202 (all 17.x-shipped per round 1's diff from the 17.7.0 cut). On origin/main at 6d7f4df3c the same sweep adds exactly the strings this PR corrects (the two email_template, StorageScope 17.8.0, the shared element string, defaultFilters, the manifest list, provider: 'api') and nothing newer; main's nine commits since 197fbe2c0 touch no file under packages/spec, add no retiredAfter line, and the stamped-id set is the same seven. Release-less prescriptions for shapes 17.7.0 accepts, outside this card's class (it names the WRONG release) and noted, not failed: the two D3 narrowings the dev names (page-default-record-page-one-per-object-refused, ui-page-action-row-on-success-shape-closed; neither entry's text names a release) and, from this reviewer, the two-master controlled_by_parent refusal in object.zod.ts (①.3).

8. Overlap with PR #23244 (head 80db1670d, card #23147) — a sequencing finding, not a defect of this head. Merge base of the two heads: 01a3421f4. Four files are touched by both: .changeset/23103-…md, packages/lint/src/validate-component-props-row-on-success.test.ts, packages/lint/src/validate-component-props.test.ts, packages/spec/src/ui/component.zod.ts.

9. Carry-over from round 1 (6144306153), unchanged on this head and re-read where the tree moved. The accept set is unchanged — the round delta's branch commits edit string literals, test assertions, one changeset and one regenerated page; no retiredKey(, enumWithRetiredValues(, enum, union, .strict() or registry value moves (the merge commit's 20 patch-ids are identical to the pre-merge branch). The seven round-1 strings and the interval refusal name the right release (live at the tag, refused in next.0 with the old text — re-confirmed in this round's probe: 56 / 6 / 0 hits as above). The [REMOVED] describes and the three generated pages follow byte-for-byte (①.1). The RETIRED_SUB_DAY_INTERVALS TSDoc is true. The pin's derivation (removalMajor, newestStable under the prerelease label, PROTOCOL_MAJOR 18 from protocol-version.ts:22-25) is unchanged in logic; this round only widened refusal() with an optional at filter and added imports and two JOIN rows. The --from 17 sentences are untouched and right. The docs-drift advisory on metadata-lifecycle.mdx still owes no edit (the page names the protocol major for the rename, which agrees with 18). The ratchet judgment on the completeness guard stands: it refused exactly the tree it was built to refuse and passed once the two entries were joined; a per-entry locator on the conversion remains the lower-conflict shape and a follow-up, not a defect. pre/22876 CONFIRMED (①.6).

② Semver level

@objectstack/spec patch, Clause-②: no in the changeset and in the PR body — RIGHT, unchanged from round 1. The fix-round commit 6e4a1485c changes one string line in component.zod.ts, three string lines in object.zod.ts, one in view.zod.ts, test assertions, the pin's JOIN, and two pending notes; 38728b3e1 changes the changeset only. No key, value, arm or shape is accepted or refused differently (①.3 shows every shape was already refused at the head before the wording changed). A wrong or missing release name in shipped prescription text is a bug fix in a released package: patch. Only @objectstack/spec carries product text; the lint and driver-memory edits are test files only, so one changeset is right. Under pre mode this ships in 18.0.0-next.1, and the changeset's two tables say which rows next.0 already refuses and which it does not — the one sentence round 1 said would need re-reading on the next head ("every shape below") is now split per table and true per table (①.5). check:future-spec-major is green (Type Check · source gates): every citation names major 18 under the 18.0.0-next.0 label.

③ Boundary flags

DELIBERATE CORRECTIONS. Three, each CONFIRMED in ①.6: .changeset/23082-view-data-api-provider-retired.md:25, .changeset/23103-page-action-row-on-success-and-executor.md:36, .changeset/pre/22876-email-template-category-is-system-retired.md:29,31. Only the quoted lines changed, frontmatter byte-identical, quotes byte-equal to what the head emits, each note pending; Check Changeset red by design on pull_request only; note 6146032386 accurate. The landing rule's "every check green" is met with that one designed red, as the seat's ACCEPT 6143909117 item 2 already provides.

Dev flags on this head (report 6146077819), each answered.

  • Deviation: the previous head's Test Core (1/6) log could not be read from the container — the seat read it (6144192235), and this head's shard is green; moot.
  • Deviation: the harness's attribution reminder not followed (commits keep the model-free trailer pair) — a process note with no contract bearing.
  • Out-of-scope finding: page-default-record-page-one-per-object-refused and ui-page-action-row-on-success-shape-closed refuse without naming a release — confirmed (neither entry's text names one); outside this card's class; add the two-master controlled_by_parent refusal (①.3) to the same list. One omission-sweep card for release-less v18 prescriptions would close all three; none of them reds this head or the pin (no D2 stamp joins them).
  • Acceptance note "Value-level prescriptions naming no release were not swept" — the same omission class; same answer.
  • The PR body's "main since: 9 commits to 6d7f4df3c, none touches packages/spec, merge-tree clean" — verified true on today's origin/main (①.2, ①.7).

Seat-surface conformance. The amended surface (6144323612): the two entries' prescriptions (text only), view.zod.ts:193, two one-line literal release pins, the changeset rows, the PR-body recount — every file in the round delta's branch commits is inside it; the seat's withdrawn limit ("a release-less prescription must not gain a release") is correctly not followed, since the pin fails a joined prescription that names no release and the governing @param guidance asks for the removal version.

Sequencing with #23244. A finding for the seat, not a ground against this head (①.8): either order merges clean; the second lander restates the shared 23103…md correction for its own line and re-runs CI on the merge.

Not measured here. The dev's local 113-gate run, the vitest counts and the ablation legs ⑥ and ⑦ (read-only review; CI's green Test Core, Type Check and Lint & Repo Gates on this head stand in for them). The 17.4.0 and 17.5.0 tarballs (the shallow clone does not reach those trees; round 1's CHANGELOG-and-census reading of the interval row is relied on). retired-after.census.json still trails at 17.4.0 — no live defect; the pin reads the stamps, not the census.

Implemented-by: claude/issue-23145-tombstone-removal-version
Reviewed-by: session_012uFegdfR6K6uqvLzt7XsdZ

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 13, 2026 13:20
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 13, 2026
Merged via the queue into main with commit c056979 Oct 13, 2026
49 of 52 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-23145-tombstone-removal-version branch October 13, 2026 13:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants