Repository navigation
Commit 0603bfa
fix(service-messaging)!: sys_notification_template.channel accepts only email and sms, the channels that read a template (#24976)
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.channel` names a channel that
reads a template row (`email` or `sms`), 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.
- **Write warning.** The object declares one `format` validation rule,
`channel_renders_template`, at `severity: 'warning'`. Its pattern is
built from a single `TEMPLATE_CHANNELS` constant (`email`, `sms`). A
write naming any other channel is **accepted and stored**, and it
reports one advisory. The advisory carries `rule:
'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."
- **Copy.** The object description, the `all` view's empty state, and
the `channel` and `subject` help 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.
- **Docs.** In `content/docs/permissions/authentication.mdx`, the "SMS
text customisation & localisation" paragraph loses the retired-seed
sentence. It now states what PR #24930 made true: the auth SMS row is
read in `tenancy.defaultOrgId()`. Under `single` that is the Default
Organization's row. Under `isolated` and `group` no row is read and the
built-in text is sent.
- **Not touched:** `packages/spec/**` (the `script.config.template`
tombstone half belongs to #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."
- No ADR-0087 conversion carries this narrowing, because the rows are
stored data of a platform object, not authored metadata.
- So 18.x ships the warning half and the corrected copy.
- The refusal of stored and new rows is filed for 19.0, by the seat.
- Nothing in this PR refuses a write, and no pin asserts a refusal.
## 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.
| Write | Accepted and stored | What the caller is answered | Server log
|
|---|---|---|---|
| single-record create (`createData`) | yes | `warnings` with the hit |
one line |
| single-record update (`updateData`) | yes | `warnings` with the hit |
one line |
| import commit (`insertManyData`) | yes | outcome `ok: true`, no
`warnings` | one line |
| bulk update (`updateManyData`) | yes | `success`, no `warnings` | one
line |
| `email` / `sms` write; an edit of a stored row not naming `channel` |
yes | no `warnings` key | none |
- At the engine, insert, by-id update and predicate update each hand
exactly one hit to that write's own `onValidationAdvisory` listener.
These are pinned.
- REST's create and update routes relay the protocol answer whole
(`crud-routes.ts`, `res.status(201).json(result)` and
`res.json(result)`), so their callers receive `warnings`.
- The `warnings` member is the existing write-answer field the spec
already declares (`CreateDataResponseSchema` /
`UpdateDataResponseSchema` / `CloneDataResponseSchema`). No response
field or other surface is added.
- Bulk and import commits report the hit only in the log. Whether the
console displays a create or update answer's `warnings` was not
measured.
- The log line reads: `Validation rule 'channel_renders_template'
(warning): This channel never uses a notification template: …`.
## Why a `format` rule and not a `select`
Option membership on a `select` is 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
`select` spelling:
- refuses with the generic "Channel must be one of: email, sms", with no
per-field sentence to carry the email-template pointer;
- admits `inbox` on an insert carrying an import's `keptOptionValues`;
- moves the column from `varchar(64)` to `varchar(255)`.
At the console pin `616df6598`, objectui's `SelectField` clears an
out-of-set stored value on load. A Setup edit of a stored `inbox` row
would therefore save `channel: null`, which is refused as `required`.
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
`template` uses that email template on every channel. That is false for
SMS at this commit. `sms-channel.ts` has no template path: it never
reads `payload.template`, and it loads the `(topic, 'sms', locale)` row
whether or not the notification names an email template. On the template
path, `notify-node.ts` sets 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
- **New test file.**
`packages/services/service-messaging/src/objects/notification-template-channel.integration.test.ts`
has 15 cases on a real ObjectQL with SqlDriver over better-sqlite3.
- Warnings: an insert naming `inbox`, `push`, `webhook`, `Email` or `'
sms'`, an insert carrying `keptOptionValues`, 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 names
`channel_renders_template` on `channel` (`invalid_format`, `severity:
'warning'`), with the message head and `email_template`.
- Silence: `email` and `sms` inserts, and an email-to-sms update,
produce no advisory.
- Stored-row preservation: editing other columns gives no advisory,
delete works, and the row renders on neither channel.
- **Ablation, rule inert.** The pattern became `[\s\S]*` through
`scripts/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 == HEAD `84c52411f6b9`; `git diff HEAD` is empty.
- **Inverse ablation, rule warns on everything.** The pattern became
`^(?!)$`. The 3 silence cases went red ("expected [ { …(5) } ] to deeply
equal []") and the other 12 stayed green. Restored blob == HEAD
`84c52411f6b9`.
- **Package checks at `c7102b32f`.** `pnpm --filter
@objectstack/service-messaging run typecheck` exits 0. The suite passes:
54 files, 608 tests.
- **Import side.** `@objectstack/plugin-auth`'s
`phone-sms-template-organization.integration.test.ts` and
`phone-sms-seed-retired.test.ts` pass: 7 tests.
- **Changeset level.** `check-changeset-no-major --base origin/main
--event` with this body's declaration reads "LEVEL AXIS: this PR
declares clause-② `no`", with no direction arm, and passes at `patch`.
`check-adr-0087-registration` reads "this PR adds no declared-breaking
changeset".
- **Gates.** `dispatch-gates --commands` derives 98 commands at
`c7102b32f`; each was run with its exit code captured, and the result is
in the os-dev-report on the card.
## Acceptance notes
- **SMS ignores a notify `template`** (see the correction above). Not
filed: no measured producer sends a templated notify on `sms`. HotCRM's
19 templated notify nodes use inbox and email, and the examples name no
template, so there is no reach reading. Carrier: the `domain:services`
seat (the #24770 family). Dedupe words: sms channel notify template
ignored; payload.template sms; templated notify sms topic body.
- **Bulk updates and import commits** answer the warning only in the
server log, not in their answer (measured above). This PR adds no
surface to carry it. Noted, not filed. Carrier: none.
- `origin/main` is 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](https://claude.ai/code/session_01UmqzD97e14iws6hmVhgZ5y)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent ba69b16 commit 0603bfa
10 files changed
Lines changed: 350 additions & 33 deletions
File tree
- .changeset
- content/docs/permissions
- packages/services/service-messaging/src
- objects
- translations
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
443 | 443 | | |
444 | 444 | | |
445 | 445 | | |
446 | | - | |
447 | | - | |
448 | | - | |
449 | | - | |
450 | | - | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
451 | 462 | | |
452 | 463 | | |
453 | 464 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
0 commit comments