Repository navigation
fix(service-messaging)!: sys_notification_template.channel accepts only email and sms, the channels that read a template - #24976
Conversation
…nels that read it (email, sms) The channel column refuses any value but email or sms at write, with a message pointing in-app content to an email template. The object's description, empty state and channel/subject help say which channels read a row. The authentication docs' SMS paragraph drops the retired seed and states which organization's row an auth SMS reads. Claude-Session: https://claude.ai/code/session_01UmqzD97e14iws6hmVhgZ5y Co-authored-by: Claude <noreply@anthropic.com>
…te the new copy The refusal pins cover insert, by-id update, predicate update and an import's kept option values (code VALIDATION_FAILED, served 400, attributed to channel, naming the email template). Their positive twins accept email and sms, and a row already stored with another channel is still read, edited in other columns, deleted, and rendered on no channel. The four bundles are regenerated, and the changed copy and the new rule message are translated in zh-CN, ja-JP and es-ES. Claude-Session: https://claude.ai/code/session_01UmqzD97e14iws6hmVhgZ5y Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UmqzD97e14iws6hmVhgZ5y Co-authored-by: Claude <noreply@anthropic.com>
…mplate-channel-email-sms
📓 Docs Drift CheckThis PR changes 1 package(s): 13 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 5 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin f8bcc4009746af392fdf55d5ca1e66179c6d3f22 && git checkout f8bcc4009746af392fdf55d5ca1e66179c6d3f22
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6440cf16334e1c8106dfdb31d87b6ca728d176c2 c7102b32fe4ee4d880635a3ac9d95b34aa79f4f5 && git checkout -B drift-repro 6440cf16334e1c8106dfdb31d87b6ca728d176c2 && git merge --no-ff c7102b32fe4ee4d880635a3ac9d95b34aa79f4f5
node scripts/docs-audit/affected-docs.mjs --json 6440cf16334e1c8106dfdb31d87b6ca728d176c2
|
…annel reads (18.x half) The ruling refuses stored or new non-email/sms rows only where a stored-row conversion carries it; none carries data rows, so 18.x warns on write and the refusal waits for 19.0. channel_renders_template moves to severity warning with a warning's wording: the write is accepted and stored, the hit reaches the write's onValidationAdvisory listener (the single-record write answer's warnings) and the per-write log. The pins follow: every write shape is accepted with exactly one channel advisory, email and sms carry none, and stored rows stay untouched. The changeset drops to patch with Clause-② no. Claude-Session: https://claude.ai/code/session_01UmqzD97e14iws6hmVhgZ5y Co-authored-by: Claude <noreply@anthropic.com>
席位核对ACCEPT · #24924 ·
|
Fixes #24924
Clause-②: no — nothing a write could send before is refused now; a save naming another channel gains one advisory in the write answer's existing
warnings.What changes
This is the 18.x half of execution card ② of the maintainer's ruling D on #24770.
sys_notification_template.channelnames a channel that reads a template row (emailorsms), or the write is warned about. Patch round 1 replaced the refusal this PR first shipped: the seat's correction is on the card, comment 6300407976.formatvalidation rule,channel_renders_template, atseverity: 'warning'. Its pattern is built from a singleTEMPLATE_CHANNELSconstant (email,sms). A write naming any other channel is accepted and stored, and it reports one advisory. The advisory carriesrule: 'channel_renders_template',severity: 'warning',field: 'channel',code: 'invalid_format', and this message: "This channel never uses a notification template: only email and sms do, so this template will never be sent. For in-app (inbox) content, write an email template (email_template) and name it in the notify step's template; email and the inbox both render it."allview's empty state, and thechannelandsubjecthelp now say which channels use a row and that the inbox never does. They are translated in zh-CN, ja-JP and es-ES, as is the warning. The es-ES and ja-JP leaves for the changed keys were untranslated English fills; they are translations now, so their provenance hashes drop.content/docs/permissions/authentication.mdx, the "SMS text customisation & localisation" paragraph loses the retired-seed sentence. It now states what PR fix(service-messaging): resolve a notification template in the recipient's organization #24930 made true: the auth SMS row is read intenancy.defaultOrgId(). Undersinglethat is the Default Organization's row. Underisolatedandgroupno row is read and the built-in text is sent.packages/spec/**(thescript.config.templatetombstone half belongs to spec: the script.config.template tombstone points authors at sys_notification_template, which notify's owntemplatekey superseded (ruling D on #24770) #24965 in the spec lane),template-renderer.ts, and the channels.Release reading (standing rule 甲)
The ruling record (
6293376907) reads: "② refuses stored or new non-email/sms rows. If no stored-row conversion carries that, 18.x warns on write and corrects the copy, and the refusal is filed for 19.0."Where the warning reaches (measured)
Measured on a real ObjectQL with SqlDriver at this branch; the protocol half is a scratch test that is not committed.
createData)warningswith the hitupdateData)warningswith the hitinsertManyData)ok: true, nowarningsupdateManyData)success, nowarningsemail/smswrite; an edit of a stored row not namingchannelwarningskeyonValidationAdvisorylistener. These are pinned.crud-routes.ts,res.status(201).json(result)andres.json(result)), so their callers receivewarnings.warningsmember is the existing write-answer field the spec already declares (CreateDataResponseSchema/UpdateDataResponseSchema/CloneDataResponseSchema). No response field or other surface is added.warningswas not measured.Validation rule 'channel_renders_template' (warning): This channel never uses a notification template: ….Why a
formatrule and not aselectOption membership on a
selectis a field constraint in objectql's record validator. It refuses, and has no advisory severity, so it would be the 19.0 refusal and cannot be the 18.x warning.For whoever builds 19.0, measured in round 1 at this branch's base, the
selectspelling:inboxon an insert carrying an import'skeptOptionValues;varchar(64)tovarchar(255).At the console pin
616df6598, objectui'sSelectFieldclears an out-of-set stored value on load. A Setup edit of a storedinboxrow would therefore savechannel: null, which is refused asrequired. That is a source reading, not a browser run.A correction to the copy the dispatch asked for
The dispatch asked the copy to say that a notify node naming a
templateuses that email template on every channel. That is false for SMS at this commit.sms-channel.tshas no template path: it never readspayload.template, and it loads the(topic, 'sms', locale)row whether or not the notification names an email template. On the template path,notify-node.tssets no title or body, so with no row the SMS body is the topic. The shipped copy says what is true: email and the inbox render the named email template, and SMS still uses its row.Tests
packages/services/service-messaging/src/objects/notification-template-channel.integration.test.tshas 15 cases on a real ObjectQL with SqlDriver over better-sqlite3.inbox,push,webhook,Emailor' sms', an insert carryingkeptOptionValues, a by-id update, a predicate update, and a write re-naming a stored row's channel. Each is accepted, the row is stored as written, and exactly one advisory nameschannel_renders_templateonchannel(invalid_format,severity: 'warning'), with the message head andemail_template.emailandsmsinserts, and an email-to-sms update, produce no advisory.[\s\S]*throughscripts/ablation-replace.mjs. The 9 warning cases went red ("expected [] to have a length of 1 but got +0") and the other 6 stayed green. Restored blob == HEAD84c52411f6b9;git diff HEADis empty.^(?!)$. The 3 silence cases went red ("expected [ { …(5) } ] to deeply equal []") and the other 12 stayed green. Restored blob == HEAD84c52411f6b9.c7102b32f.pnpm --filter @objectstack/service-messaging run typecheckexits 0. The suite passes: 54 files, 608 tests.@objectstack/plugin-auth'sphone-sms-template-organization.integration.test.tsandphone-sms-seed-retired.test.tspass: 7 tests.check-changeset-no-major --base origin/main --eventwith this body's declaration reads "LEVEL AXIS: this PR declares clause-②no", with no direction arm, and passes atpatch.check-adr-0087-registrationreads "this PR adds no declared-breaking changeset".dispatch-gates --commandsderives 98 commands atc7102b32f; each was run with its exit code captured, and the result is in the os-dev-report on the card.Acceptance notes
template(see the correction above). Not filed: no measured producer sends a templated notify onsms. HotCRM's 19 templated notify nodes use inbox and email, and the examples name no template, so there is no reach reading. Carrier: thedomain:servicesseat (the Notification templates and subscriptions authored in Setup have no effect on the app's notifications #24770 family). Dedupe words: sms channel notify template ignored; payload.template sms; templated notify sms topic body.origin/mainis ahead of this branch's last merge (5d27d326c) and does not conflict (a local merge-tree is clean), so it was not merged again.Generated by Claude Code