{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/run402-com/json-schema/run402-com-project-transfer-preview-schema.json",
  "title": "ProjectTransferPreview",
  "description": "v1.59 — safe review document. secret_names are present; secret VALUES are never returned. signers is [] in Phase 1A.",
  "x-generated": "2026-10-29",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/run402-com-openapi.json#/components/schemas/ProjectTransferPreview",
  "type": "object",
  "properties": {
    "transfer_id": {
      "type": "string",
      "format": "uuid"
    },
    "project_id": {
      "type": "string"
    },
    "project_name_snapshot": {
      "type": [
        "string",
        "null"
      ]
    },
    "status": {
      "type": "string",
      "enum": [
        "pending",
        "accepted",
        "cancelled",
        "expired"
      ]
    },
    "recipient_kind": {
      "type": "string",
      "enum": [
        "wallet",
        "email",
        "org"
      ]
    },
    "from_wallet": {
      "type": "string"
    },
    "from_wallet_display": {
      "type": "string",
      "description": "Truncated form, e.g. 0xaaaa…1234"
    },
    "to_wallet": {
      "type": "string"
    },
    "to_wallet_display": {
      "type": "string"
    },
    "to_email": {
      "type": [
        "string",
        "null"
      ],
      "format": "email"
    },
    "billing_policy": {
      "type": "string",
      "enum": [
        "migrate"
      ]
    },
    "message": {
      "type": [
        "string",
        "null"
      ]
    },
    "initiated_at": {
      "type": "string",
      "format": "date-time"
    },
    "expires_at": {
      "type": "string",
      "format": "date-time"
    },
    "kysigned_record_id": {
      "type": [
        "string",
        "null"
      ]
    },
    "terms_sha256": {
      "type": "string"
    },
    "custom_domains": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "hostname": {
            "type": "string"
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      }
    },
    "subdomains": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      }
    },
    "functions": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "runtime": {
            "type": [
              "string",
              "null"
            ]
          },
          "timeout_ms": {
            "type": [
              "integer",
              "null"
            ]
          },
          "memory_mb": {
            "type": [
              "integer",
              "null"
            ]
          },
          "scheduled": {
            "type": "boolean"
          }
        }
      }
    },
    "secret_names": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Names ONLY. Secret values are never returned anywhere in this response."
    },
    "mailbox_summary": {
      "type": "object",
      "properties": {
        "count": {
          "type": "integer"
        },
        "slugs_truncated": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      }
    },
    "ci_bindings_to_be_revoked": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "github_repository": {
            "type": [
              "string",
              "null"
            ]
          },
          "github_subject_pattern": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    },
    "signers": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string"
          },
          "chain": {
            "type": "string"
          }
        }
      },
      "description": "Empty in Phase 1A. signers are currently wallet-scoped; this field is reserved for the future case where they become project-scoped."
    },
    "github_repo_note": {
      "type": "string",
      "description": "Verbatim clarifier: 'GitHub repository ownership is not transferred by Run402. B must receive repo/admin access separately.'"
    },
    "billing_implications": {
      "type": "object",
      "properties": {
        "from_org_id": {
          "type": [
            "string",
            "null"
          ],
          "format": "uuid"
        },
        "target_org_id": {
          "type": [
            "string",
            "null"
          ],
          "format": "uuid"
        },
        "tier": {
          "type": [
            "string",
            "null"
          ]
        },
        "secrets_count": {
          "type": "integer"
        },
        "functions_count": {
          "type": "integer"
        },
        "custom_domains_count": {
          "type": "integer"
        }
      }
    },
    "retain_member": {
      "type": [
        "object",
        "null"
      ],
      "description": "Present only when an email-addressed transfer includes a sender proposal to stay on as a developer of the receiving org.",
      "properties": {
        "principal_id": {
          "type": "string",
          "format": "uuid"
        },
        "role": {
          "type": "string",
          "enum": [
            "developer"
          ]
        },
        "sender_label": {
          "type": [
            "string",
            "null"
          ]
        },
        "scope": {
          "type": "string",
          "enum": [
            "organization"
          ]
        },
        "note": {
          "type": "string"
        },
        "accept_field": {
          "type": "string",
          "enum": [
            "accept_retained_member"
          ]
        }
      }
    },
    "payment_drain": {
      "type": "object",
      "description": "Payment-generation drain state for this transfer. Existing pre-cutoff payments remain discoverable/reconcilable; no post-cutoff identity, settlement, lease, or delivery is admitted.",
      "required": [
        "active",
        "mutation_id",
        "cutoff_epoch",
        "expected_by",
        "blocker_count",
        "active_lease_count",
        "outgoing_generation_settled_intent_count"
      ],
      "properties": {
        "active": {
          "type": "boolean"
        },
        "mutation_id": {
          "type": [
            "string",
            "null"
          ]
        },
        "cutoff_epoch": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 1
        },
        "expected_by": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time"
        },
        "blocker_count": {
          "type": "integer",
          "minimum": 0
        },
        "active_lease_count": {
          "type": "integer",
          "minimum": 0
        },
        "outgoing_generation_settled_intent_count": {
          "type": "integer",
          "minimum": 0
        }
      },
      "additionalProperties": false
    },
    "source_organization": {
      "allOf": [
        {
          "$ref": "#/$defs/OrganizationReference"
        }
      ],
      "nullable": true,
      "description": "Organization that currently owns the offered project."
    },
    "destination_organization": {
      "allOf": [
        {
          "$ref": "#/$defs/OrganizationReference"
        }
      ],
      "nullable": true,
      "description": "Resolved receiving organization when known."
    },
    "initiated_by": {
      "allOf": [
        {
          "$ref": "#/$defs/OperationActorSnapshot"
        }
      ],
      "nullable": true,
      "description": "Immutable transfer-initiation actor snapshot."
    },
    "recipient_principal": {
      "allOf": [
        {
          "$ref": "#/$defs/PrincipalRepresentation"
        }
      ],
      "nullable": true,
      "description": "Current receiving principal when resolution is possible; this display record does not alter transfer authorization."
    },
    "vault": {
      "type": [
        "object",
        "null"
      ],
      "description": "The project's vault and its footprint in the recipient's pool; null when the project has no admitted vault. Billed bytes (the per-vault minimum applies) beside decimal labels. Informational: being over the limit never refuses accept.",
      "properties": {
        "repo_id": {
          "type": "string"
        },
        "storage_profile": {
          "type": "string",
          "enum": [
            "managed",
            "byo"
          ]
        },
        "source_bytes": {
          "type": "integer"
        },
        "source": {
          "type": "string"
        },
        "recipient_vault_usage_after_accept": {
          "type": "object",
          "properties": {
            "source_bytes": {
              "type": "integer"
            },
            "source": {
              "type": "string"
            },
            "source_bytes_limit": {
              "type": [
                "integer",
                "null"
              ]
            },
            "source_limit": {
              "type": [
                "string",
                "null"
              ]
            }
          }
        },
        "over_limit": {
          "type": "boolean"
        }
      }
    },
    "vault_handover": {
      "type": [
        "object",
        "null"
      ],
      "description": "The vault handover this transfer requires; null when the project has no admitted vault. A transfer moves the project's KyGit vault, and the gateway never holds its key, so the recipient names the principal that receives the source (POST /agent/v1/transfers/{transfer_id}/vault-handover), the sender's writer admits that principal's key and wraps the source key for it (`run402 transfer handover <transfer_id>`), and only then can accept succeed. `state` is derived from the vault's writer set and envelopes at read time.",
      "properties": {
        "repo_id": {
          "type": "string"
        },
        "state": {
          "type": "string",
          "enum": [
            "awaiting_recipient",
            "awaiting_sender",
            "complete"
          ]
        },
        "recipient_principal_id": {
          "type": [
            "string",
            "null"
          ],
          "format": "uuid"
        },
        "recipient": {
          "type": [
            "object",
            "null"
          ],
          "description": "The nominee's published keystore identity (public keys only) the sender's writer admits and wraps to.",
          "properties": {
            "principal_id": {
              "type": "string",
              "format": "uuid"
            },
            "writer_key_id": {
              "type": "string"
            },
            "signing_pubkey": {
              "type": "string"
            },
            "ek_fingerprint": {
              "type": "string"
            },
            "public_key": {
              "type": "string"
            }
          }
        },
        "current_epoch": {
          "type": "string",
          "description": "16 lowercase hex: the vault's current epoch."
        },
        "writer_admitted": {
          "type": "boolean"
        },
        "envelope_current_epoch": {
          "type": "boolean"
        }
      }
    }
  },
  "$defs": {
    "AuthenticatorSnapshot": {
      "type": "object",
      "required": [
        "authenticator_id",
        "kind",
        "public_subject"
      ],
      "properties": {
        "authenticator_id": {
          "type": "string"
        },
        "kind": {
          "type": "string"
        },
        "public_subject": {
          "type": "string"
        }
      }
    },
    "AuthoritySnapshot": {
      "type": "object",
      "required": [
        "kind"
      ],
      "description": "Discriminated immutable action-time authority: organization_membership, project_grant, grant_key, ci, system, legacy, or a preserved future kind. A link is never an authority kind.",
      "properties": {
        "kind": {
          "type": "string"
        },
        "org_id": {
          "type": [
            "string",
            "null"
          ]
        },
        "project_id": {
          "type": [
            "string",
            "null"
          ]
        },
        "membership_id": {
          "type": [
            "string",
            "null"
          ]
        },
        "grant_id": {
          "type": [
            "string",
            "null"
          ]
        },
        "grant_key_id": {
          "type": [
            "string",
            "null"
          ]
        },
        "credential_id": {
          "type": [
            "string",
            "null"
          ]
        },
        "role": {
          "type": [
            "string",
            "null"
          ]
        },
        "scope": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "reason_code": {
          "type": [
            "string",
            "null"
          ]
        }
      },
      "additionalProperties": true
    },
    "LinkedIdentityRepresentation": {
      "type": "object",
      "required": [
        "identity_link_id",
        "proof_protocol",
        "kind",
        "public_subject",
        "display_subject",
        "verified_at",
        "status",
        "effective_status",
        "revoked_at"
      ],
      "properties": {
        "identity_link_id": {
          "type": "string"
        },
        "proof_protocol": {
          "type": "string",
          "enum": [
            "run402.identity-link.nostr.v1",
            "run402.identity-link.nostr.human.v1"
          ]
        },
        "kind": {
          "type": "string",
          "description": "Current v1 value is nostr_nip01; clients must preserve unknown future kinds."
        },
        "public_subject": {
          "type": "string"
        },
        "display_subject": {
          "type": "string"
        },
        "verified_at": {
          "type": "string",
          "format": "date-time"
        },
        "status": {
          "type": "string",
          "enum": [
            "active",
            "revoked"
          ]
        },
        "effective_status": {
          "type": "string",
          "enum": [
            "active",
            "revoked",
            "principal_inactive"
          ]
        },
        "revoked_at": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time"
        }
      }
    },
    "LinkedIdentitySnapshot": {
      "type": "object",
      "required": [
        "identity_link_id",
        "kind",
        "public_subject",
        "display_subject",
        "verified_at",
        "status_at_capture"
      ],
      "properties": {
        "identity_link_id": {
          "type": "string"
        },
        "kind": {
          "type": "string"
        },
        "public_subject": {
          "type": "string"
        },
        "display_subject": {
          "type": "string"
        },
        "verified_at": {
          "type": "string",
          "format": "date-time"
        },
        "status_at_capture": {
          "type": "string",
          "enum": [
            "active"
          ]
        }
      }
    },
    "OperationActorSnapshot": {
      "type": "object",
      "required": [
        "schema_version",
        "principal",
        "authenticator",
        "authority",
        "captured_at"
      ],
      "properties": {
        "schema_version": {
          "type": "integer",
          "enum": [
            1
          ]
        },
        "principal": {
          "allOf": [
            {
              "$ref": "#/$defs/PrincipalSnapshot"
            }
          ],
          "nullable": true
        },
        "authenticator": {
          "allOf": [
            {
              "$ref": "#/$defs/AuthenticatorSnapshot"
            }
          ],
          "nullable": true
        },
        "authority": {
          "$ref": "#/$defs/AuthoritySnapshot"
        },
        "captured_at": {
          "type": "string",
          "format": "date-time"
        }
      }
    },
    "OrganizationReference": {
      "type": "object",
      "required": [
        "org_id"
      ],
      "properties": {
        "org_id": {
          "type": "string",
          "format": "uuid"
        }
      }
    },
    "PrincipalRepresentation": {
      "type": "object",
      "required": [
        "principal_id",
        "principal_type",
        "display_name",
        "linked_identities"
      ],
      "properties": {
        "principal_id": {
          "type": "string"
        },
        "principal_type": {
          "type": "string"
        },
        "display_name": {
          "type": [
            "string",
            "null"
          ]
        },
        "linked_identities": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/LinkedIdentityRepresentation"
          }
        }
      }
    },
    "PrincipalSnapshot": {
      "type": "object",
      "required": [
        "principal_id",
        "principal_type",
        "display_name_at_capture",
        "linked_identities_at_capture"
      ],
      "properties": {
        "principal_id": {
          "type": "string"
        },
        "principal_type": {
          "type": "string"
        },
        "display_name_at_capture": {
          "type": [
            "string",
            "null"
          ]
        },
        "linked_identities_at_capture": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/LinkedIdentitySnapshot"
          }
        }
      }
    }
  }
}