Switching the active organization (and, more generally, visiting any object page) pops a user-facing amber warning toast:
已保存,但部分字段未生效
以下字段为只读,未生效: 偏好设置 ID
Nothing the user edited was dropped. The write is the console's internal "recent items" trace.
Actual
The trigger is the ui.recent preference write. Response body of the PATCH behind the toast:
PATCH /api/v1/data/sys_user_preference/4mekbFDEhx0QgC85 → 200
{
"object": "sys_user_preference",
"id": "4mekbFDEhx0QgC85",
"record": { "id": "4mekbFDEhx0QgC85", ..., "key": "ui.recent", "value": [ ... ] },
"droppedFields": [ { "object": "sys_user_preference", "fields": ["id"], "reason": "readonly" } ]
}
The dropped field is id — the record's own primary key, carried in the URL path, and the client's update body does not contain it. ObjectStackDataSource.update() forwards exactly the data argument (packages/data-objectstack/src/index.ts:1573), and the caller passes only { value: items } (packages/data-objectstack/src/userState.ts:169 — dataSource.update(resource, cachedRowId, { value: items })). So the server appears to fold the path id into the candidate write set, judge it read-only, and then report it as a dropped field.
(The request body was not captured on the wire; the above is read off the client source in the current main checkout. If the running build does send id, this is a client bug instead — either way the toast is wrong.)
Expected
droppedFields reports fields the caller supplied and the engine refused. The primary key addressing the row is not a supplied field, and an internal preference write must never surface a warning to the user.
Both invariants are already written down:
This is that same drowning, one field over, and it is the loudest thing a user sees after switching workspaces.
Suggested fix
Server side: exclude the path/primary key from the read-only drop accounting on single-record update (it is addressing, not payload). Optionally also let a write opt out of drop reporting for internal preference traces.
Environment
Local dev server http://localhost:8080, multi-org enabled, zh locale, observed 2026-08-12 (reproduced on every org switch). The server was started by the maintainer and its exact commit is not verified.
Switching the active organization (and, more generally, visiting any object page) pops a user-facing amber warning toast:
Nothing the user edited was dropped. The write is the console's internal "recent items" trace.
Actual
The trigger is the
ui.recentpreference write. Response body of the PATCH behind the toast:The dropped field is
id— the record's own primary key, carried in the URL path, and the client's update body does not contain it.ObjectStackDataSource.update()forwards exactly thedataargument (packages/data-objectstack/src/index.ts:1573), and the caller passes only{ value: items }(packages/data-objectstack/src/userState.ts:169—dataSource.update(resource, cachedRowId, { value: items })). So the server appears to fold the path id into the candidate write set, judge it read-only, and then report it as a dropped field.(The request body was not captured on the wire; the above is read off the client source in the current main checkout. If the running build does send
id, this is a client bug instead — either way the toast is wrong.)Expected
droppedFieldsreports fields the caller supplied and the engine refused. The primary key addressing the row is not a supplied field, and an internal preference write must never surface a warning to the user.Both invariants are already written down:
packages/data-objectstack/src/userState.ts:41— "save()resolves without throwing, so UI mutations never surface a toast."updated_atis no longer sent (rest: PATCH /data 对被静默剥离的写入字段无任何回传 — onFieldsDropped 通道未接线(follow-up #3407/#3413) #3431/审批场景下记录可写性的反馈全线失真:能改的显示「已锁定」,改不了的提示「更新成功」 #3794) — "Sending it made every recents/favorites write pop a scary warning about a field the user never touched, drowning the real signal the toast exists for."This is that same drowning, one field over, and it is the loudest thing a user sees after switching workspaces.
Suggested fix
Server side: exclude the path/primary key from the read-only drop accounting on single-record update (it is addressing, not payload). Optionally also let a write opt out of drop reporting for internal preference traces.
Environment
Local dev server
http://localhost:8080, multi-org enabled, zh locale, observed 2026-08-12 (reproduced on every org switch). The server was started by the maintainer and its exact commit is not verified.