Skip to content

Fix plugin tests: add missing drivers field to mock contexts - #133

Closed
hotlong with Copilot wants to merge 2 commits into
copilot/release-new-version-please-workfrom
copilot/update-action-run-job
Closed

hotlong with Copilot wants to merge 2 commits into
copilot/release-new-version-please-workfrom
copilot/update-action-run-job

Conversation

Copilot AI commented Jan 25, 2026

Copy link
Copy Markdown
Contributor

PluginContextSchema added a required drivers field but test mocks were not updated, causing 6 test failures in plugin.test.ts.

Changes

  • Added drivers: { register: () => {} } to all 7 mock PluginContext objects in test file

The schema change in plugin.zod.ts (lines 136-148):

export const PluginContextSchema = z.object({
  // ... existing fields
  drivers: z.object({
    register: z.function()
        .args(z.any()) 
        .describe('Register a new driver instance'),
  }).describe('Driver Management'),
});

Test mocks now include the required field:

const context: PluginContextData = {
  ql: { /* ... */ },
  os: { /* ... */ },
  // ... other fields
  drivers: {
    register: () => {}
  }
};
Original prompt

引用: https://github.com/objectstack-ai/spec/actions/runs/21325390632/job/61381937508#step:8:1


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@vercel

vercel Bot commented Jan 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
spec Ready Ready Preview, Comment Jan 25, 2026 2:38am

Request Review

All plugin tests now pass. Added the required 'drivers' field with a 'register' function to all mock PluginContext objects in the test file to match the updated PluginContextSchema.

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Update action run job configuration Fix plugin tests: add missing drivers field to mock contexts Jan 25, 2026
Copilot AI requested a review from hotlong January 25, 2026 02:38
@hotlong hotlong closed this Jan 25, 2026
This was referenced Sep 14, 2026
github-merge-queue Bot pushed a commit that referenced this pull request Sep 16, 2026
… reason) beside FILTER_TEXT_CASES (#18438)

Fixes #18113

`@objectstack/spec/data` now publishes the case-insensitive-contains
**text-comparand door** — the predicate for the two REJECTION rows
`FILTER_TEXT_CASES` has declared since #5701, and the reason text they
are refused with — so every face reads one implementation instead of
writing its own copy of both halves. Executes objectui#9048 batch #133
item 1, ruling **D**.

## What landed

| path | what |
|---|---|
| `packages/spec/src/data/filter-text-comparand.ts` | new —
`isRefusedTextComparand`, `textComparandRefusalReason`, and the
module-internal `describeComparand` |
| `packages/spec/src/data/index.ts` | re-export (the entry-reachability
hop the ruling names) |
| `packages/spec/src/data/filter-text-comparand.test.ts` | new — both
acceptance pins, driven from the table |
| `packages/spec/api-surface/data.json`,
`packages/spec/export-origins/data.json` | regenerated: **2 added, 0
removed** |
| `.changeset/18113-icontains-text-comparand-refusal.md` | `minor` on
`@objectstack/spec` |

Measured file face: **6 paths**, all under `packages/spec` plus the
changeset — disjoint from the sibling cards named at dispatch.

## The port is byte-exact, and that is measured rather than asserted

The reference is objectui `packages/core/src/utils/text-comparand.ts` at
objectui `origin/main` @ `55f39ee9`. That blob is
`c29782139426fc1af51dac86f0a4b8d0b5d2827e` at `55f39ee9`, at objectui
`HEAD` (`ff1d5ea8`) and in the read-only checkout — one file, not three
readings.

- **Source text**: the three function bodies extracted from both files
and compared — `describeComparand` 159 bytes, `isRefusedTextComparand`
115, `textComparandRefusalReason` 928, **all three identical** (only the
`export` modifier normalised, which is the publication decision, not the
behaviour).
- **Behaviour**: both implementations driven over 17 comparand shapes x
2 arriving spellings x 2 field names — **85 readings, 0 mismatches**,
including the two shapes `describeComparand` exists for (a BigInt and a
cyclic object, on which `JSON.stringify` throws).

Both are one-off scripts, not committed test files.

## The acceptance pins

`pnpm --filter @objectstack/spec exec vitest run
src/data/filter-text-comparand.test.ts` — **46 passed**.

1. **Every** `FILTER_TEXT_CASES` case is driven through
`isRefusedTextComparand` (24 cases, one `it` each), plus a whole-table
set assertion that its TRUE set equals the rows the table declares
refused for this operator, plus every `FILTER_TEXT_ROWS` stored `name`.
2. The reason for `''` and for a non-string comparand carries each row's
`mustMention` tokens, **per arriving spelling**, plus a transcription
pin on the exact bytes — `mustMention` only requires `$icontains`, so it
cannot catch a reword, and a reword is what the fence forbids.

**Ablation** (mutate, prove it hit disk, run, restore, prove the restore
— both legs restored with `git hash-object` matching the HEAD blob and
`git diff HEAD` empty):

| leg | on-disk proof | result |
|---|---|---|
| reword one word of the reason | removed-text count 1 to 0, injected 1
| **1 failed** / 45 passed, exit 1 |
| drop the `=== ''` arm from the predicate | removed-text count 1 to 0,
injected 1 | **2 failed** / 44 passed, exit 1 |

## Two readings the card asked for

**⚠️ The second acceptance clause is falsified for one spelling, and the
fence outranks it.** The card asks that the reason contain each case's
`mustMention` tokens "for BOTH arriving spellings". `mustMention` is
`['$icontains']`; for an arriving `icontains` the reason names what
arrived and therefore does **not** contain the `$`-dialect token.
Rewording it to would break the byte-for-byte fence and diverge from two
shipped faces. This is also what objectui#9152 already does about it —
it names the `$` twin in its own tail, with a comment saying why the
substitution would misdirect a view author. So the pin asserts the
measured truth in both directions: the token for the `$` spelling, the
token minus its sigil for the infix one, and `not.toContain` on the `$`
form there. Flagged for the seat rather than settled by me.

**The fold measurement — measured, not folded.** The note names
`@objectstack/formula` and the engine. Neither is a literal copy of this
predicate:

- `packages/formula/src/matches-filter.ts:249` fuses the De Morgan
complement into its positive arm (`typeof v === 'string' && v !== ''`)
and **answers `false`** rather than refusing — its docblock says the
totality is deliberate.
- `packages/objectql/src/having-filter.ts:388` **refuses**, so it is not
one of the faces that answer 0 of 9 rows.

So: report the reading and leave it. What the sweep did turn up is in
the acceptance notes below.

## Verification

- `pnpm --filter @objectstack/spec test` — **483 files, 13734 tests, all
passed**.
- `pnpm --filter @objectstack/spec typecheck` — exit 0. Coverage proven
rather than assumed: the main `tsconfig.json` excludes `**/*.test.ts`,
and `--listFiles` on `tsconfig.test.json` (what `check:test-typecheck`
runs) shows **both** new files in the program.
- `pnpm --filter @objectstack/spec check:generated` — proved exactly
`api-surface/` and `export-origins/` stale, `--fix` regenerated only
those two. The gate's own diff line is the published-face evidence: `+
isRefusedTextComparand (function)`, `+ textComparandRefusalReason
(function)` on `./data`, nothing else, and no `describeComparand`.
- **Derived gate families**: `scripts/pm/dispatch-gates.mjs` derived
**85** from the change set; **83 run, 2 NOT MEASURED, 0 unrun**,
reconciled through `--ran` with a recorded exit code per family.
- **Lint, narrowed and declared** (at `812a5bf565`): eslint's own config
lints `**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}` repo-wide; `--format json`
reports **3 files linted, 0 errors, 0 warnings**; and type-aware linting
is **not** enabled for these files (`parserOptions.project`,
`projectService` and `EXPERIMENTAL_useProjectService` all null under
`--print-config`), so this diff cannot move the verdict on any file it
does not touch. The repo-wide sweep is CI's.
- **Changeset publishes** — measured, with both controls.
`@objectstack/spec` is public at `17.4.0` and its `files[]` is `dist`,
`json-schema`, `liveness`, `prompts`, `llms.txt`, `README.md`,
`src/**/*.zod.ts`, `CHANGELOG.md`, `api-surface`, `spec-changes.json`.
**Positive control**: `isRefusedTextComparand` appears in **6** shipped
files under `dist/`, `dist/data/index.js` / `.mjs` / `.d.mts` and the
browser build among them. **Negative control**: `ARRIVING_SPELLINGS`,
which exists only in the new test file (2 occurrences in `src/`),
appears in **0** shipped files — so the grep discriminates and the test
layer does not ship. Note `src/**/*.zod.ts` IS published, but the new
module is not a `.zod.ts`, so it reaches consumers only as built output.
A published symbol moved, so this is `minor` — ⛔ not `skip-changeset`.

**NOT MEASURED (2 of 85), both `exit 3 PREREQUISITE NOT MET`** —
`check:dual-build-cjs-loads` and `check:type-check-debt` both refuse
until the repo-wide build exists, and 54 of 69 buildable packages have
no `dist/` in this worktree. A repo-wide build is CI's run (`Build
Core`, `TypeScript Type Check`), not this card's; declaring the
narrowing rather than reporting a green.

## Acceptance notes

**A gate whose verdict depends on whether you built —
`check:cross-package-test-inputs`, measured red here and green on
`main`.** It names
`packages/cli/test/init-created-files-summary.e2e.test.ts` descending
into `packages/spec/dist/`; it names none of my files. Ablated to be
sure: same tree, same sources, `dist/` parked aside then restored —
**exit 1 with `packages/spec/dist/` present, exit 0 without it** (115
entries, restored). A pristine `origin/main` worktree also exits 0,
because nothing there is built. So the finding is real and CI is
structurally blind to it: the lint job does not build spec, and
following AGENTS.md's mandatory "regenerate spec artifacts before
pushing" is exactly what makes it visible. Filed as a finding for the
seat, not fixed here.

**Five faces carry the same discrimination inline, and none is in the
note's named set.** `driver-sql:4047`, `driver-mongodb:296`,
`driver-memory/filter-refusal.ts:911`, `objectql/having-filter.ts:388`
and `driver-turso/remote-transport.ts:2989` each spell `typeof X !==
'string' || X === ''` and each throws its own `icontainsComparandError`.
Folding them is a five-package diff with a message-text question inside
it, well outside this card's measured face and outside what the note
authorises. Noted, not filed; the natural carrier is whichever card next
consolidates that refusal family.

**`Clause-②: yes`** — two new exported symbols on a published entry. The
carrier is the seat's on both the card and this PR; not hung, not
stripped, not waited on here.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01KB5PFtxuy1x3dcR5gxudx6)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants