# Type system

Canonical reference for DSL types: scalar base types, list modifiers, enums, regex, and custom validators. Env blocks, CLI flags, and `@operation` params/outputs all use `DslType`.

## Usage

Types annotate env entries (`@int THRESHOLD: 80`), operation inputs (`@in.type name`), and outputs (`@out.type field`). Untyped env keys default to `string` (see [env-block.md](env-block.md)).

## Grammar

```
DslType         = BaseType ListMod?
BaseType        = 'string' | 'int' | 'number' | 'bool'
                | 'email' | 'url'
                | 'file-exists' | 'dir-exists' | 'file-opt' | 'dir-opt'
                | 'command' | 'glob' | 'json' | 'file-json'
                | 'duration' | 'semver' | 'version' | 'secret'
                | 'time' | 'time-iso-utc' | 'time-iso-tz'
                | 'time-unix' | 'time-unix-sec' | 'time-unix-ms' | 'time-unix-nano'
                | 'time-http' | 'time-rfc' | 'time-rfc-utc' | 'time-rfc-tz'
                | 'enum' '(' IDENT (',' IDENT)* ')'
                | EnumRef
                | InlineRegex | RegexRef
                | InlineCustom | CustomRef
ListMod         = '[' ListSep? ']'
ListSep         = 'space' | 'flag' | STRING_LIT
EnumRef         = 'enum' '.' IDENT | IDENT '.' 'enum' '.' IDENT
InlineRegex     = '/' REGEX_BODY '/'
RegexRef        = '\' IDENT '\'
InlineCustom    = '(' '{' CUSTOM_BODY '}' ')'
CustomRef       = '(' IDENT ('.' IDENT)* ')'
```

## IR representation

Canonical type and value shapes live in [values-and-types](../ir/values-and-types.md). Named enum refs resolve to their variant list and emit inline in IR. List types carry `list: true`, `separator`, and defaults as arrays when present. Per-key env schema in IR mirrors `DslType` (see [env-block.md](env-block.md) for env object shape).

## Types

| Type | Env example | CLI flag | Validation/Notes |
| --- | --- | --- | --- |
| `string` | `NAME: "blizz"`, `@string NAME` | `--name <value>` | none |
| `int` | `@int THRESHOLD: 80` | `--threshold N` | integer check |
| `number` | `@number RATIO: 0.75` | `--ratio N` | numeric check |
| `bool` | `@bool VERBOSE` | `--verbose` | presence or "true"/"false" |
| `email` | `@email CONTACT` | `--contact <email-address>` | valid email format |
| `url` | `@url WEBSITE: kernelle-soft.com` | `--website <address>` | valid URL format |
| `file-exists` | `@file-exists CONFIG: ./ci.json` | `--config <file>` | `-f` check |
| `dir-exists` | `@dir-exists OUTPUT: .coverage` | `--output <dir>` | `-d` check |
| `file-opt` | `@file-opt DEST: ./dist/lib.o` | `--dest <path>` | none (may not exist) |
| `dir-opt` | `@dir-opt DEST: ./dist` | `--dest <path>` | none (may not exist) |
| `command` | `@command TOOL: kcov` | `--tool <tool>` | `command -v` check |
| `glob` | `@glob PATTERN: test/*.bats` | `--pattern <glob>` | none |
| `json` | `@json JSON: '{"key": "value"}'` | `--json <json>` | JSON validation via `__json.awk` |
| `file-json` | `@file-json FILE` | `--file <path/to/file.json>` | -f check, JSON validation via `__json.awk` |
| `duration` | `@duration TIMEOUT: 30s` | `--timeout <duration>` | parses ms/s/m/h/d/w/mo/y |
| `enum(...)` | `@enum(dev, release) MODE: release` | `--mode <mode>` | value in set |
| `enum.name` | `@enum.datacenter DC: alpha` | `--dc <datacenter>` | value in set (named ref) |
| `semver` / `version` | `@version VERSION: "0.9.0"` | `--version <version>` | Semver-ish check. `@version` alias. |
| `secret` | `@secret TOKEN` | `--token <secret>` | Mask in logs, hardcoded defaults forbidden |
| time types | `@time TIMESTAMP`, `@time-iso-utc`, `@time-iso-tz`, `@time-unix`, `@time-unix-sec`, `@time-unix-ms`, `@time-unix-nano`, `@time-http`, `@time-rfc`, `@time-rfc-utc`, `@time-rfc-tz` | various | format-specific validation |
| inline regex | `@/.*/ VAR` | `--var <val>` | regex validation |
| regex reference | `@\REGEXNAME\ VAR` | `--var <val>` | regex validation |
| inline custom | `@({<validation code>}) VAR` | `--var <val>` | custom validation block |
| custom reference | `@(pipeline.name) VAR` | `--var <val>` | custom validation reference |

### List separators

| Separator | CLI encoding | Default |
| --- | --- | --- |
| `@<type>[]` | `--targets a,b,c` | yes |
| `@<type>[<sep>]` | `--paths /usr/bin:/usr/local/bin` | |
| `@<type>[space]` | `--terms google yahoo facebook` | |
| `@<type>[flag]` | `--target dev --target prod` | |

List defaults use `[...]` syntax: `@string[] TARGETS: [alpha beta]`.

### Named enums

Declared at top level (`@enum datacenter(alpha, beta, production)`) and referenced as `enum.datacenter` locally or `<ns>.enum.datacenter` from imports. Inline anonymous enums `enum(a, b, c)` are supported. Named refs resolve to their variant list and emit inline in IR.

### Layers

- **BaseType:** scalars (and enum/regex/custom forms above).
- **DslType:** `BaseType` plus optional list modifier with separator. Env and CLI surface use `DslType`.
- **Invocation args:** additionally support `Object` (`{ k: v }` syntax) and positional lists.

## Runtime

- `@in.type name` — named typed input on `@operation`.
- `@out.type field` — named typed output field on `@operation`.

## Implementation

| Tier | Scope |
| --- | --- |
| **Tier 5 (Type System Foundation)** | `types.rs`: `BaseType` enum, `DslType` struct. `registry.rs`: deserialize params/outputs. `lower.rs`: validate args against signatures. |
| **Tier 7 (Env Block & Named Enums)** | `BaseType` gains remaining variants. `DslType` gains list modifier with separator. |

**Validates:** Rust tests for type validation (correct types pass, mismatches warn, unknown args error).

## Design decisions

- **Two layers:** keeps scalar grammar stable while lists and separators stay orthogonal.
- **`version` alias:** `@version` maps to semver-ish validation alongside `semver`.
- **Secrets:** distinct behavior (masking, no hardcoded defaults) vs plain `string`.

## Caveats

- Time family types share the “time types” row in tooling/docs; each variant has its own parser/validator.
- Custom and regex validators depend on registry resolution; unresolved refs are errors (see env-block for enum analog).

## Settled

- **Top-level typed declarations**: `@type NAME = value` at the top level, private and non-configurable. Not part of `env = {}`, not in `--help`, not overridable by callers. Referenced locally as `$type.NAME` and from imports as `$<ns>.type.NAME` — the type segment is part of the qualified path, making every reference self-documenting. Follows the same `@use` import conventions as `@enum`. Compile error if a top-level declaration name collides with an env key.

- **File-level custom type definitions**: see [custom-types.md](custom-types.md). `@type <name> = ({ ... })` for user-defined validation types, analogous to `@enum`. Referenced locally as `@type.<name>`, from imports as `@<ns>.type.<name>`. `@type` declarations with imperative validation blocks, `@<type>.is()` composition, runtime validation. Follows the same `@use` import pattern as `@enum`. The `@` sigil accesses type/structure definitions; the `$` sigil accesses values — two sigils with two clear purposes.

## Open questions

None.
