Repository navigation
QA run · upgrade:ceremony (9/9) · 307ce4c4 · 2026-10-20 · 6 PASS / 3 PARTIAL / 0 FAIL / 0 BLOCKED / 0 NOT-RUN #24838
Description
QA run record — 18.0 round-4 supplementary sweep, the #24681 targeted pass (18.x steps 5 and 6, the upgrade ceremony opened), record 2 of 3: the upgrade path, driven by hand, server side only. Framework 307ce4c4. Maintainer-approved (dispatch session session_01CfRDy7SuTfUqaTu2AEH2Hi, 2026-10-20). Wave anchor: #24579. Previous round: round 3 at 580fd4ed (records #24779 #24786 #24787 #24783). Sister records of this pass: tier1:24681-touched and t2:24681-touched (linked in the close-out comment).
Environment fingerprint
- Framework:
307ce4c4b42503347d7f85825f572e4ca058b05f(pinned, detached; no pull). No console build (pnpm objectui:buildnot run): every console leg isnot-run (console not built);/_console/answers 503 ConsoleNotBuilt. - Container: cold tree.
pnpm install --frozen-lockfile(21 s),pnpm build --concurrency=2(76/76 tasks, 7m29s),node scripts/check-dev-prereqs.mjsgreen (70 artifacts). - 18.0 code: two linked worktrees outside the main checkout, never a switch of the main checkout's sha:
/home/user/os-next5at820fd5aef0(the@objectstack/cli@18.0.0-next.5tag commit),pnpm install+turbo run build --filter=@objectstack/dogfood --filter=@objectstack/cli --filter=@objectstack/example-showcase --concurrency=2;/home/user/os-next3at2c9bf9430a(18.0.0-next.3), same, plus@objectstack/organizations.
- Boots:
os serve(production:OS_DATABASE_URL, ownOS_AUTH_SECRET, 64-hexOS_SECRET_KEY),os serve --dev,os dev,os start, each started withsetsidand stopped by the listener's process group; ports 41851–41858; never more than 2 servers alive. Every DB a file under/tmp/qa4/(SQLite), or a local PostgreSQL 16.15 cluster this run started (qa4_n5,qa4_fresh). - Scratch apps: copies of
examples/app-showcase(HEAD and next.5) for every leg that writes into the app directory; walled legs use scratch copies whose ownpackage.jsondeclares@objectstack/organizationsand whosenode_moduleslinks it (RUNNER "A walled boot is a fixture of its own"). - Readers: row-level SQLite snapshots through
node:sqlite(WAL included), diffed table by table over the columns the earlier snapshot held;sha256sumonly afterPRAGMA wal_checkpoint(TRUNCATE). - Runner: one parent session (this record). Independent verifier subagent for RULE 7 on the P0-adjacent finding (below).
- Timestamps (UTC, 2026-10-20): env prep 08:03–08:13; 18.0 worktrees 08:10–08:57 (in parallel); upgrade matrix 08:13–09:20; off-clause probes 08:49–09:15 (about 30 min of the run, below); core-item clauses 09:17–09:30.
Scope
Selector upgrade:ceremony (a maintainer-named target, not a resolver selector). Judged: the 9 core items the dispatch names, each at its current revision (resolver: node scripts/checklist-select.mjs ID --json at 307ce4c4):
| item | rev | priority |
|---|---|---|
| cli.organization-ownership-ceremony | 3 | P0 |
| platform-core.v18-boot-refusals | 5 | P0 |
| cli.dev-boot-contract | 5 | P0 |
| platform-core.boot-health | 7 | P0 |
| platform-core.seed-integrity | 3 | P0 |
| cli.migrate-plan-apply-json | 6 | P1 |
| platform-core.protocol-18-handshake-and-stored-replay | 1 | P1 |
| platform-core.settings-audit-secret-fingerprint | 3 | P1 |
| identity-auth.self-service-password-reset | 3 | P1 |
Upgrade behaviour no clause names is in "Upgrade matrix" and "Off-clause probes". No item here is planned.
Result
6 PASS / 3 PARTIAL / 0 FAIL / 0 BLOCKED / 0 NOT-RUN of 9. No clause failed. Three product defects were met beside the clauses and extracted (#24827, #24833, #24835); one open card still reproduces (#24638).
Per-clause verdicts (aN = acceptance[N], nN = negative[N])
cli.organization-ownership-ceremony (rev 3) — PASS
- a0 pass — pins (test oracle): 9 files, 200/200 passed at
307ce4c4(organization-ownership.apply-flags,organization-ownership-apply,.occupancy.integration,.dialect,apply-organization-ownership-gate.integration,comment-reactions.integration,organization-ownership-host-supplement.integration,organization-ownership-apply.generation-1, runtimeorganization-ownership-boot-guard). - a1 pass — v17-trait copy (cell c): bare plan exit 0, plan file
kind organization-ownership-plan,ceremony ADR-0131 D10,inventoryDigest 1a9300d9…; sha256 before = after (6ee65d3a…, WAL checkpointed);--applywithout--plan-file→ exit 1 "Refused: --apply executes only a plan you reviewed…",--json{error:"apply_refused", detail:"pass --plan-file with the plan file you reviewed"}. - a2 pass —
--apply --plan-file PLAN --backup-taken --out … --jsonexit 0,complete true,blocking 0, all 13 stepsdone; marker row verified,details.checkpoint.shapeGeneration 1. Same on the next.5, next.3, fixture, PostgreSQL and turso legs. - a3 pass —
os serveover the unmigrated v17 copy: exit 1, never listening, refusal namesos migrate organization-ownershipand both steps, 0 hits for "17.x release"; the migrated copy boots (health 200). The code ORGANIZATION_OWNERSHIP_MIGRATION_REQUIRED is not printed byos serve(its message only) — the code is asserted by the a0 pins. - a4 pass — fresh unmigrated v17 copy:
os migrate apply --allow-destructive --yes --jsonexit 1,message refused_organization_ownership_unmigrated,tables [sys_flow_credential, sys_metadata, sys_secret],detail "No run of the organization-ownership ceremony is recorded on this database.",applied []; sha25629b61638…before = after; row diff 0. - n0 pass — every refusing arm (apply without plan file / without --backup-taken / missing plan file / plan for another DB / drop gate) and every plan run left 0 rows changed.
- Also run (step 5):
os migrate comment-reactions --applywithout--yes→ exit 1 (confirmation); with--yestwice → exit 0 both times, 0 converted, verified.
platform-core.v18-boot-refusals (rev 5) — PASS
- a0 pass — pins: 3 files, 35/35 passed (
organization-ownership-boot-guard.test.ts,.kernel.test.ts, plugin-securityauthz-identity-objects-boot-refusal.test.ts). - a1 pass —
OS_DATABASE_URL=file:COPY os serveover the v17-trait copy: exit 1 before any listening line; printed refusal opens "This database carries no organization-ownership marker", namessys_flow_credential, sys_metadata, sys_secret, containsos migrate organization-ownership --out PLANand--apply --plan-file PLAN --backup-taken; "17.x release" 0 hits, "fresh installs only" 0 hits. - a2 pass — row-level diff over the refused boot: 0 rows added/deleted/changed in every pre-existing table, 11 tables created by the boot, all empty;
sys_migrationholds noadr-0131-organization-ownershiprow. - a3 pass (pin) — the auth-less security rig was not booted; the clause rests on
authz-identity-objects-boot-refusal.test.ts(in a0's run), as the clause allows. - n0 pass — no v18 boot served or half-migrated any v17 or 18.0 database in this run (14 refused boots, each diffed or marker-checked).
cli.dev-boot-contract (rev 5) — PARTIAL
- a0 partial — health 200 after 11 s,
GET /api/v1/ready200; the console half is not-run (console not built:/_console/503 ConsoleNotBuilt). - a1 pass —
--seed-adminadmin signs in 200; restart on the same DB with--admin-password changed99: original password 200,changed99401. - a2 pass — Database line per variant: nothing chosen →
file:CWD/.objectstack/data/objectstack.db;-d :memory:→:memory:;OS_DATABASE_URL=file:…/env.db→ that file; legacy.objectstack/data/dev.dbwith no objectstack.db →file:…/dev.dbplus "⚠ Reading legacy database file …/dev.db — dev, start and migrate now share one default, …/objectstack.db; migrate with: mv …". The config-declared-default-datasource tier was not staged. - a3 pass —
--fresh: "🧪 Fresh OS_HOME: /tmp/objectstack-dev-EwiT2h", Database…/objectstack-dev-EwiT2h/data/objectstack.db; SIGINT → exit 130; the directory is gone afterwards. - a4 pass — instance B on the busy port: "↪ server bound to port 41859 (requested 41858)".
- a5 pass — after touching a source file,
--no-compileboot: "⚠ dist/objectstack.json is OLDER than your sources — this boot serves the STALE build. newest source: src/automation/webhooks/index.ts … fix: runobjectstack buildor start with--compile…"; the server still came up. - a6 pass —
os devin a directory with no config: exit 1, "Run in a directory with objectstack.config.ts, pass --artifact PATH-OR-URL, or run from the monorepo root." - n0 pass — the nothing-chosen DB is the persistent project file (restart kept the admin).
- n1 pass —
--database-driver memory→ INVOCATION ERROR (allowlist), exit 2;OS_DATABASE_DRIVER=mingo→ exit 1, 0 Database lines printed;-d memory://x→ exit 1 after the Database line, "An OS_DATABASE_URL with the "memory://" scheme selects the in-memory (mingo) engine, which is no longer a boot store …". - n2 pass — legacy dev.db read with the notice; no objectstack.db created beside it.
- n3 pass — see a4.
platform-core.boot-health (rev 7) — PARTIAL
- a0 pass — fresh
os dev --ui --seed-admin -d file:…health 200 after 11 s. - a1 pass —
/api/v1/ready200. - a2 pass — boot log to health: 0 ERROR lines; Flows banner
32 flow(s) 19 bound … · 8 draftwith only the two "disabled by deployment policy" ℹ lines (time_relative, schedule). - a3 partial —
GET /api/v1/meta/app?id=showcase_appreturns 1 item with the merged nav; the/_console/half is not-run (console not built, 503). - a4 pass — every grp_data objectName in
src/ui/apps/index.tsappears in the served nav (0 missing). - n0 pass — no SeedLoader rejection;
Seeds: com.example.showcase 132 rows(plain). - n1 pass — no ERROR in the boot window. (On the
os devauto-upgrade path the refused child prints an ERROR line with a stack before the upgrade — os dev's in-place upgrade says every refused database is "still in the v17 organization-ownership shape", after an ERROR-level stack dump of the boot refusal — an 18.0 pre-release database (and a database HEAD itself created) is told it is v17 #24833; that path is not this item's boot.)
platform-core.seed-integrity (rev 3) — PASS
- a0–a4 pass on the fresh stock boot (judged in the sister record
t2:24681-touched: 19 objects, 0 count mismatches against the artifact's 132 rows; Specimen — Full values verbatim; banner plain; restart{"inserted":0,"updated":0,"skipped":132,"errored":0}; f_user/f_users/f_secret/task.cover null as documented). - Upgrade angle (this record): every upgraded boot printed
Seeds: com.example.showcase 132 rows; across the ceremony the row diffs show no seeded row deleted or changed (next.5, next.3, fixture, PostgreSQL legs). - n0, n1 pass — no zero counts; no growth on restart.
cli.migrate-plan-apply-json (rev 6) — PASS (scratch app, NODE_ENV=development, -d file:/tmp/qa4/dbc/migrate.db)
- a0 pass — a field added +
os build; two bareos migrateruns print the identical plan+ showcase_task [add_columns: qa4_extra]; the column is absent afterwards. - a1 pass —
os migrate plan --jsonexit 0, keysdatabase, databaseSource, telemetryDatabase, managedTables, total, changes, pending, unmanagedTables, composition, duration. - a2 pass —
--jsonexit 0 for plan, apply, recorded-by and resume; pinformat.exit-code.test.ts4/4. - a3 pass — field removed + build:
apply --yeslists✗ showcase_task.qa4_extra [drop_column]under "Destructive (requires --allow-destructive)", column kept;--allow-destructive --yesdrops it. - a4 pass — post-apply plan: "No drift over the 107 object(s) this plan examined — but 2 of 109 declared object(s) were NOT examined … PARTIAL plan"; JSON re-apply
message in_sync_partial,composition.coverage {registeredObjects:109, examinedObjects:107, unexaminedObjects:2, reasons.federated:2}, exit 0. - a5 pass — with
os devholding the DB:apply --yesexit 1 "✗ …/migrate.db is in use — it is open in pid … (node)";planexit 0 with "⚠ … is in use … The plan below is still accurate". - a6 pass —
apply --jsonwithout--yes:message confirmation_required,hint pass --yes, exit 0; the column is still absent and the next plan still lists it. - n0, n1 pass.
platform-core.protocol-18-handshake-and-stored-replay (rev 1) — PARTIAL
- a0 pass — pins: 5 files, 98/98 passed.
- a1 pass — judged in the sister record
t2:24681-touched(platform-core.manifest-install-contract, same sha):^17→ 422OS_PROTOCOL_INCOMPATIBLE,migrateCommand "objectstack migrate meta --from 17";^18→ 201. - a2 not-run — no planted v17-shaped page row was built this round.
- a3 not-run — no pre-retirement
^18artifact was booted withos start.
platform-core.settings-audit-secret-fingerprint (rev 3) — PASS (on the next.5 database after the ceremony, os serve --dev)
- a0 pass — three writes of
mail.api_key(V1, V2, V1; fresh random values): per-key ledgersys_platform_setting_audit.new_hash=hmac-sha256:+ 64 hex;sys_audit_logconfig_changenew_value.digest= the encrypted marker (the word encrypted, a colon, then that same keyed digest, inside angle brackets),object_name sys_platform_setting,metadata.encrypted true. - a1 pass — offline unkeyed digests of V1 (fnv32 of the canonical JSON, sha256 with and without prefix): 0 hits in either ledger; positive control:
mail.from_email's row carriesfnv32:6d1d9810, which equals the offline fnv32 of"ops@example.com". - a2 pass — writes 1 and 3 carry the same keyed digest (
9630eb01…), write 2 a different one (a29c5388…). - a3 pass —
POST /api/settings/mail/reset200 → reset rows withnew_hash null; config_changenew_value null. - a4 pass — see the a1 control.
- a5 pass (pin) —
settings-audit-secret-digest.test.ts7/7 in the Tier 1 run. - n0–n3 pass — no unkeyed digest, no plaintext, no refused write. n4 — the positive control was run.
- Upgrade angle: after the ceremony 0 global-scope rows remain in
sys_setting_audit; the 7 moved global rows are byte-identical insys_platform_setting_audit.
identity-auth.self-service-password-reset (rev 3) — PASS (on the next.5 database after the ceremony)
- a0 pass —
POST /api/v1/auth/request-password-reset200{"status":true,"message":"If this email exists in our system, check your email for the reset link"}; the mail row lands insys_identity_email(4 → 5 rows), none insys_email; body carriesreset-password/TOKEN. - a1 pass — reset 200, the new password signs in 200, the previous one 401.
- a2 pass — the same token again → 400.
- a3 pass — a garbage token → 400, the credential unchanged.
- a4 pass — an unknown address answers the identical 200 body.
- n0 pass. n1 pass — reuse leg: 400 (above); expiry leg (09:38, same database): a fresh token's
sys_verification.expires_atset one hour into the past (simulated clock) →POST /auth/reset-password400{"message":"Invalid token","code":"INVALID_TOKEN"}, the current password still signs in 200, the attempted one 401. n2, n3 pass. - Upgrade angle: the reset mail an 18.0.0-next.5 install sent before the upgrade (moved by
sibling-moveswith its id) still works — its token reset the password (200{"status":true}) and the new password signed in.
Upgrade matrix
a. Fresh install (HEAD, empty SQLite file)
os serve(production): "[organization-ownership] a datastore created from empty: birth marker written (shape generation 1, platform 18.0.0-next.5)"; ready; restart on the same DB ready. Marker: verified,details.birth {shapeGeneration:1, platformVersion:"18.0.0-next.5", createdAt}. A first boot that failed after the marker write (an invalidOS_SECRET_KEYof this run's own making) left the marker, and the next boot served.os dev --seed-admin: marker in the DB (the line is INFO; the warn-level dev log does not print it); restart ready.os start -d … --home …: birth line, ready; restart ready.- First command
os migrate apply --yes: exit 0, 71 tables created,sys_migration0 rows; the firstos serveis REFUSED, exit 1, "This database carries no organization-ownership marker: 17.x or an 18.0 pre-release (18.0.0-next.*) created it …". Reproduced twice. → os migrate apply on an empty database writes no organization-ownership birth marker, so the fresh install's first os serve is refused as a 17.x / 18.0 pre-release database #24827 (verified by an independent agent, RULE 7: CONFIRMED).os devover such a DB is refused, then auto-runs the ceremony and serves, calling the DB "still in the v17 organization-ownership shape" (os dev's in-place upgrade says every refused database is "still in the v17 organization-ownership shape", after an ERROR-level stack dump of the boot refusal — an 18.0 pre-release database (and a database HEAD itself created) is told it is v17 #24833). - First command
os seed: there is no such command (os seed --help→ "Command seed not found.");os migrate planfirst is harmless by code reading (it never flushes DDL), not booted.
b. Real 18.0 databases
- Generator:
node scripts/gen-upgrade-harness-fixture.mjs --ref …does not run against either published pre-release (fixture gap below), so the 18.0 databases were made by the pre-releases themselves: each release's ownos dev --seed-adminover a fresh file, then used through its HTTP doors (member invited and signed up, a second member by admin create-user, password reset, change-email, verification resend, two org invitations, globalmailsettings twice, tenantbranding, the declared webhook activated, admin and member tasks, an admin sharing rule). - next.5 (
820fd5aef0), with planted rows the release cannot produce throughos serve(a magic-link mail — 18.0os servehard-codes its auth plugins withoutmagicLink— and five mail jobs): HEADos serve --devexit 1, absent-marker sentence namingsys_flow_credential, sys_secret; refused boot wrote 0 rows, no marker. Plan exit 0 (row diff 0). Apply exit 0, complete true, blocking 0; sibling-moves moved 11 (reset, two verification mails, the magic link; 7 global audit rows), jobsRewritten 3, activityRepointed 13; declared-webhooks mirrorsDeleted 1, activationRows 1; column-drops 2; not-null 62/63 (1 rotation shard unsupported). Data: moved rows byte-identical over the shared columns (mail 4/0 diffs, audit 7/0); both org invitations stay insys_email; the pendingemail.send.async(reset, magic link) and runningemail.attachment.reclaim(verification) jobs carryobject sys_identity_emailin payload and metadata and the respelled idempotency key; the completed job and the org-invitation job untouched; no other row changed (NOT NULL lost none). HEAD boot: admin, member A (18.0 password), member B sign in 200, wrong password 401; A reads its own task;sys_webhookempty; one task PATCH → exactly onesys_http_deliverywithref_id declared:showcase_task_changed; the re-pointed send jobs completed without error. - next.3 (
2c9bf9430a), no plants: same shape; attribution 39 (next.3 wrote tenant setting-audit rows and anadmin_full_accessgrant with NULL organization — single org, all to the one org), sibling-moves 10, mirror-deletion 2 (the two package sharing-rule mirrors; the admin ruleqa4_red_projectskept), column-drops 2, not-null 62/63; HEAD boot and the same data checks pass. - Declared-webhook deliveries: a real next.5 database holds none — on 18.0.0-next.5 the org-less declared webhook refuses to fan out an organization's event ("belongs to NO organization … refusing to fan out"). The delivery re-source was therefore measured on the committed harness fixture (main
5b14b7f3data), production composition: deliveriesResourced 2 (ref_id whk_… → declared:showcase_task_changed), and HEAD's outbox picked both up under the declaration (attempts 3;hooks.exampleis unreachable here).
c. v17 shape (R3: sys_metadata.organization_id added to the next.5 database) — refused (names sys_metadata among the three tables), drop gate holds, plan changes nothing, apply complete, sys_metadata.organization_id dropped, boot 200 (clause evidence above).
d. Developer's local database (scratch app directory; next.5 os dev with nothing chosen created .objectstack/data/objectstack.db; then the app's code swapped to HEAD, .objectstack/ kept)
- HEAD
os dev(nothing chosen) upgraded it in place and served (health 200 after 27 s): backup at.objectstack/data/backups/organization-ownership-TIMESTAMP/holding both databases, plan, report and ceremony log; admin, members (18.0 passwords), own data, mail moves and the webhook all check out. - What the developer reads, in order: two
[schema-drift] sys_secret.organization_id / sys_flow_credential.organization_id … "os migrate apply --allow-destructive" to drop itlines ([Decision] An 18.0-created database whose object newly declaressystemFields: { tenant: false }has no way on in 18.0 — the drift report prescribes--allow-destructive, the drop gate refuses it, and the ceremony is refused #24638, still reproduces); an ERROR line with the refusal's stack; "⟳ This development database is still in the v17 organization-ownership shape — upgrading it in place (a copy is kept first)…" (os dev's in-place upgrade says every refused database is "still in the v17 organization-ownership shape", after an ERROR-level stack dump of the boot refusal — an 18.0 pre-release database (and a database HEAD itself created) is told it is v17 #24833); "✓ Upgraded … copied to …"; "✓ server started on the upgraded database". The outcome is right; the account of it is wrong in two places.
e. Walled (isolated and group)
- HEAD fresh walled boot (scratch app declaring the runtime): Tenancy isolated, Organizations mounted, birth marker written.
- 18.0 walled database: 18.0.0-next.3 (it predates next.5's walled-boot refusal) under
OS_TENANCY_POSTURE=isolatedwithOS_PLATFORM_OWNER_EMAILandOS_AUTH_MEMBERSHIP_POLICY=invite-only; two organizations (/auth/organization/create), one member each (admin create-user → change-password → invite → accept), per org an admin task, a member task, an unaccepted invitation, a branding setting, a password reset and an admin sharing rule. next.3 wrote every tenant setting-audit row with organization_id NULL. - isolated: refused; plan posture isolated, 3 organizations, unattributable
sys_setting_audit3 ("no anchor names the owner"); apply exit 1, complete true, blocking 3, held with the remedy "assign each row its organization … or delete it by hand, then re-run --apply; the ceremony never guesses an owner and never deletes such a row". After the operator's assignment (this run matched each row'snew_hashto its organization's current setting value) the re-apply certified (blocking 0). HEAD boot: Alice (org A) and Bob (org B) sign in with their 18.0 passwords; each sees exactly its own organization's two QA4 tasks (foreign rows 0); the other organization's task → 404; own task 200; members → 403 onsys_identity_emailandsys_email. Whole-DB row diff: organization_id null→value 3 (exactly the operator's), value→another organization 0. - group: identical outcome (3 held, assigned, certified, same isolation results, 0 rows moved across organizations).
os devover the unassigned walled DB: prints the held table and "✗ Every step finished, and the post-check found 3 row(s) left … not certified … Resolve them, then runos migrate organization-ownership --dev --apply --plan-file … --backup-taken— or restore the copy", exit 1, nothing listening.- No cross-organization mismatch was found.
Off-clause probes
About 30 minutes of the run (08:49–09:15 plus the PostgreSQL leg).
- Kill mid-apply, then re-run. SIGKILL at 3.5 / 4.3 / 4.8 / 5.0 / 5.1 / 5.3 s into
--applyon the planted next.5 database. Up to 4.8 s no checkpoint existed and the boot refused with the absent-marker sentence; from 5.0 s an unverified checkpoint existed and the boot refused with "The organization-ownership ceremony has not finished on this database … not verified". In every case re-running--applywith the same plan completed (blocking 0), with 0 mail ids lost, 0 duplicated, jobs re-pointed once, and the next boot served. No kill landed inside sibling-moves (under 0.2 s on this DB); simulated instead — a reset row copied intosys_identity_emailand not deleted — the re-run reported moved 10, alreadyMoved 1, one copy, nothing left behind. Neither a half-upgraded servable database nor data loss was found. - Re-run on a certified database. Plan and apply exit 0, every step
checkpointed, row diff 0 apart from the marker's timestamps — a no-op. On a birth-marker database every step runsdonewith row diff 0, and the marker'sdetails.birthis replaced by a checkpoint (observation below). - Lower shape generation (F5). Simulated (generation removed / set to 0 on a certified marker) and real: 18.0.0-next.3 ships an open generation-0 ceremony; its own plan/apply certified the next.3 database without
shapeGeneration; HEAD then refused it, exit 1: "This database was certified by an organization-ownership ceremony of shape generation 0, and this release requires generation 1: the ceremony steps added since have not run on it. sys_flow_credential, sys_secret still carry …". HEAD's ceremony then re-ran every step (sibling-moves 10, mirror-deletion 2, column-drops 2, not-null 62/63), certified, and the data checks pass. - Telemetry sibling. A fresh primary next to a leftover 18.0 telemetry sibling (113 audit rows) was born and served; an old primary with no sibling was still refused and got no marker. Holds both ways.
- driver-sql vs driver-turso. PostgreSQL 16.15 (SqlDriver(pg), local): next.5 database on PG → refused → ceremony complete (not-null 63/63, 0 unsupported — SQLite reports 1 unsupported rotation shard) → boot and data checks pass; but the declared webhook never enqueues on PostgreSQL, fresh install included → On PostgreSQL every webhook delivery is dropped at enqueue — "[webhook-auto-enqueuer] enqueue failed … Converting circular structure to JSON (Timeout)" — and the loss is logged at WARN #24835. driver-turso (TursoDriver(libsql), local file): fresh boot born and restarted; the next.5 file under the turso driver refused → ceremony complete (not-null 62/63) → boot and data checks pass; activityRepointed 0 there because the turso composition mounts no telemetry sibling while this file's activity rows live in the SQLite composition's sibling (mixed fixture). Turso remote face, MySQL, MongoDB: blocked(fixture) — none provisioned.
- Exit codes and
--json.os serverefusal exit 1 (no--jsonon serve). Ceremony--json: plan exit 0, stdout one JSON value{file, plan}; every refusal exit 1 with stdout one JSON value{error:"apply_refused", reason, detail[, file, reviewed, current]}— no plan file, missing plan file, no--backup-taken, a plan computed for another database ("…was computed for the database …/n3.db, and this run opened …/n5.db. Nothing was written."); held rows exit 1 with the report. Drop gate--jsonexit 1{message:"refused_organization_ownership_unmigrated", tables, detail, marker}.os devwith held rows exit 1, nothing listening. These match PR feat(cli,runtime)!: the upgrade ceremony opens — v17 and 18.0 databases take it, and a server serves only a database it created or one the ceremony certified (18.x steps 5 and 6) #24681's stated shapes.
Defects extracted (reproduction rules in each card)
- os migrate apply on an empty database writes no organization-ownership birth marker, so the fresh install's first os serve is refused as a 17.x / 18.0 pre-release database #24827 —
os migrate apply --yeson an empty database writes no birth marker; the firstos serverefuses the fresh install as a 17.x / 18.0 pre-release database. Repro:os migrate apply --yes --database-url file:NEW.db(exit 0, 71 tables,sys_migration0 rows) →OS_DATABASE_URL=file:NEW.db os serve→ exit 1, absent-marker sentence; expected: served. Reproduced twice; RULE 7 verifier CONFIRMED from the evidence and the code (deferred-DDL boot reports 0 tables created; nothing records the birth afterflushSchemaDdl()). Path platform-core.v18-boot-refusals, P0 item, observed beside the clauses. - os dev's in-place upgrade says every refused database is "still in the v17 organization-ownership shape", after an ERROR-level stack dump of the boot refusal — an 18.0 pre-release database (and a database HEAD itself created) is told it is v17 #24833 —
os dev's in-place upgrade prints "still in the v17 organization-ownership shape" for every refused database (18.0 pre-release ones and HEAD-created ones included), after an ERROR-level stack dump of the refusal it handles. Repro in matrix cell d. Path cli.dev-boot-contract, observed beside the clauses. - On PostgreSQL every webhook delivery is dropped at enqueue — "[webhook-auto-enqueuer] enqueue failed … Converting circular structure to JSON (Timeout)" — and the loss is logged at WARN #24835 — On PostgreSQL every webhook delivery is dropped at enqueue ("[webhook-auto-enqueuer] enqueue failed … Converting circular structure to JSON (Timeout)"), logged at WARN. Repro:
os dev -d postgres://…/fresh→POST /api/v1/security/_activation/webhook/showcase_task_changed {"enabled":true}200 →PATCH /api/v1/data/showcase_task/ID200 →sys_http_delivery0 rows (SQLite: 1). Reproduced on a fresh and an upgraded PG database. Path integration-system.webhook-lifecycle, observed beside the clauses. - Still reproduces: [Decision] An 18.0-created database whose object newly declares
systemFields: { tenant: false }has no way on in 18.0 — the drift report prescribes--allow-destructive, the drop gate refuses it, and the ceremony is refused #24638 (the[schema-drift]line prescribes--allow-destructivefor a ceremony-ownedorganization_id, printed on everyos devover an 18.0 database).
Observations (no declared contract violated; not filed)
- The ceremony on a birth-marker database replaces
details.birth(platformVersion, createdAt) with a checkpoint; the boot is unaffected, the birth provenance is lost. - The birth marker records
platformVersion 18.0.0-next.5for HEAD code (the package versions are not yet bumped); the guard decides on the shape generation alone, so nothing reads it. - Every 18.0.0-next.3 walled install that changed a tenant setting holds certification on those audit rows, and the operator's only clue for assigning each is the hash of the current setting value (history rows of a value changed since cannot be matched). Designed — the ceremony never guesses — but it will reach every such operator.
- On a walled upgrade, mirror-deletion deletes the organization-less
sys_activityrows (35 here), announced in the plan's warning ("the change itself stays in sys_audit_log"). - Under the turso driver over a file made by the SQLite composition, the ceremony does not see the SQLite composition's telemetry sibling (activityRepointed 0).
Checklist-accuracy findings / fixture gaps (for #24579)
Fixture gaps:
scripts/gen-upgrade-harness-fixture.mjscannot generate from either published pre-release: (1) its copy filter!relative(from, src).startsWith('fixture-')dropsfixture-manifest.tsalong withfixture-18.0/, so any ref that predates the harness failsERR_MODULE_NOT_FOUND …/fixture-manifest.js(worked around by copying the file into the checkout's harness path); (2) on next.5 the census then refusessys_http_delivery: empty, because the 18.0.0-next.5 declared webhook never fans out an organization's event. The committed fixture comes from main5b14b7f3, not from a published 18.0 build.- 18.0
os servecannot enablemagicLink(its auth plugin list is hard-coded), so a magic-link identity mail cannot be produced through a stock 18.0 boot; planted by shape here. - No PostgreSQL / MySQL / Turso-remote fixture is named by any upgrade item; the PG leg here used a cluster this run started.
os seed(named by PR feat(cli,runtime)!: the upgrade ceremony opens — v17 and 18.0 databases take it, and a server serves only a database it created or one the ceremony certified (18.x steps 5 and 6) #24681's body) does not exist in this CLI.
Checklist accuracy:
cli.organization-ownership-ceremony/platform-core.v18-boot-refusalsrequire "a v17-shaped DB (npm@objectstack/cli@17.7.0)"; the 18.0-database path (the case feat(cli,runtime)!: the upgrade ceremony opens — v17 and 18.0 databases take it, and a server serves only a database it created or one the ceremony certified (18.x steps 5 and 6) #24681 opened) is in no clause. Candidate clause: an 18.0 pre-release database is refused, takes the ceremony, and keeps its identity mail, audit, webhook and job rows.- No item covers the fresh-install-then-
os migrate applyorder (os migrate apply on an empty database writes no organization-ownership birth marker, so the fresh install's first os serve is refused as a 17.x / 18.0 pre-release database #24827) or the generation-0 marker (F5) live. identity-auth.self-service-password-resetrequires/steps still read the reset mail fromsys_email; it is insys_identity_emailnow.cli.dev-boot-contracta2 names the config-declared default datasource tier; no step stages it.platform-core.boot-healtha3 andcli.dev-boot-contracta0 bundle the console with server probes, so a no-console run can never reach PASS.
Item verdicts (derived)
6 PASS / 3 PARTIAL / 0 FAIL / 0 BLOCKED / 0 NOT-RUN of 9. PARTIAL: cli.dev-boot-contract (a0 console half), platform-core.boot-health (a3 console half), platform-core.protocol-18-handshake-and-stored-replay (a2, a3 not run).
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 20, 2026
Close-out.
Extracted: #24827 · platform-core.v18-boot-refusals · observed beside the clauses
Extracted: #24833 · cli.dev-boot-contract · observed beside the clauses
Extracted: #24835 · integration-system.webhook-lifecycle · observed beside the clauses
Parked-on: #24579 · checklist-accuracy findings and fixture gaps listed in this record (harness generator cannot run on published 18.0 refs; no 18.0-database clause on the ceremony items; magic link unreachable through a stock 18.0 serve; console-bundled clauses)
Still reproduces at 307ce4c, commented on the card: #24638.
Sister records of this pass: #24840 (
tier1:24681-touched), #24841 (t2:24681-touched).Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Closure complete (checklist-test §5): this record has no FAIL. Its three findings beside the clauses are extracted (the
Extracted:lines in comment 6288136271: #24827, #24833, #24835). Its accuracy findings and fixture gaps are parked on #24579 (comment 6288485402).Closed by: the 18.0 QA wave dispatch session
session_01CfRDy7SuTfUqaTu2AEH2Hi, on the maintainer's standing instruction there (2026-10-19, verbatim 「qa-run的卡片处理完的是不是可以关闭」), at 2026-10-20T13:12Z, after 18.0.0 was published.Generated by Claude Code