Planning¶
The Planning module converts discovery output into a deterministic execution plan. It is where intent is expressed explicitly as ordered actions with clear reasons and traceable origins.
Planning does not mutate files or execute transformations. It analyzes structure, applies planning steps, and emits a plan that can be reviewed, validated, versioned, and replayed.
This separation allows complex transformations to be reasoned about and tested independently of execution, and it makes the system explainable by design.
dita_package_processor.planning.executor
¶
Planning execution adapter.
Planning never performs execution directly. It delegates execution to the execution layer.
This adapter exists for backward compatibility with callers that still invoke execution through the planning namespace.
dita_package_processor.planning.graph_planner
¶
Graph-based planner for dependency resolution.
This module operates strictly on the PlanningInput contract layer.
It does NOT depend on discovery types or DependencyGraph.
Responsibilities¶
- Determine root artifact
- Walk relationships deterministically
- Produce stable execution ordering
- No filesystem
- No mutation
- No discovery coupling
Input¶
nodes : list[str] relationships : list[PlanningRelationship | dict]
Output¶
list[str] Deterministic artifact order suitable for action emission.
Design rules¶
- deterministic
- pure
- contract-only
- fail fast
GraphPlanner
¶
Deterministic dependency planner operating on contract relationships.
Guarantees¶
- stable ordering
- no duplicates
- dependencies visited before dependents
- no discovery layer coupling
GraphPlannerError
¶
Bases: RuntimeError
Raised when dependency planning cannot be resolved safely.
dita_package_processor.planning.hydrator
¶
Plan hydration logic.
This module converts a JSON-loaded dictionary into strongly-typed planning domain models.
Hydration is a strict boundary:
- JSON is untrusted input
- Models are validated, typed contracts
- Errors are explicit and never silent
No filesystem or execution semantics exist here.
PlanHydrationError
¶
Bases: ValueError
Raised when a plan cannot be hydrated into a Plan model.
This signals malformed, missing, or structurally invalid input.
hydrate_plan(payload)
¶
Hydrate a :class:Plan model from a parsed JSON payload.
This function is a strict deserialization boundary. It assumes:
- Input is untrusted
- All required fields must be present
- Types must be valid or convertible
- Failures must be explicit and actionable
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
payload
|
Dict[str, Any]
|
Parsed JSON dictionary. |
required |
Returns:
| Type | Description |
|---|---|
Plan
|
Hydrated :class: |
Raises:
| Type | Description |
|---|---|
PlanHydrationError
|
If required fields are missing or invalid. |
dita_package_processor.planning.input_normalizer
¶
Discovery input normalizer (legacy compatibility layer).
This module exists to normalize older discovery JSON formats that still expose graph structures. It is NOT part of the new contract boundary.
The new, canonical boundary is:
discovery.json
→ planning/contracts/discovery_to_planning.py
→ PlanningInput
This module remains only for historical pipeline compatibility and migration support. Planning MUST NOT depend on this module.
Responsibilities: - Canonicalize paths - Remove media artifacts from graph topology - Remove edges involving media - Ensure graph nodes reference known artifacts - Perform no inference and no guessing
PlanningInputNormalizer
¶
Normalize legacy discovery graph output into planner-compatible structure.
WARNING: This is NOT the new contract bridge. The canonical bridge is planning/contracts/discovery_to_planning.py.
This class only exists to stabilize older pipeline stages that still expect graph-shaped discovery output.
normalize(discovery)
staticmethod
¶
Normalize legacy discovery input.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
discovery
|
Dict[str, Any]
|
Parsed discovery JSON. |
required |
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
Normalized structure with semantic-only artifacts and graph. |
Raises:
| Type | Description |
|---|---|
ValueError
|
On structural inconsistency. |
normalize(discovery)
¶
Functional wrapper for PlanningInputNormalizer.normalize.
Exists only for backward pipeline compatibility.
dita_package_processor.planning.invariants
¶
Invariant enforcement for DITA execution plans.
This module defines and enforces global execution invariants that must hold for a plan to be considered logically safe to execute.
Invariants differ from schema validation:
- Validation ensures structural correctness.
- Invariants ensure semantic and operational safety.
Any invariant violation is fatal and must halt execution.
InvariantViolationError
¶
Bases: ValueError
Raised when an execution invariant is violated.
This signals that a plan is unsafe to execute regardless of syntactic correctness.
validate_invariants(plan)
¶
Validate all execution invariants for a plan.
This function is the single public entry point for invariant enforcement. It must be called after schema validation and before execution.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
plan
|
Dict[str, Any]
|
Execution plan dictionary. |
required |
Raises:
| Type | Description |
|---|---|
InvariantViolationError
|
If any invariant is violated. |
dita_package_processor.planning.layout_rules
¶
Target layout rules for planned artifacts.
This module defines deterministic rules that map an artifact type to its target location within the output package.
This layer is pure planning logic:
- No filesystem access
- No directory creation
- No content inspection
- No mutation
It is a pure mapping layer used by the planning system to determine where artifacts should be placed.
LayoutRuleError
¶
Bases: ValueError
Raised when an unknown or unsupported artifact type is encountered.
This indicates a planning error: either discovery classification failed or a new artifact type has not yet been mapped.
resolve_target_path(*, artifact_type, source_path, target_root)
¶
Resolve the target filesystem path for an artifact.
Layout rules:
map→<target_root>/<filename>topic→<target_root>/topics/<filename>media→<target_root>/media/<filename>
Only the filename is preserved. All directory hierarchy from the source path is intentionally flattened per artifact class to ensure deterministic, collision-free layouts.
This function performs no I/O and no mutation. It only returns a computed path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
artifact_type
|
str
|
Artifact classification ( |
required |
source_path
|
Path
|
Original artifact path. |
required |
target_root
|
Path
|
Root directory of the output package. |
required |
Returns:
| Type | Description |
|---|---|
Path
|
Target path for the artifact. |
Raises:
| Type | Description |
|---|---|
LayoutRuleError
|
If the artifact type is unsupported. |
dita_package_processor.planning.loader
¶
Plan loading utilities.
Loads a plan.json file from disk and hydrates it into a validated
:class:~dita_package_processor.planning.models.Plan model.
Responsibilities: - Read JSON from disk - Parse JSON into a Python object - Delegate structural validation and typing to the hydrator
This module enforces a hard boundary between: Filesystem → Planning Domain
No semantic validation, execution logic, or fallback behavior is allowed here. All failures are fatal and must abort the pipeline.
PlanLoadError
¶
Bases: ValueError
Raised when a plan file cannot be loaded or hydrated.
Indicates a contract boundary failure between the filesystem and the planning domain model.
These errors are non-recoverable by design.
load_plan(path)
¶
Load and hydrate a plan.json file.
Strict process:
1. Read UTF-8 JSON text from disk
2. Parse JSON into a Python mapping
3. Hydrate mapping into a :class:Plan
No optional behavior, no guessing, no silent recovery.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
Path to the |
required |
Returns:
| Type | Description |
|---|---|
Plan
|
Fully hydrated :class: |
Raises:
| Type | Description |
|---|---|
PlanLoadError
|
If any step fails. |
dita_package_processor.planning.models
¶
Planning data models.
This module defines the immutable data structures that represent a validated execution plan.
Design Principles¶
- Declarative only.
- No execution state.
- No mutation.
- No filesystem logic.
- No runtime side effects.
Planning describes intent. Execution describes effects.
ActionType
¶
Bases: str, Enum
Canonical set of allowed plan action types.
This enum is the single source of truth for action identity.
Plan
dataclass
¶
PlanAction
dataclass
¶
Declarative execution action.
This structure represents intent only. It contains no execution state.
PlanIntent
dataclass
¶
PlanSourceDiscovery
dataclass
¶
dita_package_processor.planning.planner
¶
dita_package_processor.planning.validation
¶
Execution-time validation utilities.
These checks validate action parameters before execution. They do not perform filesystem writes or mutate any state.
This module exists to enforce the executor contract: - Plans may be structurally valid - Actions may be syntactically correct - But execution must still fail fast if parameters are unsafe
ActionValidationError
¶
Bases: ValueError
Raised when action parameters are invalid or unsafe for execution.
validate_action(action)
¶
Validate a PlanAction based on its type.
This is the main entry point used by executors. It dispatches to the
appropriate validator based on action.type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
action
|
PlanAction
|
PlanAction to validate. |
required |
Raises:
| Type | Description |
|---|---|
ActionValidationError
|
If validation fails. |
validate_copy_map_parameters(action)
¶
Validate parameters for the copy_map action.
Required parameters: - source_path - target_path
Validation rules: - source_path must exist - target_path must NOT already exist
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
action
|
PlanAction
|
PlanAction to validate. |
required |
Raises:
| Type | Description |
|---|---|
ActionValidationError
|
If validation fails. |