@@ -967,6 +967,92 @@ const FAILURE_PROPAGATION_SITES = new Map([
967967// and after. Only the seam count moves, and ⛔ no baseline entry was added: an
968968// entry there says a human read the seam, not that a rule guessed wrong.
969969
970+ // ── THE WRAPPER RECURSION'S CALLBACK REFUSAL — MEASURED, NOT CHANGED (#12138) ─
971+ //
972+ // `isReadCall`'s wrapper recursion walks a same-file wrapper's body with
973+ // `walkSameTickInclusive`, so a driver read sitting inside a nested function
974+ // body is not seen. The top of this file states the reason the `try` side
975+ // refuses the same descent ("a callback registered inside a try runs later and
976+ // is not guarded by that catch"). That reason is about the TRY. #12138 asked
977+ // whether it is also the right answer for a WRAPPER body, where it is not
978+ // obviously right: a wrapper whose read sits in a SYNCHRONOUSLY invoked
979+ // callback does perform that read on its caller's behalf, inside the caller's
980+ // try. The narrowness was recorded here for the try side only and nowhere for
981+ // the wrapper side; this block is that missing record.
982+ //
983+ // RE-MEASURED on one named tree — `origin/main` @ 3ddad51b5c, and reproduced
984+ // byte-identically (both counts AND all 8 delta seams) after merging
985+ // `origin/main` @ c312a562e3 — because the filing's own table (64 → 72) was
986+ // attributed to a tree that predates #12137 and reported 66 there:
987+ //
988+ // | recognizer | read seams |
989+ // |--------------------------------------------------|-----------:|
990+ // | today — `walkSameTickInclusive`, depth 2 | 64 |
991+ // | probe — `walkAll`, depth 2 | 72 |
992+ //
993+ // The delta is still 8. What the per-seam reading found is that the wrapper
994+ // recursion's callback refusal explains only THREE of those 8.
995+ //
996+ // THE DISCRIMINATING RUN. Raising `MAX_READ_WRAPPER_DEPTH` from 2 to 6 while
997+ // leaving `walkSameTickInclusive` in place admits 5 of the same 8 (70 seams: +8
998+ // / -2, where the 2 are the SAME try lines re-attributed to a different
999+ // first-matching callee, engine.ts:9407 and :10572). Saturation checked at
1000+ // depth 50: 70 and 75, i.e. unchanged. So for those 5 the miss is the DEPTH
1001+ // BOUND, not the callback boundary — `walkAll` merely masks the bound by
1002+ // descending lexically through nested DECLARATIONS instead of counting call
1003+ // hops, which reaches the read at depth 1 no matter how many awaits are between.
1004+ //
1005+ // THE 8 DELTA SEAMS, each read at its call site:
1006+ //
1007+ // | # | seam (try line → wrapper) | why today misses it | invoked now? |
1008+ // |--:|----------------------------------------------------------------|---------------------|--------------|
1009+ // | 1 | metadata-protocol protocol.ts:10243 getMetaItemCached→getMetaItem | depth bound | yes — real |
1010+ // | 2 | metadata-protocol protocol.ts:13559 saveMetaItem→getMetaItem | depth bound | yes — real |
1011+ // | 3 | metadata-protocol protocol.ts:14535 migrateStoredMetadata→saveMetaItem | depth bound | yes — real |
1012+ // | 4 | metadata-protocol protocol.ts:17213 duplicatePackage→saveMetaItem | depth bound | yes — real |
1013+ // | 5 | metadata-protocol sys-metadata-repository.ts:883 promoteDraft→dropPromotedDraftRow | CALLBACK | yes — real |
1014+ // | 6 | metadata-protocol sys-metadata-repository.ts:1353 close→terminate | CALLBACK | NO — FAKE |
1015+ // | 7 | objectql engine.ts:9237 insert→applyAutonumbers | CALLBACK | yes — real |
1016+ // | 8 | objectql lifecycle-service.ts:625 sweep→reapObject | depth bound | yes — real |
1017+ //
1018+ // All 8 were decidable from the call site; none needed provenance. Seams 1-5,
1019+ // 7 and 8 are genuine members the census does not count: every hop is an
1020+ // `await` on the caller's own tick (`getMetaItem` → `findOverlay`/`findDraft` →
1021+ // `lookup` → `engine.findOne`; `delete` → `withTxn(cb)`, which is
1022+ // `engine.transaction(cb)` or `cb(undefined)` and is awaited either way;
1023+ // `seedAutonumber` → `keysetWalk(cb)` driven by the `for await` on the next
1024+ // line; `archiveObject` → `archivePass`, an awaited local const).
1025+ //
1026+ // ⚠️ SEAM 6 IS A FAKE SEAM, AND IT IS THE REASON `walkAll` IS NOT THE FIX.
1027+ // `close()`'s try calls `w.terminate()`. `terminate` resolves BY NAME to the
1028+ // local const arrow at sys-metadata-repository.ts:1246 — a synchronous, void,
1029+ // in-memory routine whose only call is `self.watchers.delete(subscription)` on
1030+ // `private readonly watchers = new Set<...>()`. `calleeName` reads that as
1031+ // `delete`, and the wrapper recursion resolves `delete` to THIS FILE'S
1032+ // `async delete(ref, opts)` method, whose `findOne` lives inside a `withTxn`
1033+ // callback. Ablation: refusing the `delete` wrapper hop drops the probe from 72
1034+ // to exactly 70, removing seams 5 and 6 and nothing else.
1035+ //
1036+ // That is #11921's defect — a callee NAME matched with no shape check — one
1037+ // level up, on the WRAPPER name instead of the vocabulary name.
1038+ // `contradictsDriverReadShape` guards only the `DRIVER_READ_CALLEES` hit above;
1039+ // the wrapper hop has no equivalent. Today it is harmless because the callback
1040+ // refusal stops the walk before the fake read is reached. Widening the walk is
1041+ // what arms it, and a fake seam is the UNSAFE direction: an invented member of
1042+ // the denominator #5186 / #6451 / #9165 / #8845 / #8901 are all quoted against.
1043+ //
1044+ // ⛔ NOTHING WAS CHANGED, and the reason is a measurement rather than caution.
1045+ // The sanctioned cheap fix for this card was an `Array.prototype.map` /
1046+ // `Promise.all` allowlist. NOT ONE of the 8 goes through `map` or
1047+ // `Promise.all`: the real shapes are `withTxn(cb)`, `keysetWalk(cb)` (imported
1048+ // from `@objectstack/types`, so its body is not even in this file's index) and
1049+ // locally-bound const arrows. That allowlist would admit zero of them while
1050+ // still not excluding seam 6. Telling the four real callback seams from the
1051+ // fake one needs to know what the receiving method does with its argument —
1052+ // which is #11921's provenance problem, deliberately out of this card's scope.
1053+ // The census is therefore UNMOVED at 64, and #8901's restart conjunct (b) is
1054+ // not triggered by this reading.
1055+
9701056/**
9711057 * Where the read-seam rule looks. Narrowed on purpose — see above.
9721058 *
0 commit comments