Originally created by: fu351
Originally owned by: snowyukitty
Doberman's plugin registry (src/doberman/engine/registry.py) declares 11 entry-point groups — doberman.rules, doberman.detectors, doberman.policy_sources, doberman.auth_providers, doberman.audit_sinks, doberman.drift_observers, doberman.cost_observers, doberman.algebra_adapters, doberman.adjudicators, doberman.egress_brokers, and doberman.async_challenge_backends (lines 38–68) — each with a working interface (a duck-typed protocol/shape check). Ten resolve through a discover_*() function; the eleventh, doberman.async_challenge_backends, resolves through active_async_backend() instead, and the docs page should flag that difference. Only one group, doberman.rules, has a runnable worked example (examples/plugin-guardrail/, with its own installable package + tests/test_example_rule.py::test_entry_point_is_discoverable_after_install), and there is no single doc page enumerating all 11 seams for a contributor deciding where to plug in. Complete the closest sibling seam, doberman.detectors (structurally identical to doberman.rules — both discover Guardrail-shaped objects, per discover_detectors()'s own docstring, lines 166–174): add a second example package mirroring examples/plugin-guardrail/'s shape but registered under doberman.detectors, with its own install-based discoverability test, and add docs/EXTENDING.md documenting all 11 groups (one short paragraph each: what shape is required, how it resolves, and a link to the one worked example).
Completing an extension seam end-to-end: the interface and registry already exist and are proven correct (discover_detectors, tests/unit/test_registry.py), and there's a worked example to mirror — the work is producing a second, real, installable example that proves the pattern generalizes beyond doberman.rules, an install-based test for it (mirroring examples/plugin-guardrail's), and the docs page that ties all 11 seams together for the next contributor.
ExampleRule (examples/plugin-guardrail/src/example_plugin/rules.py) — PASS or AUTH only, never BLOCK from a tutorial plugin, and it must never put a raw path, argument, or payload into its explanation.docs/EXTENDING.md must state the same defensive-loading guarantee registry.py's module docstring already documents (a broken/hostile plugin is logged and skipped, never crashes core, and can only ever add risk via combine()) — do not describe or imply a stronger contract than the code actually provides.testpaths (mirrors [#194]'s constraint) — keep it self-contained under examples/, installed only by its own test/instructions.src/doberman/engine/registry.py — discover_detectors() (line 166), DETECTOR_GROUP (line 39), the full list of 11 groups (lines 38–68) for the docs page.examples/plugin-guardrail/ — the pattern to mirror (pyproject.toml entry-points block, src/example_plugin/rules.py, tests/test_example_rule.py).examples/plugin-detector/ (package name e.g. doberman-example-plugin-detector, entry point under [project.entry-points."doberman.detectors"]).docs/EXTENDING.md.examples/plugin-detector/ is a real, installable package registering an example under doberman.detectors (not doberman.rules).plugin-guardrail's test_entry_point_is_discoverable_after_install.docs/EXTENDING.md documents all 11 entry-point groups from registry.py, each with: required shape, how it resolves (discover_*(), or active_async_backend() for doberman.async_challenge_backends), and a link to the one worked example (rules or detectors).testpaths.ruff check . && ruff format --check . and lint-imports passpytest passespip install -e examples/plugin-detector
pytest examples/plugin-detector/tests -v
pip uninstall -y doberman-example-plugin-detector
doberman.detectors only; a follow-up can cover the rest.examples/plugin-guardrail/ itself.examples/ to CI's default testpaths.New here? Start with CONTRIBUTING.md. Issues are labelled level-1 (docs only) through level-10 (new subsystem) — pick one at your level and climb. Comment to claim an issue before starting.
Originally posted by: snowyukitty
I'd like to claim this issue. I checked current main at
dd4683bc9c6a450e8edbe847833998fe8d1daa92; the registry now declares 11 entry-point groups rather than the issue's 10. The additionaldoberman.async_challenge_backendsseam is resolved separately byactive_async_backend()(with the in-memory fallback), rather than by adiscover_*()function, so I would document that actual path explicitly.For the detector example, I plan to add a real installable
doberman.detectorspackage with PASS/AUTH-only behavior and generic, redacted explanations. Its tests would prove real installed entry-point discovery and execution throughSubjectiveGuardrail, including raise-only composition. I would also adddocs/EXTENDING.mdfor all 11 current seams and link it from README, while leavingexamples/plugin-guardrail/and the defaulttestpathsunchanged. If this updated scope matches your intent, I'm happy to implement it.Originally posted by: fu351
Assigned — and good catch on the count. You're right: the registry declares 11 groups now, not 10. The new one is
doberman.async_challenge_backends, and it resolves throughactive_async_backend()rather than adiscover_*(), so it's the one seam the docs page should flag as different. I've folded the correction into the body.This is a close cousin of your plugin-guardrail tutorial (#132) — same shape, one seam over — so you've half-written the sister page already.
docs/EXTENDING.mdis the piece that ties all 11 together.Originally posted by: fu351
Hey @snowyukitty, a no-deadline check-in. The detector example plus
EXTENDING.mdis a real chunk of writing, so slow going is normal. If you're stuck on anything, such as how to describe theasync_challenge_backendspath or what the detector example should prove, ask here and I'll answer. And if life moved on since you claimed it, say the word and I'll unassign it, no hard feelings; it'll be here if you come back.