Skip to content

Review fixes: every Tier 1 item, release checks, stricter fixture matrix - #73

Merged
nmcc24 merged 13 commits into
masterfrom
release-notes-check
Nov 13, 2026
Merged

nmcc24 merged 13 commits into
masterfrom
release-notes-check

Conversation

@nmcc24

@nmcc24 nmcc24 commented Nov 13, 2026 •

Copy link
Copy Markdown
Owner

Fixes from the full-codebase review of 3.0.0-beta.3: all eight Tier 1 items, the release workflow's ordering and gates, and a stricter fixture matrix. Each fix comes with a fixture or test that fails without it.

Changelog

  • afce031 Check the release notes before tagging. New scripts/release-notes.sh <version> prints the version's CHANGELOG section and fails if it's missing or holds only whitespace. The check job runs it first, dry runs included, and the publish step uses it for the notes. Before, a missing section was found only after the tag was pushed, leaving a tag whose release a re-run couldn't publish.
  • 67ffbb5 Report XCTest failures at the full path of the failing line. SourceLocation is now (fileID:, filePath: StaticString, line:, column:), and file: is dropped from verify (both), verifyNoMoreInteractions (both), inOrder, enableDefaultStubImplementation and refuseActorDefaultImplementation. XCTFail gets the full #filePath: #file is the short Module/File.swift form in Swift 6, so Xcode couldn't place the failure. New XCTestFailureTest.testFailureIsReportedAtTheVerifyLine asserts the issue's file and line (it fails on master).
  • f2411bb Add hasLength(in:) and give hasLength(inRange:) back its Cuckoo 2 meaning. hasLength(in:) takes any range with its standard meaning. hasLength(inRange: Range<Int>, inclusive: Bool = true) matches as in Cuckoo 2 (1..<3 matches 3) and is deprecated with a migration message, so migrated tests keep passing and warn instead of silently matching differently. The migration guide also gains the review's missing deprecations and behaviour changes.
  • b2b504f Release: require master's CI, and tag on Ubuntu. The first job checks that CI passed succeeded on the commit being released (a dry run only warns). "Tag and publish" runs on Ubuntu with sha256sum, which gives SwiftPM's checksum, instead of waiting for a macOS runner.
  • c8aeaa2 Dependabot leaves swift-syntax majors alone; CLAUDE.md fixes. A new swift-syntax major needs its own CI pin, so its upper bound is raised by hand.
  • 8f04359 Fail the fixture matrix on a silent swiftc failure or a warning in a mock. It caught fixture 05's mock writing a bare Error (9 ExistentialAny warnings with upcoming features on), fixed to any Error.
  • 271a8cb Say what to do when a release's verify job fails. Releases are immutable, so: note the problem on the release and ship the next version.
  • f43ffd0 Answer an unstubbed rethrows call with a default value. Called with a non-throwing closure, it threw into a call site with no try and crashed the test process (signal 5). It now records the failure and returns the default value, sync and async. RethrowsTest (5 tests).
  • f4bee8a Keep associated types' where clauses in the mock. An associatedtype's where requirements join the protocol's, and requirements on nested types (Items.Element == Int, which were dropped or written as an invalid typealias) become a where clause on the mock and stub. Fixture 34 and a runtime test.
  • ed35612 Mock variadic parameters. The mock keeps the ..., and records and matches the arguments as an array, as the function receives them. Swift can't pass that array on as separate arguments, so forwarding to the real or default implementation crashes with a message, as for ~Copyable arguments. Fixture 33 covers methods, generic, async, static and closure variadics, subscripts, actors, main-actor and associated-type protocols, and a class.
  • 86c2fa1 Test, document and snapshot variadic parameters. VariadicTest (4 tests), Matching.md, CHANGELOG.
  • 550dd7c Give a protocol's mock the isolation it inherits. A protocol refining a @MainActor, global-actor, Actor or Sendable protocol got a nonisolated mock that didn't compile. Isolation now propagates from parents through any number of levels, unless the protocol states its own. Fixture 35 and InheritedIsolationTests (4). Every existing snapshot is unchanged.
  • 8ff9fb6 Leave the generator's dependencies out of a release's manifest. With a prebuilt generator (release tags only), the generator targets, its executable product, swift-syntax, ArgumentParser and TOMLDecoder are left out, so a project whose macro packages pin swift-syntax below 602 can add Cuckoo. Master is unchanged. The release smoke test adds a consumer pinned to swift-syntax 600.0.0..<602.0.0, which fails on the old manifest with the resolution error and passes now.

Verified

  • macOS (Xcode 27.2): swift test (466 runtime + 92 generator tests, 13 known issues, 0 warnings); CuckooTests on the iOS simulator; tvOS and watchOS arm64 build-for-testing.
  • Linux Swift 6.2, 6.3 (native) and 6.4 (swiftbuild): swift test with features off and on (558 tests, 13 known issues, 0 warnings), and the fixture matrix in all four CI modes.
  • scripts/build-docs.sh (Swift 6.3): no warnings.
  • The old-swift-syntax smoke consumer, with the 3.0.0-beta.3 bundle: passes on macOS and Linux (swift:6.3-jammy).

nmcc24 and others added 7 commits November 13, 2026 18:34
The Release workflow looked for the version's CHANGELOG section only when publishing, after it had pushed the tag.
A missing section then left a tag whose Package.swift points at a release that was never published, and a re-run
couldn't recover: the check job refuses a version whose tag exists. The check job now extracts the notes first,
dry runs included, through scripts/release-notes.sh, which the publish step uses too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
verify, verifyNoMoreInteractions and inOrder defaulted their file to #file, which a Swift 6 module evaluates as the
module-relative #fileID path, and passed it to XCTFail: Xcode couldn't place the failure on the line. SourceLocation
drops that redundant file, keeps filePath as a StaticString, and XCTFail gets the full #filePath. An XCTest test now
checks the recorded file and line; it failed before this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ning

beta.2 changed hasLength(inRange: 1..<3) to stop matching 3 without a warning, so tests moved from Cuckoo 2
compiled and silently matched differently. hasLength(in:) now has the standard range meaning. hasLength(inRange:)
is deprecated: with a half-open range, it includes the upper bound unless inclusive is false, as Cuckoo 2 did,
and its message says how to move; a disfavored generic overload keeps beta users' closed and partial ranges
working, renamed to in:. The migration guide covers it, with the deprecations and behaviour changes it missed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The first job checks that CI passed succeeded on the commit being released
(a dry run only warns), so a release ships only what passed the merge gate.

Tag and publish ran on macOS only for swift package compute-checksum, which is
the zip's SHA-256: it waited 17 minutes for a runner on 3.0.0-beta.3. It runs on
Ubuntu with sha256sum now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new swift-syntax major needs its own CI pin, so its upper bound is raised by
hand. CLAUDE.md now says each macOS image runs two jobs, and describes the
release's checks and immutable releases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mock

The matrix counted a fixture as passing when its log had no error line, so a swiftc that exited non-zero
without one passed, and so did a generated mock with warnings, which the zero-warnings rule covers but the
package's warnings-as-errors never sees in these modes. Both now fail the fixture. The check caught fixture 05
writing a bare Error, which ExistentialAny warns about in the mock that copies it; it writes any Error now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The verify jobs run after the release is public, and releases are immutable, so a failure can't be fixed by
replacing the release. The workflow's header says to note it in the release and ship the next version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

nmcc24 commented Nov 13, 2026

Copy link
Copy Markdown
Owner Author

CI passed failed on afce031 only because the two macos-26 legs never got a runner (runner id 0) and were cancelled; every job that ran passed. More commits for this PR are about to be pushed, which re-runs CI, so no re-run is needed for this one.


Generated by Claude Code

@nmcc24 nmcc24 changed the title Check the release notes before tagging Review fixes: release checks, XCTest file paths, hasLength(in:), stricter fixture matrix Nov 13, 2026
nmcc24 and others added 6 commits November 13, 2026 21:47
An unstubbed rethrows member threw CuckooError.unstubbedCall, which reached call sites that passed closures that
don't throw and so had no try: Swift trapped, and the whole test process died with no message. callRethrows now
records the failure and returns a default value, as a non-throwing member does. RethrowsTest covers the sync and
async members, with throwing and non-throwing closures, stubs and thenThrow; the first test crashed before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An associated type's own where clause was ignored, so `associatedtype Element where Element: Equatable` gave a
mock that didn't conform. Its requirements now join the protocol's, which constrain the mock's generic
parameters or fix them as typealiases. A requirement on a nested type, such as `Items.Element == Int`, was
written as an invalid typealias or dropped; the mock and its stub now repeat it in their own where clause.
Fixture 34 and ConstrainedAssociatedTypesTest cover both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The generator dropped a variadic parameter's ..., so the mock didn't conform.
It keeps it now, and records and matches the arguments as an array, as the
function receives them: when(stub.log(equal(to: ["a", "b"]))). Swift can't pass
that array on as separate arguments, so forwarding to the real or default
implementation crashes with a message, as for ~Copyable arguments. Fixture 33
covers methods, generic, async, static and closure variadics, subscripts,
actors, main-actor and associated-type protocols, and a class.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Records fixture 33's snapshot and the runtime sources' new variadic protocol and class. VariadicTest stubs,
verifies and captures a variadic argument as an array, with and without values, through a then closure, and on
a class mock. Matching.md and the changelog say how to match one, and that such a member can't forward to its
real or default implementation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A protocol that refines a @mainactor, global-actor, Actor or Sendable protocol, and states no isolation of its
own, is isolated as its parent in Swift. The generator merged the parent's members but not that, so the mock
was nonisolated and called main-actor requirements from a nonisolated context. A protocol without a stated
isolation now takes its parents' global actor (replacing the module's default isolation), becomes an actor
protocol if one refines Actor, and Sendable if one is. Its members, inherited ones included, are re-parented to
the merged protocol, so each takes its isolation and an actor mock's closures receive the right mock type.
Fixture 35 covers three levels in both isolation modes; InheritedIsolationTests stubs and verifies each kind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A release's plugins run the prebuilt generator, but its manifest still declared the source generator and its
dependencies, so SwiftPM resolved them: swift-syntax's 602.0.0..<605.0.0 kept a package whose macro packages pin
an older swift-syntax from resolving Cuckoo (Brightify#547, which the prebuilt generator was for), and
macOS still downloaded 115 MB of swift-syntax prebuilts. With prebuiltGenerator set, Package.swift now leaves out
the CuckooGenerator target, its tests and product, and the swift-syntax, ArgumentParser and TOMLDecoder
dependencies; master is unchanged. The smoke test's consumer also depends on swift-syntax 600.0.0..<602.0.0 and
fails unless a 601 release resolves: it fails on the previous manifest with the resolution error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nmcc24 nmcc24 changed the title Review fixes: release checks, XCTest file paths, hasLength(in:), stricter fixture matrix Review fixes: every Tier 1 item, release checks, stricter fixture matrix Nov 13, 2026
@nmcc24
nmcc24 merged commit d2079ab into master Nov 13, 2026
15 checks passed
@nmcc24
nmcc24 deleted the release-notes-check branch November 13, 2026 22:47
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