Capability rules
The seven rules that run only when a port is bound — resource kinds for access control, commands and relay modes against the manifest, recovery vocabulary and readiness, the portal button, native provider keys, the migrator's reports.
Each rule here runs when the registry says the connector binds the port it checks ($registry->binds($key, Port::class)), so a connector without the capability never sees the rule.
access.declares_kinds
Runs when AccessController is bound. Checks the manifest lists at least one resource kind.
Fails with access_control is declared but the manifest gates no resource kind.
Why access control grants access to a kind of place; with no kind declared there is nothing a creator can link and the port can never be called.
Fix declare the kinds in resource_kinds, or drop the capability.
management.commands_match_manifest
Runs when ManagementSurface is bound. Checks the sorted list commands() returns equals the manifest's sorted management_commands.
Fails with renders [broadcast, plan_manage], manifest declares [plan_manage, project_settings].
Why the marketplace and the Connectors tab show the coverage from the manifest; the class must render exactly that.
Fix make the two lists agree; the manifest is the declaration, the class the implementation.
relay.modes_match_manifest
Runs when SupportRelay is bound. Checks the sorted list relayModes() returns equals the manifest's sorted relay_modes.
Fails with offers [owner_dm], manifest declares [forum_group, owner_dm].
Why the support settings offer what the manifest says and the port must honour each.
Fix make the two lists agree, and declare only modes the core can store (relay_modes).
recovery.vocabulary_and_readiness
Runs when RecoverySupport is bound. Checks the six nouns of vocabulary() (installationNoun, spaceNoun, identityNoun, grantNoun, installationsNoun, spacesNoun) are non-empty, and readinessChecks() for a synthetic project-scope installation and project returns ReadinessItems with unique keys.
Fails with recovery: vocabulary grantNoun is empty, readiness key "standby" is declared twice.
Why every recovery page and notice describes the connector's world in these nouns, and the readiness checklist keys its lines by key.
Fix name every noun, key every item once. The synthetic refs carry zero UUIDs, so readinessChecks() must cope with a project the core has no coverage for (it will answer an empty coverage).
portal_login.button
Runs when PortalLoginMethod is bound. Checks button() has a non-empty label and icon.
Fails with portal login: the button has no icon.
Why the portal's sign-in sheet renders the button from these two strings.
Fix both strings; the icon is a key from the connector icon set, usually your own.
payments.provider_keys
Runs when ProvidesPaymentMethods is bound. Checks every entry of paymentProviders() is a NativePaymentProvider keyed <key>:[a-z][a-z0-9_-]* with this connector's key, with a non-empty label(), settling in at least one currency.
Fails with payment providers: "stars" is not keyed telegram:provider, "telegram:stars" settles in no currency.
Why the key is stored on every payment method and payment row that uses the provider, and must name the connector that owns it.
Fix PaymentProviderKey::native($key, $provider) as the key's string form, a label, at least one currency code. The registry has already refused the capability for a non-official connector.
Passing is not doing
These rules prove the shapes, not the behaviour: a RecoverySupport whose failOver() throws UnsupportedByConnector passes recovery.vocabulary_and_readiness with a manifest that promises resource_standby. Review holds a declared capability to what the platform can actually do.
How is this guide?
Inbound, identity and slots
The three rules that hand the connector something empty and expect it to cope — an empty JSON request, an envelope with nothing in it, and a well-formed slot list.
Migration rules
The one rule that reads a package's migrations — every table created carries the connector's prefix and no core table is touched — and exactly how the sources are scanned.