diff --git a/.claude/agent-notes.md b/.claude/agent-notes.md index 85e01cbd..f7763cc7 100644 --- a/.claude/agent-notes.md +++ b/.claude/agent-notes.md @@ -15,3 +15,6 @@ Standing always/never directives and corrections from the human. Agents must rea - ALWAYS append corrections and always/never directives to `.claude/agent-notes.md` proactively; ALWAYS write project-scoped facts to `.claude/memory/` (with an index line in `MEMORY.md`). - NEVER store project-scoped memories in a native or global memory system (Claude Code `~/.claude/projects/*/memory/`, Cursor memories, etc.) — use `.claude/memory/` in this repo instead. - NEVER run bare `git stash`/`git stash pop`/`git stash drop` in this repo — the stash stack is shared across ALL worktrees, so a pop in one worktree can bury or restore another branch's WIP; commit to your own branch instead. +- CI: in-development Swift branches (e.g. 6.4 snapshots) belong IN the `build-ubuntu` matrix as a swift entry carrying an `image` override (ConfigKeyKit pattern: `{"version":"6.4","image":"swiftlang/swift:nightly-6.4.x"}` plus a `container:` fallback expression) — NEVER as a separate job. Supersedes the earlier "no nightly toolchains" directive. +- Repo-wide CI version bumps (Xcode/simulator/toolchain) DO extend into the `Examples/` subrepos — update BushelCloud and CelestraCloud in the same pass rather than deferring them to their own repos. +- Follow sibling brightdigit repos (e.g. ConfigKeyKit) for current CI workflow shape before inventing a new one. diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md index 176a3f42..9ccba95a 100644 --- a/.claude/memory/MEMORY.md +++ b/.claude/memory/MEMORY.md @@ -15,7 +15,7 @@ Project-scoped agent memory for MistKit. This directory **replaces** any native - [wasm CI failure signatures](reference_wasm_ci_signatures.md) — Two distinct wasm failures: silent exit-1 (OOM on big test target) vs curl exit-7 (SDK download flake, just re-run) - [Swift Testing availability guard](feedback_swift_testing_availability.md) — Never annotate @Suite types with @available; use guard #available inside @Test functions instead - [GitHub Action pinning preference](feedback_action_pinning.md) — Use @v for brightdigit-owned actions; pin third-party actions explicitly -- [CI Swift matrix preferences](feedback_ci_swift_matrix.md) — Keep Swift 6.1 in full matrix; no nightly toolchains in CI +- [CI Swift matrix preferences](feedback_ci_swift_matrix.md) — Keep Swift 6.1 in full matrix; in-dev Swift branches (6.4 snapshots) ride in the build-ubuntu matrix via an `image` override (ConfigKeyKit pattern), never a separate job - [Test parent type — enum vs struct](feedback_test_parent_enum_vs_struct.md) — Use enum only when the type-under-test has multiple test files; otherwise simple struct - [Explicit access modifier on every import](feedback_explicit_import_access.md) — Always write `internal import Foo` etc.; never bare `import Foo` - [Capture follow-up findings in issues, not code](feedback_findings_to_issues_not_code.md) — When verification surfaces an out-of-scope fix, write it up on the relevant GitHub issue and stop; don't expand the current PR diff --git a/.claude/memory/feedback_ci_swift_matrix.md b/.claude/memory/feedback_ci_swift_matrix.md index c7de9a92..ff8950eb 100644 --- a/.claude/memory/feedback_ci_swift_matrix.md +++ b/.claude/memory/feedback_ci_swift_matrix.md @@ -1,11 +1,38 @@ --- name: CI Swift matrix preferences -description: For MistKit CI matrices, keep Swift 6.1 in the full matrix where it still compiles; do not include nightly Swift toolchains +description: Keep Swift 6.1 in the full matrix; carry in-development Swift branches (6.4 snapshots) as a build-ubuntu matrix entry with an `image` override, never as a separate job type: feedback originSessionId: d667433a-6b44-41ff-a056-470ceb1a865e --- -When designing or updating MistKit CI Swift matrices: include all stable Swift versions back to **6.1** in the full matrix where the code still compiles; do **not** add nightly toolchain entries (`swiftlang/swift:nightly-*` or `nightly: true` matrix flags). +When designing or updating MistKit CI Swift matrices: include all stable Swift versions +back to **6.1** in the full matrix where the code still compiles. -**Why:** The user wants concrete, reproducible CI signal. Nightly toolchains break unpredictably and create flake noise without protecting any actual user. Keeping 6.1 in the full matrix preserves the support window for downstream consumers still on older toolchains. +**In-development toolchains belong IN the `build-ubuntu` matrix, not in a job of their own.** +The user asked for Swift 6.4 (`release/6.4.x` snapshot) coverage in 2026-08 and pointed at +[ConfigKeyKit's workflow](https://github.com/brightdigit/ConfigKeyKit/blob/main/.github/workflows/ConfigKeyKit.yml) +as the reference shape. The pattern: -**How to apply:** When editing `.github/workflows/MistKit.yml`, `swift-source-compat.yml`, MistDemo's workflow, or any subrepo workflow, default to a stable-only Swift matrix `[6.1, 6.2, 6.3, …]`. Drop any `nightly: true` matrix entries and any `swiftlang/swift:nightly-*` containers. Only re-introduce nightly if the user explicitly asks. If a specific Swift version genuinely doesn't compile, prefer documenting and fixing rather than silently dropping it from the matrix. +- Give the swift matrix entries an optional `image` key and let the snapshot entry carry it: + `[{"version":"6.2"},{"version":"6.3"},{"version":"6.4","image":"swiftlang/swift:nightly-6.4.x"}]` +- Resolve the container with a fallback expression so stable and snapshot entries share one job: + ```yaml + container: ${{ matrix.swift.image && format('{0}-{1}', matrix.swift.image, matrix.os) || format('swift:{0}-{1}', matrix.swift.version, matrix.os) }} + ``` +- Exclude the snapshot entry from `wasm` / `wasm-embedded`: Swift nightly publishes no + matching Wasm SDK snapshot. +- Only the **full** matrix carries the snapshot entry; the quick matrix stays on one stable version. + +**Registry gotchas** (cost real time to discover): +- The official `swift` Docker image publishes **zero** nightly tags. Snapshots live only under + the `swiftlang/swift` registry. +- The tag is `nightly-.x-` — `nightly-6.4.x-noble`. There is no + `nightly-6.4-noble`; it 404s. + +**Note on blocking:** ConfigKeyKit runs the snapshot entry as a normal, blocking matrix cell — +no `continue-on-error`. That is the house shape; match it. An earlier version of this note +proposed an advisory `continue-on-error` job instead, which the user rejected in favor of the +matrix entry. + +**Supersedes:** the original form of this note said to add no nightly toolchains at all, and a +later revision said to add them as a separate advisory job. Both are wrong; the matrix-entry +pattern above is current. diff --git a/.github/workflows/MistDemo.yml b/.github/workflows/MistDemo.yml index 582c0380..b9e6ebf1 100644 --- a/.github/workflows/MistDemo.yml +++ b/.github/workflows/MistDemo.yml @@ -64,11 +64,11 @@ jobs: # so Swift 6.1 is not supported. if [[ "${{ steps.check.outputs.full }}" == "true" ]]; then echo 'ubuntu-os=["noble","jammy"]' >> "$GITHUB_OUTPUT" - echo 'ubuntu-swift=["6.2","6.3"]' >> "$GITHUB_OUTPUT" + echo 'ubuntu-swift=[{"version":"6.2"},{"version":"6.3"},{"version":"6.4","image":"swiftlang/swift:nightly-6.4.x"}]' >> "$GITHUB_OUTPUT" echo 'ubuntu-type=["","wasm","wasm-embedded"]' >> "$GITHUB_OUTPUT" else echo 'ubuntu-os=["noble"]' >> "$GITHUB_OUTPUT" - echo 'ubuntu-swift=["6.3"]' >> "$GITHUB_OUTPUT" + echo 'ubuntu-swift=[{"version":"6.3"}]' >> "$GITHUB_OUTPUT" echo 'ubuntu-type=[""]' >> "$GITHUB_OUTPUT" fi @@ -76,7 +76,7 @@ jobs: name: Build on Ubuntu needs: configure runs-on: ubuntu-latest - container: swift:${{ matrix.swift }}-${{ matrix.os }} + container: ${{ matrix.swift.image && format('{0}-{1}', matrix.swift.image, matrix.os) || format('swift:{0}-{1}', matrix.swift.version, matrix.os) }} if: ${{ !contains(github.event.head_commit.message, 'ci skip') }} strategy: fail-fast: false @@ -84,6 +84,13 @@ jobs: os: ${{ fromJSON(needs.configure.outputs.ubuntu-os) }} swift: ${{ fromJSON(needs.configure.outputs.ubuntu-swift) }} type: ${{ fromJSON(needs.configure.outputs.ubuntu-type) }} + exclude: + # Swift nightly publishes no matching Wasm SDK snapshot, so the 6.4 + # entry builds SPM only. + - swift: { version: "6.4", image: "swiftlang/swift:nightly-6.4.x" } + type: "wasm" + - swift: { version: "6.4", image: "swiftlang/swift:nightly-6.4.x" } + type: "wasm-embedded" steps: - uses: actions/checkout@v6 - uses: brightdigit/swift-build@v1 @@ -118,7 +125,7 @@ jobs: uses: codecov/codecov-action@v6 with: fail_ci_if_error: true - flags: mistdemo-swift-${{ matrix.swift }}-${{ matrix.os }} + flags: mistdemo-swift-${{ matrix.swift.version }}-${{ matrix.os }} verbose: true token: ${{ secrets.CODECOV_TOKEN }} files: ${{ join(fromJSON(steps.coverage-files.outputs.files), ',') }} @@ -211,13 +218,13 @@ jobs: matrix: include: # SPM build - - xcode: "/Applications/Xcode_26.4.app" + - xcode: "/Applications/Xcode_26.6.app" # iOS build - type: ios - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" deviceName: "iPhone 17 Pro" - osVersion: "26.4.1" + osVersion: "26.5" download-platform: true steps: - uses: actions/checkout@v6 @@ -269,27 +276,27 @@ jobs: include: # macOS - type: macos - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" # watchOS - type: watchos - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" deviceName: "Apple Watch Ultra 3 (49mm)" - osVersion: "26.4" + osVersion: "26.5" download-platform: true # tvOS - type: tvos - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" deviceName: "Apple TV" - osVersion: "26.4" + osVersion: "26.5" download-platform: true # visionOS - type: visionos - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" deviceName: "Apple Vision Pro" - osVersion: "26.4.1" + osVersion: "26.5" download-platform: true steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/MistKit.yml b/.github/workflows/MistKit.yml index 0530db9a..dab4cc07 100644 --- a/.github/workflows/MistKit.yml +++ b/.github/workflows/MistKit.yml @@ -61,7 +61,7 @@ jobs: run: | if [[ "${{ steps.check.outputs.full }}" == "true" ]]; then echo 'ubuntu-os=["noble","jammy"]' >> "$GITHUB_OUTPUT" - echo 'ubuntu-swift=[{"version":"6.1"},{"version":"6.2"},{"version":"6.3"}]' >> "$GITHUB_OUTPUT" + echo 'ubuntu-swift=[{"version":"6.1"},{"version":"6.2"},{"version":"6.3"},{"version":"6.4","image":"swiftlang/swift:nightly-6.4.x"}]' >> "$GITHUB_OUTPUT" echo 'ubuntu-type=["","wasm","wasm-embedded"]' >> "$GITHUB_OUTPUT" else echo 'ubuntu-os=["noble"]' >> "$GITHUB_OUTPUT" @@ -73,7 +73,7 @@ jobs: name: Build on Ubuntu needs: configure runs-on: ubuntu-latest - container: swift:${{ matrix.swift.version }}-${{ matrix.os }} + container: ${{ matrix.swift.image && format('{0}-{1}', matrix.swift.image, matrix.os) || format('swift:{0}-{1}', matrix.swift.version, matrix.os) }} if: ${{ !contains(github.event.head_commit.message, 'ci skip') }} strategy: fail-fast: false @@ -87,6 +87,12 @@ jobs: type: "wasm" - swift: { version: "6.1" } type: "wasm-embedded" + # Swift nightly publishes no matching Wasm SDK snapshot, so the 6.4 + # entry builds SPM only. + - swift: { version: "6.4", image: "swiftlang/swift:nightly-6.4.x" } + type: "wasm" + - swift: { version: "6.4", image: "swiftlang/swift:nightly-6.4.x" } + type: "wasm-embedded" steps: - uses: actions/checkout@v6 - uses: brightdigit/swift-build@v1 @@ -213,13 +219,13 @@ jobs: matrix: include: # SPM build - - xcode: "/Applications/Xcode_26.4.app" + - xcode: "/Applications/Xcode_26.6.app" # iOS build - type: ios - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" deviceName: "iPhone 17 Pro" - osVersion: "26.4.1" + osVersion: "26.5" download-platform: true steps: - uses: actions/checkout@v6 @@ -264,7 +270,7 @@ jobs: # macOS - type: macos runs-on: macos-26 - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" # iOS — older Xcode for backward compat - type: ios @@ -277,25 +283,25 @@ jobs: # watchOS - type: watchos runs-on: macos-26 - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" deviceName: "Apple Watch Ultra 3 (49mm)" - osVersion: "26.4" + osVersion: "26.5" download-platform: true # tvOS - type: tvos runs-on: macos-26 - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" deviceName: "Apple TV" - osVersion: "26.4" + osVersion: "26.5" download-platform: true # visionOS - type: visionos runs-on: macos-26 - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" deviceName: "Apple Vision Pro" - osVersion: "26.4.1" + osVersion: "26.5" download-platform: true steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2b3b13fe..6d1351bf 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -49,7 +49,7 @@ jobs: - name: Setup Xcode if: matrix.language == 'swift' - run: sudo xcode-select -s /Applications/Xcode_26.4.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_26.6.app/Contents/Developer - name: Verify Swift Version if: matrix.language == 'swift' diff --git a/Examples/BushelCloud/.github/workflows/BushelCloud.yml b/Examples/BushelCloud/.github/workflows/BushelCloud.yml index a88dfaa9..abdcf3bd 100644 --- a/Examples/BushelCloud/.github/workflows/BushelCloud.yml +++ b/Examples/BushelCloud/.github/workflows/BushelCloud.yml @@ -62,17 +62,17 @@ jobs: # so Swift 6.1 is not supported. if [[ "${{ steps.check.outputs.full }}" == "true" ]]; then echo 'ubuntu-os=["noble","jammy"]' >> "$GITHUB_OUTPUT" - echo 'ubuntu-swift=["6.2","6.3"]' >> "$GITHUB_OUTPUT" + echo 'ubuntu-swift=[{"version":"6.2"},{"version":"6.3"},{"version":"6.4","image":"swiftlang/swift:nightly-6.4.x"}]' >> "$GITHUB_OUTPUT" else echo 'ubuntu-os=["noble"]' >> "$GITHUB_OUTPUT" - echo 'ubuntu-swift=["6.3"]' >> "$GITHUB_OUTPUT" + echo 'ubuntu-swift=[{"version":"6.3"}]' >> "$GITHUB_OUTPUT" fi build-ubuntu: name: Build on Ubuntu needs: configure runs-on: ubuntu-latest - container: swift:${{ matrix.swift }}-${{ matrix.os }} + container: ${{ matrix.swift.image && format('{0}-{1}', matrix.swift.image, matrix.os) || format('swift:{0}-{1}', matrix.swift.version, matrix.os) }} if: ${{ !contains(github.event.head_commit.message, 'ci skip') }} strategy: fail-fast: false @@ -104,7 +104,7 @@ jobs: uses: codecov/codecov-action@v6 with: fail_ci_if_error: true - flags: swift-${{ matrix.swift }}-${{ matrix.os }} + flags: swift-${{ matrix.swift.version }}-${{ matrix.os }} verbose: true token: ${{ secrets.CODECOV_TOKEN }} files: ${{ join(fromJSON(steps.coverage-files.outputs.files), ',') }} @@ -152,13 +152,13 @@ jobs: matrix: include: # SPM build - - xcode: "/Applications/Xcode_26.4.app" + - xcode: "/Applications/Xcode_26.6.app" # iOS build - type: ios - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" deviceName: "iPhone 17 Pro" - osVersion: "26.4.1" + osVersion: "26.5" download-platform: true steps: - uses: actions/checkout@v6 @@ -198,27 +198,27 @@ jobs: include: # macOS - type: macos - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" # watchOS - type: watchos - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" deviceName: "Apple Watch Ultra 3 (49mm)" - osVersion: "26.4" + osVersion: "26.5" download-platform: true # tvOS - type: tvos - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" deviceName: "Apple TV" - osVersion: "26.4" + osVersion: "26.5" download-platform: true # visionOS - type: visionos - xcode: "/Applications/Xcode_26.4.app" + xcode: "/Applications/Xcode_26.6.app" deviceName: "Apple Vision Pro" - osVersion: "26.4.1" + osVersion: "26.5" download-platform: true steps: - uses: actions/checkout@v6 diff --git a/Examples/BushelCloud/.github/workflows/codeql.yml b/Examples/BushelCloud/.github/workflows/codeql.yml index e78a1389..d68481dc 100644 --- a/Examples/BushelCloud/.github/workflows/codeql.yml +++ b/Examples/BushelCloud/.github/workflows/codeql.yml @@ -50,7 +50,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Xcode - run: sudo xcode-select -s /Applications/Xcode_26.2.app/Contents/Developer + run: sudo xcode-select -s /Applications/Xcode_26.6.app/Contents/Developer - name: Verify Swift Version run: | diff --git a/Examples/CelestraCloud/.github/workflows/CelestraCloud.yml b/Examples/CelestraCloud/.github/workflows/CelestraCloud.yml index 59b4e7cd..b1fdf565 100644 --- a/Examples/CelestraCloud/.github/workflows/CelestraCloud.yml +++ b/Examples/CelestraCloud/.github/workflows/CelestraCloud.yml @@ -63,17 +63,17 @@ jobs: # so Swift 6.1 is not supported. if [[ "${{ steps.check.outputs.full }}" == "true" ]]; then echo 'ubuntu-os=["noble","jammy"]' >> "$GITHUB_OUTPUT" - echo 'ubuntu-swift=["6.2","6.3"]' >> "$GITHUB_OUTPUT" + echo 'ubuntu-swift=[{"version":"6.2"},{"version":"6.3"},{"version":"6.4","image":"swiftlang/swift:nightly-6.4.x"}]' >> "$GITHUB_OUTPUT" else echo 'ubuntu-os=["noble"]' >> "$GITHUB_OUTPUT" - echo 'ubuntu-swift=["6.3"]' >> "$GITHUB_OUTPUT" + echo 'ubuntu-swift=[{"version":"6.3"}]' >> "$GITHUB_OUTPUT" fi build-ubuntu: name: Build on Ubuntu needs: configure runs-on: ubuntu-latest - container: swift:${{ matrix.swift }}-${{ matrix.os }} + container: ${{ matrix.swift.image && format('{0}-{1}', matrix.swift.image, matrix.os) || format('swift:{0}-{1}', matrix.swift.version, matrix.os) }} if: ${{ !contains(github.event.head_commit.message, 'ci skip') }} strategy: fail-fast: false @@ -109,7 +109,7 @@ jobs: uses: codecov/codecov-action@v6 with: fail_ci_if_error: false - flags: swift-${{ matrix.swift }}-${{ matrix.os }} + flags: swift-${{ matrix.swift.version }}-${{ matrix.os }} verbose: true token: ${{ secrets.CODECOV_TOKEN }} files: ${{ join(fromJSON(steps.coverage-files.outputs.files), ',') }}