Skip to content

DaVinci flow node data missing outcomes field — absent from OpenAPI spec, breaks downstream flow round-trip #86

Description

@samir-gandhi

Summary

DaVinciFlowGraphDataResponseElementsNodeData (and its request counterpart) has no field for a DaVinci flow node's outcomes — the array that defines a node's named exit paths (e.g. a form's "Save" vs. "Resend" buttons). The gap originates in the SDK's own OpenAPI spec, not just the generated Go structs, so it can't be fixed by regenerating from the current spec — the spec itself needs the property added.

This causes a real, reproducible bug downstream: terraform-provider-pingone's pingone_davinci_flow resource generates its schema from this SDK, so it also has no way to read or write outcomes on node data. Edges reference a specific outcome by ID via multiValueSourceId (which round-trips correctly today). When a flow with multi-outcome nodes is read via the SDK, re-exported, and re-applied, the outcome definitions are silently dropped while the edges referencing their IDs are preserved — producing a flow with edges that point at outcome IDs that no longer exist on any node. The flow renders broken in the DaVinci UI. Filing this against terraform-provider-pingone as well: [link/cross-reference once filed].

Reproduction

Given a flow node like this one from a live PingOne environment (a pingOneFormsConnector showForm node with two named outcomes):

{
  "id": "esqd1w6k6h",
  "nodeType": "CONNECTION",
  "capabilityClass": "render",
  "capabilityName": "showForm",
  "connectorId": "pingOneFormsConnector",
  "outcomes": [
    { "result": "submit", "label": "Save", "id": "0qw160q8zo" },
    { "result": "resend", "label": "Didn't receive an email? Resend", "id": "k0hv0wr75q" }
  ]
}

Two edges elsewhere in the same flow route based on those outcome IDs:

{ "source": "esqd1w6k6h", "target": "vzo75y0cg1", "multiValueSourceId": "0qw160q8zo" }
{ "source": "esqd1w6k6h", "target": "vzo75y0cg1", "multiValueSourceId": "k0hv0wr75q" }
resp, _, err := apiClient.DaVinciFlowsApi.GetFlowById(ctx, environmentID, flowID).Execute()
node := resp.GraphData.Elements.Nodes[/* the showForm node */]
node.Data.Outcomes // does not exist — compile error; the only way to access this is
                    // node.Data.AdditionalProperties["outcomes"], as an untyped interface{}

outcomes lands in NodeData.AdditionalProperties["outcomes"] as an untyped interface{} (a []interface{} of map[string]interface{}), because the field isn't declared in the OpenAPI spec at all — confirmed by grepping pingone/api/openapi.yaml for outcome (case-insensitive) with zero matches, at the current main HEAD (2d5939c0, = v0.11.0).

Root cause

The OpenAPI spec's DaVinciFlowGraphDataResponse schema (and the parallel ...Request schema) enumerates node data properties explicitly:

elements:
  nodes:
  - data:
      capabilityName: capabilityName
      connectorId: connectorId
      label: label
      nodeType: nodeType
      type: type
      linterError: [...]
      name: name
      connectionId: connectionId
      idUnique: idUnique
      id: id
      capabilityClass: capabilityClass
      properties: {...}
      status: status

outcomes is absent from this list. Because the generated Go structs (model_da_vinci_flow_graph_data_response_elements_node_data.go, model_da_vinci_flow_graph_data_request_elements_node_data.go) are produced directly from this spec, they only have a typed field for each enumerated property, plus a generic AdditionalProperties map[string]interface{} catch-all for anything else. outcomes falls into that catch-all.

The catch-all does round-trip through MarshalJSON/UnmarshalJSON today (values in AdditionalProperties are re-serialized on marshal), so raw pass-through consumers of the SDK aren't silently losing data at the SDK layer by themselves. The actual breakage happens one layer up: consumers that build typed request objects from a Terraform-style intermediate representation (e.g. terraform-provider-pingone, or pingcli-plugin-terraformer's export/reflection pipeline) have no typed field to map to/from, and their own generated schemas — themselves generated from this SDK — have no attribute for outcomes either. The result is that outcomes never survives a read → external representation → write round-trip in any of the tooling built on top of this SDK.

Suggested fix

Add outcomes to the OpenAPI spec's node data schema (both DaVinciFlowGraphDataResponse and DaVinciFlowGraphDataRequest node data definitions) as an array of objects with:

  • id (string, required) — client-assigned; consumers depend on this being preserved verbatim since edges reference it via multiValueSourceId
  • result (string) — the internal outcome key (e.g. submit, resend)
  • label (string) — the user-facing label (e.g. "Save", "Didn't receive an email? Resend")

Regenerate the SDK from the updated spec so NodeData.Outcomes becomes a typed field. outcomes is conditional — most nodes don't have it (only certain render capabilities with multiple exit paths, based on observation), so it should be optional/omitempty like the other node data fields.

Environment

  • SDK version: github.com/pingidentity/pingone-go-client v0.11.0 (confirmed still current — this is the tip of main as of this report)
  • Also reproduced against v0.10.1 (the version terraform-provider-pingone currently pins) and all other cached versions back to v0.2.0 — the gap has existed throughout
  • Downstream impact confirmed in terraform-provider-pingone's generated pingone_davinci_flow schema (internal/service/davinci/resource_davinci_flow_gen.go), and in pingcli-plugin-terraformer's export pipeline

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions