DD-010: Process-step AI executor (llm_intent steps inside a process) — parked until a consumer runs AI work as a process step¶
id: DD-010
status: PARKED
issues: [1454, 1457]
adrs: [0043, 0057]
decided: 2026-10-13
decided_at_sha: 7879465836d4c38ded550e9c564f1a7d7d29d9e8
parent: flense-programme
One-line intent¶
http/runtime/process_executor.py (a linear, checkpointed executor for
llm_intent / service / condition process steps that writes the governed
ProcessRun row ADR-0043 makes the AIJob subject) was never mounted: no
route, subsystem or process adapter constructed ProcessExecutor, ADR-0043
records it as "not yet request-mounted", and no consumer declares an
llm_intent step inside a process. Flense ship O (ADR-0057) deletes it.
Plan (what we already concluded)¶
Restore http/runtime/process_executor.py and its two test modules
(tests/unit/test_process_executor.py, tests/unit/test_process_run_executor.py)
from the commit this DD was parked at (the original #417 design, "Layer 3" of
docs/plans/2026-03-09-llm-async-event-queue-design.md, is at the same commit),
then wire it where the live process runtime dispatches steps rather than as a
second runtime:
- The live dispatcher is
core/process/step_executor._dispatch_step(service, human_task, wait, send, query, foreach). Anllm_intentstep today falls through to its "Unknown step kind" warning. The forced change adds anllm_intentarm there that callsLLMIntentExecutor.executewithsubject_type="ProcessRun"andsubject_id=<run id>, so the ADR-0043 subject guarantee (every AI call names a scope-able subject) holds. - The governed
ProcessRunentity (injected when a process has anllm_intentstep;db/virtual.is_virtual_entitytreats it as real when it carriesstarted_by) is the row the step writes; the restored executor's_start_process_run/_finish_process_runshow the shape. - Checkpoint replay (
ProcessContext.checkpoints) maps onto the step state the Postgres process adapter already persists; do not add a second checkpoint store. - Counter-priors: no generic
POST /execute/{intent}route (ADR-0043,tests/unit/test_no_bare_llm_route.py); no AI call without a subject.
Reopen when (consumer force)¶
- Named consumer — a consumer declares a
processwith anllm_intentstep (candidates: pennydreadful's story intents run as an editorial pipeline; AegisMark marking as a multi-step process). - Evidence of host workaround — a consumer calling
llm_executorfrom a service step or app code to get AI work inside a process. - Acceptance that unblocks — the consumer's process runs its
llm_intentstep on the live process adapter, theAIJobrow names theProcessRunas subject, andsubject[ProcessRun].started_by = current_userscopes the jobs in that consumer's CI.
When a force lands:
- Set
status: FORCEDand date it. - Comment on every linked issue with the consumer + this DD path.
- Implement against the plan above; open child issues if the plan splits.
- When shipped, set
status: DONEand close issues.
Already shipped (do not re-litigate)¶
- ADR-0043 closed-system AI cognition:
llm_executorandllm_queuerequire a subject; LLM triggers (llm_trigger.py) supply one and are live. - The
llm_intentstep kind still parses (StepKind.LLM_INTENT) and the governedProcessRunentity is still injected; only the executor is parked.
Explicitly out of scope until force¶
- Parallel or branching AI steps, retries beyond the process retry policy, a separate AI process runtime.
Trail¶
| Date | Event |
|---|---|
| 2026-10-13 | Parked (this DD); process_executor.py removed in flense ship O |