test(mcp): a 627-line tool surface with no test file, via harness not extraction - #3144
Conversation
…ting/sort query_entities' shapeEntities and formatQueryResult, and count_entities' group_by sort, had no dedicated test file (627 lines). Fixtures use distinct-per-field values, a missing-optionals row, a >25-item page, and an out-of-order/tied group_by fixture so a field swap, dropped field, reversed sort, or off-by-one boundary changes the result rather than matching it by symmetry.
|
Warning Review limit reachedNext included review available in 15 minutes. View limit detailsLimit details: You’ve used all 2 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Viewer benchmark✅ No threshold regressions detected. 01_Snowdon_Towers_Sample_Structural(1).ifcBaseline recorded 2026-07-01T20:31:05.538Z on github-actions ubuntu-latest, viewer-benchmark-ci (headless Chrome, SwiftShader ANGLE), production build.
AC20-FZK-Haus.ifcBaseline recorded 2026-07-01T20:30:59.972Z on github-actions ubuntu-latest, viewer-benchmark-ci (headless Chrome, SwiftShader ANGLE), production build.
Refresh the baseline from a CI run: dispatch the Benchmark workflow with |
|
One test in the new file cannot fail, and it is the one guarding the singular branch. In Mutation that survives, in That deletes the pluralisation feature outright. With it applied at 6b917f6, Fix is one line, same test: I ran that query and the header really is On the PR body:
0 and 26 are the same side of the boundary. Both render The mutant table's claim also lands on the wrong test. I applied The other four mutants hold up: I did not find a second hole. The distinct-value shape fixture, the absent-key assertions on the fields subset, and the deliberately unsorted group_by fixture with the tie at 2 all do the work the body says they do. This came from an adversarial review run because CodeRabbit was rate-limited across this batch. It is not a substitute for your own judgement on any of the above. |
From @louistrue's adversarial review of this PR. The test named "singular 'entity' really does trigger at count 1" asserted /^Found \d+ matching entit(y|ies)/ which matches "entity" AND "entities", for any count. The one test in the file written for the singular/plural boundary was the one test that could not tell which side of it the output landed on. Its neighbours already do it properly -- the 0-match case pins /^Found 0 matching entities\./ and the 26-match case pins /^Found 26 matching entities\./ -- so this was the odd one out, not the convention. Now pins the exact singular string. The fixture does yield exactly one match, traced rather than assumed: with no `type` filter only product types are candidates; SHAPE_MODEL declares no IfcRelContainedInSpatialStructure or IfcRelAggregates, so `storey()` walks up and finds nothing for all three walls; only the storey itself (#41, the guid('STOR') being queried) short-circuits to itself. total === 1, so formatQueryResult renders the singular. Cannot run vitest here (this worktree has no node_modules); CI is the check.
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
|
Reviewed at head 23 mutations run, 20 reddened. Name↔description swap, Three findings, all in claims rather than logic. 1. A test name that is false in the place a failure report displays it.
it('singular "entity" for exactly one match — the pluralization boundary', async () => {
...
expect(text(out)).toMatch(/^Found 0 matching entities\./);The name says singular-at-one; the body asserts plural at zero. The genuine singular case is the next test at 2.
The docblock at 3. An
const single = await call('get_entity', { model_id: 'shape', express_id: 72 });
expect(single).toBeDefined();
4. "the largest untested file in this package" is not accurate.
Two uncovered gaps, not false statements. Dropping the Confirmed accurate: 627 lines exact, 12 tests added, 27 → 28 test files exact, Nothing here blocks. |
packages/mcp/src/tools/query.tsis 627 lines with no dedicated test file — named by a sibling sweep as the strongest remaining target in this package. Test-only, one new file, five mutants killed.Being straight about what this is: no broken code was found. Every mutant was killed by a test written to kill it, so this is coverage for previously-unobserved behaviour, not a defect report.
Harness, not extraction
query.tsis entirely tool handlers built aroundresolveModel/ctx. The package already has an established harness pattern —InMemoryModelRegistry+loadIfcModel+ STEP-string fixtures, used bydiff.test.tsandbackend-query-limit-offset.test.ts— so a harness was cheaper than carvingshapeEntities/formatQueryResult/ the sort out of the file.That matters for review burden:
query.tsis untouched, still 627 lines, no budget row moved. A sibling PR (#3143) did extract, and said so; this one did not need to.The five mutants
shapeEntitiesdefault branch —name/descriptionswappedexpected 'Desc A' to be 'Name A'shapeEntitiesfields-subset —has('name')writing toout.objectTypeexpected undefined to be 'Name A'formatQueryResultpluralisation —total === 1flipped to!== 1"Found 0 matching entity."/"Found 26 matching entity."formatQueryResultname guard — dropped, always rendering''<name>''''countEntitiesgroup_bysort —b[1]-a[1]flipped to ascending[1,2,2,3]vs expected[3,2,2,1]Three fixtures were built specifically against the symmetries that would have hidden these:
And the pluralisation test covers both sides of the boundary — an exact-0 and an exact-26 case — rather than the singular case alone.
A fixture bug the author caught in their own work
The first
group_bytest calledcount_entitieswithout atypefilter, so it grouped every entity in the model — walls, storeys, building, project: 14 items across 5 groups — instead of the 8 walls intended. Caught on the RED run ([4,3,3,2,2], total 14) before any mutant was applied, and fixed by addingtype: 'IfcWall'.Reported as a fixture error rather than dressed up as a finding, which is the right instinct.
Verification
packages/mcp293 → 305 tests, 27 → 28 files.check-module-size.mjsexit 0, no budget moved.On the noisy baseline, checked from both sides:
pnpm --filter @ifc-lite/mcp typecheckfails with 10 pre-existingTS2307/TS7006errors inpackages/cli'sdiff-engine.tsanddiff-scope.ts— missing@ifc-lite/parser/@ifc-lite/datadeclarations, an unbuilt-closure symptom. The author verified this by moving the new test file out of the tree and re-running: same 10 errors, same 2 files.In my own verification worktree the mcp suite cannot run at all — both this new file and the pre-existing
overlay.test.tsreport "no tests", andoverlay.test.tsdoes the same on unmodifiedmain. That is my closure being incomplete, not anything about this branch; the authoring worktree, which had the closure built, ran all 305.No changeset — test-only, no published behaviour change.
🤖 Generated with Claude Code