Extension framework optimization

This commit is contained in:
2026-05-04 11:49:39 +02:00
parent 32f4af8359
commit 33fa602fe5
7 changed files with 208 additions and 18 deletions

View File

@@ -95,6 +95,63 @@ The canonical processing model should define a small set of shared envelopes:
Subsystem-specific types may remain richer. The canonical model is the bridge,
not a forced replacement for every local dataclass.
### Processing Request Example
```python
from pathlib import Path
from markitect_tool.extension import ProcessingContext, ProcessingRequest
request = ProcessingRequest(
operation="query.selector",
input={"selector": "sections[heading=Decision]"},
context=ProcessingContext(
source_path=Path("docs/adr.md"),
namespaces={"std": "standards"},
variables={"audience": "internal"},
),
options={"format": "json"},
scope="document",
)
```
The request cache key includes operation, input, options, scope, declared
capabilities, metadata, and stable context semantics:
- source path
- namespaces
- variables
- policy
- metadata
It intentionally excludes root path, caller name, and live backend handles.
Those are execution-environment details. If they matter semantically for an
extension, put explicit values in request options or metadata.
### Processing Result Example
```python
from markitect_tool.extension import (
ProcessingProvenance,
ProcessingResult,
ProcessingTrace,
)
result = ProcessingResult(
output={"count": 1},
provenance=[
ProcessingProvenance(
operation="query.selector",
source_path="docs/adr.md",
content_hash="sha256:...",
)
],
).with_trace(ProcessingTrace(event="query.done"))
```
`ProcessingResult.valid` is derived from diagnostics. Any diagnostic with
severity `error` makes the result invalid.
## Registration Strategy
Start with in-package registration:
@@ -115,6 +172,35 @@ packages become a real requirement.
See `docs/extension-authoring.md` for the extension authoring checklist and
descriptor template.
### Registry Use
Extension registries are optimized for common lookup patterns:
- `registry.get("backend.local-sqlite")`
- `registry.list(kind="query-engine")`
- `registry.require_capability("fts")`
- `registry.check_dependencies("jsonpath")`
Kinds and capabilities are indexed at registration time, so large registries can
avoid repeated full scans for basic discovery.
### Execution Lifecycle
`ExtensionExecutor` wraps a descriptor factory with deterministic lifecycle
hooks:
1. Fetch descriptor.
2. Check required optional dependencies.
3. Instantiate callable implementation.
4. Run `before` callbacks.
5. Execute implementation.
6. Normalize result type.
7. Append `extension.executed` trace.
8. Run success or failure callbacks.
9. Run final `after` callbacks.
Callbacks are explicit. The framework does not introduce hidden global behavior.
## Compatibility Rules
The refactor must preserve: