Skip to content

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.

get_registry()

Return the global execution handler registry.

This function lazily constructs the registry exactly once.

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

Deterministic plan dispatcher.

__init__(executor)

Initialize dispatcher with executor.

dispatch(*, execution_id, plan, dry_run)

Execute all actions sequentially.

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.

DryRunExecutor

Executor that simulates execution without performing mutations.

Structural twin of FilesystemExecutor:

  • Owns a dispatcher
  • Implements execute(action)
  • Executes full plans via dispatcher
  • Never mutates state
__init__()

Initialize dry-run executor and dispatcher.

execute(action)

Simulate execution of a single action.

This method is invoked by ExecutionDispatcher.

Parameters

action : dict Normalized action dictionary.

Returns

ExecutionActionResult Deterministic dry-run result with status="skipped".

run(*, execution_id, plan)

Execute a full plan in dry-run mode.

Parameters

execution_id : str Unique execution identifier. plan : dict Validated execution plan dictionary.

Returns

ExecutionReport Dry-run execution report.

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.

to_dict()

Serialize action execution result.

Returns

Dict[str, Any] JSON-safe dictionary representation.

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

Create execution report and compute summary.

Parameters

execution_id : str Execution identifier. dry_run : bool Dry-run flag. results : List[ExecutionActionResult] Execution results.

Returns

ExecutionReport

to_dict()

Serialize execution report.

Returns

Dict[str, Any] JSON-safe dictionary representation.

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.