Repository navigation
feat(spec,cli): a structured relevance question takes a semantic notice off os migrate meta's default list (counted; --all lists it) - #22115
Conversation
…luated by the chain
`SemanticMigration.relevantWhen` is an optional, closed question over the
loaded stack (`{ kind: 'stack-declares', keys: [...] }`). `applyMetaMigrations`
evaluates it over the stack it is handed and every hop checkpoint, and an entry
whose surface it proves absent moves from `todos` to the new `absentTodos`
(chain and per hop). Unreadable values, opaque plugins and an applied edit the
entry judges all keep the entry listed. A first batch of 29 entries whose
surface lives only under named top-level stack keys carries the question.
Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RPo7FUd6bSnAfkWMAKi848
…them Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RPo7FUd6bSnAfkWMAKi848
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RPo7FUd6bSnAfkWMAKi848
…nce types Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RPo7FUd6bSnAfkWMAKi848
📓 Docs Drift CheckThis PR changes 2 package(s): 20 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 9 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 145 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin eb5e21a0ab51ba853f97a7b34be64f5f36c3d061 && git checkout eb5e21a0ab51ba853f97a7b34be64f5f36c3d061
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 54ace18c669a776c7e849708039c7876ac534cee 16cb55b8d0acda74b4e740e56bf1b5cbe3871bbd && git checkout -B drift-repro 54ace18c669a776c7e849708039c7876ac534cee && git merge --no-ff 16cb55b8d0acda74b4e740e56bf1b5cbe3871bbd
node scripts/docs-audit/affected-docs.mjs --json 54ace18c669a776c7e849708039c7876ac534cee
|
Contract reviewServed-tier: Isolated at-tier reviewer, dispatched from the adopting seat; read-only. Inputs, and nothing else: card #22072 (body and its 4 comments: triage Check-runs on the head. First reading at 2026-10-07T18:34Z: 36 runs, 16 ① Derived judgmentsThe accept-set and public-surface changes the diff implies, each judged.
② Semver levelWhat the diff publishes. Additive: three exported types; the optional The changeset as shipped ( Ruling on the open question ( Disposition — either of two satisfies the contract; the state as shipped does not:
A′ is the smaller edit from the shipped diff; B is the cleaner contract (triage scoped the DEFAULT LIST, not the function's array). Either passes ②; ③ Boundary flagsEvery flag and
What a PASS on the next head needs: ① item 5 fixed (four Implemented-by: VERDICT: FAIL Generated by Claude Code |
…grate-meta-relevance-predicate
… code-door entries lose their question; tiers is a carrier Contract-review patch round: applyMetaMigrations().todos and each hop's todos keep every semantic entry again; absentTodos names the proven-absent entries as a subset of them (same objects). os migrate meta lists todos minus absentTodos. The four CEL/RLS predicate entries whose surface also names a direct evaluator or compiler caller lose relevantWhen (batch 25). A declared tiers preset answers unknown like plugins. Docs: --all in the flags table. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RPo7FUd6bSnAfkWMAKi848
Contract reviewServed-tier: Isolated at-tier reviewer, dispatched from the adopting seat; read-only; patch round 1, answering the FAIL Check-runs on the head. Read at 2026-10-07T20:00:47Z: 35 runs, every one ① Derived judgmentsThe accept-set and public-surface changes the diff (vs
② Semver levelWhat the diff publishes under disposition B. Additive only: three exported types; the optional Ruling. ③ Boundary flagsEvery flag and
Landing: the contract holds on this head. The one open item is mechanical and the seat's: merge current Implemented-by: VERDICT: PASS |
…grate-meta-relevance-predicate # Conflicts: # content/docs/upgrading.mdx # packages/cli/src/commands/migrate/meta.ts
… zero Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RPo7FUd6bSnAfkWMAKi848
…grate-meta-relevance-predicate
`MigrationReport.all` (the --all flag) is a required member of the report; the literal the early-return pin builds omitted it (TS2741 under tsconfig.test.json). No assertion changes. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RPo7FUd6bSnAfkWMAKi848
Contract reviewServed-tier: Isolated at-tier reviewer, dispatched from the adopting seat; read-only; merge rounds 1 and 2, after the PASS Check-runs on the head. Read at 2026-10-07T22:28:03Z: 42 runs, every one The commit chain (10 commits from ① Derived judgmentsThe accept-set and public-surface changes the net diff (39 files, +942 / −64) implies, each judged.
② Semver levelWhat the diff publishes. Ruling. ③ Boundary flagsEvery flag and
Landing: the contract holds on this head; no governed path, so the record is owed by the claim's Implemented-by: VERDICT: PASS |
Fixes #22072
Clause-②: yes
os migrate metanow has the one exit that #20620's triage (5888087153) allows a notice: a structured proof, derived from the stack, that the notice's surface is absent. An entry that carries a question leaves the default list only when the chain answersabsentfor this stack. The run counts those entries on one line, and--alllists them in full. ⛔ Nothing matches the prose ofsurface.The question:
SemanticMigration.relevantWhen(packages/spec/src/migrations/types.ts)conversionIds, following the precedent spec(migrations): a semantic entry names the D2 conversions whose applied edits it judges (SemanticMigration.conversionIds), so os migrate meta can pair them (the spec half of #20620) #20697 set. Its type is a closed union,SemanticRelevance. This release has one member,StackDeclaresRelevance:{ kind: 'stack-declares', keys: [...] }. It asks one question: does the stack declare anything under one of these top-level keys?keysis a non-empty tuple ofSemanticRelevanceKey, which isStackDefinitionKeyminus the five carrier keys (manifest,packages,plugins,devPluginsandtiers). A typo does not compile. A key later retired from the stack makes the entry that names it fail to compile.chain.ts.Evaluation (
chain.ts)The answer has three values, and only
absentmoves an entry (H2, built in):[]or{}null, or a getter that throwsplugins/devPlugins/tiers(unless the stack visibly declares the key itself)packages[].manifestbodyconversionIdsnames a conversion that applied an edit in the same run is always listed. The applied edit proves the surface is there.MigrationChainResultandMigrationHopResultgain a required member,absentTodos.todoskeeps every semantic entry of every hop crossed, exactly as before;absentTodosnames the proven-absent subset of it (the same objects, in chain order).The output (
packages/cli/src/commands/migrate/meta.ts; the cross-lane half, declared on thedomain:cliseat post)todosminusabsentTodos, and its header counts that difference. A new group ④ follows it. It is two lines. The first counts the entries proven absent and names--all. The second says the proof covers the stack this run loaded, and not metadata a deployment stores (Studio, the metadata API).--allprints each of those entries in full, as the same block ③ prints, followed byabsent: nothing is declared underand the keys.--jsonalways carriesabsentTodos, andhops[].absentTodoswith--step.--stepadds anot listedcount to a hop's line when that count is not zero.--out.--outon both exits, the early return is guarded by the original conditionapplied.length === 0 && todos.length === 0.Because
todosis whole, a run whose only notices are proven absent never takes that branch. It goes down the main path: ④, then the onewriteStackSnapshot, then--write.Measured in-process on the merged code, with and without
--all. Every arm writes the snapshot exactly once and names it on exactly one line:todos=absentTodos= the 20 questioned)--write, its own group (⑤ in the report docstring) prints after ④ and before the data-migration advice.--writereads only the chain'sapplied,stackand the normalized input. It never readstodosorabsentTodos, and neither of them changes what it writes.refreshIntervaland no cubes (--from 17):--write --jsonreport identicaltodos(314) andabsentTodos(17).applied(1 of 1).--write --alllists ④ in full, then prints ⑤ (Wrote 1 of 1 …).--write's "no mechanical change" line in either branch.hotcrm's default report now ends like this:
The first batch: 25 of the 391 entries carry a question
analyticsCubescube-join-sql-and-relationship-retired,cube-member-inner-name-retired,cube-member-sql-expression-retired,cube-metric-expression-types-retired,cube-metric-filters-retired,cube-refresh-key-retired,analytics-cube-public-default-visible-enforced,analytics-cube-single-granularity-default-enforceddashboardsdashboard-widget-compareto-offset,dashboard-refresh-interval-unit-in-key,dashboard-header-modal-target-page-onlydashboards/reports/pageschart-config-aria-retiredpermissionspermission-restore-purge-bits-retiredsharingRulessharing-rule-recipient-reconcileapisdeclarative-apis-endpoints-live,api-endpoint-cache-ttl-unit-in-keyjobsjob-retry-policy-constraints-tightened,job-timeout-unit-in-keyagentsagent-memory-store-retired-and-limits-required,agent-structured-output-refused-members-retireddatasetsdataset-measure-aggregate-field-type-refused,dataset-measure-selecting-aggregate-field-type-refusedmappingsmapping-lookup-params-retiredhookshook-timeout-unit-in-keytoolstool-requires-confirmation-retiredsemantic-relevance.test.tspins this table, so every addition is a reviewed edit. I read each entry against three rules:ReportSchemais also carried inline in anobject-metricdrill-down, so the chart-config entry namespagestoo.sys_metadatarow and no runtime door.Some families are left out on purpose:
tags,checkon select/delete, the cross-class comparison, andcel-predicate-list-comparand-refused.cel-predicate-one-value-comparand-refused,cel-predicate-variable-root-comparand-refused,rls-predicate-array-comparand-refusedandrls-predicate-stored-list-ordering-refused: their surface also names a code door, a directmatchesFilterCondition/ compiler caller (patch round 1).engine.registerConnectorfrom code;flow-edge-unresolved-or-repeated-refusedfalls under rule 3: its acceptance criteria send the author to stored flow rows insys_metadata.sys_flow_dispatch/sys_job/sys_job_queue/sys_job_run/sys_migration_journal/sys_migration/sys_presenceorganization_idretirements fall under rule 2: each surface is a platform-shipped table, not a stack key.Measured: listed count before and after
"Before" is
todos, which is whole again (disposition B). "After" istodosminusabsentTodos, which is what ③ lists. I read both from--jsonof this branch's CLI at the merge heade74764dbb.absentTodoswas a subset oftodoson every row.--fromc967803c967803examples/app-crmexamples/app-todoexamples/app-multi-package(assembledpackages[])examples/app-showcase(lists runtime plugins)c967803, the commit the card measured, loaded with this branch's CLI and spec.mainhas added ten step-18 entries since. The 12 entries that leave the list, and the 12 applied edits, are unchanged.--stephop line reads12 mechanical, 302 manual, 12 not listed (surface absent).stack-declaresquestion can reach them, and each needs a different kind of question.For the contract review
todosmembership — disposition B (patch round 1).applyMetaMigrations().todos,MigrationHopResult.todosand--json'stodosare unchanged: every semantic entry, as their TSDoc promised.absentTodosis a new required member ofMigrationChainResultandMigrationHopResultnaming the proven-absent subset.migrations.test.ts's original equality pin is restored, with a subset pin beside it.Clause-②: yes,minor, no BREAKING line.os migrate meta --storedreports D2 conversion TODOs per row and never reports the D3 catalogue. The printed scope line states this boundary.chain.tsexports the functionssemanticRelevanceVerdictandsemanticTodoAbsentand the typeSemanticRelevanceVerdictfor its own tests only. None of them is re-exported from@objectstack/spec/migrations; theapi-surface/migrations.jsonshard gains only the three published types.Verification (head
16cb55b8d; the merge5fc3a5a2awith54ace18c6)client-reactgave 61 tasks, all successful.--out/ report pins against the merged code:test/migrate-meta-out-snapshot.test.ts(fix(cli): os migrate meta --out writes its snapshot on a run with nothing to migrate #22121, whole file),src/commands/migrate/meta.report-order.test.ts(ORDER, SET, PAIR, ABSENT, including 'a run whose only notices are proven absent still counts them and still writes --out') andtest/migrate-meta-write.test.tsgaveTest Files 3 passed (3),Tests 52 passed (52).Test Files 58 passed (58),Tests 2331 passed (2331). That covers the ENUMERATION (25: 5 + 20), SHAPE, EVALUATION and CHAIN pins, andmigrations.test.ts's equality and subset pins.pnpm --filter @objectstack/spec typecheckexit 0.pnpm --filter @objectstack/cli typecheckexit 0,check:test-typecheckincluded:OK — … 3 file(s) / 28 error(s) / 6 pinned signature(s) held in test-typecheck-debt.json.tsc -p tsconfig.test.jsongave 29 errors before the fix (the 28 the ledger holds, plus the new TS2741) and 28 after. The ledger is not touched.Test Files 263 passed (263),Tests 3874 passed (3874).test/migrate-meta-engine-guidance.test.ts(it passes--all) andtest/migrate-meta-default-range.test.tsgaveTest Files 2 passed (2),Tests 10 passed | 1 skipped (11).check:migration-registryreports391 semantic; fix(cli): os migrate meta --out writes its snapshot on a run with nothing to migrate #22121 adds no entry.registry.tscarries 25relevantWhenlines.dispatch-gates --commandsderived 117 families at16cb55b8d. 116 exited 0. 1 is NOT MEASURED:check:dual-build-cjs-loadsexited 3, PREREQUISITE NOT MET.check:vendor-version-stampsfirst exited 1 on ENOENT for a temp file the concurrently running CLI unit tier created underpackages/cli/tmp/. Re-run alone, it exited 0.--ranaccounted for all 117.54ace18c6: 35 files, 0 errors, 0 warnings. There is no type-aware linting, so no untouched file's verdict can move.Mechanism hypotheses, measured
SemanticMigrationwas attypes.ts:38andconversionIdsat:73. The chain mapped everystep.semanticentry intotodos(chain.ts:102). Since the order and pair work, ③ prints frommeta.tsaround:439.app-showcasemeasures it: 314 before and 314 after.Acceptance notes
os migrate meta --from 18 --to 18 --out FILEcovers a range with no step: its human report writes no snapshot and says nothing about it, while--jsonwrites the file. Unchanged here (an empty range has noabsentTodos). Filed by the seat as finding(cli):os migrate meta --out FILEover a range with no step exits 0 and writes no snapshot, while the same run with--jsonwrites FILE #22116.skills/objectstack-upgrade/SKILL.md(Tier H) loops over--json'stodos; under disposition B its reading is unchanged, so no governed edit is owed.origin/main:de8ccbcfa(witha543e244f, clean);e74764dbb(withdb4c45b8c, two conflicts resolved by stacking both intents, see the merge-round note at the top);5fc3a5a2a(with54ace18c6, clean, see merge round 2).meta.tsandupgrading.mdxsurvives the merge, and so does every line main added, except two that were changed by hand. Both are comments.--writegroup is relabelled from ④ to ⑤, because this PR's ④ is the absent group.;, and a ⑤ item follows it for--write.e74764dbb. The catalogue (391) and everyrelevantWhenare unchanged since, so it still holds.Generated by Claude Code