Skip to content
54 changes: 54 additions & 0 deletions .changeset/retire-adr-0030-notification-event-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
'@objectstack/metadata': minor
'@objectstack/spec': minor
---

**BREAKING** — retire the `adr-0030-notification-event` data migration.

`migrateSysNotificationToEvent` had no way to be run: zero production callers
anywhere in the repo, and no `os migrate` sub-command, while the two sibling
members of `CREATION_ATTESTED_MIGRATION_IDS` had both. The runner, its barrel
export, its tests, the ruled `sys_migration` receipt-claim matrix, that matrix's
pin, and the id's membership in `CREATION_ATTESTED_MIGRATION_IDS` are removed
together. Pre-ADR-0030 `sys_notification` rows are not carried by the platform
on this line.

## What is gone, and what an upgrader does about it

⭐ **Nothing is renamed and nothing replaces it**, so there is no new spelling to
adopt — every item below is a deletion, and the fix is to stop using it.

- `migrateSysNotificationToEvent` (`@objectstack/metadata/migrations`) — deleted.
No replacement exists, and none is coming: an `os migrate notification-event`
sub-command was considered and refused. Delete the call. The compiler delivers
this one: the import fails to resolve.
- `SysNotificationMigrationResult`, `SysNotificationMigrationOptions` and
`SysNotificationMigrationReceipt` (same entry point) — deleted with it. They
described that runner's own result, options and receipt and nothing else.
- `CREATION_ATTESTED_MIGRATION_IDS` (`@objectstack/spec/system`) — was a
three-member tuple and is now a two-member one holding
`'adr-0104-file-references'` and `'adr-0104-value-shapes'`. Both ADR-0104 ids
keep their sub-commands, their receipt rows and their birth attestation; only
the notification id left. Code typed against
`(typeof CREATION_ATTESTED_MIGRATION_IDS)[number]` that names the notification
id no longer compiles — delete that arm.

`NOTIFICATION_EVENT_MIGRATION_ID` (`@objectstack/spec/system`) is **kept**. A
deployment attested at birth, or one that made the operator call while the runner
shipped, still holds a `sys_migration` row keyed `'adr-0030-notification-event'`,
and the constant is that row's name. Nothing writes or reads a row under it any
more — `attestFreshDatastore` no longer includes it — and it is not a
registration: it gates nothing and never did.

## Reversal path

Two answers were considered and both refused: an `os migrate notification-event`
sub-command is a permanent operator surface for a migration with no measured
demand, and a boot-time invoker is an unattended data rewrite nobody asked for.
⚠️ Nobody has measured whether any live deployment carries pre-ADR-0030
`sys_notification` rows. If a **named** deployment turns out to hold rows it
needs, the migration returns as an operator-runnable sub-command shaped exactly
like `files-to-references` / `value-shapes` — dry-run default, `--apply` gate,
documented consequence — under its own card.

<!-- adr-0087: not-required (no-migration-prescription) Nothing authorable moves and nothing is renamed: no spec key, no config field, no stored-metadata shape, and no replacement spelling for anyone to adopt. The removed surfaces are one runtime function on `@objectstack/metadata/migrations`, its three own result/option/receipt types, and one member of a constant tuple — none of which appears in any authorable document, so `objectstack migrate meta` has nothing it could rewrite and a ledger entry would prescribe a rewrite that does not exist. The consumer-side action is a deletion, delivered by the compiler on the import and by the barrel tombstone beside it. -->
47 changes: 36 additions & 11 deletions docs/handoff/adr-0030-notification-convergence.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,24 +62,43 @@ a per-user inbox row directly.
a `dedupKey`. No more direct `sys_notification` writes. The plugin resolves the
`messaging` service lazily at hook time (`audit-plugin.ts`).

### Data migration (not auto-run)
### ⚰️ Data migration — RETIRED, there is none

This section used to describe
`packages/metadata/src/migrations/migrate-sys-notification-to-event.ts`
(exported from `@objectstack/metadata/migrations`). Splits each legacy
`sys_notification` inbox row into `sys_inbox_message` + a receipt, rewrites the
row to the event shape, and clears the legacy columns. **Idempotent**; reports
`not_applicable` on fresh installs.
(exported from `@objectstack/metadata/migrations`), which split each legacy
`sys_notification` inbox row into `sys_inbox_message` + a receipt, rewrote the
row to the event shape and cleared the legacy columns.

**That runner is gone (#16194).** It had zero production callers and no
`os migrate` sub-command, and both ways of giving it one were refused: an
operator door is a permanent surface for a migration with no measured demand,
and a boot-time invoker is an unattended data rewrite. ⇒ **Pre-ADR-0030
`sys_notification` rows are not carried by the platform on this line.** After
the cut-over the bell shows rows emitted from the new pipeline onward; older
per-user inbox rows stay where they are, unread by the new UI.

⚠️ Nobody has measured whether any live deployment still holds pre-ADR-0030
`sys_notification` rows. If **your named deployment** does and needs them, ⛔ do
not re-add the call — the migration returns as an operator-runnable `os migrate`
sub-command shaped exactly like `files-to-references` / `value-shapes` (dry-run
default, `--apply` gate, documented consequence), under its own card. Say so on
#16194.

### Tests
`messaging-service`, `inbox-channel`, `messaging-service-plugin`, `notify-node`,
and the migration all have updated/added coverage. All green.
`messaging-service`, `inbox-channel`, `messaging-service-plugin` and
`notify-node` all have updated/added coverage. All green. (The migration's own
suites went with the runner.)

---

## ⚠️ Breaking change — Console bell (objectui, separate repo)

The bell read `sys_notification.{recipient_id, is_read, title, body, …}`. Those
fields **no longer exist**. Until objectui is updated, the bell will be empty /
error. **Do the objectui cut-over and the data migration together.**
error. ⚰️ There is **no data migration to pair it with** any more (see above):
do the objectui cut-over on its own, and expect the bell to start from the
rows the new pipeline emits.

### objectui changes required (`app-shell`)
1. **`AppHeader.tsx` / `InboxPopover.tsx`**: poll **`sys_inbox_message`** filtered
Expand All @@ -98,13 +117,19 @@ error. **Do the objectui cut-over and the data migration together.**
### Cut-over sequence (avoid a blank bell)
1. Deploy this framework change (objects + emit + producers). New notifications
now land in `sys_inbox_message` + receipts.
2. Run `migrateSysNotificationToEvent({ driver, data })` to carry existing
notifications into `sys_inbox_message` + receipts.
3. Deploy the objectui bell repoint.
2. Deploy the objectui bell repoint.

(Step order tolerates a brief window where new rows exist but the UI hasn't
flipped — the inbox is being populated the whole time.)

> ⚰️ **This sequence used to have three steps.** The middle one was
> `migrateSysNotificationToEvent({ driver, data })`, carrying pre-cut-over
> `sys_notification` rows into `sys_inbox_message` + receipts. That runner is
> retired (#16194) and **pre-ADR-0030 rows are not carried by the platform on
> this line** — the reasoning, the unmeasured-deployment caveat and the reversal
> path are in [Data migration — RETIRED](#-data-migration--retired-there-is-none)
> above. ⛔ Do not re-add the call here.

---

## Behavior notes / watch-outs
Expand Down
10 changes: 6 additions & 4 deletions packages/metadata/src/migrations/driver-exec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
* `(path, init)`. `SqlDriver` keeps its knex handle `protected`, so
* `driver.raw` is `undefined` there too, and `SqliteWasmDriver` inherits that.
* The result was a published, operator-documented migration path that refused
* every driver the platform ships — quietly, because
* `migrateSysNotificationToEvent` *returns* `{ status: 'error' }` rather than
* throwing, and the message blamed the operator's driver instead of saying the
* migration did not run.
* every driver the platform ships — quietly, because the helper that found the
* defect *returned* `{ status: 'error' }` rather than throwing, and the message
* blamed the operator's driver instead of saying the migration did not run.
* (That helper — the ADR-0030 notification cut-over — has since been retired
* whole; the surface argument below is what outlived it, and every remaining
* migration in this directory depends on it.)
*
* ## Why `execute` is tried FIRST
*
Expand Down
35 changes: 29 additions & 6 deletions packages/metadata/src/migrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,32 @@ export { dropProjectionTables, type DropProjectionResult } from './drop-projecti
*/


export {
migrateSysNotificationToEvent,
type SysNotificationMigrationResult,
type SysNotificationMigrationOptions,
type SysNotificationMigrationReceipt,
} from './migrate-sys-notification-to-event.js';
/**
* ⚰️ TOMBSTONE — `migrateSysNotificationToEvent` /
* `migrate-sys-notification-to-event.ts` (with `SysNotificationMigrationResult`
* / `SysNotificationMigrationOptions` / `SysNotificationMigrationReceipt`) was
* REMOVED. ⛔ Do not reintroduce a runner for the ADR-0030 notification
* cut-over in this package.
*
* It had no way to be run. Re-measured on the tree this tombstone landed on:
* ZERO production callers anywhere in `packages` / `apps` / `examples` — the
* definition, its own usage docblock, this barrel line, one comment in
* `./driver-exec.ts`, the id's docblock in `@objectstack/spec` and three test
* files were every non-CHANGELOG occurrence there was. The instrument was live
* in the same run: the symbol was in 17 files.
*
* Two ways to give it one were considered and both refused. An
* `os migrate notification-event` sub-command shaped like its two
* `CREATION_ATTESTED_MIGRATION_IDS` siblings is a permanent operator surface
* for a migration with no measured demand; a boot-time invoker is an
* unattended data rewrite nobody asked for. Pre-ADR-0030 `sys_notification`
* rows are not carried by the platform on this line.
*
* ⚠️ Stated rather than papered over: nobody has measured whether any live
* deployment carries pre-ADR-0030 `sys_notification` rows. If a NAMED
* deployment turns out to hold rows it needs, the migration returns as an
* operator-runnable sub-command shaped exactly like `files-to-references` /
* `value-shapes`, under its own card — with the dry-run posture, the `--apply`
* gate and the documented consequence those two carry, none of which this one
* ever had.
*/
Loading
Loading