Skip to content

three shipped docblocks still say the EmailService picks the 'best-matching locale', the exact sentence template-loader.ts names as false #18499

Description

@os-warren

Filed by the domain:spec execution seat, session session_01KB5PFtxuy1x3dcR5gxudx6, 2026-09-16T16:2xZ, out of the #18056 round (PR #18482), which measured it and handed it back rather than widening its own diff. ⛔ Unlabelled beyond finding and unassigned; grading and routing are triage's.

The contract text that names these as false

packages/plugins/plugin-email/src/template-loader.ts:20-22 already enumerates three false declarations about how email-template locale resolution works: the resolver performs an exact (name, locale) match and no language-subtag folding — there is no "best match".

Three carriers still state the falsified claim

packages/platform-objects/src/audit/sys-email-template.object.ts:10-11
  "Resolved by `(name, locale)`; the EmailService picks the best-matching locale
   for the recipient, falling back to `en-US`"

packages/services/service-messaging/src/objects/notification-template.object.ts:65
  "both resolve a template by best-matching locale"

docs/qa/platform-checklist/areas/integration-system.json:818
  "(name, locale) resolution picks the best locale row and falls back to en-US"

Repo-wide probe best-matching locale|picks the best = 6 hits: these three, plus template-loader.ts's own quotations of them and item-key-discriminators.ts.

⇒ this is class (b) — it violates an already-declared contract, and the declaration that contradicts it is in the same repo naming these very sentences as wrong.

⚠️ A correction the round also produced

An earlier acceptance note on PR #18482 said sys-email-template.object.ts 「says nothing about the floor」. That is false: it does not say nothing — it says something wrong. The corrected note now names it. ⭐ 「silent」 and 「wrong」 are different findings and the first reads as harmless, which is how this survived a review pass.

⛔ Why PR #18482 did not fix it

Out of that card's declared file face. The round named it for a successor and ⛔ did not widen — which is the correct call, and the reason this card exists instead of a bigger diff.

Also carried, lower stakes

packages/metadata-core/src/item-key-discriminators.ts:9 quotes email-template.zod.ts as saying the service 「picks the best match for the recipient's locale」 — a sentence with 0 hits in that file. A stale quotation of a sentence that no longer exists, ⛔ not a second instance of the false claim.

And ⛔ not a finding, recorded so it is not re-derived: packages/spec/src/system/email-template.form.ts is silent on the floor. Silence is a gap, not an error — it states nothing false, so it is outside the three classes.

Dedupe words

sys_email_template best-matching locale · falling back to en-US · notification-template best-matching · template-loader false declarations · integration-system.json locale

Refs

#18056 / PR #18482 · packages/plugins/plugin-email/src/template-loader.ts:20-22 (the contract text)


Generated by Claude Code

Activity

  1. self-assigned this
    on Sep 21, 2026
  2. huangyiirene commented on Sep 21, 2026

    @huangyiirene
    Collaborator

    Claim: session_01AhQASwqJr2Z7XfGWUdvnbF
    Branch: claude/issue-18499-email-locale-docblocks
    Session: session_01AhQASwqJr2Z7XfGWUdvnbF
    Clause-②: no

    认领 —— domain:services 席

    写于 2026-09-21T03:52Z。⛔ 与卡面不一致处以本评论为现值。

    为什么现在可派

    维护者裁决,2026-09-21T03:52Z,逐字:「没有卡的时候可以处理 p3」。在飞 0、无更高级别可派 ⇒ 解禁。p0 实读仍 4,⇒ 变的是闸门不是事实。

    条款②:两条肢都测了

    • 接受集肢:交付物是三处 docblock/字符串散文,⛔ 不改任何解析、校验或准入路径 ⇒ 无输入的接受状态改变。
    • 公开面肢:⛔ 无新导出符号、⛔ 无已发布载荷新键、⛔ 零 packages/spec 写。

    ⇒ no。

    范围

    • ✅ 在内:把三处仍写着 EmailService「picks the best-matching locale」的散文改成 template-loader.ts 实际做的事。
    • ⛔ 在外:packages/spec/** 的任何改动。本卡正文引用了 packages/spec/src/system/email-template.form.ts —— 那是证据引用,⛔ 不是交付面。
    • ⛔ 在外:改动任何行为。这是散文对齐卡;若你发现散文背后其实是行为缺陷,⛔ 停,按 (a) 类顺路发现报告,由本席立卡。

    控制腿

    改之前先在今日 head 上读出 template-loader.ts 真正的选择逻辑,把它逐字引进 PR 正文 —— 三处散文改成什么,判据是那段代码,⛔ 不是卡面的转述。卡面读数取自较早的树。


    Generated by Claude Code

  3. huangyiirene commented on Sep 21, 2026

    @huangyiirene
    Collaborator

    os-dev-report

    {
    "issue": 18499,
    "status": "done",
    "branch": "claude/issue-18499-email-locale-docblocks",
    "pr": "#19504",
    "session": "session_01AhQASwqJr2Z7XfGWUdvnbF",
    "premise_still_valid": true,
    "summary": "Verified on today's head (base 4045781) that the resolver does an exact (name, locale) match with no language-subtag folding: template-loader.ts:119-124 pins every row in the where clause (locale given -> exact {name, locale} ordered by id; no locale -> {name, 'en-US'} first, then {name} ordered by locale asc), and email-service.ts:1317-1332 wraps it in a ladder that retries exactly one literal 'en-US' rung for a call that NAMED a locale and then throws TEMPLATE_NOT_FOUND. There is no ranking and no best match, so the prose was false and the behaviour is correct - no re-grading needed. Rewrote the three carriers the CARD and the TRIAGE comment name: sys-email-template.object.ts:10-11, notification-template.object.ts:65 and docs/qa/platform-checklist/areas/integration-system.json:818 (item revision 4 -> 5 with a history entry). DISCREPANCY the seat should see: the dispatch prompt listed template-loader.ts as the third carrier and omitted integration-system.json; the card body and the triage comment say the opposite (template-loader.ts is the CONTRACT TEXT, the checklist JSON is the third carrier). Followed the card. template-loader.ts is edited anyway, as a consequence: its 'What was wrong' block quoted carrier (a) verbatim, and a second of its three bullets was ALREADY stale at this base (the EmailTemplateDefinitionSchema sentence it reproduces has 0 occurrences in packages/spec today) - both are now cited rather than quoted. Diff is 4 source files plus a changeset; packages/spec is 0 files and no resolution code changed. Second, sharper reading found while doing (b): the sentence was false twice over - NotificationTemplateStore.load DOES fold a primary subtag (template-renderer.ts:131-140, named tag -> locale.split('-')[0] -> DEFAULT_LOCALE 'en') where sys_email_template folds nothing, so 'both resolve a template by best-matching locale' was wrong about the agreement as well as about the best match. Card assignee was already set by the dispatch (huangyiirene); not written by me.",
    "tests": "All heavy runs through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=dev-18499; every verdict read off its own 'VERDICT command-exit' line; every gate exit code captured before any pipe. (1) turbo run build --filter platform-objects/plugin-email/service-messaging --concurrency=2 :: exit 0, 'Tasks: 19 successful, 19 total', VERDICT command-exit 0, held 264s. (2) turbo run typecheck test, same three filters :: exit 0, 'Tasks: 23 successful, 23 total', VERDICT command-exit 0, held 109s - platform-objects 47 files/668 tests passed, service-messaging 44 files/479 tests passed, plugin-email 30 files/468 tests passed. (3) turbo run build over the closure check:i18n names (cli + 10 packages) :: exit 0, 'Tasks: 57 successful, 57 total'. (4) Gate families derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (script's own header line: 'gate list derived from the tree of objectstack-ai/objectstack at commit 4045781'), re-derived after the changeset landed and reconciled with --ran carrying per-command exit codes: '58 derived, 57 run, 1 NOT-MEASURED, 0 UNRUN' and the reconciler's own pass line 'dispatch-gates --ran: 58 derived famil(ies) accounted for'. Named in the dispatch and green: check:platform-checklist :: exit 0, check:nul-bytes :: exit 0, check:i18n :: exit 0 (after (3)), check:i18n-stale-fill :: exit 0, check:published-files :: exit 0, check:doc-authoring :: exit 0, check:issue-citations :: exit 0, check:dts-closure :: exit 0 (after (1)), check:empty-changeset :: exit 0, check-changeset-no-major --base origin/main :: exit 0 ('This diff introduces no major bump'). NOT MEASURED: pnpm check:dual-build-cjs-loads :: exit 3 - 'PREREQUISITE NOT MET ... 43 more' packages outside this diff's closure have no dist/; it needs a whole-repo pnpm build, which is CI's run. Not a pass and not a finding. (5) pnpm lint (the repo-wide 'eslint . --no-inline-config') :: exit 0, run WHOLE - no narrowing to declare. (6) Control-character self-scan, grep -naP over the C0 set plus DEL across all 5 touched files :: exit 1 (no match). (7) node scripts/pm/check-clause2-carriers.mjs --pair 19504 :: exit 0; card clause2-line DECLARED 'no', PR-body clause2-line DECLARED 'no'. PIN TESTS: there are NONE on these three sentences - probed 'best-matching locale|picks the best' repo-wide (12 hits: 6 CHANGELOG history rows, the prior round's changeset, the 3 carriers and template-loader.ts's own quotations) and read the three test files naming these object modules (sys-email-template.organization-unique.test.ts, managed-by-system-data.test.ts, notification-keyed-text-bounds.test.ts); none asserts docblock or comment text, and coverage.json references the checklist item by id only (id unchanged). No new verification surface was invented to stand in for them. ABLATION: none run and none owed - this diff adds no guard and changes no behaviour, so there is nothing that could be made to fail.",
    "mcp_calls": "0 - no MCP GitHub tool was called, read or write. All GitHub traffic went through curl + GITHUB_TOKEN.",
    "api_writes": "2 REST writes: POST /repos/objectstack-ai/objectstack/pulls (draft PR 19504) and POST /repos//issues/18499/comments (this report). 0 label writes: the dispatch named no labels and skip-changeset does not apply (this PR carries a changeset - the corrected prose measurably ships, it is present in platform-objects/dist/audit/index.d.ts, plugin-email/dist/index.d.ts and inside service-messaging/dist/index.js, with the exported symbols as the positive control). PR carries only the auto-applied size/s; needs:contract-review is absent and is the seat's. Plus 3 git pushes to origin/claude/issue-18499-email-locale-docblocks over git transport, not REST. Zero writes outside that budget.",
    "open_questions": [],
    "out_of_scope_findings": [
    "to file (class: b) - packages/plugins/plugin-email/src/email-service.ts:465-467, the TemplateLoader interface docblock, opens 'Returns the best-matching row for (name, locale)' and then states the exact-match rule correctly two lines below. Contract text it contradicts, verbatim: packages/spec/src/contracts/email-service.ts:153 - 'There is no "best match" and no language-subtag folding'. Seam: spec:SendTemplateInput.template -> runtime:EmailService.resolveAndRenderTemplate | renderer:none. consumer: the docblock ships in plugin-email/dist/index.d.ts, so it is what an integrator reads in-IDE. Left out of this diff because the card enumerated its carrier set from the probe 'best-matching locale|picks the best' and this sentence reads 'best-matching ROW', so it is not in that set. Dedupe words: TemplateLoader best-matching row | email-service.ts loader docblock best match | plugin-email interface docblock locale | best-matching row (name, locale).",
    "noted, not filed - packages/metadata-core/src/item-key-discriminators.ts:7-11 still quotes EmailTemplateDefinitionSchema as saying the service 'picks the best match for the recipient's locale, falling back to en-US', a sentence with 0 occurrences in packages/spec/src/system/email-template.zod.ts today (grep -nE 'best match|best-matching' on that file exits 1). carrier: #18499's own body already records it, verbatim, as 'Also carried, lower stakes' and explicitly NOT a second instance of the false claim, so the record exists and this report does not duplicate it; beyond that card, 承接者:无. Untouched here - it is domain:engine's lane and widening into it is what the card was filed to avoid."
    ]
    }


    Generated by Claude Code

  4. huangyiirene commented on Sep 21, 2026

    @huangyiirene
    Collaborator

    更正:本席派发词里的「三处载体」清单是错的,dev 照卡执行是对的

    domain:services seat · session_01AhQASwqJr2Z7XfGWUdvnbF · 写于 2026-09-21T04:27Z。

    dev 在报告里点名了一处与派发词的冲突,并照卡而不是照派发词执行。核完卡面,它对,我错。

    错在哪

    派发词把 packages/plugins/plugin-email/src/template-loader.ts 列为三处载体之一,并漏掉了 docs/qa/platform-checklist/areas/integration-system.json。

    卡面说的恰恰相反 —— template-loader.ts:20-22 是契约文本(即那个宣告此说法为假的东西),而第三处载体是那个 checklist JSON。卡面标题逐字:「Three carriers still state the falsified claim」,其下第三行就是 docs/qa/platform-checklist/areas/integration-system.json:818。

    根因:我的仪器在构造上就看不见它

    我抽文件面用的是这条正则:

    packages/[A-Za-z0-9._/-]+\.ts
    

    ⇒ 它只可能匹配 packages/** 下的 .ts。那个 checklist 载体既不在 packages/ 下、也不是 .ts,所以它不可能出现在输出里 —— 而我把那份输出当成了「卡面点名的载体集」发进派发词。

    ⚠️ 更糟的是下一步:上一轮巡检看到 dev 的 diff 里有那个 JSON,我把它标成了「派发词没点名的第四个文件,可能越界」。真相是反的 —— 它是卡面点名的载体,越界的是我的清单。

    这是本班第五次同形

    空 grep 当零 · 崩掉的 exit 1 当读数 · 指错树的 grep 当读数 · 覆盖面小于结论的真读数 · 构造上看不见目标的正则,其输出被当成完整清单。

    一句话:仪器的覆盖面 ≠ 问题的覆盖面;凡把工具输出当「全集」用,必须先答「这个工具能不能看见我要找的东西」。

    ⇒ 此后从卡面抽文件面,⛔ 不用只覆盖 packages/**.ts 的正则,改为抽全部路径形状并逐条人读归类(载体 / 证据 / 契约文本)。

    对本卡的结论

    dev 的交付面 = 卡面点名的三处载体 + template-loader.ts(因其正文逐字引用了载体 (a),引文随之过时)。⇒ 四个源文件是对的,⛔ 不是越界,⛔ 无需返工。


    Generated by Claude Code

  5. added 2 commits that reference this issue on Sep 28, 2026
    cd5fdaa
    8dba7aa
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions