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    ParserUnexpectedToken, "HARN-PAR-001", Par, "parser found an unexpected token";
201    ParserUnexpectedEof, "HARN-PAR-002", Par, "parser reached end of file while expecting syntax";
202    ParserUnexpectedCharacter, "HARN-PAR-003", Par, "lexer found an unexpected character";
203    ParserUnterminatedString, "HARN-PAR-004", Par, "string literal is unterminated";
204    ParserUnterminatedBlockComment, "HARN-PAR-005", Par, "block comment is unterminated";
205    ParserIntegerLiteralOutOfRange, "HARN-PAR-006", Par, "integer literal is out of range for int (i64)";
206    CompilerError, "HARN-CMP-001", Cmp, "the program failed to compile to bytecode";
207    UndefinedVariable, "HARN-NAM-001", Nam, "variable name cannot be resolved";
208    UndefinedFunction, "HARN-NAM-002", Nam, "function name cannot be resolved";
209    UnknownAttribute, "HARN-NAM-003", Nam, "attribute name is not recognized";
210    UnknownField, "HARN-NAM-004", Nam, "field name does not exist on the target type";
211    UnknownMethod, "HARN-NAM-005", Nam, "method name does not exist on the receiver type";
212    DuplicateArgument, "HARN-NAM-006", Nam, "argument name is duplicated";
213    UnknownBuiltin, "HARN-NAM-008", Nam, "builtin name cannot be resolved";
214    DeprecatedFunction, "HARN-NAM-009", Nam, "function call targets a deprecated declaration";
215    UnknownDeclaration, "HARN-NAM-010", Nam, "declaration reference cannot be resolved";
216    InvalidAttributeTarget, "HARN-NAM-011", Nam, "attribute is attached to an unsupported declaration";
217    InvalidAttributeArgument, "HARN-NAM-012", Nam, "attribute argument is invalid";
218    InvalidMainSignature, "HARN-NAM-101", Nam, "`fn main` must take an explicit `harness: Harness` parameter";
219    CapabilityPayloadInvalid, "HARN-CAP-001", Cap, "capability payload is invalid";
220    HitlMissingApprovalPolicy, "HARN-CAP-002", Cap, "human approval construct is missing policy";
221    HitlInvalidApprovalArgument, "HARN-CAP-003", Cap, "human approval argument is invalid";
222    CapabilityResultUnchecked, "HARN-CAP-004", Cap, "capability result must be checked";
223    CapabilityUnknownOperation, "HARN-CAP-005", Cap, "host capability operation is not declared";
224    CapabilityCallStaticNameRequired, "HARN-CAP-006", Cap, "host capability call must use a static operation name";
225    CapabilityBindingInvalid, "HARN-CAP-007", Cap, "tool host capability binding is invalid";
226    CapabilityOperationUnserved, "HARN-CAP-008", Cap, "declared host capability operation is not served";
227    EffectInheritanceViolation, "HARN-CAP-301", Cap, "child agent effect set exceeds the parent's declared effects";
228    DeprecatedLlmOption, "HARN-LLM-002", Llm, "LLM option key is deprecated";
229    LlmSchemaMissing, "HARN-LLM-003", Llm, "LLM call is missing schema validation";
230    LlmSchemaInvalid, "HARN-LLM-004", Llm, "LLM schema option is invalid";
231    LlmProviderIdentityBranch, "HARN-LLM-005", Llm, "prompt branches on provider identity instead of capability flags";
232    LlmCapabilityCompositionInvalid, "HARN-LLM-006", Llm, "provider, model, and requested options form a known-unsafe composition";
233    OrchestrationArity, "HARN-ORC-001", Orc, "orchestration construct has invalid arity";
234    OrchestrationType, "HARN-ORC-002", Orc, "orchestration construct argument has invalid type";
235    AgentDefinitionInvalid, "HARN-ORC-003", Orc, "agent declaration is invalid";
236    WorkflowDefinitionInvalid, "HARN-ORC-004", Orc, "workflow declaration is invalid";
237    ToolDefinitionInvalid, "HARN-ORC-005", Orc, "tool declaration is invalid";
238    PipelineDefinitionInvalid, "HARN-ORC-006", Orc, "pipeline declaration is invalid";
239    InvalidSelectConstruct, "HARN-ORC-007", Orc, "select construct is invalid";
240    UnreachableCode, "HARN-ORC-008", Orc, "statement cannot be reached";
241    FlowInvariantAttributeInvalid, "HARN-ORC-009", Orc, "Flow invariant attribute set is invalid";
242    ExecutionTargetMissing, "HARN-ORC-010", Orc, "execution target path cannot be found";
243    SelfDeadlockDetected, "HARN-ORC-011", Orc, "a self-deadlock acquire would block forever";
244    WaitForGraphDeadlockDetected, "HARN-ORC-012", Orc, "a wait-for graph cycle would block forever";
245    DeprecatedStdlibSymbol, "HARN-STD-001", Std, "stdlib symbol has been renamed or deprecated";
246    StdlibUsageInvalid, "HARN-STD-002", Std, "stdlib call is invalid";
247    BuiltinArity, "HARN-STD-003", Std, "builtin call has invalid arity";
248    LintMissingStdlibMetadata, "HARN-STD-101", Std, "public stdlib function is missing declared metadata";
249    LintMissingStdlibReturnType, "HARN-STD-102", Std, "public stdlib function is missing an explicit return type";
250    PromptTemplateParse, "HARN-PRM-001", Prm, "prompt template cannot be parsed";
251    PromptVariantExplosion, "HARN-PRM-002", Prm, "prompt template has too many capability-aware branches";
252    PromptInjectionRisk, "HARN-PRM-003", Prm, "prompt construction risks direct injection";
253    PromptProviderIdentityBranch, "HARN-PRM-004", Prm, "prompt template branches on provider identity";
254    PromptToolSurfaceUnknown, "HARN-PRM-005", Prm, "prompt references a tool outside the declared surface";
255    PromptToolSurfaceDeferredReference, "HARN-PRM-006", Prm, "prompt references a deferred tool without tool search";
256    PromptTargetMissing, "HARN-PRM-007", Prm, "prompt or template target cannot be found";
257    ModuleImportUnresolved, "HARN-MOD-001", Mod, "module import cannot be resolved";
258    ModuleImportUnused, "HARN-MOD-002", Mod, "module import is unused";
259    ModuleImportOrder, "HARN-MOD-003", Mod, "module imports are not in canonical order";
260    ModuleExportInvalid, "HARN-MOD-004", Mod, "module export is invalid";
261    ModuleImportCollision, "HARN-MOD-005", Mod, "module imports expose colliding names";
262    ModuleReExportConflict, "HARN-MOD-006", Mod, "module re-exports conflict";
263    ModuleImportCompileFailed, "HARN-MOD-007", Mod, "imported module failed to compile";
264    ReminderUnknownOption, "HARN-RMD-001", Rmd, "reminder lifecycle option key is not recognized";
265    ReminderInvalidShape, "HARN-RMD-002", Rmd, "reminder payload shape is invalid";
266    ReminderUnsupportedUserBlockRoleHint, "HARN-RMD-003", Rmd, "retired provider-specific reminder role-hint diagnostic";
267    ReminderInfiniteDiscardable, "HARN-RMD-004", Rmd, "discardable reminder has no TTL";
268    ReminderUnknownPropagate, "HARN-RMD-005", Rmd, "reminder propagate value is not recognized";
269    ReminderProviderMalformedSpec, "HARN-RMD-006", Rmd, "reminder provider returned a malformed reminder spec";
270    ReminderProviderBloat, "HARN-RMD-007", Rmd, "too many reminder providers are enabled";
271    ReminderUnsupportedHookEvent, "HARN-RMD-008", Rmd, "hook event does not support reminder effects";
272    SuspendWorkerNotRunning, "HARN-SUS-001", Sus, "suspend_agent target worker is not running";
273    ResumeConditionsInvalid, "HARN-SUS-002", Sus, "ResumeConditions validation failed";
274    ResumeWorkerNotSuspended, "HARN-SUS-003", Sus, "resume_agent target worker is not suspended";
275    ResumeSnapshotInvalid, "HARN-SUS-004", Sus, "resume snapshot cannot be loaded or used";
276    AwaitResumptionOutsideAgentLoop, "HARN-SUS-005", Sus, "agent_await_resumption was invoked outside agent_loop structural handling";
277    ConcurrentResumeConflict, "HARN-SUS-006", Sus, "concurrent resume changed the worker before resume could complete";
278    ResumeTriggerRegistrationFailed, "HARN-SUS-007", Sus, "ResumeConditions trigger could not be registered";
279    ResumeTimeoutUnsupported, "HARN-SUS-008", Sus, "resume timeout action is unsupported";
280    ResumeInputInvalid, "HARN-SUS-009", Sus, "resume input failed agent_loop input validation";
281    ResumeWorkerClosed, "HARN-SUS-010", Sus, "closed suspended worker cannot be resumed";
282    ReplayResumeInputHashMismatch, "HARN-SUS-011", Sus, "replay resume input hash diverges from journaled suspension";
283    ReplayDrainDecisionPromptHashMismatch, "HARN-SUS-012", Sus, "replay drain decision prompt hash diverges from journaled receipt";
284    LifecycleSignatureMismatch, "HARN-SUS-013", Sus, "lifecycle receipt signed timestamp failed verification";
285    LintRenamedStdlibSymbol, "HARN-LNT-001", Lnt, "renamed stdlib symbol lint";
286    LintCyclomaticComplexity, "HARN-LNT-002", Lnt, "cyclomatic complexity lint";
287    LintNamingConvention, "HARN-LNT-003", Lnt, "naming convention lint";
288    LintEagerCollectionConversion, "HARN-LNT-004", Lnt, "eager collection conversion lint";
289    LintRedundantClone, "HARN-LNT-005", Lnt, "redundant clone lint";
290    LintLongRunningWithoutCleanup, "HARN-LNT-006", Lnt, "long-running workflow cleanup lint";
291    LintMcpToolAnnotations, "HARN-LNT-007", Lnt, "MCP tool annotations lint";
292    LintPrOpenWithoutSecretScan, "HARN-LNT-008", Lnt, "PR open without secret scan lint";
293    LintShadowVariable, "HARN-LNT-009", Lnt, "shadow variable lint";
294    LintPersonaHookTarget, "HARN-LNT-010", Lnt, "persona hook target lint";
295    LintDeadCodeAfterReturn, "HARN-LNT-011", Lnt, "dead code after return lint";
296    LintLetThenReturn, "HARN-LNT-012", Lnt, "let then return lint";
297    LintUnhandledApprovalResult, "HARN-LNT-013", Lnt, "unhandled approval result lint";
298    LintUnusedVariable, "HARN-LNT-014", Lnt, "unused variable lint";
299    LintUnusedPatternBinding, "HARN-LNT-015", Lnt, "unused pattern binding lint";
300    LintUnusedParameter, "HARN-LNT-016", Lnt, "unused parameter lint";
301    LintUnusedImport, "HARN-LNT-017", Lnt, "unused import lint";
302    LintMutableNeverReassigned, "HARN-LNT-018", Lnt, "mutable never reassigned lint";
303    LintUnusedFunction, "HARN-LNT-019", Lnt, "unused function lint";
304    LintUnusedType, "HARN-LNT-020", Lnt, "unused type lint";
305    LintPersonaBodyMustCallSteps, "HARN-LNT-021", Lnt, "persona body must call steps lint";
306    LintUndefinedFunction, "HARN-LNT-022", Lnt, "undefined function lint";
307    LintPipelineReturnType, "HARN-LNT-023", Lnt, "pipeline return type lint";
308    LintMissingHarndoc, "HARN-LNT-024", Lnt, "missing harndoc lint";
309    LintAssertOutsideTest, "HARN-LNT-025", Lnt, "assert outside test lint";
310    LintPromptInjectionRisk, "HARN-LNT-026", Lnt, "prompt injection risk lint";
311    LintConnectorEffectPolicy, "HARN-LNT-027", Lnt, "connector effect policy lint";
312    LintUnnecessaryCast, "HARN-LNT-028", Lnt, "unnecessary cast lint";
313    LintUntypedDictAccess, "HARN-LNT-029", Lnt, "untyped dict access lint";
314    LintConstantLogicalOperand, "HARN-LNT-030", Lnt, "constant logical operand lint";
315    LintPointlessComparison, "HARN-LNT-031", Lnt, "pointless comparison lint";
316    LintComparisonToBool, "HARN-LNT-032", Lnt, "comparison to bool lint";
317    LintInvalidBinaryOpLiteral, "HARN-LNT-033", Lnt, "invalid binary operator literal lint";
318    LintRedundantNilTernary, "HARN-LNT-034", Lnt, "redundant nil ternary lint";
319    LintEmptyBlock, "HARN-LNT-035", Lnt, "empty block lint";
320    LintUnnecessaryElseReturn, "HARN-LNT-036", Lnt, "unnecessary else return lint";
321    LintDuplicateMatchArm, "HARN-LNT-037", Lnt, "duplicate match arm lint";
322    LintRequireInTest, "HARN-LNT-038", Lnt, "require in test lint";
323    LintBreakOutsideLoop, "HARN-LNT-039", Lnt, "break outside loop lint";
324    LintTemplateParse, "HARN-LNT-040", Lnt, "template parse lint";
325    LintBlankLineBetweenItems, "HARN-LNT-041", Lnt, "blank line between items lint";
326    LintTrailingComma, "HARN-LNT-042", Lnt, "trailing comma lint";
327    LintUnnecessaryParentheses, "HARN-LNT-043", Lnt, "unnecessary parentheses lint";
328    LintTemplateVariantExplosion, "HARN-LNT-044", Lnt, "template variant explosion lint";
329    LintRequireFileHeader, "HARN-LNT-045", Lnt, "require file header lint";
330    LintTemplateProviderIdentityBranch, "HARN-LNT-046", Lnt, "template provider identity branch lint";
331    LintImportOrder, "HARN-LNT-047", Lnt, "import order lint";
332    LintPreferOptionalShorthand, "HARN-LNT-048", Lnt, "prefer optional shorthand lint";
333    LintLegacyDocComment, "HARN-LNT-049", Lnt, "legacy doc comment lint";
334    LintDeprecatedLlmOptions, "HARN-LNT-050", Lnt, "deprecated LLM options lint";
335    LintUnnecessarySafeNavigation, "HARN-LNT-051", Lnt, "unnecessary safe navigation lint";
336    LintAmbientClockBuiltin, "HARN-LNT-052", Lnt, "ambient clock builtin replaced by `harness.clock.*`";
337    LintAmbientStdioBuiltin, "HARN-LNT-053", Lnt, "ambient stdio builtin replaced by `harness.stdio.*`";
338    LintAmbientFsBuiltin, "HARN-LNT-054", Lnt, "ambient fs builtin replaced by `harness.fs.*`";
339    LintAmbientEnvBuiltin, "HARN-LNT-055", Lnt, "ambient env builtin replaced by `harness.env.*`";
340    LintAmbientRandomBuiltin, "HARN-LNT-056", Lnt, "ambient random builtin replaced by `harness.random.*`";
341    LintAmbientNetBuiltin, "HARN-LNT-057", Lnt, "ambient net builtin replaced by `harness.net.*`";
342    LintVacuousCondition, "HARN-LNT-058", Lnt, "if / while / guard condition is statically known to always succeed or always fail";
343    LintRuleEngine, "HARN-LNT-059", Lnt, "project rule-engine or native lint rule";
344    LintUnnormalizedOptions, "HARN-LNT-060", Lnt, "inline options dict bypasses the typed option constructors";
345    LintNilCoalesceNoop, "HARN-LNT-061", Lnt, "nil coalesce fallback is nil";
346    LintNilCoalesceUnreachableFallback, "HARN-LNT-062", Lnt, "nil coalesce fallback is unreachable";
347    LintUnnecessaryNonNullAssert, "HARN-LNT-063", Lnt, "non-null assertion `!` on an already-non-nil value";
348    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";
349    LintNilCoalesceSelfFallback, "HARN-LNT-065", Lnt, "nil coalesce fallback repeats the left identifier";
350    LintDiscardedPureResult, "HARN-LNT-066", Lnt, "the result of a pure collection method is discarded, so the call has no effect on the receiver";
351    LintTemplateUnknownFilter, "HARN-LNT-068", Lnt, "prompt template names a filter the engine does not implement";
352    LintBroadHarnessParameter, "HARN-LNT-069", Lnt, "helper accepts root Harness but uses only narrow capability handles";
353    LintHomogeneousPositionalApi, "HARN-LNT-070", Lnt, "public API has too many same-typed positional parameters";
354    LintAmbientHarnessMethod, "HARN-LNT-071", Lnt, "global builtin has moved to a Harness capability method";
355    LintNonSourceCallableBuiltin, "HARN-LNT-072", Lnt, "call names a builtin whose declared exposure keeps Harn source from naming it";
356    LintCapabilityParameterName, "HARN-LNT-073", Lnt, "parameter carrying a narrow capability handle is not named for that capability";
357    SandboxCapabilityDenied, "HARN-CAP-201", Cap, "harness capability denied by active sandbox profile";
358    FormatterParseFailed, "HARN-FMT-001", Fmt, "formatter could not parse the source";
359    FormatterWouldReformat, "HARN-FMT-002", Fmt, "source is not in canonical format";
360    FormatterTrailingComma, "HARN-FMT-003", Fmt, "formatter normalized trailing comma layout";
361    ImportResolutionFailed, "HARN-IMP-001", Imp, "import target cannot be resolved";
362    ImportSymbolMissing, "HARN-IMP-002", Imp, "imported symbol does not exist";
363    ImportCycle, "HARN-IMP-003", Imp, "import graph contains a cycle";
364    ImmutableAssignment, "HARN-OWN-001", Own, "immutable binding is reassigned";
365    MutableNeverReassigned, "HARN-OWN-002", Own, "mutable binding is never reassigned";
366    OwnershipEscape, "HARN-OWN-003", Own, "owned value escapes its valid scope";
367    BoundaryValueUnvalidated, "HARN-OWN-004", Own, "unvalidated boundary value is used directly";
368    RescueOutsideFunction, "HARN-RCV-001", Rcv, "rescue construct is outside a function body";
369    TryOutsideFunction, "HARN-RCV-002", Rcv, "try construct is outside a function body";
370    InvalidRescueConstruct, "HARN-RCV-003", Rcv, "rescue construct is invalid";
371    NonExhaustiveMatch, "HARN-MAT-001", Mat, "match expression is not exhaustive";
372    DuplicateMatchArm, "HARN-MAT-002", Mat, "match expression contains a duplicate arm";
373    InvalidMatchPattern, "HARN-MAT-003", Mat, "match pattern is invalid";
374    PoolBackpressureFull, "HARN-POL-001", Pol, "pool backpressure rejected a submit";
375    PoolFailFastFull, "HARN-POL-002", Pol, "fail-fast pool has no immediate capacity";
376    ConstEvalDisallowedExpression, "HARN-MET-001", Met, "expression is not permitted in a const initializer";
377    ConstEvalStepLimit, "HARN-CST-001", Cst, "const initializer exceeded the step budget";
378    ConstEvalRecursionLimit, "HARN-CST-002", Cst, "const initializer exceeded the recursion depth budget";
379    ConstEvalSandboxViolation, "HARN-CST-003", Cst, "const initializer attempted a sandboxed capability";
380    ConstEvalRuntimeError, "HARN-CST-004", Cst, "const initializer raised a runtime error during evaluation";
381}
382impl Code {
383    pub const fn registry() -> &'static [RegistryEntry] {
384        REGISTRY
385    }
386
387    /// Codes that an agent should consider alongside this one when planning
388    /// repairs. Curated per-code — typically near-neighbours in the same
389    /// category that share a fix shape. Returns an empty slice for codes
390    /// without curated cross-references.
391    pub const fn related(self) -> &'static [Code] {
392        match self {
393            // Type mismatches form a family — surfacing the others helps an
394            // agent disambiguate between assignment, argument, return, etc.
395            Code::TypeMismatch => &[
396                Code::AssignmentTypeMismatch,
397                Code::ArgumentTypeMismatch,
398                Code::ReturnTypeMismatch,
399                Code::VariableTypeMismatch,
400                Code::FieldTypeMismatch,
401            ],
402            Code::AssignmentTypeMismatch => &[Code::TypeMismatch, Code::VariableTypeMismatch],
403            Code::ArgumentTypeMismatch => &[Code::TypeMismatch, Code::GenericTypeArgumentMismatch],
404            Code::ReturnTypeMismatch => &[Code::TypeMismatch, Code::ClosureReturnTypeMismatch],
405            Code::VariableTypeMismatch => &[Code::TypeMismatch, Code::AssignmentTypeMismatch],
406            Code::ClosureReturnTypeMismatch => &[Code::ReturnTypeMismatch],
407            Code::FieldTypeMismatch => &[Code::TypeMismatch, Code::InvalidStructLiteral],
408            Code::MethodTypeMismatch => &[Code::TypeMismatch, Code::CallableExpected],
409            // Generic type-argument family.
410            Code::GenericTypeArgumentUnsupported => &[
411                Code::GenericTypeArgumentMismatch,
412                Code::GenericTypeArgumentArity,
413            ],
414            Code::GenericTypeArgumentMismatch => &[
415                Code::GenericTypeArgumentArity,
416                Code::WhereConstraintMismatch,
417            ],
418            Code::GenericTypeArgumentArity => {
419                &[Code::GenericTypeArgumentMismatch, Code::TypeParameterArity]
420            }
421            Code::TypeParameterArity => &[Code::GenericTypeArgumentArity],
422            Code::WhereConstraintMismatch => &[Code::GenericTypeArgumentMismatch],
423            // Naming.
424            Code::UndefinedVariable => &[Code::UndefinedFunction, Code::UnknownDeclaration],
425            Code::UndefinedFunction => &[Code::UnknownBuiltin, Code::UnknownDeclaration],
426            Code::UnknownField => &[Code::UnknownMethod, Code::InvalidStructLiteral],
427            Code::UnknownMethod => &[Code::UnknownField, Code::CallableExpected],
428            Code::UnknownAttribute => {
429                &[Code::InvalidAttributeArgument, Code::InvalidAttributeTarget]
430            }
431            Code::InvalidAttributeArgument => {
432                &[Code::UnknownAttribute, Code::InvalidAttributeTarget]
433            }
434            Code::InvalidAttributeTarget => {
435                &[Code::UnknownAttribute, Code::InvalidAttributeArgument]
436            }
437            // LLM call family — schema, options, provider branching.
438            Code::LlmSchemaMissing => &[Code::LlmSchemaInvalid],
439            Code::LlmSchemaInvalid => &[Code::LlmSchemaMissing],
440            Code::DeprecatedLlmOption => &[Code::LintDeprecatedLlmOptions],
441            Code::LlmProviderIdentityBranch => &[Code::PromptProviderIdentityBranch],
442            // Prompt-template family.
443            Code::PromptTemplateParse => &[Code::PromptTargetMissing],
444            Code::PromptInjectionRisk => &[Code::LintPromptInjectionRisk],
445            Code::PromptProviderIdentityBranch => &[
446                Code::LlmProviderIdentityBranch,
447                Code::LintTemplateProviderIdentityBranch,
448            ],
449            Code::PromptVariantExplosion => &[Code::LintTemplateVariantExplosion],
450            // Capabilities.
451            Code::CapabilityResultUnchecked => {
452                &[Code::RescueOutsideFunction, Code::TryOutsideFunction]
453            }
454            Code::CapabilityUnknownOperation => &[Code::CapabilityCallStaticNameRequired],
455            Code::EffectInheritanceViolation => &[
456                Code::CapabilityPayloadInvalid,
457                Code::CapabilityBindingInvalid,
458            ],
459            // Recovery / match.
460            Code::RescueOutsideFunction => {
461                &[Code::TryOutsideFunction, Code::InvalidRescueConstruct]
462            }
463            Code::TryOutsideFunction => &[Code::RescueOutsideFunction],
464            Code::NonExhaustiveMatch => &[Code::InvalidMatchPattern, Code::DuplicateMatchArm],
465            Code::DuplicateMatchArm => &[Code::NonExhaustiveMatch, Code::LintDuplicateMatchArm],
466            // Module / import family.
467            Code::ModuleImportUnresolved => {
468                &[Code::ImportResolutionFailed, Code::ImportSymbolMissing]
469            }
470            Code::ModuleImportUnused => &[Code::LintUnusedImport],
471            Code::ImportResolutionFailed => {
472                &[Code::ModuleImportUnresolved, Code::ImportSymbolMissing]
473            }
474            Code::ImportCycle => &[Code::ImportResolutionFailed],
475            // Suspend / resume lifecycle.
476            Code::SuspendWorkerNotRunning => {
477                &[Code::ResumeWorkerNotSuspended, Code::ResumeWorkerClosed]
478            }
479            Code::ResumeConditionsInvalid => &[
480                Code::ResumeTriggerRegistrationFailed,
481                Code::ResumeTimeoutUnsupported,
482            ],
483            Code::ResumeWorkerNotSuspended => &[
484                Code::SuspendWorkerNotRunning,
485                Code::ConcurrentResumeConflict,
486            ],
487            Code::ResumeSnapshotInvalid => &[Code::ResumeWorkerNotSuspended],
488            Code::AwaitResumptionOutsideAgentLoop => &[Code::ResumeConditionsInvalid],
489            Code::ConcurrentResumeConflict => {
490                &[Code::ResumeWorkerNotSuspended, Code::ResumeWorkerClosed]
491            }
492            Code::ResumeTriggerRegistrationFailed => &[
493                Code::ResumeConditionsInvalid,
494                Code::ResumeTimeoutUnsupported,
495            ],
496            Code::ResumeTimeoutUnsupported => &[
497                Code::ResumeConditionsInvalid,
498                Code::ResumeTriggerRegistrationFailed,
499            ],
500            Code::ResumeInputInvalid => &[Code::ResumeWorkerNotSuspended],
501            Code::ResumeWorkerClosed => &[
502                Code::ResumeWorkerNotSuspended,
503                Code::ConcurrentResumeConflict,
504            ],
505            // Reminder lifecycle diagnostics share the same payload shape and
506            // propagation field, so nearby codes help route runtime vs lint
507            // failures to the right fix.
508            Code::ReminderUnknownOption => {
509                &[Code::ReminderInvalidShape, Code::ReminderUnknownPropagate]
510            }
511            Code::ReminderInvalidShape => {
512                &[Code::ReminderUnknownOption, Code::ReminderUnknownPropagate]
513            }
514            Code::ReminderUnknownPropagate => {
515                &[Code::ReminderUnknownOption, Code::ReminderInvalidShape]
516            }
517            Code::ReminderProviderMalformedSpec => &[Code::ReminderInvalidShape],
518            Code::ReminderProviderBloat => &[Code::ReminderInfiniteDiscardable],
519            Code::ReminderUnsupportedHookEvent => &[Code::ReminderProviderMalformedSpec],
520            // Ownership.
521            Code::ImmutableAssignment => &[Code::MutableNeverReassigned],
522            Code::MutableNeverReassigned => &[Code::LintMutableNeverReassigned],
523            // Lint pairs (drift between lint and runtime/typecheck codes).
524            Code::LintDeprecatedLlmOptions => &[Code::DeprecatedLlmOption],
525            Code::LintUnnormalizedOptions => {
526                &[Code::LintDeprecatedLlmOptions, Code::LintUntypedDictAccess]
527            }
528            Code::LintPromptInjectionRisk => &[Code::PromptInjectionRisk],
529            Code::LintTemplateVariantExplosion => &[Code::PromptVariantExplosion],
530            Code::LintTemplateProviderIdentityBranch => &[Code::PromptProviderIdentityBranch],
531            Code::LintRenamedStdlibSymbol => &[Code::DeprecatedStdlibSymbol],
532            Code::LintAmbientClockBuiltin
533            | Code::LintAmbientStdioBuiltin
534            | Code::LintAmbientFsBuiltin
535            | Code::LintAmbientEnvBuiltin
536            | Code::LintAmbientRandomBuiltin
537            | Code::LintAmbientNetBuiltin => {
538                &[Code::InvalidMainSignature, Code::LintRenamedStdlibSymbol]
539            }
540            Code::SandboxCapabilityDenied => &[Code::CapabilityPayloadInvalid],
541            Code::LintMutableNeverReassigned => &[Code::MutableNeverReassigned],
542            Code::LintUnusedImport => &[Code::ModuleImportUnused],
543            Code::LintDuplicateMatchArm => &[Code::DuplicateMatchArm],
544            _ => &[],
545        }
546    }
547}
548
549impl fmt::Display for Code {
550    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
551        f.write_str(self.as_str())
552    }
553}
554
555/// Error returned when parsing an unknown diagnostic code.
556#[derive(Debug, Clone, Copy, PartialEq, Eq)]
557pub struct ParseCodeError;
558
559impl fmt::Display for ParseCodeError {
560    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
561        f.write_str("unknown Harn diagnostic code")
562    }
563}
564
565impl std::error::Error for ParseCodeError {}
566
567impl FromStr for Code {
568    type Err = ParseCodeError;
569
570    fn from_str(value: &str) -> Result<Self, Self::Err> {
571        Code::ALL
572            .iter()
573            .copied()
574            .find(|code| code.as_str() == value)
575            .ok_or(ParseCodeError)
576    }
577}
578
579mod repairs;
580
581pub use repairs::*;