# Diagnostic codes

<!-- GENERATED by `harn explain --catalog --format markdown` -- do not edit by hand. -->
<!-- Source of truth: crates/harn-parser/src/diagnostic_codes.rs. Run `make sync-diagnostics-catalog` to regenerate. -->

<!-- markdownlint-disable MD013 MD024 -->

Every diagnostic emitted by `harn check`, `harn lint`, and `harn fmt` carries a stable `HARN-<CAT>-<NNN>` code. Codes are dispatchable: agents, IDEs, and the hosted error pages all read the same `apiStability: stable` contract, so cross-tooling integrations never have to regex on prose.

Look up a single code interactively:

```sh
harn explain HARN-TYP-014
harn explain HARN-TYP-014 --json
```

The structured JSON sidecar that drives this page is committed at [`docs/diagnostics-catalog.json`](https://github.com/burin-labs/harn/blob/main/docs/diagnostics-catalog.json) — its `schemaVersion: 1` shape is the contract consumed by downstream tooling (burin-code's IDE diagnostic panel, harn-cloud's hosted error pages). Regenerate locally with `make sync-diagnostics-catalog`.

Prose-style tour of common shape and nilable diagnostics: [Reading shape diagnostics](./reading-shape-diagnostics.md).

## Repair safety classes

Repairs are tagged with a six-level safety class so `harn fix --apply --safety <ceiling>` and IDE auto-apply policies can dispatch without inspecting individual edits:

| Class | Meaning |
|---|---|
| `format-only` | Whitespace, trivia, or canonical layout only. Always safe to auto-apply. |
| `behavior-preserving` | Intended not to change observable runtime behavior. |
| `scope-local` | Confined to the current local scope or file; blast radius does not cross a public surface. |
| `surface-changing` | Touches a signature, export, or call-site surface other files can observe. |
| `capability-changing` | Required capabilities or sandbox profile may change. |
| `needs-human` | Planning hint only — propose, never auto-apply. |

## Categories

| Category | Title | Codes |
|---|---|---:|
| [`TYP`](#typ--type-checker) | Type checker | 25 |
| [`PAR`](#par--parser--lexer) | Parser / lexer | 6 |
| [`NAM`](#nam--naming-and-resolution) | Naming and resolution | 13 |
| [`CAP`](#cap--capabilities) | Capabilities | 9 |
| [`LLM`](#llm--llm-calls) | LLM calls | 5 |
| [`ORC`](#orc--orchestration-constructs) | Orchestration constructs | 12 |
| [`STD`](#std--stdlib-usage) | Stdlib usage | 4 |
| [`PRM`](#prm--prompt-templates) | Prompt templates | 7 |
| [`MOD`](#mod--modules-and-exports) | Modules and exports | 6 |
| [`RMD`](#rmd--reminder-lifecycle) | Reminder lifecycle | 8 |
| [`SUS`](#sus--suspend--resume-lifecycle) | Suspend / resume lifecycle | 13 |
| [`LNT`](#lnt--lint-rules) | Lint rules | 59 |
| [`FMT`](#fmt--formatter) | Formatter | 3 |
| [`IMP`](#imp--import-resolution) | Import resolution | 3 |
| [`OWN`](#own--ownership-and-mutability) | Ownership and mutability | 4 |
| [`RCV`](#rcv--error-recovery) | Error recovery | 3 |
| [`MAT`](#mat--match-exhaustiveness) | Match exhaustiveness | 3 |
| [`POL`](#pol--runtime-policies) | Runtime policies | 2 |
| [`MET`](#met--compile-time-meta-restrictions) | Compile-time meta restrictions | 1 |
| [`CST`](#cst--const-eval-sandbox) | Const-eval sandbox | 4 |
| [`CMP`](#cmp--bytecode-compilation) | Bytecode compilation | 1 |

## TYP — Type checker

Harn's static type checker rejects programs whose types do not unify. Type errors block compilation — Harn refuses to run a program until they are fixed.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-TYP-001`](#harn-typ-001) | expected and actual types are incompatible | `casts/insert-explicit-conversion` | `scope-local` |
| [`HARN-TYP-002`](#harn-typ-002) | binary operator is not defined for the operand types | — | — |
| [`HARN-TYP-003`](#harn-typ-003) | string concatenation should be rewritten as interpolation | `style/string-interpolation` | `behavior-preserving` |
| [`HARN-TYP-004`](#harn-typ-004) | returned expression does not match the declared return type | `casts/insert-explicit-conversion` | `scope-local` |
| [`HARN-TYP-005`](#harn-typ-005) | assigned value does not match the target type | `casts/insert-explicit-conversion` | `scope-local` |
| [`HARN-TYP-006`](#harn-typ-006) | argument value does not match the parameter type | `casts/insert-explicit-conversion` | `scope-local` |
| [`HARN-TYP-007`](#harn-typ-007) | initializer does not match the declared variable type | `casts/insert-explicit-conversion` | `scope-local` |
| [`HARN-TYP-008`](#harn-typ-008) | closure return expression does not match its declared type | `casts/insert-explicit-conversion` | `scope-local` |
| [`HARN-TYP-009`](#harn-typ-009) | field value does not match its declared type | `casts/insert-explicit-conversion` | `scope-local` |
| [`HARN-TYP-010`](#harn-typ-010) | method receiver or result type is incompatible | `casts/insert-explicit-conversion` | `scope-local` |
| [`HARN-TYP-011`](#harn-typ-011) | callable does not accept type arguments | — | — |
| [`HARN-TYP-012`](#harn-typ-012) | type argument does not satisfy the generic parameter | — | — |
| [`HARN-TYP-013`](#harn-typ-013) | generic call has the wrong number of type arguments | — | — |
| [`HARN-TYP-014`](#harn-typ-014) | declaration has the wrong number of type parameters | — | — |
| [`HARN-TYP-015`](#harn-typ-015) | type argument does not satisfy a where-clause constraint | — | — |
| [`HARN-TYP-016`](#harn-typ-016) | expression must be iterable | — | — |
| [`HARN-TYP-017`](#harn-typ-017) | subscript index type is invalid | `casts/insert-explicit-conversion` | `scope-local` |
| [`HARN-TYP-018`](#harn-typ-018) | expression must be callable | — | — |
| [`HARN-TYP-019`](#harn-typ-019) | cast cannot be proven valid | `casts/remove-unchecked` | `scope-local` |
| [`HARN-TYP-020`](#harn-typ-020) | type name cannot be resolved | `imports/fix-path` | `scope-local` |
| [`HARN-TYP-021`](#harn-typ-021) | variant type is used in an invalid position | — | — |
| [`HARN-TYP-022`](#harn-typ-022) | struct literal is invalid | — | — |
| [`HARN-TYP-023`](#harn-typ-023) | enum construction is invalid | — | — |
| [`HARN-TYP-024`](#harn-typ-024) | pattern binding is invalid for the expected type | — | — |
| [`HARN-TYP-025`](#harn-typ-025) | optional access is invalid for the receiver type | — | — |

## PAR — Parser / lexer

The lexer or parser raises these before type checking begins. Harn cannot build an AST from the source until the offending token sequence is repaired.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-PAR-001`](#harn-par-001) | parser found an unexpected token | — | — |
| [`HARN-PAR-002`](#harn-par-002) | parser reached end of file while expecting syntax | — | — |
| [`HARN-PAR-003`](#harn-par-003) | lexer found an unexpected character | — | — |
| [`HARN-PAR-004`](#harn-par-004) | string literal is unterminated | — | — |
| [`HARN-PAR-005`](#harn-par-005) | block comment is unterminated | — | — |
| [`HARN-PAR-006`](#harn-par-006) | integer literal is out of range for int (i64) | — | — |

## NAM — Naming and resolution

Name resolution failed: the identifier, field, or attribute referenced does not match anything in the visible scope. Harn cannot proceed without a binding.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-NAM-001`](#harn-nam-001) | variable name cannot be resolved | `bindings/rename-to-closest` | `scope-local` |
| [`HARN-NAM-002`](#harn-nam-002) | function name cannot be resolved | `bindings/rename-to-closest` | `scope-local` |
| [`HARN-NAM-003`](#harn-nam-003) | attribute name is not recognized | — | — |
| [`HARN-NAM-004`](#harn-nam-004) | field name does not exist on the target type | `bindings/rename-to-closest` | `scope-local` |
| [`HARN-NAM-005`](#harn-nam-005) | method name does not exist on the receiver type | `bindings/rename-to-closest` | `scope-local` |
| [`HARN-NAM-006`](#harn-nam-006) | argument name is duplicated | — | — |
| [`HARN-NAM-007`](#harn-nam-007) | option key is not recognized | — | — |
| [`HARN-NAM-008`](#harn-nam-008) | builtin name cannot be resolved | `bindings/rename-to-closest` | `scope-local` |
| [`HARN-NAM-009`](#harn-nam-009) | function call targets a deprecated declaration | `stdlib/migrate-renamed` | `scope-local` |
| [`HARN-NAM-010`](#harn-nam-010) | declaration reference cannot be resolved | `bindings/rename-to-closest` | `scope-local` |
| [`HARN-NAM-011`](#harn-nam-011) | attribute is attached to an unsupported declaration | — | — |
| [`HARN-NAM-012`](#harn-nam-012) | attribute argument is invalid | — | — |
| [`HARN-NAM-101`](#harn-nam-101) | `main` entrypoint must take a single `harness: Harness` parameter | `bindings/thread-harness-needs-param` | `surface-changing` |

## CAP — Capabilities

A host capability call (file I/O, network, HITL approval, tool host, etc.) failed static validation. Capabilities are the trust boundary between Harn scripts and the embedding host, so checks are strict by design.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-CAP-001`](#harn-cap-001) | capability payload is invalid | — | — |
| [`HARN-CAP-002`](#harn-cap-002) | human approval construct is missing policy | — | — |
| [`HARN-CAP-003`](#harn-cap-003) | human approval argument is invalid | — | — |
| [`HARN-CAP-004`](#harn-cap-004) | capability result must be checked | `errors/check-or-rescue` | `scope-local` |
| [`HARN-CAP-005`](#harn-cap-005) | host capability operation is not declared | — | — |
| [`HARN-CAP-006`](#harn-cap-006) | host capability call must use a static operation name | — | — |
| [`HARN-CAP-007`](#harn-cap-007) | tool host capability binding is invalid | `manual/review-capability-binding` | `needs-human` |
| [`HARN-CAP-201`](#harn-cap-201) | harness capability denied by active sandbox profile | — | — |
| [`HARN-CAP-301`](#harn-cap-301) | child agent effect set exceeds the parent's declared effects | `policy/narrow-child-effects` | `surface-changing` |

## LLM — LLM calls

An `llm_call(...)` invocation violates the schema Harn enforces. Schema-validated, provider-portable LLM calls are a load-bearing Harn contract; drift in the options table is rejected at check time.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-LLM-001`](#harn-llm-001) | LLM option key is not recognized | — | — |
| [`HARN-LLM-002`](#harn-llm-002) | LLM option key is deprecated | `llm/migrate-deprecated-option` | `scope-local` |
| [`HARN-LLM-003`](#harn-llm-003) | LLM call is missing schema validation | `llm/add-schema` | `surface-changing` |
| [`HARN-LLM-004`](#harn-llm-004) | LLM schema option is invalid | — | — |
| [`HARN-LLM-005`](#harn-llm-005) | prompt branches on provider identity instead of capability flags | `llm/use-capability-flag` | `capability-changing` |

## ORC — Orchestration constructs

An orchestration construct — agent / workflow / pipeline / tool definition, or a call to an orchestration builtin — is shaped in a way the orchestrator cannot accept.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-ORC-001`](#harn-orc-001) | orchestration construct has invalid arity | — | — |
| [`HARN-ORC-002`](#harn-orc-002) | orchestration construct argument has invalid type | — | — |
| [`HARN-ORC-003`](#harn-orc-003) | agent declaration is invalid | — | — |
| [`HARN-ORC-004`](#harn-orc-004) | workflow declaration is invalid | — | — |
| [`HARN-ORC-005`](#harn-orc-005) | tool declaration is invalid | — | — |
| [`HARN-ORC-006`](#harn-orc-006) | pipeline declaration is invalid | — | — |
| [`HARN-ORC-007`](#harn-orc-007) | select construct is invalid | — | — |
| [`HARN-ORC-008`](#harn-orc-008) | statement cannot be reached | `control-flow/remove-dead` | `behavior-preserving` |
| [`HARN-ORC-009`](#harn-orc-009) | Flow invariant attribute set is invalid | — | — |
| [`HARN-ORC-010`](#harn-orc-010) | execution target path cannot be found | — | — |
| [`HARN-ORC-011`](#harn-orc-011) | a self-deadlock acquire would block forever | — | — |
| [`HARN-ORC-012`](#harn-orc-012) | a wait-for graph cycle would block forever | — | — |

## STD — Stdlib usage

A stdlib symbol is used in a way Harn does not support, or has been renamed/removed and the call site still references the old surface.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-STD-001`](#harn-std-001) | stdlib symbol has been renamed or deprecated | `stdlib/migrate-renamed` | `scope-local` |
| [`HARN-STD-002`](#harn-std-002) | stdlib call is invalid | — | — |
| [`HARN-STD-003`](#harn-std-003) | builtin call has invalid arity | — | — |
| [`HARN-STD-101`](#harn-std-101) | public stdlib function is missing declared metadata | `doc/add-stdlib-metadata` | `behavior-preserving` |

## PRM — Prompt templates

A prompt template (`.harn.prompt` / `.prompt`) failed validation, either because its front matter is missing required fields or because the body references slots the schema does not declare.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-PRM-001`](#harn-prm-001) | prompt template cannot be parsed | — | — |
| [`HARN-PRM-002`](#harn-prm-002) | prompt template has too many capability-aware branches | `manual/needs-human` | `needs-human` |
| [`HARN-PRM-003`](#harn-prm-003) | prompt construction risks direct injection | `prompts/escape-injection` | `scope-local` |
| [`HARN-PRM-004`](#harn-prm-004) | prompt template branches on provider identity | `llm/use-capability-flag` | `capability-changing` |
| [`HARN-PRM-005`](#harn-prm-005) | prompt references a tool outside the declared surface | `prompts/add-tool-to-surface` | `surface-changing` |
| [`HARN-PRM-006`](#harn-prm-006) | prompt references a deferred tool without tool search | `prompts/add-tool-to-surface` | `surface-changing` |
| [`HARN-PRM-007`](#harn-prm-007) | prompt or template target cannot be found | — | — |

## MOD — Modules and exports

A module-level import declaration cannot be satisfied or has been authored in a shape Harn rejects. Module boundaries are checked before the body is type-checked.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-MOD-001`](#harn-mod-001) | module import cannot be resolved | `imports/fix-path` | `scope-local` |
| [`HARN-MOD-002`](#harn-mod-002) | module import is unused | `imports/remove-unused` | `behavior-preserving` |
| [`HARN-MOD-003`](#harn-mod-003) | module imports are not in canonical order | `imports/reorder` | `format-only` |
| [`HARN-MOD-004`](#harn-mod-004) | module export is invalid | — | — |
| [`HARN-MOD-005`](#harn-mod-005) | module imports expose colliding names | — | — |
| [`HARN-MOD-006`](#harn-mod-006) | module re-exports conflict | — | — |

## RMD — Reminder lifecycle

Reminder lifecycle errors are raised by `session/remind` and friends when the payload, tags, or scheduling do not match the documented contract.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-RMD-001`](#harn-rmd-001) | reminder lifecycle option key is not recognized | — | — |
| [`HARN-RMD-002`](#harn-rmd-002) | reminder payload shape is invalid | — | — |
| [`HARN-RMD-003`](#harn-rmd-003) | user_block reminder role hint is not supported by the selected provider | — | — |
| [`HARN-RMD-004`](#harn-rmd-004) | discardable reminder has no TTL | — | — |
| [`HARN-RMD-005`](#harn-rmd-005) | reminder propagate value is not recognized | — | — |
| [`HARN-RMD-006`](#harn-rmd-006) | reminder provider returned a malformed reminder spec | — | — |
| [`HARN-RMD-007`](#harn-rmd-007) | too many reminder providers are enabled | — | — |
| [`HARN-RMD-008`](#harn-rmd-008) | hook event does not support reminder effects | — | — |

## SUS — Suspend / resume lifecycle

Suspend / resume lifecycle errors are raised when a worker is suspended, resumed, or queried outside the lifecycle states the operation supports.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-SUS-001`](#harn-sus-001) | suspend_agent target worker is not running | — | — |
| [`HARN-SUS-002`](#harn-sus-002) | ResumeConditions validation failed | — | — |
| [`HARN-SUS-003`](#harn-sus-003) | resume_agent target worker is not suspended | — | — |
| [`HARN-SUS-004`](#harn-sus-004) | resume snapshot cannot be loaded or used | — | — |
| [`HARN-SUS-005`](#harn-sus-005) | agent_await_resumption was invoked outside agent_loop structural handling | — | — |
| [`HARN-SUS-006`](#harn-sus-006) | concurrent resume changed the worker before resume could complete | — | — |
| [`HARN-SUS-007`](#harn-sus-007) | ResumeConditions trigger could not be registered | — | — |
| [`HARN-SUS-008`](#harn-sus-008) | resume timeout action is unsupported | — | — |
| [`HARN-SUS-009`](#harn-sus-009) | resume input failed agent_loop input validation | — | — |
| [`HARN-SUS-010`](#harn-sus-010) | closed suspended worker cannot be resumed | — | — |
| [`HARN-SUS-011`](#harn-sus-011) | replay resume input hash diverges from journaled suspension | — | — |
| [`HARN-SUS-012`](#harn-sus-012) | replay drain decision prompt hash diverges from journaled receipt | — | — |
| [`HARN-SUS-013`](#harn-sus-013) | lifecycle receipt signed timestamp failed verification | — | — |

## LNT — Lint rules

Lints are not hard errors. The code compiles, but Harn flags the pattern as likely-incorrect, unidiomatic, or risky in a production agent. Most lints can be auto-fixed.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-LNT-001`](#harn-lnt-001) | renamed stdlib symbol lint | `stdlib/migrate-renamed` | `scope-local` |
| [`HARN-LNT-002`](#harn-lnt-002) | cyclomatic complexity lint | — | — |
| [`HARN-LNT-003`](#harn-lnt-003) | naming convention lint | `style/rename-to-convention` | `surface-changing` |
| [`HARN-LNT-004`](#harn-lnt-004) | eager collection conversion lint | `collections/prefer-lazy` | `scope-local` |
| [`HARN-LNT-005`](#harn-lnt-005) | redundant clone lint | `clones/remove-redundant` | `behavior-preserving` |
| [`HARN-LNT-006`](#harn-lnt-006) | long-running workflow cleanup lint | `manual/needs-human` | `needs-human` |
| [`HARN-LNT-007`](#harn-lnt-007) | MCP tool annotations lint | `manual/needs-human` | `needs-human` |
| [`HARN-LNT-008`](#harn-lnt-008) | PR open without secret scan lint | — | — |
| [`HARN-LNT-009`](#harn-lnt-009) | shadow variable lint | `bindings/rename-shadow` | `scope-local` |
| [`HARN-LNT-010`](#harn-lnt-010) | persona hook target lint | — | — |
| [`HARN-LNT-011`](#harn-lnt-011) | dead code after return lint | `control-flow/remove-dead` | `behavior-preserving` |
| [`HARN-LNT-012`](#harn-lnt-012) | let then return lint | `control-flow/flatten` | `behavior-preserving` |
| [`HARN-LNT-013`](#harn-lnt-013) | unhandled approval result lint | `errors/check-or-rescue` | `scope-local` |
| [`HARN-LNT-014`](#harn-lnt-014) | unused variable lint | `bindings/rename-unused` | `behavior-preserving` |
| [`HARN-LNT-015`](#harn-lnt-015) | unused pattern binding lint | `bindings/rename-unused` | `behavior-preserving` |
| [`HARN-LNT-016`](#harn-lnt-016) | unused parameter lint | `bindings/rename-unused` | `behavior-preserving` |
| [`HARN-LNT-017`](#harn-lnt-017) | unused import lint | `imports/remove-unused` | `behavior-preserving` |
| [`HARN-LNT-018`](#harn-lnt-018) | mutable never reassigned lint | `bindings/make-immutable` | `behavior-preserving` |
| [`HARN-LNT-019`](#harn-lnt-019) | unused function lint | `declarations/remove-unused` | `surface-changing` |
| [`HARN-LNT-020`](#harn-lnt-020) | unused type lint | `declarations/remove-unused` | `surface-changing` |
| [`HARN-LNT-021`](#harn-lnt-021) | persona body must call steps lint | — | — |
| [`HARN-LNT-022`](#harn-lnt-022) | undefined function lint | — | — |
| [`HARN-LNT-023`](#harn-lnt-023) | pipeline return type lint | — | — |
| [`HARN-LNT-024`](#harn-lnt-024) | missing harndoc lint | `doc/add-harndoc` | `behavior-preserving` |
| [`HARN-LNT-025`](#harn-lnt-025) | assert outside test lint | — | — |
| [`HARN-LNT-026`](#harn-lnt-026) | prompt injection risk lint | `prompts/escape-injection` | `scope-local` |
| [`HARN-LNT-027`](#harn-lnt-027) | connector effect policy lint | — | — |
| [`HARN-LNT-028`](#harn-lnt-028) | unnecessary cast lint | `casts/remove-redundant` | `behavior-preserving` |
| [`HARN-LNT-029`](#harn-lnt-029) | untyped dict access lint | `types/add-shape-annotation` | `surface-changing` |
| [`HARN-LNT-030`](#harn-lnt-030) | constant logical operand lint | `expressions/simplify` | `behavior-preserving` |
| [`HARN-LNT-031`](#harn-lnt-031) | pointless comparison lint | `expressions/simplify` | `behavior-preserving` |
| [`HARN-LNT-032`](#harn-lnt-032) | comparison to bool lint | `expressions/simplify` | `behavior-preserving` |
| [`HARN-LNT-033`](#harn-lnt-033) | invalid binary operator literal lint | — | — |
| [`HARN-LNT-034`](#harn-lnt-034) | redundant nil ternary lint | `expressions/simplify` | `behavior-preserving` |
| [`HARN-LNT-035`](#harn-lnt-035) | empty block lint | `blocks/remove-empty` | `scope-local` |
| [`HARN-LNT-036`](#harn-lnt-036) | unnecessary else return lint | `control-flow/flatten` | `behavior-preserving` |
| [`HARN-LNT-037`](#harn-lnt-037) | duplicate match arm lint | `match/remove-duplicate-arm` | `behavior-preserving` |
| [`HARN-LNT-038`](#harn-lnt-038) | require in test lint | — | — |
| [`HARN-LNT-039`](#harn-lnt-039) | break outside loop lint | — | — |
| [`HARN-LNT-040`](#harn-lnt-040) | template parse lint | — | — |
| [`HARN-LNT-041`](#harn-lnt-041) | blank line between items lint | `format/reformat` | `format-only` |
| [`HARN-LNT-042`](#harn-lnt-042) | trailing comma lint | `format/reformat` | `format-only` |
| [`HARN-LNT-043`](#harn-lnt-043) | unnecessary parentheses lint | `format/reformat` | `format-only` |
| [`HARN-LNT-044`](#harn-lnt-044) | template variant explosion lint | `manual/needs-human` | `needs-human` |
| [`HARN-LNT-045`](#harn-lnt-045) | require file header lint | `format/reformat` | `format-only` |
| [`HARN-LNT-046`](#harn-lnt-046) | template provider identity branch lint | `llm/use-capability-flag` | `capability-changing` |
| [`HARN-LNT-047`](#harn-lnt-047) | import order lint | `imports/reorder` | `format-only` |
| [`HARN-LNT-048`](#harn-lnt-048) | prefer optional shorthand lint | `expressions/simplify` | `behavior-preserving` |
| [`HARN-LNT-049`](#harn-lnt-049) | legacy doc comment lint | `doc/migrate-comment-style` | `format-only` |
| [`HARN-LNT-050`](#harn-lnt-050) | deprecated LLM options lint | `llm/migrate-deprecated-option` | `scope-local` |
| [`HARN-LNT-051`](#harn-lnt-051) | unnecessary safe navigation lint | `expressions/simplify` | `behavior-preserving` |
| [`HARN-LNT-052`](#harn-lnt-052) | ambient clock builtin replaced by `harness.clock.*` | `bindings/thread-harness-clock` | `scope-local` |
| [`HARN-LNT-053`](#harn-lnt-053) | ambient stdio builtin replaced by `harness.stdio.*` | `bindings/thread-harness` | `scope-local` |
| [`HARN-LNT-054`](#harn-lnt-054) | ambient fs builtin replaced by `harness.fs.*` | `bindings/thread-harness-fs` | `scope-local` |
| [`HARN-LNT-055`](#harn-lnt-055) | ambient env builtin replaced by `harness.env.*` | `bindings/thread-harness-env` | `scope-local` |
| [`HARN-LNT-056`](#harn-lnt-056) | ambient random builtin replaced by `harness.random.*` | `bindings/thread-harness-random` | `scope-local` |
| [`HARN-LNT-057`](#harn-lnt-057) | ambient net builtin replaced by `harness.net.*` | `bindings/thread-harness-net` | `scope-local` |
| [`HARN-LNT-058`](#harn-lnt-058) | if / while / guard condition is statically known to always succeed or always fail | — | — |
| [`HARN-LNT-059`](#harn-lnt-059) | project rule-engine or native lint rule | — | — |

## FMT — Formatter

The formatter could not produce a canonical layout — either the input contains a construct it does not know how to render, or a layout rule was violated in a way auto-fix cannot resolve.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-FMT-001`](#harn-fmt-001) | formatter could not parse the source | — | — |
| [`HARN-FMT-002`](#harn-fmt-002) | source is not in canonical format | `format/reformat` | `format-only` |
| [`HARN-FMT-003`](#harn-fmt-003) | formatter normalized trailing comma layout | `format/reformat` | `format-only` |

## IMP — Import resolution

Import resolution failed at a deeper layer than `MOD` — the file, symbol, or package referenced in an import declaration could not be located, parsed, or exposed.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-IMP-001`](#harn-imp-001) | import target cannot be resolved | `imports/fix-path` | `scope-local` |
| [`HARN-IMP-002`](#harn-imp-002) | imported symbol does not exist | — | — |
| [`HARN-IMP-003`](#harn-imp-003) | import graph contains a cycle | — | — |

## OWN — Ownership and mutability

Harn's binding-and-mutability discipline rejects this usage. `let` bindings may not be reassigned; `mut` bindings should actually be reassigned somewhere.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-OWN-001`](#harn-own-001) | immutable binding is reassigned | `bindings/make-mutable` | `scope-local` |
| [`HARN-OWN-002`](#harn-own-002) | mutable binding is never reassigned | `bindings/make-immutable` | `behavior-preserving` |
| [`HARN-OWN-003`](#harn-own-003) | owned value escapes its valid scope | — | — |
| [`HARN-OWN-004`](#harn-own-004) | unvalidated boundary value is used directly | — | — |

## RCV — Error recovery

A recovery construct (`try`, `rescue`) is in an invalid position or shaped in a way Harn's error-recovery rules cannot accept.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-RCV-001`](#harn-rcv-001) | rescue construct is outside a function body | `errors/wrap-in-fn` | `surface-changing` |
| [`HARN-RCV-002`](#harn-rcv-002) | try construct is outside a function body | `errors/wrap-in-fn` | `surface-changing` |
| [`HARN-RCV-003`](#harn-rcv-003) | rescue construct is invalid | — | — |

## MAT — Match exhaustiveness

A `match` expression is incomplete, ambiguous, or otherwise invalid. Harn requires arms to cover every variant of the scrutinee type — partial matches must opt in with an explicit catch-all.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-MAT-001`](#harn-mat-001) | match expression is not exhaustive | `match/add-missing-arms` | `scope-local` |
| [`HARN-MAT-002`](#harn-mat-002) | match expression contains a duplicate arm | `match/remove-duplicate-arm` | `behavior-preserving` |
| [`HARN-MAT-003`](#harn-mat-003) | match pattern is invalid | — | — |

## POL — Runtime policies

A runtime policy (pool backpressure, scheduling, quotas) rejected the attempt. Policies are configurable, but defaults are tuned for safety over throughput.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-POL-001`](#harn-pol-001) | pool backpressure rejected a submit | — | — |
| [`HARN-POL-002`](#harn-pol-002) | fail-fast pool has no immediate capacity | — | — |

## MET — Compile-time meta restrictions

A `const` binding's right-hand side must be a pure expression evaluable at compile time under the const-eval sandbox. These codes flag constructs the sandbox rejects.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-MET-001`](#harn-met-001) | expression is not permitted in a const initializer | — | — |

## CST — Const-eval sandbox

The bounded const-eval sandbox enforces step, recursion, and capability limits on every `const` initializer so a hostile or accidental expression cannot stall the compiler.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-CST-001`](#harn-cst-001) | const initializer exceeded the step budget | — | — |
| [`HARN-CST-002`](#harn-cst-002) | const initializer exceeded the recursion depth budget | — | — |
| [`HARN-CST-003`](#harn-cst-003) | const initializer attempted a sandboxed capability | — | — |
| [`HARN-CST-004`](#harn-cst-004) | const initializer raised a runtime error during evaluation | — | — |

## CMP — Bytecode compilation

The bytecode compiler rejected a program that parsed and type-checked. These are structural / codegen errors the type checker does not model — `harn check` runs the compile pass too, so anything that would stop `harn run` is reported up front.

| Code | Summary | Repair | Safety |
|---|---|---|---|
| [`HARN-CMP-001`](#harn-cmp-001) | the program failed to compile to bytecode | — | — |

## Code reference

### `HARN-TYP-001`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

expected and actual types are incompatible

- **Repair:** `casts/insert-explicit-conversion` &nbsp;·&nbsp; **Safety:** `scope-local`
- Insert an explicit conversion or correct the operand type
- **See also:** [`HARN-TYP-005`](#harn-typ-005), [`HARN-TYP-006`](#harn-typ-006), [`HARN-TYP-004`](#harn-typ-004), [`HARN-TYP-007`](#harn-typ-007), [`HARN-TYP-009`](#harn-typ-009)

#### What it means

Harn's type checker compared the inferred ("actual") type of an expression
against the type the surrounding context expects, and the two did not unify.
This is the most common type error — it covers any mismatch that doesn't fall
into one of the more specific TYP codes (assignment, argument, return, etc.).

#### How to fix

- Adjust the expression so its inferred type matches the surrounding
  context.
- Widen the declared type at the binding / parameter / return position to
  accept the actual type.
- Convert the value explicitly (`as`, a stdlib coercion, etc.) when a safe
  conversion exists.
- If the mismatch is between a concrete type and an optional, use
  `?`-chaining or supply a default with `??`.

### `HARN-TYP-002`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

binary operator is not defined for the operand types

### `HARN-TYP-003`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

string concatenation should be rewritten as interpolation

- **Repair:** `style/string-interpolation` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Rewrite string concatenation as an interpolation literal

### `HARN-TYP-004`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

returned expression does not match the declared return type

- **Repair:** `casts/insert-explicit-conversion` &nbsp;·&nbsp; **Safety:** `scope-local`
- Insert an explicit conversion or correct the operand type
- **See also:** [`HARN-TYP-001`](#harn-typ-001), [`HARN-TYP-008`](#harn-typ-008)

### `HARN-TYP-005`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

assigned value does not match the target type

- **Repair:** `casts/insert-explicit-conversion` &nbsp;·&nbsp; **Safety:** `scope-local`
- Insert an explicit conversion or correct the operand type
- **See also:** [`HARN-TYP-001`](#harn-typ-001), [`HARN-TYP-007`](#harn-typ-007)

### `HARN-TYP-006`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

argument value does not match the parameter type

- **Repair:** `casts/insert-explicit-conversion` &nbsp;·&nbsp; **Safety:** `scope-local`
- Insert an explicit conversion or correct the operand type
- **See also:** [`HARN-TYP-001`](#harn-typ-001), [`HARN-TYP-012`](#harn-typ-012)

### `HARN-TYP-007`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

initializer does not match the declared variable type

- **Repair:** `casts/insert-explicit-conversion` &nbsp;·&nbsp; **Safety:** `scope-local`
- Insert an explicit conversion or correct the operand type
- **See also:** [`HARN-TYP-001`](#harn-typ-001), [`HARN-TYP-005`](#harn-typ-005)

### `HARN-TYP-008`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

closure return expression does not match its declared type

- **Repair:** `casts/insert-explicit-conversion` &nbsp;·&nbsp; **Safety:** `scope-local`
- Insert an explicit conversion or correct the operand type
- **See also:** [`HARN-TYP-004`](#harn-typ-004)

### `HARN-TYP-009`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

field value does not match its declared type

- **Repair:** `casts/insert-explicit-conversion` &nbsp;·&nbsp; **Safety:** `scope-local`
- Insert an explicit conversion or correct the operand type
- **See also:** [`HARN-TYP-001`](#harn-typ-001), [`HARN-TYP-022`](#harn-typ-022)

### `HARN-TYP-010`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

method receiver or result type is incompatible

- **Repair:** `casts/insert-explicit-conversion` &nbsp;·&nbsp; **Safety:** `scope-local`
- Insert an explicit conversion or correct the operand type
- **See also:** [`HARN-TYP-001`](#harn-typ-001), [`HARN-TYP-018`](#harn-typ-018)

### `HARN-TYP-011`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

callable does not accept type arguments

- **See also:** [`HARN-TYP-012`](#harn-typ-012), [`HARN-TYP-013`](#harn-typ-013)

unsupported)

### `HARN-TYP-012`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

type argument does not satisfy the generic parameter

- **See also:** [`HARN-TYP-013`](#harn-typ-013), [`HARN-TYP-015`](#harn-typ-015)

mismatch)

### `HARN-TYP-013`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

generic call has the wrong number of type arguments

- **See also:** [`HARN-TYP-012`](#harn-typ-012), [`HARN-TYP-014`](#harn-typ-014)

### `HARN-TYP-014`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

declaration has the wrong number of type parameters

- **See also:** [`HARN-TYP-013`](#harn-typ-013)

#### What it means

A generic declaration (function, type alias, or struct) was written with a
different number of type parameters than the use-site supplies. Harn refuses
to silently fill in missing parameters or discard extra ones — the count must
match exactly.

#### Example

```harn,ignore
fn pair<T>(a: T, b: T) -> [T; 2] { [a, b] }

// HARN-TYP-014: pair takes 1 type parameter, not 2
let xs = pair::<int, string>(1, "two")
```

#### How to fix

- Supply exactly as many type arguments as the declaration declares, or omit
  the explicit list and let Harn infer them.
- If the declaration itself is wrong, edit the `<T, U, ...>` list on the
  declaration to match the arity the callers expect.
- For type aliases and structs, the same rule applies: `Map<K, V>` needs two
  arguments, not one and not three.

### `HARN-TYP-015`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

type argument does not satisfy a where-clause constraint

- **See also:** [`HARN-TYP-012`](#harn-typ-012)

### `HARN-TYP-016`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

expression must be iterable

### `HARN-TYP-017`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

subscript index type is invalid

- **Repair:** `casts/insert-explicit-conversion` &nbsp;·&nbsp; **Safety:** `scope-local`
- Insert an explicit conversion or correct the operand type

### `HARN-TYP-018`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

expression must be callable

### `HARN-TYP-019`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

cast cannot be proven valid

- **Repair:** `casts/remove-unchecked` &nbsp;·&nbsp; **Safety:** `scope-local`
- Remove the unchecked cast or guard it with a type test

### `HARN-TYP-020`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

type name cannot be resolved

- **Repair:** `imports/fix-path` &nbsp;·&nbsp; **Safety:** `scope-local`
- Replace the import path with a resolvable target

### `HARN-TYP-021`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

variant type is used in an invalid position

### `HARN-TYP-022`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

struct literal is invalid

### `HARN-TYP-023`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

enum construction is invalid

### `HARN-TYP-024`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

pattern binding is invalid for the expected type

### `HARN-TYP-025`

**Category:** `TYP` (Type checker) &nbsp;·&nbsp; **API stability:** `stable`

optional access is invalid for the receiver type

### `HARN-PAR-001`

**Category:** `PAR` (Parser / lexer) &nbsp;·&nbsp; **API stability:** `stable`

parser found an unexpected token

#### How to fix

- Re-read the source around the highlighted span and restore the missing token(s).
- If the surrounding construct is a multi-line expression, check brace / bracket balance.

### `HARN-PAR-002`

**Category:** `PAR` (Parser / lexer) &nbsp;·&nbsp; **API stability:** `stable`

parser reached end of file while expecting syntax

#### How to fix

- Re-read the source around the highlighted span and restore the missing token(s).
- If the surrounding construct is a multi-line expression, check brace / bracket balance.

### `HARN-PAR-003`

**Category:** `PAR` (Parser / lexer) &nbsp;·&nbsp; **API stability:** `stable`

lexer found an unexpected character

#### How to fix

- Re-read the source around the highlighted span and restore the missing token(s).
- If the surrounding construct is a multi-line expression, check brace / bracket balance.

### `HARN-PAR-004`

**Category:** `PAR` (Parser / lexer) &nbsp;·&nbsp; **API stability:** `stable`

string literal is unterminated

#### How to fix

- Re-read the source around the highlighted span and restore the missing token(s).
- If the surrounding construct is a multi-line expression, check brace / bracket balance.

### `HARN-PAR-005`

**Category:** `PAR` (Parser / lexer) &nbsp;·&nbsp; **API stability:** `stable`

block comment is unterminated

comment)

#### How to fix

- Re-read the source around the highlighted span and restore the missing token(s).
- If the surrounding construct is a multi-line expression, check brace / bracket balance.

### `HARN-PAR-006`

**Category:** `PAR` (Parser / lexer) &nbsp;·&nbsp; **API stability:** `stable`

integer literal is out of range for int (i64)

An integer literal must fit in a 64-bit signed integer (`int`), i.e. be in the
range `-9223372036854775808 ..= 9223372036854775807`. Harn does not silently
widen an out-of-range integer literal to a float, because that would lose both
the exact value (distinct literals collapse onto the same `float`) and the
`int` type.

#### How to fix

- If you meant a floating-point value, write it with a decimal point or
  exponent so it lexes as a `float` (e.g. `9223372036854775808.0`).
- If you need the most negative `int`, build it by arithmetic — the sign is not
  part of the literal, so `9223372036854775808` overflows on its own:
  `-9223372036854775807 - 1`.
- Otherwise the value genuinely does not fit in `int`; rework the computation to
  stay within range.

### `HARN-NAM-001`

**Category:** `NAM` (Naming and resolution) &nbsp;·&nbsp; **API stability:** `stable`

variable name cannot be resolved

- **Repair:** `bindings/rename-to-closest` &nbsp;·&nbsp; **Safety:** `scope-local`
- Rename to the closest in-scope identifier
- **See also:** [`HARN-NAM-002`](#harn-nam-002), [`HARN-NAM-010`](#harn-nam-010)

#### How to fix

- Define the missing name, import it, or fix the typo.
- Confirm the symbol is exported by the module you're importing from.

### `HARN-NAM-002`

**Category:** `NAM` (Naming and resolution) &nbsp;·&nbsp; **API stability:** `stable`

function name cannot be resolved

- **Repair:** `bindings/rename-to-closest` &nbsp;·&nbsp; **Safety:** `scope-local`
- Rename to the closest in-scope identifier
- **See also:** [`HARN-NAM-008`](#harn-nam-008), [`HARN-NAM-010`](#harn-nam-010)

#### How to fix

- Define the missing name, import it, or fix the typo.
- Confirm the symbol is exported by the module you're importing from.

### `HARN-NAM-003`

**Category:** `NAM` (Naming and resolution) &nbsp;·&nbsp; **API stability:** `stable`

attribute name is not recognized

- **See also:** [`HARN-NAM-012`](#harn-nam-012), [`HARN-NAM-011`](#harn-nam-011)

#### How to fix

- Define the missing name, import it, or fix the typo.
- Confirm the symbol is exported by the module you're importing from.

### `HARN-NAM-004`

**Category:** `NAM` (Naming and resolution) &nbsp;·&nbsp; **API stability:** `stable`

field name does not exist on the target type

- **Repair:** `bindings/rename-to-closest` &nbsp;·&nbsp; **Safety:** `scope-local`
- Rename to the closest in-scope identifier
- **See also:** [`HARN-NAM-005`](#harn-nam-005), [`HARN-TYP-022`](#harn-typ-022)

#### How to fix

- Define the missing name, import it, or fix the typo.
- Confirm the symbol is exported by the module you're importing from.

### `HARN-NAM-005`

**Category:** `NAM` (Naming and resolution) &nbsp;·&nbsp; **API stability:** `stable`

method name does not exist on the receiver type

- **Repair:** `bindings/rename-to-closest` &nbsp;·&nbsp; **Safety:** `scope-local`
- Rename to the closest in-scope identifier
- **See also:** [`HARN-NAM-004`](#harn-nam-004), [`HARN-TYP-018`](#harn-typ-018)

#### How to fix

- Define the missing name, import it, or fix the typo.
- Confirm the symbol is exported by the module you're importing from.

### `HARN-NAM-006`

**Category:** `NAM` (Naming and resolution) &nbsp;·&nbsp; **API stability:** `stable`

argument name is duplicated

#### How to fix

- Define the missing name, import it, or fix the typo.
- Confirm the symbol is exported by the module you're importing from.

### `HARN-NAM-007`

**Category:** `NAM` (Naming and resolution) &nbsp;·&nbsp; **API stability:** `stable`

option key is not recognized

#### How to fix

- Define the missing name, import it, or fix the typo.
- Confirm the symbol is exported by the module you're importing from.

### `HARN-NAM-008`

**Category:** `NAM` (Naming and resolution) &nbsp;·&nbsp; **API stability:** `stable`

builtin name cannot be resolved

- **Repair:** `bindings/rename-to-closest` &nbsp;·&nbsp; **Safety:** `scope-local`
- Rename to the closest in-scope identifier

#### How to fix

- Define the missing name, import it, or fix the typo.
- Confirm the symbol is exported by the module you're importing from.

### `HARN-NAM-009`

**Category:** `NAM` (Naming and resolution) &nbsp;·&nbsp; **API stability:** `stable`

function call targets a deprecated declaration

- **Repair:** `stdlib/migrate-renamed` &nbsp;·&nbsp; **Safety:** `scope-local`
- Rename the call to the renamed stdlib symbol

#### How to fix

- Define the missing name, import it, or fix the typo.
- Confirm the symbol is exported by the module you're importing from.

### `HARN-NAM-010`

**Category:** `NAM` (Naming and resolution) &nbsp;·&nbsp; **API stability:** `stable`

declaration reference cannot be resolved

- **Repair:** `bindings/rename-to-closest` &nbsp;·&nbsp; **Safety:** `scope-local`
- Rename to the closest in-scope identifier

#### How to fix

- Define the missing name, import it, or fix the typo.
- Confirm the symbol is exported by the module you're importing from.

### `HARN-NAM-011`

**Category:** `NAM` (Naming and resolution) &nbsp;·&nbsp; **API stability:** `stable`

attribute is attached to an unsupported declaration

- **See also:** [`HARN-NAM-003`](#harn-nam-003), [`HARN-NAM-012`](#harn-nam-012)

#### How to fix

- Define the missing name, import it, or fix the typo.
- Confirm the symbol is exported by the module you're importing from.

### `HARN-NAM-012`

**Category:** `NAM` (Naming and resolution) &nbsp;·&nbsp; **API stability:** `stable`

attribute argument is invalid

- **See also:** [`HARN-NAM-003`](#harn-nam-003), [`HARN-NAM-011`](#harn-nam-011)

#### How to fix

- Define the missing name, import it, or fix the typo.
- Confirm the symbol is exported by the module you're importing from.

### `HARN-NAM-101`

**Category:** `NAM` (Naming and resolution) &nbsp;·&nbsp; **API stability:** `stable`

`main` entrypoint must take a single `harness: Harness` parameter

- **Repair:** `bindings/thread-harness-needs-param` &nbsp;·&nbsp; **Safety:** `surface-changing`
- Add a `harness: Harness` parameter where the stdio capability handle is required and update local callers

#### What it means

When a Harn program declares a top-level `fn main`, the runtime auto-invokes
it with the script's `Harness` capability handle. The convention is therefore
strict: the entrypoint must be exactly `fn main(harness: Harness) { ... }` —
or `fn main(_harness: Harness) { ... }` when the handle is intentionally
unused. It takes one parameter, named `harness` or `_harness`, typed
`Harness`, no defaults, no rest.

Any other shape (zero parameters, a renamed parameter, a missing or
non-`Harness` type annotation, extra parameters, or a default value) fails
this check before bytecode is emitted, so the runtime never tries to bind a
mismatched signature.

The `Harness` value gives the script typed access to its capability sub-handles
via field access (`harness.stdio`, `harness.term`, `harness.clock`,
`harness.fs`, `harness.env`, `harness.random`, `harness.net`,
`harness.process`, `harness.crypto`, `harness.system`, `harness.llm`).
Threading the handle through `main` replaces ambient stdio, terminal, clock,
filesystem, environment, randomness, network, process, crypto, system, and LLM
catalog globals.

#### How to fix

Rewrite the entrypoint with the canonical signature:

```harn
fn main(harness: Harness) {
  harness.stdio.println("Hello, world!")
}
```

If you do not need any capabilities — for example, a script that only does
pure computation — prefix the parameter with `_` to mark it deliberately
unused:

```harn
fn main(_harness: Harness) {
  // pure logic …
}
```

If the function does not need to be the entrypoint, rename it (e.g. `helper`,
`run_once`) so the convention does not apply.

### `HARN-CAP-001`

**Category:** `CAP` (Capabilities) &nbsp;·&nbsp; **API stability:** `stable`

capability payload is invalid

#### How to fix

- Match the capability signature documented in the Harn capability spec.
- If approval / receipt handling is required, wire it through `human_approval` or the equivalent before calling the capability.

### `HARN-CAP-002`

**Category:** `CAP` (Capabilities) &nbsp;·&nbsp; **API stability:** `stable`

human approval construct is missing policy

#### How to fix

- Match the capability signature documented in the Harn capability spec.
- If approval / receipt handling is required, wire it through `human_approval` or the equivalent before calling the capability.

### `HARN-CAP-003`

**Category:** `CAP` (Capabilities) &nbsp;·&nbsp; **API stability:** `stable`

human approval argument is invalid

argument)

#### How to fix

- Match the capability signature documented in the Harn capability spec.
- If approval / receipt handling is required, wire it through `human_approval` or the equivalent before calling the capability.

### `HARN-CAP-004`

**Category:** `CAP` (Capabilities) &nbsp;·&nbsp; **API stability:** `stable`

capability result must be checked

- **Repair:** `errors/check-or-rescue` &nbsp;·&nbsp; **Safety:** `scope-local`
- Check the result or wrap the call in a `rescue` block
- **See also:** [`HARN-RCV-001`](#harn-rcv-001), [`HARN-RCV-002`](#harn-rcv-002)

#### How to fix

- Match the capability signature documented in the Harn capability spec.
- If approval / receipt handling is required, wire it through `human_approval` or the equivalent before calling the capability.

### `HARN-CAP-005`

**Category:** `CAP` (Capabilities) &nbsp;·&nbsp; **API stability:** `stable`

host capability operation is not declared

- **See also:** [`HARN-CAP-006`](#harn-cap-006)

#### How to fix

- Match the capability signature documented in the Harn capability spec.
- If approval / receipt handling is required, wire it through `human_approval` or the equivalent before calling the capability.

### `HARN-CAP-006`

**Category:** `CAP` (Capabilities) &nbsp;·&nbsp; **API stability:** `stable`

host capability call must use a static operation name

name required)

#### How to fix

- Match the capability signature documented in the Harn capability spec.
- If approval / receipt handling is required, wire it through `human_approval` or the equivalent before calling the capability.

### `HARN-CAP-007`

**Category:** `CAP` (Capabilities) &nbsp;·&nbsp; **API stability:** `stable`

tool host capability binding is invalid

- **Repair:** `manual/review-capability-binding` &nbsp;·&nbsp; **Safety:** `needs-human`
- Review the capability binding; the fix is not mechanical

#### How to fix

- Match the capability signature documented in the Harn capability spec.
- If approval / receipt handling is required, wire it through `human_approval` or the equivalent before calling the capability.

### `HARN-CAP-201`

**Category:** `CAP` (Capabilities) &nbsp;·&nbsp; **API stability:** `stable`

harness capability denied by active sandbox profile

- **See also:** [`HARN-CAP-001`](#harn-cap-001)

#### What it means

A `harness.fs.*`, `harness.env.*`, `harness.random.*`, `harness.net.*`,
`harness.system.*`, or `harness.llm.*` method was rejected by the active
sandbox profile.
Examples:

- `harness.fs.write_text("/etc/passwd", ...)` from a script whose
  `workspace_roots` only include `./build/` — the path is outside the
  permitted set.
- `harness.net.get("https://example.com")` from a script whose egress
  allowlist does not include `example.com`.
- Any `harness.*` capability under `SandboxProfile::OsHardened` when the
  required platform mechanism is unavailable.

The runtime raises the rejection as a typed `tool_rejected` error so
the harness method surface stays narrow — every script-visible
capability tightens the same way at the same boundary, instead of each
ambient builtin growing its own bespoke deny diagnostic.

When the requested operation can be evaluated against the profile
ahead of time (literal path or URL argument, well-known method on a
sub-handle), `harn check` and `harn lint` surface the same diagnostic
at static-check time so callers don't have to actually execute the
script to discover the denial.

#### How to fix

- Widen the active sandbox profile via `CapabilityPolicy::workspace_roots`
  or the egress allowlist if the request is legitimate. The relevant
  policy lives in `~/.config/harn/policy.toml` or the per-script
  `CapabilityPolicy` overlay.
- Use `harn graph --json` to inspect which capabilities your script
  actually needs, then narrow the call site to those.
- For tests, switch from `Harness::real()` to `Harness::mock()` /
  `Harness::null()` so the call is recorded without touching the host.

### `HARN-CAP-301`

**Category:** `CAP` (Capabilities) &nbsp;·&nbsp; **API stability:** `stable`

child agent effect set exceeds the parent's declared effects

- **Repair:** `policy/narrow-child-effects` &nbsp;·&nbsp; **Safety:** `surface-changing`
- Narrow the child agent's effects to a subset of the parent's, or widen the parent's declared effects
- **See also:** [`HARN-CAP-001`](#harn-cap-001), [`HARN-CAP-007`](#harn-cap-007)

#### What it means

A spawned child agent requests typed side-effects (`harness.net.*`,
`harness.fs.*`, `llm_call`, tool dispatch, ...) that are not part of the
parent agent's declared effect set. The dispatcher (and `harn check`'s
static analyzer) enforce that a child's effect set must be a subset of
the parent's so an over-delegated child can never escape its parent's
trust boundary.

Specifically: at least one effect on the child handoff is not covered by
any effect declared on the parent. Coverage is structural:

- **Kind** must match by family (`stdio`, `fs`, `net`, `llm`, `tool`,
  `hostcall`, `persona`, `spawn`).
- **Scope** must be at least as permissive on the parent
  (`read`/`observe` ≤ `write` ≤ `mutate`).
- **Resource**, when declared on the parent, must match the child's
  exactly. A parent with no `resource` covers any child resource of the
  same kind/scope family.

This diagnostic surfaces from two paths and they are intentionally
identical:

- **Static**: `harn check` derives parent and child effect sets via the
  same capability analysis that backs `harn graph --json` and emits
  `HARN-CAP-301` when a child statically out-grants its parent.
- **Runtime**: at spawn time the dispatcher folds the parent's
  `current_execution_policy()` into an effect set, compares it against
  the child's computed effects, and refuses the spawn with a typed
  `EffectInheritanceViolation` deny event. The event payload carries the
  same `HARN-CAP-301` code and `policy/narrow-child-effects` repair id.

#### How to fix

The repair id is `policy/narrow-child-effects`. Two shapes are
typically valid:

1. **Narrow the child** — remove the over-granted calls from the child
   pipeline body, or guard them behind a capability the parent already
   declares. This is the safe default; the child stops asking for what
   it does not need.
2. **Widen the parent** — declare the missing effect on the parent
   pipeline (e.g. add a real `harness.net.get(...)` call in the parent's
   entrypoint, or extend the parent's `policy.capabilities` map). Only
   apply this when widening the parent's trust surface is itself an
   intentional design change — it touches a public surface.

Both shapes are marked `safety: surface-changing`, so `harn fix --apply
--safety surface-changing` will dispatch the chosen repair.

#### Stability

The matched `EffectInheritanceViolation` runtime payload's `_type`
discriminator (`effect_inheritance_violation`) is part of the stable
contract.

### `HARN-LLM-001`

**Category:** `LLM` (LLM calls) &nbsp;·&nbsp; **API stability:** `stable`

LLM option key is not recognized

- **See also:** [`HARN-LLM-002`](#harn-llm-002), [`HARN-LLM-004`](#harn-llm-004)

#### How to fix

- Pass a `schema:` option that validates the model output, with `schema_retries:` as appropriate.
- Drop or rename deprecated options to the names listed in the LLM call quickref.
- Pick capability flags (`tool_calling: true`, etc.) instead of branching on `provider:` identity.

### `HARN-LLM-002`

**Category:** `LLM` (LLM calls) &nbsp;·&nbsp; **API stability:** `stable`

LLM option key is deprecated

- **Repair:** `llm/migrate-deprecated-option` &nbsp;·&nbsp; **Safety:** `scope-local`
- Replace the deprecated option with its supported equivalent
- **See also:** [`HARN-LLM-001`](#harn-llm-001)

#### How to fix

- Pass a `schema:` option that validates the model output, with `schema_retries:` as appropriate.
- Drop or rename deprecated options to the names listed in the LLM call quickref.
- Pick capability flags (`tool_calling: true`, etc.) instead of branching on `provider:` identity.

### `HARN-LLM-003`

**Category:** `LLM` (LLM calls) &nbsp;·&nbsp; **API stability:** `stable`

LLM call is missing schema validation

- **Repair:** `llm/add-schema` &nbsp;·&nbsp; **Safety:** `surface-changing`
- Add a typed output schema to the LLM call
- **See also:** [`HARN-LLM-004`](#harn-llm-004), [`HARN-LLM-001`](#harn-llm-001)

#### How to fix

- Pass a `schema:` option that validates the model output, with `schema_retries:` as appropriate.
- Drop or rename deprecated options to the names listed in the LLM call quickref.
- Pick capability flags (`tool_calling: true`, etc.) instead of branching on `provider:` identity.

### `HARN-LLM-004`

**Category:** `LLM` (LLM calls) &nbsp;·&nbsp; **API stability:** `stable`

LLM schema option is invalid

- **See also:** [`HARN-LLM-003`](#harn-llm-003), [`HARN-LLM-001`](#harn-llm-001)

#### How to fix

- Pass a `schema:` option that validates the model output, with `schema_retries:` as appropriate.
- Drop or rename deprecated options to the names listed in the LLM call quickref.
- Pick capability flags (`tool_calling: true`, etc.) instead of branching on `provider:` identity.

### `HARN-LLM-005`

**Category:** `LLM` (LLM calls) &nbsp;·&nbsp; **API stability:** `stable`

prompt branches on provider identity instead of capability flags

- **Repair:** `llm/use-capability-flag` &nbsp;·&nbsp; **Safety:** `capability-changing`
- Branch on a capability flag instead of provider identity
- **See also:** [`HARN-PRM-004`](#harn-prm-004)

#### How to fix

- Pass a `schema:` option that validates the model output, with `schema_retries:` as appropriate.
- Drop or rename deprecated options to the names listed in the LLM call quickref.
- Pick capability flags (`tool_calling: true`, etc.) instead of branching on `provider:` identity.

### `HARN-ORC-001`

**Category:** `ORC` (Orchestration constructs) &nbsp;·&nbsp; **API stability:** `stable`

orchestration construct has invalid arity

#### What it means

An orchestration construct — agent / workflow / pipeline / tool definition, or a
`select` block — does not satisfy the structural rules Harn enforces. These
constructs carry runtime semantics that depend on a small set of well-formed
shapes.

#### How to fix

- Re-read the orchestration construct's spec section and align the arity / type / structure.

### `HARN-ORC-002`

**Category:** `ORC` (Orchestration constructs) &nbsp;·&nbsp; **API stability:** `stable`

orchestration construct argument has invalid type

#### What it means

An orchestration construct — agent / workflow / pipeline / tool definition, or a
`select` block — does not satisfy the structural rules Harn enforces. These
constructs carry runtime semantics that depend on a small set of well-formed
shapes.

#### How to fix

- Re-read the orchestration construct's spec section and align the arity / type / structure.

### `HARN-ORC-003`

**Category:** `ORC` (Orchestration constructs) &nbsp;·&nbsp; **API stability:** `stable`

agent declaration is invalid

#### What it means

An orchestration construct — agent / workflow / pipeline / tool definition, or a
`select` block — does not satisfy the structural rules Harn enforces. These
constructs carry runtime semantics that depend on a small set of well-formed
shapes.

#### How to fix

- Re-read the orchestration construct's spec section and align the arity / type / structure.

### `HARN-ORC-004`

**Category:** `ORC` (Orchestration constructs) &nbsp;·&nbsp; **API stability:** `stable`

workflow declaration is invalid

#### What it means

An orchestration construct — agent / workflow / pipeline / tool definition, or a
`select` block — does not satisfy the structural rules Harn enforces. These
constructs carry runtime semantics that depend on a small set of well-formed
shapes.

#### How to fix

- Re-read the orchestration construct's spec section and align the arity / type / structure.

### `HARN-ORC-005`

**Category:** `ORC` (Orchestration constructs) &nbsp;·&nbsp; **API stability:** `stable`

tool declaration is invalid

#### What it means

An orchestration construct — agent / workflow / pipeline / tool definition, or a
`select` block — does not satisfy the structural rules Harn enforces. These
constructs carry runtime semantics that depend on a small set of well-formed
shapes.

#### How to fix

- Re-read the orchestration construct's spec section and align the arity / type / structure.

### `HARN-ORC-006`

**Category:** `ORC` (Orchestration constructs) &nbsp;·&nbsp; **API stability:** `stable`

pipeline declaration is invalid

#### What it means

An orchestration construct — agent / workflow / pipeline / tool definition, or a
`select` block — does not satisfy the structural rules Harn enforces. These
constructs carry runtime semantics that depend on a small set of well-formed
shapes.

#### How to fix

- Re-read the orchestration construct's spec section and align the arity / type / structure.

### `HARN-ORC-007`

**Category:** `ORC` (Orchestration constructs) &nbsp;·&nbsp; **API stability:** `stable`

select construct is invalid

#### What it means

An orchestration construct — agent / workflow / pipeline / tool definition, or a
`select` block — does not satisfy the structural rules Harn enforces. These
constructs carry runtime semantics that depend on a small set of well-formed
shapes.

#### How to fix

- Re-read the orchestration construct's spec section and align the arity / type / structure.

### `HARN-ORC-008`

**Category:** `ORC` (Orchestration constructs) &nbsp;·&nbsp; **API stability:** `stable`

statement cannot be reached

- **Repair:** `control-flow/remove-dead` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Remove the unreachable code

#### What it means

An orchestration construct — agent / workflow / pipeline / tool definition, or a
`select` block — does not satisfy the structural rules Harn enforces. These
constructs carry runtime semantics that depend on a small set of well-formed
shapes.

#### How to fix

- Re-read the orchestration construct's spec section and align the arity / type / structure.

### `HARN-ORC-009`

**Category:** `ORC` (Orchestration constructs) &nbsp;·&nbsp; **API stability:** `stable`

Flow invariant attribute set is invalid

invalid)

#### What it means

An orchestration construct — agent / workflow / pipeline / tool definition, or a
`select` block — does not satisfy the structural rules Harn enforces. These
constructs carry runtime semantics that depend on a small set of well-formed
shapes.

#### How to fix

- Re-read the orchestration construct's spec section and align the arity / type / structure.

### `HARN-ORC-010`

**Category:** `ORC` (Orchestration constructs) &nbsp;·&nbsp; **API stability:** `stable`

execution target path cannot be found

#### What it means

An orchestration construct — agent / workflow / pipeline / tool definition, or a
`select` block — does not satisfy the structural rules Harn enforces. These
constructs carry runtime semantics that depend on a small set of well-formed
shapes.

#### How to fix

- Re-read the orchestration construct's spec section and align the arity / type / structure.

### `HARN-ORC-011`

**Category:** `ORC` (Orchestration constructs) &nbsp;·&nbsp; **API stability:** `stable`

a self-deadlock acquire would block forever

#### What it means

The VM detected an acquire that can never succeed and would otherwise block
forever, so it surfaced an error instead of hanging. Two deterministic,
provably-unresolvable cases are caught:

- **Re-entrant mutex.** A lexical `mutex { ... }` block acquires a
  non-reentrant, capacity-1 lock. Entering a second `mutex` block on the same
  key while the first is still held — directly or through a called function —
  can never be granted, because the sole permit holder is the task that is now
  waiting on it.
- **Self-join.** A task `await`s its own join handle. The handle only resolves
  when the task finishes, so waiting on it from inside the task itself can
  never complete.

Harn's static checks (like Rust's borrow checker) prevent data races but not
deadlocks; this runtime guard is the analogue of the Go runtime's
"all goroutines are asleep — deadlock!" detection for the cases that are
provable with no false positives.

#### How to fix

- Do not nest `mutex { ... }` blocks that resolve to the same lock, and avoid
  calling a function that opens a `mutex` block from inside another one.
  Restructure so the lock is released before it is acquired again, or hold a
  single lock around the whole critical section.
- Never `await` the handle of the current task. Await it from the task that
  spawned it instead.

This error is non-retryable: it indicates a structural concurrency bug, not a
transient failure.

### `HARN-ORC-012`

**Category:** `ORC` (Orchestration constructs) &nbsp;·&nbsp; **API stability:** `stable`

a wait-for graph cycle would block forever

#### What it means

The VM detected that every active task in the current execution tree is waiting,
and the outstanding channel operations cannot match a sender with a receiver.
Without this guard the run would block forever.

This check only fires when the runtime can prove the wait is closed-world:
running tasks, sleeping tasks, time-bounded selects, and `deadline { ... }`
scopes keep the guard from reporting a deadlock.

#### How to fix

Make sure every blocking `receive` has a task that can still send to that
channel, and every blocking `send` on a full channel has a task that can still
receive from it. If the wait is intentionally optional, use `try_receive`,
`select timeout`, `channel_select(..., timeout_ms)`, or wrap the operation in a
`deadline { ... }` block.

This error is non-retryable: it indicates a structural concurrency bug, not a
transient failure.

### `HARN-STD-001`

**Category:** `STD` (Stdlib usage) &nbsp;·&nbsp; **API stability:** `stable`

stdlib symbol has been renamed or deprecated

- **Repair:** `stdlib/migrate-renamed` &nbsp;·&nbsp; **Safety:** `scope-local`
- Rename the call to the renamed stdlib symbol

#### What it means

A stdlib symbol is being used in a way Harn does not support, or has been
renamed / deprecated since the script was written. The stdlib is the live source
of truth for what's available.

#### How to fix

- Switch to the supported / renamed stdlib API listed in the diagnostic help text.

### `HARN-STD-002`

**Category:** `STD` (Stdlib usage) &nbsp;·&nbsp; **API stability:** `stable`

stdlib call is invalid

#### What it means

A stdlib symbol is being used in a way Harn does not support, or has been
renamed / deprecated since the script was written. The stdlib is the live source
of truth for what's available.

#### How to fix

- Switch to the supported / renamed stdlib API listed in the diagnostic help text.

### `HARN-STD-003`

**Category:** `STD` (Stdlib usage) &nbsp;·&nbsp; **API stability:** `stable`

builtin call has invalid arity

#### What it means

A stdlib symbol is being used in a way Harn does not support, or has been
renamed / deprecated since the script was written. The stdlib is the live source
of truth for what's available.

#### How to fix

- Switch to the supported / renamed stdlib API listed in the diagnostic help text.

### `HARN-STD-101`

**Category:** `STD` (Stdlib usage) &nbsp;·&nbsp; **API stability:** `stable`

public stdlib function is missing declared metadata

- **Repair:** `doc/add-stdlib-metadata` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Add `@effects` and `@errors` fields to the stdlib function's doc block

#### What it means

Every public stdlib function ships with a prose summary plus two
machine-meaningful metadata fields above its `pub fn` declaration so that
`harn graph --json`, the LSP hover, generated docs, and downstream agents
can read a single source of truth for the function's runtime contract.

The required fields are:

| Field      | Purpose                                                                                           |
|------------|---------------------------------------------------------------------------------------------------|
| `@effects` | Capabilities the function may touch (e.g. `fs.read`, `stdio.write`, `llm.call`). `[]` means pure. |
| `@errors`  | Error variants the function may surface. `[]` means infallible.                                   |

Two more fields are recognized but optional:

| Field            | Purpose                                                                       |
|------------------|--------------------------------------------------------------------------------|
| `@api_stability` | Stability promise (`experimental`, `internal`, `deprecated`). Absent ⇒ stable. |
| `@example`       | Hand-written usage example. Absent ⇒ tooling derives one from the signature.   |

Only write an `@example` when it shows something the type signature cannot
(non-obvious argument shapes, a multi-step idiom). LSP hover and
`harn graph --json` synthesize a signature-derived example otherwise.

The lint warns when a `pub fn` declared inside an embedded stdlib module
(`crates/harn-stdlib/src/stdlib/**/*.harn`) is missing a required field
from the `/** ... */` HarnDoc block immediately above it.

#### How to fix

Add the missing fields to the function's HarnDoc block:

```harn,ignore
/**
 * Render the project README.
 *
 * @effects: [fs.read, fs.write]
 * @errors: [FileNotFound, PermissionDenied]
 */
pub fn render_readme(path: string) -> Result<string, FsError> { ... }
```

The lint considers `@effects: []` and `@errors: []` valid declarations — they
explicitly assert "no effects" and "infallible" respectively, which is what
agents need to read out of the graph.

### `HARN-PRM-001`

**Category:** `PRM` (Prompt templates) &nbsp;·&nbsp; **API stability:** `stable`

prompt template cannot be parsed

- **See also:** [`HARN-PRM-007`](#harn-prm-007)

#### What it means

A prompt template (`.harn.prompt` / `.prompt`) failed validation, either because
the template body is malformed or because it references the model surface in a
way that violates Harn's prompt safety rules.

#### How to fix

- Fix the template syntax (`{{ }}`, `{% %}` are the only structural delimiters).
- Replace identity-based branching with capability flags from the LLM call options.

### `HARN-PRM-002`

**Category:** `PRM` (Prompt templates) &nbsp;·&nbsp; **API stability:** `stable`

prompt template has too many capability-aware branches

- **Repair:** `manual/needs-human` &nbsp;·&nbsp; **Safety:** `needs-human`
- Plan a human-led change; auto-apply is not safe here
- **See also:** [`HARN-LNT-044`](#harn-lnt-044)

#### What it means

A prompt template (`.harn.prompt` / `.prompt`) failed validation, either because
the template body is malformed or because it references the model surface in a
way that violates Harn's prompt safety rules.

#### How to fix

- Fix the template syntax (`{{ }}`, `{% %}` are the only structural delimiters).
- Replace identity-based branching with capability flags from the LLM call options.

### `HARN-PRM-003`

**Category:** `PRM` (Prompt templates) &nbsp;·&nbsp; **API stability:** `stable`

prompt construction risks direct injection

- **Repair:** `prompts/escape-injection` &nbsp;·&nbsp; **Safety:** `scope-local`
- Pass the untrusted input through a structured placeholder
- **See also:** [`HARN-LNT-026`](#harn-lnt-026)

#### What it means

A prompt template (`.harn.prompt` / `.prompt`) failed validation, either because
the template body is malformed or because it references the model surface in a
way that violates Harn's prompt safety rules.

#### How to fix

- Fix the template syntax (`{{ }}`, `{% %}` are the only structural delimiters).
- Replace identity-based branching with capability flags from the LLM call options.

### `HARN-PRM-004`

**Category:** `PRM` (Prompt templates) &nbsp;·&nbsp; **API stability:** `stable`

prompt template branches on provider identity

- **Repair:** `llm/use-capability-flag` &nbsp;·&nbsp; **Safety:** `capability-changing`
- Branch on a capability flag instead of provider identity
- **See also:** [`HARN-LLM-005`](#harn-llm-005), [`HARN-LNT-046`](#harn-lnt-046)

branch)

#### What it means

A prompt template (`.harn.prompt` / `.prompt`) failed validation, either because
the template body is malformed or because it references the model surface in a
way that violates Harn's prompt safety rules.

#### How to fix

- Fix the template syntax (`{{ }}`, `{% %}` are the only structural delimiters).
- Replace identity-based branching with capability flags from the LLM call options.

### `HARN-PRM-005`

**Category:** `PRM` (Prompt templates) &nbsp;·&nbsp; **API stability:** `stable`

prompt references a tool outside the declared surface

- **Repair:** `prompts/add-tool-to-surface` &nbsp;·&nbsp; **Safety:** `surface-changing`
- Add the referenced tool to the declared tool surface

#### What it means

A prompt template (`.harn.prompt` / `.prompt`) failed validation, either because
the template body is malformed or because it references the model surface in a
way that violates Harn's prompt safety rules.

#### How to fix

- Fix the template syntax (`{{ }}`, `{% %}` are the only structural delimiters).
- Replace identity-based branching with capability flags from the LLM call options.

### `HARN-PRM-006`

**Category:** `PRM` (Prompt templates) &nbsp;·&nbsp; **API stability:** `stable`

prompt references a deferred tool without tool search

- **Repair:** `prompts/add-tool-to-surface` &nbsp;·&nbsp; **Safety:** `surface-changing`
- Add the referenced tool to the declared tool surface

deferred reference)

#### What it means

A prompt template (`.harn.prompt` / `.prompt`) failed validation, either because
the template body is malformed or because it references the model surface in a
way that violates Harn's prompt safety rules.

#### How to fix

- Fix the template syntax (`{{ }}`, `{% %}` are the only structural delimiters).
- Replace identity-based branching with capability flags from the LLM call options.

### `HARN-PRM-007`

**Category:** `PRM` (Prompt templates) &nbsp;·&nbsp; **API stability:** `stable`

prompt or template target cannot be found

#### What it means

A prompt template (`.harn.prompt` / `.prompt`) failed validation, either because
the template body is malformed or because it references the model surface in a
way that violates Harn's prompt safety rules.

#### How to fix

- Fix the template syntax (`{{ }}`, `{% %}` are the only structural delimiters).
- Replace identity-based branching with capability flags from the LLM call options.

### `HARN-MOD-001`

**Category:** `MOD` (Modules and exports) &nbsp;·&nbsp; **API stability:** `stable`

module import cannot be resolved

- **Repair:** `imports/fix-path` &nbsp;·&nbsp; **Safety:** `scope-local`
- Replace the import path with a resolvable target
- **See also:** [`HARN-IMP-001`](#harn-imp-001), [`HARN-IMP-002`](#harn-imp-002)

#### What it means

A module-level import declaration cannot be satisfied or has been authored in a
non-canonical form. The module graph must resolve cleanly before any further
checks.

#### How to fix

- Confirm the import path resolves on disk and the imported symbol is exported.
- Run `harn lint --fix` to auto-sort / dedupe import groups.

### `HARN-MOD-002`

**Category:** `MOD` (Modules and exports) &nbsp;·&nbsp; **API stability:** `stable`

module import is unused

- **Repair:** `imports/remove-unused` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Remove the unused import
- **See also:** [`HARN-LNT-017`](#harn-lnt-017)

#### What it means

A module-level import declaration cannot be satisfied or has been authored in a
non-canonical form. The module graph must resolve cleanly before any further
checks.

#### How to fix

- Confirm the import path resolves on disk and the imported symbol is exported.
- Run `harn lint --fix` to auto-sort / dedupe import groups.

### `HARN-MOD-003`

**Category:** `MOD` (Modules and exports) &nbsp;·&nbsp; **API stability:** `stable`

module imports are not in canonical order

- **Repair:** `imports/reorder` &nbsp;·&nbsp; **Safety:** `format-only`
- Reorder imports into canonical grouping

#### What it means

A module-level import declaration cannot be satisfied or has been authored in a
non-canonical form. The module graph must resolve cleanly before any further
checks.

#### How to fix

- Confirm the import path resolves on disk and the imported symbol is exported.
- Run `harn lint --fix` to auto-sort / dedupe import groups.

### `HARN-MOD-004`

**Category:** `MOD` (Modules and exports) &nbsp;·&nbsp; **API stability:** `stable`

module export is invalid

#### What it means

A module-level import declaration cannot be satisfied or has been authored in a
non-canonical form. The module graph must resolve cleanly before any further
checks.

#### How to fix

- Confirm the import path resolves on disk and the imported symbol is exported.
- Run `harn lint --fix` to auto-sort / dedupe import groups.

### `HARN-MOD-005`

**Category:** `MOD` (Modules and exports) &nbsp;·&nbsp; **API stability:** `stable`

module imports expose colliding names

#### What it means

A module-level import declaration cannot be satisfied or has been authored in a
non-canonical form. The module graph must resolve cleanly before any further
checks.

#### How to fix

- Confirm the import path resolves on disk and the imported symbol is exported.
- Run `harn lint --fix` to auto-sort / dedupe import groups.

### `HARN-MOD-006`

**Category:** `MOD` (Modules and exports) &nbsp;·&nbsp; **API stability:** `stable`

module re-exports conflict

#### What it means

A module-level import declaration cannot be satisfied or has been authored in a
non-canonical form. The module graph must resolve cleanly before any further
checks.

#### How to fix

- Confirm the import path resolves on disk and the imported symbol is exported.
- Run `harn lint --fix` to auto-sort / dedupe import groups.

### `HARN-RMD-001`

**Category:** `RMD` (Reminder lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

reminder lifecycle option key is not recognized

- **See also:** [`HARN-RMD-002`](#harn-rmd-002), [`HARN-RMD-005`](#harn-rmd-005)

Reminder lifecycle option tables reject unknown keys so reminder shape stays stable across
transcript transforms, hooks, and bridge integrations.

Use only the documented `transcript.inject_reminder` keys: `body`, `tags`, `dedupe_key`,
`ttl_turns`, `preserve_on_compact`, `propagate`, and `role_hint`.

For `transcript.clear_reminders`, use at least one selector from `id`, `tag`, or `dedupe_key`.

### `HARN-RMD-002`

**Category:** `RMD` (Reminder lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

reminder payload shape is invalid

- **See also:** [`HARN-RMD-001`](#harn-rmd-001), [`HARN-RMD-005`](#harn-rmd-005)

The reminder payload shape is invalid.

`session/remind` expects a typed reminder object, not a user-message payload.
Provide a non-empty `body`, use string `tags`, a positive integer `ttl_turns`
when present, boolean `preserve_on_compact`, and one of the documented
`propagate` and `role_hint` values. Put host-specific extension fields under
`_meta`.

### `HARN-RMD-003`

**Category:** `RMD` (Reminder lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

user_block reminder role hint is not supported by the selected provider

The pipeline hardcodes `role_hint: "user_block"` while also selecting an LLM
provider/model route that cannot render reminders as Anthropic-style user
content blocks or OpenAI developer-role messages.

Use `role_hint: "system"` or `role_hint: "developer"` for provider-neutral
reminders, or branch on provider capability flags before selecting a
provider-specific reminder shape.

### `HARN-RMD-004`

**Category:** `RMD` (Reminder lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

discardable reminder has no TTL

A reminder literal sets `preserve_on_compact: false` while leaving
`ttl_turns` unset or `nil`. That reminder can live forever during normal
turns, but it is allowed to disappear at the next transcript compaction.

Set a finite `ttl_turns` for short-lived nudges, or set
`preserve_on_compact: true` when the reminder must survive compaction.

### `HARN-RMD-005`

**Category:** `RMD` (Reminder lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

reminder propagate value is not recognized

- **See also:** [`HARN-RMD-001`](#harn-rmd-001), [`HARN-RMD-002`](#harn-rmd-002)

A reminder specified an unsupported `propagate` value. Reminder propagation must
be one of `all`, `session`, or `none`.

Use `all` for reminders that should follow child agents, `session` for the
current session only, and `none` for reminders that should never propagate.

Example fix:

```harn
transcript.inject_reminder(transcript(), {
  body: "Check the task ledger before continuing.",
  propagate: "session",
})
```

### `HARN-RMD-006`

**Category:** `RMD` (Reminder lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

reminder provider returned a malformed reminder spec

- **See also:** [`HARN-RMD-002`](#harn-rmd-002)

A reminder provider closure returned a value that could not be parsed as a
`ReminderSpec`. Provider closures may return `nil`, a reminder spec, an effect
such as `{reminder: {...}}`, or a list of those effects.

Return a dict with a non-empty `body` and only supported reminder fields.

Example fix:

```harn
register_reminder_provider({
  id: "custom",
  subscribes_to: ["session_idle"],
  evaluate: { _ctx ->
    return {reminder: {body: "Re-check current session state.", ttl_turns: 1}}
  },
})
```

### `HARN-RMD-007`

**Category:** `RMD` (Reminder lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

too many reminder providers are enabled

- **See also:** [`HARN-RMD-004`](#harn-rmd-004)

An `agent_loop` enables more than eight distinct reminder providers. Many
providers can inject overlapping ambient context and increase prompt size.

Disable providers that are not useful for the loop, or split the loop into
smaller stages with different reminder settings.

Example fix:

```harn
agent_loop(task, nil, {
  reminders: {providers: ["token_pressure", "idle_nudge"]},
})
```

### `HARN-RMD-008`

**Category:** `RMD` (Reminder lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

hook event does not support reminder effects

- **See also:** [`HARN-RMD-006`](#harn-rmd-006)

A hook handler returned a reminder effect from a lifecycle event that cannot
inject reminders. Worker lifecycle events are observational and must not mutate
the active transcript with reminder effects.

Move the reminder to a session, tool, step, or persona hook that runs at a
turn-boundary mutation point.

Example fix:

```harn
register_session_hook("post_turn", { _event ->
  return {reminder: {body: "Review worker progress before continuing."}}
})
```

### `HARN-SUS-001`

**Category:** `SUS` (Suspend / resume lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

suspend_agent target worker is not running

- **See also:** [`HARN-SUS-003`](#harn-sus-003), [`HARN-SUS-010`](#harn-sus-010)

`suspend_agent(...)` can only create a new cooperative suspension for a
running worker. A worker that is awaiting input, completed, failed, cancelled,
or interrupted no longer has a running turn boundary where a suspend checkpoint
can be installed.

Use the worker summary status to branch before suspending. For terminal workers,
spawn a fresh worker instead. Calling `suspend_agent(...)` again on an already
suspended worker remains an idempotent summary read.

### `HARN-SUS-002`

**Category:** `SUS` (Suspend / resume lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

ResumeConditions validation failed

- **See also:** [`HARN-SUS-007`](#harn-sus-007), [`HARN-SUS-008`](#harn-sus-008)

`ResumeConditions` did not match the supported shape for a suspended agent.
The object may contain `trigger`, `timeout`, and `on_event`. Trigger entries
must parse as trigger specs, timeout entries need a positive
`duration_minutes`, and event entries must be valid runtime event topics.

Validate untrusted condition tables with `parse_resume_conditions(...)` or
`agent_await_resumption(...)` before passing them to `suspend_agent(...)`.

### `HARN-SUS-003`

**Category:** `SUS` (Suspend / resume lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

resume_agent target worker is not suspended

- **See also:** [`HARN-SUS-001`](#harn-sus-001), [`HARN-SUS-006`](#harn-sus-006)

`resume_agent(...)` was called on a live worker that is not currently in the
`suspended` state. Warm resume is only meaningful for workers with an active
suspension envelope.

Check the worker summary before resuming. Use `send_input(...)` for workers
that are awaiting input, inspect terminal summaries directly, or load a
snapshot path when you only need to restore persisted state.

### `HARN-SUS-004`

**Category:** `SUS` (Suspend / resume lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

resume snapshot cannot be loaded or used

- **See also:** [`HARN-SUS-003`](#harn-sus-003)

`resume_agent(...)` could not load the requested snapshot, or the snapshot was
not usable as a worker state. The path may be missing, stale, unreadable, or
from an incompatible worker-state format.

Use the `snapshot_path` from the latest worker summary and keep the worker
state directory available across process restarts. If the snapshot belongs to
an older incompatible runtime, spawn a replacement worker instead of resuming.

### `HARN-SUS-005`

**Category:** `SUS` (Suspend / resume lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

agent_await_resumption was invoked outside agent_loop structural handling

- **See also:** [`HARN-SUS-002`](#harn-sus-002)

The model-facing `agent_await_resumption` tool is structural. `agent_loop`
intercepts that tool call, records audit metadata, and turns it into a
suspend checkpoint. Invoking the tool handler directly bypasses that control
flow, so Harn rejects it.

Call `agent_await_resumption(reason, conditions?)` only to build or normalize
the request shape, or let an `agent_loop` turn handle the lifecycle tool call.

### `HARN-SUS-006`

**Category:** `SUS` (Suspend / resume lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

concurrent resume changed the worker before resume could complete

- **See also:** [`HARN-SUS-003`](#harn-sus-003), [`HARN-SUS-010`](#harn-sus-010)

A resume operation started while the worker looked suspended, but another
operator, trigger, or timeout changed the worker state before the resume could
finish. Harn rejects the later resume so callers do not accidentally treat a
race as a successful wake-up.

Refresh the worker summary and retry only if the worker is still suspended.
For trigger-driven resumes, ensure only one trigger or timeout path remains
armed for the suspension.

### `HARN-SUS-007`

**Category:** `SUS` (Suspend / resume lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

ResumeConditions trigger could not be registered

- **See also:** [`HARN-SUS-002`](#harn-sus-002), [`HARN-SUS-008`](#harn-sus-008)

The `conditions.trigger` entry was valid enough to request an auto-resume
binding, but Harn could not register or resolve the trigger in the live
dispatcher registry.

Check the trigger kind, event matchers, and registry availability. Prefer
normalizing the full `ResumeConditions` table before suspension so shape
errors surface as `HARN-SUS-002`.

### `HARN-SUS-008`

**Category:** `SUS` (Suspend / resume lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

resume timeout action is unsupported

- **See also:** [`HARN-SUS-002`](#harn-sus-002), [`HARN-SUS-007`](#harn-sus-007)

An auto-resume timeout used an `on_timeout` action Harn does not implement.
Supported actions are `resume_with_summary`, `resume_with_input`, and `fail`.

Use `parse_resume_conditions(...)` to normalize timeout settings before
suspending, or update the timeout table to one of the supported actions.

### `HARN-SUS-009`

**Category:** `SUS` (Suspend / resume lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

resume input failed agent_loop input validation

- **See also:** [`HARN-SUS-003`](#harn-sus-003)

`resume_agent(...)` received resume input that could not be converted into a
non-empty task prompt for the resumed agent loop.

Pass `nil` when resuming without new input, or pass a non-empty string or value
whose string form is suitable as the next task prompt.

### `HARN-SUS-010`

**Category:** `SUS` (Suspend / resume lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

closed suspended worker cannot be resumed

- **See also:** [`HARN-SUS-003`](#harn-sus-003), [`HARN-SUS-006`](#harn-sus-006)

The target worker was closed or cancelled after being suspended. Closing a
worker removes the suspension envelope and rejects future resume attempts
against that live worker handle.

Treat the worker as terminal. Spawn a new worker, or restore an explicit
snapshot path only when you intentionally want to inspect persisted state.

### `HARN-SUS-011`

**Category:** `SUS` (Suspend / resume lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

replay resume input hash diverges from journaled suspension

The replay runtime computed a different resume-input fingerprint than the
one captured in the original run's [`ResumptionReceipt`]. Lifecycle replay
must be deterministic: the second run must feed the suspended worker the
exact same payload it received the first time, because the worker's
post-resume trajectory was hashed into the journaled state.

Common causes:

- A pipeline that used to depend on wall-clock time or another
  non-deterministic input now produces a different resume payload on
  replay. Capture the payload itself (or use `mock_time(...)`) so the
  replayed runtime can reproduce the original value.
- The journal entry was edited after the original run completed. The
  signed timestamp on the receipt detects this — verify the receipt's
  signature with `verify_lifecycle_receipt_signature(...)` before
  blaming the runtime.
- The settlement agent (drain phase) changed its mind and produced a
  different resume input. Record a fresh `ResumptionReceipt` in the
  current run instead of replaying the stale one.

If the new payload is intentionally different (eg. you are running a
deliberate counterfactual, not a determinism replay), open the trace as
a fresh recording rather than feeding it back through the replay oracle.

### `HARN-SUS-012`

**Category:** `SUS` (Suspend / resume lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

replay drain decision prompt hash diverges from journaled receipt

The replay runtime tried to memoize a settlement-agent drain decision
against a [`DrainDecisionReceipt`] whose `prompt_hash` does not match the
candidate prompt the second run computed. Drain decisions are journaled
so that replay can skip the settlement agent's LLM call — but if the
prompt drifts, the recorded `action` no longer reflects what the agent
would actually decide.

Common causes:

- The pipeline's settlement-agent prompt template or its inputs (the
  unsettled-state snapshot, the budget summary, the worker list) changed
  between record and replay. Either re-record the trace or roll the
  template back to its recorded form.
- The drain item set itself changed shape (eg. a new suspended subagent
  appeared on replay). Fix the upstream determinism gap first, then the
  drain receipt will line up.

The recorded receipt is still safe to inspect via
`lifecycle_receipts_snapshot()`, and its signed timestamp tells you
when the original decision was minted. Treat the mismatch as a signal
that the replay is no longer a determinism check.

### `HARN-SUS-013`

**Category:** `SUS` (Suspend / resume lifecycle) &nbsp;·&nbsp; **API stability:** `stable`

lifecycle receipt signed timestamp failed verification

A [`SuspensionReceipt`], [`ResumptionReceipt`], or [`DrainDecisionReceipt`]
carries a `SignedLifecycleTimestamp` whose HMAC signature does not match
the receipt's identifying fields under the per-process signing salt.

The signature binds `(kind, at_ms, subject_id, initiator_id)`, so any of
the following will trip this diagnostic:

- The receipt was minted by a *different* `harn` process and is now
  being verified after a restart. Per-process salts are intentional —
  cross-process verification requires migrating to the longer-lived
  `provenance` chain (see `build_signed_receipt`).
- The journal entry was edited after the fact (eg. someone hand-tweaked
  `at_ms` or `initiator_id` in the on-disk record). The replay oracle
  rejects the tampered receipt before relying on it.
- The signing algorithm or key id changed across a Harn upgrade. The
  current algorithm is `hmac-sha256` with key id `local-session`.

If the original process is gone but you still need to read the
receipts, treat the on-disk payloads as advisory only — the unsigned
fields (`handle`, `reason`, `input_hash`, `action`) are still
informational, but `replay_resume_input` / `replay_drain_decision` will
refuse to memoize against an unverified receipt.

### `HARN-LNT-001`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

renamed stdlib symbol lint

- **Repair:** `stdlib/migrate-renamed` &nbsp;·&nbsp; **Safety:** `scope-local`
- Rename the call to the renamed stdlib symbol
- **See also:** [`HARN-STD-001`](#harn-std-001)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-002`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

cyclomatic complexity lint

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-003`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

naming convention lint

- **Repair:** `style/rename-to-convention` &nbsp;·&nbsp; **Safety:** `surface-changing`
- Rename to match the casing convention for this kind

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-004`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

eager collection conversion lint

- **Repair:** `collections/prefer-lazy` &nbsp;·&nbsp; **Safety:** `scope-local`
- Replace the eager collection step with a lazy variant

conversion)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-005`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

redundant clone lint

- **Repair:** `clones/remove-redundant` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Remove the redundant clone

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-006`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

long-running workflow cleanup lint

- **Repair:** `manual/needs-human` &nbsp;·&nbsp; **Safety:** `needs-human`
- Plan a human-led change; auto-apply is not safe here

cleanup)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-007`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

MCP tool annotations lint

- **Repair:** `manual/needs-human` &nbsp;·&nbsp; **Safety:** `needs-human`
- Plan a human-led change; auto-apply is not safe here

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-008`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

PR open without secret scan lint

scan)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-009`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

shadow variable lint

- **Repair:** `bindings/rename-shadow` &nbsp;·&nbsp; **Safety:** `scope-local`
- Rename the shadowing binding to a distinct name

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-010`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

persona hook target lint

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-011`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

dead code after return lint

- **Repair:** `control-flow/remove-dead` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Remove the unreachable code

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-012`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

let then return lint

- **Repair:** `control-flow/flatten` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Flatten the unnecessary control flow construct

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-013`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

unhandled approval result lint

- **Repair:** `errors/check-or-rescue` &nbsp;·&nbsp; **Safety:** `scope-local`
- Check the result or wrap the call in a `rescue` block

result)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-014`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

unused variable lint

- **Repair:** `bindings/rename-unused` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Prefix the unused binding with `_` to silence the lint

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-015`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

unused pattern binding lint

- **Repair:** `bindings/rename-unused` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Prefix the unused binding with `_` to silence the lint

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-016`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

unused parameter lint

- **Repair:** `bindings/rename-unused` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Prefix the unused binding with `_` to silence the lint

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-017`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

unused import lint

- **Repair:** `imports/remove-unused` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Remove the unused import
- **See also:** [`HARN-MOD-002`](#harn-mod-002)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-018`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

mutable never reassigned lint

- **Repair:** `bindings/make-immutable` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Drop `mut` since the binding is never reassigned
- **See also:** [`HARN-OWN-002`](#harn-own-002)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-019`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

unused function lint

- **Repair:** `declarations/remove-unused` &nbsp;·&nbsp; **Safety:** `surface-changing`
- Remove the unused declaration

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-020`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

unused type lint

- **Repair:** `declarations/remove-unused` &nbsp;·&nbsp; **Safety:** `surface-changing`
- Remove the unused declaration

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-021`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

persona body must call steps lint

steps)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-022`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

undefined function lint

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-023`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

pipeline return type lint

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-024`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

missing harndoc lint

- **Repair:** `doc/add-harndoc` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Add a `///` doc comment describing this declaration

#### What it means

A public function has no `/** */` HarnDoc block above its declaration.

This rule is **opt-in**: it only runs when the nearest `harn.toml` sets

```toml
[lint]
require_docstrings = true
```

Out of the box, public functions in user scripts and pipelines need no
doc comments. Embedded stdlib sources always enforce docstrings (the
HARN-STD-101 metadata lint relies on the doc block existing).

#### How to fix

- Add a `/** ... */` block with a one-line prose summary above the
  declaration. No structured tags are required; LSP hover derives a usage
  example from the type signature.
- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Or leave `require_docstrings` unset if the project doesn't want the
  requirement.

### `HARN-LNT-025`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

assert outside test lint

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-026`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

prompt injection risk lint

- **Repair:** `prompts/escape-injection` &nbsp;·&nbsp; **Safety:** `scope-local`
- Pass the untrusted input through a structured placeholder
- **See also:** [`HARN-PRM-003`](#harn-prm-003)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-027`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

connector effect policy lint

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-028`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

unnecessary cast lint

- **Repair:** `casts/remove-redundant` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Remove the redundant cast

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-029`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

untyped dict access lint

- **Repair:** `types/add-shape-annotation` &nbsp;·&nbsp; **Safety:** `surface-changing`
- Annotate the dict with a concrete shape type

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-030`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

constant logical operand lint

- **Repair:** `expressions/simplify` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Simplify the expression to its canonical form

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-031`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

pointless comparison lint

- **Repair:** `expressions/simplify` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Simplify the expression to its canonical form

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

#### NaN caveat

A self-comparison such as `x == x` or `x != x` is **not** constant when `x` is a
NaN float: `x == x` is `false` and `x != x` is `true` for NaN (and the same
holds element-wise for lists/dicts containing a NaN). The lint therefore only
offers an auto-fix when the operand provably cannot be NaN (a non-float literal,
or a list/dict built only from such literals). When the operand could be a float
the lint still warns — a self-comparison is usually a typo — but leaves the code
untouched and points you at `is_nan(...)`, the idiomatic NaN test.

### `HARN-LNT-032`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

comparison to bool lint

- **Repair:** `expressions/simplify` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Simplify the expression to its canonical form

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-033`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

invalid binary operator literal lint

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-034`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

redundant nil ternary lint

- **Repair:** `expressions/simplify` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Simplify the expression to its canonical form

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-035`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

empty block lint

- **Repair:** `blocks/remove-empty` &nbsp;·&nbsp; **Safety:** `scope-local`
- Remove the empty block or fill in an explicit body

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-036`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

unnecessary else return lint

- **Repair:** `control-flow/flatten` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Flatten the unnecessary control flow construct

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-037`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

duplicate match arm lint

- **Repair:** `match/remove-duplicate-arm` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Remove the duplicated match arm
- **See also:** [`HARN-MAT-002`](#harn-mat-002)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-038`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

require in test lint

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-039`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

break outside loop lint

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-040`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

template parse lint

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-041`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

blank line between items lint

- **Repair:** `format/reformat` &nbsp;·&nbsp; **Safety:** `format-only`
- Apply canonical formatting

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-042`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

trailing comma lint

- **Repair:** `format/reformat` &nbsp;·&nbsp; **Safety:** `format-only`
- Apply canonical formatting

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-043`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

unnecessary parentheses lint

- **Repair:** `format/reformat` &nbsp;·&nbsp; **Safety:** `format-only`
- Apply canonical formatting

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-044`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

template variant explosion lint

- **Repair:** `manual/needs-human` &nbsp;·&nbsp; **Safety:** `needs-human`
- Plan a human-led change; auto-apply is not safe here
- **See also:** [`HARN-PRM-002`](#harn-prm-002)

explosion)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-045`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

require file header lint

- **Repair:** `format/reformat` &nbsp;·&nbsp; **Safety:** `format-only`
- Apply canonical formatting

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-046`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

template provider identity branch lint

- **Repair:** `llm/use-capability-flag` &nbsp;·&nbsp; **Safety:** `capability-changing`
- Branch on a capability flag instead of provider identity
- **See also:** [`HARN-PRM-004`](#harn-prm-004)

identity branch)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-047`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

import order lint

- **Repair:** `imports/reorder` &nbsp;·&nbsp; **Safety:** `format-only`
- Reorder imports into canonical grouping

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-048`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

prefer optional shorthand lint

- **Repair:** `expressions/simplify` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Simplify the expression to its canonical form

shorthand)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-049`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

legacy doc comment lint

- **Repair:** `doc/migrate-comment-style` &nbsp;·&nbsp; **Safety:** `format-only`
- Migrate the legacy comment to canonical doc syntax

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-050`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

deprecated LLM options lint

- **Repair:** `llm/migrate-deprecated-option` &nbsp;·&nbsp; **Safety:** `scope-local`
- Replace the deprecated option with its supported equivalent
- **See also:** [`HARN-LLM-002`](#harn-llm-002), [`HARN-LLM-001`](#harn-llm-001)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-051`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

unnecessary safe navigation lint

- **Repair:** `expressions/simplify` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Simplify the expression to its canonical form

navigation)

#### How to fix

- Apply the lint's auto-fix where one is offered (`harn lint --fix`).
- Suppress the lint with an attribute only when the surrounding code is intentionally non-idiomatic.

### `HARN-LNT-052`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

ambient clock builtin replaced by `harness.clock.*`

- **Repair:** `bindings/thread-harness-clock` &nbsp;·&nbsp; **Safety:** `scope-local`
- Replace the ambient clock builtin with the corresponding `harness.clock.*` method
- **See also:** [`HARN-NAM-101`](#harn-nam-101), [`HARN-LNT-001`](#harn-lnt-001)

#### What it means

The lint fires on any call to `now_ms`, `monotonic_ms`, `sleep_ms`,
`timestamp`, or `elapsed`. These were ambient clock-capability builtins in
the pre-`Harness` runtime. Time access now routes through the
`harness.clock.*` sub-handle so capability requirements appear in the type
system instead of being hidden in the stdlib surface.

This is a lint, not a hard error. The legacy builtins still compile while
the migration is in flight, but every new call site should use the
`harness.clock.*` method that matches it (`now_ms` → `harness.clock.now_ms`,
`sleep_ms` → `harness.clock.sleep_ms`, etc.).

#### How to fix

- Run `harn fix --apply --safety scope-local` over the file. By default the
  fixer rewrites ambient clock calls to the VM-level `harness` binding with
  `bindings/use-enclosing-harness-global`, preserving helper signatures.
- If you explicitly want source-level parameter threading, run
  `harn fix --apply --safety surface-changing --harness-threading thread-params`.
  `harn fix --plan --json` reports which signatures would change and whether
  cross-module callers must be updated.

### `HARN-LNT-053`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

ambient stdio builtin replaced by `harness.stdio.*`

- **Repair:** `bindings/thread-harness` &nbsp;·&nbsp; **Safety:** `scope-local`
- Thread the existing `harness` binding through local helper calls and replace the ambient stdio builtin with `harness.stdio.*`
- **See also:** [`HARN-NAM-101`](#harn-nam-101), [`HARN-LNT-001`](#harn-lnt-001)

#### What it means

The lint fires on calls to `print`, `println`, `eprint`, `eprintln`,
`read_line`, and `prompt_user`. These were ambient stdio-capability builtins
in the pre-`Harness` runtime. Stdio access now routes through the
`harness.stdio.*` sub-handle so capability requirements are visible in the
type system.

This lint is emitted during auto-repair planning so existing call sites can be
migrated before the removed builtin produces an unknown-name diagnostic. New
code should use `harness.stdio.print`, `harness.stdio.println`,
`harness.stdio.eprint`, `harness.stdio.eprintln`,
`harness.stdio.read_line`, or `harness.stdio.prompt`.

#### How to fix

- Run `harn fix --apply --safety scope-local` over the file. By default the
  fixer rewrites ambient stdio calls to an existing local Harness binding or to
  the VM-level `harness` binding with `bindings/use-enclosing-harness-global`,
  preserving helper signatures.
- If you explicitly want source-level parameter threading, run
  `harn fix --apply --safety surface-changing --harness-threading thread-params`.
  `harn fix --plan --json` reports which signatures would change and whether
  cross-module callers must be updated.

### `HARN-LNT-054`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

ambient fs builtin replaced by `harness.fs.*`

- **Repair:** `bindings/thread-harness-fs` &nbsp;·&nbsp; **Safety:** `scope-local`
- Replace the ambient fs builtin with the corresponding `harness.fs.*` method
- **See also:** [`HARN-NAM-101`](#harn-nam-101), [`HARN-LNT-001`](#harn-lnt-001)

#### What it means

The lint fires on any call to `read_file`, `write_file`, `file_exists`,
`delete_file`, `append_file`, `list_dir`, `mkdir`, `copy_file`,
`temp_dir`, `mkdtemp`, `stat`, `move_file`, `read_lines`, `walk_dir`,
`glob`, or `find_text`.
These were ambient fs-capability builtins in the pre-`Harness` runtime.
Filesystem access now routes through the `harness.fs.*` sub-handle so
capability requirements appear in the type system instead of being
hidden in the stdlib surface.

This is a lint, not a hard error. The legacy builtins still compile
while the migration is in flight, but every new call site should use the
`harness.fs.*` method that matches it (`read_file` →
`harness.fs.read_text`, `write_file` → `harness.fs.write_text`, etc.).

#### How to fix

- Run `harn fix --apply --safety scope-local` over the file. By default the
  fixer rewrites ambient filesystem calls to the VM-level `harness` binding
  with `bindings/use-enclosing-harness-global`, preserving helper signatures.
- If you explicitly want source-level parameter threading, run
  `harn fix --apply --safety surface-changing --harness-threading thread-params`.
  `harn fix --plan --json` reports which signatures would change and whether
  cross-module callers must be updated.

### `HARN-LNT-055`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

ambient env builtin replaced by `harness.env.*`

- **Repair:** `bindings/thread-harness-env` &nbsp;·&nbsp; **Safety:** `scope-local`
- Replace the ambient env builtin with the corresponding `harness.env.*` method
- **See also:** [`HARN-NAM-101`](#harn-nam-101), [`HARN-LNT-001`](#harn-lnt-001)

#### What it means

The lint fires on calls to the ambient `env` and `env_or` builtins.
Environment access now routes through the `harness.env.*` sub-handle so
capability requirements appear in the type system instead of being
hidden in the stdlib surface.

This is a lint, not a hard error. The legacy builtins still compile
while the migration is in flight, but every new call site should use
`harness.env.get(name)` / `harness.env.get_or(name, default)`.

#### How to fix

- Run `harn fix --apply --safety scope-local` over the file. By default the
  fixer rewrites ambient env calls to the VM-level `harness` binding with
  `bindings/use-enclosing-harness-global`, preserving helper signatures.
- If you explicitly want source-level parameter threading, run
  `harn fix --apply --safety surface-changing --harness-threading thread-params`.
  `harn fix --plan --json` reports which signatures would change and whether
  cross-module callers must be updated.

### `HARN-LNT-056`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

ambient random builtin replaced by `harness.random.*`

- **Repair:** `bindings/thread-harness-random` &nbsp;·&nbsp; **Safety:** `scope-local`
- Replace the ambient random builtin with the corresponding `harness.random.*` method
- **See also:** [`HARN-NAM-101`](#harn-nam-101), [`HARN-LNT-001`](#harn-lnt-001)

#### What it means

The lint fires on calls to the ambient `random`, `random_int`,
`random_choice`, and `random_shuffle` builtins. Randomness now routes
through the `harness.random.*` sub-handle so capability requirements
appear in the type system instead of being hidden in the stdlib surface.

This is a lint, not a hard error. The legacy builtins still compile
while the migration is in flight, but every new call site should use
the matching `harness.random.*` method (`random` →
`harness.random.gen_f64`, `random_int` → `harness.random.gen_range`,
etc.). Seeded streams via an explicit `Rng` handle remain available
through the `Rng.*` surface for tests that need deterministic output.

#### How to fix

- Run `harn fix --apply --safety scope-local` over the file. By default the
  fixer rewrites ambient random calls to the VM-level `harness` binding with
  `bindings/use-enclosing-harness-global`, preserving helper signatures.
- If you explicitly want source-level parameter threading, run
  `harn fix --apply --safety surface-changing --harness-threading thread-params`.
  `harn fix --plan --json` reports which signatures would change and whether
  cross-module callers must be updated.

### `HARN-LNT-057`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

ambient net builtin replaced by `harness.net.*`

- **Repair:** `bindings/thread-harness-net` &nbsp;·&nbsp; **Safety:** `scope-local`
- Replace the ambient net builtin with the corresponding `harness.net.*` method
- **See also:** [`HARN-NAM-101`](#harn-nam-101), [`HARN-LNT-001`](#harn-lnt-001)

#### What it means

The lint fires on calls to the ambient `http_get`, `http_post`,
`http_put`, `http_patch`, `http_delete`, `http_request`, and
`http_download` builtins. Outbound HTTP now routes through the
`harness.net.*` sub-handle so capability requirements appear in the
type system instead of being hidden in the stdlib surface.

This is a lint, not a hard error. The legacy builtins still compile
while the migration is in flight, but every new call site should use
the matching `harness.net.*` method (`http_get` → `harness.net.get`,
`http_post` → `harness.net.post`, etc.). Streaming, server-mode, and
session builtins keep their ambient names today and will migrate in a
follow-up ticket.

#### How to fix

- Run `harn fix --apply --safety scope-local` over the file. By default the
  fixer rewrites ambient network calls to the VM-level `harness` binding with
  `bindings/use-enclosing-harness-global`, preserving helper signatures.
- If you explicitly want source-level parameter threading, run
  `harn fix --apply --safety surface-changing --harness-threading thread-params`.
  `harn fix --plan --json` reports which signatures would change and whether
  cross-module callers must be updated.

### `HARN-LNT-058`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

if / while / guard condition is statically known to always succeed or always fail

#### What it means

The condition of an `if`, `while`, or `guard` is statically known — one of
its two branches is unreachable. The lint fires for two patterns:

##### 1. Constant-evaluable conditions

The condition reduces to a known boolean using only literal operands and
short-circuit / negation rules. Examples:

- `if true { … }`, `if false { … }` — direct booleans.
- `if nil { … }`, `if 0 { … }`, `if "" { … }` — falsy literals.
- `if (true || some_call()) { … }` — short-circuits to `true`.
- `if (some_call() && false) { … }` — short-circuits to `false`.
- `if !!true { … }` — chains of negations on a constant.

Side-effecting subexpressions inside a vacuous compound (`some_call()`
above) still execute, but their result is dead — usually a mistake left
behind by a partial refactor.

##### 2. Statically-determined `schema_is` / `is_type`

The variable's static type already proves whether the predicate matches:

- **Always true** — `x`'s static type is a subtype of the schema, so the
  truthy branch narrows to nothing new and the falsy branch is dead.
  Example: `x: int` and `schema_is(x, int)`, or `x: {a: int, b: string}`
  and `schema_is(x, {b: string})` (width subtyping).
- **Always false** — `x`'s static type and the schema are disjoint. The
  truthy branch is dead. Example: `x: int` and `schema_is(x, string)`.

The check is deliberately conservative: it skips when `x: unknown` or
`x: any` (the open-world top types — `schema_is` is informative there),
and it requires shape fields to match optionality before reporting
"always true" (an optional field in `x` can be absent at runtime, so the
predicate may still legitimately fail). The same shape is used by
[`no-unnecessary-condition` in typescript-eslint][tse] and the
[`unnecessary-invariant` rule in Flow][flow].

[tse]: https://typescript-eslint.io/rules/no-unnecessary-condition/
[flow]: https://flow.org/en/docs/linting/rule-reference/#toc-unnecessary-invariant

#### How to fix

- If the check is genuinely dead code, remove the surrounding `if` /
  `while` / `guard` and inline (or delete) the live branch.
- If you intended a *narrower* schema, change `S` to the narrower shape
  (e.g. a tagged variant, not the parent type).
- If the variable is meant to come from an untrusted boundary, type it
  as `unknown` (or `any`) and validate at the boundary; the lint will
  then correctly stay silent.

### `HARN-LNT-059`

**Category:** `LNT` (Lint rules) &nbsp;·&nbsp; **API stability:** `stable`

project rule-engine or native lint rule

#### What it means

A project-supplied rule matched here. This is not a built-in lint: it is a
structural rule (a `*.toml` pattern from the project's `[rules] ruleDirs`) run
through the linter via the rule engine (`harn-rules`), a `.lint.harn` script
rule loaded from `ruleDirs`, or a trusted native rule library loaded from
`[rules] nativeRuleDirs`.

The message, severity, and any suggested fix come from the matched rule. The
diagnostic's reported rule id is the project rule's id, so you filter it with
`disable_rules` (or `[lint]` config) by that id, exactly like a built-in.

#### Why it fires

The project declared one or more rule directories:

```toml
[rules]
ruleDirs = ["rules"]
nativeRuleDirs = ["native-rules"]
```

and a rule in one of them matched this code. Declarative rules pair a structural
`pattern` with a `message`; script rules return findings from `lint(source)`;
native rules emit diagnostics through the `harn_lint::native` ABI. Rules that
carry a fix surface it as a machine-applicable lint fix.

#### How to fix

- Address the issue the rule describes (see the rule's `message`).
- If the rule carries a fix, `harn lint --fix` applies it. Declarative codemod
  fixes can also be applied by `harn codemod`.
- To silence it, disable the rule by its id, or remove/adjust the rule in your
  `ruleDirs` / `nativeRuleDirs`.

#### See also

- The rule engine: `harn scan`, `harn codemod`, and the `harn-rules` skill.
- Project rule discovery: `[rules] ruleDirs` and `nativeRuleDirs` in
  `harn.toml`.

### `HARN-FMT-001`

**Category:** `FMT` (Formatter) &nbsp;·&nbsp; **API stability:** `stable`

formatter could not parse the source

#### What it means

The formatter could not produce a canonical layout for this source — either
because parsing failed first, or because the existing layout drifts from the
canonical form.

#### How to fix

- Run `harn fmt` to bring the file to canonical form, or fix the parse error blocking the formatter.

### `HARN-FMT-002`

**Category:** `FMT` (Formatter) &nbsp;·&nbsp; **API stability:** `stable`

source is not in canonical format

- **Repair:** `format/reformat` &nbsp;·&nbsp; **Safety:** `format-only`
- Apply canonical formatting

#### What it means

The formatter could not produce a canonical layout for this source — either
because parsing failed first, or because the existing layout drifts from the
canonical form.

#### How to fix

- Run `harn fmt` to bring the file to canonical form, or fix the parse error blocking the formatter.

### `HARN-FMT-003`

**Category:** `FMT` (Formatter) &nbsp;·&nbsp; **API stability:** `stable`

formatter normalized trailing comma layout

- **Repair:** `format/reformat` &nbsp;·&nbsp; **Safety:** `format-only`
- Apply canonical formatting

#### What it means

The formatter could not produce a canonical layout for this source — either
because parsing failed first, or because the existing layout drifts from the
canonical form.

#### How to fix

- Run `harn fmt` to bring the file to canonical form, or fix the parse error blocking the formatter.

### `HARN-IMP-001`

**Category:** `IMP` (Import resolution) &nbsp;·&nbsp; **API stability:** `stable`

import target cannot be resolved

- **Repair:** `imports/fix-path` &nbsp;·&nbsp; **Safety:** `scope-local`
- Replace the import path with a resolvable target
- **See also:** [`HARN-MOD-001`](#harn-mod-001), [`HARN-IMP-002`](#harn-imp-002)

#### What it means

Import resolution failed at a deeper layer than `MOD` — the file, symbol, or
module graph cannot be constructed. Compilation cannot proceed.

#### How to fix

- Add the missing module or symbol, or update the import path.
- Break import cycles by extracting the shared definitions into a third module.

### `HARN-IMP-002`

**Category:** `IMP` (Import resolution) &nbsp;·&nbsp; **API stability:** `stable`

imported symbol does not exist

#### What it means

Import resolution failed at a deeper layer than `MOD` — the file, symbol, or
module graph cannot be constructed. Compilation cannot proceed.

#### How to fix

- Add the missing module or symbol, or update the import path.
- Break import cycles by extracting the shared definitions into a third module.

### `HARN-IMP-003`

**Category:** `IMP` (Import resolution) &nbsp;·&nbsp; **API stability:** `stable`

import graph contains a cycle

- **See also:** [`HARN-IMP-001`](#harn-imp-001)

#### What it means

Import resolution failed at a deeper layer than `MOD` — the file, symbol, or
module graph cannot be constructed. Compilation cannot proceed.

#### How to fix

- Add the missing module or symbol, or update the import path.
- Break import cycles by extracting the shared definitions into a third module.

### `HARN-OWN-001`

**Category:** `OWN` (Ownership and mutability) &nbsp;·&nbsp; **API stability:** `stable`

immutable binding is reassigned

- **Repair:** `bindings/make-mutable` &nbsp;·&nbsp; **Safety:** `scope-local`
- Mark the binding `mut` so it can be reassigned
- **See also:** [`HARN-OWN-002`](#harn-own-002)

#### How to fix

- Switch the binding kind (`let` ↔ `mut`) to match its actual use.
- Restructure so owned values do not escape their scope.

### `HARN-OWN-002`

**Category:** `OWN` (Ownership and mutability) &nbsp;·&nbsp; **API stability:** `stable`

mutable binding is never reassigned

- **Repair:** `bindings/make-immutable` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Drop `mut` since the binding is never reassigned
- **See also:** [`HARN-LNT-018`](#harn-lnt-018)

#### How to fix

- Switch the binding kind (`let` ↔ `mut`) to match its actual use.
- Restructure so owned values do not escape their scope.

### `HARN-OWN-003`

**Category:** `OWN` (Ownership and mutability) &nbsp;·&nbsp; **API stability:** `stable`

owned value escapes its valid scope

#### What it means

A binding annotated with `owned<T>` carries sole ownership of a drop-able
resource (a file, channel, MCP session, transcript writer, sync permit). The
compiler emits an implicit `defer { drop(x) }` at the binding's enclosing
block so the resource closes deterministically when control leaves the scope.

Returning the binding by name — or otherwise transferring it out of the scope
without declaring the transfer in the type — defeats that contract: the auto-
drop never fires, and the resource leaks until the runtime garbage-collects
the handle (which, for OS resources, may be never).

```harn
fn open_log() -> channel {
  let ch: owned<channel> = channel("log", 64)
  return ch    // HARN-OWN-003: `ch` escapes; auto-drop is bypassed
}
```

#### How to fix

- **Transfer ownership explicitly** by declaring the function's return type as
  `owned<T>`. The caller then receives an owned binding and is responsible for
  dropping it (or transferring it on again):

  ```harn
  fn open_log() -> owned<channel> {
    let ch: owned<channel> = channel("log", 64)
    return ch    // OK — ownership flows to the caller
  }
  ```

- **Drop the value before returning** by wrapping the work in a block whose
  exit triggers the auto-drop, then returning a non-owned summary:

  ```harn
  fn write_log(msg: string) -> nil {
    {
      let ch: owned<channel> = channel("log", 64)
      send(ch, msg)
    }   // `ch` drops here, before the function returns
    nil
  }
  ```

- **Drop the value explicitly** with `drop(x)` if you need to release earlier
  than the enclosing block would close it.

### `HARN-OWN-004`

**Category:** `OWN` (Ownership and mutability) &nbsp;·&nbsp; **API stability:** `stable`

unvalidated boundary value is used directly

#### How to fix

- Switch the binding kind (`let` ↔ `mut`) to match its actual use.
- Restructure so owned values do not escape their scope.

### `HARN-RCV-001`

**Category:** `RCV` (Error recovery) &nbsp;·&nbsp; **API stability:** `stable`

rescue construct is outside a function body

- **Repair:** `errors/wrap-in-fn` &nbsp;·&nbsp; **Safety:** `surface-changing`
- Move the construct inside a function body
- **See also:** [`HARN-RCV-002`](#harn-rcv-002), [`HARN-RCV-003`](#harn-rcv-003)

#### What it means

A recovery construct (`try`, `rescue`) is in an invalid position or is shaped in
a way Harn's structured-error handling does not support.

#### How to fix

- Move the construct inside a function body, or wrap it in one.
- Use `try` / `rescue` only around expressions that can produce structured errors.

### `HARN-RCV-002`

**Category:** `RCV` (Error recovery) &nbsp;·&nbsp; **API stability:** `stable`

try construct is outside a function body

- **Repair:** `errors/wrap-in-fn` &nbsp;·&nbsp; **Safety:** `surface-changing`
- Move the construct inside a function body
- **See also:** [`HARN-RCV-001`](#harn-rcv-001)

#### What it means

A recovery construct (`try`, `rescue`) is in an invalid position or is shaped in
a way Harn's structured-error handling does not support.

#### How to fix

- Move the construct inside a function body, or wrap it in one.
- Use `try` / `rescue` only around expressions that can produce structured errors.

### `HARN-RCV-003`

**Category:** `RCV` (Error recovery) &nbsp;·&nbsp; **API stability:** `stable`

rescue construct is invalid

#### What it means

A recovery construct (`try`, `rescue`) is in an invalid position or is shaped in
a way Harn's structured-error handling does not support.

#### How to fix

- Move the construct inside a function body, or wrap it in one.
- Use `try` / `rescue` only around expressions that can produce structured errors.

### `HARN-MAT-001`

**Category:** `MAT` (Match exhaustiveness) &nbsp;·&nbsp; **API stability:** `stable`

match expression is not exhaustive

- **Repair:** `match/add-missing-arms` &nbsp;·&nbsp; **Safety:** `scope-local`
- Add arms covering the missing variants
- **See also:** [`HARN-MAT-003`](#harn-mat-003), [`HARN-MAT-002`](#harn-mat-002)

#### What it means

A `match` expression is incomplete, ambiguous, or otherwise invalid. Harn
enforces exhaustive matching to keep agent decision logic auditable.

#### How to fix

- Add arms covering the remaining variants, or use a wildcard `_` arm as the explicit fallback.
- Remove duplicate arms — each variant should appear at most once.

### `HARN-MAT-002`

**Category:** `MAT` (Match exhaustiveness) &nbsp;·&nbsp; **API stability:** `stable`

match expression contains a duplicate arm

- **Repair:** `match/remove-duplicate-arm` &nbsp;·&nbsp; **Safety:** `behavior-preserving`
- Remove the duplicated match arm
- **See also:** [`HARN-MAT-001`](#harn-mat-001), [`HARN-LNT-037`](#harn-lnt-037)

#### What it means

A `match` expression is incomplete, ambiguous, or otherwise invalid. Harn
enforces exhaustive matching to keep agent decision logic auditable.

#### How to fix

- Add arms covering the remaining variants, or use a wildcard `_` arm as the explicit fallback.
- Remove duplicate arms — each variant should appear at most once.

### `HARN-MAT-003`

**Category:** `MAT` (Match exhaustiveness) &nbsp;·&nbsp; **API stability:** `stable`

match pattern is invalid

#### What it means

A `match` expression is incomplete, ambiguous, or otherwise invalid. Harn
enforces exhaustive matching to keep agent decision logic auditable.

#### How to fix

- Add arms covering the remaining variants, or use a wildcard `_` arm as the explicit fallback.
- Remove duplicate arms — each variant should appear at most once.

### `HARN-POL-001`

**Category:** `POL` (Runtime policies) &nbsp;·&nbsp; **API stability:** `stable`

pool backpressure rejected a submit

`pool.submit(...)` attempted to enqueue work into a bounded pool whose
`backpressure` policy was already full and configured with
`on_full: "fail_submitter"`.

Increase the queue depth, choose a different `on_full` policy, wait for
existing task handles to drain, or catch the error and retry from your
own orchestration policy.

### `HARN-POL-002`

**Category:** `POL` (Runtime policies) &nbsp;·&nbsp; **API stability:** `stable`

fail-fast pool has no immediate capacity

`pool.submit(...)` targeted a pool configured with
`Backpressure().fail_fast`, but all worker slots were already occupied.
Fail-fast pools do not queue work.

Catch the error if rejection is expected, raise `max_concurrent`, or use
`Backpressure().queue(...)` when callers should wait, drop, or retain a
bounded queue instead.

### `HARN-MET-001`

**Category:** `MET` (Compile-time meta restrictions) &nbsp;·&nbsp; **API stability:** `stable`

expression is not permitted in a const initializer

#### What it means

A `const` binding's right-hand side must be a pure expression that can be
folded at compile time by the bounded const-evaluator. The expression
referenced something the evaluator does not permit: a call into a non-const
function, a property access on a host object such as `harness`, a runtime
construct (spawn / parallel / select / try / yield / emit / await), a
loop, an assignment, or any builtin outside the curated const-friendly
allowlist.

Rejected:

```harn,ignore
const Z = harness.clock.now()              // host capability
const W = spawn { 1 }                      // runtime construct
const Q = some_user_fn()                   // user function call
```

Accepted:

```harn
const X: int = 5 + 3
const Y: string = format("hello-{}", X)
const NS: list = [1, 2, X]
const COUNT: int = len([1, 2, 3])

// reads to silence the unused-variable lint in the example
let _ = [X, Y, NS, COUNT]
```

#### How to fix

- Move the side-effecting computation into a regular `let` binding inside a
  pipeline or function body.
- If the value really is a compile-time constant, restructure it as
  arithmetic, string concatenation, literal collections, or reads of
  earlier `const` bindings.

#### Stability

Adding pure builtins to the const-eval allowlist is backwards-compatible —
newly permitted expressions stop being rejected.

### `HARN-CST-001`

**Category:** `CST` (Const-eval sandbox) &nbsp;·&nbsp; **API stability:** `stable`

const initializer exceeded the step budget

#### What it means

The bounded compile-time evaluator counts every reduction step it
performs while folding a `const` initializer. When the running count
exceeds `MAX_STEPS` (default 100,000), evaluation is aborted with this
diagnostic. The cap is enforced on every step, not amortized, so a
hostile or accidental quadratic expression cannot stall the compiler.

```harn,ignore
// Rejected (would expand far beyond the step budget):
const HUGE = sum_to(1_000_000)
```

#### How to fix

- Pre-compute the value off-line and embed a literal.
- Reduce the expression to a smaller closed form.
- If the work genuinely belongs at runtime, switch from `const` to `let`.

#### Stability

The default budget may grow over time; tightening it would require a
deprecation cycle.

### `HARN-CST-002`

**Category:** `CST` (Const-eval sandbox) &nbsp;·&nbsp; **API stability:** `stable`

const initializer exceeded the recursion depth budget

#### What it means

The compile-time evaluator tracks how deeply it has recursed into nested
expressions or conditionals. Exceeding `MAX_DEPTH` (default 256) aborts
evaluation with this diagnostic. The cap protects the compiler thread's
stack and prevents pathological deeply-nested literals from creating an
unbounded stack frame chain.

#### How to fix

- Flatten deeply-nested literals (e.g. a 1,000-level nested ternary).
- Break the constant into intermediate `const` bindings.

#### Stability

The default budget may grow over time; tightening it would require a
deprecation cycle.

### `HARN-CST-003`

**Category:** `CST` (Const-eval sandbox) &nbsp;·&nbsp; **API stability:** `stable`

const initializer attempted a sandboxed capability

#### What it means

The compile-time evaluator denies any expression that would touch the
filesystem, network, environment, the current process, host bindings
(`harness.*`), the orchestration runtime, or any other ambient side
effect. Even a syntactically reachable call into one of those surfaces
is rejected before evaluation runs — the const-eval sandbox refuses to
mediate I/O or non-determinism.

```harn,ignore
// Rejected:
const X = read_file("/etc/passwd")
const Y = env("HOME")
const Z = spawn { ... }
const W = harness.clock.now()
```

#### How to fix

- Move the impure expression into a `let` binding inside a pipeline.
- Replace I/O with a literal value or with a pure transformation of
  already-folded constants.

#### Stability

The denylist is enforced by allowlist (only listed pure builtins are
accepted), so newly added stdlib functions stay sandboxed by default.

### `HARN-CST-004`

**Category:** `CST` (Const-eval sandbox) &nbsp;·&nbsp; **API stability:** `stable`

const initializer raised a runtime error during evaluation

#### What it means

The expression was syntactically eligible for compile-time evaluation,
but the evaluator hit a value-level error during folding: integer
overflow on a literal arithmetic, division by zero, indexing past the
end of a literal list, an undefined identifier the const-eval
environment cannot resolve, or a type mismatch on a binary operator.

```harn,ignore
// Rejected at compile time:
const ZERO = 1 / 0
const OOB = [1, 2, 3][9]
const BAD = "a" + 1
```

#### How to fix

- Inspect the offending operand and supply a valid value.
- If the expression depends on a value that is only known at runtime,
  use `let` instead of `const`.

### `HARN-CMP-001`

**Category:** `CMP` (Bytecode compilation) &nbsp;·&nbsp; **API stability:** `stable`

the program failed to compile to bytecode

The program parsed and type-checked, but the bytecode compiler rejected it.
These are structural or codegen errors the type checker does not model yet —
for example an unsupported nested list/dict pattern in a `match` arm, a `break`
or `continue` outside a loop, `try*` outside a function, or a malformed string
interpolation hole.

`harn check` runs this compilation pass (discarding the bytecode) so that any
error which would stop `harn run` is reported up front, rather than only when
the program is executed.

#### How to fix

- Read the message: it names the specific construct the compiler could not
  lower and usually how to rewrite it.
- For nested `match` patterns, bind the element with an identifier and match it
  in a nested `match`.
- For `break`/`continue`, ensure they appear inside a loop.
