/** * Motion — the two rules that make this a system, and the one departure that * makes it a risk. * * The departure first. `permissions.ts` states that every read endpoint returns * the whole book because no row-level filter exists anywhere in the query * layer; motion templates are the first exception, and an exception that is * only enforced by the UI is not an exception, it is a leak with a nice screen * in front of it. So the first suite renders the actual predicate to SQL and * asserts on it. It looks like a test of an implementation detail and is not: * the WHERE clause IS the access policy, and the two ways of getting it wrong — * dropping the owner comparison, or widening it with `OR owner IS NULL` — both * produce a query that returns rows and reports nothing. * * The rest drive the exported mutation definitions against a scripted * transaction, in the register of `activities.test.ts`. The fake answers * queries in call order and records what ran; it is deliberately not a * database, because a fake that pretends to run SQL is a fake that will one day * assert a broken query works. */ import { strict as assert } from 'node:assert'; import { describe, it } from 'node:test'; import { getTableName, isSQLWrapper, isTable, type SQL } from 'drizzle-orm'; import { PgDialect } from 'drizzle-orm/pg-core'; import { motionScoreBasisPoints } from '@pig/core'; import type { Database, MotionTemplate } from '@pig/db'; import { Hono } from 'hono'; import { AuthError, type Principal } from '../src/lib/auth'; import { executeMutation, MutationError, type ApiEnv } from '../src/lib/mutation'; import { createMotionRoutes, motionArtifactCreateDefinition, motionArtifactPromoteDefinition, motionEngagementCreateDefinition, motionEngagementUpdateDefinition, motionScoreDefinition, motionTemplateCreateDefinition, motionTemplatePublishDefinition, motionTemplateUpdateDefinition, motionTemplateVersionDefinition, } from '../src/routes/motion'; import { MotionService, motionSlug, visibleTemplates } from '../src/services/motion'; import { onTeam, principal } from './helpers/principal'; const OWNER = '00000000-0000-4000-8000-000000000001'; const OTHER = '00000000-0000-4000-8000-0000000000aa'; const DEAL_ID = '00000000-0000-4000-8000-0000000000d1'; const ACCOUNT_ID = '00000000-0000-4000-8000-0000000000ac'; const ENGAGEMENT_ID = '00000000-0000-4000-8000-0000000000e1'; const ARTIFACT_ID = '00000000-0000-4000-8000-0000000000f1'; const TEMPLATE_ID = '00000000-0000-4000-8000-0000000000b1'; const NOW = new Date('2026-08-17T09:00:00.000Z'); /** A demand member: `motion:write`, no `motion:publish`. */ const member = principal(onTeam('demand', 'member')); /** A demand lead: both, which is the point of the split. */ const lead = principal(onTeam('demand', 'lead')); // --------------------------------------------------------------- the fixtures function template(overrides: Partial = {}): MotionTemplate { return { id: TEMPLATE_ID, kind: 'poc', slug: 'poc-plan', version: 1, title: 'POC plan', summary: 'What a proof of concept must show.', body: '# POC plan', fields: null, stage: 'poc', visibility: 'private', ownerUserId: OWNER, supersedesId: null, originArtifactId: null, isSystem: false, usageCount: 0, archivedAt: null, createdAt: NOW, updatedAt: NOW, ...overrides, }; } const deal = { id: DEAL_ID, accountId: ACCOUNT_ID, name: 'DEMO — Northwind training' }; const engagement = { id: ENGAGEMENT_ID, demandDealId: DEAL_ID, status: 'open' }; function artifact(overrides: Record = {}) { return { id: ARTIFACT_ID, engagementId: ENGAGEMENT_ID, templateId: null, kind: 'poc', stage: 'poc', title: 'Northwind POC plan', body: '# What we proved', fields: null, status: 'final', authoredByUserId: OWNER, promotedTemplateId: null, archivedAt: null, createdAt: NOW, updatedAt: NOW, ...overrides, }; } // ------------------------------------------------------------------ the fake interface Recorded { events: string[]; inserted: { table: string; row: Record }[]; updated: { table: string; values: Record }[]; } /** * A transaction that answers selects from a script, in call order, and records * every write with the table it landed in. Order-dependence is the price of not * pretending to be Postgres, and it is what makes "no UPDATE ran" assertable. */ function database(script: unknown[][]): { db: Database; log: Recorded } { const log: Recorded = { events: [], inserted: [], updated: [] }; const results = [...script]; const next = (): unknown[] => results.shift() ?? []; const selectChain = { from: () => selectChain, innerJoin: () => selectChain, leftJoin: () => selectChain, where: () => selectChain, orderBy: () => selectChain, groupBy: () => selectChain, // `limit` returns the chain rather than a promise so that `.for('update')` // can follow it, as it does on every query in this feature that allocates // a version number. The chain is a thenable, so `await` still ends it. limit: () => selectChain, for: () => selectChain, then: (resolve: (rows: unknown[]) => unknown) => resolve(next()), }; const name = (table: unknown): string => (isTable(table) ? getTableName(table) : 'unknown'); const tx = { select: () => { log.events.push('select'); return selectChain; }, insert: (table: unknown) => ({ values: (row: Record) => { log.events.push(`insert:${name(table)}`); log.inserted.push({ table: name(table), row }); const written = [{ id: `${name(table)}-${log.inserted.length}`, ...row }]; return { returning: async () => written, then: (resolve: (value: unknown) => unknown) => resolve(undefined), }; }, }), update: (table: unknown) => ({ set: (values: Record) => ({ where: () => { log.events.push(`update:${name(table)}`); log.updated.push({ table: name(table), values }); return Object.assign(Promise.resolve(undefined), { returning: async () => [{ id: `${name(table)}-updated`, ...values }], }); }, }), }), }; return { db: { transaction: async (work: (t: unknown) => Promise) => { log.events.push('transaction'); return work(tx); }, // The same scripted chain outside a transaction, so a read handler can be // driven through the mounted routes rather than only its service. select: tx.select, } as unknown as Database, log, }; } /** The motion routes with a principal already resolved, as `createApp` mounts them. */ function mounted(db: Database, who: Principal): Hono { const app = new Hono(); app.use('*', async (c, next) => { c.set('principal', who); await next(); }); app.route('/', createMotionRoutes(db)); return app; } function rendered(userId: string, isPlatformAdmin = false) { const predicate = visibleTemplates({ userId, isPlatformAdmin }); return predicate ? new PgDialect().sqlToQuery(predicate) : null; } // ------------------------------------------------------------------- the tests describe('the private library filter is a WHERE clause, not an affordance', () => { it('matches shared rows for everyone and private rows only against the viewer id', () => { const query = rendered(OWNER); assert.ok(query, 'a member must be filtered at all'); assert.match(query.sql, /"visibility" = \$1/); assert.match(query.sql, /"owner_user_id" = \$3/); assert.deepEqual(query.params, ['shared', 'private', OWNER]); }); it('never widens to `owner_user_id IS NULL` — an orphaned private draft belongs to nobody', () => { const query = rendered(OWNER); // `ON DELETE SET NULL` on the owner column can produce a private row with // no owner. Matching it here would publish every departed colleague's // drafts to the whole workspace, and the query would look like a fix for // rows that had "gone missing". assert.ok(query); assert.doesNotMatch(query.sql, /owner_user_id" is null/i); }); it('is deliberately absent for a platform admin — an admin CAN read a private template', () => { // Not a hole. An unfiltered query here is the decision: someone has to be // able to answer "what is in this workspace" during an audit or a // departure. If this ever starts returning a predicate, that was a choice // somebody made, and this test is where they say so. assert.equal(rendered(OTHER, true), null); }); }); describe('a slug is the identity of a lineage', () => { it('strips the combining mark NFKD leaves behind rather than hyphenating through a word', () => { // `normalize('NFKD')` splits "é" into "e" plus a combining acute, and the // `[^a-z0-9]+` rule that follows turns that mark into a separator — so // without the strip, "Café strategy" starts the lineage `caf-e-strategy` // and the next person authoring the same title cannot find it. assert.equal(motionSlug('Café strategy'), 'cafe-strategy'); assert.equal(motionSlug('Proposal Blocks'), 'proposal-blocks'); // Nothing latin survives, and an empty slug would violate the NOT NULL. assert.equal(motionSlug('日本語'), 'untitled'); }); }); describe('a used template is never edited in place', () => { it('refuses a PATCH once usage_count is above zero, and names the versions endpoint', async () => { const { db, log } = database([[template({ usageCount: 3 })]]); await assert.rejects( executeMutation( db, principal(onTeam('demand', 'member')), async () => ({ body: '# Rewritten' }), motionTemplateUpdateDefinition(), { id: TEMPLATE_ID }, ), (error: unknown) => error instanceof MutationError && error.code === 'template_in_use' && error.status === 409 && error.message.includes('/versions'), ); assert.deepEqual(log.updated, [], 'a live engagement must not have its template move underneath it'); }); it('edits freely while nobody has instantiated it — an unused template is still a draft', async () => { const { db, log } = database([[template({ usageCount: 0 })]]); await executeMutation( db, member, async () => ({ title: 'POC plan, tightened' }), motionTemplateUpdateDefinition(), { id: TEMPLATE_ID }, ); assert.equal(log.updated.length, 1); assert.equal(log.updated[0]?.table, 'motion_templates'); assert.equal(log.updated[0]?.values.title, 'POC plan, tightened'); }); it('refuses an edit to somebody else\'s template even when it is shared — publishing is not donating', async () => { const { db, log } = database([[template({ visibility: 'shared', ownerUserId: OTHER })]]); await assert.rejects( executeMutation( db, member, async () => ({ body: '# Mine now' }), motionTemplateUpdateDefinition(), { id: TEMPLATE_ID }, ), (error: unknown) => error instanceof AuthError && error.code === 'not_owner', ); assert.deepEqual(log.updated, []); }); }); describe('publishing is a lead\'s judgement, and the owner\'s', () => { it('refuses a member without motion:publish before the row is read at all', async () => { const { db, log } = database([[template()]]); await assert.rejects( executeMutation(db, member, async () => ({}), motionTemplatePublishDefinition(), { id: TEMPLATE_ID, }), (error: unknown) => error instanceof AuthError && error.code === 'insufficient_permission', ); assert.deepEqual(log.events, [], 'permission precedes the transaction, so nothing was queried'); }); it('refuses a lead flipping somebody else\'s private template to shared', async () => { const { db, log } = database([[template({ ownerUserId: OTHER })]]); await assert.rejects( executeMutation(db, lead, async () => ({}), motionTemplatePublishDefinition(), { id: TEMPLATE_ID, }), (error: unknown) => error instanceof AuthError && error.code === 'not_owner', ); assert.deepEqual(log.updated, []); }); it('gates creating straight into the shared library on the same capability', async () => { // The publish endpoint is not the only door into the shared library, so a // member who simply POSTs `visibility: 'shared'` must be refused too. const { db, log } = database([]); await assert.rejects( executeMutation( db, member, async () => ({ kind: 'poc', title: 'POC plan', summary: 'What a POC must show.', body: '# POC', stage: 'poc', visibility: 'shared', }), motionTemplateCreateDefinition(), ), (error: unknown) => error instanceof AuthError && error.code === 'insufficient_permission', ); assert.deepEqual(log.inserted, []); }); it('creates a private template owned by the author, because an unowned private row is unreadable', async () => { const { db, log } = database([]); await executeMutation( db, member, async () => ({ kind: 'poc', title: 'POC plan', summary: 'What a POC must show.', body: '# POC', stage: 'poc', }), motionTemplateCreateDefinition(), ); const written = log.inserted.find((row) => row.table === 'motion_templates'); assert.equal(written?.row.visibility, 'private'); assert.equal(written?.row.ownerUserId, member.userId); assert.equal(written?.row.version, 1); assert.equal(written?.row.slug, 'poc-plan'); }); }); describe('promotion is the loop', () => { function promote(db: Database, input: Record = {}) { return executeMutation( db, lead, async () => input, motionArtifactPromoteDefinition(), { id: ARTIFACT_ID }, ); } it('refuses to promote an artifact that is already in the library', async () => { const { db, log } = database([[artifact({ promotedTemplateId: TEMPLATE_ID })]]); await assert.rejects( promote(db), (error: unknown) => error instanceof MutationError && error.code === 'already_promoted' && error.status === 409, ); assert.deepEqual(log.inserted, [], 'a second promotion would fork the lineage silently'); }); it('refuses to promote a draft — the library is what the next deployment copies', async () => { const { db, log } = database([[artifact({ status: 'draft' })]]); await assert.rejects( promote(db), (error: unknown) => error instanceof MutationError && error.code === 'artifact_not_final' && error.status === 409, ); assert.deepEqual(log.inserted, []); }); it('writes a shared version pointing back at the artifact that proved it', async () => { const { db, log } = database([[artifact()], [{ engagement, deal }], []]); const result = (await promote(db, { slug: 'poc-plan' })) as { template: { version: number; visibility: string; originArtifactId: string }; }; assert.equal(result.template.version, 1); assert.equal(result.template.visibility, 'shared'); assert.equal(result.template.originArtifactId, ARTIFACT_ID); assert.equal( log.updated.find((row) => row.table === 'engagement_artifacts')?.values.promotedTemplateId, 'motion_templates-1', ); }); it('chains supersedes_id across three promotions of one lineage', async () => { let previous: { id: string; version: number } | null = null; const chain: { id: string; version: number; supersedesId: string | null }[] = []; for (let round = 0; round < 3; round += 1) { // The lineage is read twice and on purpose: once unfiltered for the // version number, once through the visibility filter for the row the new // version may claim to supersede. const lineage = previous ? [{ ...template(), ...previous, slug: 'poc-plan' }] : []; const { db } = database([ [artifact({ id: `${ARTIFACT_ID}-${round}` })], [{ engagement, deal }], lineage, lineage, ]); const result = (await promote(db, { slug: 'poc-plan' })) as { template: { id: string; version: number; supersedesId: string | null }; }; chain.push({ id: result.template.id, version: result.template.version, supersedesId: result.template.supersedesId, }); previous = { id: result.template.id, version: result.template.version }; } assert.deepEqual( chain.map((row) => row.version), [1, 2, 3], ); assert.equal(chain[0]?.supersedesId, null, 'the first version supersedes nothing'); assert.equal(chain[1]?.supersedesId, chain[0]?.id); assert.equal(chain[2]?.supersedesId, chain[1]?.id); }); it('lands the audit row on the account of the deal that proved it', async () => { const { db, log } = database([[artifact()], [{ engagement, deal }], []]); await promote(db, { slug: 'poc-plan' }); const activity = log.inserted.find((row) => row.table === 'activities')?.row; assert.equal(activity?.accountId, ACCOUNT_ID); assert.equal(activity?.demandDealId, DEAL_ID); assert.match(String(activity?.subject), /^Promoted to the library:/); }); }); describe('a lineage nobody can read never supplies content to one everybody can', () => { /** * The version number and the predecessor row are two different questions, and * answering both from one unfiltered query is the shape of the bug these pin. * Both suites script a lineage whose newest row is private to somebody else: * the unfiltered read finds v4, the filtered read finds nothing. */ const PRIVATE_SUMMARY = 'Unreleased pricing: 40% floor, Northwind only.'; /** Alice's v4, which the unfiltered read finds and the filtered read must not. */ const hidden = () => template({ id: '00000000-0000-4000-8000-0000000000c4', version: 4, ownerUserId: OTHER, summary: PRIVATE_SUMMARY, }); it('promotes past a private newest version without copying its summary or naming its id', async () => { const { db, log } = database([ [artifact()], [{ engagement, deal }], [hidden()], [], ]); await executeMutation(db, lead, async () => ({ slug: 'poc-plan' }), motionArtifactPromoteDefinition(), { id: ARTIFACT_ID, }); const written = log.inserted.find((row) => row.table === 'motion_templates')?.row; // v5, because the unique constraint is on the whole lineage and a private // fork still consumes a number. assert.equal(written?.version, 5); // But nothing else from that row. The summary fell back to the artifact's // own title, and the new version supersedes nothing it cannot show. assert.notEqual(written?.summary, PRIVATE_SUMMARY); assert.equal(written?.summary, artifact().title); assert.equal(written?.supersedesId, null); }); it('forks a shared template without disclosing that private versions of it exist', async () => { const source = template({ id: TEMPLATE_ID, visibility: 'shared', ownerUserId: OTHER }); const { db, log } = database([[source], [hidden()], []]); await executeMutation(db, member, async () => ({}), motionTemplateVersionDefinition(), { id: TEMPLATE_ID, }); const written = log.inserted.find((row) => row.table === 'motion_templates')?.row; assert.equal(written?.version, 5, 'the number is allocated against the whole lineage'); assert.equal( written?.supersedesId, source.id, 'the edge points at the row that was actually forked, not at a private row the forker cannot fetch', ); }); it('refuses to promote an artifact whose source template is unreadable, rather than 404ing on the artifact', async () => { const { db, log } = database([ [artifact({ templateId: TEMPLATE_ID })], [{ engagement, deal }], [], ]); await assert.rejects( executeMutation(db, lead, async () => ({}), motionArtifactPromoteDefinition(), { id: ARTIFACT_ID, }), (error: unknown) => error instanceof MutationError && error.code === 'source_template_unreadable' && error.status === 409 && error.message.includes('slug'), ); assert.deepEqual(log.inserted, []); }); }); describe('a template id somebody sent is read before it is stored', () => { it('refuses a playbook the setter cannot read, so a private id cannot go book-wide on an engagement', async () => { const { db, log } = database([[{ engagement, deal }], []]); await assert.rejects( executeMutation( db, member, async () => ({ playbookTemplateId: TEMPLATE_ID }), motionEngagementUpdateDefinition(), { id: ENGAGEMENT_ID }, ), (error: unknown) => error instanceof MutationError && error.status === 404, ); assert.deepEqual(log.updated, [], 'an unreadable id must not reach the foreign key either'); }); }); describe('a UI hint that disagrees with its endpoint is the hint that is wrong', () => { it('does not offer publish to a read-only key, which the endpoint would refuse for scope', async () => { const readOnlyLead = principal({ ...onTeam('demand', 'lead'), via: 'api_key', scopes: ['read'] }); const mine = template({ ownerUserId: readOnlyLead.userId }); const { db } = database([[mine], [mine]]); const response = await mounted(db, readOnlyLead).request(`/api/motion/templates/${TEMPLATE_ID}`); const body = (await response.json()) as { canPublish: boolean }; assert.equal(response.status, 200); assert.equal( body.canPublish, false, 'the button would 403 insufficient_scope, and a button that cannot work must not be offered', ); }); it('still offers it to the same lead on a full-scope session', async () => { const mine = template({ ownerUserId: lead.userId }); const { db } = database([[mine], [mine]]); const response = await mounted(db, lead).request(`/api/motion/templates/${TEMPLATE_ID}`); const body = (await response.json()) as { canPublish: boolean }; assert.equal(body.canPublish, true); }); }); describe('a slug collision is the caller\'s to fix, not a 500', () => { it('answers 409 naming the versions endpoint when the title derives a slug already in use', async () => { // "Proposal Blocks" is one of the nine shipped starter templates, so this // is the first thing a new author trips over rather than an edge case. const { db, log } = database([[{ version: 1 }]]); await assert.rejects( executeMutation( db, member, async () => ({ kind: 'proposal', title: 'Proposal Blocks', summary: 'Reusable proposal language.', body: '# Blocks', stage: 'proposal', }), motionTemplateCreateDefinition(), ), (error: unknown) => error instanceof MutationError && error.code === 'template_slug_exists' && error.status === 409 && error.message.includes('/versions'), ); assert.deepEqual(log.inserted, []); }); }); describe('instantiating a template', () => { it('increments usage_count in the same transaction that writes the artifact', async () => { const { db, log } = database([ [{ engagement, deal }], [template({ usageCount: 2, visibility: 'shared', ownerUserId: OTHER })], ]); await executeMutation( db, member, async () => ({ templateId: TEMPLATE_ID }), motionArtifactCreateDefinition(), { id: ENGAGEMENT_ID }, ); // One transaction, both writes: a count that could be committed without the // artifact would close the template to edits for a use that never happened. assert.equal(log.updated[0]?.table, 'motion_templates'); // And the count is incremented by the database, not by JS arithmetic on the // row that was read a moment ago. Two people instantiating one template // under READ COMMITTED both read 2 and both write 3, so a use is lost — and // `usage_count` is the only thing holding §7a shut. Asserting the rendered // SQL is what makes the difference between the two visible at all: the // wrong version writes the literal 3 and passes every behavioural test. const increment = log.updated[0]?.values.usageCount; assert.ok( isSQLWrapper(increment), 'usage_count must be written as an expression, never as a number computed in JS', ); assert.match(new PgDialect().sqlToQuery(increment as SQL).sql, /"usage_count" \+ \$?1/); assert.equal(log.inserted[0]?.table, 'engagement_artifacts'); assert.equal(log.inserted[0]?.row.templateId, TEMPLATE_ID); // The body is copied, not referenced — editing the artifact must not reach // back into the library. assert.equal(log.inserted[0]?.row.body, template().body); }); }); describe('one engagement per deal', () => { it('answers 409 with the id of the engagement that already exists', async () => { const { db, log } = database([[deal], [engagement]]); await assert.rejects( executeMutation( db, member, async () => ({ demandDealId: DEAL_ID }), motionEngagementCreateDefinition(), ), (error: unknown) => error instanceof MutationError && error.code === 'engagement_exists' && error.status === 409 && error.message.includes(ENGAGEMENT_ID), ); assert.deepEqual(log.inserted, []); }); }); describe('qualification scores', () => { it('computes the score from the dimensions rather than believing the body', async () => { const { db, log } = database([[{ engagement, deal }]]); const dimensions = [ { id: 'budget', weight: 30, score: 4 }, { id: 'urgency', weight: 20, score: 2 }, { id: 'fit', weight: 50, score: 3 }, ]; await executeMutation( db, member, async () => ({ dimensions }), motionScoreDefinition(), { id: ENGAGEMENT_ID }, ); const written = log.inserted.find((row) => row.table === 'qualification_scores')?.row; assert.equal(written?.basisPoints, motionScoreBasisPoints(dimensions)); assert.equal(written?.band, 'Strategic'); assert.equal(typeof written?.basisPoints, 'number'); assert.ok(Number.isInteger(written?.basisPoints), 'a score is an integer, exactly as money is'); }); it('refuses a posted basisPoints outright — a score somebody can send is a score somebody can fix', async () => { const { db } = database([[{ engagement, deal }]]); await assert.rejects( executeMutation( db, member, async () => ({ dimensions: [{ id: 'fit', weight: 1, score: 1 }], basisPoints: 10_000 }), motionScoreDefinition(), { id: ENGAGEMENT_ID }, ), (error: unknown) => error instanceof MutationError && error.code === 'invalid_request', ); }); }); describe('an id that cannot name a row is a row that does not exist', () => { /* * Measured against a running server before this test existed: every `:id` * route answered `500 {"error":"Internal error"}` for an id like `nope`. * Nothing was wrong with the code that handled a missing row — that branch * was simply never reached, because each id column is a `uuid` and Postgres * refuses the cast with `22P02` several layers below it. The reads therefore * check the shape before they ask, and the writes do it in `requiredId`. * * 404 rather than 400 is the load-bearing half. A 400 for a malformed id and * a 404 for a well-formed one tells anyone probing which of their guesses * are the right shape, and this feature already routes "somebody else's * private draft" through the same 404 precisely so that no answer here * distinguishes between the reasons a row is not yours to see. */ const viewer = { userId: OWNER, isPlatformAdmin: false }; it('answers null for a malformed template id without going to the database at all', async () => { const { db, log } = database([]); assert.equal(await new MotionService(db).template(viewer, 'nope'), null); assert.deepEqual(log.events, [], 'a malformed id must not reach Postgres to be refused'); }); it('answers null for a malformed engagement id, likewise', async () => { const { db, log } = database([]); assert.equal(await new MotionService(db).engagement(viewer, 'nope'), null); assert.deepEqual(log.events, []); }); it('still reads a well-formed id — the guard is a shape check, not a rejection of unknown ids', async () => { const { db, log } = database([[]]); assert.equal(await new MotionService(db).template(viewer, ENGAGEMENT_ID), null); assert.deepEqual(log.events, ['select'], 'a well-formed id is answered by the database'); }); it('refuses a malformed id on a write as not_found, the same answer an unknown one gets', async () => { const { db, log } = database([]); // A lead, so the write gets past the capability check and reaches the id: // authorization deliberately precedes it, and a member would be refused // here for the other reason entirely. await assert.rejects( executeMutation( db, lead, async () => ({}), motionTemplatePublishDefinition(), { id: 'nope' }, ), (error: unknown) => error instanceof MutationError && error.code === 'not_found', ); // The transaction opens first — `executeMutation` owns that — but nothing // is ever asked of it, which is the property that matters: no statement // carrying `nope` was sent to Postgres to be refused there. assert.deepEqual(log.events, ['transaction'], 'refused on shape, without a query'); }); });