> ## Documentation Index
> Fetch the complete documentation index at: https://docs.manthan.systems/llms.txt
> Use this file to discover all available pages before exploring further.

# Signal Types

> All supported signal types and their validation rules

## integer

Whole numbers only. Floats and strings are rejected.

```json theme={null}
"amount": { "type": "integer" }
```

| Value   | Valid? | Error     |
| ------- | ------ | --------- |
| `100`   | ✅      | -         |
| `-50`   | ✅      | -         |
| `0`     | ✅      | -         |
| `1.5`   | ❌      | `VAL-007` |
| `"100"` | ❌      | `VAL-007` |
| `null`  | ❌      | `VAL-007` |

## boolean

Must be exactly `true` or `false`. Truthy values like `1` or `"true"` are rejected.

```json theme={null}
"verified": { "type": "boolean" }
```

| Value    | Valid? | Error     |
| -------- | ------ | --------- |
| `true`   | ✅      | -         |
| `false`  | ✅      | -         |
| `1`      | ❌      | `VAL-006` |
| `"true"` | ❌      | `VAL-006` |
| `null`   | ❌      | `VAL-006` |

## string

Any string value, including empty string.

```json theme={null}
"user_id": { "type": "string" }
```

| Value   | Valid? | Error     |
| ------- | ------ | --------- |
| `"abc"` | ✅      | -         |
| `""`    | ✅      | -         |
| `123`   | ❌      | `VAL-008` |
| `null`  | ❌      | `VAL-008` |

## enum

String value restricted to a declared set of values. The `values` array is required.

```json theme={null}
"status": {
  "type": "enum",
  "values": ["active", "inactive", "pending"]
}
```

| 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.

```json theme={null}
"signalsSchema": {
  "rate_bps": { "type": "integer" }
}
```

```json theme={null}
// Signal value: 3.75% → store as 375 basis points
{ "rate_bps": 375 }
```

```json theme={null}
// Condition in policy: greater than 5.00% = 500 bps
{ "signal": "rate_bps", "greater_than": 500 }
```

The scaling factor (`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) |

For rupee amounts that are always whole numbers, no scaling is needed — `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:

```json theme={null}
"signalsSchema": {
  "monthly_income":    { "type": "integer" },
  "loan_amount":       { "type": "integer" },
  "credit_score":      { "type": "integer" },
  "emi_obligations":   { "type": "integer" },
  "employed":          { "type": "boolean" },
  "employment_type":   { "type": "enum", "values": ["salaried", "self_employed", "government"] },
  "blacklisted":       { "type": "boolean" }
}
```

Signal values sent with each request:

```json theme={null}
{
  "monthly_income":  82000,
  "loan_amount":     500000,
  "credit_score":    720,
  "emi_obligations": 18000,
  "employed":        true,
  "employment_type": "salaried",
  "blacklisted":     false
}
```

### 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:

```json theme={null}
"signalsSchema": {
  "transaction_amount": { "type": "integer" },
  "risk_score":         { "type": "integer" },
  "is_foreign":         { "type": "boolean" }
}
```

```json theme={null}
{
  "transaction_amount": 50000,
  "risk_score":         87,
  "is_foreign":         false
}
```

The policy rule uses `"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 passes `credit_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](/reference/policy-schema) - how to declare signals
* [Error Codes](/reference/error-codes) - full error code reference
* [Governed Signals](/architecture/governed-signals) - why signals are schema-validated
