You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
objectql: the "sys_metadata could NOT be read at boot" ERROR tells the operator to "check the datasource behind sys_metadata" when no datasource is declared and no driver is registered #23636
Filing gate ①, class (a). reach:measured at the public doorobjectstack serve objectstack.config.ts --no-server --preset minimal (production, no storage, boot R10, at 650e28a731). It was also seen on R3, R11 and R20c.
Filed by domain:cli seat 2 (#22648) · sunhaolin · session session_01Q9PZ5Pzqcus4woVvTZwWNU, from #23573's build report (os-dev-report on #23573, PR #23631, head 650e28a731). ⛔ Not a claim. Grade and lane are triage's.
What was measured
objectql prints "ERROR sys_metadata could NOT be read at boot … Fix: check the datasource behind sys_metadata — connection, credentials, and that the table exists — then restart."
No datasource was declared, and no driver is registered.
Triage grades it and routes it. The landing is the hydration ERROR in packages/objectql/src/plugin.ts: when no driver serves sys_metadata, say so, and name the storage remedies rather than a datasource's connection and credentials.
Dedupe words: sys_metadata hydration error remedy no driver; objectql DB hydration skipped no datasource declared; misleading fix datasource behind sys_metadata.
Read fresh. On a production serve with no datasource declared and no driver registered, objectql's hydration ERROR ("sys_metadata could NOT be read at boot … Fix: check the datasource behind sys_metadata — connection, credentials …") points at a datasource nobody declared. This was measured at the public door (#23573's report, boots R3, R10, R11 and R20c).
Claim: PM loop round 5 · 2026-10-15T15:39Z · on the maintainer's 「你不要收班,继续串行派」 and 「p2 p3 都可以派」 (this session); serial, after #23661, whose dev work is done and whose PR #23687 is ACCEPTed and in the merge queue
Session: session_01ADzJtzYTLUfgrRZHxkagkX
Account: os-steve (the seat's linked user as GET /user answers it; always the card's assignee)
Branch: claude/issue-23636-no-storage-hydration-error
Worktree: objectstack-issue-23636
Domain: domain:engine
Seat: domain:engine#2 (seat post #20966)
File surface: packages/objectql/src/plugin.ts, the restoreMetadataFromDb region only (the "sys_metadata could NOT be read at boot" ERROR, about :2163–:2200 at main), plus pins beside the existing hydration tests in packages/objectql and one changeset.
os-dev-report
{
"issue": 23636,
"status": "done",
"branch": "claude/issue-23636-no-storage-hydration-error",
"pr": "#23698",
"session": "session_01ADzJtzYTLUfgrRZHxkagkX (the parent's session; this run is mode:subagent)",
"premise_still_valid": true,
"summary": "The premise holds on fresh main: with no driver and no datasource the boot read of sys_metadata fails ([ObjectQL] No driver available for object 'sys_metadata', measured through the real protocol over a driverless engine) and restoreMetadataFromDb answered with the datasource remedy. It now asks the engine's own routing (getDriverForObject, resolveEffectiveDatasource, listUnavailableDatasources, via a new private sysMetadataHasNoStorage, asked only after the read failed) and, when all three are empty, logs the same error-level line with 'no storage is configured: no datasource is declared and no driver is registered' and the three remedies copied verbatim from the CLI's No storage line, in the CLI's own sentence shape. The datasource arm is byte for byte unchanged for a registered driver whose read failed, a named binding with no driver, and a declared datasource the connection layer marked unavailable; level, counts and the consequence sentence are unchanged. Deviation to disclose: I pushed the branch after the first commit, not as an empty-branch probe before the first edit (the push succeeded, so the write route was never at risk).",
"tests": "All readings at head f273dab (base c9810dd; main has since moved to 3bc407d, which landed #23687 in plugin.ts, and a local merge-tree of the branch with it is clean, so main was not merged per the queue ruling). (1) Pins plus the existing outage pins: pnpm --filter @objectstack/objectql exec vitest run --maxWorkers=2 src/plugin-restore-metadata-no-storage.test.ts src/plugin-restore-metadata-outage.test.ts -> 2 files, 15 passed (6 new, 9 existing, whose assertions are untouched; only makePlugin() now builds a real engine with one registered driver, because the line now consults the engine). The first run had 2 failed, both my own harness: the real-protocol cases need sys_metadata registered, else the read fails earlier on Object 'sys_metadata' not found; fixed in the test. (2) Full package: pnpm --filter @objectstack/objectql test -> 424 files, 8129 tests passed, VERDICT command-exit 0. (3) pnpm --filter @objectstack/objectql typecheck, run after the last test edit -> exit 0 (tsc --noEmit clean; check:test-typecheck OK with the ledger unchanged at 39 files / 233 errors; the new test file is in tsconfig.test.json's program, 1 hit, and not in tsconfig.json's, 0). (4) eslint --no-inline-config on plugin.ts and the two test files -> exit 0. (5) Ablation with scripts/ablation-replace.mjs on packages/objectql/src/plugin.ts (anchor hit once, blob changed, restore verified blob == HEAD and git diff HEAD empty after every leg; the subject is imported from src, so no rebuild or dist leg applies). Verdict forced false -> 2 (a) pins RED, 4 (b) controls green, 9 existing green (2 failed | 13 passed). Verdict forced true -> 4 (b) RED, (a) green, 9 existing green (4 failed | 11 passed). Each probe dropped alone (getDriverForObject / resolveEffectiveDatasource / listUnavailableDatasources) -> 2 / 1 / 1 (b) controls RED, (a) green, new file only. Direction predicted before running; ordinary, no inversion. (6) dispatch-gates --commands 64 + 53 artifact-roster + 11 wide-population = 127 distinct commands, run at f273dab: 123 exit 0 on the first pass. check:dual-build-cjs-loads and check:published-readme-exports exited 3 (prerequisite, no dist) and are exit 0 after a full turbo build (75 tasks); check:type-check-debt exited 124 in my 280 s runner window and is exit 0 on rerun; check-partof-closing-keyword, check-closing-target-claim and check-single-claim-paths exited 2 (need a PR body or PR number) and are exit 0 with the PR body and PR_NUMBER=23698. dispatch-gates --ran with recorded exit codes: 64 derived, 64 run, 0 NOT-MEASURED (derived), 0 UNRUN. NOT MEASURED: node scripts/pm/check-governed-queue-guard.mjs (exit 1, no GITHUB_EVENT_PATH payload to read; the diff touches no governed surface). CI on the PR head at the one read I took: 37 check runs, 14 success, 6 skipped, 17 in_progress (Build Core among them), 0 failed; in_progress is the honest value and I did not wait.",
"mcp_calls": "0 — no MCP GitHub calls; reads were REST GETs through curl",
"api_writes": "2 — both relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): pr_create with assignees os-steve (POST /pulls draft, then POST /issues/23698/assignees; body read back byte-identical, 8696 bytes) and this os-dev-report comment (POST /issues/23636/comments). Plus 1 git push of the branch (not REST). label-write: 0 writes, the dispatch named no labels and the diff publishes (changeset present), so skip-changeset does not apply",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none (承接者:无) · noted, not filed · the three storage remedies are now spelled in two places, packages/cli serve.ts (noStorageRemedies) and packages/objectql plugin.ts (NO_STORAGE_REMEDIES), and nothing pins them equal; sharing one constant crosses into packages/cli, outside this card's surface; drift not yet exercised; in the PR's Acceptance notes",
"carrier: none (承接者:无) · noted, not filed · the remedies name CLI inputs (OS_DATABASE_URL, --dev), so a host that boots a kernel by hand with no driver reads the same three, of which 'mount a storage driver' is the one that applies; in the PR's Acceptance notes"
]
}
the seat's own reading of the full diff against main.
Review (in-seat, the full diff read). The diff is operator text in one function, with no contract surface, so no contract review is owed.
How the arm is chosen.restoreMetadataFromDb's ERROR picks its arm from the engine's own routing, through a new private sysMetadataHasNoStorage(). It asks getDriverForObject, resolveEffectiveDatasource and listUnavailableDatasources, and only after the read has already failed, so a healthy boot pays nothing. It never reads the text of the error.
The new arm. When all three are empty, the line says no storage is configured and names the three remedies. The seat checked them word for word against the CLI's noStorageRemedies (packages/cli/src/commands/serve.ts, about :5144–:5146 at main).
What is unchanged. The datasource arm is unchanged for a registered driver whose read failed, for a named binding with no driver, and for a declared datasource the connection layer marked unavailable. The level stays error, and the consequence sentence is word for word the same.
The pins. 6 new pins sit beside the 9 existing outage pins, whose assertions are untouched. Only the outage harness now builds a real engine with one driver, because the line consults the engine.
The dev's ablation: a forced-false verdict turns the no-storage pins red; a forced-true one turns the controls red; dropping each probe alone turns its own control red. The rest stays green.
Typecheck. It was run after the final test edit, which is the lesson from this seat's previous PR.
Clause-②: no, with a patch changeset.
Landing checks at f273dab8e3:
ci-failure.mjs --pr 23698 is GREEN: 40 of 40 check runs completed, none failed.
The path face is 4 files, none governed. The size is under the threshold.
The body carries Fixes #23636. The closing-target claim guard is green.
Out-of-scope findings:
Acceptance notes: the three remedies are now spelled in two places, packages/cliserve.ts (noStorageRemedies) and packages/objectqlplugin.ts (NO_STORAGE_REMEDIES), and nothing pins them equal. Sharing one constant would cross into packages/cli, outside this card. The drift is not yet exercised.
Acceptance notes: the remedies name CLI inputs (OS_DATABASE_URL, --dev). A host that boots a kernel by hand reads the same three, of which "mount a storage driver" is the one that applies.
Merged by the merge queue as 30c33e3875363bc3f81446f4a3859bfb0bea828a, from head f273dab8e3, on its first queue build: added 2026-10-15T16:50Z, merged 2026-10-15T17:18Z. The queue's removal event in the same second is the merge itself. The ACCEPT is 6197401826. Fixes #23636 closed this card.
Squash verified. The squash's diff against its parent f1e21c4f45 equals the head's diff against their merge-base c9810dd9d1: the same 4 files, and every file's changed lines identical (+319 / −5).
What landed. When no datasource is declared and no driver is registered, the boot hydration ERROR says no storage is configured and names the CLI's three storage remedies. The datasource remedy stays for every case where a datasource exists. The 6 new pins are in place, and the outage pins are unchanged.
Carried. The two Acceptance notes in the ACCEPT, not filed: the remedies are spelled in two places with no pin holding them equal, and the CLI-input wording is read by hand-built hosts. pm:dispatched is removed in the same act.
Activity
objectstack-fleet commentedon Oct 15, 2026
Triage: first grade ·
bug·priority:p3·domain:engine·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-15T09:03ZRead fresh. On a production
servewith no datasource declared and no driver registered, objectql's hydration ERROR ("sys_metadata could NOT be read at boot … Fix: check the datasource behind sys_metadata — connection, credentials …") points at a datasource nobody declared. This was measured at the public door (#23573's report, boots R3, R10, R11 and R20c).priority:p3: operator text with a wrong remedy. PR fix(cli): a production serve with no storage says so before any plugin starts, and refuses when its auth service needs a driver #23631's⚠ No storage:line now precedes it with the real fixes, so the operator is not left without one.domain:engine(packages/objectql/src/plugin.ts, by the lane table).sys_metadata, the ERROR says so and names the storage remedies (the same three PR fix(cli): a production serve with no storage says so before any plugin starts, and refuses when its auth service needs a driver #23631 names). The datasource arm stays for a declared datasource that fails. Pin both shapes.packages/cli.findingleaves on grading.objectstack-fleet commentedon Oct 15, 2026
Claim: PM loop round 5 · 2026-10-15T15:39Z · on the maintainer's 「你不要收班,继续串行派」 and 「p2 p3 都可以派」 (this session); serial, after #23661, whose dev work is done and whose PR #23687 is ACCEPTed and in the merge queue
Session:
session_01ADzJtzYTLUfgrRZHxkagkXAccount:
os-steve(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-23636-no-storage-hydration-errorWorktree:
objectstack-issue-23636Domain:
domain:engineSeat:
domain:engine#2(seat post #20966)File surface:
packages/objectql/src/plugin.ts, therestoreMetadataFromDbregion only (the "sys_metadata could NOT be read at boot" ERROR, about:2163–:2200atmain), plus pins beside the existing hydration tests inpackages/objectqland one changeset.onMetadataMutationcallback, or the bridge'sfollowRuntimeObjectCopymethods (this seat's objectql/mcp: the boot bridge's copy of each runtime object in the metadata service is never updated, so MCP stdio's enforceApiExposure keeps serving an object whose API exposure was turned off after boot, and lists a deleted one, until a restart #23661, PR fix(objectql): keep the metadata service's copy of a runtime-authored object current after boot (MCP stdio exposure gate) #23687).packages/cli: PR fix(cli): a production serve with no storage says so before any plugin starts, and refuses when its auth service needs a driver #23631's⚠ No storage:line is the reference for the remedy wording, not an edit target.Container & model:
S,mode:subagent,model: floor(this run'sdispatch-gates.mjs --tier: "no path-derived mandate … floor · default · ceiling"; operator text in one function plus two pins)Clause-②: no
Responsibility: the wrong remedy text is produced by objectql's
restoreMetadataFromDb. The platform path partly covers it: PR fix(cli): a production serve with no storage says so before any plugin starts, and refuses when its auth service needs a driver #23631's⚠ No storage:line now comes first, with the real fixes. It is reached by a productionservewith no datasource declared and no driver registered, measured at the public door by cli/serve: a productionobjectstack servewith no OS_DATABASE_URL registers no driver in silence, then fails at AuthPlugin.start with "No driver available for object 'sys_organization'" and a remedy naming a datasource nobody declared #23573's report (boots R3, R10, R11 and R20c).Thread-read: 6188460662
Serial constraints cleared: the regions above stay out of scope, and the later lander merges
main. No open PR touchesrestoreMetadataFromDb.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
os-dev-report
{
"issue": 23636,
"status": "done",
"branch": "claude/issue-23636-no-storage-hydration-error",
"pr": "#23698",
"session": "session_01ADzJtzYTLUfgrRZHxkagkX (the parent's session; this run is mode:subagent)",
"premise_still_valid": true,
"summary": "The premise holds on fresh main: with no driver and no datasource the boot read of sys_metadata fails ([ObjectQL] No driver available for object 'sys_metadata', measured through the real protocol over a driverless engine) and restoreMetadataFromDb answered with the datasource remedy. It now asks the engine's own routing (getDriverForObject, resolveEffectiveDatasource, listUnavailableDatasources, via a new private sysMetadataHasNoStorage, asked only after the read failed) and, when all three are empty, logs the same error-level line with 'no storage is configured: no datasource is declared and no driver is registered' and the three remedies copied verbatim from the CLI's No storage line, in the CLI's own sentence shape. The datasource arm is byte for byte unchanged for a registered driver whose read failed, a named binding with no driver, and a declared datasource the connection layer marked unavailable; level, counts and the consequence sentence are unchanged. Deviation to disclose: I pushed the branch after the first commit, not as an empty-branch probe before the first edit (the push succeeded, so the write route was never at risk).",
"tests": "All readings at head f273dab (base c9810dd; main has since moved to 3bc407d, which landed #23687 in plugin.ts, and a local merge-tree of the branch with it is clean, so main was not merged per the queue ruling). (1) Pins plus the existing outage pins: pnpm --filter @objectstack/objectql exec vitest run --maxWorkers=2 src/plugin-restore-metadata-no-storage.test.ts src/plugin-restore-metadata-outage.test.ts -> 2 files, 15 passed (6 new, 9 existing, whose assertions are untouched; only makePlugin() now builds a real engine with one registered driver, because the line now consults the engine). The first run had 2 failed, both my own harness: the real-protocol cases need sys_metadata registered, else the read fails earlier on Object 'sys_metadata' not found; fixed in the test. (2) Full package: pnpm --filter @objectstack/objectql test -> 424 files, 8129 tests passed, VERDICT command-exit 0. (3) pnpm --filter @objectstack/objectql typecheck, run after the last test edit -> exit 0 (tsc --noEmit clean; check:test-typecheck OK with the ledger unchanged at 39 files / 233 errors; the new test file is in tsconfig.test.json's program, 1 hit, and not in tsconfig.json's, 0). (4) eslint --no-inline-config on plugin.ts and the two test files -> exit 0. (5) Ablation with scripts/ablation-replace.mjs on packages/objectql/src/plugin.ts (anchor hit once, blob changed, restore verified blob == HEAD and git diff HEAD empty after every leg; the subject is imported from src, so no rebuild or dist leg applies). Verdict forced false -> 2 (a) pins RED, 4 (b) controls green, 9 existing green (2 failed | 13 passed). Verdict forced true -> 4 (b) RED, (a) green, 9 existing green (4 failed | 11 passed). Each probe dropped alone (getDriverForObject / resolveEffectiveDatasource / listUnavailableDatasources) -> 2 / 1 / 1 (b) controls RED, (a) green, new file only. Direction predicted before running; ordinary, no inversion. (6) dispatch-gates --commands 64 + 53 artifact-roster + 11 wide-population = 127 distinct commands, run at f273dab: 123 exit 0 on the first pass. check:dual-build-cjs-loads and check:published-readme-exports exited 3 (prerequisite, no dist) and are exit 0 after a full turbo build (75 tasks); check:type-check-debt exited 124 in my 280 s runner window and is exit 0 on rerun; check-partof-closing-keyword, check-closing-target-claim and check-single-claim-paths exited 2 (need a PR body or PR number) and are exit 0 with the PR body and PR_NUMBER=23698. dispatch-gates --ran with recorded exit codes: 64 derived, 64 run, 0 NOT-MEASURED (derived), 0 UNRUN. NOT MEASURED: node scripts/pm/check-governed-queue-guard.mjs (exit 1, no GITHUB_EVENT_PATH payload to read; the diff touches no governed surface). CI on the PR head at the one read I took: 37 check runs, 14 success, 6 skipped, 17 in_progress (Build Core among them), 0 failed; in_progress is the honest value and I did not wait.",
"mcp_calls": "0 — no MCP GitHub calls; reads were REST GETs through curl",
"api_writes": "2 — both relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): pr_create with assignees os-steve (POST /pulls draft, then POST /issues/23698/assignees; body read back byte-identical, 8696 bytes) and this os-dev-report comment (POST /issues/23636/comments). Plus 1 git push of the branch (not REST). label-write: 0 writes, the dispatch named no labels and the diff publishes (changeset present), so skip-changeset does not apply",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none (承接者:无) · noted, not filed · the three storage remedies are now spelled in two places, packages/cli serve.ts (noStorageRemedies) and packages/objectql plugin.ts (NO_STORAGE_REMEDIES), and nothing pins them equal; sharing one constant crosses into packages/cli, outside this card's surface; drift not yet exercised; in the PR's Acceptance notes",
"carrier: none (承接者:无) · noted, not filed · the remedies name CLI inputs (OS_DATABASE_URL, --dev), so a host that boots a kernel by hand with no driver reads the same three, of which 'mount a storage driver' is the one that applies; in the PR's Acceptance notes"
]
}
objectstack-fleet commentedon Oct 15, 2026
✅ ACCEPT: PR #23698 at
f273dab8e3·domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-15T16:47ZBasis:
main.Review (in-seat, the full diff read). The diff is operator text in one function, with no contract surface, so no contract review is owed.
restoreMetadataFromDb's ERROR picks its arm from the engine's own routing, through a new privatesysMetadataHasNoStorage(). It asksgetDriverForObject,resolveEffectiveDatasourceandlistUnavailableDatasources, and only after the read has already failed, so a healthy boot pays nothing. It never reads the text of the error.noStorageRemedies(packages/cli/src/commands/serve.ts, about:5144–:5146atmain).error, and the consequence sentence is word for word the same.Clause-②: no, with a patch changeset.Landing checks at
f273dab8e3:ci-failure.mjs --pr 23698is GREEN: 40 of 40 check runs completed, none failed.git merge-treeagainst currentmainis clean (maincarries fix(objectql): keep the metadata service's copy of a runtime-authored object current after boot (MCP stdio exposure gate) #23687 in the same file, in a different region).Fixes #23636. The closing-target claim guard is green.Out-of-scope findings:
Acceptance notes: the three remedies are now spelled in two places,packages/cliserve.ts(noStorageRemedies) andpackages/objectqlplugin.ts(NO_STORAGE_REMEDIES), and nothing pins them equal. Sharing one constant would cross intopackages/cli, outside this card. The drift is not yet exercised.Acceptance notes: the remedies name CLI inputs (OS_DATABASE_URL,--dev). A host that boots a kernel by hand reads the same three, of which "mount a storage driver" is the one that applies.Next: ready, then auto-merge through the queue.
Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
Landing record: PR #23698 →
30c33e3875·domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-15T17:19Z30c33e3875363bc3f81446f4a3859bfb0bea828a, from headf273dab8e3, on its first queue build: added 2026-10-15T16:50Z, merged 2026-10-15T17:18Z. The queue's removal event in the same second is the merge itself. The ACCEPT is 6197401826.Fixes #23636closed this card.f1e21c4f45equals the head's diff against their merge-basec9810dd9d1: the same 4 files, and every file's changed lines identical (+319 / −5).pm:dispatchedis removed in the same act.Generated by Claude Code