diff --git a/PLAN.md b/PLAN.md index 58ef9d1..561b99e 100644 --- a/PLAN.md +++ b/PLAN.md @@ -600,11 +600,36 @@ The lesson worth carrying into M1 is the shape of 1-4: every one is a reach a steady state. The unit suite proved each mechanism works once. Only the churn gate showed that none of them worked twice. -A compatibility gap also surfaced, out of M0's scope and left alone: -`update.apply` (`src/update.zig:18`) rejects any update document whose first -key is not `$`, so `replaceOne`, `findOneAndReplace` and `bulkWrite`'s -`replaceOne` all fail with "bad update". It is a CRUD feature rather than -storage, and it is already inside what the 161 spec failures cover. +A compatibility gap also surfaced, out of M0's scope: `update.apply` rejected +any update document whose first key was not `$`, so `replaceOne`, +`findOneAndReplace` and `bulkWrite`'s `replaceOne` all failed with "bad +update". Fixed straight after the gate rather than deferred to a milestone, +since it was small and the scorecard put a number on it (below). + +### After the gate, before M1: two CRUD corrections + +Not milestone work — both came out of the gate run and were cheap enough that +deferring them would have cost more in explanation than in code. + +**Replacement-style writes.** MongoDB decides operator-vs-replacement on the +update document's first field; a replacement replaces every field except `_id`, +which is immutable. Also refuses two options rather than ignoring them: `multi` +with a replacement, and `sort` on an update spec (a MongoDB 8.0 addition — +ignoring it would silently write a *different* document than the client asked +for). Took the scorecard from 131 pass / 161 fail to 161 / 131, sixteen files +improved, none regressed. + +**`nModified` counted every write.** MongoDB counts a document as modified only +if the update altered it, and writes nothing when it did not. Decided in the +engine, where the document is already serialized and the check lands before the +log append, so a no-op now costs no log record, no fsync and no garbage. That in +turn exposed `_id` not being stored first: MongoDB moves it to the front +whatever order it arrives in, and the Node driver appends a generated `_id`, so +replacing a document with itself was a byte-level change. 163 pass / 129 fail. + +The pattern worth noting for M1: both were found by *running* the suites, not by +reading them, and the second was only visible because the first stopped masking +it. --- diff --git a/tests/e2e/results/m0-gates.txt b/tests/e2e/results/m0-gates.txt index e9880ed..1718d37 100644 --- a/tests/e2e/results/m0-gates.txt +++ b/tests/e2e/results/m0-gates.txt @@ -148,9 +148,12 @@ # argument for keeping both the churn gate and the concurrent benchmark in the # gate list rather than treating them as optional. # -# ONE COMPATIBILITY GAP FOUND, NOT FIXED (out of M0's scope, storage-only) -# `update.apply` (src/update.zig:18) rejects any update document whose first -# key is not `$`, so replacement-style writes -- replaceOne, findOneAndReplace, -# bulkWrite's replaceOne -- fail with "bad update". Found while building the -# churn workload. It is a CRUD feature, not storage, and it is already part of -# what the 161 spec failures cover. +# ONE COMPATIBILITY GAP FOUND HERE, FIXED AFTER THE GATE +# `update.apply` rejected any update document whose first key was not `$`, so +# replacement-style writes -- replaceOne, findOneAndReplace, bulkWrite's +# replaceOne -- failed with "bad update". Found while building the churn +# workload, out of scope for a storage milestone, and fixed immediately after in +# `update: replacement-style writes` and `db: a write that changes nothing is +# not a write`. The scorecard above is the M0 figure and is left as measured; +# those two commits took it to 163 pass / 129 fail, and `tests/spec/scorecard.txt` +# always holds the current one.