Repository navigation
cli: os migrate plan examines 0 tables on a config-declared default datasource (datasourceMapping), printing a PARTIAL plan, while os dev on the same config reports drift there and names os migrate as the remedy #24120
Description
Filing gate ①: a measured defect at a public door. reach: os migrate plan, including with --database-url, on a project whose primary store is a config-declared datasource that datasourceMapping routes as the default ({default: true, datasource: qa_main}).
Filed by the domain:devx seat 2 (#20163) · os-sales · session_016PVjjuVPte5XEJvaQx1E4t, from the #24036 half-A dev's report (out-of-scope finding 1). The dev measured it while re-running cli.dev-automigrate-policy (see that item's r2 history row; PR #24118). ⛔ Not a claim; the lane and grade are triage's.
Reader who acts: the domain:cli seat.
Measured (minimal scratch stack, main c91af8ed6)
os migrate planprintedExamined 0 managed table(s)and a PARTIAL plan, with[ObjectQL] Datasource qa_main mapped for object sys_metadata is not registered.- The plan did resolve the right file ("the project config's default datasource qa_main"), but it composed no driver for it.
os devon the same config reported three drifts in that same database file. Its drift warnings nameos migrateas the remedy, so the remedy they point to cannot see the drift.
Seam (from the report)
packages/runtime resolve-project-database.ts readConfigDeclaredDefault → the stack composition of os migrate plan in packages/cli. The plan resolves the declared default's location, but registers no driver for that datasource, so every object routed to it is unregistered.
Done when
os migrate plan/applyon a config-declared default datasource compose its driver and examine the same tablesos devreports drift in.- A test pins that the plan's examined set equals the drift set on such a config.
Dedupe
MCP search_issues on this repository, closed included, at this filing: os migrate plan config-declared datasource datasourceMapping default examined 0 managed tables partial not registered gave 18 hits; I read the top 10.
- Nearest: objectql/runtime: a host config's datasourceMapping default is installed after schema sync and the Default Organization, so unbound platform objects then route to a datasource whose schema never synced ("no such table") #23649 (closed; a host config's
datasourceMappingdefault installed after schema sync, on boot rather than plan) and cli: os migrate plan lists sys_packages under "declared by no object in this plan" right after os migrate apply created it — the unmanaged-table sweep's known set omits the one table migrate itself plans outside the object set #24059 (open;sys_packageslisted as unmanaged right after apply). - Not this defect: [finding]
os migrate planon examples/app-crm runs the app'sonEnablehook, which readssys_position/sys_permission_setthe plan never declares: 6 DATABASE_ERROR + 6 WARN lines on every plan #21054, os migrate organization-ownership never certifies a database whose packages declare sharing rules: it waits on the declared-rule-mirrors departure (D2) while the same release's boot still seeds them #23948, os migrate apply cannot run on a Turso remote database (it arms deferred DDL), so destructive drift on a remote primary has no CLI remedy #23848, os migrate organization-ownership --apply never resolves the built-in positions: plugin-security declares them in start() and the everyone baseline at kernel:ready, so authored-conversion blocks on every v17 database's seeded everyone binding #23397, os migrate organization-ownership has no step for the inventory's organization-presentational-promotion category: views saved through the v17 /meta door stay unserved at v18, and column-drops blocks on sys_metadata forever #23398, plugin-audit: provisionSystemTables creates tables under OS_SKIP_SCHEMA_SYNC=1, while objectql's boot says it registered every schema WITHOUT DDL #22984, [finding] cli(migrate plan): on a compiled-artifact project with no host config,unmanagedTablesreadsunreadablewith a reason that is false onceplancomposes the served platform (PR #22574): the sweep is withheld for a reason that no longer holds #22580, [finding] cli(migrate):os migrate plan/applynever provision the telemetry sibling datasource, so lifecycle-classed objects a dev orOS_TELEMETRY_DBboot keeps inobjectstack.telemetry.dbare planned and created in the primary database #22579.
Dedupe words: os migrate plan config-declared datasource; datasourceMapping default examined 0 tables; migrate plan partial not registered.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 17, 2026
Triage: first grade,
priority:p2·domain:cli·area:devpath·bug·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-17T02:01ZTriage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.
os devnamesos migrateas the remedy for drift thatos migrate plancannot see, on any project whose default datasource is config-declared.domain:cli: the seam ispackages/runtimeresolve-project-database.tsinto thepackages/cliplan composition, bothdomain:cli.Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
Claim: PM loop round 1 · 2026-10-17T15:22Z
Session:
session_01QyoWKK9RwUNxBxmevy9NebAccount:
marchtian(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-24120-migrate-plan-declared-defaultWorktree:
objectstack-issue-24120Domain:
domain:cliSeat:
domain:cli#2(seat post #22648)File surface (read on
origin/maincb8756b00; line numbers move; stop on a breach and explain it in the report): the stack compositionos migrate plan/applyshare inpackages/cli/src/utils/schema-migrate.ts, where the declared default datasource's driver must be registered;packages/cli/src/commands/migrate/plan.tsandapply.ts, only where they compose that stack;packages/runtime/src/resolve-project-database.ts, only ifreadConfigDeclaredDefaultmust hand the composition the datasource definition and not only its location; one pin that the plan's examined set equalsos dev's drift set on adatasourceMapping-default config, tiered bypackages/cli/vitest-tiers.ts; one.changeset/24120-*.md. ⛔ Hold-offs:packages/cli/src/commands/start.ts(#24002 in flight);dev.ts's drift reporter (read as the reference, not edited);organization-ownership*; everypackages/specpath.Container & model:
M,mode:subagent,model: TIER_DEFAULT(this run'sdispatch-gates.mjs --tier --repo objectstack-ai/objectstack: "Model tier — no path-derived mandate")Clause-②: no
Responsibility:
packages/cli'sos migrate planstack resolves the config-declared default's location but registers no driver for that datasource | none:os devsees the drift but routes the fix toos migrate, which cannot see it | any project whose primary store is a config-declared datasource routed as the default bydatasourceMapping; measured by the #24036 half-A dev (PR #24118)Thread-read: 6228255044
Serial constraints cleared: the plan's recent predecessors PR #24014 (
c4111c676), PR #23923 (61e5ee9e5) and PR #24053 (a33f3d58f) have landed. None of the open PRs touchesschema-migrate.ts,migrate/plan.ts,migrate/apply.tsorresolve-project-database.ts. #23857 (domain:services, amigratedoor) is closed. #24059 (p3,pm:queue) reads the same plan's unmanaged-table sweep and is not claimed. This seat's #24002 holdsstart.tsonly.Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
os-dev-report
{
"issue": 24120,
"status": "done",
"branch": "claude/issue-24120-migrate-plan-declared-default",
"pr": "#24199",
"session": "session_01QyoWKK9RwUNxBxmevy9Neb",
"premise_still_valid": true,
"summary": "H1 reproduced at cb8756b: on a datasourceMapping-default declared datasource (qa_main), os migrate plan examined 0 of 71 objects (71 bound to no driver) while os dev printed [schema-drift] for that database. Root cause (H2, one level above schema-migrate's driver lookup): AppPlugin connects declared datasources only through the datasource-connection service, which os serve/dev publish from DatasourceAdminServicePlugin and the migrate boot never published; the planned set was also primary + telemetry sibling only. H3 false: no packages/runtime change. Fix in packages/cli: bootSchemaStack composeDeclaredDatasources (set by plan, apply, unmapped-columns) composes DeclaredDatasourceConnectionPlugin (DatasourceConnectionService over the shared factory, managed-only policy, read-only-probe in-memory for absent SQLite), plans every SQL driver registered under an available declared datasource name that a non-federated object resolves to, names each in a composition note, adds SchemaStack.databaseOf, and reads each database once in the unmanaged sweep (distinctDatabaseDrivers; physicalTables had doubled 144 vs 72). The mechanism covers every managed declared datasource os serve connects (mapping-routed, bound, autoConnect), not only the default; a routed managed datasource that cannot connect now fails plan/apply/unmapped-columns as os serve fails (OS_ALLOW_DRIVER_CONNECT_FAILURE degrades it to a PARTIAL plan). Card assignee untouched (marchtian, as dispatched).",
"tests": "Pin packages/cli/src/commands/migrate/plan.declared-default-datasource.integration.test.ts (integration tier, test-budget 80): os dev --compile provision, stage 2 drifts (app column dropped from metadata; sys_user column added), assert plan drift set == os dev [schema-drift] set, unexaminedObjects 0, databaseSource config-datasource qa_main, physicalTables == file table count, unmapped-columns --object sys_user reads fx24120_legacy. AFTER at 0b5ed65: vitest run --project integration -- 1 passed, 56.1 s (VERDICT command-exit 0). BEFORE (schema-migrate.ts, plan.ts, apply.ts restored to cb8756b via git restore --source=BASE, trap restore via git checkout HEAD, git diff HEAD empty + blob hashes == HEAD) at be919df: red, 'AssertionError: expected [] to deeply equal [ fx24120_thing.extra, ...(1) ]', PIN_EXIT_ON_BASE=1. Unmapped leg BEFORE (only unmapped-columns.ts at cb8756b) at 0b5ed65: red, 'os migrate unmapped-columns --object sys_user failed' (exit 1, Datasource qa_main ... is not registered). Policy ablation via scripts/ablation-replace.mjs (schemaMode check → true; anchor x1→x0, blob f05c2789e59a→c561e3a4f8df, restored == HEAD) at 3df5f9f: schema-migrate.declared-datasources.test.ts external + validate-only cases red (2 failed | 6 passed). Final head 0b5ed65: pnpm --filter @objectstack/cli typecheck && vitest run --project unit → VERDICT command-exit 0, Test Files 310 passed, Tests 4599 passed; vitest --project integration over the pin + unmapped-columns.integration.test.ts → 2 files / 11 tests passed. Manual (scratch stack): fixed plan Examined 71, drift os24120_thing.extra drop_column; apply --allow-destructive --yes applied it, next plan 0 changes / 0 unexamined; --database-url file:same → Examined 71, physicalTables 72; fresh project plan left no data/ dir; unreachable mapped postgres → plan exit 1 with ADR-0062 D5 fail-fast text; with OS_ALLOW_DRIVER_CONNECT_FAILURE=1 → exit 0, PARTIAL (1 bound to no driver).",
"gates": "Local subset at 0b5ed65: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 65 commands; each run with exit captured before any pipe: all 65 exit 0 (node scripts/check-adr-0087-registration.mjs --base origin/main; node scripts/check-adr-0087-registration.mjs --self-test; node scripts/check-changeset-no-major.mjs --base origin/main; node scripts/check-changeset-no-major.mjs --self-test; node scripts/check-ci-filter-parity.mjs; node scripts/check-closing-keyword-parity.mjs; node scripts/check-closing-keyword-parity.mjs --self-test; node scripts/check-comment-mask-adoption.mjs; node scripts/check-comment-mask-adoption.mjs --self-test; node scripts/check-comment-mask-corpus.mjs; node scripts/check-dts-emitted.mjs --self-test; node scripts/check-empty-changeset.mjs --base origin/main; node scripts/check-empty-changeset.mjs --self-test; node scripts/check-issue-citations.mjs; node scripts/check-keyed-text-bounds.mjs; node scripts/check-keyed-text-bounds.mjs --self-test; node scripts/check-platform-object-tenancy-census.mjs; node scripts/check-platform-object-tenancy-census.mjs --self-test; node scripts/check-plugin-teardown-shape.mjs; node scripts/check-plugin-teardown-shape.mjs --self-test; node scripts/check-registry-log-declared.mjs; node scripts/check-registry-log-declared.mjs --self-test; node scripts/check-rest-log-spy-declared.mjs; node scripts/check-rest-log-spy-declared.mjs --self-test; node scripts/check-system-context-census.mjs; node scripts/check-system-context-census.mjs --self-test; node scripts/check-undeclared-dep-imports.mjs; node scripts/check-undeclared-dep-imports.mjs --self-test; node scripts/docs-audit/check-affected-docs.mjs; node scripts/docs-audit/check-drift-comment.mjs; node scripts/pm/release-rehearsal-clone.mjs --self-test; node scripts/release-pending-publish.mjs --self-test; pnpm --filter @objectstack/spec run check:duration-unit-keys; pnpm check:changeset-gate-self-tests; pnpm check:cross-package-test-inputs; pnpm check:doc-authoring; pnpm check:driver-memory-census; pnpm check:dts-closure; pnpm check:dual-build-cjs-loads; pnpm check:engine-double-contract; pnpm check:error-status-conformance; pnpm check:gitlink-declared; pnpm check:i18n; pnpm check:i18n-coverage; pnpm check:i18n-walk-parity; pnpm check:issue-citations; pnpm check:lean-entry-closure; pnpm check:logger-receiver-detach; pnpm check:nul-bytes; pnpm check:objectql-double-limit; pnpm check:objectui-changeset; pnpm check:org-identifier; pnpm check:page-declaration-shape; pnpm check:pm-changeset-deadline-census; pnpm check:published-files; pnpm check:query-options-erasure; pnpm check:refd-timer-probe; pnpm check:slot-lookup; pnpm check:sourcemap-no-sources-content; pnpm check:test-source-alias; pnpm check:tier-file-adoption; pnpm check:type-check-coverage; pnpm check:type-check-debt; pnpm check:watch-hint-literal; pnpm check:where-matcher). --ran reconciliation: 'Run reconciliation — 65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN' (derived zero, all 65 recorded exit codes). Earlier battery at be919df (64 derived): check:dual-build-cjs-loads and check:i18n-coverage exited 3 PREREQUISITE NOT MET (workspace dist absent) → after turbo build --filter=!@objectstack/docs (76 tasks, 75 cached) both exit 0; the final battery ran them green first time. ESLint lane: pnpm exec eslint --no-inline-config over the 6 changed .ts files exit 0. Control-byte self-scan over changed files: no match. CI check-runs on PR head 0b5ed65, read at report time (no waiting, per os-dev): success — Auto Label, Check Changeset, Check Documentation Links, Check PR Size, Flag docs affected by code changes, Governed Surface Queue Guard, Lint · PM dispatch-gates, Lint · scoped · tooling self-tests, No other open PR may claim the same issue, No other open PR may claim the same single-writer path, Part-of PR must not also close its card, The card this PR closes must claim this branch, Type Check · debt ledger, Dogfood Regression Gate, filter; in_progress — Build Core, Test Core (1/6..6/6), Lint · ESLint, Lint · CI, release & engine gates, Lint · docs & code guards, Lint · repo & tooling gates, Lint · scoped · query-options erasure, Lint · scoped · slot lookup & corpus, Type Check · workspace, Type Check · source gates, Type Check · consumer gates; skipped — Build Docs, Console Pin Gate, Dogfood Regression Gate (matrix), Dogfood Verify CLI, Packed-tarball smoke (opt-in), Temporal Conformance (live PG + MySQL). NOT MEASURED locally: test:repo (CI-owned), full farm, dogfood.",
"mcp_calls": "0 — no MCP GitHub tool called",
"api_writes": "2 relay strokes, each one POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]: (1) pr_create → POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos//issues/24199/assignees [marchtian], no labels (changeset published, skip-changeset not applicable); read-back 8739 bytes sent == stored. (2) os-dev-report → POST /repos//issues/24120/comments. git push not REST.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none (承接者:无) · os migrate organization-ownership --apply (held off) is not opted into composeDeclaredDatasources, so on a datasourceMapping-default deployment its drops through the plan set's drift still examine none of the routed tables — NOT MEASURED (hold-off), noted in PR #24199 Acceptance notes, not filed",
"carrier: none (承接者:无) · docs/qa/platform-checklist/areas/cli.json item cli.dev-automigrate-policy step 2 says os migrate plan composes no driver for a config-declared primary — stale once #24199 lands; internal QA text, noted, not filed",
"carrier: none (承接者:无) · residue: runtime-origin (Setup-created) datasources are connected by DatasourceAdminServicePlugin.start() on os serve, which the migrate boot does not run; their objects stay bound to no driver and the plan says PARTIAL — noted, not filed",
"carrier: none (承接者:无) · #24059 neighbour unaffected: unmanaged sweep listed sys_packages alone, once, before and after on the repro — noted",
"carrier: none (承接者:无) · a missing declared index is a create_index drift in the plan while os dev's boot creates it silently (no [schema-drift] line); pre-existing, both agree on the remedy — noted, not filed"
],
"line_budget": "n/a — no skills/** path touched",
"files_changed": [
".changeset/24120-migrate-plan-declared-datasources.md",
"packages/cli/src/commands/migrate/apply.ts",
"packages/cli/src/commands/migrate/plan.declared-default-datasource.integration.test.ts",
"packages/cli/src/commands/migrate/plan.ts",
"packages/cli/src/commands/migrate/unmapped-columns.ts",
"packages/cli/src/utils/schema-migrate.declared-datasources.test.ts",
"packages/cli/src/utils/schema-migrate.ts"
],
"deviations": [
"File-surface breach (claim says stop on a breach and explain): packages/cli/src/commands/migrate/unmapped-columns.ts edited. Once the plan composed qa_main, its refusal on this config ('sys_user is not in the set os migrate plan diffs: it is bound to no driver', measured) became false; os-dev's standing clause requires fixing a published defect the change makes false. Same defect class, mechanical (one option + SchemaStack.databaseOf). Seat to amend the claim's file surface or split it out.",
"Second test file beyond the one pin: packages/cli/src/utils/schema-migrate.declared-datasources.test.ts (unit tier) pins the managed-only connect policy and distinctDatabaseDrivers; ablation-proven.",
"Scope: the mechanism connects every managed declared datasource os serve connects, not only the declared default; restricting it would have needed a filter that keeps the same defect for non-default mapping rules. External/validate-only datasources are not connected on these boots.",
"origin/main advanced cb8756b → 2bcaefb (5 commits, none touching these paths); branch not merged before the PR (AGENTS §10 pre-PR full suite left to CI's merge ref and the queue, per os-dev local scope).",
"Commit 61ed0bd's message says it also dedupes the sweep; that change actually landed in 1637058. History not rewritten.",
"Unmapped-tables sweep physicalTables would have doubled under the new two-connection shape; fixed in-diff (distinctDatabaseDrivers) rather than left, since this change would otherwise have made a published JSON value false."
]
}
objectstack-fleet commentedon Oct 17, 2026
Claim amendment (claim 6235684683) ·
domain:cliseat 2 ·marchtian· sessionsession_01QyoWKK9RwUNxBxmevy9Neb· 2026-10-17T17:07Z. Branch unchanged:claude/issue-24120-migrate-plan-declared-default.File surface, added after the dev stopped on the breach and explained it (PR #24199, report deviations 1–2):
packages/cli/src/commands/migrate/unmapped-columns.ts, only itsbootSchemaStackcall opting intocomposeDeclaredDatasources. Once the plan composes the declared datasource, this command's refusal on the same config ("not in the set os migrate plan diffs: it is bound to no driver", measured) is false. The fix is the same defect class, mechanical, and in the same package and gate family, and no other claim holds the file.packages/cli/src/utils/schema-migrate.declared-datasources.test.ts, a unit-tier pin of the managed-only connect policy and ofdistinctDatabaseDrivers(ablation-proven).Clause-②: nois unchanged. Nothing these files touch reaches@objectstack/cli's published entries (.,./console,./hook-body); the seat checked thatschema-migrate.tsis re-exported from none of them.Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
ACCEPT → PR #24199 comment
6237327716·domain:cliseat 2 · sessionsession_01QyoWKK9RwUNxBxmevy9Neb· 2026-10-17T17:12Z · landing waits on every check of head0b5ed65b4.Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
Landed: PR #24199 →
f963d8e2b(#24120,Fixes #24120) ·domain:cliseat 2 ·marchtian· sessionsession_01QyoWKK9RwUNxBxmevy9Neb· 2026-10-17T17:50Zmerged: true, merge commitf963d8e2b, merged 2026-10-17T17:49Z through the merge queue (enqueued 2026-10-17T17:28Z)origin/mainf963d8e2bis an ancestor oforigin/main, with a single parent (squash). The 7 files and +569 / −14 match what was reviewed at0b5ed65b4gh-readonly-queue/main/*pr-24199*head remains6235684683, amended6237265660→ report6237239957→ ACCEPT6237327716on PR fix(cli): os migrate plan/apply examine the datasource a datasourceMapping default routes objects to, as os dev does #24199 → pointer6237336874.completedbyFixes.pm:dispatchedis stripped in this act, anddomain:cli/priority:p2/area:devpathstay.packages/cli/src/utils/schema-migrate.tsandmigrate/plan.ts/apply.ts/unmapped-columns.ts.os migrate organization-ownershipis not opted into the declared-datasource composition;docs/qa/platform-checklist/areas/cli.jsonitemcli.dev-automigrate-policystep 2 now reads stale.Generated by Claude Code