Execution Contract¶
This document defines the execution layer contract for the DITA Package Processor.
The execution layer is responsible for applying a generated plan to a target environment. It is the only layer permitted to perform side effects (filesystem mutation).
This document is normative. Tests, integration points, and future executors must conform to it.
1. Architectural Boundary¶
The execution layer sits between:
- Planning (pure, deterministic plan generation)
- Materialization (effects on disk)
Execution consumes a plan dictionary and produces an ExecutionReport.
It does not:
- Re-plan
- Infer missing fields
- Modify planning output
- Read discovery data directly
2. Executor Responsibilities¶
Execution is divided into three layers:
2.1 Dispatcher¶
The dispatcher:
- Iterates over
plan["actions"] - Preserves action order
- Invokes
executor.execute(action) - Collects
ExecutionActionResult - Produces
ExecutionReport
The dispatcher owns:
- Plan iteration
- Plan-level validation
- Aggregation of results
- Summary calculation
The dispatcher does not:
- Perform filesystem operations
- Interpret action semantics
2.2 Executor¶
The executor:
- Executes exactly one action at a time
- Resolves handler from registry
- Injects dependencies (source_root, sandbox, policy)
- Catches and classifies failures
- Returns
ExecutionActionResult
The executor owns:
- Handler resolution
- Policy enforcement
- Sandbox enforcement
- Failure translation
The executor does not:
- Iterate over plan
- Mutate plan
- Perform cross-action coordination
2.3 Handlers¶
Handlers:
- Perform concrete side effects
- Operate only on injected dependencies
- Must not guess paths
- Must not use CWD
- Must not access global state
Handlers may accept any subset of:
actionsource_rootsandboxpolicy
Handlers must return ExecutionActionResult.
3. FilesystemExecutor Contract¶
3.1 Constructor¶
FilesystemExecutor(
*,
source_root: Path,
sandbox_root: Path,
apply: bool,
)
Parameters:
-
source_rootRoot directory for reading input artifacts. -
sandbox_rootRoot directory for all writes. -
applyIfTrue, mutations are allowed. IfFalse, execution is dry-run only.
No defaults are permitted.
Executor construction must be explicit.
3.2 Plan Entry Point¶
.run(
*,
execution_id: str,
plan: Dict[str, Any],
) -> ExecutionReport
Responsibilities:
- Log execution start
- Delegate to dispatcher
- Log completion
- Return ExecutionReport
The executor must not:
- Modify
plan - Inject new actions
- Remove actions
3.3 Single Action Execution¶
.execute(action: Dict[str, Any]) -> ExecutionActionResult
Responsibilities:
- Validate action has required keys
- Resolve handler by
action["type"] - Inject supported kwargs
- Catch exceptions
- Translate failures into structured result
The method must never raise for handler failures.
All failures must be returned as ExecutionActionResult.
4. Plan Contract¶
The executor consumes a plan dictionary of shape:
{
"actions": [
{
"id": str,
"type": str,
...
}
]
}
Execution layer requires:
actionskey existsactionsis a list- Each action contains:
idtype
Dispatcher is responsible for rejecting malformed plans.
5. ExecutionReport Contract¶
ExecutionReport must contain:
execution_idresults(ordered list of ExecutionActionResult)summary
5.1 Summary Fields¶
At minimum:
totalsucceededfailedskipped(if supported)
Summary must be derived only from results.
6. ExecutionActionResult Contract¶
Each action result must contain:
action_idstatushandlerdry_runmessageerror(nullable)
6.1 Status Values¶
Allowed status values:
"succeeded""failed""skipped"
No additional status values are permitted without schema update.
7. Failure Classification¶
Failures must be explicit and categorized.
Three categories exist:
7.1 Handler Error¶
Handler raised an exception during execution.
Returned as:
status="failed"
failure_type="handler_error"
7.2 Policy Violation¶
Mutation violated overwrite or sandbox policy.
Returned as:
status="failed"
failure_type="policy_violation"
7.3 Executor Error¶
Unexpected executor failure.
Returned as:
status="failed"
failure_type="executor_error"
No silent failures. No implicit fallback behavior.
8. Safety Pipeline¶
Filesystem mutation flows through:
source_root
↓
sandbox boundary enforcement
↓
mutation policy enforcement
↓
handler execution
↓
ExecutionActionResult
Handlers must not bypass sandbox or policy.
All path resolution flows through the executor.
9. Invariants¶
The following invariants must hold:
- Plan is never mutated.
- Action order is preserved.
- ExecutionReport reflects exact plan order.
- All actions produce results.
- Execution is observable only through ExecutionReport.
- Logging is not a contract surface.
10. Test Alignment Requirements¶
All execution tests must assume:
.run()is the plan entry point..execute()is single-action only.- Constructor requires explicit roots and apply flag.
- Dispatcher owns iteration.
- Failure categories are explicit.
If tests assume otherwise, tests must be updated.
11. Versioning¶
If any of the following change:
- Executor constructor signature
- ExecutionReport shape
- Failure classification taxonomy
- Plan shape requirements
The execution contract version must be incremented.