# Validation Model

This document describes how the Architect Language Tools validation system decides
whether a diagnostic rule fires, at what severity, and how that behaviour can be
overridden at different scopes. It is the authoritative reference for anyone adding
a new rule or configuring the validator for a project.

---

## The three modes

Every file is validated in one of three **modes**. The mode is the single concept
that unifies rule applicability, severity profiles, and file-level annotations.

| Mode | Intent |
|---|---|
| `legacy` | Permissive. Suitable for older code written before modern standards existed. Style and convention rules are largely silent. |
| `default` | Balanced. All validity and advisory rules are active. Convention rules are active at warning level. Strict-only style rules are off. |
| `strict` | Opinionated. All rules are active, including style rules that enforce modern Architect idioms (variable declaration form, terminator style, etc.). |

`default` is the mode used when no annotation or configuration says otherwise.
An explicit `// @mode:default` annotation is also valid — it signals that a
conscious decision was made to keep the balanced rule set rather than inheriting a
project-wide `legacy` or `strict` default.

---

## How the effective mode is determined

The following sources are consulted in priority order. The **innermost (last) match
wins**.

```
1. Catalog default          Built-in severity for each rule in each mode.
                            Defined in diagnosticCatalog.js.

2. Project default mode     .acurity.json  →  "mode": "strict"
                            Sets the mode for all files not otherwise matched.

3. Project rule overrides   .acurity.json  →  "rules": { "ruleId": "off" }
                            Adjusts individual rule severities on top of the mode,
                            project-wide.

4. Path mode overrides      .acurity.json  →  overrides[].mode
                            Overrides the mode for files matching a glob path.
                            First matching override wins.

5. Workspace settings       VS Code settings.json
                            Developer-local per-rule severity overrides.
                            Intended for local tuning (e.g. raising advisory rules
                            to warnings during active development). Not a substitute
                            for project policy, which belongs in .acurity.json.

6. File mode annotation     // @mode:strict   (in the file itself)
                            Overrides the mode for a single file. Must appear in
                            the first 10 non-blank lines. Exact match, case-sensitive.

7. Line suppression         // @rule-ignore ACU-XXX-NNN REASON: ...
                            Suppresses a specific diagnostic on the next line only.
```

> **Rule of thumb:** policy belongs in `.acurity.json`; exceptions belong in the
> file (annotation) or on the line (`@rule-ignore`); personal preferences belong in
> VS Code settings.

---

## File mode annotation

Place in the first 10 non-blank lines of the file. Exactly one of:

```
// @mode:default
// @mode:legacy
// @mode:strict
```

Only one annotation is permitted per file. The presence of both `mode:strict` and
`mode:legacy` in the same file is undefined behaviour — the first one found wins.

**When to use each:**

- `mode:legacy` — the file predates modern standards and the team has decided not
  to migrate it. Suppresses style and convention rules that would fire on every line.
- `mode:default` — an explicit acknowledgement that the file uses the standard rule
  set. Useful when a project default of `strict` or `legacy` exists and this file
  is intentionally different.
- `mode:strict` — the file must conform to the full modern style guide. Use for new
  code in projects that have not yet set `"mode": "strict"` project-wide.

---

## Line suppression: `@rule-ignore`

Suppresses one or more specific diagnostics on the **immediately following line**.

```
// @rule-ignore ACU-VAR-001 REASON: populated by calling macro before this point
sResult = APPLY_DISCOUNT(sResult)
```

Multiple IDs can be listed on one line:

```
// @rule-ignore ACU-NAM-002 ACU-NAM-003 REASON: generated variable name
```

The `REASON:` clause is optional but strongly recommended. It makes clear that the
suppression is intentional and explains why.

**Not all diagnostics are suppressable.** Rules with `suppressable: false` in the
catalog cannot be silenced via `@rule-ignore`. This is reserved for errors so
fundamental that suppressing them would mask broken code (e.g. block-structure
mismatches). Currently no rule uses this flag, but it exists for future use.

---

## `.acurity.json` configuration

Project-level configuration file, placed at the root of the scanned folder.

```json
{
  "mode": "default",

  "rules": {
    "namingPrefixScope": "off",
    "robodocMissingStart": "warning"
  },

  "naming": {
    "charToTypeMap":  { "s": "STRING", "d": "DOUBLE" },
    "scopeToCharMap": { "global": "g", "local": "l" }
  },

  "overrides": [
    { "paths": ["ML*.TXT"], "mode": "legacy",  "failOn": "error"   },
    { "paths": ["U0*.TXT"], "mode": "strict",  "failOn": "warning" }
  ]
}
```

| Field | Purpose |
|---|---|
| `mode` | Default mode for all files in the project. Defaults to `"default"` if absent. |
| `rules` | Per-rule severity overrides applied on top of the mode. Values: `"error"`, `"warning"`, `"information"`, `"off"`. |
| `naming` | Customises the naming-convention maps used by ACU-NAM rules. |
| `overrides[].paths` | Array of glob patterns (supports `*` and `**`). First match wins. |
| `overrides[].mode` | Mode to use for matched files. Optional — omit to keep project default. |
| `overrides[].failOn` | CLI exit-code threshold for matched files. Optional. Values: `"error"`, `"warning"`, `"information"`, `"hint"`, `"none"`. |

> **Note on folder structure:** The Acurity runtime places constraints on where
> report files can reside, which typically results in all files sitting in a single
> flat directory. As a consequence, path overrides are most naturally expressed as
> **filename prefix patterns** (e.g. `ML*.TXT`, `U0*.TXT`) rather than folder
> hierarchies. Folder-based patterns (`legacy/**`) remain supported for environments
> that do use subdirectories, but they are not the common case.

---

## VS Code settings

The following settings are available in VS Code. They apply to the current workspace
and are developer-local (not committed to the project).

| Setting | Purpose |
|---|---|
| `acurity.rules.profile` | Selects the base severity profile for unannotated files. Maps to `default`, `legacy`, or `strict`. Overridden by `.acurity.json` and file annotations. |
| `acurity.rules.core.<ruleId>.severity` | Per-rule override for a core rule. |
| `acurity.rules.standards.<ruleId>.severity` | Per-rule override for a standards rule. |

The VS Code setting `acurity.rules.profile` is the workspace equivalent of
`.acurity.json "mode"`. If both exist, the file annotation (level 6) always wins;
`.acurity.json` (levels 2–4) wins over the workspace setting (level 5).

---

## Surfaces: IDE vs CI/CD

Each catalog entry declares which **surfaces** a rule is active on:

| Surface | Context |
|---|---|
| `ide` | Real-time diagnostics shown in VS Code as you type. |
| `cicd` | Batch validation run by the CLI. |

Some rules are IDE-only (e.g. `ACU-KWD-001` keyword capitalisation) because they
are too noisy or low-value for CI pipeline output. Others apply to both. This is a
static property of the rule — it cannot be overridden per-project. If a rule is not
listed for a surface, it is silent on that surface regardless of mode or severity.

---

## Adding a new rule: decision guide

When implementing a new diagnostic, answer these questions in order:

**1. Which mode(s) should this rule be active in?**

| Rule fires in... | Typical category |
|---|---|
| All three modes | Validity or correctness (`blockStructure`, `undefinedVariable`) |
| `default` and `strict` only | Advisory or convention (`namingPrefixScope`, `unsetVariable`) |
| `strict` only | Style opinions that would be too disruptive in older code (`exitTerminatorIssue`, `varDeclarationForm`) |

Set the severity in `DEFAULT_RULE_SEVERITY_PROFILES` in `diagnosticCatalog.js`.
Use `"off"` for modes where the rule should be silent.

**2. Which surfaces?**

- Both `ide` and `cicd` — default for correctness and advisory rules.
- `ide` only — for rules that produce noise in CI (e.g. formatting style, TODO tags).

Set `surfaces` on the catalog entry.

**3. Is it suppressable?**

Default: yes. Set `suppressable: false` only for errors where silencing them would
hide broken code.

**4. Does it need a quick-fix?**

If the fix is mechanical and unambiguous, add an entry to `quickFixCatalog.js` and
implement it in `codeActionProvider.js`.

**5. Write the syntax test first (TDD).**

- For a `strict`-only rule: create a `.TXT` with `// @mode:strict` in the
  header. Add both accepted and rejected cases.
- For a guard (rule must NOT fire): use `unexpected-messages` in the spec.
- For a stub (rule not yet implemented): leave both `expected-messages` and
  `unexpected-messages` empty. Graduate to a real spec when implemented.

---

## Summary table: mechanism reference

| Mechanism | Scope | Who controls it | What it affects |
|---|---|---|---|
| `surfaces` in catalog | Per-rule, static | Rule author | Which runtime contexts the rule is active in |
| Mode severity profiles | Per-mode, per-rule | Rule author | Default severity in each mode |
| `.acurity.json` `"mode"` | Project | Team | Default mode for the project |
| `.acurity.json` `"rules"` | Project, per-rule | Team | Per-rule overrides on top of mode |
| `.acurity.json` `overrides[].mode` | Path glob | Team | Mode for files in specific directories |
| `.acurity.json` `overrides[].failOn` | Path glob | Team | CI exit-code threshold per directory |
| VS Code `settings.json` | Workspace, per-rule | Developer | Local severity tuning |
| `// @mode:...` | File | Developer | Mode for one file |
| `// @rule-ignore` | Line | Developer | Suppress a specific diagnostic on the next line |
