Skip to content

Deal Instance Specification v1.3

Document Purpose: Define the complete runtime structure, computation model, and state management for Deal Instances in the Deal Engine architecture revision.

Status: Draft for review

Version: 1.3


1. Overview

1.1 What is a Deal Instance?

A Deal Instance is a self-contained, executable representation of a specific contract. It contains:

  • All deal-level data (parties, dates, territory)
  • All clause instances (each with its own data and copied logic)
  • Deal-level logic for aggregation
  • All computed state (event states, calculated values)

Deal instances have no runtime dependencies on the clause type or deal type catalogs. Once created, they are complete snapshots that can be evaluated independently.

Deal instances are versioned. Every change—whether to data or logic—creates a new immutable version. The version chain provides a complete audit trail of the deal's evolution from creation through all amendments.

Deal Instance (version chain)
├── Version 1 (immutable) ─── Initial deal
├── Version 2 (immutable) ─── Show 1 settled
├── Version 3 (immutable) ─── Show 2 settled
├── Version 4 (immutable) ─── Bonus structure amended
└── Version 5 (current)   ─── Show 3 settled

1.2 Self-Containment Principle

When a deal is created:

  1. Deal-level schema is populated with actual data
  2. Selected clause types have their logic copied into the instance
  3. Clause data is populated
  4. Deal-level logic is copied into the instance

The result is like a compiled program—it contains everything needed to execute without referencing source libraries.

Deal Instance (Current Version)
├── version_info       // Version number, effective date, amendment details
├── deal_data          // Actual values (parties, dates, etc.)
├── clauses[]          // Each active clause instance:
│   ├── data           //   - Instance-specific data
│   ├── logic          //   - Copied from clause type (frozen)
│   └── status         //   - active, superseded, or removed
├── archived_clauses[] // Superseded/removed clauses (frozen final state)
├── deal_logic         // Copied from deal type (frozen)
└── computed_state     // All calculated values and event states

        └── prior_version → [Previous Version] → [Previous Version] → ...

Each version is immutable. When changes occur, a new version is created containing the updated state. Prior versions are preserved for audit and historical queries.

1.3 Why Self-Containment?

BenefitExplanation
ImmutabilityContract terms don't change if clause types are updated
AuditabilityExact logic that produced results is preserved
IndependenceNo external dependencies at runtime
Legal validityFrozen logic matches contractual agreement
ReproducibilitySame inputs always produce same outputs
Version historyEvery version is a complete, queryable snapshot

2. Deal Instance Structure

2.1 Top-Level Structure

json
{
  "instance_metadata": { ... },
  "version_info": { ... },
  "deal_data": { ... },
  "clauses": [ ... ],
  "archived_clauses": [ ... ],
  "deal_logic": { ... },
  "computed_state": { ... }
}
SectionPurpose
instance_metadataSystem information about the deal instance itself
version_infoVersion number, effective date, amendment details
deal_dataDeal-level data (parties, dates, territory, etc.)
clausesArray of active clause instances, each with data and logic
archived_clausesSuperseded or removed clauses with frozen final state
deal_logicDeal-level events and computations (copied from deal type)
computed_stateAll calculated values, event states, outputs

2.2 Instance Metadata

json
{
  "instance_metadata": {
    "instance_id": "deal-2024-001234",
    "deal_type_ref": {
      "id": "music-touring",
      "version": "1.0.0"
    },
    "created_at": "2024-03-15T10:30:00Z",
    "created_by": "user@agency.com",
    "current_version": 5,
    "status": "active"
  }
}
FieldDescription
instance_idUnique identifier for this deal instance
deal_type_refReference to originating deal type (informational only)
created_atWhen instance was first created (version 1)
created_byWho created the instance
current_versionLatest version number
statusCurrent deal status

Note: Version-specific information (effective date, amendment details) is in version_info, not metadata.

Note: deal_type_ref is informational only—the instance does not depend on the deal type at runtime.

2.3 Version Info

json
{
  "version_info": {
    "version": 5,
    "effective_date": "2024-08-01",
    "created_at": "2024-08-01T14:30:00Z",
    "created_by": "user@agency.com",
    "prior_version": 4,
    
    "change_type": "data_update",
    "change_summary": "Show 3 settlement data entered",
    
    "amendment": null
  }
}
FieldRequiredDescription
versionYesSequential version number (starts at 1)
effective_dateYesDate this version takes effect
created_atYesTimestamp when version was created
created_byYesWho created this version
prior_versionNoPrevious version number (null for version 1)
change_typeYesType of change that triggered this version
change_summaryYesHuman-readable description of change
amendmentNoAmendment details (for logic/clause changes)

Change types:

Change TypeDescriptionTriggers Recalculation
initialFirst version (deal creation)Full calculation
data_updateClause or deal data changedFull recalculation
logic_amendmentClause logic modifiedFull recalculation from inception
clause_additionNew clause addedFull recalculation
clause_replacementClause deactivated and replacedFull recalculation (excluding archived)
clause_removalClause deactivatedFull recalculation (excluding archived)
deal_logic_amendmentDeal-level logic modifiedFull recalculation

Amendment Details

When a version involves a logic change (not just data), the amendment field captures details:

json
{
  "version_info": {
    "version": 4,
    "effective_date": "2024-07-15",
    "created_at": "2024-07-15T10:30:00Z",
    "created_by": "agent@agency.com",
    "prior_version": 3,
    
    "change_type": "clause_replacement",
    "change_summary": "Renegotiated bonus structure per Amendment 2",
    
    "amendment": {
      "amendment_id": "AMD-002",
      "reason": "Artist requested simplified bonus tiers",
      "document_ref": "contracts/deal-2024-001234/amendment-002.pdf",
      "authorized_by": "agent-jane-doe",
      "effective_date": "2024-07-15",
      
      "changes": [
        {
          "action": "deactivate",
          "clause_id": "bonus_structure_v1",
          "reason": "Superseded by new structure"
        },
        {
          "action": "add",
          "clause_id": "bonus_structure_v2",
          "clause_type_ref": {
            "id": "tiered-bonus",
            "version": "1.0.0"
          },
          "replaces": "bonus_structure_v1"
        }
      ]
    }
  }
}
FieldDescription
amendment_idExternal amendment identifier
reasonBusiness reason for the amendment
document_refReference to legal amendment document
authorized_byWho authorized the amendment
effective_dateWhen the amendment takes effect
changesArray of specific changes made

Change actions:

ActionDescription
addNew clause added
deactivateExisting clause deactivated (superseded or removed)
modify_logicClause logic changed in place
modify_deal_logicDeal-level logic changed

2.4 Deal Data

Deal-level data populated from the deal type schema:

json
{
  "deal_data": {
    "parties": {
      "talent": {
        "id": "talent-12345",
        "name": "Big Talent",
        "legal_entity": "Big Talent Touring LLC"
      },
      "promoter": {
        "id": "promoter-67890",
        "name": "Big Promoter Entertainment",
        "legal_entity": "Big Promoter Worldwide Inc."
      },
      "agency": {
        "id": "agency-001",
        "name": "United Talent Agency"
      }
    },
    "dates": {
      "effective_date": "2024-03-01",
      "tour_start": "2024-06-15",
      "tour_end": "2024-09-30"
    },
    "currency": "USD",
    "territory": {
      "primary": "North America",
      "secondary": ["Canada"],
      "exclusions": []
    },
    "tour_info": {
      "tour_name": "Summer 2024 Tour",
      "tour_region": "North America",
      "headliner": true
    }
  }
}

2.5 Clause Instances

Each clause instance contains status fields for versioning:

json
{
  "clauses": [
    {
      "clause_id": "show_settlement",
      "clause_type_ref": {
        "id": "show-settlement",
        "version": "1.0.0"
      },
      "category": "guarantee",
      "value_type": "earning",
      
      "status": "active",
      "effective_from": "2024-03-15",
      "effective_until": null,
      "replaces": null,
      "superseded_by": null,
      
      "data": { ... },
      "logic": { ... }
    },
    {
      "clause_id": "bonus_structure_v2",
      "clause_type_ref": {
        "id": "tiered-bonus",
        "version": "1.0.0"
      },
      "category": "contingent",
      "value_type": "earning",
      
      "status": "active",
      "effective_from": "2024-07-15",
      "effective_until": null,
      "replaces": "bonus_structure_v1",
      "superseded_by": null,
      
      "data": { ... },
      "logic": { ... }
    }
  ]
}
FieldDescription
clause_idInstance identifier (unique within deal)
clause_type_refReference to originating clause type (informational)
categoryguarantee, contingent, or simple
value_typeearning, reimbursement, third_party, or in_kind
statusactive, superseded, or removed
effective_fromDate this clause became active
effective_untilDate this clause was deactivated (null if active)
replacesclause_id this clause replaces (null if original)
superseded_byclause_id that superseded this clause (null if active)
dataClause-specific data
logicFrozen DSL logic copied from clause type

Clause status values:

StatusDescription
activeClause is currently in effect
supersededClause was replaced by another clause
removedClause was removed without replacement

2.6 Archived Clauses

When a clause is superseded or removed, it moves to archived_clauses with its final computed state frozen:

json
{
  "archived_clauses": [
    {
      "clause_id": "bonus_structure_v1",
      "clause_type_ref": {
        "id": "tiered-bonus",
        "version": "1.0.0"
      },
      "category": "contingent",
      "value_type": "earning",
      
      "status": "superseded",
      "effective_from": "2024-03-15",
      "effective_until": "2024-07-15",
      "superseded_by": "bonus_structure_v2",
      "archived_at_version": 4,
      
      "data": { ... },
      "logic": { ... },
      
      "final_computed_state": {
        "events": {
          "any_bonus_earned": { "state": "true", "occurred_at": "2024-06-01" }
        },
        "outputs": {
          "total_earned": 25000,
          "total_received": 25000
        }
      }
    }
  ]
}
FieldDescription
archived_at_versionVersion number when clause was archived
final_computed_stateFrozen computed state at time of archival

Critical rule: Archived clauses are never recalculated. Their final_computed_state represents the actual financial activity that occurred under that clause's terms.

2.7 Clause Data Structure

json
{
  "data": {
    "shows": [
      {
        "id": "show_01",
        "date": "2024-06-15",
        "venue": "Madison Square Garden",
        "city": "New York",
        "guarantee": 150000,
        "gross_revenue": null,
        "expenses": null,
        "occurred": false,
        "settled": false,
        "artist_share": null,
        "earned": null
      },
      {
        "id": "show_02",
        "date": "2024-06-18",
        "venue": "TD Garden",
        "city": "Boston",
        "guarantee": 125000,
        "gross_revenue": 450000,
        "expenses": 85000,
        "occurred": true,
        "settled": true,
        "artist_share": null,
        "earned": null
      }
    ],
    "artist_percentage": 0.85,
    "earning_schedule": {
      "pattern": "event_triggered",
      "trigger": "show_settled"
    },
    "receipt_schedule": {
      "pattern": "event_triggered",
      "trigger": "show_settled",
      "days_after": 30
    }
  }
}

Data categories:

CategoryDescriptionExample Fields
Input dataValues from contractguarantee, artist_percentage
External dataUpdated during deal lifecyclegross_revenue, expenses
State flagsBoolean statesoccurred, settled
Computed fieldsPopulated by logic (start as null)artist_share, earned
SchedulesEmbedded schedule definitionsearning_schedule, receipt_schedule

2.8 Clause Logic Structure

Logic is stored as structured DSL (not raw text):

json
{
  "logic": {
    "events": [
      {
        "name": "show_occurred",
        "description": "Show has occurred",
        "condition": {
          "type": "field_equals",
          "field": "item.occurred",
          "value": true
        },
        "scope": "for_each",
        "collection": "shows"
      },
      {
        "name": "all_settled",
        "description": "All shows have been settled",
        "condition": {
          "type": "comparison",
          "left": {
            "type": "count",
            "collection": "shows",
            "where": { "field": "settled", "equals": true }
          },
          "operator": "==",
          "right": {
            "type": "count",
            "collection": "shows"
          }
        }
      }
    ],
    "for_each": [
      {
        "collection": "shows",
        "item_alias": "show",
        "computations": [
          {
            "name": "net_revenue",
            "expression": {
              "type": "subtract",
              "left": { "type": "field", "path": "show.gross_revenue" },
              "right": { "type": "field", "path": "show.expenses" }
            }
          },
          {
            "name": "artist_share",
            "expression": {
              "type": "multiply",
              "left": { "type": "variable", "name": "net_revenue" },
              "right": { "type": "field", "path": "artist_percentage" }
            },
            "target": "show.artist_share"
          },
          {
            "name": "earned",
            "expression": {
              "type": "max",
              "args": [
                { "type": "field", "path": "show.guarantee" },
                { "type": "variable", "name": "artist_share" }
              ]
            },
            "target": "show.earned"
          }
        ]
      }
    ],
    "computations": [
      {
        "name": "total_guarantee",
        "expression": {
          "type": "sum",
          "collection": "shows",
          "field": "guarantee"
        }
      },
      {
        "name": "total_earned",
        "expression": {
          "type": "sum_coalesce",
          "collection": "shows",
          "field": "earned",
          "default": 0
        }
      }
    ],
    "outputs": [
      "total_guarantee",
      "total_earned",
      "total_received",
      "all_settled"
    ],
    "financial": {
      "amount": { "type": "output", "name": "total_earned" },
      "earned": { "type": "schedule", "ref": "earning_schedule" },
      "received": { "type": "schedule", "ref": "receipt_schedule" }
    }
  }
}

2.9 Deal-Level Logic

Copied from deal type, handles cross-clause aggregation:

json
{
  "deal_logic": {
    "events": [
      {
        "name": "all_shows_settled",
        "description": "All shows in the tour have been settled",
        "condition": {
          "type": "clause_output",
          "clause": "show_settlement",
          "output": "all_settled",
          "coalesce": false
        }
      },
      {
        "name": "tour_complete",
        "description": "Tour fully settled including versus",
        "condition": {
          "type": "and",
          "args": [
            { "type": "event", "name": "all_shows_settled" },
            {
              "type": "clause_output",
              "clause": "tour_versus",
              "output": "settled",
              "coalesce": true
            }
          ]
        }
      }
    ],
    "computations": [
      {
        "name": "total_guaranteed",
        "expression": {
          "type": "add",
          "args": [
            {
              "type": "clause_output",
              "clause": "show_settlement",
              "output": "total_guarantee",
              "coalesce": 0
            },
            {
              "type": "clause_output",
              "clause": "tour_versus",
              "output": "tour_guarantee",
              "coalesce": 0
            }
          ]
        }
      },
      {
        "name": "total_earned",
        "expression": {
          "type": "add",
          "args": [
            {
              "type": "clause_output",
              "clause": "show_settlement",
              "output": "total_earned",
              "coalesce": 0
            },
            {
              "type": "clause_output",
              "clause": "tour_versus",
              "output": "versus_earned",
              "coalesce": 0
            }
          ]
        }
      }
    ],
    "outputs": [
      "total_guaranteed",
      "total_earned",
      "total_received",
      "total_pending",
      "tour_complete"
    ]
  }
}

2.10 Computed State

All computed values stored after evaluation:

json
{
  "computed_state": {
    "computed_at": "2024-06-20T14:22:17Z",
    "computation_version": 47,
    
    "clause_states": {
      "show_settlement": {
        "events": {
          "all_occurred": false,
          "all_settled": false
        },
        "outputs": {
          "total_guarantee": 1250000,
          "total_earned": 485000,
          "total_received": 320000,
          "all_settled": false
        },
        "item_states": {
          "show_01": {
            "events": { "occurred": false, "settled": false },
            "computed": { "artist_share": null, "earned": null }
          },
          "show_02": {
            "events": { "occurred": true, "settled": true },
            "computed": { "artist_share": 310250, "earned": 310250 }
          }
        }
      },
      "tour_versus": {
        "events": {
          "settled": false
        },
        "outputs": {
          "tour_guarantee": 500000,
          "versus_earned": null,
          "settled": false
        }
      }
    },
    
    "deal_outputs": {
      "total_guaranteed": 1750000,
      "total_earned": 485000,
      "total_received": 320000,
      "total_pending": 165000,
      "tour_complete": false
    },
    
    "deal_events": {
      "all_shows_settled": false,
      "tour_complete": false
    }
  }
}

3. Computation Model

3.1 Reactive Full-Recalculation

The Deal Engine uses reactive full-recalculation: any change triggers complete re-evaluation of the entire deal state.

Input Change (data update, event trigger)

Full Recomputation
    ├── Evaluate all clause instances
    │   ├── Process for_each loops
    │   ├── Evaluate clause events
    │   └── Compute clause outputs
    ├── Evaluate deal-level logic
    │   ├── Aggregate clause outputs
    │   └── Evaluate deal events
    └── Store computed state

New Computed State (immutable snapshot)

3.2 Evaluation Order

Computation follows a strict order to ensure deterministic results:

1. CLAUSE EVALUATION (for each clause instance)
   1.1 Evaluate for_each loops (process collections)
       - For each item in collection:
         - Evaluate item-scoped events
         - Compute item-scoped values
         - Populate computed fields in data
   1.2 Evaluate clause-level events
   1.3 Compute clause-level values
   1.4 Populate clause outputs

2. DEAL-LEVEL EVALUATION
   2.1 Gather clause outputs (via @clause.output references)
   2.2 Evaluate deal-level events
   2.3 Compute deal-level aggregations
   2.4 Populate deal outputs

3. STATE STORAGE
   3.1 Increment computation_version
   3.2 Store all computed values
   3.3 Store all event states
   3.4 Record timestamp

3.3 Dependency Resolution

Within each evaluation phase, computations are ordered by dependency:

Example: Clause computations
  net_revenue = gross_revenue - expenses          // No dependencies
  artist_share = net_revenue * artist_percentage  // Depends on net_revenue
  earned = max(guarantee, artist_share)           // Depends on artist_share

Evaluation order: net_revenue → artist_share → earned

Circular dependencies are invalid and detected at deal creation time.

3.4 Null Handling

The ?? (null coalescing) operator provides defaults for null values:

sum(@bonus_groups[*].earned ?? 0)

Null propagation rules:

ExpressionIf any operand is nullResult
a + bPropagatesnull
a * bPropagatesnull
a > bPropagatesnull (not false)
a ?? defaultUses defaultdefault
sum(collection)Skips nullsSum of non-null values
count(collection)Counts allTotal count (including null)

3.5 Event State Model

Events use a three-state model:

StateMeaning
unknownNot yet determinable
trueCondition satisfied
falseCondition definitively not satisfied

State transitions:

Initial: unknown

Condition evaluates to true → true
Condition evaluates to false → false (or remains unknown if data missing)

Event state in computed_state:

json
{
  "events": {
    "all_settled": {
      "state": "false",
      "evaluated_at": "2024-06-20T14:22:17Z",
      "transition_history": [
        {
          "from": "unknown",
          "to": "false",
          "at": "2024-06-20T14:22:17Z",
          "reason": "3 of 42 shows settled"
        }
      ]
    }
  }
}

4: Instance Versioning

4.1 Version Chain Model

Every deal instance maintains a chain of versions. Each version is an immutable snapshot capturing the complete deal state at a point in time.

┌─────────────────────────────────────────────────────────────────────┐
│                        Deal Instance                                 │
│                     instance_id: deal-2024-001234                   │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐         │
│  │ Ver 1   │───▶│ Ver 2   │───▶│ Ver 3   │───▶│ Ver 4   │         │
│  │ Initial │    │ Data    │    │ Data    │    │ Clause  │         │
│  │         │    │ Update  │    │ Update  │    │ Replace │         │
│  └─────────┘    └─────────┘    └─────────┘    └─────────┘         │
│       │              │              │              │                │
│       ▼              ▼              ▼              ▼                │
│  [computed     [computed     [computed     [computed               │
│   state 1]     state 2]     state 3]     state 4]                 │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

4.2 Version Creation Triggers

TriggerChange TypeWhat Happens
Show data entereddata_updateNew version, full recalculation
Settlement recordeddata_updateNew version, full recalculation
Event state changeddata_updateNew version, full recalculation
Clause logic amendedlogic_amendmentNew version, full recalculation from inception
New clause addedclause_additionNew version, full recalculation
Clause replacedclause_replacementNew version, old clause archived, full recalculation
Clause removedclause_removalNew version, clause archived, full recalculation
Deal logic amendeddeal_logic_amendmentNew version, full recalculation

4.3 Effective Dates

Every version has an effective_date indicating when that version's state takes effect.

Rules:

  1. effective_date must be ≥ prior version's effective_date
  2. For data updates, effective_date is typically the date of the change
  3. For amendments, effective_date may be backdated to when terms actually changed
  4. Queries for "state at date X" find the version with the latest effective_date ≤ X
Timeline:
─────────────────────────────────────────────────────────────▶
     │           │           │           │
   Mar 15      Jun 1       Jul 15      Aug 1
   Ver 1       Ver 2       Ver 3       Ver 4
   (initial)   (show 1)    (amendment) (show 2)
                           (eff: Jul 1)
                           
Query: "State at Jul 10?" → Version 3 (effective Jul 1)
Query: "State at Jun 15?" → Version 2 (effective Jun 1)

4.4 Immutability Guarantees

ComponentImmutability Rule
Prior versionsNever modified after creation
Archived clausesNever recalculated; final_computed_state frozen
Version chainAppend-only; versions never deleted
Amendment recordsImmutable audit trail

5: Amendment Processing

5.1 Data Change Processing

When deal or clause data changes (settlements, events, external data):

1. CAPTURE CHANGE
   - Identify changed fields
   - Record change metadata (who, when, what)

2. CREATE NEW VERSION
   - Increment version number
   - Set effective_date
   - Copy current structure
   - Apply data changes

3. FULL RECALCULATION
   - Evaluate all active clauses
   - Process for_each loops with new data
   - Evaluate all events
   - Compute all outputs
   - Aggregate at deal level

4. STORE VERSION
   - Store complete version snapshot
   - Update instance_metadata.current_version

Example: Show Settlement

json
// Version 2 created when Show 1 settles
{
  "version_info": {
    "version": 2,
    "effective_date": "2024-06-01",
    "prior_version": 1,
    "change_type": "data_update",
    "change_summary": "Show 1 (MSG) settlement: gross $500,000, expenses $75,000"
  }
}

5.2 Logic Amendment Processing

When clause or deal logic is modified:

1. VALIDATE AMENDMENT
   - Verify authorization
   - Validate new logic structure
   - Check for circular dependencies

2. CREATE NEW VERSION
   - Increment version number
   - Set effective_date (may be backdated)
   - Record amendment details
   - Apply logic changes

3. FULL RECALCULATION FROM INCEPTION
   - Recalculate entire deal with new logic
   - Apply new logic to ALL historical data
   - Recompute all events and outputs
   
   NOTE: This ensures the deal reflects "what would have been calculated
   if this logic had always been in place." Actual cash movements are
   handled by downstream accounting systems.

4. STORE VERSION
   - Store complete version snapshot
   - Update instance_metadata.current_version

Example: Percentage Change

json
// Artist percentage changed from 85% to 87.5%
{
  "version_info": {
    "version": 5,
    "effective_date": "2024-07-01",
    "prior_version": 4,
    "change_type": "logic_amendment",
    "change_summary": "Artist percentage increased from 85% to 87.5%",
    
    "amendment": {
      "amendment_id": "AMD-001",
      "reason": "Renegotiated split based on ticket sales performance",
      "document_ref": "contracts/deal-2024-001234/amendment-001.pdf",
      "authorized_by": "agent-jane-doe",
      "changes": [
        {
          "action": "modify_logic",
          "clause_id": "show_settlement",
          "field": "artist_percentage",
          "old_value": 0.85,
          "new_value": 0.875
        }
      ]
    }
  }
}

5.3 Clause Replacement Processing

When a clause is replaced by a new version:

1. VALIDATE REPLACEMENT
   - Verify authorization
   - Validate new clause structure
   - Check output compatibility (if other clauses depend on outputs)

2. ARCHIVE OLD CLAUSE
   - Set status = "superseded"
   - Set effective_until = amendment effective_date
   - Set superseded_by = new clause_id
   - Capture final_computed_state (frozen, never recalculated)
   - Move to archived_clauses

3. ADD NEW CLAUSE
   - Set status = "active"
   - Set effective_from = amendment effective_date
   - Set replaces = old clause_id
   - Copy logic from clause type

4. UPDATE CROSS-CLAUSE REFERENCES
   - Update deal_logic references to point to new clause
   - Update any clause references (if applicable)

5. CREATE NEW VERSION
   - Increment version number
   - Record amendment details
   - Include both archived and new clauses

6. FULL RECALCULATION
   - Recalculate all ACTIVE clauses only
   - Archived clauses retain frozen final_computed_state
   - Aggregate at deal level using active clause outputs

7. STORE VERSION

Example: Bonus Structure Replacement

json
{
  "version_info": {
    "version": 4,
    "effective_date": "2024-07-15",
    "change_type": "clause_replacement",
    "change_summary": "Replaced tiered bonus with simplified flat bonus",
    
    "amendment": {
      "amendment_id": "AMD-002",
      "changes": [
        {
          "action": "deactivate",
          "clause_id": "bonus_structure_v1",
          "reason": "Superseded by simplified structure"
        },
        {
          "action": "add",
          "clause_id": "bonus_structure_v2",
          "clause_type_ref": { "id": "flat-bonus", "version": "1.0.0" },
          "replaces": "bonus_structure_v1"
        }
      ]
    }
  },
  
  "archived_clauses": [
    {
      "clause_id": "bonus_structure_v1",
      "status": "superseded",
      "effective_until": "2024-07-15",
      "superseded_by": "bonus_structure_v2",
      "archived_at_version": 4,
      "final_computed_state": {
        "outputs": {
          "total_earned": 25000,
          "total_received": 25000
        }
      }
    }
  ],
  
  "clauses": [
    {
      "clause_id": "bonus_structure_v2",
      "status": "active",
      "effective_from": "2024-07-15",
      "replaces": "bonus_structure_v1",
      "data": { ... },
      "logic": { ... }
    }
  ]
}

5.4 Clause Removal Processing

When a clause is removed without replacement:

1. ARCHIVE CLAUSE
   - Set status = "removed"
   - Set effective_until = removal effective_date
   - Capture final_computed_state
   - Move to archived_clauses

2. UPDATE REFERENCES
   - Update deal_logic to handle missing clause outputs
   - Use null coalescing (??) for graceful degradation

3. CREATE NEW VERSION & RECALCULATE
   - Same as replacement, but no new clause added

6: Version Queries

6.1 Current State

To get the current deal state, query the latest version:

GET /deals/{instance_id}/current

Returns: Latest version with computed_state

6.2 Specific Version

To get a specific historical version:

GET /deals/{instance_id}/versions/{version}

Returns: Complete version snapshot

6.3 Point-in-Time State

To get the state as of a specific date:

GET /deals/{instance_id}/state?as_of=2024-06-15

Returns: Version with latest effective_date ≤ 2024-06-15

6.4 Version History

To get the amendment history:

GET /deals/{instance_id}/history

Returns: [
  { version: 1, effective_date: "2024-03-15", change_type: "initial", ... },
  { version: 2, effective_date: "2024-06-01", change_type: "data_update", ... },
  { version: 3, effective_date: "2024-06-15", change_type: "data_update", ... },
  { version: 4, effective_date: "2024-07-15", change_type: "clause_replacement", ... }
]

6.5 Version Comparison

To compare two versions:

GET /deals/{instance_id}/compare?from=3&to=4

Returns: {
  data_changes: [ ... ],
  logic_changes: [ ... ],
  clause_changes: [
    { action: "deactivate", clause_id: "bonus_structure_v1" },
    { action: "add", clause_id: "bonus_structure_v2" }
  ],
  output_changes: {
    total_earned: { from: 150000, to: 175000 },
    ...
  }
}

6.6 Archived Clause History

To get the history of a specific clause (including after archival):

GET /deals/{instance_id}/clauses/{clause_id}/history

Returns: {
  clause_id: "bonus_structure_v1",
  status: "superseded",
  active_versions: [1, 2, 3],
  archived_at_version: 4,
  superseded_by: "bonus_structure_v2",
  final_computed_state: { ... }
}

7. Cross-Clause Communication

7.1 Output-Based Interface

Clauses communicate through declared outputs only:

Clause: show_settlement
  outputs: [total_guarantee, total_earned, total_received, all_settled]

Deal-level logic can reference:
  @show_settlement.total_guarantee
  @show_settlement.total_earned
  @show_settlement.all_settled

Deal-level logic CANNOT reference:
  @show_settlement.shows[0].artist_share  // Internal data
  @show_settlement.net_revenue            // Internal computation

7.2 Reference Syntax

SyntaxMeaningReturns
@clause_id.outputSingle clause outputValue or null
@clause_id[*].outputAll instances of clause typeArray of values
@clause_id.output ?? defaultWith fallbackValue or default

7.3 Multi-Instance Clauses

When cardinality is many, multiple clause instances exist:

json
{
  "clauses": [
    { "clause_id": "bonus_group_1", "clause_type_ref": { "id": "tiered-bonus" }, ... },
    { "clause_id": "bonus_group_2", "clause_type_ref": { "id": "tiered-bonus" }, ... },
    { "clause_id": "bonus_group_3", "clause_type_ref": { "id": "tiered-bonus" }, ... }
  ]
}

Referencing multiple instances:

// Reference specific instance
@bonus_group_1.earned

// Reference all instances of a clause type
sum(@tiered-bonus[*].earned ?? 0)

// Alternative: reference by clause_id pattern
sum(@bonus_group_*.earned ?? 0)

7.4 Cross-Clause Dependencies

Cross-clause references create dependencies:

tour_versus depends on show_settlement
  (tour_versus.versus_amount uses @show_settlement.total_earned)

Evaluation order respects dependencies:

  1. show_settlement evaluated first
  2. tour_versus evaluated second (can now reference show_settlement outputs)

Circular cross-clause dependencies are invalid.


8. Schedule Integration

8.1 Embedded Schedules

Schedules are embedded in clause data, not referenced externally:

json
{
  "data": {
    "earning_schedule": {
      "pattern": "straight_line",
      "start_date": "2024-03-01",
      "end_date": "2024-09-30"
    },
    "receipt_schedule": {
      "pattern": "equal_periodic_installments",
      "total_amount": 3100000,
      "frequency": "quarterly",
      "period_count": 4,
      "start_date": "2024-03-01"
    }
  }
}

8.2 Schedule Patterns

Earning schedules (when revenue is recognized):

PatternDescription
straight_lineLinear recognition over period
event_triggeredRecognized when event occurs
periodicRecognized at regular intervals

Receipt schedules (when cash is received):

PatternDescription
equal_periodic_installmentsEqual amounts at regular intervals
event_installmentsSpecific amounts at specific events

8.3 Schedule Computation

Schedules produce computed values:

json
{
  "receipt_schedule": {
    "pattern": "equal_periodic_installments",
    "total_amount": 400000,
    "frequency": "quarterly",
    "period_count": 4,
    "start_date": "2024-01-01"
  }
}

Computed schedule state:

json
{
  "computed_schedule": {
    "installments": [
      { "date": "2024-01-01", "amount": 100000, "status": "received" },
      { "date": "2024-04-01", "amount": 100000, "status": "received" },
      { "date": "2024-07-01", "amount": 100000, "status": "pending" },
      { "date": "2024-10-01", "amount": 100000, "status": "future" }
    ],
    "total_received": 200000,
    "total_pending": 100000,
    "total_future": 100000
  }
}


9. Validation Rules

9.1 Instance Structure Validation

RuleDescription
DI-1instance_id must be unique
DI-2instance_metadata required
DI-3deal_data must match deal type schema
DI-4Each clause must have unique clause_id

9.2 Clause Instance Validation

RuleDescription
CI-1clause_id must be unique within instance
CI-2category must be valid
CI-3value_type required for financial clauses
CI-4data must match clause type schema
CI-5logic must be present (copied from clause type)

9.3 Logic Validation

RuleDescription
LV-1No circular dependencies within clause
LV-2No circular dependencies across clauses
LV-3All output references must target declared outputs
LV-4All collection references must exist in data

9.4 Computation Validation

RuleDescription
CV-1All variables must be defined before use
CV-2Type consistency in expressions
CV-3Collection operations only on arrays
CV-4Computed fields must exist in schema

9.5 Version Validation

RuleDescription
VR-1version must be a positive integer
VR-2version must increment sequentially (no gaps)
VR-3prior_version must reference an existing version
VR-4Version 1 must have prior_version: null
VR-5effective_date must be ≥ prior version's effective_date
VR-6change_type must be a valid change type
VR-7amendment required for non-data change types

9.6 Clause Status Validation

RuleDescription
CS-1Active clauses must have effective_until: null
CS-2Superseded clauses must have effective_until set
CS-3Superseded clauses must have superseded_by set
CS-4Replacement clauses must have replaces referencing archived clause
CS-5effective_from must be ≤ effective_until (when both set)

9.7 Archive Validation

RuleDescription
AR-1Archived clauses must have final_computed_state
AR-2Archived clauses must have archived_at_version
AR-3archived_at_version must be ≤ current version
AR-4Archived clause final_computed_state must not change

9.8 Amendment Validation

RuleDescription
AM-1Amendment changes must reference valid clause_ids
AM-2Deactivate actions must target active clauses
AM-3Add actions must provide valid clause_type_ref
AM-4Replace references must point to clause being deactivated

10. Design Rationale

10.1 Why Full Recalculation?

Incremental computation (only recalculating changed values) is complex and error-prone:

  • Dependency tracking across for_each loops
  • Cascading updates through cross-clause references
  • Risk of stale state

Full recalculation is simpler and safer:

  • Always consistent state
  • Deterministic results
  • Easier to debug and audit
  • Modern hardware makes it fast enough for typical deal sizes

10.2 Why Store Logic with Instance?

Storing logic with each instance:

  • Immutability: Contract logic never changes unexpectedly
  • Reproducibility: Can always re-run exact same logic
  • Independence: No catalog dependency at runtime
  • Audit: Know exactly what logic produced results

10.3 Why Structured Logic (not Raw DSL)?

Logic is stored as structured JSON (AST-like), not raw DSL text:

  • Parseable: No parsing needed at evaluation time
  • Versionable: Can detect structural changes
  • Transformable: Can optimize, analyze, or migrate
  • Portable: Language-agnostic representation

10.4 Why Separate Computed State?

Computed state is separated from input data:

  • Clarity: Clear what's input vs. derived
  • Recomputation: Easy to throw away and recalculate
  • Versioning: Can store computation history
  • Debugging: Compare computed state across versions

10.5 Why Version Every Data Change?

Every data change creates a new version because:

  1. Complete audit trail: Every state the deal passed through is preserved
  2. Reproducibility: Can always reconstruct what was known when
  3. Debugging: Can trace how values evolved over time
  4. Compliance: Meets audit requirements for financial systems
  5. Simplicity: One consistent model for all changes

Storage efficiency is handled at the infrastructure level (compression, deduplication), not by complicating the versioning model.

10.6 Why Include Effective Dates?

Effective dates allow:

  1. Backdated amendments: Legal amendments that apply retroactively
  2. Point-in-time queries: "What did we think the deal was worth on June 15?"
  3. Audit alignment: Match versions to business events, not just system timestamps
  4. Reporting flexibility: Generate reports as of any date

10.7 Why Recalculate from Inception on Logic Changes?

When logic changes, the entire deal is recalculated because:

  1. Current truth: Deal Engine shows what the deal IS worth under current terms
  2. Consistency: All computed values reflect consistent logic
  3. Simplicity: No complex "partial recalculation" logic
  4. Downstream handling: Accounting systems handle actual cash corrections

The alternative (only recalculating from the effective date forward) creates inconsistent state and complex edge cases.

10.8 Why Archive Replaced Clauses Without Recalculation?

Archived clauses keep their final_computed_state because:

  1. Historical accuracy: Reflects what actually happened under those terms
  2. Cash basis: Payments made under old terms remain accurate
  3. Audit trail: Can verify what was calculated and paid
  4. No retroactive fiction: Don't pretend old terms never existed

The new clause handles ongoing/future activity; the archived clause preserves history.


11. Relationship to Other Specifications

11.1 Clause Type Specification

Clause types define:

  • Schema for clause data (copied to clause.data)
  • Logic structure (copied to clause.logic)
  • Outputs exposed (referenced via @clause.output)

11.2 Deal Type Specification

Deal types define:

  • Schema for deal data (instantiated to deal_data)
  • Suggested clauses (user selects which to include)
  • Deal-level logic (copied to deal_logic)

11.3 This Specification

Deal instances are the runtime result of combining:

  • Deal type schema → deal_data
  • Selected clause types → clauses[]
  • Deal type logic → deal_logic
  • Computed results → computed_state

Document History

  • v1.3 (2026-01-XX) - Added instance versioning
    • New Section 4: Instance Versioning (version chain, triggers, effective dates)
    • New Section 5: Amendment Processing (data changes, logic amendments, clause replacement)
    • New Section 6: Version Queries (current, historical, point-in-time, comparison)
    • Updated Section 2: Added version_info, clause status fields, archived_clauses
    • New validation rules for versioning, clause status, archives, amendments
    • Updated design rationale for versioning decisions
  • v1.2 (2026-01-XX) - Initial specification
    • Complete instance structure
    • Computation model (reactive full-recalculation)
    • Evaluation order and dependency resolution
    • Null handling and event state model
    • Cross-clause communication via outputs
    • Schedule integration
    • Complete example (music touring deal)
    • Validation rules
    • Design rationale

Confidential. For internal use only.