# Learn: Coda Contract Creation

This page explains what happens when Coda creates a **distribution contract** from a deal memo.
It is the conceptual companion to the [contract-creation runbook](../../runbooks/coda/contract-creation.md)
(how to operate it) and the [TRD](../../technical-projects/coda/TRD.md) (how it is built).

## The problem

Setting up a distribution contract in Abacus is a multi-step write: create the contract and its
lifecycle schedule, add one or more terms, attach rate conditions to each term, and set excluded
territories. The source of truth is usually a **deal memo**, a PDF or email describing the
account, the signing entity, the royalty split, the renewal terms. Today a person reads that
memo and clicks through the Abacus UI, transcribing fields and rates by hand.

Coda automates the transcription **without** automating the judgement. It reads the memo into
structured fields, shows a human exactly what it intends to write, and only writes after the
human confirms. The model never touches the live system; it only ever turns prose into a draft.

## The three ways to start

A workflow run begins from any one of:

- **A document**: a contract PDF, Word doc, CSV, or plain/markdown text file (up to ~25 MB).
- **Free text**: the memo pasted as a string.
- **Structured params**: a pre-built draft (e.g. from another service). When params are the
  *only* input, the LLM is skipped entirely and the draft is taken as given.

Documents and text go through the one model call; params bypass it. When both are supplied,
explicit params win over extracted values, since the caller is assumed to know best.

## The pipeline

```mermaid
flowchart TD
    START["Start<br/>(document / text / params)"] --> EX["extract"]
    EX --> VA["validate"]
    VA --> PR["prepare"]
    PR --> RV{{"review · PAUSE"}}
    RV -->|"amend (patch fields)"| VA
    RV -->|cancel| CX["cancelled"]
    RV -->|confirm| EXE["execute"]
    EXE --> AU["audit"]
    AU --> DONE["executed / dry_run / failed"]

    style RV fill:#fff3cd,stroke:#e0a800,color:#000
    style EX fill:#e8eaf6,stroke:#3f51b5,color:#000
```

### 1. Extract, the only step the model touches

A Bedrock Claude model reads the document/text and fills a **draft**, the same field set the
contract-creation tool accepts but with everything optional. The model runs at temperature 0
and is forced to emit the draft schema, so output is as deterministic as a model gets.

The extraction prompt is deliberately conservative about the dangerous fields:

- **Never invent IDs.** `account_id`, `signing_entity_id`, and `run_controller_id` are internal
  numeric identifiers. A deal memo almost never states them, so the model is told to leave them
  blank rather than guess. A name is not an ID, so the signing entity's legal name is captured
  as a *hint* (`signing_entity_name`) for a human to resolve later.
- **Label/vendor attachments are internal IDs too.** Memos don't carry them; the reviewer
  supplies them at confirm time.
- **Splits total 100.** `term_rate` is the client/label share and `commission` is the
  distributor share; "an 80/20 split in favour of the label" becomes `term_rate 80, commission 20`.
- **Terms vs conditions.** Multiple *terms* exist only when different catalogues get different
  deals. Rate variations within the same catalogue (streaming vs sync vs ad sales) are
  *conditions* on a single term. (Abacus allows a given label on only one term per contract.)

### 2. Validate, to catch problems in the preview rather than at execution

A pure validator decides what is missing and what is wrong, mirroring the rules the write API
enforces so issues surface in the preview instead of failing mid-write:

- **Required fields:** contract name, account ID, signing entity ID, run controller ID,
  lifecycle term start, plus at least one term, each with at least one rate condition.
- **Rates:** every condition's `term_rate + commission` must equal 100, each in the 0–100 range.
- **Attachments:** every term must attach to at least one label/vendor ID. Because memos don't
  state these, the validator asks the reviewer for `default_term_attachments` when a term has none.
- **One label, one term:** a label/vendor attached to two terms is an error. The fix is to
  model the rate difference as conditions on one term.
- **Dates** must be real `YYYY-MM-DD` calendar dates.

Missing required fields or any error-severity issue makes the draft **blocking**: it cannot be
confirmed until amended. Warnings (e.g. "no excluded territories, the platform default `["RUS"]`
will be applied") are surfaced but don't block.

### 3. Prepare, to build the plan and the preview from one source

`prepare` turns the draft into two things:

- an **execution plan**: the exact tool input plus the ordered GraphQL mutations that input
  will produce, with handler defaults filled in (fallback schedule, `isBaseTerm`, priorities,
  the `["RUS"]` exclusion) and runtime IDs shown as placeholders; and
- a **preview**: a human-readable summary of the contract, its terms and conditions, and the
  warnings.

Both are derived from the *same* checkpointed draft, which is the guarantee that the preview
reflects reality.

### 4. Review, where the workflow stops and waits for a person

This is the heart of the design. The graph **pauses** at `review` and returns the preview to
the caller with status `awaiting_confirmation` (or `needs_input` if the draft is blocking). It
stays paused, with the run checkpointed to the cache, until a later request answers with one of:

- **confirm**: proceed to execute.
- **amend**: apply a field patch, then loop back through validate and prepare to produce a
  fresh preview. A reviewer typically amends here to supply the IDs the memo lacked (account,
  signing entity, run controller, label attachments).
- **cancel**: end the run; nothing is written.

### 5. Execute, wrapping the real write rather than reimplementing it

On confirm, `execute` runs the previewed plan through the **same hardened
`create_distribution_contract` write handler** the chatbot uses, so the QA gate, rate
re-validation, fallback-schedule logic and partial-failure handling all still apply. It issues
four mutations in order:

1. **Create the contract** with its lifecycle schedule(s).
2. **Create each term** (the first is the base term; every term needs at least one label
   attachment).
3. **Create the rate conditions** for each term.
4. **Set excluded territories** (defaults to `["RUS"]`).

Execution forwards **the confirming user's own identity** to the API, not a service token, so
permissions are enforced server-side, exactly as if they had used the UI.

### 6. Audit, to record what happened

Every execution writes one audit record (who, the confirmed input, the outcome, any error) to
the cache and the structured log, before the result returns to the caller.

## The two safety gates

Real contract writes are guarded twice over:

- **Dry-run.** In dry-run mode, confirm returns the **exact mutation payloads that would have
  been sent** and writes nothing. The whole flow, including the confirm gate, is exercised with
  no backend. This is the default in local/dev.
- **QA-only execution.** Even with dry-run off, the underlying write handler refuses to run
  outside the QA environment. Producing real contracts elsewhere is still a UI task.

## Things to know

- **One execution per run.** A thread executes at most once, no matter how many times confirm
  is sent. A double-confirm returns the original result rather than creating a duplicate
  contract. The same idempotency applies to cancel.
- **Preview is what runs.** Because the plan and the preview come from one checkpointed draft,
  there is no "the preview said X but it did Y" failure mode.
- **Runs expire.** A paused workflow is kept for 7 days (the checkpoint TTL); audit records for
  30 days. Abandoned drafts clean themselves up.
- **The model is measured, not trusted.** Extraction quality is tracked by an offline eval
  harness over a fixed set of fixtures. It is the only part of the workflow that *can* be wrong,
  so it is the only part with a score. Everything else is covered by ordinary unit tests.
- **This is the template.** Contract creation is the first agentic workflow; the same
  extract → validate → prepare → review → execute → audit shape is intended to carry the next
  ones (adjustments, transfers, and so on).
