Repository navigation
fix(service-datasource)!: POST /datasources/:name/test answers an unknown name 404 RESOURCE_NOT_FOUND - #27574
Conversation
…own name (red)
An unknown saved name answers 200 { ok: false } at the Test door while
GET /datasources/:name answers the same name 404 RESOURCE_NOT_FOUND.
Controls: an existing datasource that fails its probe keeps { ok: false },
an existing one that is up answers ok, and the primary datasource with no
stored record is still tested through its live driver.
Claude-Session: https://claude.ai/code/session_01L6bhgXcN9HaZYSEUdJWEjw
Co-authored-by: Claude <noreply@anthropic.com>
…ces/:name/test
Test resolved no saved record before probing, so a name no datasource has
answered 200 { ok: false } with the engine's driver-missing sentence, the
answer a saved datasource that is down gets. testConnection now reads the
stored record first (getDatasource, the same metadata read the sibling
:name doors make) and throws the 404 RESOURCE_NOT_FOUND envelope in GET's
words, which the route relays. The primary datasource is not looked up: it
may have no stored record and its live driver answers for it.
Fixtures that tested a saved datasource with no live driver now store that
datasource's record.
Claude-Session: https://claude.ai/code/session_01L6bhgXcN9HaZYSEUdJWEjw
Co-authored-by: Claude <noreply@anthropic.com>
…tasource-test-unknown-404
📓 Docs Drift CheckThis PR changes 1 package(s): 10 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 6 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 2 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 4046c96620112657b99fe797c308ed670c0d5c2d && git checkout 4046c96620112657b99fe797c308ed670c0d5c2d
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 1ed33609731b0bc3b2da81c97242e9c8582d003d b09ea62c764f4d63a128b14220f87b00f4254be3 && git checkout -B drift-repro 1ed33609731b0bc3b2da81c97242e9c8582d003d && git merge --no-ff b09ea62c764f4d63a128b14220f87b00f4254be3
node scripts/docs-audit/affected-docs.mjs --json 1ed33609731b0bc3b2da81c97242e9c8582d003d
|
…owing Clause-2 moves from no to no (narrowing): a request answered 200 is now refused 404. Adds the BREAKING banner (before / now / unchanged / remedy) and the ADR-0087 not-required (no-migration-prescription) marker. Claude-Session: https://claude.ai/code/session_01L6bhgXcN9HaZYSEUdJWEjw Co-authored-by: Claude <noreply@anthropic.com>
|
domain:server#1 · os-sales · session_01L6bhgXcN9HaZYSEUdJWEjw Contract-review-claim: session_01L6bhgXcN9HaZYSEUdJWEjw · head b09ea62 · 2026-10-29T14:41Z |
|
domain:server#1 · os-sales · session_01L6bhgXcN9HaZYSEUdJWEjw Contract reviewServed-tier: Face: ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Implemented-by: VERDICT: PASS Reviewed 2026-10-29T14:47Z. |
|
domain:server#1 · os-sales · session_01L6bhgXcN9HaZYSEUdJWEjw 维护者速读(席位终稿)
席位意见:接受。认领时席位把声明写成了 席位核对 — ACCEPT · domain:server#1 · head b09ea62 · 2026-10-29T14:54Z
|
domain:server#1 · os-sales · session_01L6bhgXcN9HaZYSEUdJWEjw
Requested by Sales · project thread
Fixes #27510
Clause-②: no (narrowing) —
POST /api/v1/datasources/:name/testand the in-processExternalDatasourceService.testConnection(name)refuse a name that resolves no saved datasource with404 RESOURCE_NOT_FOUND, which they answered200 { ok: false }before. Nothing is widened.Metadata-protocol: none
Skills-docs: none — no content/docs page or skills/** file states what
POST /api/v1/datasources/:name/testanswers (grep for the route,test_connectionandtestConnectionover content/docs and skills/ found none; data-modeling/external-datasources.mdx names onlyGET /api/v1/datasources); theRESOURCE_NOT_FOUNDexample in protocol/kernel/error-handling.mdx isGET /api/v1/datasources/:name, whose answer this door now matches.维护者速读
POST /api/v1/datasources/NAME/test遇到不存在的数据源名,现在返回404 RESOURCE_NOT_FOUND(与GET /datasources/NAME同码同文案),不再返回200 {ok:false}。200 {ok:false},主数据源default即使没有存储记录也照常测试。回滚即 revert 本 PR。external-datasource-service.ts的testConnection开头新增的存在性检查;② 新测试saved-datasource-test-unknown-name.test.ts;③ 两个旧测试里补上的数据源记录。pnpm --filter @objectstack/service-datasource exec vitest run src/__tests__/saved-datasource-test-unknown-name.test.ts,预期 5 个用例全绿。What changes
ExternalDatasourceService.testConnection(name)first resolves the saved record throughgetDatasource. This is the same stored-record read that the sibling by-name doors make: both plugins wire it tometadata.get('datasource', name). When nothing is stored under that name, it throws a404/RESOURCE_NOT_FOUNDerror in the wordsGET /datasources/NAMEuses. The admin route's existing relay inbadRequestanswers that error as404, so the route handler is unchanged.default) is not looked up. It may have no stored record, and its live driver answers for it, as before.200 { ok: false, error }, and one that is up still gets200 { ok: true, … }.admin-routes.tsnow list the Test door among the by-name doors that answer404.@objectstack/service-datasourcepatch.Tests
src/__tests__/saved-datasource-test-unknown-name.test.ts. It runs through the real HTTP door over the real composition:ObjectQL, the connection service and driver factory, the admin service, theExternalDatasourceServicePluginwiring, and the admin routes on Hono. It has 5 cases:404 RESOURCE_NOT_FOUND, names the datasource and has nodata.GET /datasources/NAMEfor the same name.200 { ok: false, error }.200 { ok: true }.200 { ok: true, latencyMs }.d4ff1a025fbefore the fix and gaveTests 2 failed | 3 passed (5). The two failures were the unknown-name cases, which receivedstatus: 200, success: true./ghost/test), so they pinned this defect directly. Their assertions are unchanged. Each fixture now stores that datasource's record:primary-datasource-test-and-sync.test.ts:ghostwas added toRECORDS, and the health-check unit'sgetDatasourcereturns a record.saved-datasource-test-after-failed-connect.test.ts:ghostis seeded into the records map, and the verdict units'getDatasourcereturns a record.1ae90cf405.pnpm --filter @objectstack/service-datasource testgaveTest Files 59 passed (59)andTests 989 passed (989).typecheck(tsc --noEmit, which covers the three test files:--listFilescounts 3/3) exited 0.eslint --no-inline-config packages/services/service-datasourceexited 0.Ablation (scripts/ablation-replace.mjs, wrap mode)
The subject is imported from
srcby a relative import, so nodistis involved.if (false ...). The new file went red with2 failed | 3 passed (5): both unknown-name cases failed. The file was restored with blob4750f4f6e7fbequal to HEAD, andgit diff HEADwas empty.1 failed | 4 passed (5): "the primary datasource with no stored record is still tested through its live driver" failed. The file was restored with blob equal to HEAD and an emptygit diff HEAD.Acceptance notes
GET /datasources/NAME/remote-tablesandPOST /datasources/NAME/object-draftanswer an unknown name400 EXTERNAL_DATASOURCE_ERROR. The code path isassertFederationSource:getDatasourcereturnsundefined,isFederationSource(undefined)is false, and the door throwsnotAFederationSourceError. This is a separate discrepancy, named in the claim. This PR did not measure it over HTTP.metadataservice now answers every non-primary name404at Test.GET /datasources/NAMEalready does the same in that host, because both read the same store.datasource-route-ledger.tsis unchanged. ItsPOST /:name/testnote does not state what the route answers.Verification
The derived gate list comes from
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackat1ae90cf405. Each command ran with its exit code captured before any pipe, and the record was reconciled with--ran: 62 derived, 61 run green (exit 0), 1 NOT MEASURED, 0 UNRUN.pnpm check:dual-build-cjs-loadsexited 3 withPREREQUISITE NOT MET — this gate reads built output, and some package has no dist/. It needs a full-repo build, so the reading is left to CI.(narrowing)arm, claim amendment 6498154139), onb09ea62c76:pnpm --filter '@objectstack/dogfood^...' build && pnpm --filter @objectstack/dogfood testunder the os-verify-lock, VERDICT command-exit 0, Test Files 350 passed | 3 skipped (353), Tests 2817 passed | 20 skipped (2837).merge-treewas needed.The 61 green families (exit 0)
node scripts/check-adr-0087-registration.mjs --base origin/mainnode scripts/check-adr-0087-registration.mjs --self-testnode scripts/check-changeset-no-major.mjs --base origin/mainnode scripts/check-closing-keyword-parity.mjsnode scripts/check-closing-keyword-parity.mjs --self-testnode scripts/check-comment-mask-adoption.mjsnode scripts/check-comment-mask-adoption.mjs --self-testnode scripts/check-comment-mask-corpus.mjsnode scripts/check-dts-emitted.mjs --self-testnode scripts/check-empty-changeset.mjs --base origin/mainnode scripts/check-empty-changeset.mjs --self-testnode scripts/check-issue-citations.mjsnode scripts/check-plugin-teardown-shape.mjsnode scripts/check-plugin-teardown-shape.mjs --self-testnode scripts/check-tenant-audit-census.mjsnode scripts/check-tenant-audit-census.mjs --self-testnode scripts/ci/assert-turbo-remote-cache.mjs --self-testnode scripts/ci/plan-test-core-shards.mjs --self-testnode scripts/ci/prune-turbo-cache.mjs --self-testnode scripts/docs-audit/check-affected-docs.mjsnode scripts/docs-audit/check-drift-comment.mjsnode scripts/pm/release-rehearsal-clone.mjs --self-testnode scripts/release-pending-publish.mjs --self-testpnpm --filter @objectstack/spec run check:duration-unit-keyspnpm check:changeset-gate-self-testspnpm check:ci-filter-paritypnpm check:closed-ceremony-textpnpm check:cross-package-test-inputspnpm check:dispatcher-error-vocabularypnpm check:doc-authoringpnpm check:driver-memory-censuspnpm check:dts-closurepnpm check:engine-double-contractpnpm check:error-status-conformancepnpm check:gitlink-declaredpnpm check:issue-citationspnpm check:keyed-text-boundspnpm check:lean-entry-closurepnpm check:logger-receiver-detachpnpm check:nul-bytespnpm check:objectql-double-limitpnpm check:org-identifierpnpm check:page-declaration-shapepnpm check:platform-object-tenancy-censuspnpm check:pm-changeset-deadline-censuspnpm check:published-filespnpm check:query-options-erasurepnpm check:refd-timer-probepnpm check:registry-log-declaredpnpm check:rest-log-spy-declaredpnpm check:route-envelopepnpm check:slot-lookuppnpm check:sourcemap-no-sources-contentpnpm check:system-context-censuspnpm check:test-source-aliaspnpm check:tier-file-adoptionpnpm check:type-check-coveragepnpm check:type-check-debtpnpm check:undeclared-dep-importspnpm check:watch-hint-literalpnpm check:where-matcherGenerated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_01L6bhgXcN9HaZYSEUdJWEjw