KB-1094

11 — Mother of Task (MOT) → Queue Mapping

9 min read Revision 1
design-packdieu-45motmother-of-taskqueue-mappingmot-not-executorjob-workflowdesign-only

11 — Mother of Task (MOT) → Queue Mapping

DESIGN-ONLY. Cites Điều 45 §13.4, §11.5, §6.7. MOT is NOT an executor. Design seam only; no MOT runtime authored.


§1. Goal

Make MOT compatible with the queue substrate without violating §13.4. MOT must:

  • Generate a job graph (the workflow template instance).
  • Hand off execution to registered §11.5 executors.
  • Never claim a job_queue row itself.
  • Never hold a lease, write a heartbeat, or register as a consumer.
  • Make its workflow's lifecycle observable in PG (per §11.5 rule executor_state_must_be_reconstructable_from_PG_after_restart).

This document is a design seam. Concrete MOT runtime schema (template definition, parameter binding, graph DSL) is out of scope — those belong in the MOT sub-design pack when MOT spec stabilises.


§2. Current state

  • MOT spec: not stable.
  • No mot_* table exists in PG.
  • No live MOT instance is running.
  • §13.4 of Điều 45 v1.0 codifies the MOT clause; this design implements only what that clause permits at Phase 1.

§3. Proposed seam — job_workflow and one MOT generator function

§3.1 Workflow parent row (job_workflow)

Recap from DP2:

NON-EXECUTABLE DESIGN SKETCH — DO NOT APPLY

table public.job_workflow (
  workflow_id    uuid PRIMARY KEY,
  workflow_kind  text NOT NULL,    -- vocab: 'mark_cut_pipeline', 'mot_template_v1', 'customer_inbound', ...
  generator      text NOT NULL,    -- 'MOT:<template_id>' for MOT graphs
  status         text NOT NULL,    -- {active, succeeded, failed, partially_failed, cancelled}
  ...
);

MOT emits exactly one job_workflow row + N job_queue rows where job_queue.workflow_id = job_workflow.workflow_id and job_queue.parent_job_id carries the DAG edge.

§3.2 MOT graph emit function

NON-EXECUTABLE DESIGN SKETCH — DO NOT APPLY

function fn_mot_graph_emit(
  p_template_id    text,
  p_template_params jsonb,    -- signal-only; CHECK forbids body/content/raw/vector/...
  p_correlation_id text,
  p_actor          text
) RETURNS jsonb
-- 1. Validate template_id ∈ mot_template registry (separate MOT pack).
-- 2. Validate actor has MOT_template_generator role.
-- 3. INSERT INTO job_workflow (...).
-- 4. For each step in template:
--      INSERT INTO job_queue (
--        job_kind         = step.job_kind,
--        executor         = step.executor (validated against §11.5 — MOT explicitly refused),
--        idempotency_key  = workflow_id||':'||step.local_id,
--        source_ref       = step.source_ref,
--        target_ref       = step.target_ref,
--        payload_ref      = step.payload_ref,
--        safe_payload     = {step.local_id, template_id, params_keys_only},
--        process_after    = step.delay_relative_to_workflow_start,
--        priority         = step.priority,
--        workflow_id      = new_workflow_id,
--        parent_job_id    = parent step's job_id (for DAG edges)
--      );
-- 5. RETURN {workflow_id, step_job_ids[], count}.

MOT calls this function; it does NOT call fn_job_claim or fn_job_succeed. Workflow lifecycle advances purely through constituent jobs.

§3.3 Workflow lifecycle derivation

NON-EXECUTABLE DESIGN SKETCH — DO NOT APPLY

function fn_job_workflow_refresh(p_workflow_id uuid) RETURNS jsonb
-- Reads job_queue rows for the workflow.
-- Derives status:
--   active            = any step in {queued, leased, in_progress, retry_waiting}
--   succeeded         = all steps succeeded
--   failed            = any step in dead_letter
--   partially_failed  = some succeeded, some dead_letter, none in_progress
--   cancelled         = parent or all steps cancelled
-- Writes status + finished_at into job_workflow.
-- Called as a worker job: job_kind='job_workflow_refresh' on cadence (DP1 Layer 1).

This refresh is also called from fn_job_succeed, fn_job_fail_*, and fn_job_cancel (DP2/DP3) as a side-effect, so workflow status converges in near-real-time.


§4. MOT step interactions

§4.1 Same-DAG step interaction

parent_job_id carries the edge. A worker claiming a step checks that parent_job_id (if not NULL) is in succeeded before processing. This is the simplest DAG semantics; richer (any-vs-all parents) belongs in the MOT pack.

§4.2 Trigger-in / trigger-out

  • MOT step may receive input via trigger-in (DP5 iu_sql_event_route row mapping an event to enqueueing a step) — same path as any other consumer.
  • MOT step may emit events via standard fn_iu_emit_event calls from its executor — same path as any other producer.
  • MOT itself never bypasses the queue substrate.

§4.3 IU step interaction

A MOT step that is an Information Unit operation (e.g. cut, restage) MUST go through the existing operator alias surface (fn_iu_op_*), not bypass it. §13.4 rule: "MOT step CANNOT create IU bypass Điều 37 cut alias / Điều 35 DOT pipeline".


§5. Enforcement that MOT is NOT an executor

Recapping from DP6 §3.4:

  • job_queue.executor CHECK refuses 'MOT'.
  • consumer_registry.executor CHECK refuses 'MOT'.
  • job_subscription.executor_kind CHECK refuses 'MOT'.
  • queue_heartbeat.executor_kind CHECK refuses 'MOT'.

Any attempt to register MOT as an executor fails INSERT at the DB level. There is no path through the design that lets MOT claim or run a job_queue row.


§6. Vocabulary

mot_vocab_at_phase_1:
  workflow_kinds:
    - mot_template_v1            # placeholder, refined in MOT pack
  generator_format:              # job_workflow.generator
    pattern: 'MOT:<template_id>'
  step_local_id:
    type: text                   # MOT-internal, used only inside one workflow scope

No new event_type. No new event_domain. No new event_stream.


§7. Observability

NON-EXECUTABLE DESIGN SKETCH — DO NOT APPLY

view v_job_workflow_health AS
  SELECT w.workflow_id, w.workflow_kind, w.generator, w.status,
         count(j.*) FILTER (WHERE j.status='queued')        AS queued_steps,
         count(j.*) FILTER (WHERE j.status='in_progress')   AS in_progress_steps,
         count(j.*) FILTER (WHERE j.status='succeeded')     AS succeeded_steps,
         count(j.*) FILTER (WHERE j.status='dead_letter')   AS dead_letter_steps,
         w.enqueued_at, w.finished_at
    FROM job_workflow w
    LEFT JOIN job_queue j ON j.workflow_id = w.workflow_id
   GROUP BY w.workflow_id;

Feeds v_queue_health (DP4).


§8. Compatibility with Điều 45 v1.0

Clause Compliance
§13.4 MOT-clause ✅ verbatim: MOT generates graph, delegates to executors, never claims
§13.4 forbidden labels (future_MOT_executor) ✅ CHECK refuses MOT in 4 surfaces
§11.5 executor whitelist ✅ MOT not in set; cannot register heartbeat
§6.7 work state machine ✅ each MOT step is a job_queue row obeying 9-state machine
§4 signal-not-data ✅ template_params CHECK forbids forbidden keys
§13.3 Phase 1 NOT bring MOT runtime ✅ this doc is design seam only

§9. Implementation prerequisites

  • DP2 (job_queue, job_workflow) in place.
  • DP3 (lease/retry) so step failures retry per policy.
  • DP6 (executor enforcement) so the MOT-CHECK is wired in 4 places.
  • MOT template registry (out of scope; a future MOT pack).

§10. Open questions

# Question Routed to
MOT-Q1 Approve job_workflow table at Phase 1, or defer to MOT-pack? Council
MOT-Q2 Approve fn_mot_graph_emit as the only MOT entry-point? Council
MOT-Q3 DAG semantics: any-parent vs all-parents at Phase 6? Council + MOT pack
MOT-Q4 Should job_workflow support nested workflows (workflow-of-workflows)? Council
MOT-Q5 Should MOT template registry be vocab-only in event_type_registry style, or its own table? MOT pack
MOT-Q6 partially_failed semantics — does it freeze the workflow or allow retry of failed steps? Council

MOT mapping. Design seam only. No MOT runtime authored. No mutation. Authored 2026-05-26.

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-dieu45-full-queue-orchestration-design-pack/11-mother-of-task-queue-mapping.md