build: add a public-API baseline and package validation#280
Merged
Conversation
The shipping libraries commit to SemVer but had no automated breaking-change gate: a repo-wide search found no PublicApiAnalyzers, no package validation, no ApiCompat baseline. A removed overload, a narrowed return type, or a renamed member could ship silently under a version that promises compatibility. Pre-release is the cheapest moment to install this, since the first published surface becomes the baseline. Wire both guards once in build/PublicApiBaseline.props, imported by the four packable libraries -- the lib train (FirstClassErrors, FirstClassErrors.Testing, FirstClassErrors.RequestBinder) and Dummies: * PublicApiAnalyzers tracks each project's surface in committed PublicAPI.Shipped.txt / PublicAPI.Unshipped.txt files, one pair per target framework (Dummies' net8.0 leg carries the modern generators netstandard2.0 lacks). RS0016/RS0017 stay warnings locally and become errors under the CI warnings-as-errors ratchet, so a surface change fails the build until the same change records it. * EnablePackageValidation runs ApiCompat on pack -- baseline-less for now (the same-package cross-TFM check), ready to gate against a published version via PackageValidationBaselineVersion once the surface stabilises. The issue scoped this to Dummies; it is extended to the lib train because those packages carry the same SemVer promise and the mechanism is identical. RS0026/RS0027 (the optional-parameter overload design rules) are disabled deliberately: they fire on the deliberate central fluent APIs (Outcome.Then/Recover/Finally/Try, Any.Reproducibly), where enforcing them would demand a breaking redesign -- a separate call for the maintainer, not a baseline chore. Refs: #221 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LuKEgwmiNthNBXEXidrbhV
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Install a committed public-API baseline (
Microsoft.CodeAnalysis.PublicApiAnalyzers) and package validation (EnablePackageValidation) on the four shipping libraries, so an accidental breaking change to the public surface — a removed overload, a narrowed return type, a renamed member — fails the build until the same change records it. Pre-release is the cheapest moment to install this: the first published surface becomes the baseline.Type of change
No product code changed.
Changes
Directory.Packages.props: pinMicrosoft.CodeAnalysis.PublicApiAnalyzers5.6.0(CPM, alongside the otherMicrosoft.CodeAnalysis.*5.6.0 packages).build/PublicApiBaseline.props(new, mirrorsbuild/Net472TestFloor.props): references the analyzer (PrivateAssets=all), wires per-target-frameworkPublicAPI.Shipped.txt/PublicAPI.Unshipped.txt, enablesEnablePackageValidation, and disablesRS0026/RS0027(see note).FirstClassErrors,FirstClassErrors.Testing,FirstClassErrors.RequestBinder(thelibtrain) andDummies(thedumtrain).Dummiestracks its two divergent surfaces separately (341 entries onnetstandard2.0, 411 onnet8.0— the net8-only generatorsAnyDateOnly/AnyTimeOnly/AnyInt128/AnyUInt128/AnyHalf).CONTRIBUTING.md(+ French translation): a "Public API baseline" section on how to accept an intended surface change.Scope. #221 scoped this to
Dummies; it is extended to thelibtrain because those packages carry the same SemVer promise and the mechanism is identical (no separate lib-train issue existed). UnlikeDummies, thelibtrain already has a published baseline (lib-v0.1.0-preview.1) to gate against later.RS0026/RS0027are optional-parameter overload design rules — distinct from the baseline-drift rules this PR is about. They fire on the deliberate central fluent APIs (Outcome.Then/Recover/Finally/Try/Create/Error,Any.Reproducibly), where enforcing them would demand a breaking overload redesign (overlapping the pre-v1 Outcome API-symmetry review, #242). Disabled deliberately (scoped, with a rationale comment) and surfaced for @Reefact rather than acted on silently.Testing
dotnet build FirstClassErrors.sln— green, including under the CI warnings-as-errors ratchet (GITHUB_ACTIONS=true).dotnet test FirstClassErrors.sln— 1434 passed, 0 failed, 0 skipped (10 test projects).FirstClassErrors.Analyzers.UnitTests) — 132 passed.Additional checks:
RS0016on both target frameworks; removing it goes green again.dotnet pack(net8.0is a clean superset ofnetstandard2.0, no suppressions needed).FirstClassErrorsagainst0.1.0-preview.1restores the baseline package and ApiCompat flags the pre-1.0 drift. Left baseline-less by default (PackageValidationBaselineVersionunset) so intended pre-1.0 breaks don't block CI.Documentation
doc/updateddoc/handwritten/for-users/README.fr.md) updated if user-facing behavior changedCONTRIBUTING.mdand its French translationdoc/handwritten/for-users/CONTRIBUTING.fr.mdboth gained the "Public API baseline" section (bilingual parity kept). The committedPublicAPI.*.txtfiles are themselves the API record.Architecture decisions
Proposed: ADR-____Checked against the ADR base (ADR-0004). ADR-0011 (Dummies as a standalone, zero-dependency package) verified compliant: the analyzer is
PrivateAssets=all, and the packedDummiesnuspec has empty dependency groups and ships onlyDummies.dll. The baseline mechanism is release-engineering hygiene — the Dummies architecture audit (§4.7 / §11 item 7) classified it as a "guard", not an ADR-worthy decision — so no ADR is drafted. The one embedded policy choice (disablingRS0026/RS0027) is documented in-code and left to @Reefact; judged below the ADR threshold but flagged here for a deliberate call.Related issues
Closes #221
Generated by Claude Code