Skip to content

Commit eca44d3

Browse files
committed
test(service-automation): hold the caller's bound and refuse the combinators this double does not implement
Two further gates were RED on this same in-process engine double before this branch's last head, and neither had run in CI: the lint job executes its gates sequentially under `bash -e`, so check:engine-double-contract's exit 1 halted the job and masked every step behind it. Both are the same defect class as the finding that halted it — a test double looser than the engine it stands in for — in the same literal, and both gates state their baseline never grows, so the mechanical fix each prints is the only route. check:where-matcher — `matches` read a combinator as a FIELD NAME. No row carries a column called `$or`, so such a clause silently drops every row and this arm would report "nobody was reached" for a reason that is not the one under test, in the very file written to make that distinction visible. The store answers scalar equality, so it now refuses a combinator loudly rather than answering wrongly. check:objectql-double-limit — `find` applied the caller's bound by truthiness, so `limit: 0` returned every row: the one call that asked for none. Applied by presence now, after the filter. Neither baseline gained a file ("no files added", both gates). No assertion and no case was touched: the diff contains zero `expect(`/`it(`/`describe(` lines, and all nine cases of the differential control still pass on both arms, CONTROLs included — the in-process arm still genuinely delivers. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zTkyNHJ7TkuN2oXtP5x37
1 parent 47b19ae commit eca44d3

1 file changed

Lines changed: 22 additions & 3 deletions

File tree

packages/services/service-automation/src/builtin/notify-zero-delivery-visibility.integration.test.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,24 @@ function inProcessEngine(): IDataEngine {
230230
tables.set(object, fresh);
231231
return fresh;
232232
};
233-
const matches = (row: Record<string, unknown>, where: Record<string, unknown> | undefined): boolean =>
234-
Object.entries(where ?? {}).every(([k, v]) => row[k] === v);
233+
const matches = (row: Record<string, unknown>, where: Record<string, unknown> | undefined): boolean => {
234+
const clauses = Object.entries(where ?? {});
235+
// This store answers SCALAR EQUALITY and nothing else. A `$or` / `$and`
236+
// read as a field name is the silently-wrong shape: no row carries a
237+
// column called `$or`, so the clause quietly drops everything and this
238+
// arm reports "nobody was reached" for a reason that is not the one
239+
// under test — the exact failure this whole file exists to make
240+
// visible. Refuse loudly instead (`check:where-matcher`).
241+
for (const [k] of clauses) {
242+
if (k.startsWith('$')) {
243+
throw new Error(
244+
`in-process engine double: WHERE combinator '${k}' is not implemented — `
245+
+ 'this store answers scalar equality only.',
246+
);
247+
}
248+
}
249+
return clauses.every(([k, v]) => row[k] === v);
250+
};
235251

236252
return {
237253
async insert(object: string, row: Record<string, unknown>) {
@@ -241,7 +257,10 @@ function inProcessEngine(): IDataEngine {
241257
},
242258
async find(object: string, query?: { where?: Record<string, unknown>; limit?: number }) {
243259
const hits = rowsOf(object).filter((r) => matches(r, query?.where));
244-
return query?.limit ? hits.slice(0, query.limit) : hits;
260+
// The caller's bound by PRESENCE, applied AFTER the filter. A
261+
// truthiness test hands back EVERY row on `limit: 0` — the one call
262+
// that asked for none (`check:objectql-double-limit`).
263+
return typeof query?.limit === 'number' ? hits.slice(0, query.limit) : hits;
245264
},
246265
async findOne(object: string, query?: { where?: Record<string, unknown> }) {
247266
// The #4419 dispatch, imported rather than approximated: a `findOne`

0 commit comments

Comments
 (0)