Skip to content

Comments

Collections XML docs migration and runnable code samples#1

Open
richlander wants to merge 7 commits intomainfrom
dev/richlander/collections-xmldocs
Open

Collections XML docs migration and runnable code samples#1
richlander wants to merge 7 commits intomainfrom
dev/richlander/collections-xmldocs

Conversation

@richlander
Copy link
Owner

@richlander richlander commented Feb 20, 2026

Migrates XML documentation from dotnet-api-docs into /// comments and adds runnable code samples for 11 core System.Collections.Generic types (351 DocFX UIDs, 11 sample files, ~1,500 lines). This is a pilot for an LLM agent-driven approach to migrating and enriching API documentation at scale across dotnet/runtime.

Approach: LLM agent fleet

The slash CLI toolkit and its companion agent skill are purpose-built for LLM agent automation. The workflow is designed so that LLM agents do the work — auditing doc coverage, writing runnable code samples, registering them in samples.json, and running the tool to generate /// comments. Each type is an independent work unit that an agent processes end-to-end with no human coordination required between agents.

The tool is deterministic and repeatable: /// comments are entirely derived from inputs (dotnet-api-docs XML, sample files, samples.json), so it can be re-run any number of times without loss. Agents write the inputs; the tool writes the source. This separation means agents never hand-edit /// comments — they produce samples and mappings, and the tool does the rest.

Fleet estimate for dotnet/runtime

Excluding non-runtime frameworks (WinForms, WPF, WCF, ASP.NET WebForms, etc.), dotnet-api-docs contains an estimated 8,000–10,000 runtime-relevant types.

Scenario Per-type time Fleet of 20 agents Notes
Doc-only migration (no new samples) < 1 minute Hours Deterministic tool run, no LLM creativity needed
Docs + samples (full enrichment) 15–30 minutes ~4–8 days wall-clock LLM agents write samples, register mappings, verify

Sample prioritization — selecting which types get samples first based on usage data (page views, NuGet downloads, API telemetry) — is an open constraint that should be resolved before scaling beyond the pilot.

See SAMPLES-REPORT.md for full context — design goals, tradeoffs, the #region divergence, duplication management, batching strategy, and CI integration path.

Key files by type

All links point to the dev/richlander/collections-xmldocs branch.

Samples infrastructure

File Description
Directory.Build.props Isolates samples from the repo build system
Directory.Build.targets Empty — blocks repo targets inheritance
eng/run-samples.sh Discovers and runs all samples, reports pass/fail

Sample files (runnable file-based apps with local functions as boundaries)

File Type
List.Examples.cs List<T>
Dictionary.Examples.cs Dictionary<TKey, TValue>
Stack.Examples.cs Stack<T>
LinkedList.Examples.cs LinkedList<T>
OrderedDictionary.Examples.cs OrderedDictionary<TKey, TValue>

samples.json (maps DocFX UIDs → sample methods; one per-type fragment, one merged per library)

File Scope
samples.json (System.Collections) Merged — all System.Collections types
samples.json (CoreLib) Merged — all CoreLib types
LinkedList.samples.json Per-type fragment (24 UIDs → 5 functions)
Stack.samples.json Per-type fragment
List.samples.json Per-type fragment

Note: This PR is for review and discussion — not intended for merge.

richlander and others added 7 commits February 14, 2026 00:44
Set up samples infrastructure for the collections XML doc migration
pilot. Targets 16 core collection types across System.Private.CoreLib
and System.Collections (562 members total, all Good quality, zero
samples currently).

Types: List, Dictionary, HashSet, Queue, Stack, SortedSet,
SortedDictionary, SortedList, LinkedList, LinkedListNode,
OrderedDictionary, PriorityQueue, SynchronizedCollection,
SynchronizedReadOnlyCollection, SynchronizedKeyedCollection,
KeyedByTypeCollection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
First batch of the collections pilot. Each type gets:
- A runnable .Examples.cs with self-contained local functions
- A .samples.json fragment mapping DocIds to methods
- Entries merged into the main samples.json (107 total)

List<T>: 9 functions, 55 DocId mappings
Dictionary<TKey,TValue>: 5 functions, 19 DocId mappings
HashSet<T>: 4 functions, 17 DocId mappings
Queue<T>: 3 functions, 16 DocId mappings

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Second batch of the collections pilot. Each type gets a runnable
.Examples.cs with self-contained local functions and a .samples.json
fragment merged into the main samples.json (108 entries).

Stack<T>: 10 functions, 24 DocId mappings
LinkedList<T> + LinkedListNode<T>: 5 functions, 31 DocId mappings
SortedSet<T>: 7 functions, 29 DocId mappings
PriorityQueue<TElement,TPriority>: 4 functions, 24 DocId mappings

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Final batch of the collections pilot. Each type gets a runnable
.Examples.cs with self-contained local functions and a .samples.json
fragment. System.Collections samples.json now has 245 entries.

SortedDictionary<TKey,TValue>: 5 functions, 40 DocId mappings
SortedList<TKey,TValue>: 6 functions, 27 DocId mappings
OrderedDictionary<TKey,TValue>: 7 functions, 70 DocId mappings

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Introduces a shell script that finds all *.Examples.cs files under
src/libraries/*/samples/, runs each with 'dotnet run', and reports
a pass/fail summary. Failures show full output for diagnosis.

Usage:
  ./eng/run-samples.sh              # run all, report failures
  ./eng/run-samples.sh --verbose    # run all, show all output

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
….json

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Covers: overview and slash toolkit link, design goals (any-scope,
repeatable, fleet-built), per-type coverage table, source fidelity,
branch history, sample runner details and ideal CI integration path,
Directory.Build.props isolation tradeoff, and sample prioritization
as an open constraint.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
richlander pushed a commit that referenced this pull request Feb 20, 2026
…er (dotnet#123735)

From discussion, opting into enabling the crash chaining is more
correct.

<s>The previously registered signal action/handler aren't guaranteed to
return, so we lose out on notifying shutdown and creating a dump in
those cases. Specifically, PROCCreateCrashDumpIfEnabled would be the
last chance to provide the managed context for the thread that crashed.

e.g. On Android CoreCLR, it seems that, by default, signal handlers are
already registered by Android's runtime
(/apex/com.android.runtime/bin/linker64 +
/system/lib64/libandroid_runtime.so). Whenever an unhandled synchronous
fault occurs, the previously registered handler will not return back to
invoke_previous_action and aborts the thread itself, so
PROCCreateCrashDumpIfEnabled will not be hit.</s>

## Sigsegv behavior Android CoreCLR vs other platforms

### Android CoreCLR
When intentionally writing to NULL (sigsegv) on Android CoreCLR, the
previously registered signal handler goes down this path
https://github.com/dotnet/runtime/blob/40e8c73b8f3b5f478a9bf03cf55c71d0608a8855/src/coreclr/pal/src/exception/signal.cpp#L454,
and the thread aborts before hitting PROCNotifyProcessShutdown and
PROCCreateCrashDumpIfEnabled.

### MacOS/Linux/NativeAOT(linux)
On MacOS, Linux, NativeAOT (Only checked linux at time of writing), the
same intentional SIGSEGV will hit
https://github.com/dotnet/runtime/blob/40e8c73b8f3b5f478a9bf03cf55c71d0608a8855/src/coreclr/pal/src/exception/signal.cpp#L431-L448
instead because there is no previously registered signal handler. In
those cases, PROCCreateCrashDumpIfEnabled is hit and managed callstacks
are captured in the dump.

## History investigation

From a github history dive, I didn't spot anything in particular
requiring the previous signal handler to be invoked before
PROCNotifyProcessShutdown + PROCCreateCrashDumpIfEnabled.

PROCNotifyProcessShutdown was first introduced in
dotnet@1433c3f.
It doesn't seem to state a particular reason for invoking it after the
previous signal handler.

PROCCreateCrashDumpIfEnabled was added to signal.cpp in
dotnet@7f9bd2c
because the PROCNotifyProcessShutdown didn't create a crash dump. It
doesn't state any particular reason for being invoked after the
previously registered signal handler, and was probably just placed next
to PROCNotifyProcessShutdown.

`invoke_previous_action` was introduced in
dotnet@a740f65
and was refactoring while maintaining the order.

## Android CoreCLR behavior after swapping order

Locally, I have POC changes to emit managed callstacks in Android's
PROCCreateCrashDumpIfEnabled.
```
01-28 17:26:40.951  2416  2440 F DOTNET  : Native crash detected; attempting managed stack trace.
01-28 17:26:40.951  2416  2440 F DOTNET  : {"stack":[
01-28 17:26:40.951  2416  2440 F DOTNET  : {"ip":"0x0","module":"0x0","offset":"0x0","name":"Program.MemSet(Void*, Int32, UIntPtr)"},
01-28 17:26:40.951  2416  2440 F DOTNET  : {"ip":"0x78d981145973","module":"0x0","offset":"0x0","name":"Program.MemSet(Void*, Int32, UIntPtr)"},
01-28 17:26:40.951  2416  2440 F DOTNET  : {"ip":"0x78d981145973","module":"0x0","offset":"0x73","name":"Program.ForceNativeSegv()"},
01-28 17:26:40.951  2416  2440 F DOTNET  : {"ip":"0x78d981141b60","module":"0x0","offset":"0x70","name":"Program.Main(System.String[])"}
01-28 17:26:40.951  2416  2440 F DOTNET  : ]}
01-28 17:26:40.952  2416  2440 F DOTNET  : Crash dump hook completed.
--------- beginning of crash
01-28 17:26:40.952  2416  2440 F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 2440 (.dot.MonoRunner), pid 2416 (ulator.JIT.Test)
.....
01-28 17:26:46.882  2921  2921 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
01-28 17:26:46.882  2921  2921 F DEBUG   : Build fingerprint: 'google/sdk_gphone64_x86_64/emu64xa:16/BE2A.250530.026.D1/13818094:user/release-keys'
01-28 17:26:46.882  2921  2921 F DEBUG   : Revision: '0'
01-28 17:26:46.882  2921  2921 F DEBUG   : ABI: 'x86_64'
01-28 17:26:46.882  2921  2921 F DEBUG   : Timestamp: 2026-01-28 17:26:41.492831700-0500
01-28 17:26:46.882  2921  2921 F DEBUG   : Process uptime: 20s
01-28 17:26:46.883  2921  2921 F DEBUG   : Cmdline: net.dot.Android.Device_Emulator.JIT.Test
01-28 17:26:46.883  2921  2921 F DEBUG   : pid: 2416, tid: 2440, name: .dot.MonoRunner  >>> net.dot.Android.Device_Emulator.JIT.Test <<<
01-28 17:26:46.883  2921  2921 F DEBUG   : uid: 10219
01-28 17:26:46.883  2921  2921 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0000000000000000
01-28 17:26:46.883  2921  2921 F DEBUG   : Cause: null pointer dereference
01-28 17:26:46.883  2921  2921 F DEBUG   : Abort message: 'CoreCLR: previous handler for '
01-28 17:26:46.883  2921  2921 F DEBUG   :     rax 0000000000000000  rbx 000078da87ffade0  rcx 0000000000000000  rdx 0000000000000001
01-28 17:26:46.884  1237  1297 I s.nexuslauncher: AssetManager2(0x78dd08cd9178) locale list changing from [] to [en-US]
01-28 17:26:46.903  2447  2594 I BugleNotifications: Creating notification input ids [CONTEXT im_entry_input="" im_notification_input="" im_settings_store_input="" im_final_input="" ]
01-28 17:26:46.905  2921  2921 F DEBUG   :     r8  00007ffcde5a8080  r9  34d9bb0e67871eb0  r10 000078ddb4111870  r11 0000000000000293
01-28 17:26:46.906  2921  2921 F DEBUG   :     r12 0000000000000001  r13 000078da87ffafa0  r14 0000000000000000  r15 000078da87ffaf18
01-28 17:26:46.906  2921  2921 F DEBUG   :     rdi 0000000000000000  rsi 0000000000000000
01-28 17:26:46.906  2921  2921 F DEBUG   :     rbp 000078da87ffac40  rsp 000078da87ffabc8  rip 000078ddb41118a2
01-28 17:26:46.906  2921  2921 F DEBUG   : 2 total frames
01-28 17:26:46.906  2921  2921 F DEBUG   : backtrace:
01-28 17:26:46.906  2921  2921 F DEBUG   :       #00 pc 000000000008f8a2  /apex/com.android.runtime/lib64/bionic/libc.so (memset_avx2+50) (BuildId: fcb82240218d1473de1e3d2137c0be35)
01-28 17:26:46.906  2921  2921 F DEBUG   :       #1 pc 0000000000049972  /memfd:doublemapper (deleted) (offset 0x111000)
```
Now theres a window to log managed callstacks before the original signal
handler aborts and triggers a tombstone.

## Android Mono behavior

Mono provides two embeddings APIs to configure signal and crash chaining
https://github.com/dotnet/runtime/blob/61d3943de41e948bb0ecf871b92eb456d2dd74d8/src/mono/mono/mini/driver.c#L2864-L2894
that determine whether synchronous faults would chain
https://github.com/dotnet/runtime/blob/61d3943de41e948bb0ecf871b92eb456d2dd74d8/src/mono/mono/mini/mini-runtime.c#L3892-L3903
They would only chain to the previous signal handler
https://github.com/dotnet/runtime/blob/61d3943de41e948bb0ecf871b92eb456d2dd74d8/src/mono/mono/mini/mini-posix.c#L193-L210
only after attempting to walk native and managed stacks
https://github.com/dotnet/runtime/blob/61d3943de41e948bb0ecf871b92eb456d2dd74d8/src/mono/mono/mini/mini-exceptions.c#L2992-L3012

## Alternatives

If there is any particular reason to preserve the order of
sa_sigaction/sa_handler with respect to PROCNotifyProcessShutdown and
PROCCreateCrashDumpIfEnabled for CoreCLR, a config knob can be added to
allow Android CoreCLR to opt into the swapped ordering behavior. This
may be in the form of config property key/values
https://github.com/dotnet/runtime/blob/54ca569eb62800cdb725d776e3dd2e564028594d/src/coreclr/dlls/mscoree/exports.cpp#L237-L238
or `clrconfigvalues`. That way AndroidSDK/AndroidAppBuilder may opt-in
at build-time.

Given that the history of the ordering didn't reveal any problems with
swapping the order, we can fallback to this behavior if the order swap
causes problems down the line.

The other way around is more restrictive. Should we first introduce all
the overhead to enable an opt-in/opt-out config knob, and later discover
that no platforms need to invoke their previous handlers before
PROCNotifyProcessShutdown/PROCCreateCrashDumpIfEnabled, it seems harder
to justify removing the knob.
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.

1 participant