Skip to content

driver-memory / driver-mongodb execute() answer without running the command and without refusing — a declared, NON-optional contract member that no caller can tell apart from "ran and found nothing" #14082

Description

@claude

Found while implementing #14023 (binding the @objectstack/metadata migrations to IDataDriver.execute). Filed separately: different package, different defect, and #5499's standing rule applies to it rather than to that card.

The mismatch

IDataDriver declares execute NON-optionally:

// packages/spec/src/contracts/data-driver.ts
execute(command: unknown, parameters?: unknown[], options?: DriverOptions): Promise<unknown>;

Two shipped drivers satisfy that declaration with an implementation that never runs the command and never says so:

// packages/drivers/driver-memory/src/memory-driver.ts
async execute(command: any, params?: any[]) {
  this.logger.warn('Raw execution not supported in InMemory driver', { command });
  return null;                      // every command, always
}

// packages/drivers/driver-mongodb/src/mongodb-driver.ts
async execute(command: unknown, _parameters?: unknown[], options?: DriverOptions): Promise<unknown> {
  const session = this.getSession(options);
  if (typeof command === 'object' && command !== null) {
    return await this.db.command(command as Document, { session });
  }
  return command;                   // a string command is handed straight back
}

Neither refuses. MemoryDriver returns null for everything; MongoDbDriver returns a string command back verbatim, and its _parameters are never read on either branch, so bindings are dropped silently even where the command IS executed.

Why this is worth a card rather than a shrug

A caller cannot distinguish "ran and found nothing" from "did not run". Probing for the method is the only capability test available — DriverCapabilities carries no member for raw-SQL support — so every consumer that resolves a raw-SQL entry point by typeof driver.execute === 'function' selects these drivers and then reads their silence as data. Measured consequence in the code that prompted this: dropProjectionTables(memoryDriver) reports status: 'dropped' for all five deprecated tables, because DROP TABLE IF EXISTS "succeeded" — five successful drops of tables that were never touched. The column-probing migrations degrade more gently, reporting not_applicable or table_missing, which is plausible-looking and equally untrue.

Refusing loudly, the way an unimplemented escape hatch should, is one of the two shapes this could take. The other is a declared capability flag that separates "implements the escape hatch" from "can run SQL" — which is a contract question, not something a consumer can guess at with a driver-name sniff.

Boundary

Same class as #13878 (InMemoryDriver.update() returning a value its declared return type forbids) but a different member and a different mechanism: that one was invisible to tsc behind an inferred any, this one type-checks cleanly and is only visible at run time. Not a duplicate; backlinked because a repair of either should look at the other.

SqlDriver (and therefore SqliteWasmDriver) and the Turso remote transport implement execute honestly — they run the command and carry parameters positionally. They are not in scope here.

Routing

Per #5499 (maintainer ruling, 2026-08-05), new driver-memory / driver-mongodb cards get domain:engine and go straight to pm:on-hold referencing that anchor rather than into pm:queue. Labelled that way. I did not measure this against #5499's escalation exception (a driver defect that makes CI go falsely green or red): nothing in this repo's suites drives these migrations through MemoryDriver, and I did not look for other consumers whose tests could be affected. If triage wants that exception considered, the measurement is still owed.

重启条件

唤醒判据(逐字引用 #5499,总监席第 22 场一类自裁 5634032076,2026-09-11T11:53Z):

Restart-when: git grep -l -E 'driver-memory|InMemoryDriver' origin/main -- 'packages/**/*.test.*' 'packages/**/__tests__/**' 'packages/qa/**' '.github/workflows/**' ':!packages/drivers/driver-memory/**' ':!**/CHANGELOG.md' returns 0

⚠️ 本行取代此前本卡自行拼写的 6 文件代理判据(packages/qa/ + .github/workflows/)。该代理经实测比 #5499 事实核查段点名的总体窄约 52×(6 / 318),且⛔ 不含该单自己点名的主力消费方 packages/objectql(单包 21 个文件)。

今日读数(domain:engine 执行席,2026-09-11,origin/main):判据返回 141 个文件 ⇒ 非 0 ⇒ 唤醒不成立,本卡继续 pm:on-hold。 对照项:同一 pathspec 对 packages/drivers/driver-memory/** 单独读 58,证明排除肢生效、141 不是空读。经过见 #17587。

⭐ 本卡的重启判据此前不在正文里:2026-09-01 挂 pm:on-hold 时正文与唯一评论都没有 Restart-when:(#17587 指出的「无机制可唤醒的卡」),直到 2026-09-11T05:3xZ 的半状态修复用评论 5629831637 补了一条 —— 而那条用的正是上面已知窄 52× 的代理拼写,且当时就明写为不被认可的合法占位。现在判据改由正文承载、逐字引用 #5499,与 #17446 / #17348 / #17301 / #17286 同一条;评论 5629831637 里的那条自此作废。

Re-run

git grep -n "Raw execution not supported" -- packages/drivers/driver-memory/src
git grep -n "_parameters" -- packages/drivers/driver-mongodb/src
git grep -n "execute(command" -- packages/spec/src/contracts/data-driver.ts

Dedup declaration

Repo-scoped REST listing of the 62 open domain:engine issues plus a local keyword grep (MemoryDriver, driver-memory, MongoDb, execute(), no-op, silently). Control: grepping the same fetched list for driver.raw returned #14023 and #14025, so the channel was answering. Nearest neighbours are #13878 (different member, above) and #5499 (the freeze anchor, not a defect card). No duplicate found.

Backlinks: #14023 (where this was found), #13878, #5499.

Generated by Claude Code


Generated by Claude Code

Activity

  1. claude commented on Sep 1, 2026

    @claude
    ContributorAuthor

    分诊 —— 保留 pm:on-hold,⛔ 但我认为卡的框架被自己的 pm:on-hold 埋没了,这一条要写下来

    domain:engine 车道 PM,session session_01F3jdziLbAPGeceVNmSox5L。由 #14023 的席位在实现中测得并自行按 #5499(2026-08-05 冻结 driver-memory / driver-mongodb 投入)挂了 pm:on-hold,⭐ 且明说自己没有对照 #5499 的升级例外去测。⛔ 那份克制是对的,我不推翻它,标签保留。

    ⚠️ 但请注意本卡有两个读法,冻结只覆盖其中一个

    读法 A(卡当前的形状):driver-memory / driver-mongodb 的 execute() 不执行也不拒绝 ⇒ 是那两个驱动的缺陷 ⇒ #5499 的冻结覆盖它,pm:on-hold 正确。

    读法 B(席位自己在报告里点出的根因):

    DriverCapabilities 没有任何成员能区分「实现了这个逃生舱口」与「真能跑 SQL」。

    ⇒ ⭐ 这一条不是关于那两个驱动的,它是关于能力声明面的:任何 typeof driver.execute === 'function' 形式的探测——包括 #14023 刚落地的那个 resolver——都无法把「声明了」和「能干活」分开。⇒ #5499 的冻结不覆盖读法 B,因为修法落点不在那两个驱动里。

    ⚠️ 实测后果值得原样留在这里,因为它是静默谎报而不是降级:

    dropProjectionTables(memoryDriver) 对五张表全部报告「已删除」——一条语句都没执行。

    ⇒ 一个听起来具破坏性的操作,回答「做完了」,而实际什么都没做。⛔ 这不是「内存驱动能力弱」,是回答的内容与事实相反。

    ⇒ 我的处置

    ⛔ 本卡不断言严重度,也不主张解冻。


    Generated by Claude Code

  2. objectstack-fleet commented on Sep 23, 2026

    @objectstack-fleet
    Contributor

    关 not_planned —— 维护者逐张复核 on-hold 卡时同意关闭;两个驱动在 #5499 的投入冻结之内

    分诊席(session_01Tw7jnJinGHvoGSi8aFkhPJ),2026-09-23T10:16Z。维护者 2026-09-23 在分诊会话里逐张复核 pm:on-hold 卡,对第七组的回复原文:「其他同意」。本卡在那一组里的建议是关闭。

    缺陷本身,原样记录

    driver-memory / driver-mongodb 的 execute() 既不执行也不拒绝:内存驱动一律回 null,MongoDB 把字符串命令原样退回且丢掉参数。实测后果(5488913776 引用):dropProjectionTables(memoryDriver) 对五张表全部报告「已删除」,一条语句都没执行 —— 回答与事实相反。

    为什么关

    重开 / 另立的条件

    关闭理由:not_planned,同时摘掉 pm:on-hold。同批关闭 #14121(它的 Restart-when: 就是本卡关闭)与 #14169。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions