The gap
CLAUDE.md states the rule plainly — "Coder.Graph/AstSchema.cs — the uniform view of the AST's parent/child structure, hand-written rather than reflective. Adding a node type means adding it here." — but nothing enforces it. AstSchema and AstFields are both large hand-written switches ending in a silent default (AstSchema.cs's slot table, AstFields.cs:298 _ => [], AstFields.cs:443 _ => false), so a node type omitted from either produces no error, no warning and no test failure. It produces a node that draws an empty inspector.
There is no reflection-driven test anywhere in Coder.Test — nothing in the suite calls Assembly, GetTypes(), IsSubclassOf or IsAssignableFrom.
This is not hypothetical: MemberInitialiser and ConstructionExpression are missing from AstFields today (filed separately). They were added to the AST, AstSchema, the YAML serializer and all four generators in the same run, and only the inspector was missed — exactly the failure mode a hand-written switch with a silent default invites.
Proposal
Add a test class in Coder.Test/Graph/ that reflects over every concrete AstNode subclass in the ktsu.Coder assembly and asserts, for each:
AstSchema.SlotsFor returns a decision for it — either a real slot list or a deliberate, explicitly-listed empty one, so "no children" is stated rather than defaulted.
AstFields.Read returns at least one field for any node type that declares a public settable scalar property (string, bool, an enum, or a TypeReference).
- Every field name
AstFields.Read returns is accepted by AstFields.TryWrite on the same node — a read/write symmetry check that would also catch a field added to one side only.
Node types that genuinely have nothing editable (if any) opt out through an explicit allow-list in the test, so the exemption is a line of code someone had to write rather than an omission nobody noticed.
Rationale
The hand-written schema is a deliberate design choice and worth keeping — it is what lets AstGraph walk any node without a switch over its type, and reflection over the AST at runtime would trade that clarity away. But the cost of that choice is that correctness depends on a human remembering four files, and the AST is under active growth: the 2026-09-10 work alone added SourceFile, NamespaceDeclaration, EnumDeclaration, EnumMember, FieldDeclaration, CompileTimeAssertion, UsingAlias, MemberInitialiser, ConstructionExpression and TypeReference.
A reflective test keeps the production code hand-written while making the omission loud. It costs one test file and turns a silent editor gap into a build failure that names the missing type.
The gap
CLAUDE.mdstates the rule plainly — "Coder.Graph/AstSchema.cs— the uniform view of the AST's parent/child structure, hand-written rather than reflective. Adding a node type means adding it here." — but nothing enforces it.AstSchemaandAstFieldsare both large hand-written switches ending in a silent default (AstSchema.cs's slot table,AstFields.cs:298_ => [],AstFields.cs:443_ => false), so a node type omitted from either produces no error, no warning and no test failure. It produces a node that draws an empty inspector.There is no reflection-driven test anywhere in
Coder.Test— nothing in the suite callsAssembly,GetTypes(),IsSubclassOforIsAssignableFrom.This is not hypothetical:
MemberInitialiserandConstructionExpressionare missing fromAstFieldstoday (filed separately). They were added to the AST,AstSchema, the YAML serializer and all four generators in the same run, and only the inspector was missed — exactly the failure mode a hand-written switch with a silent default invites.Proposal
Add a test class in
Coder.Test/Graph/that reflects over every concreteAstNodesubclass in thektsu.Coderassembly and asserts, for each:AstSchema.SlotsForreturns a decision for it — either a real slot list or a deliberate, explicitly-listed empty one, so "no children" is stated rather than defaulted.AstFields.Readreturns at least one field for any node type that declares a public settable scalar property (string,bool, an enum, or aTypeReference).AstFields.Readreturns is accepted byAstFields.TryWriteon the same node — a read/write symmetry check that would also catch a field added to one side only.Node types that genuinely have nothing editable (if any) opt out through an explicit allow-list in the test, so the exemption is a line of code someone had to write rather than an omission nobody noticed.
Rationale
The hand-written schema is a deliberate design choice and worth keeping — it is what lets
AstGraphwalk any node without a switch over its type, and reflection over the AST at runtime would trade that clarity away. But the cost of that choice is that correctness depends on a human remembering four files, and the AST is under active growth: the 2026-09-10 work alone addedSourceFile,NamespaceDeclaration,EnumDeclaration,EnumMember,FieldDeclaration,CompileTimeAssertion,UsingAlias,MemberInitialiser,ConstructionExpressionandTypeReference.A reflective test keeps the production code hand-written while making the omission loud. It costs one test file and turns a silent editor gap into a build failure that names the missing type.