fix(plugins): restore injectRowLimit requirement to fix registry plugin loading (#1917)#1924
Conversation
There was a problem hiding this comment.
💡 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".
| **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.) |
There was a problem hiding this comment.
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 👍 / 👎.
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
SQLLimitInjectorwithSQLLimitDetector) removedinjectRowLimit(_:limit:)from thePluginDatabaseDriverprotocol and its default implementation, withcurrentPluginKitVersionleft at 18. That deleted two public symbols from TableProPluginKit:{ nil }default implementationEvery already-published registry plugin that relied on the default (did not implement
injectRowLimititself) hard-references both symbols in itsPluginDatabaseDriverwitness table. On 0.58 dyld cannot resolve them, sobundle.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 reachedbundle.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:
injectRowLimit)Fix
Restore
injectRowLimit(_:limit:)toPluginDatabaseDriveras 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 tonil" additive, and documented that removing any published requirement is breaking.PluginKitABIResilienceTests; if the requirement is removed again the test target stops compiling.Verification
swiftcharness: a minimal library-evolutionTableProPluginKitmodule 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.