Pre-release — The API surface may change. Unaudited.
Callcium LogoCallcium

Policy Validation

Type mismatches, contradictions, and redundancies.

Callcium validates policies at build time through semantic analysis. When you call PolicyBuilder.build(), the PolicyValidator inspects every constraint for type errors, logical contradictions, redundancies, and vacuous conditions — then reverts if any issue is found.

Using validation

PolicyBuilder.build() validates by default and reverts on any issue:

// Reverts with ValidationError if issues are found.
bytes memory policy = PolicyBuilder
    .create("approve(address,uint256)")
    .add(arg(0).isIn(trustedSpenders))
    .build();

To inspect issues without reverting, use PolicyBuilder.validate():

Issue[] memory issues = PolicyBuilder
    .create("approve(address,uint256)")
    .add(arg(0).isIn(trustedSpenders))
    .validate();

for (uint256 i = 0; i < issues.length; i++) {
    // Handle each issue: severity, category, code, message.
}

PolicyBuilder.buildUnsafe() skips validation entirely. The resulting policy may be invalid.

Issue structure

Each issue contains:

FieldTypeDescription
severityIssueSeverityError, Warning, or Info.
categoryIssueCategoryTypeMismatch, Contradiction, Redundancy, or Vacuity.
groupIndexuint32Constraint group where the issue was found.
constraintIndexuint32Constraint index within the group.
codebytes32Machine-readable identifier.
value1bytes32First value involved in the issue.
value2bytes32Second value involved in the issue.
messagestringHuman-readable description.

Severity levels

PolicyBuilder.build() reverts on any issue regardless of severity. Use PolicyBuilder.validate() to inspect issues without reverting.

SeverityMeaning
ErrorThe policy is logically invalid (contradictions, type mismatches).
WarningThe policy is valid but contains redundant or suspicious constraints.
InfoThe constraint is technically correct but vacuous (always true).

Issue catalog

Type compatibility

Operators, operands, and paths that do not fit the descriptor's declared types. All are Error severity.

CodeDescription
VALUE_OP_ON_DYNAMICValue operator used on a dynamic type.
VALUE_OP_ON_COMPOSITEValue operator used on a composite type.
NUMERIC_OP_ON_NON_NUMERICComparison operator used on a non-numeric type.
BITMASK_ON_INVALIDBitmask operator used on an incompatible type.
IN_ON_BOOLisIn/notIn used on a bool.
LENGTH_ON_STATICLength operator used on a non-dynamic type.
CONTEXT_TYPE_MISMATCHContext operand paired with a target type its property cannot match.
UNKNOWN_OPERATORUnrecognized operator code.
NON_CANONICAL_OPERANDOperand word is not the canonical encoding for the declared type.
UNNAVIGABLE_PATHPath does not navigate the descriptor.
NESTED_QUANTIFIERPath applies more than one quantifier.
HINT_MISMATCHStored hint differs from the path compiled against the descriptor.

Contradictions

Make the constraint set unsatisfiable. All are Error severity.

Bound contradictions

These apply to both numeric values and lengths. Length variants have the LENGTH_ prefix.

CodeDescription
EQ_NEQ_CONTRADICTIONeq(v) and neq(v) on same path.
LENGTH_EQ_NEQ_CONTRADICTIONlengthEq(v) and lengthNeq(v) on same path.
CONFLICTING_EQUALITYMultiple eq() with different values.
CONFLICTING_LENGTHMultiple lengthEq() with different values.
OUT_OF_PHYSICAL_BOUNDSValue outside the type's physical range.
OUT_OF_PHYSICAL_LENGTH_BOUNDSLength value outside physical range.
IMPOSSIBLE_GTgt() on type maximum.
IMPOSSIBLE_LTlt() on type minimum.
IMPOSSIBLE_LENGTH_GTlengthGt() on maximum length.
IMPOSSIBLE_LENGTH_LTlengthLt(0) on minimum length.
BOUNDS_EXCLUDE_EQUALITYeq() value excluded by a bound.
BOUNDS_EXCLUDE_LENGTHlengthEq() value excluded by a bound.
IMPOSSIBLE_RANGELower bound exceeds upper bound.
IMPOSSIBLE_LENGTH_RANGELower length bound exceeds upper.

Set contradictions

CodeDescription
SET_EXCLUDES_EQUALITYSet operation excludes existing eq() value.
EMPTY_SET_INTERSECTIONMultiple isIn() sets have no intersection.
SET_FULLY_EXCLUDEDAll isIn() values excluded by neq/notIn.

Bitmask contradictions

CodeDescription
BITMASK_CONTRADICTIONConflicting bitmaskAll/bitmaskNone bits.
BITMASK_ANY_IMPOSSIBLEbitmaskAny bits all forbidden by bitmaskNone.

Structural errors

CodeDescription
UNSORTED_IN_SETisIn/notIn set is not strictly sorted and deduplicated.
EMPTY_GROUPGroup contains zero constraints.

Redundancies

Constraints with no effect because they are subsumed. All are Warning severity.

Bound redundancies

CodeDescription
DOMINATED_BOUNDNumeric bound dominated by a stricter bound.
DOMINATED_LENGTH_BOUNDLength bound dominated by a stricter bound.
REDUNDANT_BOUNDNumeric bound redundant because eq() is set.
REDUNDANT_LENGTH_BOUNDLength bound redundant because lengthEq() is set.
FUSIBLE_RANGEgte() and lte() fuse into a single between().
FUSIBLE_LENGTH_RANGElengthGte() and lengthLte() fuse into a single lengthBetween().

Set redundancies

CodeDescription
SET_REDUCTIONnotIn() value was present in isIn() set.
SET_REDUNDANCYisIn() sets partially overlap.
SET_PARTIALLY_EXCLUDEDSome isIn() values excluded by neq/notIn.

Bitmask redundancies

CodeDescription
REDUNDANT_BITMASKBitmask operation subsumed by existing mask.

Duplicates

CodeDescription
DUPLICATE_CONSTRAINTIdentical operator appears twice.

Vacuity

Constraints that are always true. All are Info severity.

CodeDescription
VACUOUS_GTEgte() on type minimum (always true).
VACUOUS_LTElte() on type maximum (always true).
VACUOUS_LENGTH_GTElengthGte(0) (always true).
VACUOUS_LENGTH_LTElengthLte() on maximum (always true).
VACUOUS_NEGATED_RANGENegated between() with low > high excludes nothing.
VACUOUS_NEGATED_LENGTH_RANGENegated lengthBetween() with low > high excludes nothing.

Compatibility

Constructs that cross a normative limit or that behave differently than most authors intend. QUANTIFIER_OVER_STATIC_LIMIT is Error severity; the rest are Warning. Normative limits are fixed for this format version and every conformant enforcer applies the same values, so buildUnsafe() is the only way to emit a policy that crosses one.

CodeDescription
PATH_DEPTH_EXCEEDEDPath deeper than MAX_PATH_DEPTH; a policy declaring it is not well-formed (PWF-17).
QUANTIFIER_OVER_STATIC_LIMITQuantifier over a static array longer than MAX_QUANTIFIED_ARRAY_LENGTH (PV-7).
UNKNOWN_CONTEXT_PROPERTYContext property ID outside the assigned set (PWF-25).
NEGATION_UNDER_ANYNegated operator under any(); a single decoy element satisfies the rule.

On this page