🍃 test: Restore Sweep Coverage of Typed-Criteria Methods (#15609)
Some checks failed
Docker Dev Images Build / publish (push) Waiting to run
Sync Helm Chart Tags / Ignore non-main push (push) Waiting to run
Sync Helm Chart Tags / Sync chart tags (push) Waiting to run
Publish `@librechat/client` to NPM / pack (push) Has been cancelled
Publish `@librechat/client` to NPM / publish-npm (push) Has been cancelled

* 🍃 test: Restore Sweep Coverage of Typed-Criteria Methods

The typed-criteria refactor (#15580) validates query criteria key by key and
fails closed on anything unrecognized — correctly, since a silently accepted
bad criterion would widen a filter into an unscoped `find` or `deleteMany`.
The sweep synthesizes arguments from parameter names, so a parameter named
`query` received a string, which `buildFilter` read as a criteria object and
rejected at index '0'.

Six methods therefore went from adjudicated to un-driven with the suite still
green: `getActions`, `getAssistants`, `deleteAction(s)`, and
`deleteAssistant(s)`. Criteria-shaped parameters are now synthesized as an
empty object, which builds an empty filter and still reaches the engine.

Recovered 13 methods in total — the six regressions plus seven that had been
silently un-driven for the same reason (prompts, groups, conversation tags),
including through the runs recorded as authoritative. Baseline coverage rises
from 372 to 385 of 518 methods. The compatibility assessment now flags this
count as the thing to watch across releases: a coverage regression hides
behind a passing suite, and only a matrix diff surfaces it.

* 🍃 test: Preserve searchMessages' String Query in the Sweep

Criteria-shaped synthesis is name-based, so it also caught
`searchMessages(query: string, ...)`, whose parameter is a genuine search
string. On a Meili-enabled deployment that object is forwarded verbatim into
`meiliSearch`, so the recorded outcome would reflect a harness-generated
request rather than the method's behavior.

`searchMessages` gets an `ARG_OVERRIDES` entry supplying a real query string;
its failure is now the honest 'MeiliSearch plugin not registered' rather than
an invalid request. It is the only method in `src/methods` whose
`query`/`criteria`/`filter` parameter is string-typed, which the synthesis
comment records along with the symptom a future one would show.

An error-driven variant (repair only on 'Unknown query criterion') was tried
first and rejected: it protects string parameters automatically but loses
seven methods whose criteria parameter makes them early-return on a string
rather than throw a recognizable error, taking coverage from 385 back to 378.
Coverage holds at 385 of 518 driven, zero engine rejections.
This commit is contained in:
Danny Avila 2026-09-04 12:58:41 -04:00 • committed by GitHub
parent 09da878a47
commit c13990a398
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 25 additions and 4 deletions

View file

@ -263,10 +263,16 @@ matrices (`SWEEP_REPORT_PATH`).
Corrected-harness baseline (replica-set MongoDB, real ACL cascades, index DDL
and transaction-lifecycle instrumentation, per-invocation async attribution,
seeded authority-transaction case, constructor exports excluded, a fresh
method bundle per case): **370 of 509 methods issue at least one query; zero
rejections on MongoDB**. The remaining 139 issue none (validation
method bundle per case, criteria-shaped parameters synthesized as objects):
**385 of 518 methods issue at least one query; zero rejections on MongoDB**.
The remaining 133 issue none (validation
rejected the synthesized arguments, or a guard short-circuited); they are
listed in the matrix and shrink by adding `ARG_OVERRIDES` entries. The report's `rows` payload is normalized for
listed in the matrix and shrink by adding `ARG_OVERRIDES` entries. Watch this count across releases: the typed
criteria refactor (#15580) silently took six adjudicated methods to
un-driven because the sweep synthesized a string for a `query` parameter and
`buildFilter` fails closed on it — a coverage regression that a green suite
hides. Diffing matrices, not reading the pass line, is what catches it. The
report's `rows` payload is normalized for
cross-engine diffing (`diff <(jq .rows a.json) <(jq .rows b.json)`); run
metadata lives outside it.

View file

@ -260,6 +260,16 @@ const ARRAY_PARAMS =
function valueFor(name: string): unknown {
if (name === 'mongoose') return mongoose;
if (name === 'kind') return 'manual';
/** Typed-criteria parameters (`utils/criteria.ts`) are validated key by key
* and fail closed, so a synthesized string is read as a criteria object and
* rejected at index '0'. An empty criteria object is valid, builds an empty
* filter, and still reaches the engine. `searchMessages` is the sole method
* whose `query` parameter is a genuine string (verified across
* `src/methods`); it carries an `ARG_OVERRIDES` entry so it keeps one. A
* future string-valued `query`/`criteria`/`filter` parameter would need the
* same treatment — the symptom is a method reporting `threw` on a type
* error rather than reaching the database. */
if (/^(query|criteria|filter)$/.test(name)) return {};
if (/pipeline/i.test(name)) return [{ $match: { _id: objectId() } }];
if (OBJECT_ID_PARAMS.test(name)) return objectId();
if (ARRAY_PARAMS.test(name)) return [`sweep-${name}-${runId}`];
@ -289,7 +299,7 @@ function replaceValue(node: unknown, target: string, replacement: unknown): unkn
/** Repairs synthesized arguments from a validation error's own message, so the
* retry reaches the database instead of being reported `not-driven`. Returns
* the repaired arguments, or null when the error is not machine-repairable. */
function adaptArgs(args: unknown[], error: unknown): unknown[] | null {
function adaptArgs(args: unknown[], error: unknown, paramNames: string[] = []): unknown[] | null {
const message = String((error as { message?: string })?.message ?? '');
let match = /Cast to (?:\[)?ObjectId(?:\])? failed for value "+?\[?'?"?([^"'\]]+)/.exec(message);
if (match != null) {
@ -349,6 +359,11 @@ const ARG_OVERRIDES: Record<string, () => SweepCase | Promise<SweepCase>> = {
/** Positional (searchParameter, id): a synthesized string for the first
* parameter lands inside a `$match` and malforms it on both engines. */
getAgentWithVersionCount: () => ({ args: [{ id: `agent-sweep-${runId}` }] }),
/** Takes a genuine search string, not typed criteria: the criteria-shaped
* synthesis above would hand it an object, which a Meili-enabled deployment
* forwards verbatim into `meiliSearch` and adjudicates a harness-generated
* request instead of the method's real behavior. */
searchMessages: () => ({ args: [`sweep-search-${runId}`, { page: 1, limit: 2 }, false] }),
/** The bounded authority snapshot is the one production path that COMMITS a
* transaction; generic synthesis dies on target validation before a session
* ever starts, which would leave the session instrumentation exercising