integer
Whole numbers only. Floats and strings are rejected.| Value | Valid? | Error |
|---|---|---|
100 | ✅ | - |
-50 | ✅ | - |
0 | ✅ | - |
1.5 | ❌ | VAL-007 |
"100" | ❌ | VAL-007 |
null | ❌ | VAL-007 |
boolean
Must be exactlytrue or false. Truthy values like 1 or "true" are rejected.
| Value | Valid? | Error |
|---|---|---|
true | ✅ | - |
false | ✅ | - |
1 | ❌ | VAL-006 |
"true" | ❌ | VAL-006 |
null | ❌ | VAL-006 |
string
Any string value, including empty string.| Value | Valid? | Error |
|---|---|---|
"abc" | ✅ | - |
"" | ✅ | - |
123 | ❌ | VAL-008 |
null | ❌ | VAL-008 |
enum
String value restricted to a declared set of values. Thevalues array is required.
| Value | Valid? | Error |
|---|---|---|
"active" | ✅ | - |
"pending" | ✅ | - |
"unknown" | ❌ | VAL-011 |
"" | ❌ | VAL-011 |
null | ❌ | VAL-009 |
VAL-009 is thrown when the value is not a string at all (e.g. null, 1, true). VAL-011 is thrown when the value is a string but is not in the declared values array.
Missing values array in the signal definition raises POL-012 at compile time.
Why float is not allowed
Floating-point arithmetic is non-deterministic across platforms —0.1 + 0.2 can yield different bit representations on different CPUs, runtimes, and JavaScript engines. Since every Parmana execution must be byte-for-byte reproducible, floating-point signals would break the determinism guarantee.
Use scaled integers instead: multiply your float value by a power of 10 and work in integer space.
100 for percentages, 100 for cents, 1000 for per-mille, etc.) is an application-layer contract that you document alongside your policy.
Common validation errors
| Code | Signal type | Cause |
|---|---|---|
VAL-003 | any | Signal not declared in signalsSchema |
VAL-004 | any | Required signal missing from input |
VAL-005 | any | Invalid schema definition: signal definition missing type field |
VAL-006 | boolean | Non-boolean value |
VAL-007 | integer | Non-integer (float or string) |
VAL-008 | string | Non-string value |
VAL-009 | enum | Non-string value (e.g. null, 1, true) |
VAL-011 | enum | String value not in declared values array |
VAL-012 | any | Unsupported signal type — use integer, boolean, string, or enum |
Scaled integer conversion table
Common financial values that require fractions and their integer equivalents:| Real-world value | Signal name | Integer encoding | Scale factor |
|---|---|---|---|
| 3.75% interest rate | rate_bps | 375 | × 100 (basis points) |
| ₹82,000.50 income | monthly_income | 8200050 | × 100 (paise) |
| 0.97 confidence score | confidence_pct | 97 | × 100 (percentage) |
| 1.5x debt-to-income ratio | dti_ratio_bps | 15000 | × 10000 |
| 87.3% LTV ratio | ltv_ratio_pct | 8730 | × 100 |
| ₹4,200,000 loan amount | loan_amount | 4200000 | × 1 (rupees, integers only) |
loan_amount: 4200000 is already a valid integer.
Use Cases
Personal loan signal schema
An NBFC evaluates personal loans using the following signal schema. All fractional values are scaled to integers:UPI fraud detection with scaled risk score
A payment processor evaluates each UPI transaction with a risk score from a fraud model. The model outputs a float (0.0–1.0); it is scaled to an integer (0–100) before being passed as a signal:"greater_than": 75 to match high-risk transactions. The scaling factor (× 100) is documented in the policy’s README — not embedded in the signal schema, which has no concept of units.
Catching type errors at the validation boundary
A developer accidentally passescredit_score: "750" (a string) instead of credit_score: 750 (an integer). The signal schema declares { "type": "integer" }. Validation throws VAL-007 before evaluation begins — the error is caught at the boundary, not silently coerced. This is the intended behavior: type safety is enforced structurally, not by convention.
See also
- Policy Schema Reference - how to declare signals
- Error Codes - full error code reference
- Governed Signals - why signals are schema-validated