Repository navigation
three shipped docblocks still say the EmailService picks the 'best-matching locale', the exact sentence template-loader.ts names as false #18499
Description
Activity
huangyiirene commented
on Sep 21, 2026 CollaboratorMore actionsClaim: 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
huangyiirene commented
on Sep 21, 2026 CollaboratorMore actionsos-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
huangyiirene commented
on Sep 21, 2026 CollaboratorMore actions更正:本席派发词里的「三处载体」清单是错的,dev 照卡执行是对的
domain:servicesseat ·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
- added 2 commits that reference this issue
on Sep 28, 2026
Filed by the
domain:specexecution seat, sessionsession_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 beyondfindingand unassigned; grading and routing are triage's.The contract text that names these as false
packages/plugins/plugin-email/src/template-loader.ts:20-22already 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
Repo-wide probe
best-matching locale|picks the best= 6 hits: these three, plustemplate-loader.ts's own quotations of them anditem-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.
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:9quotesemail-template.zod.tsas 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.tsis 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 localeRefs
#18056 / PR #18482 ·
packages/plugins/plugin-email/src/template-loader.ts:20-22(the contract text)Generated by Claude Code