KB-4B81 rev 9

Master Design Rev2 — 04 IU-Centered + 4 Mothers binding (rev3 MP-D11 + MP-D14)

45 min read Revision 9

Master Design Rev2 — IU-Centered Master Architecture + 4 Mothers Binding (WS2 + WS3)

Path: knowledge/dev/design/v0.6-iu-4mothers-event-foundation-rev2/04-iu-centered-4mothers-binding-design.md Status: DRAFT Rev2 (document-only) — Revision 5 (MP-D25 4 Mothers as governed object factories + IU relation to factory outputs added 2026-05-28; see NEW §4.7 + 10-… §5. Revision 4 added MP-D19 direct canonicalization guardrails + data lineage + MP-D18 Kaizen anti-noise relation; see §4.3b and 09-… §5 + §6. Revision 3 added MP-D11 MOIT staging input §4.3a + MP-D14 MOT/JFT matrix §4.2a; 08-… §3 + §6). Companion to 00-master-design-rev2.md. Date: 2026-05-27 (rev2) · 2026-05-28 (rev3 MP-D11 + MP-D14) · 2026-05-28 (rev4 MP-D18 + MP-D19) · 2026-05-28 (rev5 MP-D25) Authority: Rev2 brief §2 (IU doctrine), §3 (IU brick), §4 (IU bundle), §5 (4 Mothers), §9 (KG feedback), §10 (Usage evidence), §11 (No-double-ownership), §12 (Old infra). Boundary preserved: Điều 38/39 (IU), Điều 45 (queue/event), Điều 32 (approval), Điều 28/33 (UI/data plane), Điều 7 (Assembly First). Boundary: 4 Mothers are khuôn đúc around IU; they do NOT own IU body, queue/event core, or approval. This design extends existing PG substrate (reuse-first) and proposes registry-level columns; no migration in this macro.


§1. Scope and boundaries

This document designs:

  • The IU-centered master architecture: IU as the central assembly unit of every workflow (2..500 step), with no parallel "workflow artifact" track (Rev2 §2 doctrine).
  • The IU brick fields (Rev2 §3 11-field requirement).
  • The IU bundle / Step Pack (Rev2 §4).
  • The 4 Mothers binding: MOW / MOT / MOIT / MOUT each as a binding shape around IU, reusing existing PG tables where possible.
  • The IU version policy at design level (Rev2 §2 D2.6 + OD15).
  • The KG feedback bridge from this side (KG proposals land in proposal table — see WS4 §8).
  • The usage evidence schema sketched here, computed in 03-event-5layer-… §9.

This document does not design:

  • The 9-state floor / transition matrix / workflow UI — see 02-step-state-machine-and-workflow-ui-design.md.
  • The event/queue/realtime/DLQ substrate — see 03-event-5layer-realtime-dlq-design.md.
  • OSS tool selection — see 05-oss-candidate-strategy-rev2.md.
  • Approval quorum — Điều 32 surface.

§2. IU-Centered doctrine — design statement

§2.1 IU as the only central assembly unit

Per Rev2 §2 D2.1, every workflow step, task, form, output, event, or governance artifact assembles around an IU or an IU bundle. There is no "workflow artifact track separate from IU". Design consequence:

  • workflow_step_def has no body column. Its narrative / instruction / policy / contract come exclusively from a bound IU or IU bundle.
  • task_def (template) likewise — no body column. Tasks render their content from bound IU/bundle.
  • MOIT / MOUT registries describe shape (field set / output structure), not narrative; IU describes meaning.

§2.2 Build-once, reuse-many — singleton body source

information_unit.canonical_body_* (and iu_version for versioned body) is the only SoT for IU narrative. Render layer materializes for any surface (task UI, workflow doc viewer, notification body, audit log, MOUT render). Sentinel: design-time grep of tasks.body, workflow_step_def.description_text, event_outbox.payload.body_text must return zero non-render-template rows.

§2.3 No duplicate text invariant (D2.3) — render-layer pattern

Every IU body display goes through a render call:

render_iu_body(iu_unit_id, iu_version_id, render_surface, render_context) → bytes

Render surfaces (paper):

  • task.envelope.instruction — MOT region 4 (instruction).
  • workflow.doc.step_box — Standard Process View step node body popover.
  • notification.iu_event — notification render.
  • mout.inline_block — MOUT inline block in MOT region 3 (reference).
  • governance.audit_excerpt — audit timeline excerpt.

Render emits iu.rendered event (per 03-event-5layer-… §3.3). Sentinel: any surface displaying IU content corresponds to a render_iu_body call site.

MP-D6 — render_iu_body permission / cache / audit contract (binding):

Pre-render checks (refuse render if any fails; each refusal logged to event_validation_audit with a structured reason code):

Check Refusal code Meaning
iu_version_exists iu_version_not_found (iu_unit_id, iu_version_id) resolves to a real iu_version row.
governance_state_allowed iu_governance_state_blocked IU governance_state ∈ allowed set per surface (e.g. notification.iu_event allows only active; governance.audit_excerpt may show deprecated/archived with badge). Surface→allowed-states map declared in dot_config render.governance_state_allowed.<surface>.
permission_filter_backend render_permission_denied Backend permission predicate (fn_render_permission_check(surface, render_context, principal)) returns true. Permission is backend-enforced; Nuxt never decides visibility.
context_scope_allowed render_context_scope_mismatch render_context (workflow_run_id / task_run_id / notification_target_id / audit_trace_id) is scoped to the principal's reachable graph; cross-context render refused.

Audit event (mandatory). Every successful render_iu_body call MUST emit a single iu.rendered event into event_outbox carrying iu_unit_id, iu_version_id, render_surface, render_context_id, principal_id, permission_scope_hash, cache_hit ∈ {true, false}, trace_id. Refused renders MUST emit iu.render_refused with the refusal code. Sentinel: zero IU body bytes leave PG without a corresponding iu.rendered (or refusal) row.

Cache key (binding):

render_cache_key = hash(
  iu_unit_id,
  iu_version_id,
  render_surface,
  permission_scope_hash      -- digest of permission-affecting context (principal role set, tenant, language)
)

permission_scope_hash MUST be part of the cache key so that two principals with different permissions never share the same cache entry. render_context fields that affect the rendered bytes (locale, surface variant, dark/high-contrast mode) extend the key per render_cache_key_extension.<surface> declared in dot_config.

Notification render — no permission leak. Notification surface (notification.iu_event) MUST render IU content filtered through the recipient's permission scope, NOT the producer's. If recipient's permission_filter_backend denies (or partially denies) parts of the IU body, the notification renders only the permitted slice (or refuses with render_permission_denied if the slice is empty). Notification SHOULD NEVER include raw IU body bytes broader than what the recipient could read by directly opening the IU. Sentinel: notification payloads pass through the same permission predicate as direct IU view; no bypass path exists.

§2.4 4 Mothers as khuôn đúc (D2.4)

MOW/MOT/MOIT/MOUT shape flow / UI / IO contracts around IU but do not own:

  • IU body / IU axes / IU split-merge — Điều 38/39 own.
  • Queue / event core / executor boundary / heartbeat — Điều 45 owns.
  • Approval — Điều 32 owns.
  • Birth registry / event_type registry — Điều 0-G owns.

§2.5 Uniform assembly primitive (D2.5) — design proof for 500-step

Same primitive scales:

  • 2-step workflow → 2 workflow_step_def rows, each binding an IU brick or bundle, connected by workflow_step_relations.
  • 500-step workflow → 500 workflow_step_def rows (or N bundles each covering K steps), same workflow_step_relations connecting them, same MOW orchestration.

No separate schema, no separate component path. Long-workflow UI uses virtualization (see WS4 §6.3). Sentinel: workflows.step_count distribution covers full range without a sibling workflow_long_step_def table.

§2.6 IU version policy (D2.6 + OD15) — design at requirement level

  • Active workflow_run pins IU version. Step run captures pinned_iu_version_id at step entry. Any IU edit after that does NOT affect the running step (no in-flight surprise).
  • New workflow_run picks per policy. Per-workflow iu_pin_policy column (paper) on workflow_def: pin (default) / auto_upgrade_minor / auto_upgrade_major_with_approval / hybrid_per_step.
  • Upgrade in flight blocked. Only governance-approved migrations move an active workflow_run to a new IU version (rare; Điều 32 + Điều 30 reversibility).
  • Bundle versioning composes. An IU bundle has its own version; bundle version pins members. Migrating a bundle version migrates all bound steps consistently.

Default per OD15: pin for all workflows; opt-in upgrade per workflow. Future flexibility preserved.

§2.7 Editing IU does not require touching multiple tables

Edit lifecycle:

  1. Author edits IU → new iu_version row + iu.edited event.
  2. KG impact analysis (Rev2 §9) lists active workflows using prior version — surfaces in governance UI (vw_iu_impact_analysis(iu_unit_id, new_version_id)).
  3. Per workflow policy (§2.6), upgrade rolls forward — or stays pinned.
  4. Render layer always pulls pinned version for active runs; new runs pick per policy.

Sentinel: editing an IU never requires UPDATE on workflow_step_def, tasks, iu_notification_event, etc.


§3. IU as Process Brick — 11 fields (Rev2 §3)

§3.1 Brick fields (design schema sketch)

These fields are exposed per IU through information_unit row + binding tables — most live on information_unit itself; some derive from joins.

Field Storage location Vocab / type Source
iu_unit_id information_unit.iu_unit_id [VL] text PK row 1
iu_version_id iu_version.iu_version_id [VL] uuid row 1
iu_role_in_process new column on iu_process_binding (proposal) or denormalized on IU enum: instruction | decision_gate | input_contract | output_contract | policy | checklist | SOP | validation_rule | event_hook | report_context new vocab dot_config vocab.iu_role_in_process.*
assembly_slot new iu_assembly_slot_registry (paper) enum per parent role (MOW step slot / MOT region / MOIT field group / MOUT block) row 27 iu_three_axis_envelope (axis source for slot resolution)
precondition_config new on iu_process_binding jsonb (config DSL) → references trigger/guard registries row 4 IU trigger model
postcondition_config new on iu_process_binding jsonb (emitted events + output contracts + next-step signals) row 4
io_contract_refs new on iu_process_binding jsonb (refs to MOIT/MOUT schema rows) rows 28-31 (CRS-gated)
executor_class_ref new on iu_process_binding text FK → executor_class_registry row 14, row 20, G3
event_contract_ref new on iu_process_binding text[] FK → event_type_registry row 10
kg_edge_refs derived view over iu_kg_edge text[] row 21 (KG edges)
governance_state iu_lifecycle_log derived current state enum: proposed | approved | active | deprecated | archived row 8

iu_process_binding is a new binding table (paper) keyed by (iu_unit_id, role_in_process, scope_ref) so the same IU can have different process roles in different contexts (e.g. instruction in MOT, validation_rule in MOIT).

§3.2 Role-in-process taxonomy

Role Meaning Typical binding sites
instruction The "how-to" content for a step/task MOT region 4; Standard Process View step body
decision_gate A binary/multi-way decision the workflow must resolve MOW branching condition
input_contract What input the step requires MOIT form schema source
output_contract What output the step must produce MOUT block schema source + postcondition event payload
policy A constraint / rule applied to the step Step guard predicate config
checklist An enumerated list of items to verify MOT region 4 (rendered as checkbox UI)
SOP Standard Operating Procedure pack Multi-step bundle scope
validation_rule Server-side rule applied to input/output MOIT validation; MOUT computed field
event_hook Trigger / consumer mapping at IU level Producer registration; subscriber registration
report_context Reporting / aggregation context MOUT view definition

Vocab lives in dot_config vocab.iu_role_in_process.* (paper). Adding a new role is a Birth Registry act (Điều 0-G).

§3.3 Precondition / postcondition config

Precondition config (paper DSL):

{
  "kind": "all_of",
  "items": [
    { "kind": "step_state", "step_def_id": "<id>", "state": "completed" },
    { "kind": "trigger_event", "event_type": "external.callback_received", "matcher": { "tag": "vendor_invoice" } },
    { "kind": "time_gate", "after": "PT2H" }
  ]
}

Postcondition config (paper DSL):

{
  "emit_events": [{ "event_type": "step.completed", "fields": ["iu_unit_id", "step_run_id"] }],
  "output_contract_ref": "mout.invoice_review_summary",
  "next_step_signals": [{ "to_step_def_id": "<id>", "kind": "ready" }]
}

Validation: precondition config validated at workflow_def proposal-accept time (fn_workflow_def_validate). Trigger events referenced must exist in event_type_registry. Step refs must exist in workflow_step_def.

§3.4 Uniform primitive (D2.5) — design schema

workflow_step_def (extension columns, paper):

workflow_step_def
  step_def_id              uuid PK
  workflow_def_id          uuid FK
  step_label               text
  step_kind                text   -- 'iu' | 'bundle' | 'assembly_view' | 'task_template'
  binding_iu_unit_id       text   nullable
  binding_bundle_id        text   nullable
  binding_assembly_view_id text   nullable
  binding_task_template_id uuid   nullable
  mandatory                bool   default true
  optional                 bool   default false
  iu_pin_policy            text   -- 'pin' | 'auto_upgrade_minor' | 'auto_upgrade_major_with_approval' | 'hybrid_per_step' (overrides workflow_def default)
  state_machine_id         text   FK -> state_machine_def
  deadline_policy_jsonb    jsonb
  pic_assignment_policy_jsonb jsonb
  ...

Exactly one of binding_iu_unit_id | binding_bundle_id | binding_assembly_view_id | binding_task_template_id is non-NULL — enforced by check constraint (paper).

§3.5 KG bridge (Rev2 §9 + §3 kg_edge_refs)

iu_kg_edge (existing, rev1 §1) records semantic edges. Bridge to MOW/MOT:

  • Workflow author can request KG suggestions for "what other IUs are typically used together" → query iu_kg_edge + iu_usage_evidence (paper, see 03-event-5layer-… §9).
  • KG proposals (add edge / bundle / split / merge / re-parent / no-action) land in the generic proposal table (WS4 §8) — never auto-mutate registry.
  • IU kg_edge_refs field is a derived view over iu_kg_edge; not a stored column.

Sentinel: KG never writes workflow_registry, iu_process_binding, or iu_bundle_* directly — only via proposal rows.

§3.6 IU does NOT own execute logic (Rev2 §3 boundary)

information_unit and its bindings carry stable knowledge + typed relations + contracts + governance metadata. Runtime execution lives in:

  • MOW (orchestration — choose next step) — but MOW does not own executor either.
  • Executor class (DOT / SQL / AI / Human / External / Notification / Render) — actually executes.
  • MOT envelopes the task and calls executor class.

Sentinel: no DDL or function row stores executor code inside information_unit / iu_version.

§3.7 IU Bundle / Step Pack (Rev2 §4)

iu_piece_collection + iu_piece_membership + iu_collection_template_* [VL row 26] mapped to bundle:

Concept Existing table Bundle role
Bundle id + version iu_piece_collection (extend with bundle_version) Stable bundle pointer
Member IUs + order iu_piece_membership (with ordinal, member_role) N IU members + slot order + typed role
Template (reusable bundle shape) iu_collection_template_* Bundle template for reuse
Governance state iu_lifecycle_log (extended scope) Lifecycle

Bundle binding modes (Rev2 §4 R4.4):

  • Mode (a) step_kind='iu' — single IU brick binding.
  • Mode (b) step_kind='bundle' — IU bundle binding (multiple IUs with typed roles).
  • Mode (c) step_kind='assembly_view' — typed IU assembly view (e.g. all IUs of role instruction with tag vendor_review).
  • Mode (d) step_kind='task_template' — IU-backed task template (defines task envelope + bound IU(s)).

Sentinel: every workflow_step_def row has exactly one of the 4 binding refs populated; no body text.

§3.8 Bundle versioning + governance

iu_piece_collection (extension)
  bundle_id            uuid PK
  bundle_version       text  semver
  governance_state     text  -- 'proposed' | 'approved' | 'active' | 'deprecated' | 'archived'
  active_active_unique boolean -- partial index ensuring 1 active per bundle_id
  …

Bundle bump = new version row + governance proposal + Điều 32 approval if active_workflow_run count > 0 for prior version.


§4. 4 Mothers binding map

§4.1 MOW — IU Assembly Orchestrator binding

Concern Design PG substrate Reuse
Workflow graph workflow_def + workflow_step_def + workflow_step_relations workflows + workflow_steps + workflow_step_relations [VL row 16] reuse
Workflow runtime workflow_run + step_run (paper) reuse workflows for def, add workflow_run for runtime — paper-only; concrete shape in Phase 1 extension
Step binding workflow_step_def.binding_* (4 modes — §3.7) extension columns extension
Branching condition workflow_step_relations + condition config jsonb reuse reuse
Parallel branches workflow_step_relations with parallel_group_id extension extension
Sub-workflow boundary workflow_step_def.binding_sub_workflow_def_id (mode addition) extension extension
Proposal mode workflow_change_requests [VL row 17] reuse reuse
Categories / classification workflow_categories [VL row 18] reuse reuse
Long-running snapshot / replay workflow_run_snapshot (paper, derived) extension extension
Resume safety step_run.pinned_iu_version_id + replay events extension extension

Boundary: MOW orchestrator (process / function) reads workflow_def, fires step ready events, listens for step completed events, advances graph. MOW does not own queue (job_queue lives under Điều 45), does not own IU body (Điều 38/39), does not own approval (Điều 32).

Sentinel: MOW source contains zero IU body writes; MOW source has zero approval logic; queue inserts go through Layer 2 broker dispatch (§4 of 03-event-5layer-…).

§4.2 MOT — IU-Backed Task Envelope

4 UI regions (Rev2 §5.2) render from refs, not copies:

Region Content source
Header task_run metadata (id, PIC, deadline, status, state_code, waiting_facet, trace_id)
Input (region 1) MOIT contract referenced by IU brick / bundle binding → <MOITForm formId contextRef />
Reference (region 2) MOUT contract referenced → <MOUTBlock blockId contextRef />
Instruction (region 3 according to brief §5.2 (header/input/reference/instruction); we adopt the same ordering) IU or IU bundle render via render_iu_body(...)

Format declared in config: text / video / audio / sơ đồ (declared per IU binding via render_format field).

Automated task envelope = same task_run row, no UI; executor leases and runs.

MOT is not an executor (Rev2 §11.5 + §5.2). MOT calls executor class registered in executor_class_registry (see 03-event-5layer-… §5.1).

MOT does not own approval (Rev2 §5.2 + §11). Approval calls go to Điều 32 surface.

PG substrate:

Concern Design PG substrate Reuse
Task def (template) task_def (paper) reuse tasks for runtime; add task_def for templates — Phase 1 extension
Task runtime task_run (paper) reuse tasks + add task_run extension
Checkpoints task_checkpoints [VL row 19] reuse reuse
Comments task_comments [VL row 19] reuse reuse
State machine state_machine_id per task_run new state_machine_registry extension
IU binding task_def.binding_iu_unit_id / binding_bundle_id / binding_assembly_view_id extension extension

§4.2a MOT / JFT Task Envelope Matrix (MP-D14, rev3)

Extends §4.2: an MOT envelope is materialized from a task_template row × runtime context, not assembled ad-hoc per task family. Six regions are explicit (rev3 adds region 5 Action and region 6 State/Deadline/Escalation as named regions, see 08-… §6.1).

Matrix row binding (paper task_template; full schema in 08-… §6.2):

Column Binds
instruction_iu_or_bundle_ref IU / IU bundle for region 4 (Instruction), rendered via render_iu_body (MP-D6)
moit_input_contract_ref input_form_registry row (MP-D7 CRS-gated) for region 1 (Input)
mout_reference_contract_ref output_table_registry row (MP-D7 CRS-gated) for region 2 (Reference/Output)
trigger_subscription_ref event_subscription row (03-… §4.2) — decides WHEN the task materializes (JFT: only when actionable)
assignee_policy_ref assignee_policy (paper) — decides WHO gets the task
deadline_policy_ref deadline_policy (paper) — populates task_run.deadline
executor_class_ref executor_class_registry (03-… §5.1) — actual executor (MOT remains NOT-an-executor per §4.2)
state_machine_id state_machine_registry (02-… §2) — typically the 9-state floor
dashboard_target personal_jft | shared_team | governance_problem_queue | agent_ops_console (per 08-… §7.2 four surfaces)
permission_scope_ref Điều 37 v3.3 permission scope
escalation_policy_ref escalation_policy (paper) — fires on overdue / cannot_complete / blocked-threshold (MP-D4)

JFT semantics binding (per 08-… §6.3): right task / right person/agent / right time / pushed only when actionable / disappears when done / auto deadline + escalation.

Exact input parameter list required BEFORE matrix can safely mass-generate tasks (per 08-… §6.4):

  1. task_template table (paper, Phase 2 DDL).
  2. assignee_policy registry (paper, Phase 2 DDL; enumerable, no free-form code per template).
  3. deadline_policy registry (paper, Phase 2 DDL; enumerable).
  4. escalation_policy registry (paper, Phase 2 DDL).
  5. permission_scope registry (Điều 37 v3.3 — survey existing).
  6. executor_class_registry (Phase 1, 06-… §S18).
  7. state_machine_registry (Phase 1, 06-… §S18).
  8. event_subscription with delivery_kind='job_dispatch' (exists in design).
  9. CRS gate close for input_form_registry (MOIT) + output_table_registry (MOUT) — Phase 1 survey (G7, 06-… §S16). MP-D7 strict form: no executable artifact references these by literal name until VL or shape-adapter.
  10. Idempotency key per materialization: (task_template_id, trigger_event_id) UNIQUE on task_run.
  11. Audit row per materialization: task_run.materialized_from_template_id + task_run.trigger_event_id + correlation_id.

Boundary preserved (§4.2 binding unchanged): MOT is NOT an executor; MOT does NOT own approval; MOT does NOT own state machine; MOT does NOT own queue/event; MOT does NOT own IU body.

Sentinel: every task_run row references both task_template_id AND trigger_event_id; orphan rows refused. Every MOT envelope render fetches all six regions through backend gateway; Nuxt holds no template logic. The matrix is the only path for mass task generation.

§4.3 MOIT — IU-Context-Aware Input

Concern Design PG substrate CRS gate
Field definitions field_registry [CRS row 28] survey-gated G7
Form definitions input_form_registry [CRS row 29] survey-gated G7
Per-field IU link field_registry.iu_unit_id (paper) survey-gated; need to verify field_registry shape exists G7
Form binding to IU-task context input_form_registry.context_kindtask_def | step_def | iu_bundle survey-gated G7
Direct vs staging policy form_submission_policy (paper) — direct | staging_then_approve extension
Validation validation_rule (IU role) refs extension
Nuxt component <MOITForm formId contextRef /> zero logic

Critical CRS gate: WS8 §S1 must survey field_registry / input_form_registry before any of these design extensions become real. If survey shows the registries differ from rev1 §6.3 inferred shape, design must adapt before Phase 1. MP-D7 binding (06-… §S16): no executable artifact may reference these registries by literal name until VL or Điều-32-approved shape-adapter.

DOT assembly: registry → DOT function checks fields against vocab → assembles form structure + validation. Existing pattern (rev1).

§4.3a MOIT Staging Input Architecture (MP-D11, rev3)

Input minimalism / context maximization (per 08-… §3): the user provides as little as possible; backend captures as much context as possible.

Nuxt (input shell, zero business logic)
    ↓ POST submit (text + audio_ref + attachments_ref + click-context refs)
Backend input gateway (Node service; Điều 28 + Điều 33 v2.1)
    ↓ envelope shape + permission filter + size cap (MP-D8)
Staging row  →  input_submission (paper schema, `08-…` §3.2)
    │   raw_text + audio_ref + attachments_ref + captured_context_jsonb
    │
    ├── processing_branch = 'direct'   → worker.canonicalizer → PG canonical
    │      (only artifact kinds permitted by input_routing_policy:
    │       task_comment, audit_note, input_submission_ack, ...)
    │
    └── processing_branch = 'workflow' → workflow_change_requests OR generic proposal
           (per OD2 / `06-…` §S2; Điều 32-gated)

Bindings (verbatim from 08-… §3 + MP-D11):

  • Read path unchanged: PG → Directus → Nuxt. MOIT form rendered by <MOITForm formId contextRef /> zero-logic component; data fetched from backend gateway only.
  • Write path is staging-first: Nuxt POST → gateway → input_submission. Nuxt never writes PG directly. Directus never carries SoT; Directus may host a triage view over input_submission.
  • Refs-only events for input.* (see 03-… §3.4a register-before-emit). MP-D8 deny-list applies; raw text / audio / attachment bytes never travel in event payloads.
  • Routing policy: input_routing_policy (paper, 08-… §3.3) decides direct vs workflow per input_kind + actor role + target kind.
  • IU/PG/queue checks for input/proposal (cross-verified in 08-… §9): no IU body duplication in staging or events; queue carries refs only; canonicalization happens through DOT pair (Điều 35) for governance-relevant writes; IU edits always route through Điều 38/39 author lifecycle (never direct from staging).

Direct vs staging policy column on input_form_registry (paper extension form_submission_policy previously listed) is replaced by input_routing_policy.default_branch in the rev3 design — the policy is per input_kind at the gateway, not per form, so the same form may submit either direct or workflow depending on whether the user is making a Kaizen suggestion or a normal data entry.

Sentinel:

  • Every MOIT submit produces exactly one input_submission row and at most one downstream canonical row (task_comments / audit_note / etc.) OR one proposal row (workflow_change_requests / proposal). Never both, never multiple canonical mutations from one submit.
  • Nuxt input shell source contains zero PG writes; zero direct Directus writes for canonical artifacts.
  • Audio / attachment bytes appear in event payloads zero times (MP-D8 extension to input.* events).

§4.3b Direct canonicalization guardrails + Kaizen anti-noise + input lineage (MP-D18 + MP-D19, rev4)

§4.3a routes direct vs workflow per input_kind. MP-D19 hardens the direct branch; MP-D18 hardens Kaizen intake at scale; both stay backend (no new user-facing complexity). Full design in 09-… §5 + §6.

Direct canonicalization allow conditions (ALL must hold; 09-… §6.2). The worker.canonicalizer admits a direct write only if: actor_has_permission · target_kind_allowed_by_input_routing_policy · schema_valid · size_within_limit · no_structural_change · no_law/registry/IU_body_mutation · no_approval_required_effect · idempotency_key_present · audit_enabled · retention_policy_attached · PII/security_classification_checked.

Deny conditions (ANY forces workflow branch or refusal; 09-… §6.3). Direct is denied if it: changes the workflow graph · changes IU canonical body · changes a field/form/output registry · changes law/governance policy · affects other departments beyond permission scope · requires approval · transcription confidence below threshold · spam/abuse/rate-limit. A denied-but-legitimate input reroutes to the workflow branch (proposal + Điều 32); an illegitimate one is refused with input.rejected + reason.

Data lineage (staging ↔ canonical; 09-… §6.4). Forward link input_submission.canonical_target_ref = {kind,id}; back link <canonical>.source_staging_id where the table permits (e.g. task_comments.source_staging_id); audit row joins staging_id ↔ canonical write ↔ trace_id so vw_audit_event_timeline(trace_id) shows the full path; rejection_reason/validation_reason_code retained even after close; IU-affecting corrections always reroute through Điều 38/39 author lifecycle, never a direct staging rewrite.

Retention / security (09-… §6.5). dot_config retention.staging.{raw_text,audio,attachment}; input_submission.security_classification ∈ {public, internal, confidential, pii} set at gateway (required before direct write); below-threshold transcription (dot_config transcription.min_confidence default 0.6) routes to human review, never auto-direct.

Kaizen anti-noise relation to IU/MOIT/MOUT/MOT (MP-D18, 09-… §5). Kaizen review lifecycle (received → auto_classified → duplicate_suspected → needs_clarification → accepted_for_review → rejected_noise|converted_to_proposal → approved → merged → rejected_by_reviewer → measured_after_change → archived) and duplicate detection (target_artifact_ref · intent · hierarchy_context · actor_department · raw_text_semantic_hash · audio_transcription_hash · time_window · existing_open_proposal_refs) are backend-only. A Kaizen targeting an IU/MOIT-field/MOUT-block/MOT-region lands as a proposal (non-workflow) row; an approved IU-narrative change is authored via Điều 38/39 producing a new iu_version — never a direct staging rewrite of IU body. Duplicate hashes are over the staging suggestion text, never canonical IU body.

Sentinel (MP-D18 + MP-D19):

  • No direct-branch write unless all allow conditions hold; any deny condition forces workflow branch or refusal.
  • Every direct write has a lineage pair (staging_idcanonical_target_ref) + retention + security classification.
  • Direct writes never touch IU body / registries / workflow graph / law (the four §4.3b deny "changes …" conditions).
  • Kaizen never mutates IU body directly; IU edits route through Điều 38/39 author lifecycle; duplicate hashes are over staging text only.

§4.4 MOUT — IU-Backed Output Views

Concern Design PG substrate CRS / OD
Output / report blocks output_table_registry [CRS row 30] survey-gated G7
DOT functions for aggregation dot_function_registry [CRS row 31] survey-gated; OD13 ownership G7, OD13
Block binding to IU source output_table_registry.iu_source_id (paper) survey-gated G7
SQL link iu_sql_link [VL row 5] reuse
Computed fields generated columns / materialized views / DOT functions (per Rev2 §5.4) reuse + extension OD13
Inline (in MOT region 2 reference) <MOUTBlock blockId contextRef /> zero logic
Matrix independent route <MOUTTable tableId contextRef /> zero logic
Realtime through realtime gateway (§7 of 03-event-5layer-…) gateway
Permission filter backend route on every MOUT fetch gateway

OD13 default kept: MOUT-aligned namespace for dot_function_registry (e.g. dot.fn.mout.invoice_total). Registry SoT in PG. See 06-… §S13. MP-D7 binding (06-… §S16): no executable artifact may reference output_table_registry / dot_function_registry by literal name until VL or Điều-32-approved shape-adapter.

§4.5 Directus boundary (Rev2 §12 row 23)

Directus = API/admin/staging only:

  • Allowed: admin UI for IU/registry CRUD via Directus collection wrappers (governed), staging data for proposal rows pre-approval.
  • Forbidden: Directus realtime as app event plane (Rev2 §15 L2/L6 + boundary); Directus flows running app workflow logic (legacy flows respected but not extended).
  • Sentinel: any Directus row that mirrors a PG registry row must point back to PG primary row (Hiến pháp NT13).

§4.6 No-Double-Ownership — design check

Concern Owner This design's relation
Queue / event core / executor boundary / state machine ≥9 / heartbeat Điều 45 consume / call only
IU axis / compose / split / merge / SQL link / structure ops Điều 38 + Điều 39 reference / bind only
Approval quorum Điều 32 call API only
DOT lifecycle Điều 35 v5.2 call DOT pair only
UI render shell Điều 28 / S178 implement only as render
4-DB / 3-layer Điều 33 v2.1 route Nuxt → backend gateway → PG/Directus
Birth registry Điều 0-G register IU / event_type / executor_class / state
Governance org Điều 37 v3.3 same UI / backend filter
Reversibility Điều 30 every extension has rollback
Integrity / audit Điều 31 v1.2 every binding has audit row
Assembly First Điều 7 OSS as adapter only
4 Mothers app layer Future Điều XX only NEW concern owned by this design

§4.7 4 Mothers as governed object factories (MP-D25, rev5)

§4.1–§4.5 bind each Mother as a khuôn đúc around IU. MP-D25 formalizes the same four as governed object factories at industrial scale: each is registered as an Điều 37 governance_registry row type='factory' with an output_target (user/system/assembly) and governance_relations produces/owner edges to its output classes. This reuses the pre-existing factory agency type in Điều 37 — no new factory machinery. Full matrix + birth/template/event/governance contracts + health gates in 10-… §5.

can_create / can_reference / must_not_own (binding):

Mother output_target can_create can_reference must_not_own
MOW assembly workflow_def, workflow_step_def, workflow_step_relations, workflow_change_request, hierarchy-node projection, MOW canvas product config IU/bundle, executor_class_registry, event_type_registry, state_machine_registry, tier_registry IU body, executor runtime, event core, queue core, approval law, Nuxt template lifecycle
MOT user task_template, task_run, task_checkpoint, task_comment, JFT dashboard product config IU/bundle, executor_class_registry, state_machine_registry, MOIT/MOUT contracts, assignee/deadline/escalation policy executor, queue core, state machine core, approval law, IU body
MOIT system input contract (input_form_registry), field-group binding, staging route/config (input_routing_policy), input_submission policy field_registry, IU (per-field), task_def/step_def context canonical business table, Nuxt form code, approval law, event core
MOUT user output/reference/report contract (output_table_registry), read-only projection config, report-block product config dot_function_registry, iu_sql_link, IU source canonical data source, mutable workflow state, Nuxt report code, event core

Owner law per child object. workflow_def/step → future Điều XX (app) + species SPE-WKF/SPE-WFS; task_template/run → future Điều XX + SPE-TSK; form/output registries → future Điều XX + Điều 36 collection birth; state machine → Điều 45; render → Điều 28; birth → Điều 0-G; approval → Điều 32; DOT mutation → Điều 35. A Mother owns the binding/shape, never the content/substrate/approval/birth/template lifecycle (invariant 4 at factory granularity).

Required contracts per output (all four). birth contract (10-… §4 Industrial Birth Contract: birth_registry + species + collection + governance_role) · template contract (10-… §3.1: each UI surface a design_templates row + product) · event contract (register-before-emit for event-emitting outputs) · governance contract (governance_registry factory row + produces edges + law_jurisdiction) · DOT/API mutation path (Điều 35 DOT pair + Điều 32 APR; never raw psql).

IU relation to factory outputs. Every factory output that carries narrative references an IU/bundle via render_iu_body(...) (§2.3, MP-D6) and never copies body (invariant 1). Outputs that propose an IU change route through the generic proposal table → Điều 38/39 author lifecycle → new iu_version (never a direct/staging rewrite of IU body — MP-D18/MP-D19). The factory produces shells + bindings; IU stays the singleton content SoT.

Sentinel (MP-D25). Each Mother has a governance_registry type='factory' row + output_target + produces edges; each output class appears under exactly one owner law; must_not_own lists are grep-checkable (zero IU-body writes / approval logic / queue inserts in MOW/MOT source; zero canonical-table create in MOIT; zero mutable write in MOUT). No factory output reaches active without a birth record (10-… §9 reject list).


§5. IU version policy (OD15 default kept)

§5.1 Per-workflow_def iu_pin_policy

workflow_def.iu_pin_policy:
  'pin'                                  -- default; active workflow_run pins versions
  'auto_upgrade_minor'                   -- auto-upgrade minor version (additive changes)
  'auto_upgrade_major_with_approval'     -- major upgrade only with Điều 32 approval
  'hybrid_per_step'                      -- per-step override via workflow_step_def.iu_pin_policy

Per-step override available for hybrid_per_step workflows.

§5.2 Bundle version pins members

When a bundle version is pinned, all its IU member versions are also pinned (transitively). Bundle bump produces a new pin set; old runs stay on prior set.

§5.3 Edit IU during active run — no in-flight surprise

Step_run captures pinned_iu_version_id at step entry (T1 / T2 in 02-step-state-machine-… §4). Subsequent IU edits create new versions but do not affect the pinned step. Render layer fetches by pinned version.

§5.4 Migration of active run to new IU version

Migration scenario:

  1. Critical bug in IU body (e.g. instruction wrong).
  2. Author releases hotfix IU version.
  3. Operator initiates "rolling upgrade" — proposal: migrate active step_runs to new pin.
  4. Điều 32 approval required.
  5. On approval, step_run.pinned_iu_version_id updated in single TX + emits step.iu_version_migrated.
  6. Audit row in iu_lifecycle_log records actor + approval ref + prior version.

Sentinel: zero step_run.pinned_iu_version_id UPDATE without an approval_id reference in the same audit row.


§6. Governance lifecycle for IU artifacts

§6.1 IU governance state machine

States: proposed → approved → active → deprecated → archived.

Transitions:

From To Actor Trigger Audit
(none) proposed author RPC iu_propose iu_lifecycle_log: created
proposed approved reviewer (Điều 32) RPC approve iu_lifecycle_log: approved + approval_id
approved active system governance promote iu_lifecycle_log: activated
active deprecated governance RPC deprecate (with reason_code) iu_lifecycle_log: deprecated + reason
deprecated archived system timer / governance iu_lifecycle_log: archived
active active author + Điều 32 RPC edit_active (creates new version) iu_lifecycle_log: edit_active + new_version_id

This is the IU-scope state machine, distinct from the step/task state machine in WS4. Same state_machine_registry substrate.

§6.2 Bundle governance

Bundle parallels IU governance (proposed/approved/active/deprecated/archived). Bundle activation requires all member IUs to be active.

§6.3 Audit ledger

iu_lifecycle_log [VL row 8] records all transitions. New fields (paper) for binding to 4 Mothers context: affected_workflow_def_ids, affected_step_run_ids (for in-flight migration audit).


§7. Usage Evidence schema sketch (Rev2 §10 — bridge to KG)

See 03-event-5layer-realtime-dlq-design.md §9 for derivation. Here the role of the table from the IU side:

iu_usage_evidence
  evidence_id              uuid PK
  signal_kind              text   -- 8 signal classes
  iu_unit_id_a             text
  iu_unit_id_b             text nullable    -- pair signals
  workflow_run_id          uuid nullable
  step_run_id              uuid nullable
  evidence_payload_jsonb   jsonb
  evidence_window_start    timestamptz
  evidence_window_end      timestamptz
  evidence_strength        float   -- normalized
  computed_at              timestamptz
  computed_by_fn           text

KG feedback reads from this table and emits proposals. Sentinel: KG never reads event_outbox / job_queue directly — only iu_usage_evidence.


§8. Cross-references

  • 9-state floor / transitions / workflow UI / governance UI → 02-step-state-machine-and-workflow-ui-design.md.
  • Event 5-layer / executor class registry / heartbeat / idempotency / realtime gateway / DLQ → 03-event-5layer-realtime-dlq-design.md.
  • OSS labels for any tool that might encroach on IU / 4 Mothers boundary → 05-oss-candidate-strategy-rev2.md.
  • IU version policy default (OD15), proposal table OD2, executor_class_registry ownership OD3, dot_function_registry OD13, generic vs per-domain proposal OD2 — see 06-open-decisions-and-readiness.md.

§9. Acceptance criteria for this WS (WS2 + WS3)

A1. IU-centered doctrine §2 preserves 2..500 uniform primitive; no parallel workflow track. A2. IU brick fields §3.1 cover Rev2 §3 11 fields with PG substrate + vocab anchors. A3. IU bundle §3.7 maps to existing iu_piece_collection* row 26 [VL]; no new substrate when reuse fits. A4. 4 Mothers binding §4 reuses workflows, workflow_steps, workflow_step_relations, workflow_change_requests, tasks, task_checkpoints, task_comments, workflow_categories [VL]; introduces extension columns only. A5. CRS rows (§12 rows 28-31) gated by survey in WS8 §S1; design depends on no CRS row prior to verified_live. MP-D7 strict form applies in §4.3 + §4.4: no executable artifact references these registries by name until VL or Điều-32-approved shape-adapter. A6. IU version policy §5 default pin; per-workflow override; migration requires Điều 32 approval; sentinel for unauthorized migration. A7. No-double-ownership §4.6 preserved — only NEW concern = 4 Mothers application layer (future Điều XX). A8. KG bridge §3.5 — proposals only, never auto-mutate. A9. Render layer §2.3 — IU body singleton via render_iu_body(...) call sites. MP-D6 binding: pre-render checks (iu_version_exists, governance_state_allowed, permission_filter_backend, context_scope_allowed) + mandatory iu.rendered audit event + cache key includes permission_scope_hash + notification render uses recipient-scope permission. A10. No PG mutation; no migration; no DOT command run; no law enactment; all schemas paper-only. A11. (rev4 MP-D18 + MP-D19) §4.3b direct canonicalization allow/deny conditions + data lineage (staging↔canonical) + retention/PII/security + Kaizen anti-noise lifecycle relation to IU/MOIT/MOUT/MOT; IU body never mutated from direct branch or Kaizen. Full design 09-… §5 + §6. A12. (rev5 MP-D25) §4.7 each Mother formalized as a governed object factory (Điều 37 governance_registry type='factory' + output_target + produces/owner edges) with explicit can_create / can_reference / must_not_own + owner-law-per-child + birth/template/event/governance/DOT contracts + IU-reference-not-copy. No factory output reaches active without birth (10-… §5 + §9).

End WS2+WS3 design.

Back to Knowledge Hub knowledge/dev/design/v0.6-iu-4mothers-event-foundation-rev2/04-iu-centered-4mothers-binding-design.md