Skip to main content

Assembly

Assembly is the post-run compose step. Where the per-document phases each handle one document, assembly works across documents: it groups them and folds each group into a single composed record. It runs once, after every document in the pipeline reaches a terminal state, so it composes the resolved values (the latest cell version per field), not raw extraction. Assembly is how a pipeline turns many related documents into one authoritative row.

Assembly is driven by two fields you name in the rail. The grouping field decides which documents belong together. Within each group, the anchor field identifies the Anchor document: the one whose anchor field matches a configured anchor value. The anchor seeds the composed record, and the other documents in the group act as Amendments that override selected fields per the rule. A group with no anchor, or more than one, is a conflict and composes nothing, so an ambiguous group is surfaced rather than guessed.

The composed overrides are written back onto the anchor record as new cell versions with an assembly source. This means the anchor cell version history reads extraction, then resolution, then assembly, in order, and each assembly cell records the override detail: the previous value, the source document it came from, and the rule that produced it. The version history is the assembly audit trail. The full composed product is also materialized as its own record set for delivery.

The grouping field can be an organization-injected field that never appears in the extracted data. Assembly merges each document's injected fields with its extracted cells before grouping, so you can group by an external contract ID supplied at ingest even though that ID was never written into the run.

A common shape is a base document amended by later ones: an original order and its revisions, or a master agreement and its addenda. The original is the anchor; each amendment overrides the fields it changes. The composed record reflects the current state of the agreement, while the version history on every field preserves exactly which document set each value and when. This gives you both the answer and its provenance in one place.

Configuring assembly

Assembly is configured as an assembly stage in the rail, naming the grouping and anchor fields and the amendable field set. Because assembly composes the resolved values, place your resolution and validation stages before it so the values it folds together are already normalized and checked. After a run you can re-compose without redoing extraction by re-running only the assembly step over the existing cells. The stage compiles only when both the grouping field and the anchor field are set, and the field pickers offer only fields that occur on more than one document — a field unique to a single document cannot form a group.

Add an assembly stage to the rail
curl -X PUT https://api.talonic.com/v1/schemas/sch_delivery_notes/rail \
  -H "Authorization: Bearer $TALONIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "rail": [
      { "type": "registry", "name": "Field Registry" },
      { "type": "schema", "name": "Extraction" },
      { "type": "resolve", "name": "Normalize",
        "json": { "policy_ids": ["pol_dates_amounts"] } },
      { "type": "assembly", "name": "Assembly",
        "json": { "grouping_field": "contract_id",
                  "anchor_field": "document_type" } }
    ]
  }'

Assembly configuration surface (selected keys)

ParameterTypeDescription
grouping_field / anchor_fieldcoreThe bucket key and the field that identifies the anchor document class. Both are required for the assembly phase to compile.
anchor_valueselectionWhich values of the anchor field mark a document as anchor material, in preference order.
signed_field / date_fieldelectionTie-breakers for electing one anchor among several candidates: signed status first, then date recency.
amendable_fieldsoverrideThe fields an amendment document may contribute. Can be made document-type-conditional, so a rate confirmation and an invoice each amend only their own field set.
anchor_fallbackresilienceWhat to do with a group that has no anchor: "none" surfaces the group as unresolved; "newest" composes with the newest document acting as anchor and flags the record.
absence_values / placeholder_valueshygieneValues that mean "not present" (an absence value may fill an empty field but never overwrites a substantive one) and anchor values that count as empty, such as "0".
override_reviewgatePuts every amendment overwrite under review: "warning" flags the overwritten field in place, "blocking" routes it into the review queue as the synthetic Overwrite Review gate.

Anchor election and overwrite review

When a group holds several anchor candidates, assembly elects one deterministically down a ladder: identical-content candidates collapse first, then the configured anchor-value preference order decides, then signed-newest, then date recency over the configured date fields (deciding only when every candidate carries the field), and only past all of that does it fall back to the most-filled document or document order. The early rungs record a quiet election receipt; only the last-resort rungs keep a composition warning on the record, so a clean election never adds noise. A reviewer can also pin the anchor for a group explicitly, and the pinned document wins on every later compose.

With override review enabled, every field an amendment overwrites passes through a synthetic pipeline-scoped gate labeled Overwrite Review before it ships. In warning mode the overwritten field is flagged in place; in blocking mode it lands in the review queue like any gated field, and a blocked post-assembly field reopens its anchor document as partial until the reviewer decides. The gate is built from the assembly configuration itself — there is no separate validation stage to manage — and its sensitivity can distinguish similar overwrites (a reformatted date) from genuinely different ones.

Override review in the assembly configuration
{
  "override_review": {
    "mode": "blocking",
    "fields": ["total_amount", "delivery_date"]
  }
}
// mode: "off" | "warning" | "blocking".
// The optional fields list scopes which overwrites are reviewed.

Free-text merge guidance refines how the composition model chooses between candidate values: general instructions plus optional per-field guidance items. Guidance steers selection only — the platform copies the chosen value verbatim from the cited source cell, so the merge can never invent or reformat a value, and every composed cell still cites exactly one source document.

Assembly composes only after all documents are terminal, so a pipeline with documents still in review will not produce a final composed record for those groups until the review clears. Resolve the held fields in the review queue, then re-run assembly to fold the now-canonical values into the anchor record.

Frequently asked questions

What does assembly do?+
Assembly composes grouped documents into a single record after a pipeline finishes. It groups documents by a grouping field, picks an anchor document per group, seeds the record from the anchor, and lets amendment documents override selected fields. It runs once after every document is terminal, composing resolved values rather than raw extraction.
How does assembly choose which document leads a group?+
By the anchor field. Within a group, the anchor is the document whose anchor field matches a configured anchor value; it seeds the composed record. Other documents are amendments that override specific fields. A group with zero or multiple anchors is a conflict and composes nothing, so ambiguity is surfaced, not guessed.
Where is the audit trail for a composed value?+
In the cell version history. Assembly writes overrides onto the anchor record as new cell versions with an assembly source, so each field reads extraction, then resolution, then assembly. Every assembly cell records the previous value, the source document, and the rule that set it.
Can I group by a field that is not in the documents?+
Yes. Assembly merges each document's organization-injected fields with its extracted cells before grouping, so the grouping field can be an external identifier supplied at ingest (for example a contract ID) even though it was never written into the run's extracted data.
What happens to a group with no anchor document?+
That depends on anchor_fallback. With "none", the group surfaces as unresolved and composes nothing. With "newest", the newest document acts as anchor and the composed record is flagged as anchor-missing, so acting-anchored rows are visible in the product rather than silently indistinguishable from properly anchored ones.
Can I put amendment overwrites under human review?+
Yes. Enable override_review on the assembly configuration. Warning mode flags each overwritten field in place; blocking mode routes overwrites through the synthetic Overwrite Review gate into the review queue, and a blocked field reopens its anchor document as partial until a reviewer decides.