[Architecture] Plugin boundary is leaky: clinical_compliance hard-coded into core/config/CLI/TUI, two strategy registries
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 25/100
- Issue type
- Refactor
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- python
- Domain
- backend, cli, developer-experience
Research direction
Start by reading app/core/plugin_registry.py, app/core/analyzer_strategies.py, and the plugin wiring called out in app/core/session.py, app/config.py, app/main.py, and app/ui/tui.py. Map the registry calls and settings flow, then define the plugin API and migrate the built in plugin and CLI/TUI contributions. Done means the acceptance criteria pass, including a sample external plugin and running without clinical_compliance.
Written by the indexing model from the issue text.
Description
Problem
app/core/plugin_registry.py presents a generic register_plugin(registry) extension model, but the one plugin, app/plugins/clinical_compliance, is wired into every layer by name.
Core
PluginRegistry.get_clustering_strategyauto-loadsclinical_compliancefor any name starting with"clinical"(plugin_registry.py:113-114).load_plugins_from_settingsloads it when the strategy is clinical orCLINICAL_SMART_RENAMINGis set, and then always loads it anyway (plugin_registry.py:219-225).AppSessionspecial-cases("clinical_tmf", "clinical_isf")and setssmart_renaming/generate_audit_reporton the strategy object (session.py:249-260).
Config: CLINICAL_SMART_RENAMING and CLINICAL_GENERATE_AUDIT_REPORT are first-class core settings (config.py:196-197).
CLI: the --strategy choices are hard-coded to ["default", "generative", "clinical_tmf", "clinical_isf"] (main.py:1428), so a third-party sortify_plugin_* strategy can't be selected from the CLI.
TUI: reads #switch-clinical-renaming (tui.py:2203) and imports CROForensicModal via a module __getattr__ (tui.py:8480-8486). Meanwhile the plugin imports A11yMixin from app.ui.tui (tui_views.py:15).
Two registries for the same thing: PluginRegistry._clustering_strategies and the module-global clustering_registry in analyzer_strategies.py:3330-3363. Each one calls into the other (plugin_registry.py:97-107, analyzer_strategies.py:3350-3358).
Untyped contract
ClusteringStrategyis aProtocolwith a 9-positional-arggenerate_plan(analyzer_strategies.py:667-683).- Plugins get configured by mutating ad-hoc attributes (
smart_renaming), and hooks are bare callables with positional args (trigger_quarantine_scan(orig_rel_path, extracted_text, base_dir), plugin_registry.py:84).
Impact
- Adding or removing a plugin means editing core, config, CLI and TUI.
- The clinical plugin is effectively mandatory: it's always loaded, which costs startup time.
- External plugins (
sortify_plugin_*is an allowed prefix, plugin_registry.py:11) can't get parity.
Proposed approach
- Define a versioned plugin API in
app/core/plugin_api.pywith:PluginManifest(name, version, strategies, settings schema fragment, CLI choices, TUI contributions)- a typed
StrategyContext/PlanRequestdataclass instead of the 9 positional args - typed hook signatures.
- Plugins contribute their own settings, namespaced under
PLUGIN_SETTINGS["clinical_compliance"]or validated by a fragment the plugin supplies. RemoveCLINICAL_*from coreSettings. - Build CLI
--strategychoices and TUI strategy options and switches from the registry. Remove the name-prefix auto-load and the unconditional load. Load plugins only fromsettings.PLUGINS(and entry points, if desired). - Merge
clustering_registryintoPluginRegistry(or the reverse), so there's one registry with built-ins registered at startup. - Plugins depend only on
app.core.plugin_apiandapp.ui.a11y/widgets, never onapp.ui.tui.
Acceptance criteria
grep -rn "clinical" app/core app/ui app/main.py app/config.pyreturns no plugin-specific references, excluding docs-onlydiagram_schema.- Removing
app/plugins/clinical_complianceleaves the app runnable, with all non-plugin tests passing. - A sample external test plugin registers a strategy that appears in
--strategychoices and the TUI.
- Dominant language
- Python
- Stars
- 1
- Forks
- 0
- Avg merge
- 9h 3m
- Merged PRs (30d)
- 361
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- No contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from fderuiter/sortify
-
bug ready-for-agent
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
security
Difficulty 2/5 1-3 hours Newbie friendliness 57/100
Maintainers usually reply within 1 day
-
architecture enhancement ready-for-agent
Difficulty 5/5 Over a week Newbie friendliness 35/100
fderuiter/sortify#783 · 1 comment ·
Maintainers usually reply within 1 day
-
enhancement ready-for-human
Difficulty 4/5 3-5 days Newbie friendliness 48/100
fderuiter/sortify#740 · 1 comment ·
Maintainers usually reply within 1 day
-
architecture enhancement ready-for-human
Difficulty 5/5 Over a week Newbie friendliness 25/100
fderuiter/sortify#726 · 1 comment ·
Maintainers usually reply within 1 day
All issues in fderuiter/sortify
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 67/100
MISP/misp-workbench#496 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
Maintainers usually reply within 1 day
-
Difficulty 1/5 1-3 hours Newbie friendliness 88/100
fossasia/visdom-dev#69 ·
Maintainers usually reply within 3 days
-
[Bug] Parameters named like a property break to_xcal()Possibly taken @atharvasalunke1267 claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
collective/icalendar#2018 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day