Deflake the unit-test cluster: seed HNSW routing, signal-based waits, quarantine two unreproduced hangs - #2276
Conversation
There was a problem hiding this comment.
Code Review
This pull request addresses test flakiness and environment-specific hangs by introducing condition-based polling (using a waitFor helper), adding abort timeouts to fetch calls, and quarantining problematic tests on Windows and LMDB. It also introduces a random function seam in the HNSW index to allow seeding the PRNG for deterministic graph generation in tests, and clamps the entry-point level to MAX_LEVEL. The reviewer feedback recommends replacing the remaining fixed delays in subscription replay tests with a sentinel record pattern to ensure all prior events are fully processed before assertions, which aligns with best practices for testing ordered streams.
|
Reviewed; no blockers found. |
|
All four review findings are addressed in Swallowed Both tests now write a record after the in-flight writes settle and wait for that, with a terminal timeout. The ordering is code-traced, not assumed: the
One pinned seed samples the property once — confirmed by direct measurement: sweeping 40 arbitrary seeds at this head, 4 produce a graph that legitimately diverges. The suggested remedy would itself flake, though: with ~10% of graphs diverging on at least one of the 4 targets, "at most 1 of 20 diverges" fails about 20% of the time — a worse flake than the one being removed, and "at most 3" still fails ~1%. Instead the test now sweeps 8 fixed seeds, each asserted for exact equality, all verified non-divergent at this head — deterministic, 8× the sampling, +3s of suite time. The cost is that an intentional index change can force a seed re-pin; Teardown restores only the rocksdb expiration — correct, fixed exactly as suggested; both process-wide globals are restored. A pre-push cross-model round on the result (codex + gemini + harper-domain) found one further defect worth naming: the per-seed — Claude Opus 5 |
|
Round-8 push ( Subscription replay: startTime collection branch silently drops events committed after the audit cursor terminates (#2311) — P1 Bug, parented to [Epic] Audit-log subsystem hardening (#1651).
One correction, on the engine hypothesis. The grep-isolated leg was not running on the default engine. Probing the store path on exactly that command shows The real difference is which side of the window the writes land on. Instrumented here, the replay cursor sees an empty audit range and there are zero listener drops, so the uncovered window is never entered at all. On a box where the in-flight writes straddle the end of replay it is deterministic. Both of our measurements are right; #2311 is what sits between them. Thanks for pushing on this one — the 6/6-vs-0/10 disagreement is what made the window visible. The test stays unquarantined, for the round-7 reasons, but the comment at the wait now points at #2311 so a — Claude Opus 5 |
47f9b89 to
56e5445
Compare
|
Reviewed The branch was rebased ( 1. The 2. 3. The body is wrapped in 4. The additive settle went 100ms → 200ms, matching the quiet window the sibling tests use, so a duplicate trailing the last expected delivery has a wider gap in which to surface. I did check the one thing that looked like a risk from the diff shape — that a const deadline = Date.now() + timeout;
while (Date.now() < deadline) {
if (events.length >= minEvents && Date.now() - lastEventAt >= quietMs) break;
await delay(Math.min(quietMs, 20));
}
CI is fully green (43 success, 4 skipped, 0 failures) and all six findings from the earlier rounds are resolved. — |
…subscription waits, quarantine 2 unreproduced flakes Fixes three flaky unit tests with demonstrated root causes and quarantines two that could not be root-caused this round (each linked to a filed issue): - HNSW greedy-routing test: graph levels came from unseeded Math.random, and greedy-vs-full-ef equality is only statistically true across random graphs. Adds a 'random' test seam to HierarchicalNavigableSmallWorld (also clamps the entry-point level to MAX_LEVEL, matching the other assignment site) and seeds the test's graph. 0/120 contended runs post-fix (was ~2.5-5%). - Txn expiration test: fixed 50ms window raced a 40ms sleep plus real DB work plus two 20ms expiry ticks. Now waits on the actual signals and proves expiry landed before the slow get() settled. 0/160 pinned runs (was 2/80). - Subscription replay (updates to passed keys): still used collect()'s quiet-period timer, the race its sibling tests were already migrated off; now uses the same waitFor-final-values pattern. - risk-query integration suite: skipped on win32 (#2273 — deploy_component hangs after npm pack on Windows CI) and readiness-poll fetches now carry AbortSignal.timeout so one hung fetch cannot burn undici's 300s default. - MQTT non-clean-session test: skipped (#2274 — silent 20s hang on CI, 0/30 contended local repro attempts). Refs #1655 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0142195pzooHeNejheNfsPDZ
…t-period waits, narrow MQTT skip to lmdb, test the entry-point clamp
- txn-tracking: await the slow get() (asserting the abort surfaces on
rocksdb) so its 500ms tail cannot bleed into the next describe's
expiration settings and re-pathed test DB.
- subscriptionReplay: convert the two remaining quiet-period/fixed-delay
waits ('rapid updates' and 'subscribe while writes are in flight') to
the same waitFor pattern; trim history-narrating comments.
- mqtt-test: quarantine the non-clean-session test on lmdb only (where
the hang was observed) so rocksdb keeps the durable-session coverage.
- vectorIndex: regression test pinning the empty-index entry-point level
clamp (random() === 0 previously meant an infinite loop).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0142195pzooHeNejheNfsPDZ
…ect() quiet windows - vectorIndex: drive the clamp test with Number.MIN_VALUE (finite ~268 level) instead of 0 — a clamp regression now fails in milliseconds rather than wedging the runner in a synchronous infinite loop. - subscriptionReplay: convert the last three collect() quiet-window waits; the two duplicate-detection tests could previously pass vacuously when the window expired before in-flight deliveries. The non-collection test waits for the final version only, since rapid same-record versions legitimately coalesce. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0142195pzooHeNejheNfsPDZ
… tests A duplicate can trail the last expected delivery; the 100ms settle after the positive wait can only surface more events, never lose them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0142195pzooHeNejheNfsPDZ
…lmdb txn expiration The two in-flight duplicate-detection tests could pass vacuously: their `waitFor` swallowed its timeout and the only assertion left was "no duplicate (id,version)", which is trivially true over a partial set. Run alone, the count test timed out on every run (5.3s, green). Waiting for all 30 in-flight ids is not the fix — one that commits before the cursor's snapshot and falls outside `previousCount` is legitimately never delivered (17000-17002, measured). Both now write a record after the in-flight writes settle and wait for it, with the timeout terminal: deliveries follow commit order, so the sentinel's arrival bounds them. The burst test still used `collect()`'s quiet window while asserting all 600 ids arrived, and still flaked (1 failure in 32 lmdb runs). Converted, along with the three other tests that write after subscribe and then assert completeness, so the quiet window is left only where a quiet window is the right tool. The routing test pinned one graph, sampling a statistical property once: over 40 arbitrary seeds, 4 produce a graph that legitimately routes to a different entry point. It now sweeps eight fixed seeds, each asserted exactly — deterministic, unlike a divergence-rate bound, which at this rate would itself flake. Txn expiration teardown restored only the rocksdb global, so on the lmdb pass a 20ms open-transaction limit leaked into every later test in the process. Refs #1655 Co-Authored-By: Claude Opus <noreply@anthropic.com>
… comments dropTable() is async and drains in-flight writes before dropping column families; unawaited in the seed loop it would race the next graph's 600 puts and turn a LOCK_TIMEOUT rejection into an unhandled rejection. The sentinel comments now name why the cursor cannot deliver the sentinel (its history/entry is captured before subscribe() resolves) rather than only asserting commit order, which was the review's open question. Co-Authored-By: Claude Opus <noreply@anthropic.com>
…names its id The FIRST-subscription-on-fresh-DB completeness wait took waitFor's bare 2000ms default with no catch, so a genuinely lost delivery died inside waitFor with "Timed out after 2000ms waiting for condition" and never reached the per-id assert that names it. Matches the timeout+catch shape every other converted wait in this file already uses. Co-Authored-By: Claude Opus <noreply@anthropic.com>
The FIRST-subscription-on-fresh-DB wait fails as `missing in-flight id N` when the startTime replay branch drops a live event committed after its audit cursor terminated. Filed as #2311 (P1, epic #1651) with the code trace and a forced repro; point the test comment at it so a future failure here is read as the product bug rather than a timing threshold. Refs #2311 Co-Authored-By: Claude Opus <noreply@anthropic.com>
56e5445 to
d894e40
Compare
Deflakes the cluster of unit-test failures that took the Unit Test workflow red on 7 of its last 30 main runs (four distinct tests across 2026-08-21 alone), plus the Windows-only risk-query integration failure. Three tests are fixed with demonstrated root causes; two could not be root-caused within this round and are quarantined, each behind a filed, prioritized issue under epic [Epic] CI test flakiness (#1655). No product behavior changes beyond a test seam (details below).
What changed
Fixed (root cause demonstrated):
unitTests/resources/vectorIndex.test.js,resources/indexes/HierarchicalNavigableSmallWorld.ts) — graph levels were drawn from unseededMath.random(), and greedy-vs-full-ef result equality is only statistically true across random graphs: ~2-3% of random 600-node graphs legitimately route to a different layer-0 entry point and displace the top-10 tail. Added arandomproperty toHierarchicalNavigableSmallWorld(test seam, defaults toMath.random) and the test now pins the graph with a seeded PRNG. One pinned graph samples that statistical property exactly once, so the test sweeps eight fixed seeds, each asserted for exact equality — measured over 40 arbitrary seeds, 4 produce a graph that legitimately diverges, and all eight inSEEDSare non-divergent at this head. Product-side this also clamps the entry-point-creation level toMAX_LEVEL, matching the other assignment site — previously-Math.log(random())at that one site was unclamped, and arandom()returning exactly 0 (possible for bothMath.randomand any test PRNG) would producelevel = Infinityand an infinite loop in the node-initializationforloop; a high finite draw persists an entry point dozens of empty layers above the graph for the life of the index. And it is not just a lottery ticket: with a schema-configuredmL(e.g.mL: 5, which the constructor accepts), 13.5% of first-node draws exceed MAX_LEVEL — every such index got a permanently over-tall entry point while later nodes were clamped. The clamp now has its own regression test (HNSW entry-point level clamp), driven with a finite pathological draw so a clamp regression fails fast instead of wedging the runner. The statistical nature of greedy-equals-full, and the seed-sweep contract, are recorded inDESIGN.md.unitTests/resources/txn-tracking.test.js) — the test raced a fixed 50ms window (Promise.race([delay(50), result])) against a 40ms sleep + two real DB operations + an expiry that structurally needs two ~20ms monitor ticks. Ten milliseconds of slack loses on a contended runner. Now waits on the actual signals (waitFor), and proves the transaction lefttrackedTxnswhile the slowget()was still pending — so removal-by-expiry can't be confused with removal-by-completion. The suite's teardown also restores both engines' expiration globals: it set 20ms through whichever engine is active but restored only the rocksdb one, so on the lmdb pass a 20ms open-transaction limit leaked into every later test in theunitTests/resourcesprocess.unitTests/resources/subscriptionReplay.test.js) —!omitCurrent: updates to passed keys arrive via queuestill usedcollect()'s quiet-period timer, the exact race its two sibling tests were already migrated off (their in-file comments document it). Under contention the subscription can go quiet longer than the window while queued updates are in flight, so the final-value assertion reads stale values. Nine tests in this file are now converted to condition waits: the five caught in the first review round, the 600-id notify-batch burst test (still on a 300ms quiet window and still flaking — 1 failure in 32 lmdb runs,missing 7 of 600), and the three remaining tests that write after subscribe and then assert completeness.collect()'s quiet window remains only where a quiet window is the semantically right tool — asserting that no events arrive, and history-replay tests whose writes all precedesubscribe().unitTests/resources/subscriptionReplay.test.js) — the two in-flight duplicate-detection tests swallowed theirwaitFortimeout, leavingno duplicate (id,version)as the only assertion, which is trivially true over a partial event set. Run alone, the count test timed out on every run and went green in 5.3s. Waiting for all 30 in-flight ids is not the fix: an in-flight write that commits before the cursor's snapshot and falls outsidepreviousCountis legitimately never delivered (measured: 17000-17002 never arrive in an isolated run). Both tests now write a record after the in-flight writes settle and wait for it with a terminal timeout. The ordering that makes this sound is code-traced, not assumed: thepreviousCountcursor collects its history from a reverse auditgetRangeunder the default snapshot, bounded bycount = 10well underREPLAY_YIELD_INTERVAL = 100, so it completes in the subscribe IIFE's first synchronous segment — beforesubscribe()resolves and long before the sentinel commits; the non-collection shape capturesentryin that same segment and never re-reads it. Neither cursor can deliver the sentinel, so it can only arrive throughpendingRealTimeQueue, which drains in commit order after every in-flight delivery.Quarantined (issue filed, skip links to it):
integrationTests/components/risk-query.test.ts) — #2273:deploy_component(restart:true) hung server-side afternpm packon Windows CI — the instance log goes silent and the client fetch dies on undici's 300s headers timeout, cancelling all 9 children at 319s. This is a hang, not runner slowness (npm pack itself finished in <1s; then 5+ minutes of zero log output), so a timeout bump would not help — the suite is skipped onwin32until the deploy hang is fixed. The readiness poll also now carriesAbortSignal.timeout(5s)per probe so one hung fetch can't consume the whole budget. Suite verified green on Linux.unitTests/apiTests/mqtt-test.mjs) — #2274: silent 20s mocha timeout on CI (lmdb pass, Node 26), zero server-side log output, and the hang is provably in one of the steps with no individual timeout (the test's own bounded 15s wait never fired). Not reproduced in 30 contended local full-file runs. Skipped on the lmdb pass only — where the hang was observed — so the rocksdb pass keeps this durable-session coverage. Hypotheses and a reinstatement path are in the issue. Most of this file's diff is indentation from wrapping the test in the conditional skip; the body is unchanged.Found but not touched (out of scope): the repro loops surfaced a sixth flaky test,
MQTT subscribe to retained record with patch operations— ~10% failure rate under 2-core contention, duplicate retained/live delivery asserted as an uncaught exception. Filed as #2275 with mechanism and repro instructions.For the human reviewer
The red check is not this branch.
Integration Tests 2/6 (Windows, Node.js v24)fails atintegrationTests/apiTests/describe-metadata-upgrade.test.ts:62withProbe /SeoPageCache/ did not become ready within 120000ms (ECONNREFUSED) after restart_service, and phase 2 then cascades. This branch touches no integration file in that shard, no test util and no restart path.mainrun 32812674585 (05:23 UTC, 2026-08-25) fails identically;mainrun 32820775289 (07:16) passes. #2309 is the fix and names the mechanism: libuv'sfs-eventcallback asserts that theGetLongPathNameWexpansion of an event path still starts with the directory stored when the watch was armed, and the Windows runner'sos.tmpdir()(C:\Users\RUNNER~1\AppData\Local\Temp) never satisfies it, so libuv aborts the process with no JS-observable seam. The instance logs from both failed attempts here match that exactly and rule out the "120s probe budget is too tight after a slow npm install" reading recorded on #2273: the restarted http worker resolves its middleware chains (attempt 1 at 06:49:17.3, attempt 2 at 07:19:42.6) and then logs nothing at all for the full 120s while every connection is refused — a dead process, not a slow one — and phase 2 boots a fresh process on the same runner, against the same component directory and its 541-packagenode_modules, fully up with both tables initialized 2.5s later. Attempt 1 also died after a 3-minutenpm install, not a 10-minute one. No test change was made here for it, deliberately: the fix belongs in Canonicalize watch paths so a Windows 8.3 short path cannot abort the process #2309, and quarantining the suite would cost Windows coverage of the describe_all shows schema_defined: false and omits expiration for eviction-configured tables on upgraded clusters #1245 metadata-upgrade regression for a defect that is already understood.The one product-source file touched is
HierarchicalNavigableSmallWorld.ts, and the judgment call is therandominstance property as a test seam plus theMAX_LEVELclamp on the entry-point site. The seam is inert in production (this.randomdefaults toMath.random; both call sites previously calledMath.random()directly). The clamp changes behavior only forrandom() === 0or graphs demanding level > 10, i.e. probability ~2^-32 per insert — but the unclamped site could infinite-loop, so it is a genuine (if theoretical) hardening, called out here rather than buried.Two review suggestions were implemented differently than proposed, both because the proposed form would have failed or flaked — worth a look because the alternatives are still live:
assert.failon timeout). That completeness condition is unreachable by design —previousCount: 10means an in-flight write committed before the cursor snapshot is legitimately never delivered — so it would have failed on every isolated run. The sentinel wait is terminal instead, on a condition that must hold.DESIGN.mdsays so.The txn test's new "expired-before-settled" outcome check is deliberately stricter than the old assertion: it fails with a distinct message if the slow
get()completes before expiry is observed, which would indicate the timing assumption broke in a new way rather than passing vacuously.The subscription-replay conversions keep
.catch(() => {})on waits whose own completeness assert follows immediately (the per-key/per-id asserts report exactly which key went stale). The two sentinel waits do not swallow: there the wait is the only thing standing between a slow runner and a vacuous pass.Windows quarantine means Windows loses risk-query coverage entirely until Windows CI: deploy_component (restart:true) hangs after npm pack — risk-query integration suite cancelled at 319s #2273 is fixed; that felt better than a suite that red-flags the whole Integration workflow on a 300s hang, but it is a coverage regression on that platform. Same shape for the lmdb MQTT durable-session skip: engine-specific offline-queue persistence is exactly the code path most likely to differ per engine, and it is unguarded on lmdb until Flaky unit test: MQTT 'subscribe with QoS=1 and reconnect with non-clean session' silent 20s timeout (lmdb pass) #2274 is closed.
Round-7 review threads (Barber AI), both declined — the evidence is here because the alternatives are still live:
FIRST-subscription-on-fresh-DB while writes are in flighton lmdb. Declined. That test is byte-identical at the merge base and does not reproduce on this box: 0 failures in 46 lmdb runs at this head — 12 sequential full-file, 24 six-way-contended full-file, 10 grep-isolated under 16 busy cores — and it prints✔in every recentmainunit-test run on CI, including the seven that failed for other reasons. Skipping it would drop the only coverage of a claimed lost delivery on the one backend where it is claimed to happen, for a failure CI has never observed. What was applied is the thread's "at minimum": an explicit 5000 ms timeout plus.catch(() => {}), so a genuine loss now fails asmissing in-flight id Nrather than a bareTimed out after 2000ms(verified by widening the wait to an id that can never arrive). If it reproduces for you, the quarantine is one line — and the trace worth starting from is that thestartTimecollection branch nullspendingRealTimeQueueand setsdropDuringReplay = true(resources/Table.ts:4151), so that branch depends entirely on the forwardsnapshot: falseaudit cursor never being overtaken by a commit that lands during replay.Round-8 (this push): the lost delivery is root-caused and filed as #2311 — P1 Bug under [Epic] Audit-log subsystem hardening (#1651). The review thread's remaining ask was a ticket for the lost delivery itself rather than a quarantine, and the mechanism turned out to be demonstrable, not just a hypothesis.
Table.ts:4149-4188'sstartTimecollection branch is the one replay branch that discards live events (pendingRealTimeQueue = null) instead of buffering them, on the assumption that itssnapshot: falsecursor picks up the tail — butgetRange()returns a terminating iterator, so the window between cursor exhausted anddropDuringReplay = falseis covered by neither path. Forced by inserting a 100 ms delay between the replay loop and itsfinally(indistonly, nothing else changed): 200 of 200 in-flight events hit thedropDuringReplayearly return, the cursor recovered none, and the test failed withmissing in-flight id 20000— the reviewer's exact signature. The mid-replay portion of the window is genuinely covered and a fix should not over-correct there: with the artificial delay at theawait rest()yield instead, 200 events were dropped by the listener and all 200 were then delivered by the cursor. A second, narrower hole is code-traced but unreproduced: replay advancessubscription.startTimeto the last record it saw (Table.ts:4184), andtransactionBroadcast.ts:202skips any live event withsubscription.startTime >= timestamp. The test is still not quarantined — same reasoning as round 7, now with a linked issue so amissing in-flight id Nfailure reads as Subscription replay: startTime collection branch silently drops events committed after the audit cursor terminates #2311 rather than as runner slowness.test2.mdb(lmdb) on exactly the command in question, and lmdb is the faster pass here (80 ms vs 143 ms on rocksdb), not the slower one. This head is now 41/41 green on lmdb on this box (15 sequential grep-isolated, 18 six-way contended, 8 pinned to a single core). The real difference is which side of the window the writes land on: instrumented here, the replay cursor sees an empty audit range and there are zero listener drops, so the uncovered window is never entered at all. On a box where the in-flight writes straddle the end of replay it is deterministic. Both results are correct and Subscription replay: startTime collection branch silently drops events committed after the audit cursor terminates #2311 explains the gap between them.Review decision ledger, left as author calls for you to override: pin-the-graph vs a tolerance assertion on random graphs (pinned, now eight of them); the
randomseam as a public field vs threading through schemaoptions(field — options are persisted schema config, a function doesn't round-trip); MAX_LEVEL clamp bundled here vs its own PR (bundled — one line, named in the commit body, now with its own regression test); quarantine now vs holding for root cause (quarantine — greening main is the task); converting the three unflagged same-classcollect()tests vs leaving them (converted — the PR's claim about the idiom is only true if the class is gone).Verification
HNSW: pre-fix 1/40 sequential failures; post-fix 0/120 (4-way parallel) on the single-seed form, and the eight-seed sweep passes at 3.9s for the suite (up from 0.9s; ~0.47s per 600-node graph). Intermediate result worth knowing: seeding alone appeared to still fail 5/100 — because unit tests load
dist/, and the seam wasn't built yet; afternpm run build, graph state (level histograms) is byte-identical across runs.Seed divergence measured directly: a 40-seed sweep at this head diverges on 4 (
[1, 4, 6, 33]of animul(s+1, 0x9e3779b9)series), i.e. 4 of 160 target-graph pairs — matching the ~2-3% theDESIGN.mdnote records.Txn expiration: pre-fix 2/80 failures with 8 workers pinned to 2 cores (same assertion family as CI); post-fix 0/160 under the identical harness.
Subscription replay: 0 failures in 24 contended full-file lmdb runs (4-way parallel pinned to 2 cores) after the conversions, plus 0 in isolated single-test runs. The count in-flight test went from a 5.3s vacuous pass in isolation to a 0.25s real one. Sentinel ordering was instrumented over those runs: the sentinel was the last event delivered every time, with zero in-flight events after it.
Gates:
npm run test:unit:resourceson both engines — rocksdb 1672 passing / 3 failing, lmdb 1423 passing / 2 failing, where every failure is a pre-existingrandomAccessFields/replayStructuresfailure that reproduces standalone in a fresh mocha process on files this branch does not touch.lint:requiredand prettier clean.npm run test:unit:maincould not be run on this box: a stale local Harper install (~/.harperdb/hdb_boot_properties.filepointing at another checkout) makessecurity/auth.tsfail at module load, before any test runs. That gate--excludesunitTests/resources/**, which is the only area this round touches; forced onto a synthesized clean root it reports 4840 passing with 14 failures, all incliOperations/Login/configValidator, i.e. artifacts of the synthesized root.Round-7 follow-up, at
510058687: the fresh-DB in-flight test was run 46 times on lmdb at this head with zero failures (12 sequential full-file, 24 six-way-contended full-file, 10 grep-isolated under 16 busy cores). The new failure message was proved rather than assumed — widening the wait to an id that can never arrive producesAssertionError: missing in-flight id 20200after 5s instead of the old bare timeout.test:unit:resourcesre-run on both engines at this head (rocksdb 1672 passing / 3 failing, lmdb 1423 passing / 2 failing — the same pre-existingrandomAccessFields/replayStructuresfailures on files this branch does not touch), pluslint:requiredand prettier clean.Round-8 follow-up, at
47f9b8993: the change itself is a five-line comment, so the gates re-run rather than expanded —test:unit:resourceson both engines at this head (rocksdb 1672 passing / 3 failing, lmdb 1423 passing / 2 failing — the same pre-existingrandomAccessFields/replayStructuresfailures on files this branch does not touch),lint:requiredand prettier clean. The Subscription replay: startTime collection branch silently drops events committed after the audit cursor terminates #2311 mechanism was established by direct instrumentation ofdist/resources/Table.jsanddist/resources/transactionBroadcast.js(drop counter, replay start/end markers, and thestartTime >= timestampskip counter), each reverted anddistrebuilt afterwards; the counts quoted above are from those runs.test:integration:allnot run in full: this branch touches a single integration file (integrationTests/components/risk-query.test.ts, run individually, 9/9 on Linux) and the Integration workflow on main is currently failing for unrelated reasons (17 of its last 30 main runs), so a full local run has no usable baseline.Round-9 (rebase onto
main@df5355aaa, at56e544505): no conflicts — the branch's 7 changed files did not overlap anything new onmain, so the rebase replayed cleanly.npm run buildclean;npx mocha unitTests/resources/vectorIndex.test.js unitTests/resources/subscriptionReplay.test.js unitTests/resources/txn-tracking.test.js— 153 passing / 11 pending (pending are the pre-existingRead Txn Expirationand count-branch skips, unrelated to this rebase).unitTests/apiTests/**could not be run in this worktree (no installed Harper system database atHDB_ROOT, an environment gap unrelated to the diff). A full independent pre-push re-review ran (force-push breaks the ancestor chain the delta mode needs) and raised nothing not already covered above — the two Harper-domain findings it surfaced (a timing-dependent branch in the txn-trackingassert.rejects, and the lmdb MQTT quarantine's coverage cost) restate the "txn test's stricter outcome check" and "MQTT durable-session skip" points already called out in this section, so no code changed.Refs [Epic] CI test flakiness (#1655)
Complexity: low — test-only changes plus one inert test seam and a theoretical-edge clamp in HNSW level assignment.
— Claude Opus 5
🤖 Generated with Claude Code
Review-Coverage: authored=claude; ran=gemini,codex; adjudicated=domain; declined=cursor-grok,cursor-composer; rounds=10 @ d894e40
Human-Review-Need: 3 (decisions: test-seam-on-production-class, pinned-seed-sweep-vs-recall-tolerance, known-defect-test-left-red, windows-skip-whole-suite, lmdb-mqtt-quarantine-before-root-cause) @ d894e40