Summary
SchemaHelper.validateConditionFields — the runtime condition check reached from VCJS.conditionErrors — validates only thenFields / elseFields, the fields a condition declares itself, looked up by name in the local object:
const active = evaluate(condition) ? thenFields : elseFields;
for (const field of active) {
if (field.required && !present(data[field.name])) {
errors.push(`Field "${field.name}" is required.`);
}
}
It never reads thenTargets / elseTargets — the cross-schema half of a condition, where the target lives at a fieldPath inside another sub-schema.
Why that leaves a gap
buildDocument does compile targets: buildCrossRequired emits nested properties / required, and buildCrossForbidden emits false for the other branch's targets. So targets are enforced wherever those compiled keywords apply — and unenforced everywhere they do not, with nothing in the runtime check to cover the difference.
The consequence that matters is the forbidden side: a document can carry a target belonging to the inactive branch and nothing rejects it.
Reproduce
Condition: if kind = full then sub.detail appears (target detail inside sub-schema sub).
SchemaHelper.validateConditionFields(conditions, { kind: 'partial', sub: { detail: 'smuggled' } });
// actual: [] expected: an error - the branch that reveals `detail` is not active
SchemaHelper.validateConditionFields(conditions, { kind: 'full', sub: {} });
// actual: [] expected: an error - `detail` is required on the active branch
Out of scope here, but worth recording
A condition whose trigger and target sit in two paired repeatable sub-schemas (subA[i].type → subB[i].detail) cannot be validated by this function as it stands: correlating entry i of one array with entry i of another needs the schema's arrayDependencies, and validateConditionFields(conditions, data) does not receive them. Closing that would mean changing the signature, so I have left it out of the fix rather than half-doing it.
Summary
SchemaHelper.validateConditionFields— the runtime condition check reached fromVCJS.conditionErrors— validates onlythenFields/elseFields, the fields a condition declares itself, looked up by name in the local object:It never reads
thenTargets/elseTargets— the cross-schema half of a condition, where the target lives at afieldPathinside another sub-schema.Why that leaves a gap
buildDocumentdoes compile targets:buildCrossRequiredemits nestedproperties/required, andbuildCrossForbiddenemitsfalsefor the other branch's targets. So targets are enforced wherever those compiled keywords apply — and unenforced everywhere they do not, with nothing in the runtime check to cover the difference.The consequence that matters is the forbidden side: a document can carry a target belonging to the inactive branch and nothing rejects it.
Reproduce
Condition: if
kind = fullthensub.detailappears (targetdetailinside sub-schemasub).Out of scope here, but worth recording
A condition whose trigger and target sit in two paired repeatable sub-schemas (
subA[i].type→subB[i].detail) cannot be validated by this function as it stands: correlating entry i of one array with entry i of another needs the schema'sarrayDependencies, andvalidateConditionFields(conditions, data)does not receive them. Closing that would mean changing the signature, so I have left it out of the fix rather than half-doing it.