You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 0f17ba7
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: .changeset/24899-archived-mail-bodies.md
+5-2Lines changed: 5 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -11,6 +11,9 @@ Clause-②: yes (widening)
11
11
12
12
-**What was left in clear.**`sys_audit_log` declares `lifecycle.archive: { after: '90d', to: 'archive', keep: '7y' }`. Past the hot window, the lifecycle Archiver copies its rows to the datasource named `archive` as they are, then deletes them hot. A `sys_email` / `sys_identity_email` copy archived before the audit writer masked the mail body still holds `body_text` / `body_html` in clear there, password-reset, verification, magic-link and invitation links included, for as long as the archive keeps it. The engine never routes `sys_audit_log` to the archive, so the hot run could not reach those rows.
13
13
-**What changed.** After the hot run, the command reads the archive target each copy table declares (`sys_audit_log` only; `sys_activity` declares none) and runs the same mask, in the same dry-run or `--apply` mode, through that datasource's driver. Each archived row keeps every other column, `updated_at` included. The run is idempotent and its report is counts only. A hot copy masked first is archived masked, so one run covers both the copies already archived and the ones still to be.
14
-
-**Which archives it reaches.** The command now connects the datasources the stack config declares, as `os serve` does. An archive datasource is declared with `autoConnect: true`, since nothing routes objects to it. If the archive is instead a runtime datasource created in Setup → Datasources, which `os serve` connects and this command does not, the run reports it `not-connected` and exits `1` rather than reporting a clean archive. Declare it in the config's `datasources` and re-run.
15
-
-**New in the `--json` document:** an `archive` array, one entry per declared target: `{ datasource, objects, status, report? }`, with `status` one of `examined`, `none`, `not-connected` or `unknown`. The `report` key and its shape are unchanged.
14
+
-**Which archives it reaches.** The command now connects the managed datasources the stack config declares, through the same connect service `os serve` uses. An archive datasource is declared with `autoConnect: true`, since nothing routes objects to it. It is NOT examined, and the run reports `not-connected` and exits `1` rather than reporting a clean archive, in two cases. In the first, the archive is declared but this boot did not connect it; the entry carries the connect status and reason. In the second, the archive is a runtime datasource created in Setup → Datasources, which `os serve` connects and this command does not; declare it in the config's `datasources` and re-run.
15
+
-**What `none` means.** No datasource of that name is declared and connected on this boot, none was attempted, and no active runtime datasource row names one. That is all it checks. An archive a host registers in code outside the stack config is not reached and reads `none`. To mask it, declare it in the stack config's `datasources` with `autoConnect: true`.
16
+
-**The command's boot can now fail on a declared datasource.** A bound, mapped or boot-critical declared datasource that cannot connect now fails the command's boot with exit `1`, as it fails `os serve`'s. `OS_ALLOW_DRIVER_CONNECT_FAILURE` is the same escape.
17
+
-**Run it with the server stopped**, or re-run it once and read 0 to mask in both halves. A live server's Archiver can move a row between the hot run and the archive run.
18
+
-**New in the `--json` document:** an `archive` array, one entry per declared target: `{ datasource, objects, status, report?, connection? }`, with `status` one of `examined`, `none`, `not-connected` or `unknown`. The `report` key and its shape are unchanged.
16
19
-**New exports from `@objectstack/plugin-audit`:**`migrateArchivedMailLogBodyCopies(driver, logger, options)`, the runner over a datasource's driver, and an `objects` option on both runners, which limits a run to the named copy tables. Types `MailLogBodyArchiveDriver`, `MailLogBodyCopyObject` and `MailLogBodyMigrationOptions`.
`lifecycle.archive: { after: '90d', to: 'archive', keep: '7y' }`: past the hot
@@ -1516,9 +1522,9 @@ every other column, `updated_at` included. A hot copy masked first is archived
1516
1522
masked, so one run covers both the copies already archived and the ones still
1517
1523
to be. `sys_activity` declares no archive: its copies are only ever hot.
1518
1524
1519
-
The command connects the datasources the stack config declares, as `os serve`
1520
-
does, so it reaches an archive declared there. A managed datasource nothing
1521
-
routes to is connected only with `autoConnect: true`, which is how an archive
1525
+
The command connects the managed datasources the stack config declares through
1526
+
the same connect service `os serve` uses. A managed datasource nothing routes
1527
+
to is connected only with `autoConnect: true`, which is how an archive
1522
1528
datasource is declared:
1523
1529
1524
1530
```ts
@@ -1533,12 +1539,17 @@ The `--json` document carries one `archive` entry per declared target, with a
1533
1539
| `status` | Meaning | Exit |
1534
1540
| :--- | :--- | :--- |
1535
1541
| `examined` | Connected and masked (or counted); `report` holds the counts | `0`, or `1` on a failed read or write |
1536
-
| `none` | No such datasource, and no runtime datasource row of that name: the Archiver retains every row hot, so nothing was archived | `0` |
1537
-
| `not-connected` | The database holds an active runtime datasource of that name (one created in Setup → Datasources). `os serve` connects it; this command does not, so the archive was **not** examined | `1` |
1542
+
| `none` | No datasource of that name is declared and connected on this boot, none was attempted, and no active runtime datasource row names one. That is all it checked | `0` |
1543
+
| `not-connected` | The archive was **not** examined. Either the stack config declares it and this boot did not connect it (`connection` carries the connect status and reason), or the database holds an active runtime datasource of that name (one created in Setup → Datasources), which `os serve` connects and this command does not | `1` |
1538
1544
| `unknown` | Not connected, and the datasource rows could not be read | `1` |
1539
1545
1540
-
On `not-connected`, declare the archive datasource in the stack config's
1541
-
`datasources` (with `autoConnect: true`), then re-run.
1546
+
On `not-connected` for a runtime datasource, declare the archive datasource in
1547
+
the stack config's `datasources` (with `autoConnect: true`), then re-run. For a
1548
+
declared one, make it reachable from where the command runs, then re-run.
1549
+
1550
+
An archive that a host registers in code outside the stack config (a plugin
1551
+
that publishes the driver itself) is not reached and reads `none`. To mask it,
1552
+
declare it in the stack config's `datasources` with `autoConnect: true`.
Copy file name to clipboardExpand all lines: packages/cli/src/commands/migrate/audit-mail-bodies.archive.integration.test.ts
+51-13Lines changed: 51 additions & 13 deletions
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,5 @@
1
1
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2
-
// test-budget: 70 — spawns the real producer once per single-cause fixture: two served-shape boots that run the real Archiver, and five spawns of the source CLI (dry run, --apply, re-run over the archive fixture; --apply on a project with no archive; a dry run with a runtime archive row); 54.7 s, the slower of two local runs on a shared container, x 1.25, no CI reading yet
2
+
// test-budget: 70 — spawns the real producer once per single-cause fixture: two served-shape boots that run the real Archiver, and six spawns of the source CLI (dry run, --apply, re-run over the archive fixture; --apply on a project with no archive; a dry run with a runtime archive row; --apply with a declared archive that cannot connect); 54.7 s, the slower of two local runs on a shared container, x 1.25, no CI reading yet
3
3
4
4
/**
5
5
* [#24899] `os migrate audit-mail-bodies` masks the mail-log bodies the
@@ -40,6 +40,10 @@
40
40
* connects and this command's boot does not) is NOT reported clean: the
41
41
* archive reads `not-connected` and the command exits 1. With neither a
42
42
* connected datasource nor such a row it reads `none` and exits 0.
43
+
* 7. A DECLARED `autoConnect: true` archive this boot cannot connect is NOT
44
+
* reported clean either: gate (c) is not fail-fast, so the boot degrades
45
+
* and leaves no driver, and the archive reads `not-connected`, carrying
46
+
* the connect service's verdict, and the command exits 1.
43
47
*
44
48
* ⛔ The bodies are sentinels, never a link or a token, and every comparison is
0 commit comments