Tips & Best Practices for Rules

This page lists various tips and best practices to help you create rules for your study. For instructions on rule creation, refer to Creating Rules.

Rule Details (Properties)

Rule Descriptions

  • Use short and complete sentences.
  • Explicitly indicate the intention of the rule including all parameters.
    • When adding forms and events, enter a description for how the rule operates
      • Example: Did the subject meet all eligibility criteria? If Yes, then add the Treatment Event Group (egTREAT)
    • For query rules, indicate exactly how values need to be handled, ‘…greater than or equal to’ vs ‘…greater than’
      • Example: End Date is before Start Date. vs. End Date is on or before Start Date.
  • Keep in mind that testers will test against the description to determine if the rule passes
  • Use item labels within descriptions because they generate the study specifications,for example, use “Start Date” instead of “AESTDAT”.

Rule Scope & Dynamic Action

Always ensure that you select Within Event Group for Rule Scope when necessary. This is a common reason for troubleshooting why a rule doesn’t fire as expected.

Evaluating Missing Data (Blank Handling)

Best Practice: The Required property on an Item creates a system-generated rule (univariate) that fires whenever that Item is left blank. Use this as the primary check for missing data.

For multivariate rules, such as date comparisons, date calculations, and evaluating numbers, include logic within your expression to confirm the data is not missing or null. If you forget to consider the missing or null case, then you may encounter server errors, or the check could duplicate the Required univariate check, resulting in multiple queries.

  • Include Not(IsBlank(ITEM)) to confirm the data is not missing or null.
  • Select As null for the rule’s Blank Handling property.

Expression & Logic

  • #define statements should identify the variable using the item’s exact Name, or as close to exact as possible, for identification and copying efficiency.
  • Use /* ... */ to add comments at the top of the rule if needed for clarity. You must add these at the top of your rule expression, or you won’t be able to save your rule.
  • Consider that another study designer might be needed during study conduct. Well-named items in the expression help with rule clarity and reduce efforts during revisions.
  • Use white space and line breaks to help with rule clarity.

Here the study designer chose to put extra lines to break up separate sections of logic. They also used a separate line for each logical piece of the expression, aligning the operators with extra whitespaces.

Extra whitespaces and lines

Date Comparison Rules

Best Practice: To compare date Items to other date Items, we recommend that you use the Date Comparison Configurator whenever possible.

DateTime vs Date

The two examples below show how to compare the value from a DateTime-type Item to an Event Date. This syntax applies to any date/datetime comparisons.

DateTime Item doesn’t allow for unknowns:

Not(IsBlank(DTC))
&&
Not(IsBlank(EVDAT))
&&
DateValue(DTC, @Site.timezone__v) != EVDAT

DateTime Item allowing for unknowns:

Not(IsBlank(EVDAT))
&&
Not(IsBlank(VSDTC))
&&
If(Right(VSDTC , 4) = "UNKZ", DateValue(MinDateTime(VSDTC), 'UTC'), DateValue(MinDateTime(VSDTC), @Site.timezone__v)) != EVDAT

Future Date Rules

Best Practice: We recommend that you simply select the Future Date property in the Edit Checks section of the Properties panel for an Event or Item to check for future dates. When this checkbox is selected, Vault opens a query whenever a site user enters a future date (based on the site user’s timezone).

If you require a custom rule to check for future dates, then use DateValue(Now(), @Site.timezone__v) in the expression. Functions like Now() and Today() and DateValue() will return the dates converted to UTC format. Coordinated Universal Time (UTC) is the standardized time based on the 0° longitude meridian.

For any country where dates and times are beyond UTC, e.g. Italy, South Africa, Australia, this can cause the rule to fire unexpectedly when the @Site.timezone__v is not included. By using @Site.timezone__v as a best practice, it will return the converted value back to the site’s timezone and ensure the rule fires as expected.

Comparing Event Dates with Date Items

Study designers may attempt to use @Event.event_date__v as a wildcard (*) to cover all Events where the Form exists, in order to write fewer rules. However, rules with @Event.event_date__v are not re-evaluated when the Event Date is modified. They are only re-evaluated when the user completes the Form.

As best practice, use fully-qualified identifiers when comparing Event Dates ($EventGroup.Event.event_date__v), Write one rule for each visit-form instance.

For example, a rule like the one below would not re-evaluate if a user corrected the Event Date after completing all Forms within the Event.

#define EVDAT @Event.event_date__v
#define DAT @Form.ig_VS.VSDAT
EVDAT != DAT

The example below shows a fully-qualified Event Date identifier compared to a Date Item, which doesn’t allow partial (unknown) dates:

#define QSDAT @Form.QS.QSDAT
#define EVDAT $FOLLUP.V7.event_date__v
Not(IsBlank(QSDAT))
&&
Not(IsBlank(EVDAT))
&&
QSDAT > EVDAT

The example below compares a fully-qualified Event Date identifier to a datetime-type Item that doesn’t allow for unknown times. This expression is for a Query-action rule that opens a query when the Date and Time of Assessment (EGDTC) item is not the same as the Event Date for that Form.

#define EVDAT $FOLLUP.FOLLUP.event_date__v
#define EGDTC $FOLLUP.FOLLUP.ECG.ig_ECG.EGDTC
Not(IsBlank(EVDAT))
&&
Not(IsBlank(EGDTC))
&&
If(
     Right(EGDTC, 4) = "UNKZ",
     DateValue(MinDateTime(EGDTC), 'UTC'),
     DateValue(MinDateTime(EGDTC), @Site.timezone)
) != EVDAT

What about other use cases for @Event?

Use @Event to reference other Forms within the same Event. For example, if Vital Signs have to be taken within a certain time of the Drug Administration (both forms in the same event), you can use @Event.FormName.IG.Item to reference the other item. Writing the expression in this way makes the rule reusable across multiple events.

#define VSDTC @Form.VSTPT2.VSDTC
#define EXSTDTC @Event.EX.EX.EXSTDTC
Not(IsBlank(VSDTC))
&&
Not(IsBlank(EXSTDTC))
&& 
Not(InWindow(VSDTC, EXSTDTC, Minutes(5), Minutes(10), false, false))

Time vs Time (Time Comparison Rules)

Static Timepoint

Example: Fire query when the time entered is after 12:00pm

TIM1 > Time(12,0,0)

Comparing Two Times

These rules are written as a statement ( A - B > #), where the calculation returns the delta in minutes as a number object.

Example: Dose End Time is on or after Dose Start Time

EXENTIM - EXSTTIM >=0

Example: Infusion End Time is more than 12 hours after Infusion Start Time (Note: 12 Hours X 60 minutes = 720 minutes)

EXENTIM - EXSTTIM > 720 

This example can also be written by comparing the item to an expression calculating the number of minutes.

EXENTIM - EXSTTIM > 12*60

Event Date Rules & Did Not Occur

It’s important to consider if a protocol allows a subject to miss an Event and continue on to the next Event. Likewise, it’s important to consider rules that examine Event Dates where sites may mark an Event as Did Not Occur.

You may already be familiar with using the Not(IsBlank()) functions in the rule’s expression to confirm that a date is entered. You can extend this to check if a site marked the_ Event_ as Did Not Occur by checking the entry for the event’s Change Reason ($EventGroup.Event.change_reason__v). This is where Vault records the reason the site selected for the event not occurring.

The example below explicitly examines the Did Not Occur reason:

#define EVDAT $TX.DAY9.event_date__v
#define EVDNO $TX.DAY9.change_reason__v

Not(IsBlank(EVDAT))
||
EVDNO = "Subject missed event"

In this rule expression (used with an Add Event rule action), we checked the change reason and allowed the roll out of the next Event if the Change Reason was “Subject missed event”. If a site were to select “Subject early terminated” instead, this rule would not add the next event.

Be sure to confirm the exact text for the Change Reasons available in your study’s vault. These must be an exact match for the rule to evaluate correctly. You can view the available reasons, both standard and custom, from Tools > System Tools > Change Reasons.

Rules on Boolean Items (Checkboxes)

Boolean items (checkboxes) that are not set to true or false are considered blank (“Undetermined”). This can occur when the site never checks the checkbox vs. checking and then unchecking the checkbox. Proper logic within the rules expression will help ensure that the appropriate scenarios are evaluated as expected. The best practice is to explicitly set Booleans as = true or = false in your rule expression.

Include the appropriate define statements when evaluating a set of Booleans are all left blank. Take consideration of when a form/item is marked with Intentionally Left Blank (ILB) and how you’d need the rule to operate.

In the example below, the rule checks if a Reason was entered and one or more of the checkboxes was selected.

#define ND1  @Form.ig_V1.V1ND
#define ND2  @Form.ig_V2.V2ND
#define ND3  @Form.ig_V3.V3ND
#define ND4  @Form.ig_V4.V4ND
#define REAS @Form.ig_V5.VREAS

Not(IsBlank(REAS)) && (ND1 = true || ND2 = true || ND3 = true || ND4 = true)

When evaluating if a set of items or checkboxes is left blank, Include Intentionally Left Blank (ILB) in the define statements to evaluate, as needed, if forms or items are marked ILB. This will ensure the rule doesn’t fire when it shouldn’t.

#define AENONE @Form.AE.AENONE
#define AEMED @Form.AE.AEMED
#define AEACNOTH @Form.AE.AEACNOTH
#define AETRANS @Form.AE.AETRANS
#define FORMILB @Form.intentionally_left_blank__v

FORMILB = false
&&
(
    AENONE = false
    && 
    AEMED = false
    &&
    AEACNOTH = false
    &&
    AETRANS = false
)

This is often applicable to rules related to Adverse Events or Questionnaire and Medical Device forms to evaluate if none of the “check all that apply” checkboxes have been selected. Some common rules where this logic is applicable are:

  • No selections have been made for Race. Check all that apply
  • AE Action Taken: None is selected and also Medication, [etc]. were selected. Please correct.

Age Rules

The following rule examples calculate and query age, accounting for leap year:

Age Derivation (Set Item Value)

#define BRTHDAT @Form.ig_DM.BRTHDAT
#define RFICDAT @Form.ig_DM.RFICDAT

If(BRTHDAT > RFICDAT - Years((Year(RFICDAT) - Year(BRTHDAT))), (Year(RFICDAT) - Year(BRTHDAT)) - 1, (Year(RFICDAT) - Year(BRTHDAT)) )

Age Query (Query if Under 18)

#define BRTHDAT $eg_SCREEN.ev_SCREEN.DM.ig_DM.BRTHDAT
#define EVDAT $eg_SCREEN.ev_SCREEN.event_date__v

Not(IsBlank(EVDAT)) && Not(IsBlank(BRTHDAT)) && ((EVDAT - MaxDate(BRTHDAT)) / 365.25) < 17.998

Check if a Text Item Contains Specific Characters

In this example, the rule checks a text-type Item, and Vault opens a query if any part of the entered value contains a number, instead of alpha characters.

#define ITEM @Form.IG.ITEM

If(Find("0", ITEM) != 0, true,
If(Find("1", ITEM) != 0, true,
If(Find("2", ITEM) != 0, true,
If(Find("3", ITEM) != 0, true,
If(Find("4", ITEM) != 0, true,
If(Find("5", ITEM) != 0, true,
If(Find("6", ITEM) != 0, true,
If(Find("7", ITEM) != 0, true,
If(Find("8", ITEM) != 0, true,
If(Find("9", ITEM) != 0, true, false))))))))))

Adding Forms using Rules

With the Repeating Event Group feature and the use of rules, study designers can easily create the Schedule of Assessments (SOA) with much less effort. In the example below, the rule will add specific forms at specific event sequences. Be sure to confirm the correct sequence numbers, as they relate to the labels configured in the repeating event group. They can also be referenced in the Schedule Tree tab of theStudio generated Study Design Specification.

In the example below, the rule adds the ECOG form to all the Day 1 events within the Treatment Cycle (repeating event group). In this design, the Cycle # - Day 1 events are the sequence numbers 1, 3, 5, 7, 9 and 11.

#define EVDAT $eg_TREAT.ev_D1.event_date__v
#define EVSEQ @EventGroup.sequence__v

Not(IsBlank(EVDAT))
&&
(
     EVSEQ = 1
     ||
     EVSEQ = 3
     ||
     EVSEQ = 5
     || 
     EVSEQ = 7
     || 
     EVSEQ = 9
     || 
     EVSEQ = 11
)

Query Messages

  • Clearly reference the issue and options for resolution. Be factual and refrain from messages that are leading or could bring bias to the data.
  • Avoid using special characters:
    • For example, spell out greater than or equal to, instead of using “> or =”
    • Use characters from your natural keyboard. Don’t use Alt+ keys or symbols thats might impact downstream systems or applications.
  • Use single quotes around responses (example: Was the subject enrolled? Is ‘No’ and …).
  • Refrain from using double quotes.

Testing Recommendations

Best Practice: Typical unit testing includes, at a minimum, testing to make each rule open (create) and resolve a query once. Testing one rule thoroughly, similar to a full verification, and then creating similar rules by copying that rule can help you raise rule quality and reduce configuration rework and revalidation efforts.

Whether you are Unit Testing or more formally verifying your rules, consider the following best practices:

  • Include in-range values and out-of-range values. This includes numerical values, dates, and datetime windows
  • Include testing what makes the rule fire and what makes it resolve, for all cases.
  • Confirm every scenario from a codelist.
  • For cross-form queries, include tests that show the rule creates and resolves queries as expected upon completion of both the first and second forms (forward and backward).
  • If a rule references an Item within a repeating Item Group, verify that the rule opens and resolves the query on the Item in the correct sequence (instance) of the Item Group.
  • Test within, equal to, and beyond datetime windows.
  • Test the “next day” scenario. Pick a time within the window but on the next calendar day.
  • Test unknown (UNK) times, days, and months per the item’s masking properties.
  • Set up sites with applicable timezones for testing rules when data is entered from various site locations
    • Add a few testing sites in UAT that represent a sample of expected time zones from the countries included in the study.
    • Set the time zone of both the site and UAT test user assigned to that site.
  • Test time window rules as applicable for the study conduct. For example, if a longer IV infusion would result in the end time or expected ECG or PK time windows near midnight.
  • Consider a risk-based approach to testing, where peer reviews on code can raise quality and reduce findings in UAT.