From c13990a398909c0ec80973f9b9cbebaa8aa40000 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Fri, 4 Sep 2026 12:58:41 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=8D=83=20test:=20Restore=20Sweep=20Covera?= =?UTF-8?q?ge=20of=20Typed-Criteria=20Methods=20(#15609)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🍃 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. --- .../misc/documentdb/documentdb-compat.md | 12 +++++++++--- .../misc/documentdb/sweep.documentdb.spec.ts | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/data-schemas/misc/documentdb/documentdb-compat.md b/packages/data-schemas/misc/documentdb/documentdb-compat.md index 245ab2b4e7..8152e360c2 100644 --- a/packages/data-schemas/misc/documentdb/documentdb-compat.md +++ b/packages/data-schemas/misc/documentdb/documentdb-compat.md @@ -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. diff --git a/packages/data-schemas/misc/documentdb/sweep.documentdb.spec.ts b/packages/data-schemas/misc/documentdb/sweep.documentdb.spec.ts index b579718173..9e5eae1cfb 100644 --- a/packages/data-schemas/misc/documentdb/sweep.documentdb.spec.ts +++ b/packages/data-schemas/misc/documentdb/sweep.documentdb.spec.ts @@ -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 SweepCase | Promise> = { /** 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