Skip to main content

harn_parser/
diagnostic_codes.rs

1//! Stable diagnostic code registry.
2//!
3//! Codes use `HARN-<CATEGORY>-<NNN>` identifiers so CLI output, editor
4//! diagnostics, docs, and future `harn explain` lookups can refer to one
5//! durable namespace.
6//!
7//! ```
8//! use harn_parser::diagnostic_codes::Category;
9//!
10//! let categories: Vec<_> = Category::ALL.iter().map(|category| category.as_str()).collect();
11//! assert_eq!(
12//!     categories,
13//!     [
14//!         "TYP", "PAR", "NAM", "CAP", "LLM", "ORC", "STD", "PRM",
15//!         "MOD", "RMD", "SUS", "LNT", "FMT", "IMP", "OWN", "RCV",
16//!         "MAT", "POL", "MET", "CST", "CMP",
17//!     ],
18//! );
19//! ```
20
21use std::{fmt, str::FromStr};
22/// Top-level diagnostic category used in a stable Harn diagnostic code.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
24pub enum Category {
25    Typ,
26    Par,
27    Nam,
28    Cap,
29    Llm,
30    Orc,
31    Std,
32    Prm,
33    Mod,
34    Rmd,
35    Sus,
36    Lnt,
37    Fmt,
38    Imp,
39    Own,
40    Rcv,
41    Mat,
42    Pol,
43    /// Meta restrictions for bounded compile-time evaluation (issue #1791).
44    Met,
45    /// Const-eval sandbox limits and capability violations (issue #1791).
46    Cst,
47    /// Structural/codegen errors that prevent bytecode execution and surface
48    /// through both `harn check` and `harn run`.
49    Cmp,
50}
51
52impl Category {
53    pub const ALL: &'static [Category] = &[
54        Category::Typ,
55        Category::Par,
56        Category::Nam,
57        Category::Cap,
58        Category::Llm,
59        Category::Orc,
60        Category::Std,
61        Category::Prm,
62        Category::Mod,
63        Category::Rmd,
64        Category::Sus,
65        Category::Lnt,
66        Category::Fmt,
67        Category::Imp,
68        Category::Own,
69        Category::Rcv,
70        Category::Mat,
71        Category::Pol,
72        Category::Met,
73        Category::Cst,
74        Category::Cmp,
75    ];
76
77    pub const fn as_str(self) -> &'static str {
78        match self {
79            Category::Typ => "TYP",
80            Category::Par => "PAR",
81            Category::Nam => "NAM",
82            Category::Cap => "CAP",
83            Category::Llm => "LLM",
84            Category::Orc => "ORC",
85            Category::Std => "STD",
86            Category::Prm => "PRM",
87            Category::Mod => "MOD",
88            Category::Rmd => "RMD",
89            Category::Sus => "SUS",
90            Category::Lnt => "LNT",
91            Category::Fmt => "FMT",
92            Category::Imp => "IMP",
93            Category::Own => "OWN",
94            Category::Rcv => "RCV",
95            Category::Mat => "MAT",
96            Category::Pol => "POL",
97            Category::Met => "MET",
98            Category::Cst => "CST",
99            Category::Cmp => "CMP",
100        }
101    }
102}
103
104impl fmt::Display for Category {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        f.write_str(self.as_str())
107    }
108}
109
110/// One registered diagnostic code.
111#[derive(Debug, Clone, Copy, PartialEq, Eq)]
112pub struct RegistryEntry {
113    pub code: Code,
114    pub identifier: &'static str,
115    pub category: Category,
116    pub summary: &'static str,
117}
118
119macro_rules! diagnostic_codes {
120    ($($variant:ident, $identifier:literal, $category:ident, $summary:literal;)*) => {
121        /// Stable diagnostic identifier.
122        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
123        pub enum Code {
124            $($variant,)*
125        }
126
127        impl Code {
128            pub const ALL: &'static [Code] = &[
129                $(Code::$variant,)*
130            ];
131
132            pub const fn as_str(self) -> &'static str {
133                match self {
134                    $(Code::$variant => $identifier,)*
135                }
136            }
137
138            pub const fn category(self) -> Category {
139                match self {
140                    $(Code::$variant => Category::$category,)*
141                }
142            }
143
144            pub const fn summary(self) -> &'static str {
145                match self {
146                    $(Code::$variant => $summary,)*
147                }
148            }
149
150            /// Embedded markdown; a missing explanation file fails the build.
151            pub const fn explanation(self) -> &'static str {
152                match self {
153                    $(Code::$variant => include_str!(
154                        concat!("diagnostic_codes/explanations/", $identifier, ".md")
155                    ),)*
156                }
157            }
158        }
159
160        pub const REGISTRY: &[RegistryEntry] = &[
161            $(RegistryEntry {
162                code: Code::$variant,
163                identifier: $identifier,
164                category: Category::$category,
165                summary: $summary,
166            },)*
167        ];
168    };
169}
170
171diagnostic_codes! {
172    TypeMismatch, "HARN-TYP-001", Typ, "expected and actual types are incompatible";
173    InvalidBinaryOperator, "HARN-TYP-002", Typ, "binary operator is not defined for the operand types";
174    StringInterpolationRewrite, "HARN-TYP-003", Typ, "string concatenation should be rewritten as interpolation";
175    ReturnTypeMismatch, "HARN-TYP-004", Typ, "returned expression does not match the declared return type";
176    AssignmentTypeMismatch, "HARN-TYP-005", Typ, "assigned value does not match the target type";
177    ArgumentTypeMismatch, "HARN-TYP-006", Typ, "argument value does not match the parameter type";
178    VariableTypeMismatch, "HARN-TYP-007", Typ, "initializer does not match the declared variable type";
179    ClosureReturnTypeMismatch, "HARN-TYP-008", Typ, "closure return expression does not match its declared type";
180    FieldTypeMismatch, "HARN-TYP-009", Typ, "field value does not match its declared type";
181    MethodTypeMismatch, "HARN-TYP-010", Typ, "method receiver or result type is incompatible";
182    GenericTypeArgumentUnsupported, "HARN-TYP-011", Typ, "callable does not accept type arguments";
183    GenericTypeArgumentMismatch, "HARN-TYP-012", Typ, "type argument does not satisfy the generic parameter";
184    GenericTypeArgumentArity, "HARN-TYP-013", Typ, "generic call has the wrong number of type arguments";
185    TypeParameterArity, "HARN-TYP-014", Typ, "declaration has the wrong number of type parameters";
186    WhereConstraintMismatch, "HARN-TYP-015", Typ, "type argument does not satisfy a where-clause constraint";
187    IterableExpected, "HARN-TYP-016", Typ, "expression must be iterable";
188    InvalidIndexType, "HARN-TYP-017", Typ, "subscript index type is invalid";
189    CallableExpected, "HARN-TYP-018", Typ, "expression must be callable";
190    InvalidCast, "HARN-TYP-019", Typ, "cast cannot be proven valid";
191    UnknownTypeName, "HARN-TYP-020", Typ, "type name cannot be resolved";
192    InvalidVariantUse, "HARN-TYP-021", Typ, "variant type is used in an invalid position";
193    InvalidStructLiteral, "HARN-TYP-022", Typ, "struct literal is invalid";
194    InvalidEnumConstruct, "HARN-TYP-023", Typ, "enum construction is invalid";
195    InvalidPatternBinding, "HARN-TYP-024", Typ, "pattern binding is invalid for the expected type";
196    InvalidOptionalAccess, "HARN-TYP-025", Typ, "optional access is invalid for the receiver type";
197    ThrowsTypeMismatch, "HARN-TYP-026", Typ, "thrown value type is not covered by the callable's declared throws set";
198    TupleIndexOutOfBounds, "HARN-TYP-027", Typ, "constant tuple index is outside the fixed arity";
199    ImplicitAnyParameter, "HARN-TYP-028", Typ, "declared parameter has no type annotation";
200    InvalidTypePredicate, "HARN-TYP-029", Typ, "type predicate contract is invalid";
201    PredicateInputInvalid, "HARN-TYP-030", Typ, "probabilistic predicate input must have a closed serializable type";
202    PredicateBooleanUse, "HARN-TYP-031", Typ, "probabilistic predicate outcome cannot be used as a boolean";
203    PredicateOutcomeUnused, "HARN-TYP-032", Typ, "probabilistic predicate outcome must be consumed";
204    PredicateSiteInvalid, "HARN-TYP-033", Typ, "probabilistic predicate site identity must be literal and unique";
205    PredicateOutcomeUnnarrowed, "HARN-TYP-034", Typ, "probabilistic predicate variant fields require outcome narrowing";
206    PredicateModelOperationMissing, "HARN-TYP-035", Typ, "probabilistic predicate model must declare the decision operation";
207    ParserUnexpectedToken, "HARN-PAR-001", Par, "parser found an unexpected token";
208    ParserUnexpectedEof, "HARN-PAR-002", Par, "parser reached end of file while expecting syntax";
209    ParserUnexpectedCharacter, "HARN-PAR-003", Par, "lexer found an unexpected character";
210    ParserUnterminatedString, "HARN-PAR-004", Par, "string literal is unterminated";
211    ParserUnterminatedBlockComment, "HARN-PAR-005", Par, "block comment is unterminated";
212    ParserIntegerLiteralOutOfRange, "HARN-PAR-006", Par, "integer literal is out of range for int (i64)";
213    CompilerError, "HARN-CMP-001", Cmp, "the program failed to compile to bytecode";
214    UndefinedVariable, "HARN-NAM-001", Nam, "variable name cannot be resolved";
215    UndefinedFunction, "HARN-NAM-002", Nam, "function name cannot be resolved";
216    UnknownAttribute, "HARN-NAM-003", Nam, "attribute name is not recognized";
217    UnknownField, "HARN-NAM-004", Nam, "field name does not exist on the target type";
218    UnknownMethod, "HARN-NAM-005", Nam, "method name does not exist on the receiver type";
219    DuplicateArgument, "HARN-NAM-006", Nam, "argument name is duplicated";
220    UnknownBuiltin, "HARN-NAM-008", Nam, "builtin name cannot be resolved";
221    DeprecatedFunction, "HARN-NAM-009", Nam, "function call targets a deprecated declaration";
222    UnknownDeclaration, "HARN-NAM-010", Nam, "declaration reference cannot be resolved";
223    InvalidAttributeTarget, "HARN-NAM-011", Nam, "attribute is attached to an unsupported declaration";
224    InvalidAttributeArgument, "HARN-NAM-012", Nam, "attribute argument is invalid";
225    InvalidMainSignature, "HARN-NAM-101", Nam, "`fn main` must take an explicit `harness: Harness` parameter";
226    CapabilityPayloadInvalid, "HARN-CAP-001", Cap, "capability payload is invalid";
227    CapabilityResultUnchecked, "HARN-CAP-004", Cap, "capability result must be checked";
228    CapabilityUnknownOperation, "HARN-CAP-005", Cap, "host capability operation is not declared";
229    CapabilityCallStaticNameRequired, "HARN-CAP-006", Cap, "host capability call must use a static operation name";
230    CapabilityBindingInvalid, "HARN-CAP-007", Cap, "tool host capability binding is invalid";
231    CapabilityOperationUnserved, "HARN-CAP-008", Cap, "declared host capability operation is not served";
232    EffectInheritanceViolation, "HARN-CAP-301", Cap, "child agent effect set exceeds the parent's declared effects";
233    LlmSchemaMissing, "HARN-LLM-003", Llm, "LLM call is missing schema validation";
234    LlmSchemaInvalid, "HARN-LLM-004", Llm, "LLM schema option is invalid";
235    LlmProviderIdentityBranch, "HARN-LLM-005", Llm, "prompt branches on provider identity instead of capability flags";
236    LlmCapabilityCompositionInvalid, "HARN-LLM-006", Llm, "provider, model, and requested options form a known-unsafe composition";
237    OrchestrationArity, "HARN-ORC-001", Orc, "orchestration construct has invalid arity";
238    OrchestrationType, "HARN-ORC-002", Orc, "orchestration construct argument has invalid type";
239    AgentDefinitionInvalid, "HARN-ORC-003", Orc, "agent declaration is invalid";
240    WorkflowDefinitionInvalid, "HARN-ORC-004", Orc, "workflow declaration is invalid";
241    ToolDefinitionInvalid, "HARN-ORC-005", Orc, "tool declaration is invalid";
242    PipelineDefinitionInvalid, "HARN-ORC-006", Orc, "pipeline declaration is invalid";
243    InvalidSelectConstruct, "HARN-ORC-007", Orc, "select construct is invalid";
244    UnreachableCode, "HARN-ORC-008", Orc, "statement cannot be reached";
245    FlowInvariantAttributeInvalid, "HARN-ORC-009", Orc, "Flow invariant attribute set is invalid";
246    ExecutionTargetMissing, "HARN-ORC-010", Orc, "execution target path cannot be found";
247    SelfDeadlockDetected, "HARN-ORC-011", Orc, "a self-deadlock acquire would block forever";
248    WaitForGraphDeadlockDetected, "HARN-ORC-012", Orc, "a wait-for graph cycle would block forever";
249    DeprecatedStdlibSymbol, "HARN-STD-001", Std, "stdlib symbol has been renamed or deprecated";
250    StdlibUsageInvalid, "HARN-STD-002", Std, "stdlib call is invalid";
251    BuiltinArity, "HARN-STD-003", Std, "builtin call has invalid arity";
252    LintMissingStdlibMetadata, "HARN-STD-101", Std, "public stdlib function is missing declared metadata";
253    LintMissingStdlibReturnType, "HARN-STD-102", Std, "public stdlib function is missing an explicit return type";
254    PromptTemplateParse, "HARN-PRM-001", Prm, "prompt template cannot be parsed";
255    PromptVariantExplosion, "HARN-PRM-002", Prm, "prompt template has too many capability-aware branches";
256    PromptInjectionRisk, "HARN-PRM-003", Prm, "prompt construction risks direct injection";
257    PromptProviderIdentityBranch, "HARN-PRM-004", Prm, "prompt template branches on provider identity";
258    PromptToolSurfaceUnknown, "HARN-PRM-005", Prm, "prompt references a tool outside the declared surface";
259    PromptToolSurfaceDeferredReference, "HARN-PRM-006", Prm, "prompt references a deferred tool without tool search";
260    PromptTargetMissing, "HARN-PRM-007", Prm, "prompt or template target cannot be found";
261    ModuleImportUnresolved, "HARN-MOD-001", Mod, "module import cannot be resolved";
262    ModuleImportUnused, "HARN-MOD-002", Mod, "module import is unused";
263    ModuleImportOrder, "HARN-MOD-003", Mod, "module imports are not in canonical order";
264    ModuleExportInvalid, "HARN-MOD-004", Mod, "module export is invalid";
265    ModuleImportCollision, "HARN-MOD-005", Mod, "module imports expose colliding names";
266    ModuleReExportConflict, "HARN-MOD-006", Mod, "module re-exports conflict";
267    ModuleImportCompileFailed, "HARN-MOD-007", Mod, "imported module failed to compile";
268    ReminderUnknownOption, "HARN-RMD-001", Rmd, "reminder lifecycle option key is not recognized";
269    ReminderInvalidShape, "HARN-RMD-002", Rmd, "reminder payload shape is invalid";
270    ReminderUnsupportedUserBlockRoleHint, "HARN-RMD-003", Rmd, "retired provider-specific reminder role-hint diagnostic";
271    ReminderInfiniteDiscardable, "HARN-RMD-004", Rmd, "discardable reminder has no TTL";
272    ReminderUnknownPropagate, "HARN-RMD-005", Rmd, "reminder propagate value is not recognized";
273    ReminderProviderMalformedSpec, "HARN-RMD-006", Rmd, "reminder provider returned a malformed reminder spec";
274    ReminderProviderBloat, "HARN-RMD-007", Rmd, "too many reminder providers are enabled";
275    ReminderUnsupportedHookEvent, "HARN-RMD-008", Rmd, "hook event does not support reminder effects";
276    SuspendWorkerNotRunning, "HARN-SUS-001", Sus, "suspend_agent target worker is not running";
277    ResumeConditionsInvalid, "HARN-SUS-002", Sus, "ResumeConditions validation failed";
278    ResumeWorkerNotSuspended, "HARN-SUS-003", Sus, "resume_agent target worker is not suspended";
279    ResumeSnapshotInvalid, "HARN-SUS-004", Sus, "resume snapshot cannot be loaded or used";
280    AwaitResumptionOutsideAgentLoop, "HARN-SUS-005", Sus, "agent_await_resumption was invoked outside agent_loop structural handling";
281    ConcurrentResumeConflict, "HARN-SUS-006", Sus, "concurrent resume changed the worker before resume could complete";
282    ResumeTriggerRegistrationFailed, "HARN-SUS-007", Sus, "ResumeConditions trigger could not be registered";
283    ResumeTimeoutUnsupported, "HARN-SUS-008", Sus, "resume timeout action is unsupported";
284    ResumeInputInvalid, "HARN-SUS-009", Sus, "resume input failed agent_loop input validation";
285    ResumeWorkerClosed, "HARN-SUS-010", Sus, "closed suspended worker cannot be resumed";
286    ReplayResumeInputHashMismatch, "HARN-SUS-011", Sus, "replay resume input hash diverges from journaled suspension";
287    ReplayDrainDecisionPromptHashMismatch, "HARN-SUS-012", Sus, "replay drain decision prompt hash diverges from journaled receipt";
288    LifecycleSignatureMismatch, "HARN-SUS-013", Sus, "lifecycle receipt signed timestamp failed verification";
289    LintRenamedStdlibSymbol, "HARN-LNT-001", Lnt, "renamed stdlib symbol lint";
290    LintCyclomaticComplexity, "HARN-LNT-002", Lnt, "cyclomatic complexity lint";
291    LintNamingConvention, "HARN-LNT-003", Lnt, "naming convention lint";
292    LintEagerCollectionConversion, "HARN-LNT-004", Lnt, "eager collection conversion lint";
293    LintRedundantClone, "HARN-LNT-005", Lnt, "redundant clone lint";
294    LintLongRunningWithoutCleanup, "HARN-LNT-006", Lnt, "long-running workflow cleanup lint";
295    LintMcpToolAnnotations, "HARN-LNT-007", Lnt, "MCP tool annotations lint";
296    LintPrOpenWithoutSecretScan, "HARN-LNT-008", Lnt, "PR open without secret scan lint";
297    LintShadowVariable, "HARN-LNT-009", Lnt, "shadow variable lint";
298    LintPersonaHookTarget, "HARN-LNT-010", Lnt, "persona hook target lint";
299    LintDeadCodeAfterReturn, "HARN-LNT-011", Lnt, "dead code after return lint";
300    LintLetThenReturn, "HARN-LNT-012", Lnt, "let then return lint";
301    LintUnhandledApprovalResult, "HARN-LNT-013", Lnt, "unhandled approval result lint";
302    LintUnusedVariable, "HARN-LNT-014", Lnt, "unused variable lint";
303    LintUnusedPatternBinding, "HARN-LNT-015", Lnt, "unused pattern binding lint";
304    LintUnusedParameter, "HARN-LNT-016", Lnt, "unused parameter lint";
305    LintUnusedImport, "HARN-LNT-017", Lnt, "unused import lint";
306    LintMutableNeverReassigned, "HARN-LNT-018", Lnt, "mutable never reassigned lint";
307    LintUnusedFunction, "HARN-LNT-019", Lnt, "unused function lint";
308    LintUnusedType, "HARN-LNT-020", Lnt, "unused type lint";
309    LintPersonaBodyMustCallSteps, "HARN-LNT-021", Lnt, "persona body must call steps lint";
310    LintUndefinedFunction, "HARN-LNT-022", Lnt, "undefined function lint";
311    LintPipelineReturnType, "HARN-LNT-023", Lnt, "pipeline return type lint";
312    LintMissingHarndoc, "HARN-LNT-024", Lnt, "missing harndoc lint";
313    LintAssertOutsideTest, "HARN-LNT-025", Lnt, "assert outside test lint";
314    LintPromptInjectionRisk, "HARN-LNT-026", Lnt, "prompt injection risk lint";
315    LintConnectorEffectPolicy, "HARN-LNT-027", Lnt, "connector effect policy lint";
316    LintUnnecessaryCast, "HARN-LNT-028", Lnt, "unnecessary cast lint";
317    LintUntypedDictAccess, "HARN-LNT-029", Lnt, "untyped dict access lint";
318    LintConstantLogicalOperand, "HARN-LNT-030", Lnt, "constant logical operand lint";
319    LintPointlessComparison, "HARN-LNT-031", Lnt, "pointless comparison lint";
320    LintComparisonToBool, "HARN-LNT-032", Lnt, "comparison to bool lint";
321    LintInvalidBinaryOpLiteral, "HARN-LNT-033", Lnt, "invalid binary operator literal lint";
322    LintRedundantNilTernary, "HARN-LNT-034", Lnt, "redundant nil ternary lint";
323    LintEmptyBlock, "HARN-LNT-035", Lnt, "empty block lint";
324    LintUnnecessaryElseReturn, "HARN-LNT-036", Lnt, "unnecessary else return lint";
325    LintDuplicateMatchArm, "HARN-LNT-037", Lnt, "duplicate match arm lint";
326    LintRequireInTest, "HARN-LNT-038", Lnt, "require in test lint";
327    LintBreakOutsideLoop, "HARN-LNT-039", Lnt, "break outside loop lint";
328    LintTemplateParse, "HARN-LNT-040", Lnt, "template parse lint";
329    LintBlankLineBetweenItems, "HARN-LNT-041", Lnt, "blank line between items lint";
330    LintTrailingComma, "HARN-LNT-042", Lnt, "trailing comma lint";
331    LintUnnecessaryParentheses, "HARN-LNT-043", Lnt, "unnecessary parentheses lint";
332    LintTemplateVariantExplosion, "HARN-LNT-044", Lnt, "template variant explosion lint";
333    LintRequireFileHeader, "HARN-LNT-045", Lnt, "require file header lint";
334    LintTemplateProviderIdentityBranch, "HARN-LNT-046", Lnt, "template provider identity branch lint";
335    LintImportOrder, "HARN-LNT-047", Lnt, "import order lint";
336    LintPreferOptionalShorthand, "HARN-LNT-048", Lnt, "prefer optional shorthand lint";
337    LintLegacyDocComment, "HARN-LNT-049", Lnt, "legacy doc comment lint";
338    LintRemovedLlmOptions, "HARN-LNT-050", Lnt, "removed LLM options lint";
339    LintUnnecessarySafeNavigation, "HARN-LNT-051", Lnt, "unnecessary safe navigation lint";
340    LintAmbientClockBuiltin, "HARN-LNT-052", Lnt, "ambient clock builtin replaced by `harness.clock.*`";
341    LintAmbientStdioBuiltin, "HARN-LNT-053", Lnt, "ambient stdio builtin replaced by `harness.stdio.*`";
342    LintAmbientFsBuiltin, "HARN-LNT-054", Lnt, "ambient fs builtin replaced by `harness.fs.*`";
343    LintAmbientEnvBuiltin, "HARN-LNT-055", Lnt, "ambient env builtin replaced by `harness.env.*`";
344    LintAmbientRandomBuiltin, "HARN-LNT-056", Lnt, "ambient random builtin replaced by `harness.random.*`";
345    LintAmbientNetBuiltin, "HARN-LNT-057", Lnt, "ambient net builtin replaced by `harness.net.*`";
346    LintVacuousCondition, "HARN-LNT-058", Lnt, "if / while / guard condition is statically known to always succeed or always fail";
347    LintRuleEngine, "HARN-LNT-059", Lnt, "project rule-engine or native lint rule";
348    LintUnnormalizedOptions, "HARN-LNT-060", Lnt, "inline options dict bypasses the typed option constructors";
349    LintNilCoalesceNoop, "HARN-LNT-061", Lnt, "nil coalesce fallback has no effect";
350    LintNilCoalesceUnreachableFallback, "HARN-LNT-062", Lnt, "nil coalesce fallback is unreachable";
351    LintUnnecessaryNonNullAssert, "HARN-LNT-063", Lnt, "non-null assertion `!` on an already-non-nil value";
352    LintMutableCaptureAcrossParallel, "HARN-LNT-064", Lnt, "a mutable variable captured from an enclosing scope is reassigned inside a `parallel`/`spawn` body, so concurrent branches share one cell and race";
353    LintNilCoalesceSelfFallback, "HARN-LNT-065", Lnt, "nil coalesce fallback repeats the left identifier";
354    LintDiscardedPureResult, "HARN-LNT-066", Lnt, "the result of a pure collection method is discarded, so the call has no effect on the receiver";
355    LintTemplateUnknownFilter, "HARN-LNT-068", Lnt, "prompt template names a filter the engine does not implement";
356    LintBroadHarnessParameter, "HARN-LNT-069", Lnt, "helper accepts root Harness but uses only narrow capability handles";
357    LintHomogeneousPositionalApi, "HARN-LNT-070", Lnt, "public API has too many same-typed positional parameters";
358    LintAmbientHarnessMethod, "HARN-LNT-071", Lnt, "global builtin has moved to a Harness capability method";
359    LintNonSourceCallableBuiltin, "HARN-LNT-072", Lnt, "call names a builtin whose declared exposure keeps Harn source from naming it";
360    LintCapabilityParameterName, "HARN-LNT-073", Lnt, "parameter carrying a narrow capability handle is not named for that capability";
361    LintUnusedPipelineInput, "HARN-LNT-074", Lnt, "explicitly unused private pipeline input can be removed";
362    LintUntypedToolHandlerResult, "HARN-LNT-075", Lnt, "tool handler returns a freeform dict, so its outcome must be inferred from key names instead of declared by its type";
363    LintToolHandlerHostCall, "HARN-LNT-076", Lnt, "tool handler reaches the privileged host wire";
364    LintPreferPick, "HARN-LNT-077", Lnt, "record literal copies fields one by one from a value that `pick` can select";
365    LintSchemaShapedToolParameters, "HARN-LNT-078", Lnt, "tool descriptor spells its per-parameter map as a JSON Schema document";
366    SandboxCapabilityDenied, "HARN-CAP-201", Cap, "harness capability denied by active sandbox profile";
367    FormatterParseFailed, "HARN-FMT-001", Fmt, "formatter could not parse the source";
368    FormatterWouldReformat, "HARN-FMT-002", Fmt, "source is not in canonical format";
369    FormatterTrailingComma, "HARN-FMT-003", Fmt, "formatter normalized trailing comma layout";
370    ImportResolutionFailed, "HARN-IMP-001", Imp, "import target cannot be resolved";
371    ImportSymbolMissing, "HARN-IMP-002", Imp, "imported symbol does not exist";
372    ImportCycle, "HARN-IMP-003", Imp, "import graph contains a cycle";
373    ImmutableAssignment, "HARN-OWN-001", Own, "immutable binding is reassigned";
374    MutableNeverReassigned, "HARN-OWN-002", Own, "mutable binding is never reassigned";
375    OwnershipEscape, "HARN-OWN-003", Own, "owned value escapes its valid scope";
376    BoundaryValueUnvalidated, "HARN-OWN-004", Own, "unvalidated boundary value is used directly";
377    RescueOutsideFunction, "HARN-RCV-001", Rcv, "rescue construct is outside a function body";
378    TryOutsideFunction, "HARN-RCV-002", Rcv, "try construct is outside a function body";
379    InvalidRescueConstruct, "HARN-RCV-003", Rcv, "rescue construct is invalid";
380    NonExhaustiveMatch, "HARN-MAT-001", Mat, "match expression is not exhaustive";
381    DuplicateMatchArm, "HARN-MAT-002", Mat, "match expression contains a duplicate arm";
382    InvalidMatchPattern, "HARN-MAT-003", Mat, "match pattern is invalid";
383    PoolBackpressureFull, "HARN-POL-001", Pol, "pool backpressure rejected a submit";
384    PoolFailFastFull, "HARN-POL-002", Pol, "fail-fast pool has no immediate capacity";
385    ConstEvalDisallowedExpression, "HARN-MET-001", Met, "expression is not permitted in a const initializer";
386    ConstEvalStepLimit, "HARN-CST-001", Cst, "const initializer exceeded the step budget";
387    ConstEvalRecursionLimit, "HARN-CST-002", Cst, "const initializer exceeded the recursion depth budget";
388    ConstEvalSandboxViolation, "HARN-CST-003", Cst, "const initializer attempted a sandboxed capability";
389    ConstEvalRuntimeError, "HARN-CST-004", Cst, "const initializer raised a runtime error during evaluation";
390}
391impl Code {
392    pub const fn registry() -> &'static [RegistryEntry] {
393        REGISTRY
394    }
395
396    /// Codes that an agent should consider alongside this one when planning
397    /// repairs. Curated per-code — typically near-neighbours in the same
398    /// category that share a fix shape. Returns an empty slice for codes
399    /// without curated cross-references.
400    pub const fn related(self) -> &'static [Code] {
401        match self {
402            // Type mismatches form a family — surfacing the others helps an
403            // agent disambiguate between assignment, argument, return, etc.
404            Code::TypeMismatch => &[
405                Code::AssignmentTypeMismatch,
406                Code::ArgumentTypeMismatch,
407                Code::ReturnTypeMismatch,
408                Code::VariableTypeMismatch,
409                Code::FieldTypeMismatch,
410            ],
411            Code::AssignmentTypeMismatch => &[Code::TypeMismatch, Code::VariableTypeMismatch],
412            Code::ArgumentTypeMismatch => &[Code::TypeMismatch, Code::GenericTypeArgumentMismatch],
413            Code::ReturnTypeMismatch => &[Code::TypeMismatch, Code::ClosureReturnTypeMismatch],
414            Code::VariableTypeMismatch => &[Code::TypeMismatch, Code::AssignmentTypeMismatch],
415            Code::ClosureReturnTypeMismatch => &[Code::ReturnTypeMismatch],
416            Code::FieldTypeMismatch => &[Code::TypeMismatch, Code::InvalidStructLiteral],
417            Code::MethodTypeMismatch => &[Code::TypeMismatch, Code::CallableExpected],
418            // Generic type-argument family.
419            Code::GenericTypeArgumentUnsupported => &[
420                Code::GenericTypeArgumentMismatch,
421                Code::GenericTypeArgumentArity,
422            ],
423            Code::GenericTypeArgumentMismatch => &[
424                Code::GenericTypeArgumentArity,
425                Code::WhereConstraintMismatch,
426            ],
427            Code::GenericTypeArgumentArity => {
428                &[Code::GenericTypeArgumentMismatch, Code::TypeParameterArity]
429            }
430            Code::TypeParameterArity => &[Code::GenericTypeArgumentArity],
431            Code::WhereConstraintMismatch => &[Code::GenericTypeArgumentMismatch],
432            // Naming.
433            Code::UndefinedVariable => &[Code::UndefinedFunction, Code::UnknownDeclaration],
434            Code::UndefinedFunction => &[Code::UnknownBuiltin, Code::UnknownDeclaration],
435            Code::UnknownField => &[Code::UnknownMethod, Code::InvalidStructLiteral],
436            Code::UnknownMethod => &[Code::UnknownField, Code::CallableExpected],
437            Code::UnknownAttribute => {
438                &[Code::InvalidAttributeArgument, Code::InvalidAttributeTarget]
439            }
440            Code::InvalidAttributeArgument => {
441                &[Code::UnknownAttribute, Code::InvalidAttributeTarget]
442            }
443            Code::InvalidAttributeTarget => {
444                &[Code::UnknownAttribute, Code::InvalidAttributeArgument]
445            }
446            // LLM call family — schema, options, provider branching.
447            Code::LlmSchemaMissing => &[Code::LlmSchemaInvalid],
448            Code::LlmSchemaInvalid => &[Code::LlmSchemaMissing],
449            Code::LlmProviderIdentityBranch => &[Code::PromptProviderIdentityBranch],
450            // Prompt-template family.
451            Code::PromptTemplateParse => &[Code::PromptTargetMissing],
452            Code::PromptInjectionRisk => &[Code::LintPromptInjectionRisk],
453            Code::PromptProviderIdentityBranch => &[
454                Code::LlmProviderIdentityBranch,
455                Code::LintTemplateProviderIdentityBranch,
456            ],
457            Code::PromptVariantExplosion => &[Code::LintTemplateVariantExplosion],
458            // Capabilities.
459            Code::CapabilityResultUnchecked => {
460                &[Code::RescueOutsideFunction, Code::TryOutsideFunction]
461            }
462            Code::CapabilityUnknownOperation => &[Code::CapabilityCallStaticNameRequired],
463            Code::EffectInheritanceViolation => &[
464                Code::CapabilityPayloadInvalid,
465                Code::CapabilityBindingInvalid,
466            ],
467            // Recovery / match.
468            Code::RescueOutsideFunction => {
469                &[Code::TryOutsideFunction, Code::InvalidRescueConstruct]
470            }
471            Code::TryOutsideFunction => &[Code::RescueOutsideFunction],
472            Code::NonExhaustiveMatch => &[Code::InvalidMatchPattern, Code::DuplicateMatchArm],
473            Code::DuplicateMatchArm => &[Code::NonExhaustiveMatch, Code::LintDuplicateMatchArm],
474            // Module / import family.
475            Code::ModuleImportUnresolved => {
476                &[Code::ImportResolutionFailed, Code::ImportSymbolMissing]
477            }
478            Code::ModuleImportUnused => &[Code::LintUnusedImport],
479            Code::ImportResolutionFailed => {
480                &[Code::ModuleImportUnresolved, Code::ImportSymbolMissing]
481            }
482            Code::ImportCycle => &[Code::ImportResolutionFailed],
483            // Suspend / resume lifecycle.
484            Code::SuspendWorkerNotRunning => {
485                &[Code::ResumeWorkerNotSuspended, Code::ResumeWorkerClosed]
486            }
487            Code::ResumeConditionsInvalid => &[
488                Code::ResumeTriggerRegistrationFailed,
489                Code::ResumeTimeoutUnsupported,
490            ],
491            Code::ResumeWorkerNotSuspended => &[
492                Code::SuspendWorkerNotRunning,
493                Code::ConcurrentResumeConflict,
494            ],
495            Code::ResumeSnapshotInvalid => &[Code::ResumeWorkerNotSuspended],
496            Code::AwaitResumptionOutsideAgentLoop => &[Code::ResumeConditionsInvalid],
497            Code::ConcurrentResumeConflict => {
498                &[Code::ResumeWorkerNotSuspended, Code::ResumeWorkerClosed]
499            }
500            Code::ResumeTriggerRegistrationFailed => &[
501                Code::ResumeConditionsInvalid,
502                Code::ResumeTimeoutUnsupported,
503            ],
504            Code::ResumeTimeoutUnsupported => &[
505                Code::ResumeConditionsInvalid,
506                Code::ResumeTriggerRegistrationFailed,
507            ],
508            Code::ResumeInputInvalid => &[Code::ResumeWorkerNotSuspended],
509            Code::ResumeWorkerClosed => &[
510                Code::ResumeWorkerNotSuspended,
511                Code::ConcurrentResumeConflict,
512            ],
513            // Reminder lifecycle diagnostics share the same payload shape and
514            // propagation field, so nearby codes help route runtime vs lint
515            // failures to the right fix.
516            Code::ReminderUnknownOption => {
517                &[Code::ReminderInvalidShape, Code::ReminderUnknownPropagate]
518            }
519            Code::ReminderInvalidShape => {
520                &[Code::ReminderUnknownOption, Code::ReminderUnknownPropagate]
521            }
522            Code::ReminderUnknownPropagate => {
523                &[Code::ReminderUnknownOption, Code::ReminderInvalidShape]
524            }
525            Code::ReminderProviderMalformedSpec => &[Code::ReminderInvalidShape],
526            Code::ReminderProviderBloat => &[Code::ReminderInfiniteDiscardable],
527            Code::ReminderUnsupportedHookEvent => &[Code::ReminderProviderMalformedSpec],
528            // Ownership.
529            Code::ImmutableAssignment => &[Code::MutableNeverReassigned],
530            Code::MutableNeverReassigned => &[Code::LintMutableNeverReassigned],
531            // Lint pairs (drift between lint and runtime/typecheck codes).
532            Code::LintUnnormalizedOptions => {
533                &[Code::LintRemovedLlmOptions, Code::LintUntypedDictAccess]
534            }
535            Code::LintPromptInjectionRisk => &[Code::PromptInjectionRisk],
536            Code::LintTemplateVariantExplosion => &[Code::PromptVariantExplosion],
537            Code::LintTemplateProviderIdentityBranch => &[Code::PromptProviderIdentityBranch],
538            Code::LintRenamedStdlibSymbol => &[Code::DeprecatedStdlibSymbol],
539            Code::LintAmbientClockBuiltin
540            | Code::LintAmbientStdioBuiltin
541            | Code::LintAmbientFsBuiltin
542            | Code::LintAmbientEnvBuiltin
543            | Code::LintAmbientRandomBuiltin
544            | Code::LintAmbientNetBuiltin => {
545                &[Code::InvalidMainSignature, Code::LintRenamedStdlibSymbol]
546            }
547            Code::SandboxCapabilityDenied => &[Code::CapabilityPayloadInvalid],
548            Code::LintMutableNeverReassigned => &[Code::MutableNeverReassigned],
549            Code::LintUnusedImport => &[Code::ModuleImportUnused],
550            Code::LintDuplicateMatchArm => &[Code::DuplicateMatchArm],
551            _ => &[],
552        }
553    }
554}
555
556impl fmt::Display for Code {
557    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
558        f.write_str(self.as_str())
559    }
560}
561
562/// Error returned when parsing an unknown diagnostic code.
563#[derive(Debug, Clone, Copy, PartialEq, Eq)]
564pub struct ParseCodeError;
565
566impl fmt::Display for ParseCodeError {
567    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
568        f.write_str("unknown Harn diagnostic code")
569    }
570}
571
572impl std::error::Error for ParseCodeError {}
573
574impl FromStr for Code {
575    type Err = ParseCodeError;
576
577    fn from_str(value: &str) -> Result<Self, Self::Err> {
578        Code::ALL
579            .iter()
580            .copied()
581            .find(|code| code.as_str() == value)
582            .ok_or(ParseCodeError)
583    }
584}
585
586mod repairs;
587
588pub use repairs::*;