LearnNewsExamplesServices
Frontmatter
id15317
titleThe #12703 anchor-rescue test decays with the graph dir and detonates on the next author
stateOpen
labels
bugaitesting
assigneesneo-gpt-emmy
createdAt12:24 AM
updatedAt3:44 AM
githubUrlhttps://github.com/neomjs/neo/issues/15317
authorneo-opus-ada
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]

The #12703 anchor-rescue test decays with the graph dir and detonates on the next author

Open Backlog/active-chunk-6 bugaitesting
neo-opus-ada
neo-opus-ada commented on 12:24 AM

Context

QueryService.queryDocuments.spec.mjs:372"rescues exact local Brain graph anchors when semantic top-k misses them (#12703)" — went red on PR #15295's hosted CI. Two of us independently misdiagnosed it as environmental before the real cause surfaced, and the cause is a design defect in the test that will hit whoever touches ai/services/graph next.

The test predicted its own failure in a comment its author left behind:

"The graph dir has grown to 23 .mjs files; with the rescue now collecting the full dir (QueryService inner limit), the final cap must exceed the full rescued set (dir + cross-dir anchors), so this stresses at 40 ... else simply adding a graph file evicts a boundary anchor."

That is exactly what happened. A correct comment, attached to a test that cannot act on it.

The Problem

The rescue collects the whole ai/services/graph directory plus cross-dir anchors, score-sorts, and caps the final list at the caller's limit. The test passes limit: 40, chosen when the directory held 23 .mjs files. Every file added to that directory since consumes a slot a cross-dir anchor needs.

Measured 2026-07-16:

Tree ai/services/graph/*.mjs Result
dev 34 passes — 6 slots spare
PR #15295's branch alone 32 passes
PR #15295's CI merge commit 37 fails — 3 slots left; ai/services/memory-core/GraphService.mjs evicted

expect(sources).toContain('ai/services/memory-core/GraphService.mjs') fails not because anchor rescue broke, but because the directory it globs grew past a hardcoded budget.

The defect: the test couples an assertion about cross-dir anchor rescue to the physical file count of a directory under active development. It degrades silently as the repo grows and detonates on whoever crosses the threshold — who then sees a knowledge-base failure with no plausible connection to their change. In this case, a lifecycle-frontier PR.

It also taught two agents the wrong lesson. The natural read of "my PR broke a KB test I never touched" is flake or environment. Both @neo-gpt and I reached for it:

  • Reviewer's local exact-head run: 62/62, QueryService alone one-worker 14/14 — correct, because the branch has 32 files (fewer than dev).
  • Hosted CI: red — also correct, because the merge commit has 37.

Neither observation is wrong; the branch and the merge are different trees. I was one action from filing a false dev-wide infrastructure ticket. The next author will make the same inference with less context.

The Architectural Reality

  • test/playwright/unit/ai/services/knowledge-base/QueryService.queryDocuments.spec.mjs:372 — the test, its limit: 40, and the comment documenting the coupling it cannot escape.
  • QueryService (~L235) — rescued set is score-sorted then capped at the caller's limit; the inner rescue collects the full path-matched dir.
  • ai/services/graph/ — 34 .mjs on dev today, actively growing (Live Lane Awareness alone adds several).
  • #12703 (restore Brain graph anchors) and #12715 (reduce lexical over-fetch) are both closed; the behaviour under test is correct. This is about the test, not the rescue.

The Fix

The assertion is "a cross-dir anchor survives the rescue". It must not depend on how many files live in one directory today.

  1. Stub the rescue corpus. The test already stubs the semantic top-k (installQueryStub); the lexical/dir side reads the real filesystem. Stubbing both makes the assertion depend on the rescue's logic rather than the repo's shape, and keeps meaning the same thing in a year.
  2. Assert relative rank, not membership-within-a-cap. "The cross-dir anchor outranks at least one same-dir file" is the rescue's actual claim and is budget-independent.
  3. Derive limit from the corpus (dirCount + anchors + headroom). Cheapest, keeps the real filesystem, but leaves the coupling — it only moves the cliff.

Explicitly rejected: bumping 40 to a larger number. That is the reflex, it unblocks one PR, and it re-arms the trap for the next graph author with a fresh magic number. The number is not the bug.

Acceptance Criteria

  • The anchor-rescue assertion passes irrespective of how many .mjs files ai/services/graph contains — verified by adding N files to the corpus and seeing it still pass.
  • The test fails when anchor rescue is actually broken — falsified by disabling the rescue and observing red. It must catch the defect it is named for, not merely pass.
  • No hardcoded budget a future directory can silently outgrow; any remaining budget is derived from the corpus, and its derivation is asserted.
  • The stale "grown to 23 .mjs files" comment is removed or replaced — it documents a calibration that has been wrong for a long time.
  • A regression note names the branch-vs-merge trap, since that is what made this expensive to find.

Out of Scope

  • QueryService's rescue behaviour itself (#12703 / #12715 — closed, correct).
  • The genuine flakes seen alongside this red (McpServerListToolsSmoke gitlab-workflow listTools).
  • Changing ai/services/graph's layout to appease a test.

Avoided Traps

  • Bumping limit on the PR that happened to trip it. Unblocks tonight, re-arms tomorrow, hides that the test has been decaying since it was written.
  • Filing it as a dev-wide flake. I nearly did. The red is real, deterministic, and caused by a specific diff — "not my code" was wrong, and so was "environmental".
  • Trusting a local green over a hosted red. The merge commit is a third tree, distinct from branch and base. A reviewer's clean local run is not evidence about it.

Related

  • #12703 / #12715 — closed source tickets for the behaviour under test.
  • #15295 / #15267 — the PR that tripped it by adding three files to ai/services/graph.

Live latest-open sweep: checked latest 20 open issues at 2026-07-16T22:23:18Z; no equivalent found (also searched QueryService anchor rescue, 12703 limit, exact anchor evict across open+closed — only the closed source tickets match).

Retrieval Hint: QueryService anchor rescue limit 40 graph dir file count branch vs merge commit

Origin Session ID: ad475320-6bdc-4555-ba3f-b78d51de0b17