ocelkitDocs

Guides

Process files

Name the steps of a process and the order you expect. The editor catches a wrong name.

A process file describes one process in your data: the activities you care about, and the order you expect them in. ocelkit counts what really happened and draws it as a map.

Here's the payments file from the introduction, with one more pair:

processes/payments.ts
import { defineProcess } from 'ocelkit'// Do customers pay once we confirm their order, or only after a reminder?export default defineProcess({  name: 'Order payments',  activities: {    confirmOrder: 'confirm order',    paymentReminder: 'payment reminder',    payOrder: 'pay order',  },  flows: {    orders: [      ['confirmOrder', 'payOrder'],      ['confirmOrder', 'paymentReminder'],      ['paymentReminder', 'paymentReminder'],      ['paymentReminder', 'payOrder'],    ],  },})

Let's break this down:

  • The file lives in your processes folder. Every .ts file there is one process, and its default export is the result of defineProcess.
  • name is the title of the map.
  • activities names the event types you care about.
  • flows lists the pairs of activities you expect, for each type of object.

defineProcess doesn't change your file. It tells your editor which activities you declared, so a typo in a flow is underlined right away. The defineProcess reference lists every field.

Name

name is the title of the map, so write it for the people who'll read it:

name: 'Order payments',

ocelkit knows the process by its file name. processes/payments.ts is the process payments, and that's how the workspace lists it.

Activities

activities gives each event type you care about a short key:

activities: {  confirmOrder: 'confirm order',  paymentReminder: 'payment reminder',  payOrder: 'pay order',},

The value is the event type, spelled exactly as it is in your data. The key is yours: it's the name you use in the flows. Every activity is a box on the map, with the number of its events.

To see the event types in your log, run ocelkit describe:

Terminal
$ npx ocelkit describe
Output
Event types  confirm order      2000  create package     1128  failed delivery     311  item out of stock  1544  package delivered  1128  pay order          2000  payment reminder    566  pick item          7659  place order        2000  reorder item       1544  send package       1128Object types  customers    15  employees    18  items      7659  orders     2000  packages   1128  products     20

The Commands reference has more on ocelkit describe and its flags.

A value that isn't an event type in the data is an error. The check tells you the closest one:

Output
processes/payments.ts  error  activities.payOrder  "pay ordr" is not an event type in the data. Closest: "pay order".

The map counts by event type, so each event type can have only one activity. Two keys for the same event type is an error too:

activities: {  payOrder: 'pay order',  paid: 'pay order',},
Output
processes/payments.ts  error  activities.paid  Another activity already names "pay order". Each event type can have one activity.

Flows

flows says what each line counts. You write an object type from your data, then a list of pairs of activities:

flows: {  orders: [['confirmOrder', 'payOrder']],},

A line counts each connection between an instance of the first event type and an instance of the second event type, where an instance of the object type is present in both, and no other activity of the flow comes between them. Here, a confirm order instance connects to a pay order instance when the same order is present in both. Each connection adds 1 to the line.

Here's that on five events from two orders. Press Next to follow each order:

What does the number on the line count?1 of 4
  1. 09:00confirm orderorder A
  2. 09:30confirm orderorder B
  3. 10:00payment reminderorder A
  4. 10:15pay orderorder B
  5. 11:00pay orderorder A
  1. order ANot followed yet
  2. order BNot followed yet

Five events from two orders. The line counts orders: how many went from confirm order straight to pay order. To find out, ocelkit reads the log one order at a time.

The best way to see what that means is to build a flow up, one step at a time.

Start with one pair

Here's a file with two activities and one pair:

processes/payments.ts
import { defineProcess } from 'ocelkit'export default defineProcess({  name: 'Order payments',  activities: {    confirmOrder: 'confirm order',    payOrder: 'pay order',  },  flows: {    orders: [['confirmOrder', 'payOrder']],  },})
The map of the file. A line goes from confirm order, with 2,000 events, to pay order, with 2,000 events. Its count is 2,000.
Order paymentsprocesses/payments.ts
  • orders
2,000
confirm order2,000
pay order2,000

All 2,000 orders went from confirm order to pay order.

Some of them got a payment reminder in between. The flow doesn't list reminders, so ocelkit skips over them. Open Not on the map in the workspace, and you'll find payment reminder and place order under Activities left out: the orders have these events, but the flow doesn't list them.

Add an activity

Add the payment reminder, and the two pairs around it:

processes/payments.ts
activities: {  confirmOrder: 'confirm order',  paymentReminder: 'payment reminder',  payOrder: 'pay order',},flows: {  orders: [    ['confirmOrder', 'payOrder'],    ['confirmOrder', 'paymentReminder'],    ['paymentReminder', 'payOrder'],  ],},
The map now has payment reminder, with 566 events, between the two. 1,557 orders go from confirm order to pay order, 443 from confirm order to payment reminder, and 443 from payment reminder to pay order.
Order paymentsprocesses/payments.ts
  • orders
1,557
443
443
confirm order2,000
payment reminder566
pay order2,000

1,557 orders went straight from confirm order to pay order, and the other 443 got a reminder first.

The first count fell from 2,000 to 1,557. Now that the flow lists reminders, an order that got one no longer goes straight from confirm order to pay order. When you add an activity, the counts around it change.

Add what's missing

Not on the map now has a pair under Pairs not in the file: payment reminder → payment reminder, 123 times. Some orders got another reminder after the first. The data has that pair, but the flow doesn't, so the map doesn't draw it.

Add the pair to the flow:

processes/payments.ts
orders: [  ['confirmOrder', 'payOrder'],  ['confirmOrder', 'paymentReminder'],  ['paymentReminder', 'paymentReminder'],  ['paymentReminder', 'payOrder'],],
The same map, with a loop on payment reminder. Its count is 123.
Order paymentsprocesses/payments.ts
  • orders
1,557
443
123
443
confirm order2,000
payment reminder566
pay order2,000

A pair from an activity to itself is a loop. Now the map has everything the orders did between confirm order and pay order.

More than one type of object

An event can involve more than one object. ocelkit describe --links shows which object types the events of each type are attached to. Here are three of its lines:

Output
  confirm order      customers 2000, employees 2000, items 2000, orders 2000, products 2000  pay order          items 2000, orders 2000, products 2000  pick item          employees 7659, items 7659, products 7659

Confirming an order involves the order and its items. Picking an item involves the item, but not its order. To follow the items too, give them their own flow:

processes/confirmed.ts
import { defineProcess } from 'ocelkit'export default defineProcess({  name: 'After confirmation',  activities: {    confirmOrder: 'confirm order',    payOrder: 'pay order',    pickItem: 'pick item',  },  flows: {    orders: [['confirmOrder', 'payOrder']],    items: [['confirmOrder', 'pickItem']],  },})
Two lines leave confirm order. The orders line goes to pay order, 2,000 times. The items line, in another color, goes to pick item, with 7,659 events, 5,717 times.
After confirmationprocesses/confirmed.ts
  • orders
  • items
2,000
5,717
confirm order2,000
pay order2,000
pick item7,659

Each object type has its own line color. The line to pick item counts items, not orders: 5,717 items were picked after their order was confirmed. The other 1,942 were picked before, so Not on the map lists pick item → confirm order, 1,942 times.

The same events can be in the story of more than one object. Here are both flows on four events of one order and its two items:

What does each line count when events share objects?1 of 5
  1. 09:00confirm orderorder Aitem 1item 2
  2. 09:40pick itemitem 1
  3. 10:00pay orderorder Aitem 1item 2
  4. 10:20pick itemitem 2
  1. order ANot followed yet
  2. item 1Not followed yet
  3. item 2Not followed yet

Four events of one order and its two items. Some events involve all three. ocelkit still reads one object at a time, each with the flow of its own type.

That's why you write an object type in flows: it says which object the two events of a pair must share. The confirm order event at 09:00 involves order A, item 1 and item 2. Under orders, it pairs with the pay order event of order A, and adds 1 to the orders line. Under items, it pairs with the pick item event of item 1, and with the pick item event of item 2, and adds 2 to the items line. One event is in three pairs, because it involves three objects.

Every activity of a flow needs events attached to its object type. Pick item has none attached to an order, so in the orders flow, a pair with it can never happen. The check warns you:

processes/confirmed.ts
orders: [  ['confirmOrder', 'payOrder'],  ['payOrder', 'pickItem'],],
Output
processes/confirmed.ts  warn   flows.orders[1]  No "pick item" event links to an object of type "orders".

A warning doesn't stop the map. The workspace shows it above the map until you fix it.

When a name is wrong

A pair can only use the keys of activities. Use any other, and your editor underlines it before you save:

orders: [['confirmOrder', 'payOrdr']],
In your editor
Type '"payOrdr"' is not assignable to type '"confirmOrder" | "payOrder"'. Did you mean '"payOrder"'?

The object type of a flow must be one in your data. The check suggests the closest one:

Output
processes/payments.ts  error  flows.order  "order" is not an object type in the data. Closest: "orders".

Writing good process files

These are habits that make a map easier to read. They're not rules: ocelkit draws any file that passes the check, and your question may need a different shape.

Ask one question per file

A map that answers one question is quick to read. Write the question in a comment at the top of the file, where you, your team and your agent will see it:

Avoid
// Do customers pay on time? Do packages arrive? Who picks the items?
Better
// Do customers pay once we confirm their order, or only after a reminder?

Got a second question? Write a second file. Each file is its own map.

A file that maps every activity in your log has its place too: it's a good first look at all your data. It's just hard to read one answer from it.

Start small

Start with the two or three activities your question is about. Then open Not on the map, and add only what the question needs, as you did with the reminders above.

Name keys after their event types

The flows are what people and agents read, so a key should say what it is:

Avoid
activities: { a1: 'confirm order', a2: 'pay order' },flows: { orders: [['a1', 'a2']] },
Better
activities: { confirmOrder: 'confirm order', payOrder: 'pay order' },flows: { orders: [['confirmOrder', 'payOrder']] },

List pairs in the order they happen

The map keeps the order of your file where it can. List the pairs from start to end, and the map reads the same way.

Next steps

Now that you can write a process file, learn to read its map in Reading the map, and to check it against your data in Checking your files.