Skip to content

Commit 2b3b323

Browse files
committed
docs(releases): record the HotCRM 17.4.0 -> 17.5.0 findings on the 17.5.0 notes
- The edge-branched decision flip gets a 17.4.0 -> 17.5.0 table and a standing warning that flows stored in sys_metadata take the new meaning unrewritten; its checklist line says to review each offered mode: 'inclusive' (deleting it where the conditions partition, or flow-decision-inclusive-overlap follows) and then the --stored list. - The protocol declarations: 17.5.0 still implements protocol 17 and the handshake compares only the major, so engines.protocol stays '^17' and a ^17.0.0 specVersion admits 17.5.0; "protocol 18" names the migration registry's next major, whose shapes the 17.5.0 schemas already refuse. - Seven checklist lines carry what an upgrade of HotCRM (a 17.4.0 app with a 17.4.0-created SQLite DB) observed on 2026-09-29; every other line stays not exercised, and the v17 index callout says the hop was exercised only in part. Claude-Session: https://claude.ai/code/session_014VGCS11YUtYAiinRcdqQwL Co-authored-by: Claude <noreply@anthropic.com>
1 parent da443bd commit 2b3b323

2 files changed

Lines changed: 94 additions & 47 deletions

File tree

‎content/docs/releases/v17/17-5.mdx‎

Lines changed: 87 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@ Most retirements in this release are registered as ADR-0087 conversions under
151151
conversion exists — since this release `--to` defaults to the highest major the
152152
installed `@objectstack/spec` has a step for, so the command the refusals
153153
prescribe no longer answers `✓ Nothing to migrate` (`fb39b38`, #17462).
154+
"Protocol 18" is the migration registry's next major, not the runtime's:
155+
17.5.0 still implements protocol 17 (`os migrate meta` prints "this runtime
156+
implements protocol 17"), and its schemas already refuse every shape those
157+
steps convert. An app therefore keeps `engines.protocol: '^17'` — see the
158+
[upgrade checklist](#upgrade-checklist).
154159

155160
#### Scheduled work is off until a deployment turns it on (#18198, #17334, #18420)
156161

@@ -688,23 +693,28 @@ rules. Each refusal is `INVALID_FILTER` / `400` at run time and
688693
A `decision` node that declares no `config.conditions` and branches on its
689694
out-edges used to take **every** out-edge whose condition held, one after
690695
another, while its schema and docs called it an exclusive gateway
691-
(`0283cb9`, #20344). It is now exclusive: the first out-edge whose condition
692-
holds, in declaration order, runs, and the next records a `skipped` step.
693-
`mode: 'inclusive'`, accepted and never read before, now takes every true
694-
branch. When none holds, the `isDefault` edge runs as before. A `mode` beside a
695-
non-empty `conditions` list, or outside `'exclusive'` / `'inclusive'`, is
696-
refused at `registerFlow` and by `os validate`.
696+
(`0283cb9`, #20344). It is now exclusive, and `mode: 'inclusive'` is how a
697+
decision asks for every true branch:
698+
699+
| an edge-branched `decision` with no `conditions` | 17.4.0 | 17.5.0 |
700+
|:--|:--|:--|
701+
| no `mode`, two conditioned out-edges both hold | both successors run, sequentially | the first declared one runs; the second records a `skipped` step |
702+
| `config: { mode: 'inclusive' }` | accepted, never read | every out-edge whose condition holds runs, sequentially |
703+
| no condition holds | the `isDefault` edge runs | unchanged |
704+
| `mode` beside a non-empty `conditions` list, or not `exclusive` / `inclusive` | refused by a direct parse only | refused at `registerFlow` and by `os validate` |
705+
706+
⚠️ **A flow stored in `sys_metadata` is not rewritten and silently takes the
707+
new meaning**: nothing about a stored row says it was saved before the flip,
708+
so a decision the Studio designer saved runs first-match from the upgrade on.
697709

698710
**Migration.** `os migrate meta --from 17` writes `mode: 'inclusive'` onto
699711
every authored decision with no `conditions` and two or more conditioned
700712
out-edges, so a migrated flow runs as it did. Then review each written key:
701713
delete it where the conditions partition (`== 'a'` beside `!= 'a'`, a guard
702714
beside `isDefault: true`), and keep it where the flow relies on more than one
703715
branch running. `os validate` reports `flow-decision-inclusive-overlap` on
704-
every decision that keeps it, so the review list is the lint output. ⚠️ **A
705-
decision stored in `sys_metadata` is not rewritten** — nothing about a stored
706-
row says it was saved before the flip — so it runs first-match from the
707-
upgrade on. `os migrate meta --stored` lists every such node under
716+
every decision that keeps it, so the review list is the lint output. For the
717+
stored rows, `os migrate meta --stored` lists every such node under
708718
`decisionModeReview` and writes nothing for it; add
709719
`config: { mode: 'inclusive' }` to each one that meant every branch.
710720

@@ -1651,15 +1661,17 @@ walked](/docs/releases/v17#upgrade-checklists).
16511661

16521662
### 17.5.0
16531663

1654-
⛔ **Nobody has walked 17.4.0 → 17.5.0.** Every line below is derived from a
1655-
change's own **Migration** note in [Breaking changes & migration in
1656-
17.5.0](#breaking-changes--migration-in-1750) — or, for the cube member
1657-
`name`, in [Also shipped in 17.5.0](#also-shipped-in-1750--not-in-its-changelog)
1658-
— and is marked **not exercised**: accurate about what changed, unproven about
1659-
what it costs to cross. A step
1660-
nobody has run, presented beside steps that were, is how a reader finishes a
1661-
checklist and believes they are done — so this list claims nothing it has not
1662-
been given.
1664+
⛔ **Nobody has walked the whole of 17.4.0 → 17.5.0.** Seven lines below were
1665+
run in an upgrade of HotCRM — a 17.4.0 app with a 17.4.0-created SQLite
1666+
database — on 2026-09-29, and each says what was observed. Every other line
1667+
is derived from a change's own **Migration** note in [Breaking changes &
1668+
migration in 17.5.0](#breaking-changes--migration-in-1750) — or, for the cube
1669+
member `name`, in [Also shipped in
1670+
17.5.0](#also-shipped-in-1750--not-in-its-changelog) — and is marked **not
1671+
exercised**: accurate about what changed, unproven about what it costs to
1672+
cross. A step nobody has run, presented beside steps that were, is how a
1673+
reader finishes a checklist and believes they are done — so this list claims
1674+
nothing it has not been given.
16631675

16641676
**Before you upgrade**
16651677

@@ -1673,32 +1685,55 @@ been given.
16731685
`OS_AUTOMATION_SCHEDULED_WORK_ENABLED=true`; under `isolated`, add
16741686
`organization` to each scheduled flow's start-node `config` first, and drain
16751687
suspended runs. *Not exercised.*
1688+
- **Read the scheduled-work switch with `os doctor`**, which prints its
1689+
effective value. *Exercised on HotCRM (a 17.4.0 app with a 17.4.0-created
1690+
SQLite DB), 2026-09-29:* it showed "Package-authored scheduled work OFF (the
1691+
default)".
16761692
- **Run `os migrate account-issuer`** against each existing database and
1677-
resolve every collision it reports, then back up. *Not exercised.*
1693+
resolve every collision it reports, then back up. *Exercised on HotCRM (a
1694+
17.4.0 app with a 17.4.0-created SQLite DB), 2026-09-29:* on the 17.4.0
1695+
database the pre-flight reported the column safe to drop.
16781696
- **Give every `api` flow's start node a non-blank `config.secret`**, and sign
16791697
each post with it, or declare a flow that is only started explicitly
16801698
`type: 'autolaunched'`; an `api` flow without one stops registering at boot.
16811699
*Not exercised.*
16821700

16831701
**Getting onto the release**
16841702

1685-
- **Move all the `@objectstack/*` pins as one set, regenerate the lockfile, and
1686-
leave `specVersion` / `engines.protocol` alone** — this is a move inside one
1687-
major. The full procedure is [Moving the dependency
1703+
- **Move all the `@objectstack/*` pins as one set and regenerate the
1704+
lockfile.** The full procedure is [Moving the dependency
16881705
pins](/docs/upgrading#moving-the-dependency-pins). Move all eleven
16891706
`@better-auth/*` members to exactly `1.7.3` together, and any `zod` you pin
16901707
yourself to `^4.6.1` or higher. *Not exercised.*
1708+
- **Leave the protocol declarations on 17:** `engines.protocol: '^17'`, and a
1709+
`specVersion` range such as `^17.0.0` in `objectstack.manifest.json`, which
1710+
admits 17.5.0. The runtime still implements protocol 17 — `os migrate meta`
1711+
prints "this runtime implements protocol 17" — and its handshake compares
1712+
only the major, so `^17` keeps loading across every 17.x release, while a
1713+
`^18` range is refused `OS_PROTOCOL_INCOMPATIBLE`. The "protocol 18" on the
1714+
refusals and on `os migrate meta`'s steps is the migration registry's next
1715+
major, under which this release records its retirements; the 17.5.0 schemas
1716+
already refuse those shapes, which is why `os migrate meta --from 17` runs
1717+
its chain to 18. *Not exercised.*
16911718
- **Apply the `sys_account` drop:** `os migrate apply --allow-destructive`, then
16921719
`os migrate account-issuer` again, expecting zero. *Not exercised.*
16931720
- **Do not read `os migrate meta --from 17` answering `Nothing to migrate` as
16941721
completion** of this list. It now defaults `--to` to the highest registered
16951722
major and lists the protocol-18 edits, but everything under *Data*,
1696-
*Deployment* and *Application code* below is outside its scope. *Not
1697-
exercised.*
1698-
- **Review the stored edge-branched decisions:** `os migrate meta --stored`
1699-
lists them under `decisionModeReview` and rewrites none; add
1700-
`config: { mode: 'inclusive' }` to each one that meant every true branch.
1701-
*Not exercised.*
1723+
*Deployment* and *Application code* below is outside its scope. *Exercised
1724+
on HotCRM (a 17.4.0 app with a 17.4.0-created SQLite DB), 2026-09-29:* it
1725+
ran and listed 41 refusals. Its output was 874 lines, 240 of them generic
1726+
protocol-18 notices, so filter the output for the refusals that name your
1727+
sources.
1728+
- **Review each `mode: 'inclusive'` that `os migrate meta --from 17` offers
1729+
an edge-branched decision**, and delete it where the branch conditions
1730+
partition — applied blindly, it makes `os validate` report
1731+
`flow-decision-inclusive-overlap`. Then run `os migrate meta --stored`,
1732+
which lists the stored decisions under `decisionModeReview` and rewrites
1733+
none, and add `config: { mode: 'inclusive' }` to each one that meant every
1734+
true branch. *Exercised on HotCRM (a 17.4.0 app with a 17.4.0-created
1735+
SQLite DB), 2026-09-29:* 13 decisions were offered the key, all partitioned,
1736+
so none needed it; `os migrate meta --stored` reported 0 rows.
17021737
- **Recompile every artifact built by an earlier `os compile`** before serving
17031738
cubes from it — it carries `public: false` on every cube, which now hides
17041739
them. *Not exercised.*
@@ -1717,20 +1752,29 @@ been given.
17171752
`'vertical'` (plus `columns`); list-view `sort` strings → the array form;
17181753
page and `object-*` `filter` records → the `ViewFilterRule` array; a list
17191754
view's `tabs` → one `listViews` entry per tab; delete view `owner` /
1720-
`hidden`, list-view `type: 'page'` / `pageName`, `page.assignedProfiles` and
1721-
unfulfillable `undoable: true`. *Not exercised.*
1722-
- **Rewrite the flow shapes:** give every `wait` node a `waitEventConfig`, every
1723-
`lookup` screen field a `reference`, every decision branch an `expression`
1724-
and a `label`, every builtin node the keys its executor requires, every
1725-
`connector_action` node a complete `connectorConfig`, and every evaluated
1726-
slot a non-blank `source`; move `screen` / `wait` / `approval` / `end` out of
1727-
region bodies; review each `mode: 'inclusive'` that
1728-
`os migrate meta --from 17` writes. *Not exercised.*
1729-
- **Rewrite the analytics shapes:** widget `chartConfig` structure → the
1730-
widget's `dimensions` / `values`; delete cube-join `sql` / `relationship` /
1731-
`on`; sub-day granularities → `day`; measure aggregates the field type
1732-
accepts; one measure per metric-family widget; delete `public: false` from
1733-
every cube meant to be queried. *Not exercised.*
1755+
`hidden`, list-view `type: 'page'` / `pageName` and unfulfillable
1756+
`undoable: true`. *Not exercised.*
1757+
- **Delete `page.assignedProfiles`.** *Exercised on HotCRM (a 17.4.0 app with
1758+
a 17.4.0-created SQLite DB), 2026-09-29:* the key was refused on boot
1759+
exactly as documented.
1760+
- **Rewrite the flow shapes:** give every `wait` node a `waitEventConfig`,
1761+
every decision branch an `expression` and a `label`, every builtin node the
1762+
keys its executor requires, every `connector_action` node a complete
1763+
`connectorConfig`, and every evaluated slot a non-blank `source`; move
1764+
`screen` / `wait` / `approval` / `end` out of region bodies. *Not
1765+
exercised.*
1766+
- **Give every `lookup` screen field a `reference`.** *Exercised on HotCRM (a
1767+
17.4.0 app with a 17.4.0-created SQLite DB), 2026-09-29:* applied as
1768+
documented.
1769+
- **Move each dashboard widget's `chartConfig` structure onto the widget:**
1770+
`chartConfig.type` onto the widget, `xAxis.field` to `dimensions`, and
1771+
`yAxis[].field` / `series` to `values`. *Exercised on HotCRM (a 17.4.0 app
1772+
with a 17.4.0-created SQLite DB), 2026-09-29:* 34 sites, applied as
1773+
documented.
1774+
- **Rewrite the other analytics shapes:** delete cube-join `sql` /
1775+
`relationship` / `on`; sub-day granularities → `day`; measure aggregates the
1776+
field type accepts; one measure per metric-family widget; delete
1777+
`public: false` from every cube meant to be queried. *Not exercised.*
17341778
- **Delete the retired keys:** `currencyConfig.precision`, `scale` on currency
17351779
fields, `connector.connectionTimeoutMs`, `connector.health` / `status` /
17361780
`webhooks`, `object.tenancy.organizationField`, `rowLevelSecurity[].tags`,

‎content/docs/releases/v17/index.mdx‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,13 @@ marked breaking — which is exactly why a checklist is not a restatement of
9393
[Breaking changes & migration in 17.3.0](/docs/releases/v17/17-3#breaking-changes--migration-in-1730).
9494

9595
⛔ **That run covered one hop, 17.2.0 → 17.3.0. Nobody has walked 17.1.0 →
96-
17.2.0, 17.3.0 → 17.4.0 or 17.4.0 → 17.5.0.** Every line in the 17.2.0, 17.4.0
97-
and 17.5.0 lists is derived from a change's own **Migration** note and is
98-
marked **not exercised**: accurate about what changed, unproven about what it
99-
costs to cross. The two kinds are kept apart on purpose — a step nobody has run,
96+
17.2.0 or 17.3.0 → 17.4.0, and 17.4.0 → 17.5.0 has been exercised only in
97+
part:** seven lines of the 17.5.0 list were run in an upgrade of HotCRM, a
98+
17.4.0 app with a 17.4.0-created SQLite database, on 2026-09-29, and say what
99+
was observed. Every other line in the 17.2.0, 17.4.0 and 17.5.0 lists is
100+
derived from a change's own **Migration** note and is marked **not
101+
exercised**: accurate about what changed, unproven about what it costs to
102+
cross. The two kinds are kept apart on purpose — a step nobody has run,
100103
presented beside steps that were, is how a reader finishes a checklist and
101104
believes they are done.
102105
</Callout>

0 commit comments

Comments
 (0)