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 ALL execution handlers are registered.
Design rules¶
- Exactly ONE registry instance exists process-wide
- No dynamic discovery
- No reflection
- Explicit registration only
- Deterministic
Why¶
Handlers are infrastructure, not runtime state. Creating multiple registries leads to: - missing handlers - inconsistent dispatch - impossible debugging
Therefore this module exposes:
get_registry()
and NEVER returns a fresh registry.
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. 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.
create(*, execution_id, dry_run, results)
classmethod
¶
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. |