Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Reviewing an AI feature's data flow

After this lesson: I can review a feature's data flow against a checklist.

70 min lesson6 commandsAI coding agent lab: use opencode to explain and fix code, and check its work

Following the data through a feature

A data flow review follows personal data from where it comes in to where it ends. It asks where it goes, who sees it, how long it stays and why.

A review catches problems on paper, before a feature ships. It is a way of thinking, and not a certificate that anything is lawful.

By the end of this lesson

Note

I can review a feature's data flow against a checklist.

Key words

WordWhat it meansExample
Data flowthe path personal data takes through a feature
Checklista list of questions each step must answer
Approved placesomewhere you have decided data may goour database
Readera person or group who can see the data
Purposethe reason a step uses the data

The cells students fill in are left blank in this preview.

A flow is a list of steps

Write each step of the journey as one row. A step has a name, the data it uses, the place it goes to and who can read it there.

It also has the days it is kept, whether it was redacted first and the reason it is used. Five questions turn those rows into a review.

The five checks

CheckIt fails whenExample from the Run
Sent out unredactedData goes to an unapproved place, not redactedApp to model
Too many readersThe readers include everyoneLog write
No limitNo number of days is setLog write
Kept too longThe days are over your limitWeekly export, 400 days
No purposeNo reason is written downWeekly export

The cells students fill in are left blank in this preview.

The review reports each failure

Check each step in order and list every failure it has. One step can fail several checks. A step that fails none adds nothing to the list.

Count the failures by check. Then you can see that, for example, three steps have no limit, and fix them together.

A common mistake

Warning

Many people think a flow that passes the checklist is compliant with the law. It is not. It only shows that five questions have answers. Rules differ by place and by use, so a person with the right skills decides. This lesson is not legal advice.

Write the model helper, part 1

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// The token counts of a reply, or null when the reply carries none.' 'function count(data, name) {' '  return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the model helper, part 2

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' '  try {' '    const res = await fetch(base + \"/v1/chat/completions\", {' '      method: \"POST\",' '      headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' '      body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' '      signal: AbortSignal.timeout(30000),' '    });' '    if (res.ok === false) throw new Error(\"status \" + res.status);' '    const data = await res.json();' '    const text = data.choices[0].message.content;' '    return { text, inTokens: count(data, \"prompt_tokens\"), outTokens: count(data, \"completion_tokens\"), recorded: false };' '  } catch (error) {' '    console.log(\"Recorded sample: no model answered (\" + error.message + \").\");' '    return { text: sample, inTokens: null, outTokens: null, recorded: true };' '  }' '}' 'module.exports = { ask };' >> model.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the flow reviewer, part 1

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const approved = [\"our app\", \"our database\"];' 'const limit = 90;' 'const flow = [' '  { step: \"Form to app\", data: [\"email\", \"message\"], to: \"our app\", who: [\"support\"], keep: 30, redacted: false, why: \"Answer the customer\" },' '  { step: \"App to model\", data: [\"message\"], to: \"model host\", who: [\"model host\"], keep: 0, redacted: false, why: \"Write a reply\" },' '  { step: \"Log write\", data: [\"email\"], to: \"our database\", who: [\"everyone\"], keep: null, redacted: false, why: \"Debugging\" },' '];' > review.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the flow reviewer, part 2

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'flow.push({ step: \"Weekly export\", data: [\"email\"], to: \"analytics vendor\", who: [\"analyst\"], keep: 400, redacted: true, why: \"\" });' 'flow.push({ step: \"Cache\", data: [], to: \"our app\", who: [\"support\"], keep: 1, redacted: false, why: \"Speed\" });' 'function check(s) {' '  const out = [];' '  if (s.data.length > 0 && approved.indexOf(s.to) < 0 && s.redacted === false) out.push(\"sent out unredacted\");' '  if (s.who.indexOf(\"everyone\") >= 0) out.push(\"too many readers\");' '  if (s.keep === null) out.push(\"no limit\");' '  else if (s.keep > limit) out.push(\"kept too long\");' '  if (s.why.trim().length === 0) out.push(\"no purpose\");' '  return out;' '}' >> review.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the flow reviewer, part 3

Command
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' '  let failing = 0;' '  flow.forEach(function (s) {' '    const f = check(s);' '    if (f.length > 0) failing = failing + 1;' '    console.log(s.step + \" -> \" + (f.length === 0 ? \"passes\" : f.join(\", \")));' '  });' '  console.log(\"steps that fail: \" + failing + \" of \" + flow.length);' '  const q = \"In one short sentence, why write down the purpose of each step that uses personal data?\";' '  const sample = \"A written purpose shows why the data is used, so a step with no reason stands out.\";' '  const reply = await ask([{ role: \"user\", content: q }], sample, 60);' '  console.log(\"model said: \" + reply.text);' '}' 'main();' >> review.js"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Run the flow reviewer

Command
docker exec -w /home/node/project agent node review.js

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

What the Run prints

LineWhat it shows
Form to app -> passesApproved place, a reason and a limit
App to model -> sent out unredactedA message left without redaction
Log write -> too many readers, no limitTwo failures in one step
Weekly export -> kept too long, no purposeTwo more failures
Cache -> passesNo data, and it stays in our app
steps that fail: 3 of 5The summary
model said: ...A sentence. The words differ each run

The cells students fill in are left blank in this preview.

About this lab and its source: AI coding agent lab: use opencode to explain and fix code, and check its work

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.