Part of #9. Phase 0 — foundations.
Learning goals
Structs and enums as data modeling (TRPL Using Structs / Enums and Pattern Matching), serde
derive in anger (rename_all, defaults, skip_serializing_if), Option discipline,
BTreeMap vs HashMap (determinism!), newtypes.
Task
Evolve src/entities/ into the canonical CLDK contract while keeping its excellent Rust-native
leaves (is_async/is_unsafe/is_const/extern_abi, lifetimes, generics, SafetyAnalysis —
these are the "expand at the leaves" exemplars). Add the missing spine:
- Root:
RustApplication { symbol_table: BTreeMap<String, RustModule>, call_graph: Vec<RustCallEdge>, entrypoints, external_symbols }. signature: String on every declaration node; Callsite.callee_signature: Option<String>
(None at record time, backfilled by issue 06); identity-only RustCallEdge { source, target, type, weight, provenance }; cache metadata (content_hash, last_modified, file_size) on
Module; serde derives everywhere, snake_case JSON.- Design
signature_of() — the linchpin. One canonicalizer, used for declarations AND
backfilled callees. Recommended shape: crate::module::path::func(param_types) for free fns,
crate::module::Type::method(...) for inherent methods, <Type as Trait>::method(...) for
trait impls. One entity per definition (not per generic instantiation). Rust has no
constructors — Type::new is an ordinary associated fn; decide (and record) whether struct-
literal expressions count as construction callsites. - Work the anchor → differentiate → decide → define loop per node
(references/schema-design-loop.md), recording every decision in .claude/SCHEMA_DECISIONS.md
(watch the global-gitignore trap: !.claude/ + !.claude/SCHEMA_DECISIONS.md in .gitignore).
Teacher's notes
BTreeMap for symbol_table and method maps buys deterministic JSON for free — the sibling
analyzers fight for this with sort calls.- Traits/impls/enums-with-data are your new node kinds; trait bounds land in
base_classes.
Decide macros now: analyze source as written (recommended MVP) vs expanded — record it. - Compare against
codeanalyzer-clang/codeanalyzer_clang/schema/clang_schema.py field by field:
the spine must match; the leaves are yours.
Gate
- A golden-file test: a hand-built
RustApplication serializes to committed JSON (snake_case,
stable key order) and round-trips back equal. .claude/SCHEMA_DECISIONS.md covers: signature grammar, trait/impl/enum modeling, macro
stance, constructor stance, generics stance.
Part of #9. Phase 0 — foundations.
Learning goals
Structs and enums as data modeling (TRPL Using Structs / Enums and Pattern Matching), serde
derive in anger (
rename_all, defaults,skip_serializing_if),Optiondiscipline,BTreeMapvsHashMap(determinism!), newtypes.Task
Evolve
src/entities/into the canonical CLDK contract while keeping its excellent Rust-nativeleaves (
is_async/is_unsafe/is_const/extern_abi, lifetimes, generics,SafetyAnalysis—these are the "expand at the leaves" exemplars). Add the missing spine:
RustApplication { symbol_table: BTreeMap<String, RustModule>, call_graph: Vec<RustCallEdge>, entrypoints, external_symbols }.signature: Stringon every declaration node;Callsite.callee_signature: Option<String>(None at record time, backfilled by issue 06); identity-only
RustCallEdge { source, target, type, weight, provenance }; cache metadata (content_hash,last_modified,file_size) onModule; serde derives everywhere, snake_case JSON.
signature_of()— the linchpin. One canonicalizer, used for declarations ANDbackfilled callees. Recommended shape:
crate::module::path::func(param_types)for free fns,crate::module::Type::method(...)for inherent methods,<Type as Trait>::method(...)fortrait impls. One entity per definition (not per generic instantiation). Rust has no
constructors —
Type::newis an ordinary associated fn; decide (and record) whether struct-literal expressions count as construction callsites.
(
references/schema-design-loop.md), recording every decision in.claude/SCHEMA_DECISIONS.md(watch the global-gitignore trap:
!.claude/+!.claude/SCHEMA_DECISIONS.mdin .gitignore).Teacher's notes
BTreeMapforsymbol_tableand method maps buys deterministic JSON for free — the siblinganalyzers fight for this with sort calls.
base_classes.Decide macros now: analyze source as written (recommended MVP) vs expanded — record it.
codeanalyzer-clang/codeanalyzer_clang/schema/clang_schema.pyfield by field:the spine must match; the leaves are yours.
Gate
RustApplicationserializes to committed JSON (snake_case,stable key order) and round-trips back equal.
.claude/SCHEMA_DECISIONS.mdcovers: signature grammar, trait/impl/enum modeling, macrostance, constructor stance, generics stance.