11// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
22
33/**
4- * `os migrate meta` — the guidance it prints for the ADR-0087 semantic entries
5- * of the COVERED families (`engine-*`, `ui-*`, `plugin-*`, `driver-*`,
6- * `kernel-*`, `system-*`, `datasource-*`, `filter-*`, `action-*`, `data-*`,
7- * `element-*`, `field-*`, `export-*`, `api-*`, `dataset-*`, `hook-*`,
8- * `metadata-*`, `rest-*`, `analytics-*`, `view-*`, `package-*`, `object-*`,
9- * `sharing-*`, `audit-*`, `flow-*`, `http-*`, `inline-*`, `actor-*`, `hot-*`,
10- * `external-*`, `query-*`, `delete-*`, `etl-*`, `storage-*`, `apimethod-*`,
11- * `dashboard-*`, `notification-*`, `record-*`, `runtime-*`, `rls-*`, `scim-*`,
12- * `stack-*`, `evaluated-*`, `aggregation-*`, `authoring-*`, `automation-*`,
13- * `cache-*`, `tenant-*`, `client-*`, `spec-*`, `cli-*`, `identity-*`,
14- * `import-*`, `tool-*`, `advanced-*`, `cloud-*`, `startup-*`, `sys-*`,
15- * `declarative-*`, `sort-*`, `address-*`, `packages-*`, `platform-*`,
16- * `session-*`, `strategy-*`) states each lesson in words and carries no
17- * tracker number.
4+ * `os migrate meta` — the guidance it prints for EVERY ADR-0087 semantic entry
5+ * states each lesson in words and carries no tracker number.
186 *
197 * ## What this pins
208 *
2412 * author is shown, so it carries no tracker number: a number sends the reader
2513 * to a page that can be deleted (some cited pages already had been), and the
2614 * lesson the entry exists to teach then sits behind a dead link instead of in
27- * the sentence being read. The covered families were rewritten, one staged
28- * family at a time, to say what each cited ruling, measurement or fix decided;
29- * ADR ids stay, because an ADR lives in this repository. The whole printed
15+ * the sentence being read. The entries were rewritten, one staged family at a
16+ * time, to say what each cited ruling, measurement or fix decided; ADR ids
17+ * stay, because an ADR lives in this repository. The whole printed
3018 * block is held, so `surface` is held as well as the three prose fields.
3119 *
3220 * The chain reports every semantic entry of every hop it crosses, whatever the
3321 * stack authors, so the fixture only has to be a real stack the command loads;
3422 * it keeps the lookup and the virtual `formula` field the `engine-*` entries
3523 * are about. The CLI replays the chain from the support floor to the highest
36- * major carrying a covered entry. Each covered block is then located VERBATIM
37- * in what the terminal printed, and that printed block must hold no `#`
38- * followed by four or five digits. The file keeps the name it was given when
39- * `engine-*` was the only covered family.
24+ * major carrying a semantic entry. Each block is then located VERBATIM in what
25+ * the terminal printed, and that printed block must hold no `#` followed by
26+ * four or five digits. The file keeps the name it was given when `engine-*`
27+ * was the only covered family; the staged rewrites have since reached every
28+ * family, so the pin holds the whole directory rather than a prefix list.
4029 *
4130 * ## Why it cannot pass by reading nothing
4231 *
43- * - The covered set is derived from the registry by id prefix, so an entry
44- * added later to a covered family is held to the same line on arrival — and
45- * the derived set must still contain every entry the rewrites covered, and
46- * every covered prefix must still select at least one entry, so an emptied
47- * prefix cannot turn every assertion below into a loop over nothing.
32+ * - The covered set is every semantic entry in the registry, so an entry added
33+ * later — in any family, a new family included — is held to the same line on
34+ * arrival; and the set must still contain every entry the rewrites covered,
35+ * so it cannot turn every assertion below into a loop over nothing.
4836 * - Each block is asserted PRESENT in stdout before it is asserted clean, so a
4937 * renderer change that stopped printing the prose fails here instead of
5038 * passing on an absent string.
@@ -82,26 +70,10 @@ const TSX = resolve(HERE, '../../../node_modules/.bin/tsx');
8270/** A tracker id as author-shown prose must not carry it: `#` and four or five digits. */
8371const TRACKER_ID = / # \d { 4 , 5 } \b / ;
8472
85- /** The families this pin holds, selected by entry-id prefix. */
86- const COVERED_PREFIXES = [
87- 'engine-' , 'ui-' , 'plugin-' , 'driver-' , 'kernel-' , 'system-' ,
88- 'datasource-' , 'filter-' , 'action-' , 'data-' , 'element-' ,
89- 'field-' , 'export-' , 'api-' , 'dataset-' , 'hook-' , 'metadata-' ,
90- 'rest-' , 'analytics-' , 'view-' , 'package-' , 'object-' , 'sharing-' ,
91- 'audit-' , 'flow-' , 'http-' , 'inline-' ,
92- 'actor-' , 'hot-' , 'external-' , 'query-' , 'delete-' , 'etl-' , 'storage-' ,
93- 'apimethod-' , 'dashboard-' , 'notification-' , 'record-' , 'runtime-' , 'rls-' ,
94- 'scim-' ,
95- 'stack-' , 'evaluated-' , 'aggregation-' , 'authoring-' , 'automation-' , 'cache-' ,
96- 'tenant-' , 'client-' , 'spec-' , 'cli-' , 'identity-' , 'import-' , 'tool-' ,
97- 'advanced-' , 'cloud-' , 'startup-' , 'sys-' , 'declarative-' , 'sort-' , 'address-' ,
98- 'packages-' , 'platform-' , 'session-' , 'strategy-' ,
99- ] ;
100-
10173/**
10274 * The entries rewritten when each family was brought to this line — the
103- * anti-vacuity floor. A covered entry that carried no tracker id to begin with
104- * is held by its prefix and needs no row here .
75+ * anti-vacuity floor. An entry that carried no tracker id to begin with needs no
76+ * row here: the whole directory is held .
10577 */
10678const REWRITTEN = [
10779 'action-bulk-dispatch-contract-undeclared' ,
@@ -111,8 +83,11 @@ const REWRITTEN = [
11183 'action-session-roles-to-positions' ,
11284 'actor-user-roles-to-positions' ,
11385 'address-location-value-unknown-keys-refused' ,
86+ 'admin-export-wildcard-removed' ,
87+ 'admin-scope-business-unit-blank-refused' ,
11488 'advanced-plugin-lifecycle-config-retired' ,
11589 'aggregation-node-distinct-retired' ,
90+ 'ai-conversation-analytics-duration-unit-in-key' ,
11691 'analytics-authorable-unknown-keys-refused' ,
11792 'analytics-date-range-array-two-bounds-required' ,
11893 'analytics-query-request-envelope-retired' ,
@@ -122,16 +97,29 @@ const REWRITTEN = [
12297 'api-runtime-config-durations-unit-in-key' ,
12398 'api-runtime-create-withdrawn' ,
12499 'apimethod-enum-shrink' ,
100+ 'approval-escalation-enabled-default-flip' ,
101+ 'assembled-package-body-plugins-envelope' ,
102+ 'audience-posture-default-invite-only' ,
125103 'audit-log-action-enum-retired' ,
126104 'audit-log-action-restore-retired' ,
105+ 'auth-config-unadvertised-reserved-features' ,
127106 'authoring-schemas-strict-unknown-keys' ,
128107 'automation-flow-list-route-retired' ,
129108 'automation-runs-cursor-retired' ,
109+ 'autonumber-default-unique-organization' ,
110+ 'batch-row-result-schema-shape' ,
111+ 'branded-identifier-schemas-retired' ,
130112 'cache-warmup-scheduled-strategy-retired' ,
113+ 'cbp-master-detail-required-forced' ,
114+ 'cel-predicate-one-value-comparand-refused' ,
115+ 'change-management-duration-keys-retired' ,
116+ 'change-management-family-retired' ,
131117 'cli-command-contribution-retired' ,
132118 'client-delete-result-success' ,
133119 'client-meta-reset-result-reset' ,
134120 'cloud-subpath-retired' ,
121+ 'cluster-driver-dangling-values-removed' ,
122+ 'connector-inline-authentication-publish-refused' ,
135123 'dashboard-header-modal-target-page-only' ,
136124 'dashboard-widget-chart-config-structure-refused' ,
137125 'dashboard-widget-compareto-offset' ,
@@ -156,6 +144,7 @@ const REWRITTEN = [
156144 'datasource-credentialsref-mongo-url-no-user-refused' ,
157145 'declarative-apis-endpoints-live' ,
158146 'delete-by-id-before-hook-repoint-retired' ,
147+ 'device-request-response-interval-unit-in-key' ,
159148 'driver-aggregate-undeclared-key-aliases-removed' ,
160149 'driver-capabilities-inert-bits-removed' ,
161150 'driver-options-timeout-to-timeout-ms' ,
@@ -171,8 +160,12 @@ const REWRITTEN = [
171160 'engine-find-formula-filter-refused' ,
172161 'engine-find-formula-order-by-refused' ,
173162 'engine-update-upsert-retired' ,
163+ 'enhanced-api-error-field-errors-renamed' ,
164+ 'epoch-instant-keys-renamed' ,
165+ 'esignature-config-deadline-keys-retired' ,
174166 'etl-pipeline-layer-retired' ,
175167 'evaluated-expression-slots-source-required' ,
168+ 'event-name-schema-retired' ,
176169 'export-axis-opt-in' ,
177170 'export-field-meta-constraints-retired' ,
178171 'export-job-family-retired' ,
@@ -209,7 +202,10 @@ const REWRITTEN = [
209202 'http-server-runtime-vocabulary-retired' ,
210203 'identity-api-key-schema-retired' ,
211204 'import-run-automations-declared-default-corrected' ,
205+ 'incident-response-deadline-keys-retired' ,
206+ 'incident-response-family-retired' ,
212207 'inline-grid-column-currency-scale-refused' ,
208+ 'job-retry-policy-constraints-tightened' ,
213209 'kernel-compatibility-matrix-estimated-migration-time-unit-in-key' ,
214210 'kernel-context-preview-mode-retired' ,
215211 'kernel-event-bus-retention-unit-in-key' ,
@@ -219,6 +215,8 @@ const REWRITTEN = [
219215 'kernel-plugin-security-durations-unit-in-key' ,
220216 'kernel-runtime-config-timeout-unit-in-key' ,
221217 'kernel-startup-orchestrator-durations-unit-in-key' ,
218+ 'logging-durations-unit-in-key' ,
219+ 'memory-persistence-placeholder-refused' ,
222220 'metadata-customization-protocol-retired' ,
223221 'metadata-endpoints-switch-radius-repartitioned' ,
224222 'metadata-manager-config-cache-ttl-unit-in-key' ,
@@ -229,6 +227,7 @@ const REWRITTEN = [
229227 'object-grid-data-view-data-converged' ,
230228 'object-grid-default-filters-rule-array' ,
231229 'object-index-unknown-keys-refused' ,
230+ 'observability-cel-predicates-retired' ,
232231 'package-api-contracts-unmounted-entries-retired' ,
233232 'package-install-request-unknown-keys-refused' ,
234233 'package-rollback-response-retired' ,
@@ -245,6 +244,7 @@ const REWRITTEN = [
245244 'plugin-runtime-family-retired' ,
246245 'plugin-security-scan-result-surface-retired' ,
247246 'plugin-security-scanner-retired' ,
247+ 'position-permissions-column-retired' ,
248248 'query-array-string-agg-retired' ,
249249 'query-cursor-retired' ,
250250 'query-distinct-retired' ,
@@ -261,7 +261,10 @@ const REWRITTEN = [
261261 'rls-predicate-cross-class-field-comparison-refused' ,
262262 'rls-predicate-stored-list-ordering-refused' ,
263263 'runtime-httpserver-wrapper-retired' ,
264+ 'schedule-flow-acting-organization-required' ,
264265 'scim-provider-object-retired' ,
266+ 'screen-field-lookup-reference-required' ,
267+ 'send-template-input-org-retired' ,
265268 'session-payload-positions-security-axis' ,
266269 'session-user-language-retired' ,
267270 'sharing-execution-context-retired' ,
@@ -270,9 +273,12 @@ const REWRITTEN = [
270273 'spec-type-alias-input-suffix-retired' ,
271274 'stack-themes-carrier-retired' ,
272275 'stack-top-level-unknown-keys-refused' ,
276+ 'standard-error-code-batch-members-retired' ,
277+ 'standard-error-code-concurrent-limit-exceeded-retired' ,
273278 'startup-orchestrator-retired' ,
274279 'storage-service-list-retired' ,
275280 'strategy-context-aggregation-method-narrowed' ,
281+ 'structured-region-body-pause-and-end-refused' ,
276282 'sys-account-issuer-retired' ,
277283 'system-cache-durations-unit-in-key' ,
278284 'system-collaboration-durations-unit-in-key' ,
@@ -286,7 +292,13 @@ const REWRITTEN = [
286292 'system-worker-queue-rate-limit-duration-unit-in-key' ,
287293 'tenant-schema-cache-ttl-unit-in-key' ,
288294 'tenant-timeouts-unit-in-key' ,
295+ 'time-update-interval-sub-day-retired' ,
289296 'tool-requires-confirmation-retired' ,
297+ 'training-deadline-keys-retired' ,
298+ 'training-family-retired' ,
299+ 'translation-per-app-settings-platform-only' ,
300+ 'turso-config-transport-mismatch-refused' ,
301+ 'ui-bulk-action-param-unknown-keys-refused' ,
290302 'ui-cloud-connection-widgets-unknown-keys-refused' ,
291303 'ui-form-field-length-malformed-refused' ,
292304 'ui-form-field-precision-scale-integer-refused' ,
@@ -301,12 +313,16 @@ const REWRITTEN = [
301313 'ui-record-blocks-unknown-keys-refused' ,
302314 'ui-reference-rail-unknown-keys-refused' ,
303315 'ui-widget-i18n-family-retired' ,
316+ 'ups-delegated-from-column-retired' ,
304317 'view-filter-rule-absent-value-refused' ,
305318 'view-filter-rule-scalar-operator-array-refused' ,
306319 'view-filter-rule-value-shaped-by-operator' ,
307320 'view-management-protocol-retired' ,
308321 'view-overlay-options-bag-judged' ,
309322 'view-pagination-page-size-default-50' ,
323+ 'wait-node-event-config-required' ,
324+ 'websocket-durations-unit-in-key' ,
325+ 'workflow-service-slot-retired' ,
310326] ;
311327
312328interface FamilyEntry {
@@ -318,10 +334,9 @@ interface FamilyEntry {
318334 acceptanceCriteria : string ;
319335}
320336
337+ /** Every semantic entry of every major: the pin holds the whole directory. */
321338const FAMILY : FamilyEntry [ ] = Object . entries ( MIGRATIONS_BY_MAJOR ) . flatMap ( ( [ major , step ] ) =>
322- step . semantic
323- . filter ( ( s ) => COVERED_PREFIXES . some ( ( prefix ) => s . id . startsWith ( prefix ) ) )
324- . map ( ( s ) => ( { ...s , toMajor : Number ( major ) } ) ) ,
339+ step . semantic . map ( ( s ) => ( { ...s , toMajor : Number ( major ) } ) ) ,
325340) ;
326341
327342/** The block the command prints for one semantic TODO, exactly as `meta.ts` lays it out. */
@@ -378,7 +393,7 @@ afterAll(() => {
378393 try { rmSync ( dir , { recursive : true , force : true } ) ; } catch { /* ignore */ }
379394} ) ;
380395
381- describe ( 'os migrate meta — the guidance of the covered families carries no tracker number' , ( ) => {
396+ describe ( 'os migrate meta — the guidance of every semantic entry carries no tracker number' , ( ) => {
382397 it ( 'the detector fires on a tracker id and stays dark on every other number shape' , ( ) => {
383398 expect ( TRACKER_ID . test ( `see #${ '9' . repeat ( 4 ) } ` ) ) . toBe ( true ) ;
384399 expect ( TRACKER_ID . test ( `see #${ '9' . repeat ( 5 ) } ` ) ) . toBe ( true ) ;
@@ -387,11 +402,8 @@ describe('os migrate meta — the guidance of the covered families carries no tr
387402 expect ( TRACKER_ID . test ( 'ADR-0112' ) ) . toBe ( false ) ;
388403 } ) ;
389404
390- it ( 'selects every covered family , including every entry the rewrites covered' , ( ) => {
405+ it ( 'holds every semantic entry , including every entry the rewrites covered' , ( ) => {
391406 const ids = FAMILY . map ( ( e ) => e . id ) ;
392- for ( const prefix of COVERED_PREFIXES ) {
393- expect ( ids . some ( ( id ) => id . startsWith ( prefix ) ) , `no entry selected for ${ prefix } ` ) . toBe ( true ) ;
394- }
395407 for ( const id of REWRITTEN ) expect ( ids , `family lost ${ id } ` ) . toContain ( id ) ;
396408 } ) ;
397409
0 commit comments