Problem
ErrorContextKey.Register throws InvalidOperationException at runtime when a literal name is re-registered with a different value type (ErrorContextKey.cs:139-147) — typically surfacing as an opaque TypeInitializationException in whichever assembly's static field initializes last, in code its author never touched. Two literal declarations with conflicting T in one compilation are statically detectable exactly the way FCE001 detects code collisions, but no rule exists.
Impact
A documented runtime crash that could be a build-time Error; the cheapest high-alignment rule available (the facts helper ErrorContextKeyFacts.TryGetCreatedKey, the CompilationEnd pattern, and the doc template all exist).
Direction
- Compilation-end analyzer collecting (literal name → T) pairs via
ErrorContextKeyFacts, reporting on same-name/different-type — the FCE001 pattern with a ConcurrentDictionary keyed by name. Error severity, on by default (it guards a runtime throw), CompilationEnd tag.
- Use the next free FCE id (FCE019–FCE021 are taken by the in-flight
Outcome.Try branch).
- While in the area: document a key-namespacing convention and unify the three competing naming examples (PascalCase XML docs vs SCREAMING_SNAKE guide vs
#-prefixed framework keys), reserving # for framework keys — see §9.3(c).
Acceptance criteria
- Two same-name/different-T literal registrations in one compilation produce a build-time Error naming both sites; same-name/same-T stays silent.
- Bilingual doc page, tests, README row — consistent with the suite.
Context
Surfaced by the 2026-07-20 architecture, design & ecosystem audit (doc/handwritten/for-maintainers/audit/2026-07-20-firstclasserrors-architecture-and-design-audit.md, §9.3(c)/§14-HV6; branch claude/firstclasserrors-audit-83gap7).
Problem
ErrorContextKey.RegisterthrowsInvalidOperationExceptionat runtime when a literal name is re-registered with a different value type (ErrorContextKey.cs:139-147) — typically surfacing as an opaqueTypeInitializationExceptionin whichever assembly's static field initializes last, in code its author never touched. Two literal declarations with conflictingTin one compilation are statically detectable exactly the way FCE001 detects code collisions, but no rule exists.Impact
A documented runtime crash that could be a build-time Error; the cheapest high-alignment rule available (the facts helper
ErrorContextKeyFacts.TryGetCreatedKey, the CompilationEnd pattern, and the doc template all exist).Direction
ErrorContextKeyFacts, reporting on same-name/different-type — the FCE001 pattern with aConcurrentDictionarykeyed by name. Error severity, on by default (it guards a runtime throw),CompilationEndtag.Outcome.Trybranch).#-prefixed framework keys), reserving#for framework keys — see §9.3(c).Acceptance criteria
Context
Surfaced by the 2026-07-20 architecture, design & ecosystem audit (
doc/handwritten/for-maintainers/audit/2026-07-20-firstclasserrors-architecture-and-design-audit.md, §9.3(c)/§14-HV6; branchclaude/firstclasserrors-audit-83gap7).