mirror of
https://github.com/LorenEteval/Furious.git
synced 2026-10-09 15:19:56 +03:00
6.9 KiB
6.9 KiB
Plugin guidance
Inherit the nearest parent guide. This scope owns capabilities, registry publication, dispatch
and plugin lifecycle. Index rollback does not release partial resources owned by factories or plugins. Read
Furious/Plugins/Registry.py with tests/test_plugin_architecture.py; paths are relative to this source
tree's root.
Contracts and registry
Plugins.APIdefines independently composable capabilities for protocols/editors, subscription decoding, runtime factories, routing/TUN/probes, statistics, settings, actions, and navigation. Extend the owning capability instead of adding backend-name branches or a parallel registry.- The registry normalizes and validates a plugin's complete contribution before changing indexes. Initialization runs with the contribution indexed; if it fails, shutdown is attempted and those indexes are removed. This is rollback of registry publication, not a transaction over arbitrary plugin side effects. Plugins must clean their own partial acquisitions even when initialization fails. Duplicate IDs/schemes and invalid versions/descriptors must leave existing providers intact.
- Host plugin types register before external entry-point discovery. Bundled registrations are explicit for source, wheel, and Nuitka inclusion. External entries currently follow metadata enumeration order; do not promise sorted discovery or rely on it for precedence. Registration is atomic per plugin, not across a multi-plugin entry point. Discovery order is not a provider priority contract; operation-specific priority and explicit provider selection belong to dispatch.
- Failure policy belongs to the dispatch operation. Automatic subscription detection tries decoders by priority; an explicitly selected decoder restricts candidates. URI dispatch selects the registered scheme owner rather than probing unrelated handlers after failure. Keep required-operation failures observable without secret payloads. Plugin/capability IDs and type ownership define dispatch; display names and translated labels do not. A presentation rename must not change registration identity or silently migrate a saved provider choice.
Ownership and compatibility
- Registries own plugin/capability instances and descriptors; created editors and runtimes transfer to their callers. Capabilities may retain explicitly owned reusable services with shutdown obligations. Do not cache created transient UI in the registry or treat the registry as the connection/repository authority.
- Separate factory construction, registry result validation, and execution start. A factory owns partial resources until it returns a valid launch; the caller cannot recover an object hidden by construction failure or an invalid result shape. After valid transfer the caller owns that exact runtime even if start raises. Keep failure evidence for all three boundaries when changing factory contracts; returning no runtime after acquisition loses cleanup authority. Current result validation raises on a wrong launch/runtime type without a generic disposal protocol for that invalid value. Do not describe shape rejection alone as resource rollback; test a resource-bearing invalid result if changing this boundary.
- Plugin/model data is untrusted at the boundary even though installed code is trusted to execute. Validate types, ownership, required fields, and QObject validity before publishing results.
- API and model layers never import concrete plugins. Bundled backends/extensions obey the public lifecycle; their existing host-global integrations must not become prerequisites for external plugins.
- Evolve contracts additively when practical. Before a breaking change, inspect external discovery, compatibility exports, every bundled implementation, tests, and compiled inclusion; do not infer compatibility from built-ins alone.
- A capability contract is generic only when an external plugin can satisfy it without importing private application state. Backend-specific defaults, settings keys, document branches, and host assumptions stay behind the provider. Capability presence advertises an operation, not a configured target or successful execution; callers must handle absence, unavailable configuration, and operation failure separately (notably statistics, export, and probes).
- API-version-3 runtime factories return
PreparedRuntimedirectly. The runtime is fully prepared before return, starts with zero arguments, raises typed startup failures, and exposes readiness separately. An alternate result shape requires an explicit contract/version migration, not an implicit adapter inferred from built-in factories. The registry's existing synchronousstartCoreRuntime()wrapper separately returns runtime/success for compatibility; preserve ownership on start failure. TUNPreparationErroris the explicit terminal native-TUN failure contract. Other provider exceptions currently log and return an unhandled result; required TUN rejection must use the typed error rather than assume all exceptions stop fallback. Optional capabilities may be absent; an External Core need not implement statistics or download probes. The legacyusesApplicationTun2socks()name declares eligibility for application TUN, not an engine choice. Runtime factories declare native ownership; host settings policy selects the application engine only when needed.- Frozen request/result envelopes are not recursively immutable: embedded configuration/metadata mappings still
require copy isolation before mutation or worker handoff.
createCoreRuntime()dispatches preparation to a factory; it does not protect live configuration from that factory's mutations. Routing normalization chooses a supported option but does not persist it; that decision belongs to the routing controller. - Capability instances default to GUI-thread-only for background subscription preparation. A decoder or protocol
handler opts into worker execution only after its parsing, validation, caches, globals, and Qt usage are audited as
safe for concurrent copied inputs; keep unclassified third-party capability execution on the GUI thread.
Classify the complete decoder-to-protocol path: a worker-safe envelope decoder does not authorize an unsafe
item handler, and automatic detection can consider several providers.
workerSafeauthorizes concurrent execution, not bounded duration or interruptibility. Cancellation can reject a result while the provider still runs; define resource retention and shutdown separately from that opt-in.
Verification
- Cover discovery/order, API version and duplicate rejection, each changed dispatch path, registration rollback,
reverse idempotent shutdown, provider failure isolation, invalid factory results, repeated transient creations
without registry retention, and packaged discovery/import.
tests/test_plugin_architecture.pyandtests/test_public_api.pyanchor compatibility.