Skip to content

fix(plugins): restore injectRowLimit requirement to fix registry plugin loading (#1917)#1924

Merged
datlechin merged 1 commit into
mainfrom
fix/1917-injectrowlimit-abi-restore
Jul 21, 2026
Merged

fix(plugins): restore injectRowLimit requirement to fix registry plugin loading (#1917)#1924
datlechin merged 1 commit into
mainfrom
fix/1917-injectrowlimit-abi-restore

Conversation

@datlechin

Copy link
Copy Markdown
Member

Problem

Installing the MongoDB Driver on 0.58 fails with "Invalid plugin bundle: Bundle failed to load executable" (#1917). It is not MongoDB-specific: the same failure hits Oracle, Cassandra, and Elasticsearch.

Root cause

PR #1891 (the #1884 row-cap rework that replaced SQLLimitInjector with SQLLimitDetector) removed injectRowLimit(_:limit:) from the PluginDatabaseDriver protocol and its default implementation, with currentPluginKitVersion left at 18. That deleted two public symbols from TableProPluginKit:

  • the requirement's method descriptor
  • the protocol extension's { nil } default implementation

Every already-published registry plugin that relied on the default (did not implement injectRowLimit itself) hard-references both symbols in its PluginDatabaseDriver witness table. On 0.58 dyld cannot resolve them, so bundle.load() fails. The version gate did not catch it because the plugin still declared kit 18, which is exactly what the app requires, so it reached bundle.load().

Library Evolution fills in requirements added after a plugin was built, but it cannot rescue a requirement removed out from under an already-built plugin.

Scope, verified against the shipped release binaries

Symbol-diffing the live registry binaries (arm64, kit 18) against the 0.57.1 and 0.58.0 framework exports:

Plugin Result
MongoDB, Oracle, Cassandra, Elasticsearch broken (each imports exactly the two removed symbols)
DuckDB, MSSQL fine (they ship their own injectRowLimit)

Fix

Restore injectRowLimit(_:limit:) to PluginDatabaseDriver as a requirement with a { nil } default. This regenerates the identical mangled symbols, so all four plugins load again on the next app build. No version bump and no plugin re-release: keeping kit at 18 is required so the existing kit-18 registry binaries stay eligible.

The app no longer calls injectRowLimit (that path went away in #1884). It is restored as an ABI contract point consumed by external plugin binaries, not wired back into the app.

Also:

  • CLAUDE.md: removed the wrong rule that called "removing a requirement that defaulted to nil" additive, and documented that removing any published requirement is breaking.
  • Added a regression assertion in PluginKitABIResilienceTests; if the requirement is removed again the test target stops compiling.

Verification

  • Offline swiftc harness: a minimal library-evolution TableProPluginKit module built from the restored declarations emits both symbols the shipped plugins import (2/2 match).
  • swiftlint lint --strict: 0 violations.

Delivery

This ships in the app framework, so recovery needs a new app build (a 0.58.1 patch). After users update, all four plugins install cleanly with no registry changes.

@datlechin
datlechin merged commit bbe8219 into main Jul 21, 2026
3 checks passed
@datlechin
datlechin deleted the fix/1917-injectrowlimit-abi-restore branch July 21, 2026 05:15

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 077a7646ff

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CLAUDE.md
**Additive changes are binary-compatible and need NO version bump**: adding a requirement to `DriverPlugin` / `PluginDatabaseDriver` that has a default implementation, reordering requirements, adding a field to a non-`@frozen` transfer struct, or removing a requirement that defaulted to `nil`.
**Additive changes are binary-compatible and need NO version bump**: adding a requirement to `DriverPlugin` / `PluginDatabaseDriver` that has a default implementation, reordering requirements, or adding a field to a non-`@frozen` transfer struct.

**Never remove a published protocol requirement, even one that defaulted to `nil`.** Library Evolution fills in requirements *added* after a plugin was built, but it cannot rescue a requirement *removed* out from under an already-built plugin. Removing one deletes both its method descriptor and its default-implementation symbol, and every shipped plugin that relied on the default hard-references both in its witness table, so it fails to load with "Bundle failed to load executable". If the app stops using a requirement, leave it in place with its default (it costs nothing). Removing it is a breaking change: bump `currentPluginKitVersion` and re-release every plugin. (#1917, and it broke MongoDB, Oracle, Cassandra, and Elasticsearch on 0.58.)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the published ABI guidance consistent

Update docs/development/plugin-development.mdx:81-82 as part of this correction. It still tells plugin authors that removing a defaulted requirement is additive and needs no version bump, which is the exact rule this change identifies as causing registry plugins to fail to load; following that documentation can recreate this production regression.

Useful? React with 👍 / 👎.

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.

1 participant