Repository navigation
docs(spec): Seed.locale says which loads filter on it, and the ownership-queue contract says the registered service honours onFailedRead refuse - #30604
Conversation
…ed, heal and per-organization replay pick by the resolved locale Co-authored-by: Claude <[email protected]> Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa
…ibe, and add the changeset Co-authored-by: Claude <[email protected]> Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa
…honours onFailedRead 'refuse', the ledger posture stays, and when isMember answers true beside a failed read Co-authored-by: Claude <[email protected]> Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 170 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 a7f87461e3274e7f136ee324cde1110709056f40 && git checkout a7f87461e3274e7f136ee324cde1110709056f40
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin ffeda137b8412b11c909a6d00357f46e0cd555d2 d0863ab931e735fbe32bbf98fa30d8eab5092063 && git checkout -B drift-repro ffeda137b8412b11c909a6d00357f46e0cd555d2 && git merge --no-ff d0863ab931e735fbe32bbf98fa30d8eab5092063
node scripts/docs-audit/affected-docs.mjs --json ffeda137b8412b11c909a6d00357f46e0cd555d2
|
|
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa Contract-review-claim: session_01L6bhgTqqeHSwZYJmApbDCa · head 9d61fa4 · 2026-11-05T17:48Z Full review at Generated by Claude Code |
|
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa Contract reviewServed-tier: Inputs: cards #30347 and #30389 (bodies, triage, claims, dev report 6665047586 and its pointer), PR #30604 body, file list and net diff against the merge base ① Derived judgments
② Semver level
③ Boundary flagsEvery dev flag answered;
④ Design judgmentEach new sentence judged against the code it cites on
Findings. Must-fix: none. Should-fix: the two Gate verdicts on this head (every run completed; read 2026-11-05T18:15Z): 65 check-runs — 57 Implemented-by: VERDICT: PASS Generated by Claude Code |
… says an organization-less load still reads the environment or global locale setting Co-authored-by: Claude <[email protected]> Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa
… member set would be incomplete Co-authored-by: Claude <[email protected]> Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa
Co-authored-by: Claude <[email protected]> Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa
|
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa Contract review — deltaServed-tier: Delta of the record at 6665662379 (head The merge (
|
…origin/main Co-authored-by: Claude <[email protected]> Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa
…th no organization — the deployment's one organization's own setting Co-authored-by: Claude <[email protected]> Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa
|
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa Contract review — deltaServed-tier: Delta of the records at 6665662379 (
Gate verdicts on this head (every run completed; read 2026-11-05T20:02Z): 69 check-runs — 59 Implemented-by: VERDICT: PASS — must-fix: none; should-fix: none outstanding. Generated by Claude Code |
|
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa 维护者速读
席位意见:两张卡(#30347、#30389)合在一个 PR 里收,都只改说明文字。契约复审三轮 PASS:第一轮提了 3 条措辞上的建议,第一轮修补全部落实;第二轮复审又发现「不指定组织的加载」少写了一个取值来源(只有一个组织的部署会用到该组织自己的设置),第二轮修补补上,第三轮确认无遗留。复审发现的台账备注过时,另立了 #30607。 席位核对 — ACCEPT · domain:spec#3 · head
|
domain:spec#3 · os-sales · session_01L6bhgTqqeHSwZYJmApbDCa
Requested by Sales · project thread
Fixes #30347
Fixes #30389
Clause-②: no
Metadata-protocol: none
维护者速读
@objectstack/spec的两处说明文字,不改任何代码或 schema 形状。①Seed.locale的说明不再说"安装不按语种挑":现在写明启动种子按应用的i18n.defaultLocale;市场安装、重灌示例数据、重启自愈、按组织回放按"组织设置 → 安装/创建人语言 → 应用默认"挑;包应用和草稿发布仍不挑。② 队列服务契约不再说"注册的服务还不支持'refuse'",写明激活台账读失败仍按"开启"是已定的决定,并写明isMember在'refuse'下何时答true、何时拒绝。.describe()文案和由它生成的四个参考页,运行时零变化。回滚即撤 PR。packages/spec/src/data/seed.zod.ts(locale的说明,三级取值那一段);packages/spec/src/contracts/ownership-queue-service.ts(isMember文档新增的四句)。git grep -n "do not filter by locale" content/docs/references packages/spec/src,预期每处命中都是"package apply and draft publish do not filter by locale",不再有"The publish and install paths"。What changes
Wording only, in one package (
@objectstack/spec,patch). Each new sentence below names the line onorigin/main(ffeda137b, merged into this branch in round 2) it rests on.#30347:
SeedSchema.locale(packages/spec/src/data/seed.zod.ts)Before (docblock): "Publishing and installing are locale-neutral acts — this axis is scoped to the boot path, by decision. …
SeedLoaderConfig.locale, which only the boot path supplies … Package apply, draft publish and marketplace install each build their own load request and pass no locale …"Before (
.describe()): "The publish and install paths do not filter by locale — they load every dataset and warn"After: the docblock paragraph becomes three bullets, and the
.describe()says the same in one sentence. Round 1 (contract review should-fix 1 and 2) names the reseeding user in the.describe()and says what rung 1 reads for a load that names no organization.locale-scoped dataset for every locale, and the loader warnspackages/runtime/src/seed-locale.ts:30-32(no rung ⇒undefined,warnOnUnresolvedLocaleScope);marketplace-install-local-plugin.ts:5305-5307(spread, neverlocale: undefined)i18n.defaultLocalepackages/runtime/src/app-plugin.ts:1937(boot) and:2367(hot reload), boththis.resolveSeedLocale(), which readsi18n.defaultLocaleat:2299-2303resolveSeedLocaleForLoadresolvespackages/cloud-connection/src/marketplace-install-local-plugin.ts:5239-5242(applySideEffects, reached by install:2537and reseed:4376),:1465(restart heal),:1728(that plugin's own replayer);packages/runtime/src/app-plugin.ts:1825-1830(the AppPlugin per-organization replayer). All four go throughrunInlineSeed(:5287-5292) or call the producer directlylocalization.localesetting for the organization, only whensourceis not'default'seed-locale.ts:135-140globalsetting, then, where no wall stands and the deployment holds exactly one organization, that organization's own settingseed-locale.ts:137(settings.get('localization', 'locale', {})when no organization is named);packages/services/service-settings/src/settings-service.ts:1951-1966(the env override answers before any row is read),:2119and:2175(the cascade order global, tenant, default, first non-null wins),:2137-2149(the tenant rung, read for a tenant-scoped key:localizationisscope: 'tenant',manifests/localization.manifest.ts:39);settings-service.ts:2221-2227(organizationReachOfhands an organization-less caller toresolveOrganizationReach),packages/core/src/security/organization-reach.ts:87-95(no wall ⇒ the derived organization becomes the reach),packages/core/src/security/resolve-authz-context.ts:1676-1696(resolveGuestOrganization) andpackages/core/src/security/system-write-organization.ts:115-124(singleposture and exactly onesys_organization⇒derived); the heal passes no organization (marketplace-install-local-plugin.ts:1465)sys_user.localeof the user who installs, reseeds or founds, when one started the load (the.describe()now says "the installing, reseeding or founding user")seed-locale.ts:142-153; install passesadmission.userId(marketplace-install-local-plugin.ts:1744to:2537to:5239-5241), reseed passes the reseeding user'sadmission.userId(:4376to:5239-5241), the heal passes no user (:1462-1465)i18n.defaultLocale, when the caller names oneseed-locale.ts:128-129, 155; the marketplace plugin's own replayer passes none (marketplace-install-local-plugin.ts:1723-1728)seed-locale.ts:34-39(the throw reaches the caller, which writes nothing)packages/runtime/src/domains/packages.ts:4000-4007andpackages/metadata-protocol/src/protocol-publish-batch.ts:115-125: neither request carrieslocaleseed-locale.ts:7-9("maintainer ruling A, 2026-11-05 … reversing the install-path bound recorded onSeedSchema.locale")The
.describe()change regenerates four references pages, all committed:content/docs/references/data/seed.mdx,data/seed-loader.mdx,api/package-api.mdx,kernel/manifest.mdx.#30389:
packages/spec/src/contracts/ownership-queue-service.ts@objectstack/plugin-sharing's, honours'refuse'from plugins: a queue sharing recipient still revokes grants on a member-table outage, because the queue expander answers "nobody" for every consumer; refuse for the sharing-grant pass and the approver slate (ADR-0142 amendment first) #29604's code half on, so until then a caller passing'refuse'still gets'nobody'." After: "the registered one,@objectstack/plugin-sharing's, honours'refuse'." Rests onpackages/plugins/plugin-sharing/src/ownership-queue-service.ts:270-279(expandMembers) and:290-297(isMember), which takeonFailedReadand wrap a failure inqueueReadRefusal(:168).positionrecipients, so a queue's position and a rule's position cannot disagree during an outage." Rests onownership-queue-service.ts:670-688(switchedOffcatches the ledger read and returns nothing switched off, under either answer) andpackages/plugins/plugin-sharing/src/sharing-rule-service.ts,readPositionActive(a failed ledger read answers active).isMember's doc: "Under'refuse'the registered service reads the queue's own rows (sys_queue,sys_queue_member) first, and a failure there rejects at once, since without them the queue's member set would be incomplete (a declared queue's own specifications come from the registry, but its authored additions come fromsys_queue_member). Past them it answerstrueas soon as a read that succeeded reachesuserId, even beside a failed read, and rejects only when no successful read reachesuserIdand one failed." Rests onownership-queue-service.ts:232-261(resolvereadsauthoredQueueRowandauthoredMemberSpecswithrefusebefore any specification; a declared queue's specifications come fromdeclaredMemberSpecsat:243, its authored additions fromauthoredMemberSpecsat:237) and:476-496(specsReachUser: returnstrueon the first reaching spec, keeps the first failure, throws it only after the walk). Round 1 (contract review should-fix 3) replaced the earlier reason, "since without them the call does not know what to ask", which overstated it for a declared queue.Left as it was, because it is true: the
'nobody'bullet still says the admission consumers (D3, D4, D5) take'nobody'. Measured:sharing-service.ts:952,security-plugin-authz-middleware.ts:1610andobjectql/src/assignment-rules.ts:293call without the option; only D6 (approval-service.ts:3541) and D7 (sharing-rule-service.ts:1752,:2198) pass'refuse'.Tests
No behaviour changed, so no new test. Round 2 readings were taken on head
d0863ab93(after mergingorigin/mainffeda137b).pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/data/seed.test.ts src/data/seed-loader.test.ts src/data/seed-file.zod.test.ts src/data/define-seed-record-keys.test.ts: 4 files, 111 tests passed (the spec tests that touchseed.zod.ts; round 2 changes no other file's source).pnpm --filter @objectstack/spec build, thengen:docs, thencheck:generated: "All 14 generated artifacts are up to date".pnpm --filter @objectstack/spec typecheck: exit 0, 0 errors.seed.zod.ts: exit 0.node scripts/check-changeset-no-major.mjs --base origin/main --event(this body as apull_requestevent): exit 0, "a non-protocol change atpatch".node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 96 commands, run after a fullturbo run build(119/119), all exit 0, exit codes recorded before any pipe.--ran: "96 derived, 96 run, 0 NOT-MEASURED, 0 UNRUN".Acceptance notes
'nobody'was already stated and still holds (see above).isMemberunder'refuse'does not answertruebeside every failed read. A failedsys_queueorsys_queue_memberread rejects before any specification is read, even for a declared queue whose positions might reach the user (PR fix(plugin-sharing)!: the ownership-queue service refuses a failed member read when the caller asks, and the approver slate and the sharing-recipient grant recompute ask #30386's acceptance notes say the same). The doc says so, so that "rejects only when no successful read reaches the user" is not read as covering the queue's own rows.localerow note inpackages/spec/liveness/seed.jsonstill says the marketplace install passes no locale and calls publish and install locale-neutral. Same defect class; not touched here because the claim covers onlyseed.zod.ts,ownership-queue-service.ts, the regenerated pages and one changeset, and the note is a long ruling record, not a mechanical edit. Reported to the seat.9ba263492) after the source commit (3bbc3eb9b), because a force-push to fold them in was refused in this session. spec(ownership-queue-service): the onFailedRead docblock still says the registered service does not honour 'refuse' yet #30389 is the third commit (9d61fa4aa).d56c29454(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, rung 1 and the reseeding user),d0db2c6a9(spec(ownership-queue-service): the onFailedRead docblock still says the registered service does not honour 'refuse' yet #30389, theisMemberreason),8629666d9(the four regenerated references pages). The liveness-note finding is filed separately as spec liveness: the Seed.locale row's note in liveness/seed.json still says the marketplace install passes no locale and that install is locale-neutral by ruling #30607.origin/mainwas merged in first (871582d63); the moved citations (packages.ts,approval-service.ts) are updated above.8629666d9(PASS, one should-fix) found rung 1's organization-less parenthetical read as exhaustive while missing a third source, the deployment's one organization's own row.d0863ab93adds it to the docblock; the.describe()and the changeset are unchanged (their wording stays true).origin/mainffeda137bwas merged first (e2f2e2175), and15456e098regeneratespackage-api.mdxafter that merge (its only difference fromorigin/mainis the twolocalerows). The marketplace plugin moved in that merge, so its line citations above are re-measured.packages/spec/CHANGELOG.mdstill carries the released "publish and install paths do not filter by locale" entry. It is release-owned and correct for the release that shipped it; not edited.Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa