How to visualize CSV as a workflow

A workflow is a process with rework in it. How to write a backward Line to reference in a CSV file, cap the retry so revisions cannot cycle forever, and tell a real loop from a mistyped row number.

A worked example, stage by stage

  1. Shapes, no connections

    Rows 1 to 6 with the Shape column filled in and nothing else: a Start for "Receive a discount request from the customer", three Process rows, the Decision "Margin at or above 40%?", and the rep-level approval. Nothing points anywhere yet. This is roughly what a raw export gives you: a list with a type column bolted on, which is a table, not a workflow.

  2. The forward path

    Line to fills in and the approval ladder appears: row 5 forks to 6 or 7, row 7 to 8 or 10, row 10 to 11 or 13, each tier handing the margin band to a more senior approver. Every number in this prefix is larger than the row holding it, so all the arrows run forward and the file could still be read top to bottom as a list.

  3. The number that points backwards

    Rows 15 to 17 add the rework block, and row 16 is where the file stops being a list. "Second time back from the same approver?" carries Line to 3,17 with Line text First revision,Second revision: the 3 is smaller than 16, so a first revision returns to "Calculate gross margin after discount": a changed price is a changed margin and may land in a different band. The second revision goes to 17 instead, which is the cap.

  4. The whole workflow with lanes

    All twenty-four rows, with Quote, Margin check, Approval, Rework and Issue across the top and Sales rep, Sales manager, Finance and Commercial director down the side. The Rework column now visibly collects rows 15 to 17, which is why the loop is legible on the canvas and invisible in the export. The last backward reference sits on row 20, where "Asks for a bigger discount" sends the customer's counter back to row 15 rather than to a new quote.

How it works

  1. Re-order the export into process order

    System exports come out in timestamp or ticket order, which is the order things happened, not the order the process runs. Sort the rows into the sequence a single case travels before you write a single Line to value, because those values are row positions and re-sorting the file afterwards invalidates every one of them.

  2. Check the header row survived the export

    Columns are matched by header name, so the header row is the only part of the file that has to be exactly right. Confirm it reads Shape, Box text, Line to, Line text. A byte-order mark from a UTF-8 export attaches itself to the first header name, and a semicolon-delimited export from a European system puts the whole line into one cell: in both cases the column is not recognised and is carried through as an unused extra rather than failing loudly.

  3. Write the forward path first

    Fill in Line to for the straight-through case only, where every number is larger than the row it sits on. Get the workflow running end to end with no rework at all. Loops added to a path you have not yet verified are almost impossible to read back, because you cannot tell a return edge from a wrong number when both point at a row you are unsure of.

  4. Add one rework row and point the return edge at it

    Give the revision its own row ("Revise the discount, the price or the terms") and send every rejecting Decision to that one row rather than duplicating a rework step under each approver. Then write the return edge out of the rework block, pointing at the row where the changed input is re-evaluated. In the example that is row 3, the margin calculation, not row 1.

  5. Cap the retry

    An uncapped loop is a workflow that can run forever, and in a real process it does not. Add a Decision after the rework row that asks how many times this has come back (row 16, "Second time back from the same approver?") with Line to 3,17: round the loop once, escalate on the second pass. Quote that cell so the comma stays inside it.

  6. Drop the file in and read the backward arrows

    Drag the .csv onto the spreadsheet area of a new chart, or paste the text straight into it, and the diagram renders. Then read every arrow that runs backwards. Each one should be a case you can name out loud: a revision, an escalation, a counter-offer. An arrow you cannot name is a transposed row number, and this is the only view in which it is obvious.

Frequently asked questions

Can a Line to value point at an earlier row?

Yes, and that is the whole mechanism for rework. Line to takes the 1-based position of the target row and nothing constrains it to be larger than the row it sits on, so a 3 in row 16's cell draws an arrow from 16 back up to 3. The renderer routes it around the boxes; you do not place it. Because there is no separate loop marker, reading a CSV for its loops means scanning for numbers smaller than their own row: that is the only signal in the file.

How do I stop a rework loop from cycling forever?

Put a Decision on the return path that counts the attempt. In the example, row 16 asks "Second time back from the same approver?" and carries Line to 3,17 with Line text First revision,Second revision, so the first pass goes round and the second leaves the loop for row 17, "Hold the discount or walk away?". The count is not stored anywhere: the diagram documents the rule, and the rule is what people follow. What matters is that the loop has a labelled way out on the chart rather than an implicit one in someone's head.

How do I tell a genuine loop from a wrong row number in someone else's file?

Three tests. Does the target row redo work that the rework actually changed? A loop that returns to a step whose output cannot differ this time is a mistake. Does the backward edge leave a Decision? A Process row whose only Line to points backwards, with no forward exit, makes the rest of the file unreachable and is nearly always a transposition. And is the branch labelled? Real loops carry a Line text naming the case; typos never do, because nobody labels an edge they did not mean to draw.

My export has one row per approval event, not one per step. What do I do?

Collapse it. An audit table repeats the same step once per occurrence, so a deal that was revised twice appears as two "returned to requester" rows, and importing it directly produces a diagram of one case rather than a definition of the process. Pull out the distinct steps, keep one row each, and let the backward reference carry the repetition: that substitution is the point of the loop. /csv-workflow-generator has the shorter version of this if you just want to see the file rendered first.

Does the diagram stay readable when the loops cross the lanes?

Routing is computed rather than drawn, so a return edge from the Rework column back to the Quote column is routed around the boxes without you moving anything. What makes a looping workflow unreadable is not the arrows but the row order: keep the rework rows together, as rows 15 to 17 are in the example, instead of scattering a revision step under each approver. Three approvers with a rework row each produce three loops that are really one.

Open the approval workflow example

The template behind this guide

CSV approval workflow template (discount approval by margin) — A discount approval workflow you can paste in as CSV: three margin bands, four approver lanes, and rework loops whose Line to values point backwards up the file to a row number lower than the row they sit on.

More in Process mapping guides