Repository navigation
Commit f415bcf
Fixes #20201
Clause-②: no
## What
Ruling B on #17152 (director `5615360777`, restated `5634031140`, on the
maintainer's #15954 authority `5559778263`): every retirement family
carries ONE ADR-0087 D3 (`semantic`) entry, even when a lossless D2
conversion repairs its data; D2 carries the mechanical repair only. This
PR takes the major-18 family census the card asks for, adds the 25 D3
entries it found missing, corrects the prose that justified their
absence, and pins the census in the registry's own test.
- **25 new D3 entries** under
`packages/spec/src/migrations/entries/semantic/18.*.ts`, one per
D2-backed family that had none. Each names its family and its D2
conversion id, says what D2 already repairs, and says what judgment the
consumer still owes (the `reason`), with an `acceptanceCriteria` the
consumer can check. None is a placeholder: every one states a residue
specific to its family (a unit only the author knows, a belief the
platform never honoured, a shape the conversion deliberately leaves
alone, code the chain cannot reach).
- **Prose corrected** at the sites of `5854110917` and `5854456343`,
plus step 18's rationale and step 17's docblock fact (list below).
- **Census pin** in the existing
`packages/spec/src/migrations/migrations.test.ts` (registry integrity).
No new check script.
- `MIGRATIONS_BY_MAJOR[18].semantic` 186 → 211 entries at the census
base; after merging `main` (four sibling D3 entries landed meanwhile,
none with a D2 conversion) the generated region holds 215.
## The census (the card's main deliverable)
**Tree.** `objectstack-ai/objectstack` at `3cb84d084` (this branch's
fork point; it already contains #20227's view-item retirement). Major-18
population there: **185** `retired-keys`, **146** `retired-defs`,
**186** `semantic` entry files, and **36** D2 conversions graduated into
step 18. (The card measured 181 / 130 / 175 at `d7c024133e`.)
**Grouping rule (ruling B's unit, held constant).** Where a D2
conversion exists, the conversion is the family: every retired key or
def it repairs belongs to it, and a D3 entry may cover more than one
conversion only where one judgment covers them (the pre-existing
`element-filter-and-form-node-refused` covers `element-filter-removed`
and `element-form-removed`). Every new entry here covers exactly one
conversion. Where no conversion exists, the records are grouped by the
D3 entry that names them.
**Method.**
1. Mechanical pass (scratch scripts, not committed): for each of the 36
conversions, the major-18 `semantic/` entry files that name its id as a
whole id (comment or field); for each retired key, the conversion its
own comment names, else the major-18 entries naming it as `cat/Def:key`,
`Def.path` / `Def:path`, or the def name plus the leaf key; for each
retired def, the entries naming the def.
2. Reading pass, where a string match cannot decide: (a) ownership: an
entry that names a conversion only in passing is not that family's entry
(this is how `metric-filters-removed` was classed missing although
`analytics-authorable-unknown-keys-refused` names it); (b) 14 records
matched by more than one entry, each placed by its own comment (for
example `kernel/PluginStartupResult:plugin`, which goes to
`startup-orchestrator-retired`); (c) 9 records whose comment names no
conversion but which belong to a D2 family
(`integration/DeclarativeConnectorEntry:connectionTimeoutMs` and
`:errorMapping`, the three error-mapping defs, the four responsive-shape
defs), plus `integration/Connector:connectionTimeoutMs`, whose comment
names two conversion ids and belongs to
`connector-connection-timeout-ms-removed` (it names the permission
conversion only as a comparison; round 1's Table 1 placed it wrongly,
corrected in patch round 1); (d) 5 theme sub-block defs, named by the
theme family's entry as its sub-blocks.
**Control.** The pairing sees a family that has its entry: 11 of the 36
conversions pair with a pre-existing entry, among them
`cube-join-sql-and-relationship-removed` with
`cube-join-sql-and-relationship-retired` (which the pin's own control
test also asserts), and the whole-id matcher refuses a prefix
(`record-chatter-position-vocabulary` is a prefix of its entry's own id
and matches only the entry's real citation). Evaluated at the base with
the pin's logic: **24** conversions named by no major-18 entry; the
reading pass adds `metric-filters-removed` for **25**. Evaluated at this
head: **0**.
**Result.** 331 records (185 keys + 146 defs) plus 36 conversions:
- **36 D2-backed families** covering 58 records: 11 had their D3 entry,
**25 had none**. Table 1.
- **273 D2-less records** in 68 groups: every one is named by an
existing D3 entry. Table 2. None missing, as expected: before ruling B,
a retirement with no conversion needed a D3 entry anyway.
The card's grep for 「lossless」 found the `tenancy.organizationField`
site and step 17. The census finds 25 major-18 families, most of them
with no 「lossless」 wording at all.
### Table 1 — D2-backed families (step 18 `conversionIds`, in order)
| # | D2 conversion (the family) | registered records | D3 entry at base
| D3 entry after |
|---|---|---|---|---|
| 1 | `field-malformed-scale-precision-removed` | none (value or
strict-key retirement, not in the two tables) |
`field-scale-precision-integer-refused` | unchanged |
| 2 | `record-chatter-position-vocabulary` | none (value or strict-key
retirement, not in the two tables) |
`record-chatter-position-vocabulary-converged` | unchanged |
| 3 | `element-input-target-variable-removed` |
`ui/ElementRecordPickerProps:targetVariable`,
`ui/ElementTextInputProps:targetVariable` | MISSING |
`element-input-target-variable-retired` (new) |
| 4 | `element-filter-removed` | `ui/ElementFilterProps:aria`,
`ui/ElementFilterProps:fields`, `ui/ElementFilterProps:layout`,
`ui/ElementFilterProps:object`, `ui/ElementFilterProps:showSearch`,
`ui/ElementFilterProps:targetVariable` |
`element-filter-and-form-node-refused` | unchanged |
| 5 | `element-form-removed` | `ui/ElementFormProps:aria`,
`ui/ElementFormProps:fields`, `ui/ElementFormProps:mode`,
`ui/ElementFormProps:object`, `ui/ElementFormProps:onSubmit`,
`ui/ElementFormProps:submitLabel` |
`element-filter-and-form-node-refused` | unchanged |
| 6 | `field-column-lists-canonicalized` | none (value or strict-key
retirement, not in the two tables) | MISSING |
`field-inline-and-related-list-columns-closed` (new) |
| 7 | `metric-filters-removed` | `data/Metric:filters` | MISSING (named
only in passing by `analytics-authorable-unknown-keys-refused`) |
`cube-metric-filters-retired` (new) |
| 8 | `cube-sub-day-granularities-removed` | none (value or strict-key
retirement, not in the two tables) |
`time-update-interval-sub-day-retired` | unchanged |
| 9 | `cube-join-sql-and-relationship-removed` |
`data/CubeJoin:relationship`, `data/CubeJoin:sql` |
`cube-join-sql-and-relationship-retired` | unchanged |
| 10 | `record-highlights-field-icon-removed` |
`ui/RecordHighlightsField:icon` | MISSING |
`record-highlights-field-icon-retired` (new) |
| 11 | `mapping-lookup-params-removed` | none (value or strict-key
retirement, not in the two tables) | MISSING |
`mapping-lookup-params-retired` (new) |
| 12 | `translation-component-submit-label-removed` | none (value or
strict-key retirement, not in the two tables) | MISSING |
`translation-component-submit-label-retired` (new) |
| 13 | `page-component-responsive-removed` |
`ui/PageComponent:responsive`, `ui/BreakpointColumnMap`,
`ui/BreakpointName`, `ui/BreakpointOrderMap`, `ui/ResponsiveConfig` |
MISSING | `page-component-responsive-retired` (new) |
| 14 | `object-grid-default-sort-removed` |
`ui/ObjectGridProps:defaultSort` | MISSING |
`object-grid-default-sort-retired` (new) |
| 15 | `object-kanban-quick-add-removed` |
`ui/ObjectKanbanProps:quickAdd` | MISSING |
`object-kanban-quick-add-retired` (new) |
| 16 | `permission-allow-restore-purge-removed` |
`security/EffectiveObjectPermission:allowPurge`,
`security/EffectiveObjectPermission:allowRestore`,
`security/ObjectPermission:allowPurge`,
`security/ObjectPermission:allowRestore` | MISSING |
`permission-restore-purge-bits-retired` (new) |
| 17 | `form-view-option-default-removed` | none (value or strict-key
retirement, not in the two tables) | MISSING |
`form-view-option-default-retired` (new) |
| 18 | `field-reference-to-alias` | none (value or strict-key
retirement, not in the two tables) | MISSING |
`field-reference-to-spelling-retired` (new) |
| 19 | `connector-error-mapping-removed` |
`integration/Connector:errorMapping`,
`integration/DeclarativeConnectorEntry:errorMapping`,
`integration/ConnectorErrorCategory`, `integration/ErrorMappingConfig`,
`integration/ErrorMappingRule` | MISSING |
`connector-error-mapping-retired` (new) |
| 20 | `connector-connection-timeout-ms-removed` |
`integration/Connector:connectionTimeoutMs`,
`integration/DeclarativeConnectorEntry:connectionTimeoutMs` |
`connector-provider-context-connection-timeout-ms-retired` | unchanged |
| 21 | `hook-timeout-to-timeout-ms` | none (value or strict-key
retirement, not in the two tables) | MISSING |
`hook-timeout-unit-in-key` (new) |
| 22 | `job-timeout-to-timeout-ms` | `system/Job:timeout` | MISSING |
`job-timeout-unit-in-key` (new) |
| 23 | `api-endpoint-cache-ttl-to-cache-ttl-seconds` |
`api/ApiEndpoint:cacheTtl` | MISSING |
`api-endpoint-cache-ttl-unit-in-key` (new) |
| 24 | `dashboard-refresh-interval-to-refresh-interval-seconds` |
`ui/Dashboard:refreshInterval` | MISSING |
`dashboard-refresh-interval-unit-in-key` (new) |
| 25 | `connector-health-and-trigger-durations-unit-in-key` |
`integration/CircuitBreakerConfig:monitoringWindow`,
`integration/ConnectorTrigger:interval` | MISSING |
`connector-resilience-durations-unit-in-key` (new) |
| 26 | `memory-persistence-auto-save-interval-to-ms` |
`data/AutoPersistenceConfig:autoSaveInterval`,
`data/FilePersistenceConfig:autoSaveInterval` | MISSING |
`memory-persistence-auto-save-interval-unit-in-key` (new) |
| 27 | `turso-config-timeout-to-timeout-ms` | `data/TursoConfig:timeout`
| MISSING | `turso-config-timeout-unit-in-key` (new) |
| 28 | `view-page-mount-removed` | `ui/ListView:pageName`,
`ui/ObjectListView:pageName` | MISSING | `list-view-page-mount-retired`
(new) |
| 29 | `list-view-sort-string-clause-to-array` | none (value or
strict-key retirement, not in the two tables) | MISSING |
`list-view-sort-string-clause-retired` (new) |
| 30 | `page-assigned-profiles-removed` | `ui/Page:assignedProfiles` |
`page-assigned-profiles-audience-to-permission-set` | unchanged |
| 31 | `chart-config-aria-removed` | `ui/ChartConfig:aria`,
`ui/ReportChart:aria` | MISSING | `chart-config-aria-retired` (new) |
| 32 | `dashboard-widget-chart-config-structure-removed` |
`ui/DashboardWidgetChartConfig:series`,
`ui/DashboardWidgetChartConfig:type`,
`ui/DashboardWidgetChartConfig:xAxis`,
`ui/DashboardWidgetChartConfig:yAxis` |
`dashboard-widget-chart-config-structure-refused` | unchanged |
| 33 | `translation-per-app-settings-removed` | none (value or
strict-key retirement, not in the two tables) |
`translation-per-app-settings-platform-only` | unchanged |
| 34 | `object-tenancy-organization-field-removed` |
`data/TenancyConfig:organizationField` | MISSING |
`object-tenancy-organization-field-retired` (new) |
| 35 | `page-component-filter-record-to-rule-array` | none (value or
strict-key retirement, not in the two tables) |
`element-data-source-and-object-block-filter-rule-array`,
`object-grid-default-filters-rule-array` | unchanged |
| 36 | `view-item-owner-hidden-removed` | `ui/ViewItemWire:hidden`,
`ui/ViewItemWire:owner`, `ui/ViewItem:hidden`, `ui/ViewItem:owner` |
MISSING | `view-item-owner-hidden-retired` (new) |
### Table 2 — D2-less records, grouped by the existing D3 entry that
names them
| D3 entry (existing) | records it names |
|---|---|
| `advanced-plugin-lifecycle-config-retired` |
`kernel/AdvancedPluginLifecycleConfig`, `kernel/GracefulDegradation`,
`kernel/PluginUpdateStrategy` |
| `ai-conversation-analytics-duration-unit-in-key` |
`ai/ConversationAnalytics:duration` |
| `api-error-retry-after-unit-in-key` |
`api/EnhancedApiError:retryAfter` |
| `api-runtime-config-durations-unit-in-key` |
`api/DataLoaderConfig:cacheTtl`, `api/RouteDefinition:timeout` |
| `automation-flow-list-route-retired` | `api/FlowSummary`,
`api/ListFlowsRequest`, `api/ListFlowsResponse` |
| `automation-runs-cursor-retired` | `api/ListRunsRequest:cursor` |
| `branded-identifier-schemas-retired` | `shared/AppName`,
`shared/FieldName`, `shared/FlowName`, `shared/ObjectName`,
`shared/RoleName`, `shared/ViewName` |
| `change-management-duration-keys-retired` |
`system/ChangeImpact:downtime.durationMinutes`,
`system/ChangeRequest:implementation.steps.estimatedMinutes`,
`system/RollbackPlan:steps.estimatedMinutes` |
| `change-management-family-retired` | `system/ChangeImpact`,
`system/ChangePriority`, `system/ChangeRequest`, `system/ChangeStatus`,
`system/ChangeType`, `system/RollbackPlan` |
| `cli-command-contribution-retired` | `kernel/CLICommandContribution` |
| `cloud-subpath-retired` | 62 records, all `cloud/` defs |
| `data-file-value-duration-unit-in-key` | `data/FileValue:duration` |
| `data-nosql-query-options-timeout-unit-in-key` |
`data/NoSQLQueryOptions:timeout` |
| `device-request-response-interval-unit-in-key` |
`api/DeviceRequestResponse:interval` |
| `driver-options-timeout-to-timeout-ms` | `data/DriverOptions:timeout`
|
| `epoch-instant-keys-renamed` | `api/SimplePresenceState:lastSeen`,
`api/WebSocketEvent:timestamp`, `kernel/HealthStatus:timestamp`,
`kernel/KernelContext:startTime`,
`kernel/TenantRuntimeContext:startTime` |
| `esignature-config-deadline-keys-retired` |
`data/ESignatureConfig:expirationDays`,
`data/ESignatureConfig:reminderDays` |
| `event-name-schema-retired` | `shared/EventName` |
| `export-job-family-retired` | 13 records, all `api/`, `automation/`
defs |
| `hot-reload-inert-state-strategies-retired` |
`kernel/DistributedStateConfig` |
| `hot-reload-watch-placeholder-retired` |
`kernel/HotReloadConfig:watchPatterns` |
| `identity-api-key-schema-retired` | `identity/ApiKey` |
| `incident-response-deadline-keys-retired` |
`system/IncidentNotificationMatrix:escalationTimeoutMinutes`,
`system/IncidentNotificationRule:regulatorDeadlineHours`,
`system/IncidentNotificationRule:withinMinutes`,
`system/IncidentResponsePhase:targetHours`,
`system/IncidentResponsePolicy:retentionDays`,
`system/IncidentResponsePolicy:triageDeadlineHours` |
| `incident-response-family-retired` | `system/Incident`,
`system/IncidentCategory`, `system/IncidentNotificationMatrix`,
`system/IncidentNotificationRule`, `system/IncidentResponsePhase`,
`system/IncidentResponsePolicy`, `system/IncidentSeverity`,
`system/IncidentStatus` |
| `kernel-compatibility-matrix-estimated-migration-time-unit-in-key` |
`kernel/CompatibilityMatrixEntry:estimatedMigrationTime` |
| `kernel-context-preview-mode-retired` |
`kernel/KernelContext:previewMode`, `kernel/PreviewModeConfig`,
`kernel/TenantRuntimeContext:previewMode` |
| `kernel-event-bus-retention-unit-in-key` |
`kernel/EventPersistence:retention`,
`kernel/EventSourcingConfig:retention` |
| `kernel-health-check-and-hot-reload-durations-unit-in-key` |
`kernel/HotReloadConfig:debounceDelay`,
`kernel/PluginHealthCheck:interval`, `kernel/PluginHealthCheck:timeout`
|
| `kernel-package-lifecycle-durations-unit-in-key` |
`kernel/MultiVersionSupport:rollout.duration`,
`kernel/PackageDependencyResolutionResult:resolvedIn`,
`kernel/UpgradePlan:estimatedDuration` |
| `kernel-plugin-health-report-durations-unit-in-key` |
`kernel/PluginHealthReport:metrics.responseTime`,
`kernel/PluginHealthReport:metrics.uptime` |
| `kernel-plugin-security-durations-unit-in-key` |
`kernel/KernelSecurityPolicy:auditLog.retention`,
`kernel/KernelSecurityPolicy:authentication.tokenExpiration`,
`kernel/PluginSecurityManifest:vulnerabilityDisclosure.responseTime` |
| `kernel-runtime-config-timeout-unit-in-key` |
`kernel/RuntimeConfig:resourceLimits.timeout`,
`kernel/SandboxConfig:process.timeout` |
| `kernel-startup-orchestrator-durations-unit-in-key` |
`kernel/PluginStartupResult:duration`, `kernel/StartupOptions:timeout`,
`kernel/StartupOrchestrationResult:totalDuration` |
| `list-view-navigation-view-retired` | `ui/NavigationConfig:view` |
| `logging-durations-unit-in-key` |
`system/HttpDestinationConfig:batch.flushInterval`,
`system/HttpDestinationConfig:retry.initialDelay`,
`system/HttpDestinationConfig:timeout`,
`system/LoggingConfig:buffer.flushInterval` |
| `metadata-changed-event-payload-retired` |
`kernel/MetadataChangeOperation`, `kernel/MetadataChangedEventPayload` |
| `metadata-customization-protocol-retired` | 13 records, all `api/`,
`kernel/` defs |
| `metadata-manager-config-cache-ttl-unit-in-key` |
`kernel/MetadataManagerConfig:cache.ttl` |
| `metadata-manager-config-inert-cache-keys-retired` |
`kernel/MetadataManagerConfig:cache.enabled`,
`kernel/MetadataManagerConfig:cache.maxSize`,
`kernel/MetadataManagerConfig:cache.ttlSeconds` |
| `metadata-plugin-additional-types-retired` |
`kernel/MetadataPluginConfig:additionalTypes` |
| `package-rollback-response-retired` | `api/PackageRollbackResponse` |
| `packages-list-pagination-retired` |
`api/ListInstalledPackagesRequest:cursor`,
`api/ListInstalledPackagesRequest:limit` |
| `plugin-auto-restart-never-reinitialised` |
`kernel/PluginHealthCheck:autoRestart`,
`kernel/PluginHealthCheck:maxRestartAttempts`,
`kernel/PluginHealthCheck:restartBackoff` |
| `plugin-manifest-contributes-dead-members-retired` |
`kernel/Manifest:contributes.actions`,
`kernel/Manifest:contributes.commands`,
`kernel/Manifest:contributes.drivers`,
`kernel/Manifest:contributes.events`,
`kernel/Manifest:contributes.fieldTypes`,
`kernel/Manifest:contributes.functions`,
`kernel/Manifest:contributes.menus`,
`kernel/Manifest:contributes.themes`,
`kernel/Manifest:contributes.translations` |
| `plugin-manifest-contributes-routes-retired` |
`kernel/Manifest:contributes.routes` |
| `plugin-manifest-dead-containers-retired` |
`kernel/Manifest:capabilities`, `kernel/Manifest:configuration`,
`kernel/Manifest:extensions` |
| `plugin-manifest-kind-globs-retired` |
`kernel/Manifest:contributes.kinds.globs` |
| `plugin-security-scan-result-surface-retired` |
`kernel/KernelSecurityScanResult`, `kernel/KernelSecurityVulnerability`,
`kernel/PluginQualityMetrics:securityScan`,
`kernel/PluginSecurityManifest:scanResults`,
`kernel/PluginSecurityManifest:vulnerabilities` |
| `rest-api-endpoint-handler-status-retired` | `api/HandlerStatus`,
`api/RestApiEndpoint:handlerStatus`, `api/RouteCoverageEntry`,
`api/RouteCoverageReport` |
| `rest-api-plugin-durations-unit-in-key` |
`api/RestApiEndpoint:cacheTtl`, `api/RestApiEndpoint:timeout`,
`api/RestApiPluginConfig:performance.defaultCacheTtl` |
| `rest-server-config-dead-keys-retired` | 11 records, all `api/` defs |
| `session-user-language-retired` | `api/SessionUser:language` |
| `stack-themes-carrier-retired` | `ui/BorderRadius`, `ui/ColorPalette`,
`ui/Shadow`, `ui/Theme`, `ui/ThemeMode`, `ui/Typography` |
| `startup-orchestrator-retired` | `kernel/HealthStatus`,
`kernel/PluginStartupResult:health`,
`kernel/PluginStartupResult:plugin`,
`kernel/PluginStartupResult:startTime`, `kernel/StartupOptions`,
`kernel/StartupOrchestrationResult` |
| `system-cache-durations-unit-in-key` |
`system/CacheAvalanchePrevention:circuitBreaker.resetTimeout`,
`system/CacheTier:ttl` |
| `system-collaboration-durations-unit-in-key` |
`system/CollaborationSessionConfig:idleTimeout`,
`system/CollaborationSessionConfig:snapshot.interval` |
| `system-failover-health-check-interval-unit-in-key` |
`system/FailoverConfig:healthCheckInterval` |
| `system-metrics-jsdoc-durations-unit-in-key` |
`system/MetricDefinition:summary.maxAge`,
`system/MetricExportConfig:interval`,
`system/MetricsConfig:collectionInterval`,
`system/MetricsConfig:retention.period`,
`system/ServiceLevelObjective:errorBudget.burnRateWindows.window` |
| `system-metrics-window-durations-unit-in-key` |
`system/MetricAggregationConfig:window.size`,
`system/ServiceLevelIndicator:window.size`,
`system/ServiceLevelObjective:period.duration` |
| `system-object-storage-durations-unit-in-key` |
`system/AccessControlConfig:maxAge`, `system/StorageConnection:timeout`
|
| `system-registry-config-durations-unit-in-key` |
`system/RegistryConfig:cache.ttl`,
`system/RegistryUpstream:syncInterval`,
`system/RegistryUpstream:timeout` |
| `system-tracing-otel-exporter-durations-unit-in-key` |
`system/OpenTelemetryCompatibility:exporter.batch.exportTimeout`,
`system/OpenTelemetryCompatibility:exporter.batch.scheduledDelay`,
`system/OpenTelemetryCompatibility:exporter.timeout`,
`system/TracingConfig:performance.exportInterval` |
| `system-tracing-span-duration-unit-in-key` | `system/Span:duration` |
| `system-worker-queue-rate-limit-duration-unit-in-key` |
`system/QueueConfig:rateLimit.duration` |
| `tenant-schema-cache-ttl-unit-in-key` |
`system/SchemaLevelIsolationStrategy:performance.schemaCacheTTL` |
| `training-deadline-keys-retired` |
`system/TrainingCourse:durationMinutes`,
`system/TrainingCourse:validityDays`,
`system/TrainingPlan:gracePeriodDays`,
`system/TrainingPlan:recertificationIntervalDays`,
`system/TrainingPlan:reminderDaysBefore` |
| `training-family-retired` | `system/TrainingCategory`,
`system/TrainingCompletionStatus`, `system/TrainingCourse`,
`system/TrainingPlan`, `system/TrainingRecord` |
| `websocket-durations-unit-in-key` |
`api/WebSocketConfig:pingInterval`,
`api/WebSocketConfig:reconnectInterval`, `api/WebSocketConfig:timeout`,
`api/WebSocketServerConfig:heartbeatInterval` |
## Prose corrected (the single-entry sites of `5854110917` /
`5854456343`, and the rationale sentences)
| site (at this head) | was | now |
|---|---|---|
| `packages/spec/src/migrations/registry.ts:78–86` (step 17 docblock,
fact correction only) | 「Mechanical, and mechanical only … there is no
semantic residue and the `semantic` list is deliberately empty」 | the
three renames replay losslessly as D2; they carry no D3 entry because
step 17 shipped before the rule and was not back-filled; the `semantic`
list is NOT empty. ⛔ No step-17 entry added. |
| `packages/spec/src/migrations/registry.ts:5256` (step 18 rationale,
`tenancy.organizationField`) | 「The conversion is a lossless delete and
there is no semantic residue」 | a lossless delete still leaves the
author a judgment, carried by
`object-tenancy-organization-field-retired` |
| `packages/spec/src/conversions/registry.ts:3460`
(`datasource-driver-mongo-to-mongodb`, protocol 17) | 「Why D2 and not
D3」 | 「Why the data repair is D2」, plus: losslessness does not decide
whether a family owes D3; this one is protocol 17 and has none |
| `packages/spec/src/conversions/registry.ts:9312`
(`api-endpoint-cache-ttl-to-cache-ttl-seconds`) | 「gets a conversion
rather than a semantic entry」 | 「also gets a conversion」, and names its
D3 entry |
| `packages/spec/src/conversions/registry.ts:9804`
(`list-view-sort-string-clause-to-array`) | 「which is why this is a D2
conversion rather than a semantic TODO」 | the data repair is D2; the
family's D3 entry carries the clauses the rewrite leaves alone |
|
`packages/spec/src/migrations/entries/retired-keys/18.api__ApiEndpoint__cacheTtl.ts:11–19`
| 「a D2 CONVERSION rather than a semantic entry」 | also a D2 conversion,
and names the D3 entry |
|
`packages/spec/src/migrations/entries/semantic/18.metadata-endpoints-switch-radius-repartitioned.ts:11–13`
| 「exactly the residue D2 cannot express, which is why this is a
semantic entry」 | that residue is why there is no D2 at all; the D3
entry is owed either way |
| `packages/spec/scripts/build-migration-registry.ts:276` | 「a major
whose semantic residue is genuinely nil (protocol 14)」 | an empty region
is a real state (a freshly opened step, or protocol 14's, which predated
the rule) |
⛔ Not touched: the governed texts (ADR-0087,
`.claude/skills/spec-property-retirement/SKILL.md` §3), which are
#20188's.
## The census pin
**Where:** `packages/spec/src/migrations/migrations.test.ts` › `registry
integrity`: `from protocol 18 on, every graduated D2 conversion is named
by a D3 entry of its own step (ruling B)`, plus a control test. It reads
the major's `entries/semantic/` files (comment and literal) inside its
own package; `check:migration-registry` already proves those files and
the generated region are one set.
**What it asserts:** for every step whose `toMajor` is 18 or later,
every id in `conversionIds` appears as a whole id in at least one
`semantic/` entry of that major. A new major-18 (or later) retirement
that lands a D2 conversion with no D3 entry naming it goes red, naming
the conversion.
**What it cannot see**, stated so a green run is not over-read: (1)
whether the naming entry is that family's OWN (a passing mention
satisfies it; the census judged ownership by reading); (2) a family
retired with no conversion at all (no machine-readable link joins a
retired key or def to its D3 entry; the census paired those by reading,
and found none missing). Protocol 17 is outside the pin by design:
measured with the same logic, 53 of its 57 graduated conversions are
named by no step-17 entry, and step-17 backfill is out of scope (triage
`5854164872`).
**Reverse verification (one-shot, no permanent test file).** At
`c8656ad35`, with the entries committed: deleted
`18.object-tenancy-organization-field-retired.ts` (absence confirmed on
disk before the run), ran the pin: `× from protocol 18 on …` with `+
"protocol 18: object-tenancy-organization-field-removed"`, `Tests 1
failed | 140 skipped`. Restored with `git checkout HEAD -- PATH` (that
path) inside a `trap … EXIT INT TERM`: blob `2cf3007d9fff` equals
HEAD's, `git diff HEAD` empty. Direction observed: red, the expected
one. No build involved: the test imports `src/` and reads the entry
files directly.
## Patch round 1 (contract review `5857834457`: FAIL at `3197fce29`)
**Blocking: fixed.** `Lint & Repo Gates` step 189
(`check-issue-citations.mjs`, judging pass) was red. Four bare citations
this PR added answer 404 on the board: #10329, #10926, #12868 and
#14676. Each was in an entry's leading comment, and again in the
regenerated region. `--probe-cause` classes all four as **deleted** (the
web endpoint also answers 404, so none was transferred), so none of them
is a reference to another repository to qualify. Each comment now
anchors to the commit in this repository's history that retired the
family, and says in words what that commit decided. That is the
precedent of commit `66e266c93` (ruling C+D on #19123). Every sha is an
ancestor of `origin/main`:
| entry | was | now anchored to |
|---|---|---|
| `mapping-lookup-params-retired` | #10329 | commit `15d58dbf1` (the
import path never read the four lookup steering params) |
| `translation-component-submit-label-retired` | #10926 | commit
`d173125fb` (the copy key left with its only declarer, `element:form`) |
| `form-view-option-default-retired` | #12868 | commit `c459da6bc` (the
ruled narrowing: the form-view face drops per-option `default`, the
object-field face keeps it enforced) |
| `connector-error-mapping-retired` | #14676 | commit `13c48c2a5`
(eleven inert keys, one spelled like the live `userMessage` channel) |
Only the comments changed; no string an author is shown moves. The
region was regenerated with `gen:migration-registry`. The round-1
report's `pnpm check:issue-citations :: exit 0` was the package script,
which runs only the `--self-test`. The judging pass CI runs was exit 2
at `3197fce29` (8 findings = 4 numbers × 2 sites) and is exit 0 now
(below).
**Pin message.** The census pin's assertion now names the unnamed
`protocol N: conversion-id` pairs and the remedy: add a D3 `semantic`
entry of that step whose text names the conversion id as a whole word.
Its logic and scope are unchanged. Shown firing at `21418c4d2` with one
entry removed (trap-guarded restore, blob equal to HEAD's, `git diff
HEAD` empty): `AssertionError: graduated D2 conversion(s) named by no D3
entry of their own step: protocol 18:
object-tenancy-organization-field-removed. Remedy: add a D3 semantic
entry of that step …`, `Tests 1 failed | 140 passed`.
**Body.** Table 1: `integration/Connector:connectionTimeoutMs` moved
from row 16 to row 20. Its own comment names
`connector-connection-timeout-ms-removed`; the permission id appears
there only as a comparison. The code was already right.
## Sibling PRs
- **PR #20238** (#20161) has since LANDED as `6a6a17b62`, with the D2
conversion `report-joined-chart-removed` and
`18.ui-report-joined-chart-retired.ts`, which names that id. The union
of this head with `main` at `6a6a17b62` is clean and passes the pin (37
pairs, 0 unnamed; delta review `5859315908`).
- `main` was merged three times with `os-regen-merge.sh`, and never by
hand in a generated region: at `a70cd62e5` (#20223 and #20245), at
`21418c4d2` (`cel-predicate-one-value-comparand-refused` and
`filter-query-face-comparands-refused-at-save`) and at `a930cacea`
(step-17 rationale prose from #20268). Each is D3-only or prose, with no
new step-18 conversion. Regeneration produced a commit only after the
first merge (`3197fce29`) and changed nothing after the other two. Every
sibling entry id was verified present.
## Verification (head `a930cacea`)
- `pnpm check:issue-citations && node
scripts/check-issue-citations.mjs`, exactly as CI runs it (base
`origin/main`): **exit 0**, 112 citations across 29 files: 106 resolve,
6 cross-repo unjudged, 0 findings. At `3197fce29` the same command
exited 2.
- `pnpm --filter @objectstack/spec build` under the verify lock: ok.
`check:generated`: all 15 generated artifacts up to date.
`check:migration-registry`: current (292 semantic, 214 retired-key, 199
retired-def). `spec-changes.json` and `docs/protocol-upgrade-guide.md`
do not move: they project up to the current protocol major, and step 18
is beyond it.
- `pnpm --filter @objectstack/spec exec vitest run --project local`:
**552 files, 16257 passed, 1 todo**. The `src/migrations/` directory
alone: 3 files, 151 passed.
- `pnpm --filter @objectstack/spec typecheck` (tsc, scripts, test layer)
at `21418c4d2`, the head before the last merge, which brought only
another PR's prose into this diff's files: exit 0, test-typecheck debt
unchanged (53 files / 255 errors / 142 signatures).
- `node scripts/pm/dispatch-gates.mjs --commands` (no paths) at
`a930cacea`, every command run and its exit recorded, reconciled with
`--ran`: **89 derived, 87 run (all exit 0), 2 NOT MEASURED**.
`check:dual-build-cjs-loads` and `check:type-check-debt` exited 3
(PREREQUISITE NOT MET: the full 86-package workspace build does not fit
the foreground cap on this shared box). CI runs both.
`check:pm-dispatch-gates` finished this time: exit 0, in 907.6 s.
- ESLint, narrowed and proven: all 31 changed `.ts` files,
`--no-inline-config --format json`: 0 errors, 0 warnings, none reported
ignored. `eslint.config.mjs` enables no type-aware linting (its own
statement at `eslint.config.mjs:326–328`), so this diff cannot move any
untouched file's verdict.
- Changeset: `@objectstack/spec` `patch`. The published registry text
changes; no accept set moves.
## Acceptance notes (observed, not filed)
- `registry.ts:108` (released step-17 text) still says the sharing-rule
`full` conversion 「leaves no semantic residue」: triage scoped step-17
backfill out, so it is left as is.
- New entries keep tracker numbers in their `//` comments only, never in
the strings an author is shown (AGENTS.md runtime-strings rule). Several
older entries do cite numbers in `reason`; not touched.
- `dashboard-refresh-interval-unit-in-key` states the console renderer's
release lag as a verification step, not as a present fact: this
container has no objectui checkout at the pin to measure it.
- `main` moved after the last merge (`a930cacea`). #20285 (`2aa25efb4`,
prose in five semantic entries) and #20238 (`6a6a17b62`, a new step-18
conversion with its entry) landed under `migrations/` and
`conversions/`. The delta review merged this head onto `6a6a17b62`:
clean, with all six regions still mirrored. The queue verifies the
merged generation. (Corrected by the seat at 2026-09-27T19:57Z; the
earlier wording said nothing under those paths had moved.)
---
_Generated by [Claude
Code](https://claude.ai/code/session_01CiCTczDo7tGhafXjf61dUJ)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 28ad7e4 commit f415bcf
32 files changed
Lines changed: 1756 additions & 36 deletions
File tree
- .changeset
- packages/spec
- scripts
- src
- conversions
- migrations
- entries
- retired-keys
- semantic
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
273 | 273 | | |
274 | 274 | | |
275 | 275 | | |
276 | | - | |
277 | | - | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
278 | 279 | | |
279 | 280 | | |
280 | 281 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3459 | 3459 | | |
3460 | 3460 | | |
3461 | 3461 | | |
3462 | | - | |
| 3462 | + | |
3463 | 3463 | | |
3464 | 3464 | | |
3465 | 3465 | | |
| |||
3468 | 3468 | | |
3469 | 3469 | | |
3470 | 3470 | | |
| 3471 | + | |
| 3472 | + | |
| 3473 | + | |
| 3474 | + | |
| 3475 | + | |
| 3476 | + | |
3471 | 3477 | | |
3472 | 3478 | | |
3473 | 3479 | | |
| |||
9305 | 9311 | | |
9306 | 9312 | | |
9307 | 9313 | | |
9308 | | - | |
| 9314 | + | |
9309 | 9315 | | |
9310 | 9316 | | |
9311 | | - | |
| 9317 | + | |
| 9318 | + | |
| 9319 | + | |
| 9320 | + | |
9312 | 9321 | | |
9313 | 9322 | | |
9314 | 9323 | | |
| |||
9794 | 9803 | | |
9795 | 9804 | | |
9796 | 9805 | | |
9797 | | - | |
9798 | | - | |
9799 | | - | |
9800 | | - | |
9801 | | - | |
9802 | | - | |
| 9806 | + | |
| 9807 | + | |
| 9808 | + | |
| 9809 | + | |
| 9810 | + | |
| 9811 | + | |
| 9812 | + | |
| 9813 | + | |
9803 | 9814 | | |
9804 | 9815 | | |
9805 | 9816 | | |
| |||
Lines changed: 9 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
12 | | - | |
13 | | - | |
14 | | - | |
15 | | - | |
16 | | - | |
17 | | - | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
18 | 20 | | |
Lines changed: 31 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
Lines changed: 32 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
Lines changed: 41 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
Lines changed: 38 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
0 commit comments