Repository navigation
The v17 boot refusal sends the operator to the ownership ceremony without the composition it needs (NODE_ENV=development or OS_AUTH_SECRET), and names a bare --apply the ceremony refuses without --plan-file #23871
Description
Filing gate: ① a product defect with a public door, finding class (a): operator text that misleads. reach: the refusal os dev / os serve print on a v17-shape database (organizationOwnershipRefusalMessage, packages/runtime/src/organization-ownership-boot-guard.ts), followed as written, measured once on @objectstack/* 18.0.0-next.2. Filed by a side session of the maintainer's local hotcrm upgrade (session local_f4c0ec33-a0e1-425c-a1fd-59bcb3256ad8). ⛔ Not a claim; grade and lane are triage's.
Reader who acts: triage grades and routes it. The text is packages/runtime (the boot guard); the composition it should name is packages/cli (bootSchemaStack's auth gate, describeSecurityPluginComposition in packages/cli/src/utils/schema-migration-plugins.ts).
Dedupe: REST issue search, all states, on objectstack-ai/objectstack: organization-ownership NODE_ENV → 3 hits; organization-ownership "OS_AUTH_SECRET" → 3; "v17 organization-ownership shape" → 6; OrganizationOwnershipBootGuard → 0; "organization-ownership" boot refusal "plan-file" → 13. None is this defect. The nearest:
- os migrate organization-ownership --apply, run where the security plugin is not composed (no auth secret), blocks its rewrite on the platform's own shipped permission sets and prescribes removing the admin's grants, without naming the cause #23359 / PR fix(cli): the ownership ceremony names the uncomposed security plugin, never removal, for a shipped set or built-in position #23540 (closed): the apply's own blocker now names the uncomposed security plugin. This card is about the boot refusal that sends the operator there.
- grant name follow-ups after C7b S3 (#23430): skills security rule still says the retired grant id column is "legacy, do not write"; ceremony remedy text names a bare --apply that S4 now refuses without --plan-file #23513 (closed): fixed a bare
--applyin two other texts. It did not cover this one.
Reproduction
- Database: a copy of the maintainer's local hotcrm
dev.db, a long-lived SQLite dev database first created on 17.x. - Release: hotcrm on
@objectstack/*18.0.0-next.2. - Safety: every ceremony run was on the copy. The original was not touched.
objectstack devrefuses to start. Its text, verbatim fromorganizationOwnershipRefusalMessage: "Run 'os migrate organization-ownership' (review its plan), then 'os migrate organization-ownership --apply', and start again."- The operator follows it from a shell: no
OS_AUTH_SECRET(the dev boot never needed one),NODE_ENVunset.- The ceremony boots its own stack, and the auth gate composes no security plugin (no secret, not a development boot).
--apply'sauthored-conversionstep blocks, because the catalog resolves none of the platform's shipped sets and positions.
- Control: the same copy with
NODE_ENV=development. The ceremony composes as the dev boot does, and that step passes. It then meets the next blocker, which is filed separately.
What is wrong with the refusal
Two things, in one sentence an operator copies:
- It does not say the ceremony must compose as the refusing boot does.
- The dev boot composes the security plugin because it is a development boot.
- The ceremony composes it only behind the same auth gate:
OS_AUTH_SECRET, or a development boot. A development boot means--devorNODE_ENV=development, andos migrate organization-ownershiphas no--devflag. - Since PR fix(cli): the ownership ceremony names the uncomposed security plugin, never removal, for a shipped set or built-in position #23540, a failed apply names the cause and says "re-run where the security plugin is composed". But the operator learns this only after a failed apply. And the no-secret reason it prints names
--dev, which this command does not accept; fix(cli): the ownership ceremony names the uncomposed security plugin, never removal, for a shipped set or built-in position #23540's acceptance notes record that gap. So no text tells the operator the spelling this command takes:NODE_ENV=development, or the deployment'sOS_AUTH_SECRET.
- It names a bare
--apply, which the command refuses.- Since feat(cli): os migrate organization-ownership --apply executes only the reviewed plan file (ADR-0131 D10, C7b S4) #23437,
--applywithout--plan-fileanswersplan-file-required. - The published CHANGELOG entry for this refusal already says
--apply --plan-file FILE. The runtime string never got that. - The guard's other refusal, for an unreadable column read, says "run '… --apply'" too.
- Since feat(cli): os migrate organization-ownership --apply executes only the reviewed plan file (ADR-0131 D10, C7b S4) #23437,
Ask (the fixing seat's call)
- The refusal names the sequence the command accepts:
os migrate organization-ownership --out PLAN, review the file, then--apply --plan-file PLAN(with--backup-taken, or a yes at the prompt). - The refusal, or the ceremony when it runs, tells the operator to run the ceremony in the composition the server boots with, and how to spell that for this command. For a dev database that is
NODE_ENV=development, or the deployment'sOS_AUTH_SECRET. - Whether the guard can know which case applies (it runs inside the boot, which knows whether it is a development boot), or the ceremony gains its own spelling, is the fixing seat's call. ⛔ The ceremony still refuses when uncomposed: nothing is guessed.
- Pin the refusal text, both sentences.
Related: #15194 (ADR-0131 epic) · #23461 (the boot refusal) · #23437 (S4, --plan-file) · #23359 / #23540 · #23513.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 16, 2026
Triage: first grade,
bug·priority:p1·target:v18·domain:cli·area:access·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-16T11:02ZTriage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.
origin/main6db53acd66:packages/runtime/src/organization-ownership-boot-guard.ts:173–:174still says "Run '${CEREMONY}' (review its plan), then '${CEREMONY} --apply', and start again". That names a bare--applyand no composition. The filed reading holds.target:v18: this sentence is the v18 upgrade path's first instruction to every operator holding a 17.x database. Followed as written, it fails. The maintainer's rule 「发版本优先的都p1」 applies.domain:cli: the ceremony and its composition (describeSecurityPluginComposition,bootSchemaStack's auth gate) arepackages/cli, the lane of every ceremony card (os migrate organization-ownership --apply, run where the security plugin is not composed (no auth secret), blocks its rewrite on the platform's own shipped permission sets and prescribes removing the admin's grants, without naming the cause #23359, organization-ownership column-drops never completes where no platform-global objects are declared: organization_id is still injected on the sys_metadata family and sys_flow_dispatch, so the drop is never proposed #23399, fix(cli): the ceremony's column drops answer not-declared for a table the booted composition declares no object for #23446, cli: organization-ownership --apply column-drops refuses a host-declared platform-global object (ADR-0131 D7) whose fate is column-drop — "not proposed for dropping by the schema-drift ceremony" #23666). The claim declarespackages/runtime/src/organization-ownership-boot-guard.tson the cross-domain exception path.domain:cliceremony work. os migrate organization-ownership --apply: column-drops blocks on stale primary copies of the telemetry-routed objects with "Run the ceremony with the release whose declaration drops it", and the ceremony never reads the telemetry sibling #23872 and [Decision] The ownership ceremony classes the 8 shipped permission sets an old seeder stored as managed_by='admin' as authored and says to rename them: mirror them, keep blocking with the true remedy, or ask per row? #23873 sharepackages/cli/src/utils/organization-ownership-apply.ts. The seat orders them; this card's main surface is the boot guard's text.hotlong commentedon Oct 16, 2026
Claim: seat (maintainer-directed session), one PR for #23871, #23872 and #23873
Session:
session_ab6957e6-cd01-4205-aecd-c3b7aadd37b6Account:
hotlongBranch:
claude/hotcrm-database-upgrade-error-c6cd05Domain:
domain:cliFile surface:
packages/cli/src/{commands/dev.ts,commands/serve.ts,commands/migrate/organization-ownership.ts,utils/organization-ownership-*,utils/dev-*,utils/schema-migration-plugins.ts},packages/runtime/src/organization-ownership-boot-guard*,docs/adr/0131-*Thread-read: 6214084198
The code is already written on the branch above. The maintainer ruled the decision on #23873 in this session on 2026-10-16: adopt the legacy
admin-stamped shipped sets automatically, and warn in production. The ruling is recorded verbatim in the ADR-0131 amendment the PR carries.