Skip to main content

Check Performance Data - How the journey rules work

A journey is one JSON file in src/DfE.CheckPerformanceData.Web/Data/QuestionFlows/. The pages, questions and options are in the file. A rule decides one of three things.

Where you put the rule What it controls
visibleWhen on an option Whether the option shows
visibleWhen on a question Whether the whole question shows
optionalWhen on a question Whether the user can leave the question blank
requireAtLeastOneWhen on a page Whether the "fill in at least one" rule is on

If there is no rule, the option or question always shows, and the question is mandatory unless it says "optional": true.

The three kinds of test

A rule is a list of tests. Every test in the list must be true.

1. A fact test

A fact test asks something about the pupil, the school or the qualification. These things are not answers in the journey.

{ "fact": "school.isIndependent", "is": false }

This means "the school is not independent". You must always write "is".

There are only four facts:

Fact True when
pupil.isAddBack DfE added the pupil back into the results (inclusion flag 403)
school.isIndependent The school is an "Other Independent School" (GIAS type 11)
school.isOnNotOnRollList The school is on the not-on-roll college list
qualification.hasSyllabusCodes The selected qualification has syllabus codes

Date facts are different. A date fact gives a date, not true or false. A date rule on a Date question compares the answer with it:

{ "check": "onOrAfter", "fact": "cohort.start", "message": "..." }

The code gives the date, and the flow file holds the rule. If a date fact has no value, the rule is skipped and the app logs a warning. The date rules and the date facts are in question-flows.md.

2. An answer test

An answer test asks what the user answered earlier in the journey.

{ "answer": "reason", "in": ["english-not-first-language"] }

This means "the answer to the question reason is english-not-first-language". Put more values in the list to mean "any of these answers".

3. An any-of test

An any-of test is true when one or more of the tests inside it are true. Use it for "or".

{ "anyOf": [
  { "fact": "school.isIndependent", "is": true },
  { "fact": "school.isOnNotOnRollList", "is": true }
] }

A full example

The "Not on roll" option on the KS4 June removal reason page:

"visibleWhen": [
  { "fact": "pupil.isAddBack", "is": false },
  { "anyOf": [
    { "fact": "school.isIndependent", "is": true },
    { "fact": "school.isOnNotOnRollList", "is": true }
  ] }
]

In plain English: show this option when the pupil was not added back, and the school is independent or is on the college list.

How to make common changes

Hide an option from add-back pupils. Add this to the option:

"visibleWhen": [{ "fact": "pupil.isAddBack", "is": false }]

Show an option to independent schools only:

"visibleWhen": [{ "fact": "school.isIndependent", "is": true }]

Add a second condition. Add another test to the list. Both must be true:

"visibleWhen": [
  { "fact": "pupil.isAddBack", "is": false },
  { "fact": "school.isIndependent", "is": false }
]

Make a question optional after a certain answer:

"optionalWhen": [{ "answer": "first-language", "in": ["other", "not-known"] }]

Remove a rule. Delete the visibleWhen (or optionalWhen) line. The option or question then always shows, or is always mandatory.

You do not need to change C# code for any of these changes. Edit the JSON, then run the app.

When you need code

You need code only for a new fact: something about the pupil, school or qualification that the journey does not ask about. To add one:

  1. Write a small class in Application/Journey/Conditions/ that returns true or false.
  2. Register it in Application/DependencyManager.cs.
  3. Add it to the facts table in docs/question-flows.md.

Do not write a class for "not X" or "X or Y". Use "is": false or anyOf in the JSON.

For a new date fact, follow the steps in question-flows.md.

What protects you from mistakes

  • A badly written test stops the file from loading. For example, a plain string, a missing "is", or an anyOf with only one test. The error tells you what to write.

  • The rules fail closed. If the app cannot decide, it takes the safe path:

    • A fact name with no class hides the option.
    • A question that the user has not answered yet does not make a later question optional.
  • The unit tests check every flow file:

    • Each fact has a class.
    • Each answer test names a real question in the same file.
    • Each value is one of that question's options.

    A typo in a fact name, a question id or an option value fails the build.

The tests check that the rules are valid, but not that they are the rules you want. After a change, go through the journey by hand in the browser. Use the right kind of school and pupil, for example a type 11 school or an add-back pupil, and check that the options show as you expect.