# IDM Formula LLM Instruction Pack

## Goal
Convert natural English policy requirements and spreadsheet rule sets into valid IDM formulas.

## Canonical Rules
- Wrap every formula in double braces: {{ ... }}.
- Use prefix notation only: functionName arg1 arg2.
- Do not use parentheses or commas.
- Use double quotes for all string literals.
- Use dot notation for fields (example: student.sis_id).
- Functions are fixed-arity; every function must receive the exact number of arguments.
- forEach argument 3 (inner logic expression) must be URL-encoded (example: %7B%7Bitem.name%7D%7D).
- Prefer canonical names: `length` (not `len`), `equals` (not `equal`).
- Always include an explicit fallback in `if` formulas.
- In `forEach`, argument 3 must be URL-encoded (example: `%7B%7Bitem.name%7D%7D`).
- String literals cannot contain raw double quotes.

## Supported Functions
- `if` (arity 3): `if condition trueValue falseValue`
- `equals` (arity 2): `equals left right` (aliases: equal)
- `and` (arity 2): `and cond1 cond2`
- `or` (arity 2): `or cond1 cond2`
- `not` (arity 1): `not cond`
- `contains` (arity 2): `contains text needle`
- `greater` (arity 2): `greater left right`
- `less` (arity 2): `less left right`
- `geq` (arity 2): `geq left right`
- `leq` (arity 2): `leq left right`
- `in` (arity 2): `in value "item1 item2 item3"`
- `concat` (arity 2): `concat part1 part2`
- `substr` (arity 3): `substr text start length`
- `replace` (arity 3): `replace text find replacement`
- `length` (arity 1): `length text`
- `ignoreIfNull` (arity 1): `ignoreIfNull field`
- `forEach` (arity 3): `forEach "item" list encodedExpression`
- `toUpper` (arity 1): `toUpper text`
- `toLower` (arity 1): `toLower text`
- `initials` (arity 1): `initials text`
- `alphanumeric` (arity 1): `alphanumeric text`
- `trimLeft` (arity 1): `trimLeft text`
- `delimiterCapitalize` (arity 1): `delimiterCapitalize text`
- `textBefore` (arity 2): `textBefore text delimiter`
- `textAfter` (arity 2): `textAfter text delimiter`
- `textAfterLast` (arity 2): `textAfterLast text delimiter`
- `add` (arity 2): `add left right`
- `subtract` (arity 2): `subtract left right`
- `formatDate` (arity 2): `formatDate date format`

## Field Hints
- `name.first`
- `name.last`
- `name.middle`
- `student.sis_id`
- `student.student_number`
- `student.grade`
- `student.graduation_year`
- `school_name`
- `school.name`
- `school.sis_id`
- `email`

## Natural Language -> IDM Workflow
1. Extract target behavior into structured JSON:
   - `conditions`: list of field/operator/value checks
   - `match`: `all` or `any`
   - `output`: literal output when matched
   - `defaultOutput`: fallback output
2. Normalize operators using aliases:
   - `is`/`=`/`==` -> `equals`
   - `starts with` -> `startsWith`
   - `includes` -> `contains`
3. Compile deterministically:
   - `startsWith(field, "X")` -> `equals substr field 0 LEN "X"`
   - multiple conditions -> nested `and` or `or`
   - rule chain -> nested `if`
4. Validate the output formula with parser + test data.

## CSV -> Group Rules Workflow
Use one row per rule with this schema:

```csv
priority,output,match,field_1,operator_1,value_1,field_2,operator_2,value_2
1,Group A,all,school_name,equals,A,student.sis_id,startsWith,2
2,Group B,all,school_name,equals,B,,,
```

Alternative compact format:

```csv
priority,output,match,conditions
1,Group A,all,school_name|equals|A;student.sis_id|startsWith|2
```

Validation limits:
- Max rules per request: 200
- Max conditions per rule: 100

## API Endpoints
- `GET /api/idm-spec`: machine-readable language + operator schema.
- `GET /api/idm-instructions`: this instruction pack as markdown.
- `GET /api/idm-instructions?download=1`: forces file download.
- `POST /api/idm-group-rules`: compile JSON rules or CSV into normalized rules + formulas.

## JSON Request Template (`POST /api/idm-group-rules`)
```json
{
  "defaultOutput": "uncategorized",
  "rules": [
    {
      "priority": 1,
      "output": "Group A",
      "match": "all",
      "conditions": [
        { "field": "school_name", "operator": "equals", "value": "A" },
        { "field": "student.sis_id", "operator": "startsWith", "value": "2" }
      ]
    }
  ]
}
```
