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.
- 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.
- 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.
- 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
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
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 touchesai/services/graphnext.The test predicted its own failure in a comment its author left behind:
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/graphdirectory plus cross-dir anchors, score-sorts, and caps the final list at the caller'slimit. The test passeslimit: 40, chosen when the directory held 23.mjsfiles. Every file added to that directory since consumes a slot a cross-dir anchor needs.Measured 2026-07-16:
ai/services/graph/*.mjsdevai/services/memory-core/GraphService.mjsevictedexpect(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:
QueryServicealone one-worker 14/14 — correct, because the branch has 32 files (fewer than dev).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, itslimit: 40, and the comment documenting the coupling it cannot escape.QueryService(~L235) — rescued set is score-sorted then capped at the caller'slimit; the inner rescue collects the full path-matched dir.ai/services/graph/— 34.mjsondevtoday, 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.
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.limitfrom 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
.mjsfilesai/services/graphcontains — verified by adding N files to the corpus and seeing it still pass..mjsfiles" comment is removed or replaced — it documents a calibration that has been wrong for a long time.Out of Scope
QueryService's rescue behaviour itself (#12703/#12715— closed, correct).McpServerListToolsSmokegitlab-workflow listTools).ai/services/graph's layout to appease a test.Avoided Traps
limiton the PR that happened to trip it. Unblocks tonight, re-arms tomorrow, hides that the test has been decaying since it was written.Related
#12703/#12715— closed source tickets for the behaviour under test.#15295/#15267— the PR that tripped it by adding three files toai/services/graph.Live latest-open sweep: checked latest 20 open issues at
2026-07-16T22:23:18Z; no equivalent found (also searchedQueryService anchor rescue,12703 limit,exact anchor evictacross open+closed — only the closed source tickets match).Retrieval Hint:
QueryService anchor rescue limit 40 graph dir file count branch vs merge commitOrigin Session ID:
ad475320-6bdc-4555-ba3f-b78d51de0b17