Skip to content

finding: driver-mongodb answers an unrecognised aggregate function as a silent SUM instead of refusing it #12818

Description

@claude

Found while fixing #11151 in driver-mongodb (the boolean-aggregand cell). Filed unassigned, not fixed — that dispatch scoped the work to the four boolean cells, and this is a contract accept/reject question rather than a value repair.

What was read

packages/drivers/driver-mongodb/src/mongodb-aggregation.ts, buildAccumulator, ends its switch on agg.function with:

default:
return{$sum: fieldRef??0};

and the descriptor it switches on declares the function as a bare string:

exportinterfaceAggregationInput{function: string;field?: string;
alias: string;distinct?: boolean;filter?: unknown;}

So any function name this driver does not lower — a typo, a nine-valued analytics method that never narrowed, a function added to the contract but not to this switch — is silently answered as a SUM of that column, under the caller's requested alias. No error, no envelope, no log.

Why it is worth a card

It is the "answers rather than fails" family this very file's history is made of: the "[object Object]" group id (#6850) and the count_distinct set that kept its nulls (#6814) both emitted well-formed pipelines and returned plausible numbers. A default SUM is worse than either, because a sum of a numeric column is a number a dashboard tile will render without complaint.

The same file already demonstrates the opposite discipline one seam over: a groupBy entry carrying a date granularity this driver cannot bucket is REFUSED with the ADR-0112 envelope rather than dropped, and mongodb-aggregation-translation.test.ts pins that refusal. Aggregation function and groupBy entry are the two halves of one lowering, and they disagree about what to do with a shape the driver does not model.

The upstream half, which is somebody else's card

#12776 records that StrategyContext.executeAggregate declares aggregations[].method as string while the engine contract declares the six-value AggregationFunction. That is the reason an unmodelled name can arrive here at all. This card is the driver-side consequence and is worth deciding separately: even once the upstream declaration narrows, a driver that lowers fewer functions than the contract declares should say so rather than substitute one.

What was NOT established, and by whom it should be

  • Not executed against a live mongod. This is a reading of the switch plus the declared type. No behaviour claim beyond "the default arm is reachable, because function is string".
  • Whether the right answer is a refusal is a decision, not a bug fix. Plausible dispositions: (a) refuse with the ADR-0112 NOT_IMPLEMENTED/501 envelope, matching the granularity arm in the same file; (b) narrow AggregationInput.function to the declared union so the default becomes unreachable and tsc catches the drift at the call site; (c) both. Picking between them is triage's, and (b) touches the contract rather than this driver.
  • Not swept across the other drivers. Whether driver-sql, driver-memory and the Turso transport carry the same default arm was not measured here.

Related: #11151 (the boolean cell in the same function, being fixed now), #12776 (the upstream declaration), #6850 / #6814 (earlier members of this file's "answers rather than fails" family, both closed).


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions