Execution¶
The Execution module consumes a validated plan and produces an ExecutionReport. It is the only layer allowed to perform filesystem mutation, and only when explicitly enabled.
Execution resolves paths via a sandbox, enforces mutation policies, dispatches actions to registered handlers, and records outcomes in a structured, forensic report.
Dry-run execution is fully supported and is the default mode, allowing plans to be validated without side effects. Execution never invents actions or alters plans.
dita_package_processor.execution.bootstrap
¶
Execution handler bootstrap.
This module is the single authoritative place where the execution handler registry is populated.
Since the introduction of the plugin system, all handler registration is
delegated to the plugin registry. Handlers are no longer imported or
registered here explicitly — they are provided by each plugin via
DitaPlugin.handlers().
Design rules (unchanged)¶
- Exactly ONE registry instance exists process-wide.
- No dynamic discovery beyond what plugins declare.
- Deterministic: CorePlugin loads first, then third-party plugins in alphabetical entry-point order.
- Conflict (duplicate action_type) is a startup error.
Therefore this module exposes:
get_registry()
and NEVER returns a fresh registry.
get_registry()
¶
Return the global execution handler registry.
On first call, the registry is built by asking the plugin registry for all handler classes (CorePlugin first, then any installed third-party plugins in alphabetical order).
Returns¶
ExecutionHandlerRegistry Fully populated registry containing all handlers.
dita_package_processor.execution.dispatcher
¶
Execution dispatcher.
The dispatcher is responsible for:
- Receiving a validated plan dictionary
- Executing actions in deterministic order via an Executor
- Collecting ExecutionActionResult objects
- Emitting an ExecutionReport
It performs: - NO planning - NO handler resolution - NO filesystem logic - NO registry inspection
The dispatcher owns plan iteration and structural validation.
The executor owns single-action execution.
This module is intentionally minimal and deterministic.
ExecutionDispatchError
¶
Bases: RuntimeError
Raised when the execution plan is structurally invalid.
This indicates a contract violation between planning and execution.
ExecutionDispatcher
¶
ExecutorProtocol
¶
Bases: Protocol
Minimal protocol for executors consumed by ExecutionDispatcher.
Executors must implement:
execute(action: Dict[str, Any]) -> ExecutionActionResult
dita_package_processor.execution.dry_run_executor
¶
Dry-run execution orchestration.
Executes a validated plan in dry-run mode. This executor never mutates the filesystem and must never perform irreversible actions.
Responsibilities¶
- Own a dispatcher
- Implement the executor contract: execute(action: dict) -> ExecutionActionResult
- Dispatch plans in dry-run mode
- Produce a complete ExecutionReport
Dry-run answers a single question:
"What would have happened if this plan were executed?"
DryRunExecutionError
¶
Bases: RuntimeError
Raised when dry-run orchestration fails structurally.
These indicate dispatcher or structural failures, not handler or filesystem failures.
dita_package_processor.execution.models
¶
Execution domain models.
These models describe what actually happened during execution. They are forensic records, not intentions.
Execution models must never be reused by planning. They exist solely to capture observable outcomes.
ExecutionActionResult
dataclass
¶
Result of executing a single planned action.
Parameters¶
action_id : str ID of the action from the plan. status : ExecutionStatus One of: "success", "failed", "skipped". handler : str Name of the handler or executor class used. dry_run : bool Whether execution was a dry-run. message : str Human-readable description of outcome. error : Optional[str] Raw error message if failure occurred. error_type : Optional[ExecutionErrorType] Structured classification of failure.
Only meaningful when status == "failed".
Canonical taxonomy:
- "handler_error"
- "policy_violation"
- "executor_error"
metadata : Dict[str, Any] Optional structured execution metadata.
ExecutionReport
dataclass
¶
Root execution report.
Captures a complete run of an execution pipeline.
Parameters¶
execution_id : str Unique identifier for this execution run. generated_at : str ISO timestamp of report creation. started_at : str ISO timestamp when execution started. finished_at : str ISO timestamp when execution finished. duration_ms : int End-to-end execution duration in milliseconds. dry_run : bool Whether execution was simulated. results : List[ExecutionActionResult] List of per-action execution results. summary : Dict[str, int] Aggregated statistics for quick inspection. discovery : DiscoverySummary Discovery-level counts included for quick debugging context.
create(*, execution_id, dry_run, results, started_at=None, finished_at=None, discovery=None)
classmethod
¶
Create execution report and compute summary.
Parameters¶
execution_id : str Execution identifier. dry_run : bool Dry-run flag. results : List[ExecutionActionResult] Execution results. started_at : Optional[datetime] Optional execution start timestamp (UTC-aware expected). finished_at : Optional[datetime] Optional execution end timestamp (UTC-aware expected). discovery : Optional[Dict[str, Any]] Optional discovery summary for the report.
Returns¶
ExecutionReport
dita_package_processor.execution.registry
¶
Execution handler registry.
This module defines a strict registry that maps plan action types to concrete execution handlers.
The registry is the only legal mechanism for dispatching actions to handlers. There is no dynamic discovery, no reflection, and no guessing.
If an action type is not registered, execution must fail — unless a wildcard handler is explicitly registered (used for dry-run execution).
ExecutionHandler
¶
Abstract base class for all execution handlers.
Concrete handlers must implement:
- action_type: class attribute
- execute(action: dict) -> ExecutionActionResult
This base class exists only to define the interface contract.
execute(action)
¶
Execute a single plan action.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
action
|
dict
|
Action dictionary from the plan. |
required |
Returns:
| Type | Description |
|---|---|
|
ExecutionActionResult |
ExecutionHandlerError
¶
Bases: RuntimeError
Raised when execution handlers are misconfigured or missing.
These are structural errors and must halt execution immediately.
ExecutionHandlerRegistry
¶
Registry for mapping action types to execution handlers.
This is a strict, closed system: - Handlers must be explicitly registered. - Duplicate registrations are forbidden. - Missing handlers cause immediate failure unless a wildcard handler has been registered.
The wildcard handler ("*") is intended exclusively for dry-run execution.
get_handler(action_type)
¶
Retrieve a handler class for an action type.
Resolution order: 1. Exact action_type match 2. Wildcard handler (if registered) 3. Failure
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
action_type
|
str
|
Action type string. |
required |
Returns:
| Type | Description |
|---|---|
Type[ExecutionHandler]
|
Handler class. |
Raises:
| Type | Description |
|---|---|
ExecutionHandlerError
|
If not registered. |
register(handler_cls)
¶
Register a handler class.
The handler class must define a unique action_type attribute.
Special case: action_type="*" registers a wildcard fallback handler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
handler_cls
|
Type[ExecutionHandler]
|
Handler class to register. |
required |
Raises:
| Type | Description |
|---|---|
ExecutionHandlerError
|
If invalid or duplicate. |
registered_action_types()
¶
Return the set of registered concrete action types.
Wildcard is excluded.
Returns:
| Type | Description |
|---|---|
set[str]
|
Set of action type strings. |
dita_package_processor.execution.report_writer
¶
Execution report writer.
This module is responsible for writing an ExecutionReport to disk in a deterministic and reproducible way.
Determinism rules: - Keys must be sorted. - Indentation must be stable. - UTF-8 encoding must be enforced. - No implicit mutations of the report structure. - Output must be byte-for-byte reproducible for the same input.
This module is the final serialization boundary of the execution layer.
ExecutionReportWriteError
¶
Bases: RuntimeError
Raised when an execution report cannot be written to disk.
These are hard failures that indicate filesystem or serialization problems.
ExecutionReportWriter
¶
Deterministic writer for ExecutionReport objects.
This class owns all disk serialization semantics for execution reports.
__init__(*, indent=2, sort_keys=True, ensure_ascii=False)
¶
Initialize the writer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
indent
|
int
|
JSON indentation level. |
2
|
sort_keys
|
bool
|
Whether to sort dictionary keys. |
True
|
ensure_ascii
|
bool
|
Whether to escape non-ASCII characters. |
False
|
write(*, report, path)
¶
Write an ExecutionReport to disk.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
report
|
ExecutionReport
|
ExecutionReport instance. |
required |
path
|
Path
|
Target file path. |
required |
Raises:
| Type | Description |
|---|---|
ExecutionReportWriteError
|
If writing fails. |