@@ -19,8 +19,10 @@ deferral.
1919
2020Now the locale is resolved PER RECIPIENT, at delivery time, through ONE read
2121point (` recipient-locale.ts ` , ` resolveRecipientLocale ` ): the recipient's own
22- ` sys_user.locale ` — read off the same row the channel already fetches for the
23- address, so it costs no second query — else the deployment default, probed
22+ ` sys_user.locale ` — email and SMS read it off the same row they already fetch
23+ for the address, so it costs no second query there; the inbox channel, which
24+ never read the row before, makes one read for it on the template path — else
25+ the deployment default, probed
2426lazily so live ` localization ` changes are honoured. The same chain serves the
2527email channel's two arms (` sendTemplate ` and ` sys_notification_template ` ), the
2628inbox channel's template path, and the SMS channel, so one notification cannot
@@ -42,13 +44,28 @@ it now sends each recipient their own language, else the deployment default —
4244which is the ruled behaviour, not a regression. Nothing to migrate: remove the
4345key, or leave it, it is inert either way.
4446
47+ Second behaviour change: on the ` sys_notification_template ` arm (email topic
48+ path, SMS) the deployment default (` II18nService.getDefaultLocale() ` ) is now
49+ the second rung; before, that arm fell straight from ` payload.locale ` to the
50+ static ` en ` and never consulted it. A deployment whose ` localization.locale `
51+ is e.g. ` zh-CN ` with a topic bundle holding ` en ` and ` zh ` rows renders ` zh `
52+ there now for recipients without a column. SMS is newly handed the
53+ deployment-default probe.
54+
4555` @objectstack/spec ` ships the contract text: the ` notify ` node's ` template `
4656description and its refusal messages now state the per-recipient chain and
4757name ` payload.locale ` as not consulted (` automation/io-node-config.zod.ts ` ),
4858mirrored on the runtime descriptor in ` @objectstack/service-automation ` .
4959
5060Interaction with the ` TEMPLATE_* ` permanent-failure class is unchanged in
51- kind: ` sendTemplate ` 's ladder still ends at ` en-US ` , so a recipient locale can
52- dead-letter a delivery only where the deployment default would have too — a
53- bundle with neither the requested row nor an ` en-US ` row, which is off the
54- documented contract.
61+ kind: ` sendTemplate ` 's ladder for a NAMED locale still ends at ` en-US ` , so a
62+ recipient locale can dead-letter a delivery only against a bundle that has
63+ neither the requested row nor an ` en-US ` row — off the documented contract.
64+ Two asymmetries against the old single value, both on such bundles: (a) the
65+ bundle carries the deployment default's row but no ` en-US ` row — old delivered,
66+ new fails for a recipient whose own tag is a third language; (b) there is NO
67+ deployment default (i18n absent or ` getDefaultLocale ` unimplemented) — old
68+ called ` sendTemplate ` with no locale and the ladder's any-row rung delivered,
69+ new names the recipient's tag, the any-row rung is skipped, and a tag absent
70+ from the bundle is ` TEMPLATE_NOT_FOUND ` (permanent). The fix in both is the
71+ bundle (` en-US ` is the ladder's floor), not a third rung.
0 commit comments