fix(lexgen): space types generate compilable C# #179
No reviewers
Labels
No labels
breaking-change
bug
documentation
duplicate
enhancement
good first issue
help wanted
performance
question
wontfix
No milestone
No project
No assignees
4 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Grandiras/ATProto.NET!179
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/lexgen-space-collections"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of #141 (found by the #138 docs work). The generated-code sample in
docs/lexicon-codegen.mdis now compiled with the other doc snippets instead of being markedpartial.What changed
atproto-lexgen csharpgenerated a"type": "space"def's holder class with:but
SpaceTypeDeclaration.Collections(src/ATProtoNet/Spaces/SpaceTypeDeclaration.cs) isIReadOnlyList<Nsid>— CS0266, so every generated space def failed to compile. The existingemitter tests (
CSharpEmitterTests) only assert on the emitted text, so nothing caught it.tools/ATProtoNet.LexiconGenerator/CodeGen/CSharpEmitter.cs(EmitSpaceType) nowemits
IReadOnlyList<ATProtoNet.Identity.Nsid> Collections, matching the fully-qualified stylethe emitter already uses for
Nsid.Parse(...)in the same method (space-def emission doesn'tset
ctx.NeedsSdkIdentity, so the type is spelled out rather than relying on a using).Key,Name,LocalizedNames) and on thepermission-set holder (
Nsid,Include) against their SDK counterparts(
SpaceTypeDeclaration,AtProtoScopes.Include) — no other mismatch found.LocalizedNamesreturns a
Dictionary<string,string>through anIReadOnlyDictionary<string,string>?-typedproperty, which is a legal implicit interface conversion, so it was already fine.
tests/ATProtoNet.Tests/Lexicon/CSharpEmitterCompileTests.cscompiles theemitter's output, not just its text, with Roslyn (
Microsoft.CodeAnalysis.CSharp4.14.0 —matched to the version already pinned by
tests/ATProtoNet.DocSnippets.Generatoronorigin/issue-138-docs). One test (Emit_RepresentativeLexiconSet_ProducesCompilableCSharp)runs the emitter over 11 Lexicon documents — 4 reused from
CSharpEmitterTests(bumped fromprivatetointernalso they can be shared:RecipeDefs,RecipeRecord,ForumSpace,AuthBasicSet) plus 7 new ones covering what those didn't — then compiles every generatedfile together, referencing the trusted platform assemblies plus
ATProtoNet.dll, withnullable enabled, and asserts there are no error diagnostics (printing them on failure).
Coverage: records; every primitive type and every
stringformat; arrays; an open union and aclosed union of object defs; a
knownValuesstring and a ref to a string-enum def; refs acrossdocuments both within the same C# namespace (sibling NSID authority) and across namespaces
(exercising both branches of
CSharpEmitter.Shorten, including itsglobal::qualification);token families; a query and a procedure with
parameters/input/output; a subscription witha closed union
message.schema; a space def with collections and localized names, and onewithout either; and a permission set.
Fixedbullet under## [Unreleased].Verified
IReadOnlyList<string> Collectionsline(two
CS0266diagnostics, on the reusedForumSpacefixture and the newBareSpacefixture),and passes once the property is retyped.
dotnet build -p:EnableSourceControlManagerQueries=false— 0 warnings,0 errors.
dotnet test tests/ATProtoNet.Tests/ -p:EnableSourceControlManagerQueries=false—5059 passed, 0 failed, 5 skipped (the 5 skips are pre-existing Aspire manifest tests,
unrelated to this change).
Deferred / not in scope
case "query": case "procedure": break;/case "subscription": break;inCSharpEmitter.EmitDocument) — that'sthe documented Issue #45 scope, not part of this bug. The new compile test includes fixtures
for all three only to prove the emitter doesn't choke when they sit alongside emittable defs.
tools/**edits to the single line described above, andsrc/**untouched, per thenote that PR #177 is doing a mechanical pass over
tools/andsrc/.🤖 Generated with Claude Code
🤖 Reviewing this PR — the review will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the review runs.
⏳ Held on the OpenCode Go window — the 5-hour window is at 0% (the bot holds at 95%).
This continues automatically after the window resets (2026-09-27T16:04:46.098Z) — nothing to re-trigger.
@claude /review. This is a small fix plus a new compile test. Please check four things:
tools/ATProtoNet.LexiconGenerator/CodeGen/CSharpEmitter.cs.tests/ATProtoNet.Tests/Lexicon/CSharpEmitterCompileTests.csreally compiles the emitter output against the SDK: trusted platform assemblies plus ATProtoNet.dll, nullable enabled, and a failure on any error diagnostic. Also that its 11 fixtures cover the def kinds the emitter supports.Microsoft.CodeAnalysis.CSharp4.14.0 reference in the test project, which matches the doc-snippet generator's pin.docs/lexicon-codegen.md.🤖 Reviewing this PR — follow along in the action run; the reply will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the task runs.
✅ Verdict: approve — no blocking issues found.
The fix is correct:
SpaceTypeDeclaration.Collectionsinsrc/ATProtoNet/Spaces/SpaceTypeDeclaration.csis indeedIReadOnlyList<Nsid>(confirmed by reading the source), so the generated forwarder's oldIReadOnlyList<string>was a genuine CS0266 bug. The one-line fix toATProtoNet.Identity.Nsidmatches the fully-qualified style already used elsewhere inEmitSpaceType(which never setsctx.NeedsSdkIdentity), so it's consistent rather than a one-off.The new
CSharpEmitterCompileTestsis a solid regression guard — compiling the emitter's actual output with Roslyn against trusted platform assemblies plus the realATProtoNet.dllcloses the exact gap the PR description identifies (the existing tests only diffed emitted text). Fixture coverage is broad and well-targeted: every primitive/format, closed and open unions, cross-document/cross-namespace refs exercising both branches ofShorten, a space def with and without collections, and query/procedure/subscription defs to confirm they don't break compilation of neighboring emittable defs. Bumping the four reused fixtures fromprivatetointernalis the minimal change needed to share them.The doc snippet change (dropping
partialfrom theForumSpaceblock indocs/lexicon-codegen.md) is consistent with CONTRIBUTING.md's guidance to usepartialsparingly — the block is a complete, self-contained class and now compiles cleanly, so marking it non-partial is correct and keeps the sample from going stale silently. The audit of the other forwarders (Key,Name,LocalizedNameson the space holder;Nsid,Includeon the permission-set holder) checks out against their SDK counterparts. CHANGELOG entry is properly scoped under Fixed with the issue reference. Scope is appropriately narrow, matching the stated constraint of not touchingsrc/**beyond the doc snippet and only touching the one generator line intools/**.⏱ 1m 11s · 18 turns · tokens: 29.4k in / 4.3k out (+723.9k cache-read)
📜 Full session transcript