{
  "apiVersion": 56,
  "label": "Credits - Stamp Open Org Ledger",
  "description": "At create AND on update, look for another Credits__c record on the same Cloud_Org__c AND of the same Credit_Type__c whose Credit_Lifecycle__c is not 'Cancelled', and stamp Has_Open_Org_Ledger__c accordingly. Credits__VR_One_Open_Ledger_Per_Org reads that stamp and blocks; the remedy depends on the credit type - a PoC follow-on grant becomes a Credits_Topup__c on the existing ledger, while Startup grants are one per org with no top-up path at all. Why this matters: approval step criteria aggregate only within one ledger (Initial_Credits__c, plus Approved_Topups__c for top-ups), so two sibling ledgers on one org are each gated on their own smaller amount and the combined figure never reaches an approver - silently, because each record legitimately passes its own gate (issue #4733). Cloud Org is the anchor because credits are loaded onto the org, so the threshold being protected accrues per org; Account is too coarse (parallel engagements on different orgs are legitimate) and Opportunity is trivially gamed. Cancelled is the one lifecycle value that releases the anchor - an org whose every record is Cancelled is rejected-only history, and a fresh ledger there re-enters the full approval chain, so nothing is bypassed. No other lifecycle state is required to be reached: production has never produced a Completed or Cancelled record, so any rule depending on records being closed would silently block legitimate requests. WHY CreateAndUpdate rather than Create alone: the stamp answers 'does this record's Cloud Org already carry another open ledger', so it goes stale the moment Cloud_Org__c changes. That field is updateable and sits on the detail layout, so a create-only stamp left an ordinary edit - repoint an existing ledger at an org that already has one - able to rebuild the exact split-ledger bypass this closes, with the rule never firing. Re-stamping on update keeps the flag true to its own definition; the rule then gates on ISCHANGED(Cloud_Org__c) so unrelated edits are never blocked. The Id NotEqualTo $Record.Id filter is what makes the update path viable: on update the record is already persisted and would otherwise match its own lookup and block itself. On create the row does not exist yet, so the filter is a no-op there - verified on the local bootstrap oracle, where the first ledger for an org is still created with the stamp false. RecordBeforeSave mirrors Credits_Stamp_Approvers (same trigger family, same object, same createable:false stamp target), so the stamp lands in the same save the validation rule evaluates. getFirstRecordOnly is sufficient because the rule is existence, not a count. Both branches assign explicitly rather than leaning on the column default, so the stamped value is never ambiguous. WHY the slot is keyed by (Cloud_Org__c, Credit_Type__c) rather than Cloud Org alone: each credit program runs its own approval chain with its own thresholds and its own remedy for a follow-on grant, so 'the org already has a live ledger' is only a bypass when that ledger belongs to the same program - a PoC engagement and a Startup Program grant on one org are independent grants that must each enter their own chain, and collapsing them into one slot would block a legitimate request rather than close a bypass. Keying per type keeps the anti-bypass argument intact within a program, because the aggregation the gate depends on (Initial_Credits__c plus Approved_Topups__c) is itself per ledger and per chain. WHAT KEEPS THE INVARIANT CLOSED after adding the second key component: the set of events by which a record can newly occupy, or move between, slots must stay complete. Credit_Type__c is declared updateable:false and is locked after create by design (switching a record's program post-creation would invalidate approver stamping), so it can never move a record between buckets and adds no fourth event to the rule's create / Cloud_Org__c change / leaving Cancelled triad. That immutability is load-bearing for this control, not incidental - making Credit_Type__c editable would silently reopen the split-ledger bypass across programs - and is pinned by a guard test rather than left to this comment.",
  "processType": "AutoLaunchedFlow",
  "status": "Active",
  "start": {
    "object": "Credits__c",
    "triggerType": "RecordBeforeSave",
    "recordTriggerType": "CreateAndUpdate",
    "connector": {
      "targetReference": "Check_Cloud_Org_Present"
    }
  },
  "recordLookups": [
    {
      "name": "Get_Open_Org_Ledger",
      "label": "Get Open Ledger on the Same Cloud Org",
      "locationX": 100,
      "locationY": 150,
      "object": "Credits__c",
      "filterLogic": "and",
      "filters": [
        {
          "field": "Cloud_Org__c",
          "operator": "EqualTo",
          "value": {
            "elementReference": "$Record.Cloud_Org__c"
          }
        },
        {
          "field": "Credit_Type__c",
          "operator": "EqualTo",
          "value": {
            "elementReference": "$Record.Credit_Type__c"
          }
        },
        {
          "field": "Credit_Lifecycle__c",
          "operator": "NotEqualTo",
          "value": {
            "stringValue": "Cancelled"
          }
        },
        {
          "field": "Id",
          "operator": "NotEqualTo",
          "value": {
            "elementReference": "$Record.Id"
          }
        }
      ],
      "getFirstRecordOnly": true,
      "storeOutputAutomatically": true,
      "assignNullValuesIfNoRecordsFound": false,
      "connector": {
        "targetReference": "Check_Open_Ledger_Found"
      }
    }
  ],
  "decisions": [
    {
      "name": "Check_Cloud_Org_Present",
      "label": "Cloud Org linked? (defensive guard)",
      "locationX": 200,
      "locationY": 50,
      "rules": [
        {
          "name": "cloud_org_present",
          "label": "Yes — look for an existing open ledger",
          "conditionLogic": "and",
          "conditions": [
            {
              "leftValueReference": "$Record.Cloud_Org__c",
              "operator": "IsNull",
              "rightValue": {
                "booleanValue": false
              }
            }
          ],
          "connector": {
            "targetReference": "Get_Open_Org_Ledger"
          }
        }
      ],
      "defaultConnector": {
        "targetReference": "Stamp_No_Open_Ledger"
      },
      "defaultConnectorLabel": "No — nothing to anchor on; stamp false and let schema-required surface the missing Cloud Org"
    },
    {
      "name": "Check_Open_Ledger_Found",
      "label": "Open ledger already on this Cloud Org?",
      "locationX": 100,
      "locationY": 250,
      "rules": [
        {
          "name": "open_ledger_found",
          "label": "Yes — this org already has a live ledger",
          "conditionLogic": "and",
          "conditions": [
            {
              "leftValueReference": "Get_Open_Org_Ledger",
              "operator": "IsNull",
              "rightValue": {
                "booleanValue": false
              }
            }
          ],
          "connector": {
            "targetReference": "Stamp_Has_Open_Ledger"
          }
        }
      ],
      "defaultConnector": {
        "targetReference": "Stamp_No_Open_Ledger"
      },
      "defaultConnectorLabel": "No — first ledger for this org, or every prior record is Cancelled"
    }
  ],
  "assignments": [
    {
      "name": "Stamp_Has_Open_Ledger",
      "label": "Stamp Has Open Org Ledger = true",
      "locationX": 0,
      "locationY": 350,
      "assignmentItems": [
        {
          "assignToReference": "$Record.Has_Open_Org_Ledger__c",
          "operator": "Assign",
          "value": {
            "booleanValue": true
          }
        }
      ]
    },
    {
      "name": "Stamp_No_Open_Ledger",
      "label": "Stamp Has Open Org Ledger = false",
      "locationX": 250,
      "locationY": 350,
      "assignmentItems": [
        {
          "assignToReference": "$Record.Has_Open_Org_Ledger__c",
          "operator": "Assign",
          "value": {
            "booleanValue": false
          }
        }
      ]
    }
  ]
}
