Repository navigation
Commit 2db3281
fix(objectql): the 503 text for a failed datasource no longer blames a startup connect under OS_ALLOW_DRIVER_CONNECT_FAILURE (#28361)
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoXFoG5pmoNTrXPd7hYMN4JA)_
Fixes #28135
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:数据源连接失败时的 503(`ERR_DATASOURCE_UNAVAILABLE`)提示不再一律说「启动时连接失败、且以
OS_ALLOW_DRIVER_CONNECT_FAILURE 启动、必须重启」,改为「最近一次连接失败」并指向 Setup →
Datasources 或服务器日志;只有该开关确实开着时,才附带一句有条件的「代码声明的数据源需重启」。
- 为什么改:运行中安装的包(install-local)和在 Setup
里新建的数据源连接失败时,用户被告知去重启一台从未带该开关启动的服务器,原因也是错的;连接层对所有来源记录的都是同一个
`failed`,所以文案不再声称它不知道的来源。
- 风险与回滚:只改错误文案与文档,错误码、503 状态、`reason: failed` 均不变;回滚即 revert 本 PR。
- 先看:`packages/objectql/src/driver-connect-errors.ts`(`failed` 分支与
`degradedBootNote`)、`packages/objectql/src/datasource-unavailable.test.ts`(开关开/关两条
pin)。
- 两分钟验证:`pnpm --filter @objectstack/objectql exec vitest run
src/datasource-unavailable.test.ts`,预期 8 条全绿。
- 需要你做的:无,席位落地。
## What changes
`DatasourceUnavailableError`'s `failed` arm said every such datasource
"failed to connect at startup and the server was started with
`OS_ALLOW_DRIVER_CONNECT_FAILURE` … must be restarted". The connection
layer cannot back that claim: it records every failed connect as the
same `{ kind: 'failed' }`.
| # | Origin | Caller → service | Trigger | Flag needed to reach a
running server | Engine record | What re-runs the connect |
|---|---|---|---|---|---|---|
| 1 | Boot, code-declared, bound / mapped / bootCritical / `onMismatch:
'fail'` | `AppPlugin.start` → `connectPackageDatasources(installed:
false)` → `connectDeclared`; `DefaultDatasourcePlugin` → `connect` |
`declared-auto` | yes (otherwise the boot is refused) | `{ kind:
'failed' }` | restart |
| 2 | Boot, code-declared, `autoConnect: true`, nothing bound | same |
`declared-auto` | no (degrades with a warning) | `{ kind: 'failed' }` |
restart |
| 3 | install-local, hot install | `MarketplaceInstallLocal` →
`connectPackageDatasources(installed: true)` | `declared-auto` | no (the
fatal throw is caught, verdict returned) | `{ kind: 'failed' }` |
reinstall, restart |
| 4 | install-local, rehydrate at boot | same | `declared-auto` | no |
`{ kind: 'failed' }` | restart |
| 5 | Setup create / update | `registerPool` → `connect`,
`reregisterPool` → `reconnect` | `runtime-admin` | no (never fatal) | `{
kind: 'failed' }` | save in Setup, restart |
| – | Policy refusal, any origin | any | any | – | `{ kind: 'blocked',
publicDetail? }` | – |
`DatasourceConnectionService.recordState` maps availability to the kind
and drops trigger, origin and flag; `publicDetail` is set only by a
policy denial (measured on `main` 69c39b1).
So the `failed` arm now names no origin: "its last connect attempt
failed, so no driver serves it", ending "See Setup → Datasources or the
server log for the cause." The one fact that can make a restart sentence
true is the process flag: without `OS_ALLOW_DRIVER_CONNECT_FAILURE`
origin 1 cannot exist, because that boot is refused. While the flag is
set, the message adds, conditionally, that a datasource declared in code
whose connect failed at startup is re-connected only by a restart. The
flag is read through `resolveAllowDriverConnectFailure` from
`@objectstack/types`, the same parse the boot paths use; it reads
`process` through `globalThis` and answers `false` without one, so the
constructor cannot throw.
Unchanged: the `blocked` and `remote` arms, the code, the 503, the
`reason` class, `publicDetail`, the "See … for the cause" tail, and the
rule that the message never carries the underlying cause.
Also re-worded, because they quoted the old sentence:
`content/docs/api/wire-format.mdx` (the 503 section),
`content/docs/data-modeling/external-datasources.mdx` (what a query
against an unusable datasource says), and the restated error in two
`plugin-security` fixtures (`controlled-by-parent-sharing.test.ts`,
`store-fault-fail-closed.test.ts`). Patch changeset
`.changeset/28135-datasource-unavailable-failed-cause.md`.
## Tests
- `packages/objectql/src/datasource-unavailable.test.ts`: the old
degraded-boot pin is split in two. With the flag set (the
boot-under-flag origin) the message says the connect failed and,
conditionally, that a restart re-runs it. With the flag unset (the
install-local and Setup origins, which record the same kind) it names
neither the flag, a restart nor "at startup", and ends with the new
tail. The "never carries the underlying cause" pin now asserts `Setup →
Datasources` instead of `startup logs`.
- Ablation, on committed head ea7bffd, through
`scripts/ablation-replace.mjs` (anchor `if
(!resolveAllowDriverConnectFailure()) return '';`, 1 → 0 hits each leg):
- guard replaced by `if (false) return '';` (note always said): the
flag-unset pin goes red (1 failed);
- guard replaced by `return '';` (note never said): the flag-set pin
goes red (1 failed);
- restored: `git diff HEAD` empty, blob 82ec394 equals
`HEAD:packages/objectql/src/driver-connect-errors.ts`.
## Acceptance notes
- **Follow-up for the seat to decide (not filed):** the engine cannot
tell the five origins apart. Naming the recorded origin needs
`IDataEngine.markDatasourceUnavailable`'s info shape widened in
`packages/spec` (its literal union is pinned by
`packages/spec/src/contracts/data-engine.test.ts`), and
`DatasourceUnavailableKind` is served as the 503's wire `reason`, so a
new kind member is not an option either. Two docblocks state the old
narrow meaning of `failed` and belong to that follow-up:
`IDataEngine.markDatasourceUnavailable` in
`packages/spec/src/contracts/data-engine.ts` ("the connect failed while
the operator opted into a degraded boot") and
`ObjectQL.markDatasourceUnavailable` in
`packages/objectql/src/engine.ts`. Two code comments also describe
`failed` that way and were left alone as outside this card's file
surface: `packages/objectql/src/engine-datasource-routing.ts` (above the
unavailable lookup) and `packages/rest/src/rest.test.ts` (above the 503
mapping pin).
- The degraded-boot banner printed by
`DatasourceConnectionService.handleFailure` says "DEGRADED BOOT" also
for a package install into a running server while the flag is set
(origin 3 under the flag). Not touched here; noted only.
- `packages/objectql/src/datasource-mapping.test.ts` keeps its comment
calling its `failed` mark "a failed boot connect under
OS_ALLOW_DRIVER_CONNECT_FAILURE"; that is still one true origin of the
record.
## Verification
All readings on head `ea7bffd6` (the PR head), objectstack `main` merge
base 69c39b1.
<details><summary>Affected-package tests and typecheck</summary>
- `pnpm --filter @objectstack/objectql test` (under `os-verify-lock`):
`Test Files 502 passed (502)`, `Tests 9767 passed (9767)`, VERDICT
command-exit 0.
- `pnpm --filter @objectstack/plugin-security test`: `Test Files 237
passed (237)`, `Tests 5119 passed | 45 skipped (5164)`, VERDICT
command-exit 0.
- `pnpm --filter @objectstack/objectql typecheck`: exit 0
(`check:test-typecheck: OK`).
</details>
<details><summary>Derived gates: 94 derived, 90 run green, 4 NOT
MEASURED</summary>
`node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--ran F`: "94 derived famil(ies) accounted for — 90 run, 4
NOT-MEASURED". The four refused their own prerequisite (exit 3) and are
left to CI's `Lint & Repo Gates`:
- `check-plugin-teardown-shape.mjs --self-test`: needs unshallowed
history (51-commit clone).
- `spec check:skill-examples`: needs the client SDK's built `.d.ts`.
- `check:dual-build-cjs-loads`: needs a full `pnpm build`.
- `check:i18n`: needs the built CLI and its extract closure.
```
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-adr-links.mjs :: exit 0
node scripts/check-adr-links.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-adoption.mjs :: exit 0
node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-doc-route-spelling.mjs --advisory :: exit 0
node scripts/check-doc-route-spelling.mjs --self-test :: exit 0
node scripts/check-docs-section-name.mjs :: exit 0
node scripts/check-docs-section-name.mjs --self-test :: exit 0
node scripts/check-dts-emitted.mjs --self-test :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-engine-split-ratio.mjs --self-test :: exit 0
node scripts/check-issue-citations.mjs :: exit 0
node scripts/check-plugin-teardown-shape.mjs :: exit 0
node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 3
node scripts/check-section-landing-index.mjs :: exit 0
node scripts/check-section-landing-index.mjs --self-test :: exit 0
node scripts/check-tenant-audit-census.mjs :: exit 0
node scripts/check-tenant-audit-census.mjs --self-test :: exit 0
node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0
node scripts/docs-audit/check-affected-docs.mjs :: exit 0
node scripts/docs-audit/check-drift-comment.mjs :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm --filter @objectstack/lint run check:doc-security-posture :: exit 0
pnpm --filter @objectstack/spec run check:docs :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm --filter @objectstack/spec run check:empty-state :: exit 0
pnpm --filter @objectstack/spec run check:liveness :: exit 0
pnpm --filter @objectstack/spec run check:skill-examples :: exit 3
pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0
pnpm --filter @objectstack/spec run check:variant-docs :: exit 0
pnpm --filter @objectstack/spec run check:yaml-examples :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:corpus-claim-drift :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:doc-anchors :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:doc-frontmatter :: exit 0
pnpm check:docs-audit-scope :: exit 0
pnpm check:docs-redirects :: exit 0
pnpm check:docs-single-h1 :: exit 0
pnpm check:docs-spec-enumerations :: exit 0
pnpm check:docs-transcript-drift :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:dts-closure :: exit 0
pnpm check:dual-build-cjs-loads :: exit 3
pnpm check:durability-log-level :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:i18n :: exit 3
pnpm check:i18n-stale-fill :: exit 0
pnpm check:issue-citations :: exit 0
pnpm check:keyed-text-bounds :: exit 0
pnpm check:lean-entry-closure :: exit 0
pnpm check:logger-receiver-detach :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:objectql-double-limit :: exit 0
pnpm check:org-identifier :: exit 0
pnpm check:page-declaration-shape :: exit 0
pnpm check:platform-object-tenancy-census :: exit 0
pnpm check:pm-changeset-deadline-census :: exit 0
pnpm check:published-files :: exit 0
pnpm check:published-readme-links :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:react-page-adapter-contract :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:registry-log-declared :: exit 0
pnpm check:rest-log-spy-declared :: exit 0
pnpm check:role-word :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:slot-lookup :: exit 0
pnpm check:sourcemap-no-sources-content :: exit 0
pnpm check:system-context-census :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:vendor-version-stamps :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
```
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L9qibwanr5nGX9vQKHm1Cu)_
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01L9qibwanr5nGX9vQKHm1Cu
Co-authored-by: Claude <noreply@anthropic.com>1 parent 71de060 commit 2db3281
7 files changed
Lines changed: 106 additions & 24 deletions
File tree
- .changeset
- content/docs
- api
- data-modeling
- packages
- objectql/src
- plugins/plugin-security/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
400 | 400 | | |
401 | 401 | | |
402 | 402 | | |
403 | | - | |
404 | | - | |
405 | | - | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
406 | 407 | | |
407 | 408 | | |
408 | 409 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
227 | 227 | | |
228 | 228 | | |
229 | 229 | | |
230 | | - | |
231 | | - | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
232 | 235 | | |
233 | 236 | | |
234 | 237 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | | - | |
| 10 | + | |
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
70 | | - | |
71 | | - | |
72 | | - | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
73 | 79 | | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | | - | |
79 | | - | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
80 | 112 | | |
81 | 113 | | |
82 | 114 | | |
| |||
86 | 118 | | |
87 | 119 | | |
88 | 120 | | |
89 | | - | |
| 121 | + | |
90 | 122 | | |
91 | 123 | | |
92 | 124 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
| 4 | + | |
3 | 5 | | |
4 | 6 | | |
5 | 7 | | |
| |||
231 | 233 | | |
232 | 234 | | |
233 | 235 | | |
234 | | - | |
235 | | - | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
236 | 240 | | |
237 | 241 | | |
238 | 242 | | |
| |||
266 | 270 | | |
267 | 271 | | |
268 | 272 | | |
269 | | - | |
270 | | - | |
271 | | - | |
| 273 | + | |
272 | 274 | | |
273 | | - | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
274 | 281 | | |
275 | 282 | | |
276 | 283 | | |
277 | 284 | | |
278 | 285 | | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
279 | 313 | | |
280 | 314 | | |
281 | 315 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
280 | 280 | | |
281 | 281 | | |
282 | 282 | | |
283 | | - | |
| 283 | + | |
284 | 284 | | |
285 | 285 | | |
286 | 286 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
63 | | - | |
| 63 | + | |
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
| |||
0 commit comments