Public API Tracking
The public surface of the kernel packages is declared in text files checked into the repository, enforced by Roslyn analyzers at build time, guarded against breaking changes at release time, and published as one frozen documentation site per release. This page describes the three mechanisms and the contributor workflow they impose.
The declared surface
Projects opt in with <CosmosTrackPublicApi>true</CosmosTrackPublicApi> in their .csproj (wired in Directory.Build.props). Today that covers Cosmos.Kernel.System; Cosmos.Kernel.Core and the HAL packages follow once their surfaces are audited.
An opted-in project references Microsoft.CodeAnalysis.PublicApiAnalyzers, which requires every public symbol to appear in one of two files next to the .csproj:
| File | Contents |
|---|---|
PublicAPI.Shipped.txt |
The surface of the last release. Frozen: it only changes when a release is cut. |
PublicAPI.Unshipped.txt |
Surface added, changed, or removed since then. Emptied into Shipped at release time. |
Two diagnostics enforce the contract, both raised as build errors:
| Rule | Meaning |
|---|---|
RS0016 |
A public symbol exists in code but is not declared in either file. |
RS0017 |
A declared symbol no longer exists in code. |
The effect is that any change to the public surface, deliberate or accidental, must land in the same commit as a diff of PublicAPI.Unshipped.txt, where the review can see it.
Three categories stay out of the files, the first two through .editorconfig overrides that set RS0016/RS0017 to none under their paths:
- The vendored directories (
SharpZipLib, the PNG decoder, the TrueType fonts). Their types that are stillpublicleak into the package anyway; making theminternalis part of the pre-release surface cleanup, and keeping them out of the files means that cleanup will not churn the declared surface. - The generated
KernelVersion.g.csthat carriesKernel.VersionString: the declared-API format records constant values, and this one changes with every version stamp. internalsymbols, including everything exposed to the test kernels throughInternalsVisibleTo.
Changing the public API
- Make the code change. The build now fails with
RS0016orRS0017. - Run
make apifrom the repository root. It rebuilds the tracked projects and applies the analyzer's code fixes toPublicAPI.Unshipped.txt. The IDE quick fix ("Add to public API") on each diagnostic is equivalent. - Commit the txt diff together with the code.
Removing or changing a symbol that already shipped is recorded as a *REMOVED* line in Unshipped, which is exactly what it is: a breaking change, visible as such in the PR. Before the first release, while Shipped is empty, a removal simply drops the line.
Package validation
The same CosmosTrackPublicApi flag enables NuGet package validation on the project, and Directory.Build.props holds the baseline knob:
<CosmosApiBaselineVersion></CosmosApiBaselineVersion>
The property is empty until the first Gen3 release is published on NuGet.org. Once it is pinned to that version, two guards activate on their own:
PackageValidationBaselineVersionmakes every pack compare the package against the baseline release and fail on binary breaking changes.- The
API compatibility guardstep inrelease.ymldownloads the baseline package from NuGet.org and runs Microsoft.DotNet.ApiCompat.Tool against the freshly built one, as a final gate before publishing.
An intentional breaking change is recorded in a CompatibilitySuppressions.xml next to the project (dotnet pack /p:ApiCompatGenerateSuppressionFile=true generates it), so it too becomes a reviewable diff.
Versioned docs
The docs site at the root of gh-pages follows the main branch: it is the dev documentation, rebuilt by build-docs.yml on every docs push. Releases get frozen copies next to it, published by the publish-docs job of release.yml when a v* tag is pushed:
| Path | Contents |
|---|---|
/ |
Dev docs, follows main. |
/vX.Y.Z/ |
The docs as built from tag vX.Y.Z, never rebuilt. |
/latest/ |
Alias of the newest release, stable URL for external links. |
/versions.json |
The release list, newest first, plus the latest marker. |
The version dropdown in the site navbar comes from docs/templates/custom/public/main.js. It reads versions.json, lists dev plus every release, and keeps the reader on the same page across versions when the page exists there. It only appears once versions.json exists, i.e. after the first tagged release; until then the site behaves exactly as before.
The dev deploys use keep_files: true so they never wipe the v*/ folders, at the cost of deleted dev pages lingering on the branch until overwritten.
Release checklist
What cutting a release changes in this system:
- Tag
vX.Y.Z. CI builds the packages, runs the API compatibility guard, publishes to NuGet.org, and freezes/vX.Y.Z/docs. - Move the contents of
PublicAPI.Unshipped.txtintoPublicAPI.Shipped.txt(drop the*REMOVED*pairs), leavingUnshippedempty. - Set
CosmosApiBaselineVersioninDirectory.Build.propstoX.Y.Zso the next cycle validates against this release.