Debugging Business Rules
This guide covers the business rules evaluation lifecycle, tracing API, config validation, the DevTools panel, and solutions to common issues.
Rule Tracing API
The rule tracing system records every rule evaluation event, making it possible to see exactly what happened and why.
Enabling Tracing
import {
enableRuleTracing,
disableRuleTracing,
getRuleTraceLog,
clearRuleTraceLog,
} from "@formosaic/core/devtools";
enableRuleTracing();
// ... user interacts with form ...
const log = getRuleTraceLog();
log.forEach(event => {
console.log(
`[${event.type}] ${event.triggerField}=${JSON.stringify(event.triggerValue)} -> ${event.affectedField}`
);
});
disableRuleTracing();Real-Time Callback
enableRuleTracing((event) => {
console.log(`[${event.type}] ${event.triggerField} -> ${event.affectedField}`, event.newState);
});IRuleTraceEvent Shape
| Property | Type | Description |
|---|---|---|
timestamp | number | Date.now() when the rule fired |
type | "revert" | "apply" | "combo" | "dropdown" | "order" | "init" | Which phase produced this event |
triggerField | string | The field whose value change triggered evaluation |
triggerValue | unknown | The value that triggered the rule |
affectedField | string | The field whose state was changed |
previousState | Partial<IRuntimeFieldState> | State before rule applied |
newState | Partial<IRuntimeFieldState> | State after rule applied |
FormDevTools
The built-in DevTools panel provides a visual inspector with 7 tabs:
| Tab | Content |
|---|---|
| Rules | Per-field runtime state: type, required, hidden, readOnly, active rules |
| Values | JSON dump of all current form values |
| Errors | JSON dump of current form errors |
| Graph | Text-based dependency graph |
| Perf | Per-field render counts, hot field detection |
| Deps | Sortable dependency table with effect types, cycle detection |
| Timeline | Chronological event log with filtering |
import { FormDevTools } from "@formosaic/core/devtools";
<FormDevTools
configName="myForm"
formState={runtimeFormState}
formValues={getValues()}
formErrors={formState.errors}
dirtyFields={formState.dirtyFields}
enabled={process.env.NODE_ENV === "development"}
/>Config Validation
import { validateFieldConfigs } from "@formosaic/core";
const errors = validateFieldConfigs(fieldConfigs, registeredComponents);
if (errors.length > 0) {
errors.forEach(err => console.error(`[${err.type}] ${err.fieldName}: ${err.message}`));
}Checks for: missing dependency targets, self-dependencies, unregistered components, unregistered validators, missing dropdown options, and circular dependencies.
Common Issues and Solutions
"Rule not applying"
The most common cause is a value mismatch. Dependency keys are matched using string comparison: String(fieldValue) === ruleKey.
- Boolean values:
truemust match"true", not"True" - Numbers:
42must match"42" - null/undefined: Match against the empty string
""
"Circular dependency" warning
const errors = validateFieldConfigs(fieldConfigs);
const cycles = errors.filter(e => e.type === "circular_dependency");Refactor the config so dependencies form a DAG (directed acyclic graph).
"Field reverted unexpectedly"
When a field's value changes, ALL dependents from the previous value are reverted to their default config state before new rules are applied. Use the trace log to see the full revert-then-apply sequence.
Debugging Checklist
- Enable tracing --
enableRuleTracing()to capture all rule events - Open DevTools -- Add
<FormDevTools>to visualize rules, values, errors, and the dependency graph - Validate config -- Run
validateFieldConfigs()to catch structural issues - Check value types -- Dependency keys use string comparison
- Check the trace log -- Look for
"revert"events that may be clearing state - Check combo conditions -- All combo rule conditions must match simultaneously
- Check dropdown keys -- Option values must match actual
IOption.valuevalues
