Skip to content

docs: correct codeanalyzer-dotnet spec project loading and record D17-D20 - #41

Open
rahlk wants to merge 1 commit into
mainfrom
docs/issue-40-spec-errata
Open

docs: correct codeanalyzer-dotnet spec project loading and record D17-D20#41
rahlk wants to merge 1 commit into
mainfrom
docs/issue-40-spec-errata

Conversation

@rahlk

@rahlk rahlk commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Closes #40. Sub-issue of #34.

An accuracy pass on the committed spec after the datamodel was walked node by node with the maintainer. No decision text changed — two corrections and four additions.

What was wrong

§ 4.3 described reference resolution as one mechanism when it is two. The spec said project.assets.json's targets plus packageFolders produce "the absolute path of every metadata reference, including the framework reference pack". Checked against a real restore (dotnet new console + one package, SDK 10.0.302):

  • targets.<tfm> — NuGet packages only.
  • The framework appears as a bare name under project.frameworks.<tfm>.frameworkReferences.Microsoft.NETCore.App. No path.
  • What is there: runtimeIdentifierGraphPath, recorded as <dotnet-root>/sdk/10.0.302/PortableRuntimeIdentifierGraph.json — which locates the dotnet root, and from it the targeting pack at packs/Microsoft.NETCore.App.Ref/<version>/ref/<tfm>/ (167 assemblies on the probed install).

D2 stands — no MSBuild either way. But the step most likely to break on an unusual install was written as the step that cannot break.

D7 cited a TypeScript precedent that does not exist. The comparison column read "TS accessor_kind + #get/#set keys". codeanalyzer-typescript/src/schema/v2/model.ts declares neither — accessors there are first-class kinds, "getter" | "setter" | "arrow" | "function_expression". The C# decision is unchanged and was re-confirmed; it diverges from TypeScript rather than following it.

What was missing

D17–D20 — heritage field shape, top-level statements, attributes, call-site keys — were decided in the walk and recorded only in codeanalyzer-dotnet/.claude/SCHEMA_DECISIONS.md. The spec is the provenance record and now carries them, each with its rationale and its known loss.

Why § 8 matters more after this

It grows from two sibling divergences to five. The two originals are Python-vs-TypeScript disagreements where C# picked a side. The three additions — heritage naming, decorator structure, accessor modelling — are places where neither mature analyzer follows the keystone, so C# is the first to implement what the keystone actually says.

That is the more urgent kind. A field the analyzers spell three ways cannot be modelled once, and modelling it once is the premise the single-SDK design rests on.

Caveats

  • The targeting-pack path is now load-bearing and depends on an undocumented SDK layout. The PR records the Basic.Reference.Assemblies fallback rather than leaving it to be discovered.
  • runtimeIdentifierGraphPath was present on SDK 10.0.302; older restores may omit it, leaving DOTNET_ROOT and PATH as the only signals.
  • This edits the design record after implementation began — the spec catching up to the analyzer, which is the wrong direction. Called out in Spec errata: codeanalyzer-dotnet § 4.3 project loading, D7 precedent, and four unrecorded decisions #40 so it is not read as normal.

…-D20

Section 4.3 claimed project.assets.json produces "the absolute path of every
metadata reference, including the framework reference pack". Verified against a
real restore on SDK 10.0.302: its targets section carries NuGet packages only.
The framework appears solely as a name under
project.frameworks.<tfm>.frameworkReferences, with no path attached.

Reference resolution is therefore two mechanisms, not one. Packages resolve from
targets + libraries.path + packageFolders. Framework assemblies come from the
SDK targeting pack, located via runtimeIdentifierGraphPath, which the assets
file records as <dotnet-root>/sdk/<version>/PortableRuntimeIdentifierGraph.json.
D2 is unaffected -- no MSBuild is invoked either way -- but the step most likely
to fail on an unusual install layout was described as the step that cannot fail.

Two failure modes follow and are now written down. A missing targeting pack is a
hard error rather than a degradation, because a symbol table built without
System.Object looks superficially valid while resolving almost nothing. And the
packs/ layout is an SDK implementation detail, not a contract, so the fallback
of bundling reference assemblies is recorded before it is needed rather than
after.

D7 cited "TS accessor_kind + #get/#set keys" as precedent. codeanalyzer-typescript
declares neither; its accessors are first-class kinds, "getter" | "setter". The
C# decision is unchanged and was re-confirmed, but it diverges from TypeScript
rather than following it, and section 8 now says so.

Adds D17 heritage, D18 top-level statements, D19 attributes and D20 call-site
keys, all settled while walking the spine node by node and until now recorded
only in the analyzer repo. Section 8 grows from two sibling divergences to five;
the three additions are places where neither mature analyzer follows the
keystone, which makes them the more urgent kind -- the SDK cannot model a field
once if the analyzers spell it three ways.

Closes #40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spec errata: codeanalyzer-dotnet § 4.3 project loading, D7 precedent, and four unrecorded decisions

1 participant