---
title: Build the X12 envelope hierarchy
summary: Convert a flat, index-ordered segment list into the interchange/functional-group/transaction-set/hierarchical-level tree.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-09-15
library: SAIF.Framework.Common.Files
reference_type: package
operation_id: OP-08
trigger: EdiFile.SetSegments, EdiFile.Add of a control segment, or first access to EdiFile.FunctionalGroups
---

# Build the X12 envelope hierarchy

`EdiFile.RefreshGroupings` and `EdiGroupParser` convert the flat segment list produced by [Parse EDI text into segments and elements](parse-edi-text-into-segments-and-elements.md) into the X12 envelope hierarchy: interchange header/trailer, then functional groups, transaction sets, hierarchical transactions, and hierarchical levels.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-08 |
| **Trigger** | `SetSegments`, `Add` of a control segment, or first access to `EdiFile.FunctionalGroups`. |
| **Inputs** | Flat segment list. |
| **Outputs** | `IFunctionalGroupContainer` tree. |
| **Primary components** | `EdiFile.RefreshGroupings`, `EdiGroupParser` |
| **Entry point** | `Common\SAIF.Common.Files\Edi\EdiFile.cs`, `Common\SAIF.Common.Files\Edi\Core\Parsers\EdiGroupParser.cs` |

## Steps

1. `RefreshGroupings` locates the first `ISA` segment and parses it into `IsaSegment` (`Header`), and the first `IEA` into `IeaSegment` (`Trailer`) ([BR-029](../business-rules.md#br-029-first-isa-and-iea-are-the-interchange-header-and-trailer)).
2. Functional groups are (re)built **only** when `ISA`, `IEA`, `GS` and `GE` are all present ([BR-030](../business-rules.md#br-030-functional-groups-built-only-when-all-four-control-segments-present)).
   - If not all present: skip group construction; `EdiFile.FunctionalGroups` remains unbuilt.
3. `EdiFile.Add(segment)` assigns `segment.Index = IndexingSequence.NextValue` (delegated `Sequence`), appends it, and re-runs `RefreshGroupings` when the segment id `IsIn("ISA","IEA","GS","GE")` (delegated: `SAIF.Framework.Common` → `IEnumerableExtensions.IsIn`) ([BR-031](../business-rules.md#br-031-every-added-segment-receives-the-next-sequential-index), [BR-032](../business-rules.md#br-032-adding-a-control-segment-re-derives-envelope-groupings)).
4. `CreateFunctionalGroups` calls `ParseSegmentGroup(file.Segments, "GS", 6)` — each `GS` starts a group keyed on element 6 (group control number); header = first `GS`, trailer = last `GE`; member `Segments` exclude `ISA`/`IEA`/`GS`/`GE` ([BR-033](../business-rules.md#br-033-control-segments-excluded-from-member-segments-collections), [BR-034](../business-rules.md#br-034-group-keys-derived-from-control-number-elements)).
5. `CreateTransactionSets` calls `ParseSegmentGroup(fg.Segments, "ST", 2)` — key is element 2 (transaction set control number); header `ST`, trailer `SE`; members exclude `ST`/`SE` ([BR-033](../business-rules.md#br-033-control-segments-excluded-from-member-segments-collections)).
6. `CreateHierarchialTransactions` calls `ParseSegmentGroup(ts.Segments, "BHT", 1)`, parses the `BHT` into `BhtSegment`, then partitions the remainder with `ParseSegmentGroup(htc, "BHT", "HL", 1)` and builds `HierarchialLevel` objects from each `HL` (key element 1), excluding `HL`/`ST`/`SE` from level members ([BR-033](../business-rules.md#br-033-control-segments-excluded-from-member-segments-collections), [BR-035](../business-rules.md#br-035-hierarchical-levels-nested-inside-hierarchical-transaction)).
7. `ParseSegmentGroup(parentGroup, segmentId, keyElement)` creates one `SegmentGroup` per matching segment, then moves every segment between that segment's index + 1 and the index before the next occurrence (or the last segment index) into the group via `MoveSegmentsToSegmentGroup`.
   - Helper lookups `GetNext`, `GetFirstInRange`, `GetLastInRange`, `FindInRange` all operate on `Index` ordering and return `0` when nothing matches ([BR-036](../business-rules.md#br-036-segment-group-ownership-determined-by-position)).
8. `EdiFile.FunctionalGroups` lazily caches the result of `CreateFunctionalGroups` on first access.

## Process flow

```mermaid
flowchart TD
	Start([RefreshGroupings triggered]) --> HeaderTrailer["Locate first ISA (Header)<br>and IEA (Trailer)"]
	HeaderTrailer --> Check{"ISA, IEA, GS, GE all present?"}
	Check -->|No| Stop([FunctionalGroups left unbuilt])
	Check -->|Yes| FG["CreateFunctionalGroups<br>ParseSegmentGroup(GS, element 6)"]
	FG --> TS["CreateTransactionSets<br>ParseSegmentGroup(ST, element 2)"]
	TS --> HT["CreateHierarchialTransactions<br>ParseSegmentGroup(BHT, element 1)"]
	HT --> HL["Partition HL segments into<br>HierarchialLevel objects"]
	HL --> EndOk([IFunctionalGroupContainer tree])
```

## Failure and edge-case behavior
- Missing any of `ISA`/`IEA`/`GS`/`GE`: the interchange still exposes its flat `Segments` collection, but `FunctionalGroups` is not built and no exception is raised ([BR-030](../business-rules.md#br-030-functional-groups-built-only-when-all-four-control-segments-present)).
- `ParseSegmentGroup`'s `GetNext`/`GetFirstInRange`/`GetLastInRange`/`FindInRange` helpers return `0` rather than a sentinel/null when no matching segment exists, so a malformed interchange with unmatched control segments can silently produce an empty or misaligned group rather than an error ([BR-036](../business-rules.md#br-036-segment-group-ownership-determined-by-position)).*
- `EdiGroupParser.ParseSegmentGroup(parentGroup, segmentId, segmentEndId, maxCount, segmentGroupKeyElement)` (the 5-parameter overload) is unreachable as implemented: its loop guard compares the group count against a negated `maxCount`, so it always breaks after the first group; the overload has no caller in this library.*

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts.

## Sources
- Common\SAIF.Common.Files\Edi\EdiFile.cs
- Common\SAIF.Common.Files\Edi\Core\Parsers\EdiGroupParser.cs
- Common\SAIF.Common.Files\Edi\Segments\IsaSegment.cs
- Common\SAIF.Common.Files\Edi\Segments\IeaSegment.cs
- Common\SAIF.Common.Files\Edi\Segments\GsSegment.cs
- Common\SAIF.Common.Files\Edi\Segments\GeSegment.cs
- Common\SAIF.Common.Files\Edi\Segments\StSegment.cs
- Common\SAIF.Common.Files\Edi\Segments\SeSegment.cs
- Common\SAIF.Common.Files\Edi\Segments\BhtSegment.cs
- Common\SAIF.Common.Files\Edi\Segments\HlSegment.cs
- Common\SAIF.Common\Extensions\IEnumerableExtensions.cs
