Repository navigation
docs(skills): the datasources rule states that default is host-reserved, connected from OS_DATABASE_URL, and refused in a stack's datasources (#23768) - #23793
Conversation
…onnected from OS_DATABASE_URL, and refused in a stack's datasources skills/objectstack-data/rules/datasources.md L5-6 read "Most apps need only the `default` datasource; declare more to read/write a separate or external database" — an invitation to the shape the stack's `datasources` collection refuses (`defineStack`, `os validate`, publish) and AppPlugin refuses at boot. The sentence now states the rule the spec and runtime hold: `default` is host-reserved, the host connects it from `OS_DATABASE_URL`, a stack that declares a datasource named `default` is refused, and a datasource is declared under its own name only for a separate or external database. Token ratchet paid inside the file by deleting two restatements of the field reference: "`external` settings are required when `schemaMode !== 'managed'`" (the schema's own superRefine refuses the omission) and "Set `autoConnect: true` to force a live connection" (item 3 of the auto-connect list above it). 903/911 tokens before and after; 80 lines before and after. Changeset: @objectstack/skills patch — skills/** ships through packages/skills dist via sync-catalog. Claude-Session: https://claude.ai/code/session_01VqGhCg9wdsBXPz54uAEWg7 Co-authored-by: Claude <noreply@anthropic.com>
维护者速读改了什么
为什么改
风险与代价(含回滚)
席位意见
你要做的
席位核对Seat Implemented-by:
Generated by Claude Code |
Contract reviewServed-tier: Read at 2026-10-16T03:06Z: card #23768 (body and all six comments), ruling clause 6189356908 on #23634, PR #23793 (body, file list, net diff against the merge base ① Derived judgmentsThe diff publishes text only: no schema, no runtime, no generated artifact. No published accept set moves. The one public surface that changes is
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #23768
Clause-②: no
What
skills/objectstack-data/rules/datasources.mdL5–6 read "Most apps need only thedefaultdatasource; declare more to read/write a separate or external database." "Declare more" implies thatdefaultis declared too, which is the shape the stack'sdatasourcescollection now refuses. The two lines are replaced by four:Each clause checked against the base
0b1179f33(origin/mainwhen the branch was cut; one commit past the dispatch's0a168a33e, inpackages/services/service-storage—datasources.mdand the ratchet script are byte-identical between the two):datasourcefield (default:'default')" stays:packages/spec/src/data/object.zod.tsL2482,datasource: z.string().optional().default('default').defaultis host-reserved … a stack that declares a datasource nameddefaultis refused":packages/spec/src/stack.zod.ts,HOST_RESERVED_DATASOURCE_NAME = 'default'andrefuseHostReservedDatasourceName, thesuperRefineonSTACK_DEFINITION_COLLECTIONS_SHAPE.datasources(sodefineStack,os validateand publish refuse it, located atdatasources.N.name);packages/runtime/src/app-plugin.tsL1261–1266 refuses the same at boot ("that name is reserved for the host's primary datasource").OS_DATABASE_URL":packages/runtime/src/default-datasource-plugin.ts(DefaultDatasourcePlugindeclares and connectsdefault); the spec's own refusal prescribes "set OS_DATABASE_URL and omit this entry".packages/runtime/src/resolve-project-database.tsresolves the host's database by priority — an explicit URL, then the environment (OS_DATABASE_URL), then adatasourceMappingrule{ default: true, datasource: NAME }naming a datasource the stack declares under its own name (a rule namingdefaultyields nothing there), then the unified default file. The sentence names the environment rung, the one the refusal prescribes; it does not say it is the only one.Nothing the spec does not declare is stated.
Token payment — two deletions in the same file, both restatements of the field reference
The added words cost more than the 8 tokens of headroom, so two sentences this file carried in duplicate of
packages/spec/src/data/datasource.zod.ts(the field reference L8 points at;src/**/*.zod.tsis in@objectstack/spec'sfiles[]) are deleted:externalsettings are required whenschemaMode !== 'managed'.").DatasourceSchema'ssuperRefinerefuses the omission itself —schemaMode='X' requires 'external' settings.— and theexternalfield's TSDoc reads "Required whenschemaMode !== 'managed'". An author who omits it is refused at authoring with the remedy; the skill loses no rule.autoConnect: trueto force a live connection." Item 3 of the auto-connect list four lines above already namesautoConnect: trueas a trigger, and the field'sdescribe()is "Force a live driver connection at boot even when managed + unrouted". L57 is byte-identical; L58 now ends at "not connected."No re-wrap anywhere: L3–4 and L57 are byte-identical, the four new lines carry the inserted text, and the only line-count changes are the insertion (+2) and the deletion (−2).
Readings (
skills/**)0b1179f33)5dd8c0a8c)datasources.mdlinesdatasources.mdbytesskills/objectstack-data/**/*.mdlines (the package)skills/*/SKILL.mdlines (the catalog)check-skills-token-ratchet,datasources.mdcheck-skills-token-ratchet, bundle totalVerdict lines verbatim — before:
✓ check-skills-token-ratchet: skills/objectstack-data/rules/datasources.md is 903 tokens (ceiling 911; headroom 8).— after:✓ check-skills-token-ratchet: skills/objectstack-data/rules/datasources.md is 903 tokens (ceiling 911; headroom 8).TheCEILINGSrow does not move. The four new lines are 79, 78, 71 and 38 characters, inside the file's existing range (its longest line is 107).Changeset
.changeset/23768-datasources-default-host-reserved.md,@objectstack/skillspatch, carryingClause-②: no. Re-measured:packages/skills/package.jsonfiles[]isdist, and itsbuild(packages/skills/scripts/sync-catalog.mjs) copiesskills/**intodist/skills/**. Afterpnpm --filter @objectstack/skills buildunder the shared verify lock:✓ @objectstack/skills: 65 file(s) across 10 skill(s) copied from skills/** into dist/skills and read back byte-identical.—host-reservedis indist/skills/objectstack-data/rules/datasources.md(1 hit),Most apps need onlyis not (0 hits), andcmpagainst the source file is byte-identical.Verification
Derived at
5dd8c0a8cbynode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(no paths; change set from the merge base0b1179f33: 2 files, +14/−5): 41 commands — the dispatch's 29 plus the 12 the changeset adds. Each ran in the foreground with its exit code captured before any pipe (stdout and stderr redirected to a log file first,EXIT=$?read next, no pipe in between), then--ranreconciled the record:✓ dispatch-gates --ran: 41 derived famil(ies) accounted for — 39 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3).check-skills-token-ratchetand its--self-test,check:skill-identifier-liveness(Leg 1: 457 citations over 53 published files),check:skill-compatibility,check:skill-frame-sync,check:pm-skill-id-lint,check:doc-authoring(53 published skill files clean),check:nul-bytes,check:role-word,check-adr-0087-registration --base origin/main(1 non-breaking changeset seen),check-changeset-no-major --base origin/main,check-empty-changeset --base origin/main(1 declaring changeset added; none from the merge base modified),check:published-files,check:pm-changeset-deadline-census,check:objectui-changeset, andcheck:doc-formula-expressions(afterpnpm turbo run build --filter=@objectstack/formula --filter=@objectstack/lint --concurrency=2under the shared verify lock, together with the skills build: lock held 103 s, waited 0 s).pnpm check:dual-build-cjs-loadsandpnpm check:lean-entry-closureexit 3 (PREREQUISITE NOT MET — both load every package's builtdist/, which only a whole-workspace build supplies; not built here for a markdown edit). CI'sLint & Repo Gatesbuilds and runs them; its check-run is the reading.grep -naPover both changed files finds none.packages/*source, no generated artifact.CI runs the full farm; the
os-dev-reportcomment on #23768 cites this PR's check-runs by name and conclusion.Acceptance notes
skills/objectstack-api/SKILL.mdL354 (credentials route torules/datasources.md), still true; nothing else underskills/carries the replaced sentence (git grepat0b1179f33: one hit, L5).skills/**), Tier H: this PR stays a draft until an authorized approval; the seat runs the contract review. No label written, as the dispatch order says; the changeset is present, soskip-changesetwould not apply anyway.维护者速读(草稿)
改了什么 —
skills/objectstack-data/rules/datasources.md开头段落。原句写「大多数应用只需要default数据源;要读写另一个或外部数据库就再声明几个」;现在改为「default由宿主保留:宿主从OS_DATABASE_URL连接它,stack 里声明一个名为default的数据源会被拒绝;只有要读写另一个或外部数据库时,才以自己的名字声明一个数据源」。为了付 token 棘轮,同一文件里删掉两句字段参考(datasource.zod.ts)已经写明且由 schema 自己强制的话:「schemaMode非managed时external必填」和「设autoConnect: true强制连接」(上面四行的列表第 3 项已经写了)。文件 80 行不变,903/911 token 不变;另加一个@objectstack/skills的 patch changeset。为什么改 — 这份技能包随
npx skills add发到客户项目,读者是写元数据的 AI。「再声明几个」暗示default也是声明出来的;而 #23757 合并后,stack 的datasources里出现名为default的条目会在defineStack、os validate、发布和启动四处被拒绝。唯一实测过写出这个形状的生产者就是 AI。新句子陈述的是 spec 与运行时真实持有的规则,没有一句超出 spec 声明。风险与代价(含回滚) — 纯文本改动,不改任何行为与代码。token 读数 903 → 903(上限 911,余量 8 → 8),上限不动,行数不动。回滚:revert 本 PR 即可,无数据或迁移影响。
席位意见 — (留空)
你要做的 — Tier H 面(
skills/**):审阅上面四行英文是否准确,以及两处删句是否可接受;同意则给 APPROVED review,由席位落地。不需要其他动作。Generated by Claude Code