Plan
Spec: docs/design/specs/codeanalyzer-dotnet.md (this repo).
Problem
The codeanalyzer-dotnet datamodel was walked node by node with the maintainer before L1
implementation started. The walk confirmed every decision the spec already records (D1–D16),
but it also surfaced two factual errors in the spec and four decisions the spec never stated.
Left as-is, the spec misleads the next reader on how project loading works, cites a precedent
that does not exist, and omits four schema decisions that are now encoded in the analyzer.
1. § 4.3 misstates what project.assets.json contains.
The spec says its targets section plus packageFolders "produce the absolute path of every
metadata reference, including the framework reference pack". Verified against a real restore
(dotnet new console + one package, SDK 10.0.302): targets carries NuGet packages only. The
framework appears solely as a name under
project.frameworks.<tfm>.frameworkReferences.Microsoft.NETCore.App, with no path.
What the file does carry is project.frameworks.<tfm>.runtimeIdentifierGraphPath, e.g.
~/.dotnet/sdk/10.0.302/PortableRuntimeIdentifierGraph.json, which locates the dotnet root and
therefore the targeting pack at packs/Microsoft.NETCore.App.Ref/<version>/ref/<tfm>/ (167
assemblies on the probed install). D2 is unaffected — no MSBuild is invoked either way — but
the mechanism must be described correctly, because it is the step most likely to fail on an
unusual install layout.
2. D7 cites a TypeScript precedent that does not exist.
D7's comparison column reads "TS accessor_kind + #get/#set keys". codeanalyzer-typescript
v2 does neither: src/schema/v2/model.ts declares accessors as first-class callable kinds,
"getter" | "setter" | "arrow" | "function_expression". The C# decision (dual view, #get /
#set keys, accessor kind: "method") is unchanged and was re-confirmed, but it is a
divergence from TypeScript rather than a match, and the spec should say so.
3. Four decisions are missing.
D17 heritage field shape, D18 top-level statements, D19 attributes, D20 call-site keying. All
four were decided in the walk and are recorded in codeanalyzer-dotnet/.claude/SCHEMA_DECISIONS.md;
the spec is the provenance record and should carry them too.
Scope boundary
In:
- Rewrite § 4.3 step 2 to describe package resolution and targeting-pack discovery separately,
and to name runtimeIdentifierGraphPath as the dotnet-root signal.
- Correct D7's precedent column and add a sentence recording the divergence from
codeanalyzer-typescript's getter/setter kinds.
- Add D17–D20 to § 3, with the rationale and the known loss each carries.
- Note in § 8 that D17 and D19 are two further points where the mature analyzers disagree with
the keystone and with each other.
Out:
- Any change to a decision already recorded. This is an accuracy pass on the record, not a
redesign.
- Reconciling codeanalyzer-typescript to any of these answers — still its own design session.
Goals
Caveats and known risks
- The targeting-pack path is now load-bearing and undocumented by Microsoft as an API. The
packs/ layout is an implementation detail of the SDK install. A layout change breaks
reference resolution for every analyzed project at once. The spec should say this plainly so
the fallback is designed rather than discovered.
runtimeIdentifierGraphPath is not guaranteed present. It appeared on SDK 10.0.302; older
restores may omit it, leaving DOTNET_ROOT and PATH as the only signals.
- This issue edits the design record after implementation began. The four added decisions are
already encoded in codeanalyzer-dotnet; the spec is catching up to the analyzer, which is
the wrong direction and worth noting so it is not treated as normal.
Definition of done
docs/design/specs/codeanalyzer-dotnet.md describes reference resolution in terms a reader can
reproduce against a real obj/project.assets.json, with no claim that the file carries
framework paths.
- D7's precedent column matches what
codeanalyzer-typescript/src/schema/v2/model.ts actually
declares.
- § 3 carries D1–D20; the numbering in the spec and in
codeanalyzer-dotnet/.claude/SCHEMA_DECISIONS.md agree, decision for decision.
- No decision text changed other than the two corrections and the four additions.
Plan
Spec:
docs/design/specs/codeanalyzer-dotnet.md(this repo).Problem
The codeanalyzer-dotnet datamodel was walked node by node with the maintainer before L1
implementation started. The walk confirmed every decision the spec already records (D1–D16),
but it also surfaced two factual errors in the spec and four decisions the spec never stated.
Left as-is, the spec misleads the next reader on how project loading works, cites a precedent
that does not exist, and omits four schema decisions that are now encoded in the analyzer.
1. § 4.3 misstates what
project.assets.jsoncontains.The spec says its
targetssection pluspackageFolders"produce the absolute path of everymetadata reference, including the framework reference pack". Verified against a real restore
(
dotnet new console+ one package, SDK 10.0.302):targetscarries NuGet packages only. Theframework appears solely as a name under
project.frameworks.<tfm>.frameworkReferences.Microsoft.NETCore.App, with no path.What the file does carry is
project.frameworks.<tfm>.runtimeIdentifierGraphPath, e.g.~/.dotnet/sdk/10.0.302/PortableRuntimeIdentifierGraph.json, which locates the dotnet root andtherefore the targeting pack at
packs/Microsoft.NETCore.App.Ref/<version>/ref/<tfm>/(167assemblies on the probed install). D2 is unaffected — no MSBuild is invoked either way — but
the mechanism must be described correctly, because it is the step most likely to fail on an
unusual install layout.
2. D7 cites a TypeScript precedent that does not exist.
D7's comparison column reads "TS
accessor_kind+#get/#setkeys". codeanalyzer-typescriptv2 does neither:
src/schema/v2/model.tsdeclares accessors as first-class callable kinds,"getter" | "setter" | "arrow" | "function_expression". The C# decision (dual view,#get/#setkeys, accessorkind: "method") is unchanged and was re-confirmed, but it is adivergence from TypeScript rather than a match, and the spec should say so.
3. Four decisions are missing.
D17 heritage field shape, D18 top-level statements, D19 attributes, D20 call-site keying. All
four were decided in the walk and are recorded in
codeanalyzer-dotnet/.claude/SCHEMA_DECISIONS.md;the spec is the provenance record and should carry them too.
Scope boundary
In:
and to name
runtimeIdentifierGraphPathas the dotnet-root signal.codeanalyzer-typescript's
getter/setterkinds.the keystone and with each other.
Out:
redesign.
Goals
base_types[]/interfaces[], ids where resolvable, externals droppedProgramtype,functions{}always emptydecorators[{name, args[], span}], named args flattenedline:col,/kon collisionCaveats and known risks
packs/layout is an implementation detail of the SDK install. A layout change breaksreference resolution for every analyzed project at once. The spec should say this plainly so
the fallback is designed rather than discovered.
runtimeIdentifierGraphPathis not guaranteed present. It appeared on SDK 10.0.302; olderrestores may omit it, leaving
DOTNET_ROOTandPATHas the only signals.already encoded in
codeanalyzer-dotnet; the spec is catching up to the analyzer, which isthe wrong direction and worth noting so it is not treated as normal.
Definition of done
docs/design/specs/codeanalyzer-dotnet.mddescribes reference resolution in terms a reader canreproduce against a real
obj/project.assets.json, with no claim that the file carriesframework paths.
codeanalyzer-typescript/src/schema/v2/model.tsactuallydeclares.
codeanalyzer-dotnet/.claude/SCHEMA_DECISIONS.mdagree, decision for decision.