docs(configure): the notification template locale is the notification's, not the recipient's - #255

Merged
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient
Sep 2, 2026
Merged

docs(configure): the notification template locale is the notification's, not the recipient's#255
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient

Conversation

@os-bill

Copy link
Copy Markdown
Collaborator

Fixes#246

The Notification Templates field table told an admin that a template's locale is "matched to the recipient". The delivery path never reads a recipient locale, so authoring es and en rows for a topic cannot give two recipients their own languages — it gives whichever locale the producer named.

What changed

content/docs/configure/notifications.mdx, two edits carrying one claim:

  • The field-table row now reads Locale of this rendering — the notification's own, not the recipient's.
  • A paragraph after the table carries the consequence: the locale is payload.locale when the producer sets one, else the deployment default, and one emit renders in a single locale for every recipient it reaches.

The wording is aligned to upstream's own phrasing at messaging-service-plugin.ts:250 — "one locale per notification: payload.locale, else the deployment default" — rather than a third coinage.

This reports the wiring as it stands. It makes no forecast about recipient-locale matching, and it does not touch the question of whether the platform should match on recipient locale — that is a product question and a different card.

Upstream re-trace

Re-measured on objectstackorigin/main @ 2514d49. The card measured 9e0ba21 and dispatch expected 90ff957; both were stale, so this was re-read rather than quoted forward. Every claim in the card survives:

SiteReading
messaging-service.tszero occurrences of locale, in 1095 lines
recipient-resolver.tszero occurrences of locale — the file whose whole job is resolving recipients
email-channel.ts:224const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;
sms-channel.ts:124byte-identical to the line above; md5 of each line is ec055715f3db3f6cbcf5ddd08af48185
inbox-channel.ts:143-145payload.locale, else getDefaultTemplateLocale()
messaging-service-plugin.ts:148-156getDefaultTemplateLocale resolves i18n.getDefaultLocale()

Control-probed, because a zero from a path-scoped grep is worth nothing on its own. The same probe returns 41 hits in email-channel.ts, 14 in sms-channel.ts, 14 in inbox-channel.ts and 21 in messaging-service-plugin.ts; and inside messaging-service.ts itself, read the same way, it returns 52 recipient, 33 emit and 95 channel. The absence is real, not a broken pathspec.

The last row is also why the existing "Where to go next" link — "Set locale defaults that templates match against" pointing at Localization — stays accurate: the deployment default really is the tenant Localization setting.

For a reviewer wondering whether this is upstream drift rather than intent: objectstack#12178 and objectstack#12446 record a maintainer ruling of 2026-08-13 that this resolution is deliberate, and note that sys_user carries no locale column for a channel to read. That sweep's PR objectstack#12505 is why messaging-service-plugin.ts:250 reads honestly today.

Verification

All gates below ran on a059c27, the final commit, against a clean worktree. Each row quotes the gate's own conclusion.

GateExitIts own verdict
turbo run type-check build --filter=@objectos/docs0Tasks: 2 successful, 2 total · Cached: 0 cached, 2 total — both ran, neither replayed
check-locale-surface.mjs (reads the BUILT sitemap)0"every advertised URL has a source file and every source file is advertised" — sitemap.xml 409 read / 409 expected / 0 unexpected / 0 missing
check-translations.mjs (freshness)0"translations gate passed"
check-translation-ownership.mjs0"This PR touches 0 translation artifact(s) and 1 other file(s)". Reported alongside it: "TRANSLATION_BOT_LOGIN is not set — ownership is not enforced yet", so the rule itself is inert; the load-bearing half is the 0-artifact count, which is a real measurement
check-translation-output.mjs --files0"translation output gate passed (139 pre-existing finding(s) reported)" — none in this diff
gen-zh-hant.mjs --check0"zh-Hant: 73 generated file(s) match the zh-Hans sources byte for byte"
check-node-floor.mjs0"Every declared floor clears what the dependency tree requires"
turbo run test01 successful — a legitimate cache hit: the test task declares no content/docs/** input, so this diff cannot affect it
control-byte self-scancleanno bytes in the U+0000-U+001F / U+007F range in the edited file

Rendering was confirmed on the build artifact, not just on the source: the corrected row and the new paragraph appear in apps/docs/.next/server/app/en/docs/configure/notifications.html, and the string "matched to the recipient" appears zero times anywhere under apps/docs/.next/.

Scope

content/docs/configure/notifications.mdx only.

No locale siblings were touched, and none exist: this page is one of the English-only pages, so the whole translation family is a no-op here rather than merely left alone.

I checked whether anything PR #247 added implies recipient-locale matching by implication. It does not — the "What each channel renders" table names locale as a bare match key without attributing it to anyone, and with the field-table row corrected its antecedent is now unambiguous. No edits were manufactured there.


Generated by Claude Code

…ecipient's
The Notification Templates field table told an admin that a template's `locale`
is "matched to the recipient". The delivery path never reads a recipient
locale: `messaging-service.ts` contains zero occurrences of `locale` (control-
probed against 41/14/14 in the sibling channel files), and `recipient-
resolver.ts` — the file whose whole job is resolving recipients — has zero as
well. Both template channels resolve it identically, byte for byte:
`email-channel.ts:224` and `sms-channel.ts:124` are
`const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;`,
and the inbox notify-template path takes `payload.locale` else
`getDefaultTemplateLocale()` (`inbox-channel.ts:143-145`), which reads
`i18n.getDefaultLocale()`.
So the locale is the notification's own, and one emit renders in a single
locale for everyone it fans out to. The page was inviting an admin to author
`es` and `en` rows expecting two recipients to read in their own languages,
which cannot pay off. Corrected the field-table cell and stated the
consequence next to the table, aligned to upstream's own phrasing at
`messaging-service-plugin.ts:250` ("one locale per notification: payload.locale,
else the deployment default") rather than coining a third wording.
Reports the wiring as it stands; makes no forecast about recipient-locale
matching.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ChPQM8jamxLUfUAxwFpJ8S
@os-bill
os-bill marked this pull request as ready for review September 2, 2026 15:24
@os-bill
os-bill merged commit ac65e7e into mainSep 2, 2026
3 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] configure/notifications.mdx says a template's locale is "matched to the recipient" — the delivery path never reads a recipient locale

2 participants

@os-bill@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

docs(configure): the notification template locale is the notification's, not the recipient's - #255

Merged
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient
Sep 2, 2026
Merged

docs(configure): the notification template locale is the notification's, not the recipient's#255
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient

Conversation

@os-bill

Copy link
Copy Markdown
Collaborator

Fixes#246

The Notification Templates field table told an admin that a template's locale is "matched to the recipient". The delivery path never reads a recipient locale, so authoring es and en rows for a topic cannot give two recipients their own languages — it gives whichever locale the producer named.

What changed

content/docs/configure/notifications.mdx, two edits carrying one claim:

  • The field-table row now reads Locale of this rendering — the notification's own, not the recipient's.
  • A paragraph after the table carries the consequence: the locale is payload.locale when the producer sets one, else the deployment default, and one emit renders in a single locale for every recipient it reaches.

The wording is aligned to upstream's own phrasing at messaging-service-plugin.ts:250 — "one locale per notification: payload.locale, else the deployment default" — rather than a third coinage.

This reports the wiring as it stands. It makes no forecast about recipient-locale matching, and it does not touch the question of whether the platform should match on recipient locale — that is a product question and a different card.

Upstream re-trace

Re-measured on objectstackorigin/main @ 2514d49. The card measured 9e0ba21 and dispatch expected 90ff957; both were stale, so this was re-read rather than quoted forward. Every claim in the card survives:

SiteReading
messaging-service.tszero occurrences of locale, in 1095 lines
recipient-resolver.tszero occurrences of locale — the file whose whole job is resolving recipients
email-channel.ts:224const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;
sms-channel.ts:124byte-identical to the line above; md5 of each line is ec055715f3db3f6cbcf5ddd08af48185
inbox-channel.ts:143-145payload.locale, else getDefaultTemplateLocale()
messaging-service-plugin.ts:148-156getDefaultTemplateLocale resolves i18n.getDefaultLocale()

Control-probed, because a zero from a path-scoped grep is worth nothing on its own. The same probe returns 41 hits in email-channel.ts, 14 in sms-channel.ts, 14 in inbox-channel.ts and 21 in messaging-service-plugin.ts; and inside messaging-service.ts itself, read the same way, it returns 52 recipient, 33 emit and 95 channel. The absence is real, not a broken pathspec.

The last row is also why the existing "Where to go next" link — "Set locale defaults that templates match against" pointing at Localization — stays accurate: the deployment default really is the tenant Localization setting.

For a reviewer wondering whether this is upstream drift rather than intent: objectstack#12178 and objectstack#12446 record a maintainer ruling of 2026-08-13 that this resolution is deliberate, and note that sys_user carries no locale column for a channel to read. That sweep's PR objectstack#12505 is why messaging-service-plugin.ts:250 reads honestly today.

Verification

All gates below ran on a059c27, the final commit, against a clean worktree. Each row quotes the gate's own conclusion.

GateExitIts own verdict
turbo run type-check build --filter=@objectos/docs0Tasks: 2 successful, 2 total · Cached: 0 cached, 2 total — both ran, neither replayed
check-locale-surface.mjs (reads the BUILT sitemap)0"every advertised URL has a source file and every source file is advertised" — sitemap.xml 409 read / 409 expected / 0 unexpected / 0 missing
check-translations.mjs (freshness)0"translations gate passed"
check-translation-ownership.mjs0"This PR touches 0 translation artifact(s) and 1 other file(s)". Reported alongside it: "TRANSLATION_BOT_LOGIN is not set — ownership is not enforced yet", so the rule itself is inert; the load-bearing half is the 0-artifact count, which is a real measurement
check-translation-output.mjs --files0"translation output gate passed (139 pre-existing finding(s) reported)" — none in this diff
gen-zh-hant.mjs --check0"zh-Hant: 73 generated file(s) match the zh-Hans sources byte for byte"
check-node-floor.mjs0"Every declared floor clears what the dependency tree requires"
turbo run test01 successful — a legitimate cache hit: the test task declares no content/docs/** input, so this diff cannot affect it
control-byte self-scancleanno bytes in the U+0000-U+001F / U+007F range in the edited file

Rendering was confirmed on the build artifact, not just on the source: the corrected row and the new paragraph appear in apps/docs/.next/server/app/en/docs/configure/notifications.html, and the string "matched to the recipient" appears zero times anywhere under apps/docs/.next/.

Scope

content/docs/configure/notifications.mdx only.

No locale siblings were touched, and none exist: this page is one of the English-only pages, so the whole translation family is a no-op here rather than merely left alone.

I checked whether anything PR #247 added implies recipient-locale matching by implication. It does not — the "What each channel renders" table names locale as a bare match key without attributing it to anyone, and with the field-table row corrected its antecedent is now unambiguous. No edits were manufactured there.


Generated by Claude Code

…ecipient's
The Notification Templates field table told an admin that a template's `locale`
is "matched to the recipient". The delivery path never reads a recipient
locale: `messaging-service.ts` contains zero occurrences of `locale` (control-
probed against 41/14/14 in the sibling channel files), and `recipient-
resolver.ts` — the file whose whole job is resolving recipients — has zero as
well. Both template channels resolve it identically, byte for byte:
`email-channel.ts:224` and `sms-channel.ts:124` are
`const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;`,
and the inbox notify-template path takes `payload.locale` else
`getDefaultTemplateLocale()` (`inbox-channel.ts:143-145`), which reads
`i18n.getDefaultLocale()`.
So the locale is the notification's own, and one emit renders in a single
locale for everyone it fans out to. The page was inviting an admin to author
`es` and `en` rows expecting two recipients to read in their own languages,
which cannot pay off. Corrected the field-table cell and stated the
consequence next to the table, aligned to upstream's own phrasing at
`messaging-service-plugin.ts:250` ("one locale per notification: payload.locale,
else the deployment default") rather than coining a third wording.
Reports the wiring as it stands; makes no forecast about recipient-locale
matching.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ChPQM8jamxLUfUAxwFpJ8S
@os-bill
os-bill marked this pull request as ready for review September 2, 2026 15:24
@os-bill
os-bill merged commit ac65e7e into mainSep 2, 2026
3 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] configure/notifications.mdx says a template's locale is "matched to the recipient" — the delivery path never reads a recipient locale

2 participants

@os-bill@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(configure): the notification template locale is the notification's, not the recipient's - #255

Merged
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient
Sep 2, 2026
Merged

docs(configure): the notification template locale is the notification's, not the recipient's#255
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient

Conversation

@os-bill

Copy link
Copy Markdown
Collaborator

Fixes#246

The Notification Templates field table told an admin that a template's locale is "matched to the recipient". The delivery path never reads a recipient locale, so authoring es and en rows for a topic cannot give two recipients their own languages — it gives whichever locale the producer named.

What changed

content/docs/configure/notifications.mdx, two edits carrying one claim:

  • The field-table row now reads Locale of this rendering — the notification's own, not the recipient's.
  • A paragraph after the table carries the consequence: the locale is payload.locale when the producer sets one, else the deployment default, and one emit renders in a single locale for every recipient it reaches.

The wording is aligned to upstream's own phrasing at messaging-service-plugin.ts:250 — "one locale per notification: payload.locale, else the deployment default" — rather than a third coinage.

This reports the wiring as it stands. It makes no forecast about recipient-locale matching, and it does not touch the question of whether the platform should match on recipient locale — that is a product question and a different card.

Upstream re-trace

Re-measured on objectstackorigin/main @ 2514d49. The card measured 9e0ba21 and dispatch expected 90ff957; both were stale, so this was re-read rather than quoted forward. Every claim in the card survives:

SiteReading
messaging-service.tszero occurrences of locale, in 1095 lines
recipient-resolver.tszero occurrences of locale — the file whose whole job is resolving recipients
email-channel.ts:224const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;
sms-channel.ts:124byte-identical to the line above; md5 of each line is ec055715f3db3f6cbcf5ddd08af48185
inbox-channel.ts:143-145payload.locale, else getDefaultTemplateLocale()
messaging-service-plugin.ts:148-156getDefaultTemplateLocale resolves i18n.getDefaultLocale()

Control-probed, because a zero from a path-scoped grep is worth nothing on its own. The same probe returns 41 hits in email-channel.ts, 14 in sms-channel.ts, 14 in inbox-channel.ts and 21 in messaging-service-plugin.ts; and inside messaging-service.ts itself, read the same way, it returns 52 recipient, 33 emit and 95 channel. The absence is real, not a broken pathspec.

The last row is also why the existing "Where to go next" link — "Set locale defaults that templates match against" pointing at Localization — stays accurate: the deployment default really is the tenant Localization setting.

For a reviewer wondering whether this is upstream drift rather than intent: objectstack#12178 and objectstack#12446 record a maintainer ruling of 2026-08-13 that this resolution is deliberate, and note that sys_user carries no locale column for a channel to read. That sweep's PR objectstack#12505 is why messaging-service-plugin.ts:250 reads honestly today.

Verification

All gates below ran on a059c27, the final commit, against a clean worktree. Each row quotes the gate's own conclusion.

GateExitIts own verdict
turbo run type-check build --filter=@objectos/docs0Tasks: 2 successful, 2 total · Cached: 0 cached, 2 total — both ran, neither replayed
check-locale-surface.mjs (reads the BUILT sitemap)0"every advertised URL has a source file and every source file is advertised" — sitemap.xml 409 read / 409 expected / 0 unexpected / 0 missing
check-translations.mjs (freshness)0"translations gate passed"
check-translation-ownership.mjs0"This PR touches 0 translation artifact(s) and 1 other file(s)". Reported alongside it: "TRANSLATION_BOT_LOGIN is not set — ownership is not enforced yet", so the rule itself is inert; the load-bearing half is the 0-artifact count, which is a real measurement
check-translation-output.mjs --files0"translation output gate passed (139 pre-existing finding(s) reported)" — none in this diff
gen-zh-hant.mjs --check0"zh-Hant: 73 generated file(s) match the zh-Hans sources byte for byte"
check-node-floor.mjs0"Every declared floor clears what the dependency tree requires"
turbo run test01 successful — a legitimate cache hit: the test task declares no content/docs/** input, so this diff cannot affect it
control-byte self-scancleanno bytes in the U+0000-U+001F / U+007F range in the edited file

Rendering was confirmed on the build artifact, not just on the source: the corrected row and the new paragraph appear in apps/docs/.next/server/app/en/docs/configure/notifications.html, and the string "matched to the recipient" appears zero times anywhere under apps/docs/.next/.

Scope

content/docs/configure/notifications.mdx only.

No locale siblings were touched, and none exist: this page is one of the English-only pages, so the whole translation family is a no-op here rather than merely left alone.

I checked whether anything PR #247 added implies recipient-locale matching by implication. It does not — the "What each channel renders" table names locale as a bare match key without attributing it to anyone, and with the field-table row corrected its antecedent is now unambiguous. No edits were manufactured there.


Generated by Claude Code

…ecipient's
The Notification Templates field table told an admin that a template's `locale`
is "matched to the recipient". The delivery path never reads a recipient
locale: `messaging-service.ts` contains zero occurrences of `locale` (control-
probed against 41/14/14 in the sibling channel files), and `recipient-
resolver.ts` — the file whose whole job is resolving recipients — has zero as
well. Both template channels resolve it identically, byte for byte:
`email-channel.ts:224` and `sms-channel.ts:124` are
`const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;`,
and the inbox notify-template path takes `payload.locale` else
`getDefaultTemplateLocale()` (`inbox-channel.ts:143-145`), which reads
`i18n.getDefaultLocale()`.
So the locale is the notification's own, and one emit renders in a single
locale for everyone it fans out to. The page was inviting an admin to author
`es` and `en` rows expecting two recipients to read in their own languages,
which cannot pay off. Corrected the field-table cell and stated the
consequence next to the table, aligned to upstream's own phrasing at
`messaging-service-plugin.ts:250` ("one locale per notification: payload.locale,
else the deployment default") rather than coining a third wording.
Reports the wiring as it stands; makes no forecast about recipient-locale
matching.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ChPQM8jamxLUfUAxwFpJ8S
@os-bill
os-bill marked this pull request as ready for review September 2, 2026 15:24
@os-bill
os-bill merged commit ac65e7e into mainSep 2, 2026
3 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] configure/notifications.mdx says a template's locale is "matched to the recipient" — the delivery path never reads a recipient locale

2 participants

@os-bill@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(configure): the notification template locale is the notification's, not the recipient's - #255

Merged
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient
Sep 2, 2026
Merged

docs(configure): the notification template locale is the notification's, not the recipient's#255
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient

Conversation

@os-bill

Copy link
Copy Markdown
Collaborator

Fixes#246

The Notification Templates field table told an admin that a template's locale is "matched to the recipient". The delivery path never reads a recipient locale, so authoring es and en rows for a topic cannot give two recipients their own languages — it gives whichever locale the producer named.

What changed

content/docs/configure/notifications.mdx, two edits carrying one claim:

  • The field-table row now reads Locale of this rendering — the notification's own, not the recipient's.
  • A paragraph after the table carries the consequence: the locale is payload.locale when the producer sets one, else the deployment default, and one emit renders in a single locale for every recipient it reaches.

The wording is aligned to upstream's own phrasing at messaging-service-plugin.ts:250 — "one locale per notification: payload.locale, else the deployment default" — rather than a third coinage.

This reports the wiring as it stands. It makes no forecast about recipient-locale matching, and it does not touch the question of whether the platform should match on recipient locale — that is a product question and a different card.

Upstream re-trace

Re-measured on objectstackorigin/main @ 2514d49. The card measured 9e0ba21 and dispatch expected 90ff957; both were stale, so this was re-read rather than quoted forward. Every claim in the card survives:

SiteReading
messaging-service.tszero occurrences of locale, in 1095 lines
recipient-resolver.tszero occurrences of locale — the file whose whole job is resolving recipients
email-channel.ts:224const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;
sms-channel.ts:124byte-identical to the line above; md5 of each line is ec055715f3db3f6cbcf5ddd08af48185
inbox-channel.ts:143-145payload.locale, else getDefaultTemplateLocale()
messaging-service-plugin.ts:148-156getDefaultTemplateLocale resolves i18n.getDefaultLocale()

Control-probed, because a zero from a path-scoped grep is worth nothing on its own. The same probe returns 41 hits in email-channel.ts, 14 in sms-channel.ts, 14 in inbox-channel.ts and 21 in messaging-service-plugin.ts; and inside messaging-service.ts itself, read the same way, it returns 52 recipient, 33 emit and 95 channel. The absence is real, not a broken pathspec.

The last row is also why the existing "Where to go next" link — "Set locale defaults that templates match against" pointing at Localization — stays accurate: the deployment default really is the tenant Localization setting.

For a reviewer wondering whether this is upstream drift rather than intent: objectstack#12178 and objectstack#12446 record a maintainer ruling of 2026-08-13 that this resolution is deliberate, and note that sys_user carries no locale column for a channel to read. That sweep's PR objectstack#12505 is why messaging-service-plugin.ts:250 reads honestly today.

Verification

All gates below ran on a059c27, the final commit, against a clean worktree. Each row quotes the gate's own conclusion.

GateExitIts own verdict
turbo run type-check build --filter=@objectos/docs0Tasks: 2 successful, 2 total · Cached: 0 cached, 2 total — both ran, neither replayed
check-locale-surface.mjs (reads the BUILT sitemap)0"every advertised URL has a source file and every source file is advertised" — sitemap.xml 409 read / 409 expected / 0 unexpected / 0 missing
check-translations.mjs (freshness)0"translations gate passed"
check-translation-ownership.mjs0"This PR touches 0 translation artifact(s) and 1 other file(s)". Reported alongside it: "TRANSLATION_BOT_LOGIN is not set — ownership is not enforced yet", so the rule itself is inert; the load-bearing half is the 0-artifact count, which is a real measurement
check-translation-output.mjs --files0"translation output gate passed (139 pre-existing finding(s) reported)" — none in this diff
gen-zh-hant.mjs --check0"zh-Hant: 73 generated file(s) match the zh-Hans sources byte for byte"
check-node-floor.mjs0"Every declared floor clears what the dependency tree requires"
turbo run test01 successful — a legitimate cache hit: the test task declares no content/docs/** input, so this diff cannot affect it
control-byte self-scancleanno bytes in the U+0000-U+001F / U+007F range in the edited file

Rendering was confirmed on the build artifact, not just on the source: the corrected row and the new paragraph appear in apps/docs/.next/server/app/en/docs/configure/notifications.html, and the string "matched to the recipient" appears zero times anywhere under apps/docs/.next/.

Scope

content/docs/configure/notifications.mdx only.

No locale siblings were touched, and none exist: this page is one of the English-only pages, so the whole translation family is a no-op here rather than merely left alone.

I checked whether anything PR #247 added implies recipient-locale matching by implication. It does not — the "What each channel renders" table names locale as a bare match key without attributing it to anyone, and with the field-table row corrected its antecedent is now unambiguous. No edits were manufactured there.


Generated by Claude Code

…ecipient's
The Notification Templates field table told an admin that a template's `locale`
is "matched to the recipient". The delivery path never reads a recipient
locale: `messaging-service.ts` contains zero occurrences of `locale` (control-
probed against 41/14/14 in the sibling channel files), and `recipient-
resolver.ts` — the file whose whole job is resolving recipients — has zero as
well. Both template channels resolve it identically, byte for byte:
`email-channel.ts:224` and `sms-channel.ts:124` are
`const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;`,
and the inbox notify-template path takes `payload.locale` else
`getDefaultTemplateLocale()` (`inbox-channel.ts:143-145`), which reads
`i18n.getDefaultLocale()`.
So the locale is the notification's own, and one emit renders in a single
locale for everyone it fans out to. The page was inviting an admin to author
`es` and `en` rows expecting two recipients to read in their own languages,
which cannot pay off. Corrected the field-table cell and stated the
consequence next to the table, aligned to upstream's own phrasing at
`messaging-service-plugin.ts:250` ("one locale per notification: payload.locale,
else the deployment default") rather than coining a third wording.
Reports the wiring as it stands; makes no forecast about recipient-locale
matching.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ChPQM8jamxLUfUAxwFpJ8S
@os-bill
os-bill marked this pull request as ready for review September 2, 2026 15:24
@os-bill
os-bill merged commit ac65e7e into mainSep 2, 2026
3 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] configure/notifications.mdx says a template's locale is "matched to the recipient" — the delivery path never reads a recipient locale

2 participants

@os-bill@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

docs(configure): the notification template locale is the notification's, not the recipient's - #255

Merged
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient
Sep 2, 2026
Merged

docs(configure): the notification template locale is the notification's, not the recipient's#255
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient

Conversation

@os-bill

Copy link
Copy Markdown
Collaborator

Fixes#246

The Notification Templates field table told an admin that a template's locale is "matched to the recipient". The delivery path never reads a recipient locale, so authoring es and en rows for a topic cannot give two recipients their own languages — it gives whichever locale the producer named.

What changed

content/docs/configure/notifications.mdx, two edits carrying one claim:

  • The field-table row now reads Locale of this rendering — the notification's own, not the recipient's.
  • A paragraph after the table carries the consequence: the locale is payload.locale when the producer sets one, else the deployment default, and one emit renders in a single locale for every recipient it reaches.

The wording is aligned to upstream's own phrasing at messaging-service-plugin.ts:250 — "one locale per notification: payload.locale, else the deployment default" — rather than a third coinage.

This reports the wiring as it stands. It makes no forecast about recipient-locale matching, and it does not touch the question of whether the platform should match on recipient locale — that is a product question and a different card.

Upstream re-trace

Re-measured on objectstackorigin/main @ 2514d49. The card measured 9e0ba21 and dispatch expected 90ff957; both were stale, so this was re-read rather than quoted forward. Every claim in the card survives:

SiteReading
messaging-service.tszero occurrences of locale, in 1095 lines
recipient-resolver.tszero occurrences of locale — the file whose whole job is resolving recipients
email-channel.ts:224const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;
sms-channel.ts:124byte-identical to the line above; md5 of each line is ec055715f3db3f6cbcf5ddd08af48185
inbox-channel.ts:143-145payload.locale, else getDefaultTemplateLocale()
messaging-service-plugin.ts:148-156getDefaultTemplateLocale resolves i18n.getDefaultLocale()

Control-probed, because a zero from a path-scoped grep is worth nothing on its own. The same probe returns 41 hits in email-channel.ts, 14 in sms-channel.ts, 14 in inbox-channel.ts and 21 in messaging-service-plugin.ts; and inside messaging-service.ts itself, read the same way, it returns 52 recipient, 33 emit and 95 channel. The absence is real, not a broken pathspec.

The last row is also why the existing "Where to go next" link — "Set locale defaults that templates match against" pointing at Localization — stays accurate: the deployment default really is the tenant Localization setting.

For a reviewer wondering whether this is upstream drift rather than intent: objectstack#12178 and objectstack#12446 record a maintainer ruling of 2026-08-13 that this resolution is deliberate, and note that sys_user carries no locale column for a channel to read. That sweep's PR objectstack#12505 is why messaging-service-plugin.ts:250 reads honestly today.

Verification

All gates below ran on a059c27, the final commit, against a clean worktree. Each row quotes the gate's own conclusion.

GateExitIts own verdict
turbo run type-check build --filter=@objectos/docs0Tasks: 2 successful, 2 total · Cached: 0 cached, 2 total — both ran, neither replayed
check-locale-surface.mjs (reads the BUILT sitemap)0"every advertised URL has a source file and every source file is advertised" — sitemap.xml 409 read / 409 expected / 0 unexpected / 0 missing
check-translations.mjs (freshness)0"translations gate passed"
check-translation-ownership.mjs0"This PR touches 0 translation artifact(s) and 1 other file(s)". Reported alongside it: "TRANSLATION_BOT_LOGIN is not set — ownership is not enforced yet", so the rule itself is inert; the load-bearing half is the 0-artifact count, which is a real measurement
check-translation-output.mjs --files0"translation output gate passed (139 pre-existing finding(s) reported)" — none in this diff
gen-zh-hant.mjs --check0"zh-Hant: 73 generated file(s) match the zh-Hans sources byte for byte"
check-node-floor.mjs0"Every declared floor clears what the dependency tree requires"
turbo run test01 successful — a legitimate cache hit: the test task declares no content/docs/** input, so this diff cannot affect it
control-byte self-scancleanno bytes in the U+0000-U+001F / U+007F range in the edited file

Rendering was confirmed on the build artifact, not just on the source: the corrected row and the new paragraph appear in apps/docs/.next/server/app/en/docs/configure/notifications.html, and the string "matched to the recipient" appears zero times anywhere under apps/docs/.next/.

Scope

content/docs/configure/notifications.mdx only.

No locale siblings were touched, and none exist: this page is one of the English-only pages, so the whole translation family is a no-op here rather than merely left alone.

I checked whether anything PR #247 added implies recipient-locale matching by implication. It does not — the "What each channel renders" table names locale as a bare match key without attributing it to anyone, and with the field-table row corrected its antecedent is now unambiguous. No edits were manufactured there.


Generated by Claude Code

…ecipient's
The Notification Templates field table told an admin that a template's `locale`
is "matched to the recipient". The delivery path never reads a recipient
locale: `messaging-service.ts` contains zero occurrences of `locale` (control-
probed against 41/14/14 in the sibling channel files), and `recipient-
resolver.ts` — the file whose whole job is resolving recipients — has zero as
well. Both template channels resolve it identically, byte for byte:
`email-channel.ts:224` and `sms-channel.ts:124` are
`const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;`,
and the inbox notify-template path takes `payload.locale` else
`getDefaultTemplateLocale()` (`inbox-channel.ts:143-145`), which reads
`i18n.getDefaultLocale()`.
So the locale is the notification's own, and one emit renders in a single
locale for everyone it fans out to. The page was inviting an admin to author
`es` and `en` rows expecting two recipients to read in their own languages,
which cannot pay off. Corrected the field-table cell and stated the
consequence next to the table, aligned to upstream's own phrasing at
`messaging-service-plugin.ts:250` ("one locale per notification: payload.locale,
else the deployment default") rather than coining a third wording.
Reports the wiring as it stands; makes no forecast about recipient-locale
matching.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ChPQM8jamxLUfUAxwFpJ8S
@os-bill
os-bill marked this pull request as ready for review September 2, 2026 15:24
@os-bill
os-bill merged commit ac65e7e into mainSep 2, 2026
3 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] configure/notifications.mdx says a template's locale is "matched to the recipient" — the delivery path never reads a recipient locale

2 participants

@os-bill@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(configure): the notification template locale is the notification's, not the recipient's - #255

Merged
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient
Sep 2, 2026
Merged

docs(configure): the notification template locale is the notification's, not the recipient's#255
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient

Conversation

@os-bill

Copy link
Copy Markdown
Collaborator

Fixes#246

The Notification Templates field table told an admin that a template's locale is "matched to the recipient". The delivery path never reads a recipient locale, so authoring es and en rows for a topic cannot give two recipients their own languages — it gives whichever locale the producer named.

What changed

content/docs/configure/notifications.mdx, two edits carrying one claim:

  • The field-table row now reads Locale of this rendering — the notification's own, not the recipient's.
  • A paragraph after the table carries the consequence: the locale is payload.locale when the producer sets one, else the deployment default, and one emit renders in a single locale for every recipient it reaches.

The wording is aligned to upstream's own phrasing at messaging-service-plugin.ts:250 — "one locale per notification: payload.locale, else the deployment default" — rather than a third coinage.

This reports the wiring as it stands. It makes no forecast about recipient-locale matching, and it does not touch the question of whether the platform should match on recipient locale — that is a product question and a different card.

Upstream re-trace

Re-measured on objectstackorigin/main @ 2514d49. The card measured 9e0ba21 and dispatch expected 90ff957; both were stale, so this was re-read rather than quoted forward. Every claim in the card survives:

SiteReading
messaging-service.tszero occurrences of locale, in 1095 lines
recipient-resolver.tszero occurrences of locale — the file whose whole job is resolving recipients
email-channel.ts:224const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;
sms-channel.ts:124byte-identical to the line above; md5 of each line is ec055715f3db3f6cbcf5ddd08af48185
inbox-channel.ts:143-145payload.locale, else getDefaultTemplateLocale()
messaging-service-plugin.ts:148-156getDefaultTemplateLocale resolves i18n.getDefaultLocale()

Control-probed, because a zero from a path-scoped grep is worth nothing on its own. The same probe returns 41 hits in email-channel.ts, 14 in sms-channel.ts, 14 in inbox-channel.ts and 21 in messaging-service-plugin.ts; and inside messaging-service.ts itself, read the same way, it returns 52 recipient, 33 emit and 95 channel. The absence is real, not a broken pathspec.

The last row is also why the existing "Where to go next" link — "Set locale defaults that templates match against" pointing at Localization — stays accurate: the deployment default really is the tenant Localization setting.

For a reviewer wondering whether this is upstream drift rather than intent: objectstack#12178 and objectstack#12446 record a maintainer ruling of 2026-08-13 that this resolution is deliberate, and note that sys_user carries no locale column for a channel to read. That sweep's PR objectstack#12505 is why messaging-service-plugin.ts:250 reads honestly today.

Verification

All gates below ran on a059c27, the final commit, against a clean worktree. Each row quotes the gate's own conclusion.

GateExitIts own verdict
turbo run type-check build --filter=@objectos/docs0Tasks: 2 successful, 2 total · Cached: 0 cached, 2 total — both ran, neither replayed
check-locale-surface.mjs (reads the BUILT sitemap)0"every advertised URL has a source file and every source file is advertised" — sitemap.xml 409 read / 409 expected / 0 unexpected / 0 missing
check-translations.mjs (freshness)0"translations gate passed"
check-translation-ownership.mjs0"This PR touches 0 translation artifact(s) and 1 other file(s)". Reported alongside it: "TRANSLATION_BOT_LOGIN is not set — ownership is not enforced yet", so the rule itself is inert; the load-bearing half is the 0-artifact count, which is a real measurement
check-translation-output.mjs --files0"translation output gate passed (139 pre-existing finding(s) reported)" — none in this diff
gen-zh-hant.mjs --check0"zh-Hant: 73 generated file(s) match the zh-Hans sources byte for byte"
check-node-floor.mjs0"Every declared floor clears what the dependency tree requires"
turbo run test01 successful — a legitimate cache hit: the test task declares no content/docs/** input, so this diff cannot affect it
control-byte self-scancleanno bytes in the U+0000-U+001F / U+007F range in the edited file

Rendering was confirmed on the build artifact, not just on the source: the corrected row and the new paragraph appear in apps/docs/.next/server/app/en/docs/configure/notifications.html, and the string "matched to the recipient" appears zero times anywhere under apps/docs/.next/.

Scope

content/docs/configure/notifications.mdx only.

No locale siblings were touched, and none exist: this page is one of the English-only pages, so the whole translation family is a no-op here rather than merely left alone.

I checked whether anything PR #247 added implies recipient-locale matching by implication. It does not — the "What each channel renders" table names locale as a bare match key without attributing it to anyone, and with the field-table row corrected its antecedent is now unambiguous. No edits were manufactured there.


Generated by Claude Code

…ecipient's
The Notification Templates field table told an admin that a template's `locale`
is "matched to the recipient". The delivery path never reads a recipient
locale: `messaging-service.ts` contains zero occurrences of `locale` (control-
probed against 41/14/14 in the sibling channel files), and `recipient-
resolver.ts` — the file whose whole job is resolving recipients — has zero as
well. Both template channels resolve it identically, byte for byte:
`email-channel.ts:224` and `sms-channel.ts:124` are
`const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;`,
and the inbox notify-template path takes `payload.locale` else
`getDefaultTemplateLocale()` (`inbox-channel.ts:143-145`), which reads
`i18n.getDefaultLocale()`.
So the locale is the notification's own, and one emit renders in a single
locale for everyone it fans out to. The page was inviting an admin to author
`es` and `en` rows expecting two recipients to read in their own languages,
which cannot pay off. Corrected the field-table cell and stated the
consequence next to the table, aligned to upstream's own phrasing at
`messaging-service-plugin.ts:250` ("one locale per notification: payload.locale,
else the deployment default") rather than coining a third wording.
Reports the wiring as it stands; makes no forecast about recipient-locale
matching.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ChPQM8jamxLUfUAxwFpJ8S
@os-bill
os-bill marked this pull request as ready for review September 2, 2026 15:24
@os-bill
os-bill merged commit ac65e7e into mainSep 2, 2026
3 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] configure/notifications.mdx says a template's locale is "matched to the recipient" — the delivery path never reads a recipient locale

2 participants

@os-bill@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

docs(configure): the notification template locale is the notification's, not the recipient's - #255

Merged
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient
Sep 2, 2026
Merged

docs(configure): the notification template locale is the notification's, not the recipient's#255
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient

Conversation

@os-bill

Copy link
Copy Markdown
Collaborator

Fixes#246

The Notification Templates field table told an admin that a template's locale is "matched to the recipient". The delivery path never reads a recipient locale, so authoring es and en rows for a topic cannot give two recipients their own languages — it gives whichever locale the producer named.

What changed

content/docs/configure/notifications.mdx, two edits carrying one claim:

  • The field-table row now reads Locale of this rendering — the notification's own, not the recipient's.
  • A paragraph after the table carries the consequence: the locale is payload.locale when the producer sets one, else the deployment default, and one emit renders in a single locale for every recipient it reaches.

The wording is aligned to upstream's own phrasing at messaging-service-plugin.ts:250 — "one locale per notification: payload.locale, else the deployment default" — rather than a third coinage.

This reports the wiring as it stands. It makes no forecast about recipient-locale matching, and it does not touch the question of whether the platform should match on recipient locale — that is a product question and a different card.

Upstream re-trace

Re-measured on objectstackorigin/main @ 2514d49. The card measured 9e0ba21 and dispatch expected 90ff957; both were stale, so this was re-read rather than quoted forward. Every claim in the card survives:

SiteReading
messaging-service.tszero occurrences of locale, in 1095 lines
recipient-resolver.tszero occurrences of locale — the file whose whole job is resolving recipients
email-channel.ts:224const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;
sms-channel.ts:124byte-identical to the line above; md5 of each line is ec055715f3db3f6cbcf5ddd08af48185
inbox-channel.ts:143-145payload.locale, else getDefaultTemplateLocale()
messaging-service-plugin.ts:148-156getDefaultTemplateLocale resolves i18n.getDefaultLocale()

Control-probed, because a zero from a path-scoped grep is worth nothing on its own. The same probe returns 41 hits in email-channel.ts, 14 in sms-channel.ts, 14 in inbox-channel.ts and 21 in messaging-service-plugin.ts; and inside messaging-service.ts itself, read the same way, it returns 52 recipient, 33 emit and 95 channel. The absence is real, not a broken pathspec.

The last row is also why the existing "Where to go next" link — "Set locale defaults that templates match against" pointing at Localization — stays accurate: the deployment default really is the tenant Localization setting.

For a reviewer wondering whether this is upstream drift rather than intent: objectstack#12178 and objectstack#12446 record a maintainer ruling of 2026-08-13 that this resolution is deliberate, and note that sys_user carries no locale column for a channel to read. That sweep's PR objectstack#12505 is why messaging-service-plugin.ts:250 reads honestly today.

Verification

All gates below ran on a059c27, the final commit, against a clean worktree. Each row quotes the gate's own conclusion.

GateExitIts own verdict
turbo run type-check build --filter=@objectos/docs0Tasks: 2 successful, 2 total · Cached: 0 cached, 2 total — both ran, neither replayed
check-locale-surface.mjs (reads the BUILT sitemap)0"every advertised URL has a source file and every source file is advertised" — sitemap.xml 409 read / 409 expected / 0 unexpected / 0 missing
check-translations.mjs (freshness)0"translations gate passed"
check-translation-ownership.mjs0"This PR touches 0 translation artifact(s) and 1 other file(s)". Reported alongside it: "TRANSLATION_BOT_LOGIN is not set — ownership is not enforced yet", so the rule itself is inert; the load-bearing half is the 0-artifact count, which is a real measurement
check-translation-output.mjs --files0"translation output gate passed (139 pre-existing finding(s) reported)" — none in this diff
gen-zh-hant.mjs --check0"zh-Hant: 73 generated file(s) match the zh-Hans sources byte for byte"
check-node-floor.mjs0"Every declared floor clears what the dependency tree requires"
turbo run test01 successful — a legitimate cache hit: the test task declares no content/docs/** input, so this diff cannot affect it
control-byte self-scancleanno bytes in the U+0000-U+001F / U+007F range in the edited file

Rendering was confirmed on the build artifact, not just on the source: the corrected row and the new paragraph appear in apps/docs/.next/server/app/en/docs/configure/notifications.html, and the string "matched to the recipient" appears zero times anywhere under apps/docs/.next/.

Scope

content/docs/configure/notifications.mdx only.

No locale siblings were touched, and none exist: this page is one of the English-only pages, so the whole translation family is a no-op here rather than merely left alone.

I checked whether anything PR #247 added implies recipient-locale matching by implication. It does not — the "What each channel renders" table names locale as a bare match key without attributing it to anyone, and with the field-table row corrected its antecedent is now unambiguous. No edits were manufactured there.


Generated by Claude Code

…ecipient's
The Notification Templates field table told an admin that a template's `locale`
is "matched to the recipient". The delivery path never reads a recipient
locale: `messaging-service.ts` contains zero occurrences of `locale` (control-
probed against 41/14/14 in the sibling channel files), and `recipient-
resolver.ts` — the file whose whole job is resolving recipients — has zero as
well. Both template channels resolve it identically, byte for byte:
`email-channel.ts:224` and `sms-channel.ts:124` are
`const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;`,
and the inbox notify-template path takes `payload.locale` else
`getDefaultTemplateLocale()` (`inbox-channel.ts:143-145`), which reads
`i18n.getDefaultLocale()`.
So the locale is the notification's own, and one emit renders in a single
locale for everyone it fans out to. The page was inviting an admin to author
`es` and `en` rows expecting two recipients to read in their own languages,
which cannot pay off. Corrected the field-table cell and stated the
consequence next to the table, aligned to upstream's own phrasing at
`messaging-service-plugin.ts:250` ("one locale per notification: payload.locale,
else the deployment default") rather than coining a third wording.
Reports the wiring as it stands; makes no forecast about recipient-locale
matching.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ChPQM8jamxLUfUAxwFpJ8S
@os-bill
os-bill marked this pull request as ready for review September 2, 2026 15:24
@os-bill
os-bill merged commit ac65e7e into mainSep 2, 2026
3 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] configure/notifications.mdx says a template's locale is "matched to the recipient" — the delivery path never reads a recipient locale

2 participants

@os-bill@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

docs(configure): the notification template locale is the notification's, not the recipient's - #255

Merged
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient
Sep 2, 2026
Merged

docs(configure): the notification template locale is the notification's, not the recipient's#255
os-bill merged 1 commit into
mainfrom
claude/issue-246-template-locale-not-recipient

Conversation

@os-bill

Copy link
Copy Markdown
Collaborator

Fixes#246

The Notification Templates field table told an admin that a template's locale is "matched to the recipient". The delivery path never reads a recipient locale, so authoring es and en rows for a topic cannot give two recipients their own languages — it gives whichever locale the producer named.

What changed

content/docs/configure/notifications.mdx, two edits carrying one claim:

  • The field-table row now reads Locale of this rendering — the notification's own, not the recipient's.
  • A paragraph after the table carries the consequence: the locale is payload.locale when the producer sets one, else the deployment default, and one emit renders in a single locale for every recipient it reaches.

The wording is aligned to upstream's own phrasing at messaging-service-plugin.ts:250 — "one locale per notification: payload.locale, else the deployment default" — rather than a third coinage.

This reports the wiring as it stands. It makes no forecast about recipient-locale matching, and it does not touch the question of whether the platform should match on recipient locale — that is a product question and a different card.

Upstream re-trace

Re-measured on objectstackorigin/main @ 2514d49. The card measured 9e0ba21 and dispatch expected 90ff957; both were stale, so this was re-read rather than quoted forward. Every claim in the card survives:

SiteReading
messaging-service.tszero occurrences of locale, in 1095 lines
recipient-resolver.tszero occurrences of locale — the file whose whole job is resolving recipients
email-channel.ts:224const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;
sms-channel.ts:124byte-identical to the line above; md5 of each line is ec055715f3db3f6cbcf5ddd08af48185
inbox-channel.ts:143-145payload.locale, else getDefaultTemplateLocale()
messaging-service-plugin.ts:148-156getDefaultTemplateLocale resolves i18n.getDefaultLocale()

Control-probed, because a zero from a path-scoped grep is worth nothing on its own. The same probe returns 41 hits in email-channel.ts, 14 in sms-channel.ts, 14 in inbox-channel.ts and 21 in messaging-service-plugin.ts; and inside messaging-service.ts itself, read the same way, it returns 52 recipient, 33 emit and 95 channel. The absence is real, not a broken pathspec.

The last row is also why the existing "Where to go next" link — "Set locale defaults that templates match against" pointing at Localization — stays accurate: the deployment default really is the tenant Localization setting.

For a reviewer wondering whether this is upstream drift rather than intent: objectstack#12178 and objectstack#12446 record a maintainer ruling of 2026-08-13 that this resolution is deliberate, and note that sys_user carries no locale column for a channel to read. That sweep's PR objectstack#12505 is why messaging-service-plugin.ts:250 reads honestly today.

Verification

All gates below ran on a059c27, the final commit, against a clean worktree. Each row quotes the gate's own conclusion.

GateExitIts own verdict
turbo run type-check build --filter=@objectos/docs0Tasks: 2 successful, 2 total · Cached: 0 cached, 2 total — both ran, neither replayed
check-locale-surface.mjs (reads the BUILT sitemap)0"every advertised URL has a source file and every source file is advertised" — sitemap.xml 409 read / 409 expected / 0 unexpected / 0 missing
check-translations.mjs (freshness)0"translations gate passed"
check-translation-ownership.mjs0"This PR touches 0 translation artifact(s) and 1 other file(s)". Reported alongside it: "TRANSLATION_BOT_LOGIN is not set — ownership is not enforced yet", so the rule itself is inert; the load-bearing half is the 0-artifact count, which is a real measurement
check-translation-output.mjs --files0"translation output gate passed (139 pre-existing finding(s) reported)" — none in this diff
gen-zh-hant.mjs --check0"zh-Hant: 73 generated file(s) match the zh-Hans sources byte for byte"
check-node-floor.mjs0"Every declared floor clears what the dependency tree requires"
turbo run test01 successful — a legitimate cache hit: the test task declares no content/docs/** input, so this diff cannot affect it
control-byte self-scancleanno bytes in the U+0000-U+001F / U+007F range in the edited file

Rendering was confirmed on the build artifact, not just on the source: the corrected row and the new paragraph appear in apps/docs/.next/server/app/en/docs/configure/notifications.html, and the string "matched to the recipient" appears zero times anywhere under apps/docs/.next/.

Scope

content/docs/configure/notifications.mdx only.

No locale siblings were touched, and none exist: this page is one of the English-only pages, so the whole translation family is a no-op here rather than merely left alone.

I checked whether anything PR #247 added implies recipient-locale matching by implication. It does not — the "What each channel renders" table names locale as a bare match key without attributing it to anyone, and with the field-table row corrected its antecedent is now unambiguous. No edits were manufactured there.


Generated by Claude Code

…ecipient's
The Notification Templates field table told an admin that a template's `locale`
is "matched to the recipient". The delivery path never reads a recipient
locale: `messaging-service.ts` contains zero occurrences of `locale` (control-
probed against 41/14/14 in the sibling channel files), and `recipient-
resolver.ts` — the file whose whole job is resolving recipients — has zero as
well. Both template channels resolve it identically, byte for byte:
`email-channel.ts:224` and `sms-channel.ts:124` are
`const locale = typeof payload.locale === 'string' ? payload.locale : defaultLocale;`,
and the inbox notify-template path takes `payload.locale` else
`getDefaultTemplateLocale()` (`inbox-channel.ts:143-145`), which reads
`i18n.getDefaultLocale()`.
So the locale is the notification's own, and one emit renders in a single
locale for everyone it fans out to. The page was inviting an admin to author
`es` and `en` rows expecting two recipients to read in their own languages,
which cannot pay off. Corrected the field-table cell and stated the
consequence next to the table, aligned to upstream's own phrasing at
`messaging-service-plugin.ts:250` ("one locale per notification: payload.locale,
else the deployment default") rather than coining a third wording.
Reports the wiring as it stands; makes no forecast about recipient-locale
matching.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ChPQM8jamxLUfUAxwFpJ8S
@os-bill
os-bill marked this pull request as ready for review September 2, 2026 15:24
@os-bill
os-bill merged commit ac65e7e into mainSep 2, 2026
3 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] configure/notifications.mdx says a template's locale is "matched to the recipient" — the delivery path never reads a recipient locale

2 participants

@os-bill@claude