---
title: "v1.7.3"
description: "The bundled Lexical admin patch follows the Payload minor, so a Payload patch release no longer needs a Systhema release, and the upgrade tooling handles exact pins, failed installs and blocked schema plans."
requested_language: cs
language: en
translation_notice: "This page isn't translated yet"
url: https://docs.systhema.app/cs/changelog/v1.7.3
version: changelog
docs_index: https://docs.systhema.app/cs/llms.txt
---
> This page isn't translated yet. Showing English.


## ✨ Highlights

1.7.3 is the release that came out of seven consumer projects upgrading to 1.7.2 and reporting back, over five canaries. The headline change is structural: **a Payload patch release no longer needs a Systhema release.** The bundled Lexical admin patch is keyed to the Payload minor (`@payloadcms/richtext-lexical@^3.90.0`) instead of one exact version, so the family may float on caret ranges again, and the scaffold goes back to carets. The rest is the upgrade and migration tooling getting honest about the states real projects are in: exact pins that must stay exact, a failed install that must be resumable, a schema plan that must show what it would do even while something else blocks it, and a data helper that must match nothing rather than crash on a label the enum no longer has.

### The Lexical patch follows the Payload minor

Payload 3.90.1 shipped a few hours after 1.7.2, and every fresh install broke: the upgrade wrote `^3.90.0`, the patch was keyed to `3.90.0`, and pnpm aborted with `ERR_PNPM_UNUSED_PATCH` after `package.json` was already rewritten. The key is now the range. pnpm applies the diff to whatever version resolves, the doctor and the upgrade pre-flight test-apply the diff to the installed package instead of comparing version numbers, and a daily job in the Systhema repo packs the newest release the key allows and test-applies the patch, so a Payload release that rewrites one of the two patched files is caught before it reaches a project. That is the only case left where a Payload patch release costs a Systhema release (#222, #221).

### Pinned projects stay pinned, and a failed upgrade resumes

A project that pins the Payload family exactly keeps an exact pin: a pin below the new floor moves to the exact floor, never a caret, and the upgrade writes `pnpm.overrides` for the whole family, including the `@payloadcms/*` packages `@systhemaui/payload` itself depends on through caret ranges, which otherwise resolved a patch ahead of the pin and tripped Payload's boot check. A re-run after an aborted install no longer answers "Already on 1.7.3. Nothing to do": if the installed `@systhemaui/core` does not satisfy `package.json`, the install and every step after it run again (#220).

### pnpm patches survive the upgrade

The pre-flight test-applies every patched dependency the upgrade bumps. A patch that applies is re-keyed onto the resolved version; one that does not is renamed to `<name>.stale.patch` and its entry removed, behind a confirm (`--drop-stale-patches` under `--yes`), so a diff that stopped applying because the surrounding code moved can be rebased by hand rather than being lost. The check is whitespace-lenient, matching pnpm's own applier, so a working patch is never reported stale (#220, #223, #225).

### `systhema migrate --schema` shows its work

A blocked plan prints the additive statements it would have applied as SQL comments beneath the blockers, so the column a release needs cannot hide behind unrelated drift. A removed enum label that no row uses is a warning, not a blocker, and the operator-owned recreate DDL rides along commented out in both variants, because its cast fails on exactly the rows that cause a block and a plan is pipeable SQL (#220, #223, #224).

---

## ⬆️ Upgrade

```bash
pnpm add -g @systhemaui/cli@latest
cd <your-project>
systhema upgrade --dry-run
systhema upgrade --yes --allow-database
```

**The CLI needs Node 22.** The bundled `execa` calls `Set.prototype.union` at module load, so the 1.7.0 to 1.7.2 binaries crashed on Node 20 with `TEXT_ENCODINGS.union is not a function`. The requirement is now declared, and an older Node gets one line, `Systhema CLI needs Node 22 or newer`, instead of a stack trace. Project runtimes are unchanged at Node 20.9+.

The upgrade moves the Payload family to 3.90.1. A project on caret ranges resolves it and the Lexical patch applies under the `^3.90.0` key; a project pinned exactly is moved to exactly 3.90.1 with whole-family overrides. You may now drop an exact pin if you only added it to survive 1.7.2.

One codemod runs: `commit-managed-files-ledger` narrows a wholesale `.systhema/` ignore rule to `.systhema/*` and re-includes `.systhema/managed-files.json`, so the ledger that protects your edited managed files is committed. Commit it after the run.

**Then, on PostgreSQL, re-run the capability rename once**, whether or not you ran it on 1.7.1 or 1.7.2:

```bash
systhema migrate migrate-capability-strings
```

The 1.7.1 and 1.7.2 versions of that script could not work on PostgreSQL: it joined on `_parent_id` (the array convention) where a hasMany select table has `parent_id`, then compared the enum column to legacy strings the 1.7 enum recreate had already removed, and Payload's bin swallowed the rejection so the runner printed completion over a failed transaction. It now uses `parent_id`, compares as text, skips a rename whose target label the project's enum does not carry (a General Settings tab that is off drops its capabilities from the enum), and exits non-zero on error. On a push-off production database that is the usual reviewed-SQL route: a `DELETE` of legacy rows whose renamed twin exists and an `UPDATE ... SET value` per rename, mapping in `CAPABILITY_STRING_RENAMES`.

---

## ⚠️ Breaking & Behavioral Changes

### 1. The `systhema` CLI requires Node 22

`@systhemaui/cli` declares `engines.node >=22.0.0`. It never worked on Node 20 since 1.7.0; the change is the declaration and the clear message. Projects themselves still run on Node 20.9+.

### 2. Form notification emails follow the email adapter, not the templates module

The form-builder `emails` array was removed from the schema whenever the `emails` plugin option (the email templates module) was off, so a project running an email adapter with `emails: false` silently lost form notifications. The array now stays whenever Payload has an email adapter configured; the `emails` option controls only the templates module. `beforeEmail` falls back to the adapter's default sender when the module is off. A project in that state gets `forms_emails` back in its schema; an existing retained table already matches, so there is no drift (#223).

### 3. Image optimization skips client uploads

`uploads.imageOptimization` re-encoded a client-uploaded file and renamed an opaque PNG to `.jpg`, but with Payload `clientUploads` the file is already in storage under its original name and the cloud-storage plugin skips re-uploading it, so the document pointed at an object that was never written. The optimizer now leaves any file carrying `clientUploadContext` alone; server-side uploads are optimized as before (#225).

### 4. `.systhema/managed-files.json` is meant to be committed

The Next scaffold's `.gitignore` narrows `.systhema/` to `.systhema/*` plus a negation for the ledger, and the codemod above does the same in existing projects. Git never descends into an excluded directory, so a bare negation under a `.systhema/` rule was a silent no-op (#223).

---

## 🐛 Fixes & Internal Improvements

### Bug Fixes

- **Per-locale publishing migration keeps published pages published** — the live-document step derived each locale's status from the newest version row, so a pending draft version turned every locale of a published page into a draft; it now copies the main row's shared `_status` into each locale row (#219)
- **Doctor honours an exported `DATABASE_URI`** — the `pending-db-renames` and `localize-status-schema` checks read `.env` first, while `systhema migrate` let the process environment win (#225)
- **No `<path>.new` when the template is unchanged** — an edited managed file whose template hash still equals the ledger's record has nothing to fold (#225)
- **The upgrade plan names the right files** — edited managed files go to `<path>.new`, not `<path>.bak`, and the recovery hint prints `systhema payload create-app-files --override`, which runs without the moved-command notice (#223)
- **`repair-fa-icon-picker-import` stops flagging forever** — a project whose only barrel use is an intentional generic `iconPickerField` is no longer applicable (#220)
- **`systhema-core refresh-cache` is silent without `.systhema/`** — the dependency stage of a multi-stage Dockerfile has no project directory yet; the sync hint still prints when `.systhema/` exists without artifacts (#220)
- **`systhema skills refresh`** — re-copies the bundled version of every installed skill into the scope and agent locations where it already is; `--dry-run` lists the targets (#220)

### Internal / Monorepo

- **Daily Lexical patch watch** — `lexical-patch-watch.yml` packs the newest `@payloadcms/richtext-lexical` the patch key allows and runs `git apply --check` against it (#221)
- **1.7.0 and 1.7.2 notes amended** — the import-export plugin's two job task labels in the `payload_jobs` enums, and Payload 3.90's client-upload signing and `{prefix}/{_objectKey}/{filename}` key for hand-written upload handlers (#223, #225)

---

## List of all changes

### 🚀 Features

#### cli

- feat(cli): key the Lexical patch to a range so Payload patch releases need no Systhema release (#222) (1af2747d)

### 🐛 Bug fixes

#### cli, core, payload

- fix(cli,core,payload): third consumer batch for 1.7.3 (#225) (f158ddfe)

#### cli, payload

- fix(cli,payload): second consumer batch for 1.7.3 (#223) (db2b6092)
- fix(cli,payload): keep pinned projects pinned and make a failed upgrade resumable (#220) (2fccf828)

#### payload

- fix(payload): skip capability renames the enum cannot hold and comment out blocked recreate DDL (#224) (ba32ad72)
- fix(payload): keep a published page published when the localize-status migration runs (#219) (e7db4ad6)

### 🧹 Chores

#### ci

- chore(ci): watch the newest Payload release the Lexical patch key allows (#221) (b55119f6)
