Split out of #17188 after @neo-gpt's review of PR #17198 falsified the assumption both halves shared. That ticket now covers only the same-target pair, which was a provably inert deletion. This is the half that cannot be fixed test-side.
The distinction was established at source, not argued: MailboxService.mjs:2705
The same-target pair passes target for both callers, so both await getMailboxGraphProjectionRepairCandidates() — whose coalescing promise is process-wide rather than keyed (:1573). They are joined upstream of the segment load and their relative timing is not free. This pair is different: one caller passes ids, takes the idFilter branch, skips the scan entirely, and diverges before the join.
The Problem
test/playwright/unit/ai/services/memory-core/MailboxService.spec.mjs:1298 — "concurrent global and explicit repairs share one physical segment load (#16767)"
await readEntered;
for (let turn = 0; turn < 3; turn++) {
awaitnewPromise(resolve =>setImmediate(resolve));
}
expect(payloadReads, 'different ids in one segment must join before either read completes').toBe(1);
releasePayloadRead();
The single-flight map entry is dropped when caller one's read resolves (MailboxService.mjs:1216-1220), which happens after releasePayloadRead(). Because the two callers diverge before the join, a legitimately late caller two can reach its segment-load decision after that deletion, legitimately miss the pending promise, open its own read, and fail the exact-count assertion on correct production.
That is a false RED, and under workers: 4 it surfaces as a flaky. Per #15861's amended AC-2 a flaky is a positive detection that disqualifies the sample — so this costs a probe sample exactly as much as a real defect would. It is not a coverage hole; it is a false-positive source aimed at the one signal the probe reads.
The Architectural Reality — why no test-side fix exists
Three candidate anchors, all falsified rather than assumed:
candidate
why it fails
the marker readFile
getGraphMarkerFileStats (messageWalStore.mjs:334-351) uses fs.stat, not readFile — invisible to the stub
readJsonlEntries (the only marker path that does read)
skipped on the cache hit that two concurrent unchanged callers produce (:479-495)
the readdir in listMessageWalSegmentKeys
measured: the counter is already at 2 at turn 0, while caller two's read decision lands around turn 2 — the anchor fires two turns early
There is a structural reason the list is not merely incomplete: when caller two joins, it produces no side effect at all. Joining is silence by construction, and the only observable difference — the second payload read — is the failure signal. No observation can distinguish "joined" from "not yet arrived".
getMessageWalCandidateSegmentLoad (MailboxService.mjs:1187) is module-private, not exported, so a deterministic rendezvous requires a production seam. #17188 placed production behaviour out of scope, which is why this is its own ticket rather than a widening of that one.
Also checked and cleared, so it is not re-investigated: projectionStatsCache (messageWalStore.mjs:23) is module-scope keyed by dir, which looks like cross-file worker state in exactly the class #15861 hunts. It is not — messageWal.dirTest derives from the active test's memoryWal.dir, isolating the key by construction (configBase.mjs:544-549).
The Fix
Decide the seam, then build the rendezvous. The decision is the deliverable; the code is small once it is made.
Two shapes, and picking is the work:
Export a test-visible join signal from production.getMessageWalCandidateSegmentLoad already returns {joined, pending, signature} — the fact the test needs exists and is discarded at the module boundary. Exporting a counter or an event makes the rendezvous exact. Cost: a production surface that exists only for a test, which is the thing #17188 deliberately avoided.
Restructure so arrival is awaited rather than observed. Drive the second caller from a point where its progress is a promise the test already holds, rather than racing two public calls and watching. Cheaper if it works; it is unproven that it can, given the join is silent.
Not an option: widening the turn budget. For this assertion a larger budget makes the false RED less frequent rather than absent, which converts a reproducible finding into a rare one — the #17186 trap, in the direction that hides it.
Acceptance Criteria
The seam decision is recorded with the rejected alternative and why, before any code lands
Caller two's arrival at its segment-load decision is deterministic, not observed through a proxy — and if a new anchor is proposed instead, it is proved to fire at or after the decision, since the readdir candidate failed by firing two turns early
Specificity proved, not just sensitivity: correct production passes the repaired test across repeated consecutive runs. @neo-gpt's distinction is the reason this AC exists — a broken-reuse red proof shows the arm can fire, never that it does not fire when the code is right
Sensitivity retained: with the single-flight forced to never reuse its pending promise, the test still fails
Both proved individually — test.describe.configure({mode: 'serial'}) at line 25 makes a combined run report 1 did not run for the second test, which proves nothing about it
If a production surface is added, it is justified in the ticket rather than taken as a default, and its own test coverage lands with it
Out of Scope
The same-target pair — its wait is removed in #17188 / PR #17198, on the separate ground that both callers are joined upstream.
:1381 — repaired in #17186.
Widening the budget. Named above as the trap rather than an alternative.
retries: 2. Whether the suite should retry at all is #15861's question.
Avoided Traps
Assuming the anchor list is incomplete rather than the approach wrong. Three candidates failed for three different reasons, and the fourth would fail for the same structural one: a join emits nothing.
Reading a red proof as sufficient. Sensitivity and specificity are different properties; this ticket's whole subject is a test that fires when it should not, which a sensitivity proof cannot see.
Treating a false RED as harmless because it is loud. Under workers: 4 it is a flaky, and a flaky disqualifies a #15861 sample — so it costs exactly what a real defect costs.
Deleting the wait along with the assertion. Tempting once the assertion looks redundant, and wrong here: the wait is the only thing narrowing the false-RED window, even though it cannot close it.
Evidence class
L2 — the divergence is read at MailboxService.mjs:2705; the anchor falsifications are reproduced in-process, with the readdir timing measured by an instrumented loop.
Related
#17188 (the same-target half, split from this) · PR #17198 · #17186 (the fixed-turn-budget repair that started the arc) · #15861 (the workers: 4 re-land this blocks) · #17192 (the fifth defect — a different mechanism) · PR #17183
Blocks #15861.
Handoff Retrieval Hints
query_raw_memories("MailboxService divergent global explicit segment load rendezvous false red joining is silent")
Falsification anchor: MailboxService.mjs:2705 — idFilter ? null : await getMailboxGraphProjectionRepairCandidates(). The ids path skipping the scan is the entire reason this pair is not coupled like its sibling.
The three dead anchors are enumerated above; do not re-propose them without explaining why the join stops being silent.
Live latest-open sweep: latest 20 open issues at 2026-08-15T19:15Z plus a targeted segment load rendezvous divergent single-flight MailboxService search over 100 open+closed — no equivalent. A2A in-flight claim sweep: 10 most recent across all read-states — no competing claim. Structure-map gate: N/A, no .mjs file introduced or relocated.
tobiu referenced in commit 8e3216a - "fix(memory-core): rendezvous on the join decision instead of guessing at it (#17204) (#17216) on Aug 16, 2026, 1:23 AM
Context
Split out of
#17188after @neo-gpt's review of PR #17198 falsified the assumption both halves shared. That ticket now covers only the same-target pair, which was a provably inert deletion. This is the half that cannot be fixed test-side.The distinction was established at source, not argued:
MailboxService.mjs:2705const candidateState = idFilter ? null : await getMailboxGraphProjectionRepairCandidates(),The same-target pair passes
targetfor both callers, so both awaitgetMailboxGraphProjectionRepairCandidates()— whose coalescing promise is process-wide rather than keyed (:1573). They are joined upstream of the segment load and their relative timing is not free. This pair is different: one caller passesids, takes theidFilterbranch, skips the scan entirely, and diverges before the join.The Problem
test/playwright/unit/ai/services/memory-core/MailboxService.spec.mjs:1298— "concurrent global and explicit repairs share one physical segment load (#16767)"await readEntered; for (let turn = 0; turn < 3; turn++) { await new Promise(resolve => setImmediate(resolve)); } expect(payloadReads, 'different ids in one segment must join before either read completes').toBe(1); releasePayloadRead();The single-flight map entry is dropped when caller one's read resolves (
MailboxService.mjs:1216-1220), which happens afterreleasePayloadRead(). Because the two callers diverge before the join, a legitimately late caller two can reach its segment-load decision after that deletion, legitimately miss the pending promise, open its own read, and fail the exact-count assertion on correct production.That is a false RED, and under
workers: 4it surfaces as aflaky. Per#15861's amended AC-2 a flaky is a positive detection that disqualifies the sample — so this costs a probe sample exactly as much as a real defect would. It is not a coverage hole; it is a false-positive source aimed at the one signal the probe reads.The Architectural Reality — why no test-side fix exists
Three candidate anchors, all falsified rather than assumed:
readFilegetGraphMarkerFileStats(messageWalStore.mjs:334-351) usesfs.stat, notreadFile— invisible to the stubreadJsonlEntries(the only marker path that does read):479-495)readdirinlistMessageWalSegmentKeysThere is a structural reason the list is not merely incomplete: when caller two joins, it produces no side effect at all. Joining is silence by construction, and the only observable difference — the second payload read — is the failure signal. No observation can distinguish "joined" from "not yet arrived".
getMessageWalCandidateSegmentLoad(MailboxService.mjs:1187) is module-private, not exported, so a deterministic rendezvous requires a production seam.#17188placed production behaviour out of scope, which is why this is its own ticket rather than a widening of that one.Also checked and cleared, so it is not re-investigated:
projectionStatsCache(messageWalStore.mjs:23) is module-scope keyed bydir, which looks like cross-file worker state in exactly the class#15861hunts. It is not —messageWal.dirTestderives from the active test'smemoryWal.dir, isolating the key by construction (configBase.mjs:544-549).The Fix
Decide the seam, then build the rendezvous. The decision is the deliverable; the code is small once it is made.
Two shapes, and picking is the work:
getMessageWalCandidateSegmentLoadalready returns{joined, pending, signature}— the fact the test needs exists and is discarded at the module boundary. Exporting a counter or an event makes the rendezvous exact. Cost: a production surface that exists only for a test, which is the thing#17188deliberately avoided.Not an option: widening the turn budget. For this assertion a larger budget makes the false RED less frequent rather than absent, which converts a reproducible finding into a rare one — the
#17186trap, in the direction that hides it.Acceptance Criteria
readdircandidate failed by firing two turns earlytest.describe.configure({mode: 'serial'})at line 25 makes a combined run report1 did not runfor the second test, which proves nothing about itOut of Scope
#17188/ PR #17198, on the separate ground that both callers are joined upstream.:1381— repaired in#17186.retries: 2. Whether the suite should retry at all is#15861's question.Avoided Traps
workers: 4it is aflaky, and a flaky disqualifies a#15861sample — so it costs exactly what a real defect costs.Evidence class
L2 — the divergence is read at
MailboxService.mjs:2705; the anchor falsifications are reproduced in-process, with thereaddirtiming measured by an instrumented loop.Related
#17188(the same-target half, split from this) · PR #17198 ·#17186(the fixed-turn-budget repair that started the arc) ·#15861(theworkers: 4re-land this blocks) ·#17192(the fifth defect — a different mechanism) · PR #17183Blocks
#15861.Handoff Retrieval Hints
query_raw_memories("MailboxService divergent global explicit segment load rendezvous false red joining is silent")MailboxService.mjs:2705—idFilter ? null : await getMailboxGraphProjectionRepairCandidates(). Theidspath skipping the scan is the entire reason this pair is not coupled like its sibling.Origin Session ID: 00348bc3-c011-4035-90a3-f0eb62b8c95c
Live latest-open sweep: latest 20 open issues at 2026-08-15T19:15Z plus a targeted
segment load rendezvous divergent single-flight MailboxServicesearch over 100 open+closed — no equivalent. A2A in-flight claim sweep: 10 most recent across all read-states — no competing claim. Structure-map gate: N/A, no.mjsfile introduced or relocated.