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