Skip to content

M16: API freeze, packaging, and docs — ships 1.0.0-rc.1 (Phase 6)#16

Merged
lgamorim merged 22 commits into
masterfrom
feature/M16-api-freeze-and-ship
Jul 13, 2026
Merged

M16: API freeze, packaging, and docs — ships 1.0.0-rc.1 (Phase 6)#16
lgamorim merged 22 commits into
masterfrom
feature/M16-api-freeze-and-ship

Conversation

@lgamorim

@lgamorim lgamorim commented Jul 12, 2026

Copy link
Copy Markdown
Owner

M16 — API freeze & NuGet 1.0 (Phase 6, Ship)

Freezes the public API and finalizes packaging for the 1.0 release. Ships as 1.0.0-rc.1 for review; the stable 1.0.0 follows as a separate GA-promotion step once the candidate is validated. No functional change to the query, verification, or migration engines from 0.5.0.

Commits

  1. Open Phase 61.0.0-preview.1 + milestone.
  2. Strong-name all assemblies — one committed sqlbound.snk; InternalsVisibleTo grants carry the shared public key.
  3. Freeze the public APIMicrosoft.CodeAnalysis.PublicApiAnalyzers on the 7 shipping libraries; nullable-annotated baselines fail the build on surface drift.
  4. Narrow the migrations surfaceMigrationPlan / MigrationReverter / MigrationStatusReportinternal (no external consumers; widening later is non-breaking, narrowing after 1.0 is not).
  5. Complete package metadata — embedded NuGet README + per-package tags.
  6. Reproducible buildsContinuousIntegrationBuild (CI-gated) + SDK SourceLink verified.
  7. CHANGELOG[1.0.0-rc.1] with per-version compare links.
  8. Gated release workflow — builds/packs on v*.*.* tags; nuget.org publish is opt-in only (manual workflow_dispatch with publish=true).
  9. Docs — "Using SqlBound alongside Dapper" guide, ADR 0008 (stability/strong-naming/signing/docs decisions), README RC status + license.
  10. DocFX docs site — API reference from XML docs + conceptual pages, deployed to GitHub Pages.
  11. Close phase → 1.0.0-rc.1.

Verification

  • Build clean (0 warnings, TreatWarningsAsErrors).
  • 508 tests, 0 skipped — all provider integration suites ran against live containers.
  • dotnet format --verify-no-changes clean; all 9 packages pack (.nupkg + .snupkg).
  • docfx builds the site with 0 errors.

Decisions (per ADR 0008)

  • Strong-naming: yes (one-way door, fixed at 1.0). Signing: nuget.org repository signing; author signing deferred. Docs site: DocFX + Pages. Publishing: double-gated (prerelease version and disabled workflow switch).

Maintainer actions (not done by this PR — repository settings)

  • Add the NUGET_API_KEY secret before any nuget.org publish.
  • Enable GitHub Pages with source = GitHub Actions before the docs site deploys.
  • Configure branch protection on master (require PR, disallow direct pushes, squash-merge).

After merge (separate GA step, not now)

  • Tag v1.0.0-rc.1 on the squash commit; the Phase 6 milestone stays open until GA.
  • GA promotion: bump → 1.0.0, move API baselines Unshipped→Shipped, CHANGELOG + README → Done, tag v1.0.0, close the milestone, then flip the release workflow's publish gate on.

🤖 Generated with Claude Code

lgamorim and others added 11 commits July 12, 2026 20:00
Phase 6 (Ship) begins the API-freeze and packaging work that leads to the
1.0 release. Start the phase's prerelease line at 1.0.0-preview.1; the phase
closes at 1.0.0-rc.1 for review before the 1.0.0 GA promotion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A strong-named assembly cannot reference an unsigned one, and every peer in
the data-access space (EF Core, Dapper, Npgsql, Microsoft.Data.*) is signed;
shipping 1.0 unsigned would permanently lock out strong-named consumers, and
adding a name later is a binary-breaking change. Fix the identity now.

All projects share one committed key (sqlbound.snk) — strong naming is an
identity token, not a security boundary, so the key is not a secret. Setting
the PublicKey property lets the SDK stamp every InternalsVisibleTo with the
friend's key automatically, so the existing test/generator friend grants keep
resolving against the signed assemblies.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds Microsoft.CodeAnalysis.PublicApiAnalyzers to the seven shipping library
packages (opted in via <TrackPublicApi>, wired centrally in
Directory.Build.targets so it is skipped for tests, the CLI tool, and the
Roslyn component). The analyzer fails the build under TreatWarningsAsErrors if
the public surface drifts from PublicAPI.{Shipped,Unshipped}.txt, making the
post-1.0 SemVer commitment tool-enforced rather than prose.

Nothing has shipped to NuGet yet, so the entire 1.0 surface is recorded in
Unshipped.txt (with #nullable enable so nullability is tracked); the GA
promotion moves it to Shipped.txt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MigrationPlan, MigrationReverter, and MigrationStatusReport are pure decision
helpers that MigrationRunner composes internally; no code outside
SqlBound.Migrations references them, and their tests reach them through the
existing InternalsVisibleTo grant. Demoting them to internal before the 1.0
freeze keeps the public surface to exactly what consumers need (the model,
the ledger/admin contracts, MigrationDirectory, MigrationRunner, the status
types, and the exceptions). Widening later is a non-breaking change; narrowing
after 1.0 would not be.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a shared, package-oriented README (docs/nuget/README.md) embedded in
every package via PackageReadmeFile, plus PackageTags: a common set centrally,
with provider- and tool-specific tokens appended per package for discovery.
The repo README stays repo-facing (its relative links would render broken on
nuget.org), so the packages carry their own with absolute links.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SourceLink already ships in the .NET 8+ SDK and is active through the
PublishRepositoryUrl + EmbedUntrackedSources settings, mapping sources to
raw.githubusercontent.com by commit; symbol consumers can step into the exact
committed code from the snupkg. Add ContinuousIntegrationBuild, gated on the
CI environment variable so it normalizes source paths for byte-reproducible
release output without disabling local debugger path mapping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keep-a-Changelog history from Phase 1 through the 1.0.0-rc.1 candidate, with
per-version compare links. The top entry is the RC being cut this phase; it is
promoted to [1.0.0] at the GA release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Builds, tests, and packs on any v*.*.* tag and uploads the packages as
artifacts, but never publishes automatically. Pushing to nuget.org is a
separate, deliberate step: a manual workflow_dispatch run with publish=true,
which also requires a maintainer to have added the NUGET_API_KEY secret. This
keeps the 1.0.0 release an opt-in action and lets the release candidate be
built and reviewed without any risk of an accidental publish.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the 'Using SqlBound alongside Dapper' guide (docs/dapper-coexistence.md)
covering the shared connection/transaction, the deliberate absence of
Query*/Execute* method clashes, and a side-by-side example. Adds ADR 0008
recording the 1.0 public-API stability commitment, strong-naming, the
repository-signing-over-author-signing choice, and the DocFX site decision.

Updates the README to the release-candidate state: status line and roadmap
row 6 read 'Release candidate (v1.0.0-rc.1)' rather than Done, the ADR index
gains 0008, and the License section matches the house wording used across
these repos.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a DocFX site that generates the API reference from the XML doc comments
the build already enforces and renders the existing docs/*.md guides and ADRs,
so the site reuses committed content instead of duplicating it. A Pages
workflow (docs.yml) builds and deploys it on every push to master; it requires
GitHub Pages to be enabled with the GitHub Actions source (a repository
setting). Generated output (_site/, api/) is gitignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bumps the prerelease suffix from -preview to -rc.1: the phase's work is
complete and this is the candidate for 1.0.0. The suffix drops to a clean
1.0.0 at the GA promotion, once the candidate has been reviewed. Full
verification passed at this version: build clean (0 warnings), 508 tests green
with 0 skipped across all provider containers, format clean, and all nine
packages pack.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@lgamorim lgamorim added this to the Phase 6 — Ship (1.0.x) milestone Jul 12, 2026
lgamorim and others added 11 commits July 12, 2026 22:37
Introduces assets/logo.png (the sqlbound wordmark) and wires it in three
places: PackageIcon on every package (embedded, shown in the NuGet gallery and
IDE), the top of both the repo and packaged READMEs, and the DocFX site header
via _appLogoPath. The packaged README references it by absolute raw URL, as
nuget.org does not resolve relative image paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Now that GitHub Pages is enabled, point NuGet visitors to the rendered guides
and API reference at the docs site, keeping the GitHub link for source, issues,
and the changelog. The docs URL goes live once the docs workflow runs on master.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Match the repository README's 'Copyright ... Licensed under the Apache License
2.0' wording for consistency, using an absolute link to the LICENSE file since
nuget.org does not resolve relative paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The MySQL parameter scanner matched the second '@' of a system variable
such as @@sql_mode or @@session.sql_mode as a parameter placeholder, so
prepare declared a bogus parameter and verification then demanded a C#
method parameter that should not exist. Skip the whole (optionally
scoped) system-variable reference instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A manual workflow_dispatch run builds whatever ref the "Run workflow"
dropdown selects — master by default, not the release tag — so a publish
could silently ship a stale or unintended state. The publish path now
requires an expected-version input and fails before pushing unless the
packed output contains exactly that version.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The scanner treated any -- as a line comment, but MySQL only recognizes
-- when followed by whitespace or the end of the statement; "1--@x" is
the arithmetic expression 1 - (-@x), whose placeholder the scanner
silently dropped along with the rest of the line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
FetchScalarAsync fell back to Convert.ChangeType, which leaks a bare
InvalidCastException for non-IConvertible targets such as Guid; wrap it
(and Format/Overflow failures) in an InvalidOperationException naming
the actual and requested types, keeping the method's one documented
failure exception. The no-value message also claimed "no value" when
the database may have returned a NULL — say so. While here, align the
command disposal with the rest of the codebase (await using).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DropAsync deleted only the main database file. The -wal/-shm sidecars
are checkpointed away on a clean close, but a crashed process leaves
them behind, and stale ones would poison a database later created at
the same path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Neither quick-start snippet compiled as pasted: the repo README was
missing 'using SqlBound;' for the attributes, the NuGet README was
missing 'using System.Data.Common;' for DbConnection (not covered by
implicit usings).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
NuGet.org sanitizes raw HTML when rendering the README, so the
<p>/<img> block was stripped and the logo never appeared. Markdown
image syntax renders; the width and centering it drops were HTML-only
and were being stripped regardless.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
NuGet renders the package icon in a square slot, where the 2:1 wordmark
letterboxed to an illegibly small mark. Point PackageIcon at a purpose-
built 128x128 square glyph and pack that instead. The wordmark logo is
no longer packed at all — both READMEs load it by absolute URL, so it
need not travel inside every package.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@lgamorim lgamorim merged commit 94c91c5 into master Jul 13, 2026
4 checks passed
@lgamorim lgamorim deleted the feature/M16-api-freeze-and-ship branch July 13, 2026 22:00
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