Skip to content

fix(cli): the organization-ownership drop refusal says what 18.0 supports for a v17 database - #24635

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-24567-drop-gate-refusal-text
Oct 19, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-24567-drop-gate-refusal-text

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #24567
Clause-②: no — basis: refusal and help text only. No accept set, flag, exit code, JSON key or behaviour moves: the gate still holds back the whole --allow-destructive run with refused_organization_ownership_unmigrated, exit 1.

Row 3 of #24567 (rows 1–2 landed in #24592), domain:cli seat 1, claim 6273418995. The drop-gate refusal that os migrate apply --allow-destructive gives on a 17.x-created database told the operator to run os migrate organization-ownership --out PLAN, then --apply --plan-file PLAN, and 18.0 refuses that command on every database (NOT_IMPLEMENTED). The refusal now says what 18.0 supports for a v17 database, in the boot refusal's terms, and names no step of that command. The command's --help examples and os dev's way-on line had the same problem and are fixed with it.

Before and after

Measured through the real CLI (node packages/cli/bin/run.js, built from each tree), on a 17.x-shaped SQLite made the way apply-organization-ownership-gate.integration.test.ts makes it: a v18 database created by os migrate apply --yes --json on an empty file, then ALTER TABLE sys_platform_setting ADD COLUMN organization_id TEXT. The command was os migrate apply --allow-destructive --yes --database-url file:COPY.db. It exited 1 both times, and the column was still there afterwards.

Before (base 65a8eeb7d):

✗ Refusing this --allow-destructive run: it would drop organization_id from sys_platform_setting, a drop the organization-ownership ceremony owns, and the ceremony has not verified on this database. No run of "os migrate organization-ownership --apply --plan-file FILE" is recorded on this database. Dropping the column first would turn every legacy organization row into an environment row without the ceremony's promotion or report. Run "os migrate organization-ownership --out PLAN" to write and review its plan, then "os migrate organization-ownership --apply --plan-file PLAN"; it drops these columns itself, in its column-drops step, before it records the run verified. Nothing in this run was applied.

On the same file, the command it prescribed answers this (exit 1, no plan file written):

✗ os migrate organization-ownership is not available in 18.0. 18.0 supports fresh installs only; the v17 → v18 upgrade path ships in an 18.x release. Keep a v17 database on a 17.x release until then. Nothing was read or written. (NOT_IMPLEMENTED)

After (head 69778e478):

✗ Refusing this --allow-destructive run: it would drop organization_id from sys_platform_setting, a drop the organization-ownership ceremony owns, and the ceremony has not verified on this database. No run of the organization-ownership ceremony is recorded on this database. Dropping the column first would turn every legacy organization row into an environment row without the ceremony's promotion or report. 18.0 supports fresh installs only and does not upgrade a v17 database: keep a v17 database on a 17.x release until the 18.x release that carries the upgrade path, whose ceremony drops these columns itself, in its column-drops step, before it records the run verified. Nothing in this run was applied.

The boot refusal it now matches (packages/runtime/src/organization-ownership-boot-guard.ts, v17-shape branch, not touched here): "18.0 does not upgrade a v17 database: keep this one on a 17.x release until the 18.x release that carries the upgrade path, and run these steps there." The drop gate cannot tell a v17 database from one 18.0 created (see the branch map), so it says "keep a v17 database" where the guard says "keep this one". That is also the wording of the command's own 18.0 refusal.

--json, the detail (the only prose the --json refusal carries):

  • before: No run of "os migrate organization-ownership --apply --plan-file FILE" is recorded on this database.
  • after: No run of the organization-ownership ceremony is recorded on this database.
  • message: refused_organization_ownership_unmigrated, tables: ["sys_platform_setting"], marker: null, applied: [], created: [] and exit 1 are unchanged (measured).

os migrate organization-ownership --help, EXAMPLES — before: six invocations, every one refused in 18.0:

$ os migrate organization-ownership
$ os migrate organization-ownership --out plans/v18-ownership.json
$ os migrate organization-ownership --database-url postgres://… --json
$ os migrate organization-ownership --apply --plan-file plans/v18-ownership.json --backup-taken
$ os migrate organization-ownership --fate-supplement host-fates.json
$ os migrate organization-ownership --dev

after (an override on the registered 18.0 class, MigrateOrganizationOwnership; the ceremony class OrganizationOwnershipCeremony keeps its six examples for the 18.x release that registers it):

EXAMPLES
  Refused in 18.0, plan and apply alike: exit 1 with NOT_IMPLEMENTED, nothing
  read or written. Keep a v17 database on a 17.x release until the 18.x
  release that carries the upgrade path

    $ os migrate organization-ownership

  The same refusal as JSON: error, reason upgrade-unavailable, code
  NOT_IMPLEMENTED, and the detail

    $ os migrate organization-ownership --json

os dev, the way-on line (utils/dev-organization-ownership-upgrade.ts; unit-measured, not run live). Before: "Run os migrate organization-ownership --dev (review its plan), then the same command with --apply --plan-file FILE --backup-taken, and start os dev again." After: "18.0 supports fresh installs only and does not upgrade a v17 database: keep a v17 development database on a 17.x release until the 18.x release that carries the upgrade path, and upgrade it there."

Branch map of the refusal

The gate sits in MigrateApply.run() (packages/cli/src/commands/migrate/apply.ts), below the drift report, above the confirmation prompt and above both writes.

condition that selects it what the operator sees here
no drop_column organization_id among the intended drift (ceremonyOrganizationColumnDrops(intended) is empty): every run without --allow-destructive, and every fresh 18.0 database whose objects keep their injected column nothing from this gate unchanged
a drop, and the sys_migration marker adr-0131-organization-ownership is verified organization_id on TABLES: the organization-ownership ceremony verified (DATE) — the drop may proceed. kept: true on any database, names no command
a drop, no marker (flag null) detail No run of the organization-ownership ceremony is recorded on this database., then the refusal above changed
a drop, a marker that is not verified detail The last run of the organization-ownership ceremony recorded on this database (DATE) is not verified (N blocking item(s))., then the refusal above changed (in 18.0 only a database a pre-18.0 ceremony ran on can carry one: 18.0 writes no marker)
--json on either refused branch { message: refused_organization_ownership_unmigrated, tables, detail, marker }, exit 1, with no prescription sentence, so only detail detail changed

When does it fire on a fresh 18.0 install? Only when an object newly declares no organization column over a table that already carries the injected one: systemFields: { tenant: false } on an existing object. I measured this at 69778e478. On a database this 18.0 CLI created with one app object acme_note (its table gets organization_id), declaring systemFields: { tenant: false } makes the drift report offer acme_note.organization_id … "os migrate apply --allow-destructive" to drop it., and that run is refused with the text above, exit 1, the column kept. The changeset for 6074eaf names this population on purpose: the ceremony plans that table.

The premise that organization-ownership --apply IS supported on a fresh install does not hold at origin/main. The registered MigrateOrganizationOwnership.run() refuses plan and apply on every database before it reads anything. Its doc says "plan and apply alike", and organization-ownership.release-refusal.test.ts pins this. So no branch of the old text was true in 18.0 on any database. Both refused branches change. The verified branch, the only one naming no command, is kept. The new text is true on a fresh database too: it says "keep a v17 database", not "keep this one". It gives such a database no way on, because 18.0 has none. That is an Acceptance note below, not a change here.

Census

git grep -n "organization-ownership" over packages/cli (source, help text, README, CHANGELOG) and content/docs, at 65a8eeb7d. These are the places that send a 17.x-created database's operator to the command:

place what it says here
cli/src/commands/migrate/apply.ts drop-gate refusal (was :586–:591) Run "os migrate organization-ownership --out PLAN" … then "… --apply --plan-file PLAN" changed (the defect)
cli/src/commands/migrate/apply.ts status lines, the detail (was :575 / :577) No run of "os migrate organization-ownership --apply --plan-file FILE" is recorded … / The last run of "…" … is not verified changed: --json carries only this sentence, and it named the command with --plan-file
cli/src/commands/migrate/apply.ts verified line (:607) the organization-ownership ceremony verified (DATE) — the drop may proceed. kept: true, names no command
cli/src/commands/migrate/organization-ownership.ts examples (:330–:337) six plan and apply invocations kept on the ceremony class (shown nowhere in 18.0, and true for the 18.x release that registers it); overridden on the registered 18.0 class (:1134)
cli/src/commands/migrate/organization-ownership.ts description and flag help 18.0's description already opens "Refused in 18.0, which supports fresh installs only: …"; the flag lines describe the ceremony's flags kept: the help's first sentence says refused, and examples now show the refusal
cli/src/utils/dev-organization-ownership-upgrade.ts manual (:127) "Run os migrate organization-ownership --dev (review its plan), then the same command with --apply …" changed: in 18.0 it printed right under the ceremony's own NOT_IMPLEMENTED line, and on a non-local database it was the whole answer
cli/src/utils/dev-organization-ownership-upgrade.ts again (:178, used :194, :207) "run os migrate organization-ownership --dev --apply --plan-file …" kept: reached only after a plan succeeded, which 18.0 never does
cli/src/commands/dev.ts:822 "This development database is still in the v17 organization-ownership shape — upgrading it in place (a copy is kept first)…" kept: names no command (see Acceptance notes)
cli/src/utils/organization-ownership-{apply,plan,inventory,column-drops}.ts, reportReservationText in organization-ownership.ts the ceremony's own messages kept: printed only when the ceremony class runs, which in 18.0 is only its tests
cli/src/commands/serve.ts, schema-migrate.ts, migrate-occupancy-gate.ts, security-catalog-overlays.ts, schema-migration-plugins.ts, vitest.config.ts comments only; serve prints the runtime boot guard's text kept: the boot guard is held off and is the reference
cli/README.md no hit —
cli/CHANGELOG.md (6074eaf, dd29bbe, 4369677 and others) released entries prescribing the ceremony kept: release-owned, they record what those releases did, never edited in a code PR
cli/src/**/*.test.ts (about 35 files) the ceremony's tests run the class directly kept; four pin files updated, one added (Tests)
content/docs pages generated from the CLI none: content/docs/references/ is generated from the spec and has no hit, and deployment/cli.mdx is hand-written (scripts/docs-audit/handwritten-docs.json) —
hand-written content/docs see Acceptance notes not edited here: domain:devx's

Tests

At head 69778e478 (patch round 1 at head 0df297be0, marked below), after pnpm --filter '@objectstack/cli^...' build (lock VERDICT command-exit 0) and the CLI's own build:

  • New src/commands/migrate/apply.organization-ownership-refusal.test.ts (unit tier: no boot, no driver). It runs the real command with the boot, the occupancy probe, the exit and the marker read replaced. For both refused marker states (none, unverified) it pins: the human face exits 1, the refusal names the table, it does not match os migrate organization-ownership|--plan-file|organization-ownership --out, it names the 17.x and the 18.x release, and nothing is written. It pins the same absence on the --json detail. A verified-marker control reaches the writes and exits 0.
  • apply-organization-ownership-gate.integration.test.ts: the detail pin /os migrate organization-ownership --apply/ is now /organization-ownership ceremony/ plus the same absence, on the real command against a v17-shape SQLite table. Run locally because the diff edits it: 5/5 passed.
  • organization-ownership-platform-global-column-drop.integration.test.ts:439 (patch round 1, 0df297be0) is the same detail pin, /os migrate organization-ownership --apply/. This PR's rewrite turned it red in CI (Test Core (3/6), 1 failed, 1,894 passed). It now asserts /organization-ownership ceremony/ plus the same absence. A census of every packages/cli test file, unit and integration, looked for any other assertion on the removed wording: organization-ownership --apply / --out, --plan-file PLAN / FILE, --dev as a prescription, write and review its plan, start os dev again, refused_organization_ownership_unmigrated and the registered class's examples. It found none. The remaining hits are describe titles, the ceremony class's own argv in suites that run it directly, and the again lines this PR keeps.
  • organization-ownership.release-refusal.test.ts: new case. Every example of the registered class names the command without --out / --apply / --plan-file / --fate-supplement, and its description names NOT_IMPLEMENTED. The ceremony class keeps an --apply --plan-file example.
  • dev-organization-ownership-upgrade.test.ts: the non-local case's pin toContain('os migrate organization-ownership --dev') is now the 17.x release plus the absence of the command and of --plan-file. The refused-plan case gains the same.
  • pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2 --project unit: 314 files, 4640 tests passed (run at c6cea949b; the last commit changes only the wording these pins read, and they were re-run at 69778e478: 4 files 99 tests, plus the integration file 5/5).
  • pnpm --filter @objectstack/cli exec vitest run --project integration --maxWorkers=2, in full at 0df297be0, under scripts/pm/os-verify-lock.sh, exit captured before any pipe (VERDICT command-exit 0): 161 files passed, 1 skipped (162); 1384 tests passed, 9 skipped (1393). The unit tier was re-run there as well: 314 files, 4640 tests passed.
  • pnpm --filter @objectstack/cli typecheck: exit 0 at 69778e478 and again at 0df297be0 (tsc --noEmit program lists all seven edited .ts files, 0 errors; check:test-typecheck OK, ledger unchanged).
  • Ablation of the pin at 69778e478, via node scripts/ablation-replace.mjs: the old prescription was put back into the refusal (anchor 'until the 18.x release that carries the upgrade path, whose ceremony drops these columns itself, in its ', x1 → x0; blob 7a6414669b72 → e8260625ac6f). Result: 2 failed | 3 passed. The two human-face cases went red; the two --json cases and the control stayed green, because the mutation touched the message, not the detail. Restored blob == HEAD, git diff HEAD empty. The subject resolves through a relative ./apply.js import (src, no dist), so no build leg was owed. A first attempt at c6cea949b was refused by the tool as a no-op: its replacement contained its anchor, so the anchor count did not move and nothing was measured. It was re-run with a new anchor (same 2 red).
  • Ablation of the detail pins at 0df297be0 (patch round 1): the old detail was put back into the no-marker branch (anchor 'No run of the organization-ownership ceremony is recorded on this database.', x1 → x0). Result: 3 failed, 2 passed (6 filtered out by -t). The no-marker human-face and --json cases in the unit file went red, and so did :439 in the integration file; the unverified-marker cases stayed green. Restored blob == HEAD, git diff HEAD empty.

Gates

All at head 69778e478, with every exit code captured before any pipe. All of it was re-run at 0df297be0 (patch round 1) with the same result: 9 paths, 292 changed lines, the same 68 derived commands, all exit 0. The same two PREREQUISITE NOT MET first attempts re-ran exit 0 after the build. The 11 wide families exit 0. --ran answers 68 derived, 68 run, 0 NOT-MEASURED, 0 UNRUN. pnpm lint exits 0, and eslint over the round's file exits 0.

  • node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands derived 68 commands: a change set of 8 paths, 288 changed lines against merge base 65a8eeb7d. All 68 exit 0. check:dual-build-cjs-loads and check:i18n-coverage first exited 3 with PREREQUISITE NOT MET, because some packages this diff does not touch had no dist. Those attempts measured nothing. After turbo run build of those packages (75 tasks, all cache hits), both re-ran: ✓ check:dual-build-cjs-loads — 111 published require entry point(s) across 69 package(s) load and check-i18n-coverage: OK (14 config(s), 621 baselined untranslated string(s), none new).
  • The 11 declared-wide families (check:init-service-contract, live-db-isolation, meta-type-normalized, optional-error-sink, resume-authority-declared, route-envelope, runner-env-posture, settings-bind-window, startup-registry-verdict, verify-stand-in, wildcard-fallthrough): all exit 0.
  • The --ran reconciliation answers Run reconciliation — 68 derived, 68 run, 0 NOT-MEASURED, 0 UNRUN. That zero is derived from the recorded exit codes. The 11 wide families are recorded as outside the derivation.
  • pnpm lint (eslint . --no-inline-config, the full union): exit 0.
  • eslint --no-inline-config over the 7 changed .ts files: exit 0, nothing printed. The control-byte self-scan of the changed files found none.
  • Lines from the gates: ✓ check-adr-0087-registration: this PR adds no declared-breaking changeset (1 non-breaking changeset(s) seen). · ✓ This diff introduces no major bump. · ✓ doc authoring guard: 19124 customer-facing string(s) across 1437 spec sources clean.

Acceptance notes

  • Row 1's open maintainer question is touched, not answered. Like the boot refusal, this text tells the operator to keep a v17 database on a 17.x release. A v18 os serve boot may already have added v18 schema to that database. That question stays with the maintainer. os migrate apply itself writes nothing before this refusal: the gate is above every write, and the boot defers DDL.
  • A database 18.0 created can reach this gate with no way on in 18.0 (measured above, acme_note). An object that newly declares systemFields: { tenant: false } over its injected organization_id makes the drift report prescribe --allow-destructive, and this gate refuses it. By source, the v18 boot guard then refuses os serve with "This database is still in the v17 organization-ownership shape … keep this one on a 17.x release" (findV17ShapeTables reads only tenant === false plus the physical column). Its os serve half was not measured. The 18.0 ruling covers v17 upgrades; this population is outside it. Reported to the seat for a decision. The text here makes no claim about it that is false.
  • Hand-written content/docs (domain:devx), not edited: deployment/cli.mdx:1027–:1029 describes the drop gate as waiting for "a verified os migrate organization-ownership --apply --plan-file FILE run", with no 18.0 qualifier there. deployment/cli.mdx:1477–:1494 has an 18.0 callout over a fenced plan and apply block. deployment/cli.mdx:200–:222 (os dev) has a callout, then "run the ceremony yourself" and "they refuse and name the command". concepts/metadata-lifecycle.mdx:109 says "an 18.x os serve refuses to start … until the v18 migration ceremony (os migrate organization-ownership --out PLAN, then --apply --plan-file PLAN)". permissions/capabilities.mdx:220 and permissions/permission-sets.mdx:399 describe what --apply does. The hits in deployment/environment-variables.mdx, deployment/install-modes.mdx, ui/public-data-collection.mdx and releases/v18/index.mdx are the ADR-0131 file name in a URL.
  • The same family outside packages/cli, held off here: metadata-core/src/legacy-organization-row.ts:78 ("Run os migrate organization-ownership on this database first."), metadata-protocol/src/seed-loader.ts:1739 ("os migrate organization-ownership, then the same command with --apply"), plugins/plugin-security/src/catalog-reference-report.ts:437–:438 (plan, then --apply --backup-taken --plan-file). Also two of the runtime boot guard's three refusals: the unverified-marker branch and the read-failure branch name the steps with no 18.0 sentence. And the spec's ADR-0087 entries 18.sys-metadata{,-audit,-commit,-history}-organization-column-retired, 18.ups-permission-set-id-column-retired, 18.sharing-rule-declared-mirror-retired and 18.cli-organization-ownership-apply-plan-file-required (domain:spec). Listed in the report for the seat to fold into one family card.
  • dev.ts:822 still prints "upgrading it in place" before an 18.0 upgrade that always stops at the plan's refusal. The lines after it now say why and what to do. It names no command, so it is kept.

Generated by Claude Code

…orts for a v17 database

os migrate apply --allow-destructive, os migrate organization-ownership --help
and os dev's way-on line named steps of os migrate organization-ownership,
which 18.0 refuses on every database. They now state 18.0's position in the
boot refusal's terms: keep a v17 database on a 17.x release until the 18.x
release that carries the upgrade path.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYEJqDL3NXxrJRBVqaMu9T
…abase 18.0 created

The drop gate also fires on a fresh 18.0 database whose object newly
declares systemFields.tenant false over its injected organization_id, so the
refusal names a v17 database rather than this one.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYEJqDL3NXxrJRBVqaMu9T
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Oct 19, 2026
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cli, touching 4 documentable anchor(s).

12 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/ai/skills-reference.mdx (via os migrate apply (command, read off packages/cli/src/commands/migrate/apply.ts))
  • content/docs/concepts/metadata-lifecycle.mdx (via os migrate organization-ownership (command, read off packages/cli/src/commands/migrate/organization-ownership.ts))
  • content/docs/data-modeling/drivers.mdx (via os migrate apply (command, read off packages/cli/src/commands/migrate/apply.ts))
  • content/docs/data-modeling/queries.mdx (via os migrate apply (command, read off packages/cli/src/commands/migrate/apply.ts))
  • content/docs/deployment/cli.mdx (via os migrate apply (command, read off packages/cli/src/commands/migrate/apply.ts), os migrate organization-ownership (command, read off packages/cli/src/commands/migrate/organization-ownership.ts))
  • content/docs/deployment/index.mdx (via os migrate apply (command, read off packages/cli/src/commands/migrate/apply.ts))
  • content/docs/deployment/self-hosting.mdx (via os migrate apply (command, read off packages/cli/src/commands/migrate/apply.ts))
  • content/docs/kernel/services-checklist.mdx (via os migrate apply (command, read off packages/cli/src/commands/migrate/apply.ts))
  • content/docs/permissions/capabilities.mdx (via os migrate organization-ownership (command, read off packages/cli/src/commands/migrate/organization-ownership.ts))
  • content/docs/permissions/permission-sets.mdx (via os migrate organization-ownership (command, read off packages/cli/src/commands/migrate/organization-ownership.ts))
  • content/docs/protocol/kernel/lifecycle.mdx (via os migrate apply (command, read off packages/cli/src/commands/migrate/apply.ts))
  • content/docs/upgrading.mdx (via os migrate apply (command, read off packages/cli/src/commands/migrate/apply.ts))

⛔ 4 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v17/17-3.mdx (via os migrate apply (command, read off packages/cli/src/commands/migrate/apply.ts))
  • content/docs/releases/v17/17-5.mdx (via os migrate apply (command, read off packages/cli/src/commands/migrate/apply.ts))
  • content/docs/releases/v17/17-6.mdx (via os migrate apply (command, read off packages/cli/src/commands/migrate/apply.ts))
  • content/docs/releases/v17/17-7.mdx (via os migrate apply (command, read off packages/cli/src/commands/migrate/apply.ts))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 2 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 29 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json b12e16a561cae3da15c09b463b470ce760b11834 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from b7fb116b2293dc0756cab9ed6e6a7652d2893768 — the merge of head 0df297be078c9575aeddc013b7064f9453efa90e into base b12e16a561cae3da15c09b463b470ce760b11834, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b7fb116b2293dc0756cab9ed6e6a7652d2893768 && git checkout b7fb116b2293dc0756cab9ed6e6a7652d2893768
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin b12e16a561cae3da15c09b463b470ce760b11834 0df297be078c9575aeddc013b7064f9453efa90e && git checkout -B drift-repro b12e16a561cae3da15c09b463b470ce760b11834 && git merge --no-ff 0df297be078c9575aeddc013b7064f9453efa90e

node scripts/docs-audit/affected-docs.mjs --json b12e16a561cae3da15c09b463b470ce760b11834

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs b12e16a561cae3da15c09b463b470ce760b11834 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 — ACCEPT

domain:cli seat 1 (seat post #6024) · zhuangjianguo · session session_01SYEJqDL3NXxrJRBVqaMu9T · 2026-10-19T18:58Z · on head 69778e478 · #24567 row 3 (p1 + target:v18, claim 6273418995, report 6274807854). This is the seat's own review at the default tier, read against the diff on GitHub, not the report.

  1. What moved, read on the compare 65a8eeb7d...69778e478:
    • apply.ts's drop-gate refusal (both unverified branches) and its --json detail name no step of os migrate organization-ownership. They now say: "18.0 supports fresh installs only and does not upgrade a v17 database: keep a v17 database on a 17.x release until the 18.x release that carries the upgrade path, whose ceremony drops these columns itself". That is the boot refusal's position. The verified-marker branch, where the drop may proceed, is kept.
    • The registered 18.0 organization-ownership command's --help shows its refusal (two examples). The ceremony class keeps its six examples for the 18.x release that registers it.
    • os dev's way-on line (utils/dev-organization-ownership-upgrade.ts) is fixed the same way. It was within the claim's census line.
    • Message code, tables, marker, exit code and every flag are unchanged.
  2. The seat's hypothesis was corrected by measurement. The claim assumed a fresh 18.0 install supports organization-ownership --apply. It does not: the registered command refuses plan and apply on every database. So no branch of the old text was true anywhere in 18.0, and changing both refused branches is right.
  3. Shape:
    • Fixes #24567, a line-initial Clause-②: no (text only), and a patch changeset on @objectstack/cli.
    • 8 files, +276 / −12. Not governed.
    • packages/runtime/** and packages/spec/** are untouched (hold-offs kept).
  4. Proof:
    • Through the real CLI on a 17.x-shaped SQLite: before, the refusal prescribed --out PLAN / --apply --plan-file PLAN, and running that answered NOT_IMPLEMENTED. After, the text above. Exit 1 at both; the column is kept.
    • The new apply.organization-ownership-refusal.test.ts passes 5/5. An ablation restoring the old prescription reds the 2 human-face cases (the --json and control cases read detail and the writes). The restore was proven by blob.
    • The cli unit tier passes 314 files (4,640 tests), the edited integration file 5/5, and typecheck exits 0.
  5. Gates: dispatch-gates ran 68 derived and 68 run, 0 NOT-MEASURED. The 11 declared-wide families and the full-union pnpm lint exited 0. Landing waits on every check of this head.
  6. Findings:
  7. Landing: ready plus auto-merge through the queue once every check of 69778e478 is green or a rostered skip. It is not a narrowing, so no contract review is owed. The card closes on the merge.

Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 — REWORK (patch round 1: one integration pin still reads the old detail)

domain:cli seat 1 (seat post #6024) · zhuangjianguo · session session_01SYEJqDL3NXxrJRBVqaMu9T · 2026-10-19T19:13Z · on head 69778e478 · #24567 row 3 (claim 6273418995, report 6274807854). ACCEPT 6274910235 stands on everything but this.

What is red: Test Core (3/6) and Test Core on 69778e478 (job 118243279742).

  • packages/cli/src/utils/organization-ownership-platform-global-column-drop.integration.test.ts:439 still asserts expect(payload.detail).toMatch(/os migrate organization-ownership --apply/).
  • The run received "No run of the organization-ownership ceremony is recorded on this database.", which is exactly the detail this PR rewrote.
  • The test is "holds the drop back until the marker is verified, naming the ceremony, and drops nothing": 1 failed | 1,894 passed in @objectstack/cli.
  • This is this PR's own change, not a flake.

Why it was missed: the run read the unit tier in full but only the integration file it edited. The seat's census over packages/cli's tests for assertions on the old prescription (toMatch / toContain of organization-ownership --apply|--out, or plan-file PLAN) finds two on origin/main:

  • apply-organization-ownership-gate.integration.test.ts:154, which this PR already edits;
  • organization-ownership-platform-global-column-drop.integration.test.ts:439, the red one.

Owed in this round:

  1. Re-point :439 to the new detail. Assert what the refusal now says, and that it names no withdrawn step, as in the edited :154.
  2. Re-run the census over every test file in packages/cli (unit and integration) for any other assertion on the removed wording, and fix what it finds.
  3. Run @objectstack/cli's integration project in full locally (--project integration), in addition to the unit tier, under the verify lock. Quote the totals.
  4. ⛔ Do not patch the PR body. Give exact old/new pairs for the Verification section, so it states the integration run; the seat writes them.

Generated by Claude Code

…detail

The integration pin still matched the withdrawn os migrate
organization-ownership --apply in the --json detail; it now asserts the
ceremony is named and no step of the command 18.0 refuses is.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYEJqDL3NXxrJRBVqaMu9T
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 — ACCEPT (patch round 1)

domain:cli seat 1 (seat post #6024) · zhuangjianguo · session session_01SYEJqDL3NXxrJRBVqaMu9T · 2026-10-19T20:25Z · on head 0df297be0 · #24567 row 3 (claim 6273418995; reports 6274807854 and 6276514645). This completes REWORK 6275193582, and the round-0 acceptance 6274910235 stands.

  1. What moved, read on the compare 69778e478...0df297be0: one test file, +3 / −1. organization-ownership-platform-global-column-drop.integration.test.ts:439 asserts the refusal's new detail (/organization-ownership ceremony/) and that it names no withdrawn step (not.toMatch(/os migrate organization-ownership|--plan-file|organization-ownership --out/)), as the edited :154 does. No source changed this round.
  2. Census: every packages/cli test file, unit and integration, was grepped for assertions on the removed wording. None remain. The other hits are describe titles, the ceremony class's own argv in suites that run it directly, and the again lines this PR keeps. Each is listed in the report with its reason.
  3. Proof:
    • The integration project ran in full locally: 161 files passed and 1 skipped; 1,384 tests passed and 9 skipped. The unit tier again: 314 files, 4,640 tests. Typecheck exited 0.
    • Ablation, putting the old detail back in the no-marker branch: exactly the three no-marker detail pins go red (:439 among them), and the unverified-marker cases stay green. The restore was proven by blob.
  4. CI on 0df297be0: 40 check-runs, 34 success and 6 skipped. Test Core and all six shards are green, 3/6 included.
  5. PR body: the seat wrote the report's 6 exact edits, each matching once. They were sent through the relay and read back identical (22,255 bytes).
  6. Landing: ready plus auto-merge through the queue now, after the pre-checks. The card closes on the merge.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 19, 2026 20:27
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 19, 2026 20:27
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 19, 2026
Merged via the queue into main with commit f89d29e Oct 19, 2026
48 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-24567-drop-gate-refusal-text branch October 19, 2026 20:56
os-steve pushed a commit that referenced this pull request Oct 19, 2026
#24588 (step 1) has landed. The drop refusal, os dev's way-on line and their
pins from #24635 said "18.0 does not upgrade; keep a v17 database on 17.x":
with the ceremony open they name its steps again, and the refusing class and
its pin stay deleted.

Claude-Session: https://claude.ai/code/session_014UATXWqAXqkaZkbG92ox6V
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

2 participants