Skip to content

fix(spec): the Seed.locale liveness note names the six seed-load builders and the locale each supplies - #30666

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-30607-seed-locale-ledger-note
Nov 5, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-30607-seed-locale-ledger-note

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Sales · project thread

domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P

Fixes #30607
Clause-②: no
Metadata-protocol: none

维护者速读

What changes

packages/spec/liveness/seed.json, the props.locale row: note and verifiedAt only (2 lines). status (live), evidence, producer, evidenceScope, every other row and the file's _note parse identical before and after. Plus one @objectstack/spec patch changeset.

The builders, counted from the code at b8929f48. Production SeedLoaderRequestSchema parses (tests excluded) give six request builders, the same number the old note gave. A control scan of every new SeedLoaderService( finds three more constructions (marketplace-install-local-plugin.ts#sampleDataInScope, #handlePurge, #handleSampleDataCount). All three call only buildDependencyGraph, never load(), so none of them is a request builder.

# Builder (path#function) Path(s) it serves Locale it supplies
1 packages/runtime/src/app-plugin.ts#start (inline boot seed) single-tenant boot seed the app's i18n.defaultLocale (resolveSeedLocale)
2 packages/runtime/src/app-plugin.ts#registerHotReloadSeeder dev hot-reload the same, off the boot bundle
3 packages/runtime/src/app-plugin.ts#start (the seed-replayer it registers) per-organization replay resolveSeedLocaleForLoad: the org's localization.locale when set (not source: 'default'), then the founder's sys_user.locale, then the app's i18n.defaultLocale
4 packages/cloud-connection/src/marketplace-install-local-plugin.ts#runInlineSeed marketplace install and sample-data reseed (applySideEffects), restart heal (maybeHealSampleData), the plugin's own per-org replayer (buildSeedReplayer, used only where no AppPlugin replayer is registered) resolveSeedLocaleForLoad: the setting, then the installing / reseeding user or the founder, then the package's i18n.defaultLocale (the heal has no user; the plugin's replayer has no app-default rung)
5 packages/runtime/src/domains/packages.ts#applyPublishedSeeds package apply none
6 packages/metadata-protocol/src/protocol-publish-batch.ts#applySeedBodies (the body protocol.ts#applySeedBodies delegates to) draft publish none

The note, FROM → TO, by sentence (every sentence not listed is unchanged byte for byte):

In the quotes below, PR #30346's closing line is spelled in words so that this body points a closing keyword only at this card. The note itself writes it in code.

  1. FROM "⛔ It does NOT assert that every path which can reach SeedLoaderService.load() supplies a locale — three do not, they are named below, …"
    TO "… — two do not, they are named below, …"
  2. FROM "Wire config.locale at the runtime's seed-load call sites — the locale axis added by #16510 is inert on the default boot path until a producer supplies it #16595 wired the THREE in packages/runtime/src/app-plugin.ts — the default boot path, which is what makes authoring locale change runtime behaviour and therefore what makes this row live."
    TO "FOUR supply a locale, each named by the function that builds its request:" followed by builders (1)–(4) above, each with its path#function and its locale source, then "Wire config.locale at the runtime's seed-load call sites — the locale axis added by #16510 is inert on the default boot path until a producer supplies it #16595 wired (1)–(3) in packages/runtime/src/app-plugin.ts — the default boot path, which is what makes authoring locale change runtime behaviour and therefore what makes this row live — and PR feat(runtime,cloud-connection,organizations): the marketplace install, sample-data reseed, restart heal and per-organization replay pick seed datasets by the organization's language #30346 (the PR that closed card 30281 [spelled in code in the note], merged 2026-11-05) moved (3) onto resolveSeedLocaleForLoad, keeping resolveSeedLocale as its last rung, and wired (4). A builder whose source answers nothing sends no locale key, never an 'en' guess."
  3. FROM "The other three are publish/install-time paths and still pass no locale: …/packages.ts#applyPublishedSeeds (package apply), …/protocol.ts#applySeedBodies (draft publish) and …/marketplace-install-local-plugin.ts#runInlineSeed (marketplace install)."
    TO "TWO are publish-time paths and still pass no locale: (5) packages/runtime/src/domains/packages.ts#applyPublishedSeeds (package apply) and (6) packages/metadata-protocol/src/protocol-publish-batch.ts#applySeedBodies (draft publish — the body packages/metadata-protocol/src/protocol.ts#applySeedBodies delegates to; the request moved out of protocol.ts with it)."
  4. FROM "None of the three is handed the stack config, and none passes env either, … and a locale has no ambient source, so it cannot be closed the same way."
    TO "Neither is handed the stack config, and neither passes env either, … and a locale has no ambient source inside load(), so it cannot be closed the same way: the four builders that supply one resolve it at the call site."
  5. The paragraph "RULED 2026-09-10 on Seed locale scope is silently inert on the three publish/install-time seed-load paths — package apply, draft publish and marketplace install pass no config.locale #17011 (director seat, one-class self-adjudication, option A 「不扩散」): … So this line is a DECISION, not a to-do." is unchanged: 653 characters, the same bytes, found once in the new note. ADDED right after it: "⚠️ NARROWED 2026-11-05 — the ruling above is kept as it was recorded, and its "three paths" and "three sites" are the 2026-09-10 set, marketplace install included. A maintainer ruling on Seed.locale: marketplace install, reseed sample data and per-org replay should select datasets by the installing organization's locale #30281 (2026-11-05, option A, reversing Seed locale scope is silently inert on the three publish/install-time seed-load paths — package apply, draft publish and marketplace install pass no config.locale #17011's install-path bound) ordered the install paths to pick datasets by locale, on HotCRM's request for zh-CN demo data rather than through the measurement the premise below names; PR feat(runtime,cloud-connection,organizations): the marketplace install, sample-data reseed, restart heal and per-organization replay pick seed datasets by the organization's language #30346 (the PR that closed card 30281 [spelled in code in the note], merged 2026-11-05) carried it out and moved the marketplace-install path, builder (4) above, across that bound. The ruling's bound now covers package apply and draft publish only — builders (5) and (6) — and SeedSchema.locale's describe (PR docs(spec): Seed.locale says which loads filter on it, and the ownership-queue contract says the registered service honours onFailedRead refuse #30604) and that docs page state it narrowed the same way."
  6. FROM "It is the live diagnostic for the three call sites above, for any embedding host that builds its own request, and for a stack that declares no i18n block — all of which …"
    TO "It is the live diagnostic for the two call sites above that pass none (package apply, draft publish), for any embedding host that builds its own request, for a stack that declares no i18n block (the boot seed and the dev hot-reload seeder have no other source), and, since 2026-11-05, for an install, reseed, heal or replay on which no rung of resolveSeedLocaleForLoad answers — all of which …". This reason was checked against the code: SeedLoaderService#warnOnUnresolvedLocaleScope returns early only when config.locale is set, and loadDatasets calls it on every load. resolveSeedLocaleForLoad returns undefined when no rung answers, and both of its callers then spread no locale key.
  7. ADDED at the end, after the "REPOINTED while flipping" paragraph: "RE-COUNTED 2026-11-05 against b8929f4 by the same scan of production SeedLoaderRequestSchema parses: still SIX builders, the six named above, with the draft-publish request now built in protocol-publish-batch.ts. A control scan of every new SeedLoaderService( finds no seventh: its three other constructions, in the marketplace plugin's sample-data scope, purge and count reads (sampleDataInScope, handlePurge, handleSampleDataCount), call only buildDependencyGraph and never load()."
  8. verifiedAt: 2026-09-09 → 2026-11-05, the YYYY-MM-DD form the sibling rows use.

Verification

All local readings are on head 0cd1455d86 (branch point b8929f48).

  • Liveness gate, pnpm --filter @objectstack/spec check:liveness: exit 0. Its two closing lines are both ✓: every property is classified and every repo-local evidence / producer pointer, path:NNN line and path#symbol anchor resolves; state-counts/ is current. Totals are unchanged: 1172 live · 1 experimental · 83 dead · 42 planned.
  • Derived families, node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, over 2 paths (+14 / −2 lines): 55 commands, all run with exit codes captured before any pipe. 55 × exit 0.
    • The first pass, before a build, had 51 × exit 0 and 4 × exit 3 (PREREQUISITE NOT MET, no dist/): check:dts-closure, check:dual-build-cjs-loads, check:lean-entry-closure and check:sourcemap-no-sources-content.
    • The full workspace build then ran under the verify lock: pnpm build --concurrency=2, 118/118 tasks, VERDICT command-exit 0. The working tree was still clean afterwards.
    • The whole sweep was then re-run on the built tree, and that second run is the table below. The build-reading verdicts it records: 295/295 declared .d.ts present across 115 packages; 116 require entry points load; 2 lean conditions are measured from a real load; 1276 source maps embed no source text.
  • Reconciliation, dispatch-gates.mjs --ran: "✓ 55 derived famil(ies) accounted for — 55 run, 0 NOT-MEASURED (a DERIVED zero — all 55 recorded an exit code and none of them is 3)". 0 UNRUN.
  • main moved during the run (47c457b23c, 9 commits). None of them touches seed.json or any file the note cites. The builder recount at that tip is the same six SeedLoaderRequestSchema parses and the same nine SeedLoaderService constructions.
  • CI-only families (artifact rosters, wide populations, the path-scheduled jobs, the type-check lanes) are not local readings. They are this PR's check-runs.
Derived families, second pass (55 × exit 0)
# Family (command as derived) Exit
1 node scripts/check-adr-0087-registration.mjs --base origin/main 0
2 node scripts/check-adr-0087-registration.mjs --self-test 0
3 node scripts/check-changeset-no-major.mjs --base origin/main 0
4 node scripts/check-closing-keyword-parity.mjs 0
5 node scripts/check-closing-keyword-parity.mjs --self-test 0
6 node scripts/check-comment-mask-adoption.mjs 0
7 node scripts/check-comment-mask-adoption.mjs --self-test 0
8 node scripts/check-comment-mask-corpus.mjs 0
9 node scripts/check-dev-prereqs.mjs --self-test 0
10 node scripts/check-dts-emitted.mjs --self-test 0
11 node scripts/check-empty-changeset.mjs --base origin/main 0
12 node scripts/check-empty-changeset.mjs --self-test 0
13 node scripts/check-issue-citations.mjs 0
14 node scripts/check-plugin-teardown-shape.mjs 0
15 node scripts/check-plugin-teardown-shape.mjs --self-test 0
16 node scripts/ci/assert-turbo-remote-cache.mjs --self-test 0
17 node scripts/ci/plan-test-core-shards.mjs --self-test 0
18 node scripts/ci/prune-turbo-cache.mjs --self-test 0
19 node scripts/docs-audit/check-affected-docs.mjs 0
20 node scripts/docs-audit/check-drift-comment.mjs 0
21 node scripts/pm/release-rehearsal-clone.mjs --self-test 0
22 node scripts/release-pending-publish.mjs --self-test 0
23 pnpm --filter @objectstack/spec run check:empty-state 0
24 pnpm --filter @objectstack/spec run check:liveness 0
25 pnpm --filter @objectstack/spec run check:strictness-ledger 0
26 pnpm --filter @objectstack/spec run check:variant-docs 0
27 pnpm check:changeset-gate-self-tests 0
28 pnpm check:ci-filter-parity 0
29 pnpm check:closed-ceremony-text 0
30 pnpm check:cross-package-test-inputs 0
31 pnpm check:doc-authoring 0
32 pnpm check:driver-memory-census 0
33 pnpm check:dts-closure 0
34 pnpm check:dual-build-cjs-loads 0
35 pnpm check:gitlink-declared 0
36 pnpm check:issue-citations 0
37 pnpm check:keyed-text-bounds 0
38 pnpm check:lean-entry-closure 0
39 pnpm check:merge-driver 0
40 pnpm check:nul-bytes 0
41 pnpm check:org-identifier 0
42 pnpm check:page-declaration-shape 0
43 pnpm check:platform-checklist 0
44 pnpm check:platform-object-tenancy-census 0
45 pnpm check:published-files 0
46 pnpm check:refd-timer-probe 0
47 pnpm check:registry-log-declared 0
48 pnpm check:rest-log-spy-declared 0
49 pnpm check:slot-lookup 0
50 pnpm check:sourcemap-no-sources-content 0
51 pnpm check:system-context-census 0
52 pnpm check:test-source-alias 0
53 pnpm check:tier-file-adoption 0
54 pnpm check:undeclared-dep-imports 0
55 pnpm check:watch-hint-literal 0

Acceptance notes

  • No pin owed. The liveness gate does not read note. It checks statuses, evidence / producer pointers (path:NNN lines, path#symbol anchors, key mentions) and the verifiedAt format and age. No test pins the note's text: git grep for its phrases outside seed.json finds only spec(seed): the Seed.locale docblock and .describe() say installing is locale-neutral, but the install paths now pick by the organization's locale #30347's changeset and the docs page, and they use their own wording. Every path#symbol the new note names was checked to exist in its file at b8929f48.
  • Changeset, not skip-changeset. liveness is in @objectstack/spec's package.json files, so seed.json ships in the tarball, and Check Changeset requires a changeset when the PR has no skip-changeset label. A patch changeset with both declaration lines, as fix(spec): repoint the query.searchFields liveness row at engine-find.ts#expandSearchOnAst #30368 and fix(spec): the page liveness ledger grades the app page record binding live, citing its console readers #30611 did for liveness-only edits.
  • Where the card's paraphrase and the code differ (the note follows the code): the draft-publish request is built in protocol-publish-batch.ts#applySeedBodies, and protocol.ts#applySeedBodies delegates to it. The sample-data reseed and the restart heal live in marketplace-install-local-plugin.ts (both go through runInlineSeed), not in app-plugin.ts. There are two per-org replayers: AppPlugin's, and cloud-connection's buildSeedReplayer, which is registered only where no replayer exists yet.
  • False sentences found outside this PR's file surface, not fixed here:
    • The same row's producer field says resolveSeedLocale is threaded "into all THREE SeedLoaderRequests this plugin builds: the inline boot seed, the per-org replayer registered for tenant provisioning, and the dev hot-reload seeder". Since PR feat(runtime,cloud-connection,organizations): the marketplace install, sample-data reseed, restart heal and per-organization replay pick seed datasets by the organization's language #30346 the per-org replayer passes resolveSeedLocaleForLoad's answer and uses resolveSeedLocale only as its last rung (packages/runtime/src/app-plugin.ts, the replayer closure in start).
    • The file-level _note cites packages/runtime/src/app-plugin.ts:832, :971 and packages/metadata-protocol/src/protocol.ts:6764 for the seed-load calls. At b8929f48 those lines are a closing brace, a datasource-routing docblock line and a search-403 docblock line. The calls are now at app-plugin.ts L1856 / L1951 / L2376, and the publish apply has moved to protocol-publish-batch.ts. The gate bounds path:NNN only in evidence / producer, so this has never been checked.
  • Kept as recorded, not re-measured: the note's "EVIDENCE FOR THE FLIP" paragraph (an ablation of resolveSeedLocale turned 5 of 7 cases red, covering all three AppPlugin call sites) is the 2026-09-09 reading. The per-org replay now resolves through resolveSeedLocaleForLoad, so a fresh ablation could read differently. No ablation was run here, because this PR changes no tested behaviour.

🤖 Generated with Claude Code

https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P

…ders and the locale each supplies

The locale row's note in packages/spec/liveness/seed.json listed the
marketplace install among the paths that pass no locale. Since the
install paths started picking seed datasets by locale, runInlineSeed
resolves one through resolveSeedLocaleForLoad, and so do the sample-data
reseed, the restart heal and both per-organization replayers.

The note now names all six SeedLoaderRequest builders by path#function
with the locale source of each, keeps the 2026-09-10 ruling paragraph
verbatim and adds a dated line that its bound now covers package apply
and draft publish only, and restates why warnOnUnresolvedLocaleScope
stays. status stays live; verifiedAt moves to 2026-11-05.

Co-authored-by: Claude <[email protected]>
Claude-Session: https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 5, 2026
@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/spec/liveness/seed.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/liveness/seed.json) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 170 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 47c457b23c6ee340490e2245cf160f4859917d57 → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P

维护者速读

席位核对

ACCEPT · head 0cd1455d86895a2fa96f7eb8bbb466a07698c908 · 2026-11-05T21:50Z

  1. 形态:
  2. 前提实测(origin/main):
  3. 门禁 check-runs:head 0cd1455d 共 41 条 check-run,读时 15 success、8 skipped、18 仍在跑,0 failure。全部跑完且无红才 pr_ready + automerge_enable。dev 本地:check:liveness exit 0;55 条派生门禁在全量构建后各跑一遍,全部 exit 0,--ran 对账 0 NOT-MEASURED(首轮四条 exit 3 是没构建出 dist/)。
  4. 席位自读(TIER_DEFAULT,全 diff):
    • note 的 FROM → TO 逐句读过:Seed locale scope is silently inert on the three publish/install-time seed-load paths — package apply, draft publish and marketplace install pass no config.locale #17011 裁决原文一段逐字不变;“three do not”改“two do not”;四个带语言的构建点各写明函数和语言来源;新加的 “NARROWED 2026-11-05” 句说明裁决按原文保留、它的 “three” 指 2026-09-10 那一组;warnOnUnresolvedLocaleScope 保留的理由改成包应用、草稿发布、嵌入宿主、没有 i18n 的栈,以及解析器各级都没答出的安装、重灌、自愈、回放;结尾加了 2026-11-05 的重新计数和对照扫描。
    • changeset 逐句核过:@objectstack/spec patch,Clause-②: no / Metadata-protocol: none,与认领一致。liveness/ 在包的 files 里,seed.json 随包发布,所以需要 changeset,不能用 skip-changeset。“No key, schema shape or export changes” 与 diff 一致。
  5. 接受的偏差:
    • main 在 dev 跑门禁期间前进到 47c457b2,没有合进来。那 9 个提交都没碰 seed.json 或 note 引到的文件,CI 在合并组里会按最新 main 再跑一遍。
    • dev 记下的范围外观察一:同一行 producer 字段括号里说 resolveSeedLocale 的结果进了 AppPlugin 的全部三个请求。dropped:L1795 证明它在按组织回放里仍是最后一级,这句话不完整但不算错;各级来源已在本 PR 的 note 里写全。它也不在本卡文件面内。
    • dev 记下的范围外观察二:文件顶层 _note 里的 app-plugin.ts:832, :971、protocol.ts:6764 已经指不到种子调用。dropped:门禁不读 _note,构建点的权威清单是本 PR 改好的 locale 行 note(按 path#function 写),这是行号漂移的卫生问题,没有人会因此改错东西,不立卡。
    • PR 没设 assignee 和 reviewer,Tier S 不交人。
  6. 范围外去向和 Skills-docs::没有 (narrowing),不欠 Skills-docs: 行。两条范围外观察都 dropped,理由见第 5 项。
  7. 落地条款:check-governed-merges.mjs --pr 30666 已在本 head 读过:2 个路径 0 个命中 governed 登记,16 行(+14 / -2)≤ 3000,属于 Tier S;落地前再读一次。CI 全绿后经 relay pr_ready + automerge_enable,跟到 MERGED,同一动作里摘 pm:dispatched。

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 5, 2026 22:12
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 5, 2026 22:12
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit 0c9aa82 Nov 5, 2026
65 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-30607-seed-locale-ledger-note branch November 5, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

1 participant