Found while implementing #8141 (the addressing-id half of this message's falsity) and deliberately left out of it: #8141's acceptance bar pins the line as unchanged in wording for the cases that still print, so both defects below are separate decisions about the same string and would collide with that pin. Filed here so the wording is decided once, on evidence, rather than drifting.
readonlyStripWarning — packages/objectql/src/validation/rule-validator.ts.
1. "COMMITTED WITHOUT IT" is false under strictReadonlyWrites
The strip logs from inside stripReadonlyFields; assertNoStrictDrops() throws afterwards, before any driver call. So a strict caller is told in prose that the update was committed without the field, while the update was refused outright and nothing was written.
Measured on a real ObjectQL + a recording driver, by-id update of an object with a readonlylocked_note, { strictReadonlyWrites: true }:
refusedCode : ERR_READONLY_FIELD_REJECTED
driverWrites : 0
warnLines : 1
claimsCommitted: true ← the line says "COMMITTED WITHOUT IT"
This is the #4632 shape inverted: the log promises a silent partial success where the engine actually delivered a loud refusal. A reader debugging from the log alone looks for a row that was never touched.
Same class on the insert side, unverified here: runtimeOwnedStripWarning says "the write is being COMMITTED WITHOUT IT" and insert discharges strictReadonlyWrites too (#5126 / #5503).
2. The message names isSystem as the remedy but never preserveAudit
stripReadonlyFields honours context.preserveAudit (#3493) — a whitelist, narrower than isSystem by construction, and the documented route for a historical import reinstating the original timeline. The message names only { context: { isSystem: true } }, the blanket exemption from the whole strip.
Its own runtime-owned twin names both, and there is a test pinning that it does (rule-validator.test.ts, "logs the runtime-owned message…": asserts the line contains isSystemandpreserveAudit). So the two sibling messages disagree about the remedy set for the same pair of exemptions.
Consequence: an import that forgot the flag reads this line and is steered to the strictly-worse posture — exactly the failure #8141 fixed for the addressing id, one remedy over. Whoever fixes it should decide whether the audit-family case deserves a targeted remedy sentence rather than a blanket one.
Scope note
Both are one edit to one string plus its pin tests, which is why this is one card and not two. ⛔ It must not silently re-open #8141: the address key no longer reaches this message at all, and the case that still prints must keep naming the field, the consequence and a remedy that is true for it — the line stays at warn so real forgery attempts stay visible (its docblock argues the level).
Filed unassigned by the #8141 dev lane (seat #6019, domain:engine-core).
Found while implementing #8141 (the addressing-
idhalf of this message's falsity) and deliberately left out of it: #8141's acceptance bar pins the line as unchanged in wording for the cases that still print, so both defects below are separate decisions about the same string and would collide with that pin. Filed here so the wording is decided once, on evidence, rather than drifting.readonlyStripWarning—packages/objectql/src/validation/rule-validator.ts.1. "COMMITTED WITHOUT IT" is false under
strictReadonlyWritesThe strip logs from inside
stripReadonlyFields;assertNoStrictDrops()throws afterwards, before any driver call. So a strict caller is told in prose that the update was committed without the field, while the update was refused outright and nothing was written.Measured on a real
ObjectQL+ a recording driver, by-id update of an object with areadonlylocked_note,{ strictReadonlyWrites: true }:This is the #4632 shape inverted: the log promises a silent partial success where the engine actually delivered a loud refusal. A reader debugging from the log alone looks for a row that was never touched.
Same class on the insert side, unverified here:
runtimeOwnedStripWarningsays "the write is being COMMITTED WITHOUT IT" andinsertdischargesstrictReadonlyWritestoo (#5126 / #5503).2. The message names
isSystemas the remedy but neverpreserveAuditstripReadonlyFieldshonourscontext.preserveAudit(#3493) — a whitelist, narrower thanisSystemby construction, and the documented route for a historical import reinstating the original timeline. The message names only{ context: { isSystem: true } }, the blanket exemption from the whole strip.Its own runtime-owned twin names both, and there is a test pinning that it does (
rule-validator.test.ts, "logs the runtime-owned message…": asserts the line containsisSystemandpreserveAudit). So the two sibling messages disagree about the remedy set for the same pair of exemptions.Consequence: an import that forgot the flag reads this line and is steered to the strictly-worse posture — exactly the failure #8141 fixed for the addressing
id, one remedy over. Whoever fixes it should decide whether the audit-family case deserves a targeted remedy sentence rather than a blanket one.Scope note
Both are one edit to one string plus its pin tests, which is why this is one card and not two. ⛔ It must not silently re-open #8141: the address key no longer reaches this message at all, and the case that still prints must keep naming the field, the consequence and a remedy that is true for it — the line stays at
warnso real forgery attempts stay visible (its docblock argues the level).Filed unassigned by the #8141 dev lane (seat #6019,
domain:engine-core).