Repository navigation
fix(spec)!: a datasource named drivers is refused at every door that parses a datasource - #29423
Conversation
The reserved set moves to @objectstack/spec as ROUTE_SHADOWED_DATASOURCE_NAMES; service-datasource's admin registrar and create door read the spec list. Claude-Session: https://claude.ai/code/session_01ADHkmS1mEJA9L4pTrajNhU Co-authored-by: Claude <noreply@anthropic.com>
…changeset ADR-0087 semantic entry datasource-name-route-shadowed-refused, regenerated api-surface / export-origins / datasource reference, and the drivers.mdx sentence now names the schema refusal. Claude-Session: https://claude.ai/code/session_01ADHkmS1mEJA9L4pTrajNhU Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 2 package(s): 4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 5 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 168 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 ce6a2047d6ea13af52afd5a827beaa7a591f84e8 && git checkout ce6a2047d6ea13af52afd5a827beaa7a591f84e8
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 96fb7b5d07afaf828f4c0de4ba0fe3d179984e86 e5f6120b7f55592da59b6e9d2b7f710fe25be6a8 && git checkout -B drift-repro 96fb7b5d07afaf828f4c0de4ba0fe3d179984e86 && git merge --no-ff e5f6120b7f55592da59b6e9d2b7f710fe25be6a8
node scripts/docs-audit/affected-docs.mjs --json 96fb7b5d07afaf828f4c0de4ba0fe3d179984e86
|
|
domain:spec#2 · os-steve · session_01ADHkmSduNGC2SZXszyrNut Contract-review-claim: session_01ADHkmSduNGC2SZXszyrNut · head 4df813f · 2026-11-02T14:39Z The lane seat reviews this head itself at |
|
domain:spec#2 · os-steve · session_01ADHkmSduNGC2SZXszyrNut 待裁:新公开名字
|
|
domain:spec#2 · os-steve · session_01ADHkmSduNGC2SZXszyrNut Contract reviewServed-tier: Inputs read: card #29308 (body, triage 6576569136, claim 6578377666, os-dev-report 6579884811), PR #29423 (body, 9-file list, net diff against merge-base Check-runs on the head at the second poll: 0 failures. Green: Check Changeset, Governed Surface Queue Guard, PR-body guards, Spec property liveness, Dogfood Regression Gate, Lint (CI/release/engine gates, ESLint, docs & code guards, repo & tooling gates, PM dispatch-gates, scoped x3), Type Check (source gates, debt ledger), Build Docs, Build UI Deps, Live E2E UI, Check Documentation Links, Flag docs, Check PR Size. Still in_progress: Build Core, Test Core (shards 3-8), Test UI (1-16), Type Check (workspace, consumer gates, UI). The landing rule (AGENTS.md #14, Tier S) needs every check green independently of this record; nothing read here predicts a red. ① Derived judgmentsAccept-set changes the diff implies, each judged against the live tree:
Public-surface changes:
② Semver levelChangeset
③ Boundary flagsDev flags (os-dev-report 6579884811):
Reviewer's own check, asked by the brief: does any ④ Design judgment
Must-fix: 0. Should-fix: 1 (the per-list refusal sentence). Implemented-by: VERDICT: PASS |
Build the sentence from the input (zod 4 error function) instead of once for the whole list, pin that it names only itself, and correct the NAME_RE docblock in the admin service, which describes the first of the two patterns. Claude-Session: https://claude.ai/code/session_01ADHkmS1mEJA9L4pTrajNhU Co-authored-by: Claude <noreply@anthropic.com>
|
domain:spec#2 · os-steve · session_01ADHkmSduNGC2SZXszyrNut Contract reviewServed-tier: This is a DELTA record for the push after the PASS record 6580118235 (head Implemented-by: VERDICT: PASS |
|
domain:spec#2 · os-steve · session_01ADHkmSduNGC2SZXszyrNut Head-sha: 维护者速读
席位意见:可落地,只等名字。契约复审在 4df813f 判 PASS(6580118235),在现 head 的 delta 判 PASS(6580844367),CI 全绿。 席位核对 — ACCEPT ·
|
|
domain:spec#2 · os-steve · session_01ADHkmSduNGC2SZXszyrNut Withdrawn: the name question on this PR. The pm-dispatch skill carries no rule that a new public name needs the maintainer's approval; that line lived only in this seat's standard order. Under SKILL.md 〈升级与决策〉 a name escalates only when the options truly diverge on product semantics or contract shape and no existing norm decides; here the dev's name is fit and no fork exists, so it is the seat's call: the name stays as built. Prompted by the maintainer's question at 2026-11-02T17:03Z. |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 41489734213 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 41491867212 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Requested by Steve · project thread
Fixes #29308
Clause-②: no (narrowing)
Metadata-protocol: narrowed
Skills-docs: none in
skills/**(skills/objectstack-data/rules/datasources.mdteachesdefaultas host-reserved, and no file underskills/**declares or shows a datasource nameddrivers; every taught use stays true). Docs:content/docs/data-modeling/drivers.mdxsaiddriverswas reserved at the admin API only; it now names the schema refusal and every door.维护者速读
drivers现在在所有解析数据源的入口被拒收(代码声明、os validate、元数据保存门 422),不再只在管理接口的新建门拒收;保留名单搬进 spec,成为唯一一份,管理接口的路由和新建门都读它。GET /api/v1/datasources/drivers是驱动目录,叫drivers的数据源永远打不开编辑页;新建门拦住了,但代码和元数据保存门还能造出这个打不开的数据源。drivers的数据源再保存会被拒;仓内作者写的此名数据源为 0。已存的行照常加载,_diagnostics标valid: false,管理接口里仍可列出、删除、只改标签。回滚即还原本 PR。packages/spec/src/data/datasource.zod.ts(新常量与name上的第二条 pattern)、packages/services/service-datasource/src/datasource-route-reserved-names.ts(改读 spec 常量)、迁移条目18.datasource-name-route-shadowed-refused.ts。pnpm --filter @objectstack/spec exec vitest run src/data/datasource-route-shadowed-name.test.ts,预期 7 项全绿,其中一项断言报错落在name、以Datasource name 'drivers' is reserved开头。ROUTE_SHADOWED_DATASOURCE_NAMES需要你点头(席位会问);其余无,席位落地(落地前走一次契约复核)。What changes
ROUTE_SHADOWED_DATASOURCE_NAMESinpackages/spec/src/data/datasource.zod.ts(@objectstack/spec/data), a frozen['drivers'] as const: the names the datasource admin API can never serve by name, because a literal route under/api/v1/datasources/shares a method with the by-name read and is mounted ahead of it (GET /api/v1/datasources/driversis the driver catalog).DatasourceSchema.namerefuses each entry. A second.regex()onname(a negative lookahead built from the list), with the messageDatasource name 'drivers' is reserved: the datasource admin API serves its own route at /api/v1/datasources/drivers, ahead of the by-name read /api/v1/datasources/:name, so a datasource of that name could never be read by name. Pick another name.Oneinvalid_formatissue atname. A pattern, not a refinement: zod emits both patterns into the published JSON Schema (allOf), so nodropped-refinements.baseline.jsonrow is added (the build reads 988 sites before and after) and JSON-Schema consumers refuse the name too (pinned).packages/services/service-datasource/src/datasource-route-reserved-names.ts).ROUTE_SHADOWED_DATASOURCE_NAMESthere is now the spec's frozen array itself (widened toreadonly string[]for the create door'sincludes), andDRIVER_CATALOG_SEGMENT, the segment the registrar mounts the catalog from, is typed(typeof ROUTE_SHADOWED_DATASOURCE_NAMES)[number]against the spec list, so a catalog segment the spec does not reserve does not compile. The registrar (admin-routes.ts) and the create door (datasource-admin-service.ts) are unchanged: they already imported from this file.createDatasourcerunsassertValidName(which refusesdriverswith its own 400DATASOURCE_ADMIN_ERRORsentence) before any schema parse, so aPOST /api/v1/datasourcesfordriversstill answers that one refusal; the existing door pins hold unchanged (below).datasource-name-route-shadowed-refused(step 18), modelled onstack-datasource-host-reserved-name-refused: refused with a prescription, no conversion (the new name, and every object that routes to it, are the author's call).content/docs/data-modeling/drivers.mdx: the sentence PR fix(service-datasource)!: refuse creating a datasource nameddrivers, the driver-catalog route literal #29262 added ("reserved at the datasource admin API") now names the schema refusal and every door. Regenerated:content/docs/references/data/datasource.mdx,packages/spec/api-surface/data.json,packages/spec/export-origins/data.json.default(the host's owndefaultrow still parses throughDatasourceSchema; a stack still may not declare it,stack.zod.ts),test(the draft-probe literal shadows no by-name read), and names that only contain the word (driver,drivers_archive,my_drivers,_drivers), all pinned as controls.Tests
packages/spec/src/data/datasource-route-shadowed-name.test.ts(7 cases): the list is frozen and every entry matches the identifier pattern (so the refusal pattern needs no escaping);DatasourceSchemarefuses each entry with oneinvalid_formatissue atnamewhose message names the name and the route and carries no tracker number;defineStackrefuses it withSTACK_SCHEMA_INVALID/ 422 atdatasources.0.name; the published JSON Schema'snamepatterns reject each entry and acceptreporting,drivers_archive,driver; controls parse.packages/services/service-datasource/src/__tests__/datasource-route-reserved-names.test.ts(the drift pin and the door cases) is unchanged and green.Acceptance notes
saveMetaItemtest over the stub-engine harness ofprotocol.code-defined-datasource-door.test.ts, both kernel shapes; not committed). Before (eef116e4):PUT datasource/driverssaved (success: true, row stored), and a storeddriversrow read_diagnostics.valid: true. After (4df813f3):INVALID_METADATA/ 422 withdatasource/drivers failed spec validation: name: Datasource name 'drivers' is reserved: …, nothing stored; the controldrivers_oksaves; a storeddriversrow still loads with_diagnostics: { valid: false, errors: [{ path: 'name', code: 'invalid_format', … }] }.driversrow (written before PR fix(service-datasource)!: refuse creating a datasource nameddrivers, the driver-catalog route literal #29262): list,label/active-only PATCH and DELETE still work (the existing pin). A PATCH that touchesconfig,driver,poolorexternal, or carries a secret, is judged against the wholeDatasourceSchema(assertValidRecord) and is now refused with the schema's sentence: the row has to be renamed, which only a new datasource plus re-pointing the objects can do. Same posture as every other spec refusal on a stored row.git grepfor a datasource nameddriversacrossexamples/,packages/**(templates, fixtures),ui/,apps/,content/: one hit, the service-datasource stored-row fixture above.ROUTE_SHADOWED_DATASOURCE_NAMES(the name the service-datasource module already used). Open question in the report.packages/lintdoes not validate datasource names (git grep DatasourceSchema packages/lint/src: 0 hits), so it owes no reading.Verification
All readings at head
4df813f3(the last commit), treeobjectstack-ai/objectstack, each throughos-verify-lock(VERDICTcommand-exit 0on every line).Suites (spec, the consumers, full dogfood)
pnpm --filter '@objectstack/dogfood^...' --filter '@objectstack/service-datasource...' --filter '@objectstack/metadata-protocol...' build, exit 0 (386 s).pnpm --filter @objectstack/spec test: Test Files 792 passed (792), Tests 23398 passed, 1 todo.pnpm --filter @objectstack/spec typecheck: exit 0.pnpm --filter @objectstack/service-datasource test: Test Files 70 passed (70), Tests 1160 passed (1160), the unchangeddatasource-route-reserved-names.test.tsamong them. Typecheck exit 0.pnpm --filter @objectstack/metadata-protocol test: Test Files 303 passed, 4 skipped (307), Tests 22136 passed, 26 skipped.pnpm --filter @objectstack/dogfood test, no shard, no path: Test Files 393 passed, 3 skipped (396), Tests 3243 passed, 28 skipped (3271), exit 0 (29 m).spec build:dropped-refinementsreads 988 sites, as on main (the refusal is a pattern, not a refinement).Derived gates (107) and the changeset axes
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 107 commands for this change set; all 107 ran and exited 0.check:skill-examplesandcheck:dual-build-cjs-loadsfirst answered exit 3 (prerequisite: built dists) and were re-run afterturbo run build --filter='./packages/**'(exit 0): 281 prose examples type-check; 115 require entry points across 70 packages load.--ranreconciliation: 107 derived, 107 run, 0 NOT-MEASURED, 0 UNRUN.check-changeset-no-major.mjs --base eef116e4 --event(this body's two declaration lines): exit 0, LEVEL AXIS accounted (@objectstack/spec: minor,@objectstack/service-datasource: patch).check:adr-0087-registration: exit 0,registered datasource-name-route-shadowed-refused (new here).check:dev-prereqs: exit 1, "the workspace is not built" for 35ui/packages this card never builds (local container state; not a derived family).Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_01ADHkmS1mEJA9L4pTrajNhU