Skip to content

Ergonomics round 2 - #3

Merged
sbokatuk merged 12 commits into
mainfrom
ergonomics-round-2
Jul 26, 2026
Merged

sbokatuk merged 12 commits into
mainfrom
ergonomics-round-2

Conversation

@sbokatuk

Copy link
Copy Markdown
Owner

No description provided.

sbokatuk and others added 12 commits July 26, 2026 13:50
Two ways the native build could quietly ship something broken, closed:

* Every xcframework is now checked with nm the moment it is created: a
  canonical exported symbol per framework (the ObjC class behind the
  package's entry point, or the Swift nominal type descriptor for the
  three frameworks with no ObjC surface), asserted on both architecture
  slices. The pbxproj patches assert they applied; this asserts they
  worked - a patch gone stale can still archive, just with the module
  gutted, and that used to surface as a MissingMethodException in a
  consuming app rather than a red build here.

* The per-framework dSYM copy loses its `2>/dev/null || true`: these are
  the only symbolication data the binaries will ever have, so a missing
  one fails the build instead of shipping a release whose crashes can
  never be symbolicated. A final count - one dSYM per scheme plus
  OpenTelemetryApi - guards the copies and the scheme list drifting
  apart before BUILD-INFO.txt records the build as done.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The slice check accepted any ios-*maccatalyst directory, but the README
promises exactly ios-arm64_x86_64-maccatalyst - and the difference is
not cosmetic: ios-arm64-maccatalyst would pass the shape check and break
every Intel consumer. The build script now asserts the same literal path
at build time; this is the packed-artifact end of that promise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The build record - dd-sdk-ios and OTEL versions, Xcode, SDK, timestamp -
was written into libs/ and then never left CI, which defeats its stated
purpose: it exists for the human comparing two builds that claim the
same version. It now rides the dsyms artifact (copied in, so the
artifact layout the release zip expects stays flat) and therefore lands
in the release-attached dsyms-<version>.zip, whose packaging step
asserts the record is present rather than assuming.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every release run now writes build provenance attestations for the
.nupkg files and the dsyms zip - a signed, public statement binding the
exact bytes to this repository, tag, commit and workflow, verifiable
with `gh attestation verify`. Attested before the nuget.org push, so a
failure to attest means nothing was published anywhere.

The README grows a "Verifying a build" section that says what an
attestation proves and what it does not, and documents the stronger
path: rebuild at the tag with the Xcode BUILD-INFO.txt records and
compare exported symbol lists - byte-identity is off the table with an
Xcode toolchain, and the section is honest about that.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The key covered the native versions and the build script's hash, and
the comment waved Xcode away as "select-xcode pins it" - but the pin is
an SDK *line*, not a compiler: an action config change or the runner
image swapping 26.0.1 for 26.0.2 changes the toolchain under an
unchanged key, and the cache would happily serve binaries an older
Xcode built. The workflow now asks the selected Xcode for its version
and build ("26.0.1-17A400") and puts the answer in the key.

Asked in a workflow step, not output from the select-xcode action: that
action is a hand-synced verbatim copy of DatadogNet.iOS's, now guarded
by the tooling drift check, so this repository's extra need lives on
this side of the sync boundary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The binding-drift job only ever ran when something here changed - pull
requests and tags - but what it guards moves on its own. Two changes:

* The job moves to a reusable workflow (binding-drift.yml); build.yml
  still calls it on every PR and release, and a new weekly schedule
  (weekly-drift.yml, plus workflow_dispatch) calls it between releases.
  The schedule also asks the question nothing used to ask: has
  DatadogNet.iOS's src/ moved past the pinned commit? When it has, one
  idempotent issue - matched by title among open issues, so closing it
  re-arms the alert - lists the changed files.

* The drift job's manifest grows the three hand-synced tooling copies:
  merge-packages.py, the select-xcode action, CheckReadmeVersions.sh.
  Their comments legitimately differ (each copy documents its own
  repository), so the comparison strips whole-line #-comments and blank
  lines - and for merge-packages.py the module docstring, which its
  header names as the one sanctioned divergence. What survives is code,
  and code drift fails the job.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The tag alone decided which native line got released, with no
cross-check against the branch being released from - so v3.15.0.1
mistyped against a 3.14.0 branch would happily publish packages the
branch never prepared. The version job now fails on a mismatch between
the tag's first three components and DatadogNativeVersion, before
anything builds.

Deliberate different-line releases stay possible - that flexibility is
why the tag drives the version - through a documented, narrow override:
the repository variable DATADOG_RELEASE_LINE_OVERRIDE names the one
line being blessed, so the next typo still fails.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e id

The SessionReplay package description promised session recording with
no platform caveat, while the README, the support-status note and the
sample all say the same thing: upstream's recorder is iOS/iPadOS-only
and records nothing on Catalyst. A reader on nuget.org saw only the
promise. The description now carries the caveat in one sentence,
aligned with the README's wording - descriptions are owned here, not
synced from the iOS repository, so nothing drifts.

Also fixes the Directory.Build.props comment naming the packages
DatadogNet.<Module>.MacCatalyst; the actual scheme is .Mac.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A Datadog SDK upgrade rewrites more pins than anyone reliably remembers
- two version properties, the OTEL companion (which must match what the
new dd-sdk-ios tag's Cartfile.resolved says), the README's install
snippets, a release-notes file. The new script does all of it in one
move: it reads the OTEL pin from the tag on GitHub before touching
anything (a nonexistent tag leaves the tree untouched), refuses
same-version runs that would silently reset the binding revision,
scaffolds docs/release-notes/<version>.md without ever overwriting
hand-written notes, finishes by running CheckReadmeVersions.sh, and
prints the steps a script cannot do - sync, build, test, tag.

The README's upgrade section now starts with it, and the props comment
points at it instead of describing the manual ritual.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Release is the configuration consumers actually ship, and the trimming
and linker behaviour it turns on is exactly where binding packages
break after compiling clean in Debug - so the sample job becomes a
two-leg matrix. The Release leg disables codesigning and packaging:
runners hold no signing identity and nothing here ships; the check is
that Release links.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Binding revision 3 on the unchanged dd-sdk-ios 3.14.0: release notes
leading with what a consumer can now rely on - provenance attestations
and the Verifying a build path, the hard dSYM guarantee, the nm smoke
checks and exact-slice assertion, the honest SessionReplay description -
with the repository machinery (weekly drift guard, tag cross-check,
Xcode-aware cache, Release sample leg, the bump script) below the fold.
README pins bumped; CheckReadmeVersions.sh green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The weekly-drift issue body linked its own workflow relatively, which
resolves from an issue page only by URL-arithmetic luck - now absolute
via GITHUB_SERVER_URL. And build.yml's header still described the cache
key as versions + script hash; the resolved Xcode joined it a few
commits ago.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sbokatuk
sbokatuk merged commit d97a4d2 into main Jul 26, 2026
6 checks passed
@sbokatuk
sbokatuk deleted the ergonomics-round-2 branch July 26, 2026 19:35

This branch was previously deployed

1 inactive deployment
nuget.org — 41d939b2 Deployed Jul 26, 2026 by sbokatuk via publish beta to nuget.org #4
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