---
id: WF-MBR-STR-008
title: Load structure and configuration in bulk
trigger: >-
  A migration or import submits declared insert or upsert items for unit kinds, units, programs, types or
  packages.
product_area: membership
module: structure
revision: 1
status: draft
design_intent: proposed
implementation_evidence: partially-observed
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
inference: []
implements:
  - CAP-MBR-STR-020
moves: []
crosses:
  - SVC-PFM-DJE-membership-data-jobs
  - SVC-MBR-STR-structure
  - SVC-MBR-STR-configuration
idempotency: >-
  Upserts resolve existing records by supported identity, source crosswalk or unit code and update them
  through local services. Inserts reject existing records. A closing rebuild and read-only reconciliation can
  be repeated.
concurrency: >-
  Unit items acquire the workspace tree lock individually, but committed items can leave ancestry stale
  between calls and until the producer rebuilds. Reads and ordinary placement checks can therefore see earlier
  derived ancestry during an unfinished load.
hops:
  - 'n': 1
    actor_or_service: Data-job engine
    action: >-
      Use declared dependencies to place kinds before units and programs before types and packages; resolve
      each unit's parent from earlier identity, code or source mappings.
    anchor: 'services-membership:modules/data-jobs/services/operations/structure-data-operations.ts'
    seam: queue
    on_failure: Report an unresolved required parent as a blocked item.
    left_inconsistent: 'The blocked unit is absent, and dependent items cannot resolve it.'
    observer: the data job's item outcomes
    provenance: test
    source: >-
      services-membership:modules/data-jobs/tests/integration/services/operations/structure-data-operations.integration.spec.ts#the
      structure’s data operations in the database › blocks a unit whose parent has not been loaded, naming the
      field
  - 'n': 2
    actor_or_service: Structure data operation
    action: >-
      Under the tree lock, validate available kind and parent, create or replace the unit and write changed
      parent periods; do not rebuild ancestry or emit structural events.
    anchor: 'services-membership:modules/structure/services/tree/tree-loads.ts:loadUnit'
    seam: sync
    on_failure: >-
      Reject the item and roll back its transaction; continuation behavior belongs to the caller's batch
      execution.
    left_inconsistent: Earlier committed items can leave stale ancestry and depths until closing rebuild.
    observer: the data job's item outcomes
    provenance: test
    source: >-
      services-membership:modules/data-jobs/tests/integration/services/operations/structure-data-operations.integration.spec.ts#the
      structure’s data operations in the database › reports the closure stale before the rebuild after the
      load
  - 'n': 3
    actor_or_service: Configuration data operation
    action: 'Use ordinary configuration create or update services for program, type and package items.'
    anchor: >-
      services-membership:modules/configuration/services/data-operations/configuration-operations.ts:configurationDataOperations
    seam: sync
    on_failure: Classify the ordinary configuration refusal as an item failure.
    left_inconsistent: Committed independent items remain; dependent items can be blocked by missing records.
    observer: the data job's item outcomes
    provenance: observed
    source: >-
      services-membership:modules/configuration/services/data-operations/configuration-operations.ts:configurationDataOperations
  - 'n': 4
    actor_or_service: Data-job producer
    action: >-
      After unit loading, acquire the tree lock once and rebuild ancestry and depths, refusing a final depth
      of 32 or more.
    anchor: 'services-membership:modules/structure/services/tree/tree-loads.ts:rebuildTreeAfterLoad'
    seam: sync
    on_failure: A failed closing transaction retains the previous derived ancestry.
    left_inconsistent: Loaded parent references can disagree with derived reads until a successful rebuild.
    observer: the producer; reconciliation
    provenance: test
    source: >-
      services-membership:modules/data-jobs/tests/integration/services/operations/structure-data-operations.integration.spec.ts#the
      structure’s data operations in the database › rebuilds the closure once after the load, and reconciles
      the tree whole
  - 'n': 5
    actor_or_service: Data-job producer
    action: >-
      Compare parent references with open history, reconstructed ancestry, stored depth and permitted parent
      kinds; return counts and problems.
    anchor: 'services-membership:modules/structure/services/tree/tree-loads.ts:reconcileStructure'
    seam: sync
    on_failure: Report integrity problems without modifying or repairing data.
    left_inconsistent: Reported inconsistencies persist until a producer corrects data or rebuilds.
    observer: the producer
    provenance: observed
    source: 'services-membership:modules/structure/services/tree/tree-loads.ts:reconcileStructure'
branches:
  - 'No bulk operation is declared for status reasons, policy sets or program requirements.'
  - A load cannot change an existing unit's kind.
waits:
  - The producer must finish unit items before the final rebuild.
evidence:
  - >-
    services-membership at 5994c270: modules/structure/services/tree/tree-loads.ts;
    modules/data-jobs/services/operations/structure-data-operations.ts;
    modules/configuration/services/data-operations/configuration-operations.ts;
    docs/migrations/structure/README.md (data operations; the data-job engine is not wired here).
controls: [TC-AVL-002, TC-AVL-003, TC-AVL-004, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, TC-CHG-001, TC-CHG-002, TC-CHG-003, TC-CHG-004, TC-CRY-001, TC-CRY-002, TC-CRY-003, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-DAT-005, TC-DAT-007, TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-IAM-006, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-MON-002, TC-MON-004, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-SEC-001, TC-SEC-004, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-TEN-004]
---

# Load structure and configuration in bulk

## What It Does

Bulk declarations reuse record services while deferring repeated ancestry rebuilds. Units load in dependency order, and the producer must run one closing rebuild and reconciliation. Configuration items keep ordinary save validation rather than bypassing it.

## The Flow

```mermaid
sequenceDiagram
  participant Producer
  participant Structure
  participant Configuration
  Producer->>Structure: kinds and parent-first unit items
  loop each unit item
    Structure->>Structure: lock, save details and parent period
    Structure-->>Producer: item result with ancestry deferred
  end
  Producer->>Configuration: programs, types and package items
  Configuration-->>Producer: ordinary save outcomes
  Producer->>Structure: closing rebuild
  Producer->>Structure: integrity reconciliation
  Structure-->>Producer: counts and problems
```

## When Something Fails

Each failed item leaves its own transaction unapplied, but earlier successful items remain. The deferred ancestry can affect descendant reads and officer visibility until rebuilding succeeds. No local completion hook guarantees the rebuild, and the end-to-end data-job submission path is not established by these item handlers.

## Open Design Questions

Architecture should decide whether a closing rebuild belongs in guaranteed job completion and how live traffic is excluded during loading. Additional bulk verbs and equivalent placement validation require product direction.
