Skip to content

Claude/plan issue 325 a qgrh#345

Merged
leogdion merged 7 commits into
v1.0.0-beta.1from
claude/plan-issue-325-aQGRH
May 15, 2026
Merged

Claude/plan issue 325 a qgrh#345
leogdion merged 7 commits into
v1.0.0-beta.1from
claude/plan-issue-325-aQGRH

Conversation

@leogdion
Copy link
Copy Markdown
Member

No description provided.

claude added 4 commits May 14, 2026 21:49
Run test-public, test-private, demo-errors, and demo-in-filter against
the real iCloud.com.brightdigit.MistDemo container on push to main and
release branches. Uploads per-phase logs on failure for diagnosis.

Includes a temporary push trigger on the working branch so we can
iterate against real GitHub Actions before merge; that line is marked
TEMPORARY and must be stripped before this lands on main.
`set -o pipefail` is a bash-ism; the swift:6.3-noble container's default
`sh` is dash, which rejects it with 'Illegal option -o pipefail'.
Config validator requires key.id on these phases too — without it
demo-in-filter crashes at startup with ConfigurationError.missingRequired.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c0b24a9b-ed15-497b-ae67-c233d13021a1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/plan-issue-325-aQGRH

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 14, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.49%. Comparing base (d65d20b) to head (058a27f).
⚠️ Report is 1 commits behind head on v1.0.0-beta.1.

❗ There is a different number of reports uploaded between BASE (d65d20b) and HEAD (058a27f). Click for more details.

HEAD has 5 uploads less than BASE
Flag BASE (d65d20b) HEAD (058a27f)
mistdemo-spm-macos 1 0
mistdemo-swift-6.3-noble 1 0
mistdemo-swift-6.3-jammy 1 0
mistdemo-swift-6.2-noble 1 0
mistdemo-swift-6.2-jammy 1 0
Additional details and impacted files
@@                Coverage Diff                 @@
##           v1.0.0-beta.1     #345       +/-   ##
==================================================
- Coverage          70.46%   56.49%   -13.98%     
==================================================
  Files                551      132      -419     
  Lines              15426     3535    -11891     
==================================================
- Hits               10870     1997     -8873     
+ Misses              4556     1538     -3018     
Flag Coverage Δ
mistdemo-spm-macos ?
mistdemo-swift-6.2-jammy ?
mistdemo-swift-6.2-noble ?
mistdemo-swift-6.3-jammy ?
mistdemo-swift-6.3-noble ?
spm 55.30% <ø> (+3.02%) ⬆️
swift-6.1-jammy 55.95% <ø> (+3.70%) ⬆️
swift-6.1-noble 55.27% <ø> (+3.05%) ⬆️
swift-6.2-jammy 55.44% <ø> (+3.13%) ⬆️
swift-6.2-noble 55.30% <ø> (+2.96%) ⬆️
swift-6.3-jammy 55.27% <ø> (+2.60%) ⬆️
swift-6.3-noble 56.18% <ø> (+3.50%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Build job stays in swift:6.3-noble and bundles the mistdemo binary
plus the Swift runtime libs from /usr/lib/swift/linux/. Integration
job runs on plain ubuntu-24.04 (no Swift toolchain), downloads the
bundle, and invokes the binary with LD_LIBRARY_PATH set to the
bundled libs. Same glibc as the build container avoids ABI drift.
@claude
Copy link
Copy Markdown

claude Bot commented May 14, 2026

Code Review — PR #345: MistDemo Integration Workflow

Overview

Adds .github/workflows/MistDemo-Integration.yml, a new live end-to-end CI workflow that builds the mistdemo binary in a Swift container and then runs it against the real CloudKit container on a plain Ubuntu runner (no Swift toolchain required). The two-job design (build + integration) is clean and the security posture (no pull_request trigger, masking the decoded PEM line-by-line) is solid.


🔴 Critical — Will break the workflow

actions/checkout@v6 does not exist.

- uses: actions/checkout@v6

The latest stable version is v4. Using a non-existent tag will fail the build job immediately. Change to:

- uses: actions/checkout@v4

🟡 Should fix before merge

TEMPORARY branch trigger needs to be removed.

The comment already flags this, but worth calling out explicitly in review:

# TEMPORARY: remove before merge
- claude/plan-issue-325-aQGRH

This should be dropped before this PR lands so the workflow doesn't continue running on a stale dev branch.


🟡 demo-errors marker validation is fragile

Checking for bare numeric strings is too broad — any log line that happens to contain those digits will match:

for marker in "401" "404" "409"; do
  grep -q "$marker" integration-logs/demo-errors.log || { ... }
done

Consider anchoring the check to something more specific, e.g. a log prefix the demo actually emits (Scenario 401, HTTP 401, or a dedicated completion line), so incidental matches don't give false confidence.


🟡 Integration steps: set -o pipefail but not set -e

The test-public, test-private, demo-errors, and demo-in-filter steps use set -o pipefail but omit -e and -u. A command that exits non-zero mid-step (other than the final piped command) will silently continue. Use set -euo pipefail for consistency with the build and extract steps.


🔵 Suggestions / Nits

  • Debug build. swift build without -c release bundles a debug binary. This is fine for integration testing (faster build), but it's worth a brief comment explaining the intentional choice — otherwise readers may wonder if it's an oversight.

  • No retry for CloudKit API flakiness. CloudKit Web Services can return transient 503s or rate-limit responses. If a phase fails intermittently you'll need to re-trigger manually. Consider a simple retry loop or a GitHub Actions retry action for the integration steps (especially test-public / test-private).

  • concurrency.cancel-in-progress: false is the right call here (avoid concurrent writes to the same CloudKit container), but a brief comment explaining why cancel-in-progress is disabled would help future maintainers.


✅ What's done well

  • Two-job design keeps the Swift toolchain off the runner host — clean separation.
  • PEM masking line-by-line before writing to GITHUB_ENV is a solid secret-hygiene pattern.
  • if: always() on the key cleanup step ensures the decoded PEM is removed even after failures.
  • retention-days: 1 on the build artifact and compression-level: 0 on the already-gzipped tarball are both sensible micro-optimizations.
  • No pull_request trigger — secrets are correctly kept away from fork PRs.
  • Smoke check (./bundle/mistdemo --help) before any network calls catches mis-bundled libraries early.

Verdict: Fix the actions/checkout@v6 version bug (it will fail on day one), drop the TEMPORARY branch, and address the set -e gap before merging. The rest are suggestions.

Drops the LD_LIBRARY_PATH bundling approach in favor of -swift-sdk
x86_64-swift-linux-musl, which links Foundation/Dispatch statically.
Build job uploads a single executable artifact; integration job on
plain ubuntu-24.04 invokes it directly. Pins both container and SDK
to 6.3.2 (Static SDK requires exact toolchain match).
@claude
Copy link
Copy Markdown

claude Bot commented May 15, 2026

Code Review — PR #345: MistDemo Integration CI Workflow

Overview: Adds .github/workflows/MistDemo-Integration.yml — a two-job pipeline that builds a statically-linked mistdemo binary (Swift 6.3.2 + musl SDK) and runs it against the real CloudKit container to verify live integration across public/private/error/filter scenarios.


🚨 Must Fix Before Merge

Temporary branch trigger still present

# Line ~37
- claude/plan-issue-325-aQGRH

The comment above it says "TEMPORARY: remove before merge" — this branch trigger must be removed before this is merged to v1.0.0-beta.1. Leaving it in will cause every future push to this branch to trigger a full live CloudKit run unnecessarily.


⚠️ Issues / Risks

set -o pipefail vs set -euo pipefail inconsistency

The build job steps use set -euo pipefail (fail on error, undefined var, and pipeline failure), but the integration job run steps only use set -o pipefail. This means undefined variable references or command errors in the integration steps won't immediately abort the step. Recommend adding -eu flags for consistency and safety:

# Before
set -o pipefail

# After
set -euo pipefail

actions/checkout@v6 — verify availability

- uses: actions/checkout@v6

As of the latest published releases, actions/checkout is at v4. If v6 doesn't exist yet this workflow will fail silently on the checkout step. Use @v4 (or a pinned SHA) unless v6 has been confirmed released.

demo-errors marker check is fragile

for marker in "401" "404" "409"; do
  grep -q "$marker" integration-logs/demo-errors.log || { ... }
done

These numeric strings could appear in timestamps, byte counts, or other log lines unrelated to error scenarios. Consider having the demo-errors command emit more specific markers (e.g., SCENARIO_401_OK, SCENARIO_404_OK) and grep for those instead.


✅ Good Practices

  • No pull_request trigger — secrets correctly withheld from forks.
  • cancel-in-progress: false — prevents a new push from killing a mid-flight integration run and leaving CloudKit data in a partial state. Good call.
  • PEM masking — line-by-line ::add-mask:: on the decoded key is thorough.
  • chmod 600 + $RUNNER_TEMP — correct isolation for the decoded private key.
  • Cleanup step with if: always() — key is wiped even on failure.
  • CLOUDKIT_ENVIRONMENT: development — all steps correctly target development, not production.
  • Auth scoping is correcttest-public uses S2S creds (CLOUDKIT_KEY_ID) and no web-auth token, test-private uses only CLOUDKIT_API_TOKEN + CLOUDKIT_WEB_AUTH_TOKEN, matching CLAUDE.md's documented constraints.
  • CLOUDKIT_PRIVATE_KEY_PATH via $GITHUB_ENV — set once in the decode step and inherited by all subsequent steps cleanly.

Minor

  • PR title"Claude/plan issue 325 a qgrh" appears auto-generated. A descriptive title like "feat: add MistDemo live integration CI workflow" would better communicate intent in the git log and PR history.
  • retention-days: 1 for the binary artifact — tight, but appropriate since it's only needed to handoff between jobs. Log retention of 14 days is a reasonable tradeoff.

Summary: The workflow design is solid — two-job split, static binary, proper secret handling, and correct auth scoping per database type. The merge blocker is the temporary branch trigger; the set -euo pipefail inconsistency and actions/checkout@v6 version should also be addressed before merging.

@claude
Copy link
Copy Markdown

claude Bot commented May 15, 2026

Code Review: MistDemo Integration Workflow

Overview

This PR adds a live end-to-end CI workflow that builds a statically-linked mistdemo binary and runs it against a real CloudKit container. The two-job design (build → integration) is clever: the integration runner needs no Swift toolchain, which keeps the job lean and dependency-free.


❌ Blocking Issues

actions/checkout@v6 does not exist

- uses: actions/checkout@v6

GitHub's official checkout action is currently at v4. Using @v6 will cause the build job to fail immediately. This should be actions/checkout@v4.

Temporary branch trigger must be removed before merge

- claude/plan-issue-325-aQGRH
  # TEMPORARY: remove before merge — lets us iterate on this workflow

The comment acknowledges this but it must be addressed. Leaving it in would trigger the integration workflow (and consume secrets) on every push to this unrelated feature branch after merge.


⚠️ Notable Issues

Fragile demo-errors marker validation

for marker in "401" "404" "409"; do
  grep -q "$marker" integration-logs/demo-errors.log || {

Grepping for bare numeric strings 401, 404, 409 is error-prone — these can appear in timestamps, line numbers, CloudKit record names, or any other incidental output. This could produce a false positive and mask a scenario that didn't actually run. Consider grepping for specific completion strings emitted by demo-errors (e.g., "scenario 401 completed", "✓ 404", or whatever the command actually outputs), or have demo-errors write a structured summary.

Integration test steps use set -o pipefail only

run: |
  set -o pipefail
  ./mistdemo test-public \

The build/prep steps use the stricter set -euo pipefail. The integration steps drop -e and -u. Without -e, a non-zero exit from any command before the pipeline (env setup, etc.) would be silently swallowed. Use set -euo pipefail here too for consistency and robustness.


✅ What's Done Well

  • No pull_request trigger — secrets are not exposed to fork PRs. This is the right call.
  • cancel-in-progress: false — correct for a workflow that creates/modifies CloudKit records; cancelling mid-run could leave orphaned data.
  • Secret masking — the ::add-mask:: line-by-line loop on the decoded PEM is thorough.
  • chmod 600 + RUNNER_TEMP — proper key hygiene; RUNNER_TEMP is outside the workspace and less likely to be inadvertently cached or archived.
  • if: always() cleanup — the private key cleanup step correctly runs even on failure.
  • Checksum pinning with a comment to "bump together" is excellent practice; the exact Swift patch version is pinned for reproducibility.
  • Static binary design — decoupling the heavy Swift build from the lightweight integration runner is a good pattern.
  • Integration log artifact — logs uploaded on always() with 14-day retention gives good debuggability.

Minor Suggestions

  • The demo-errors step passes CLOUDKIT_WEB_AUTH_TOKEN which is rotated manually per the header comment. Consider adding a step-level check (or demo-errors command flag) that surfaces a clear error when the token is stale, rather than failing opaquely mid-run.
  • retention-days: 1 for the mistdemo artifact is intentionally minimal — that's fine, but worth noting in the workflow comment that re-running the integration job alone will fail after the artifact expires (since needs: build doesn't re-trigger automatically on re-run).

Summary

Two blocking issues before this is ready to merge:

  1. Fix actions/checkout@v6@v4
  2. Remove the temporary branch trigger

The demo-errors grep logic is also worth hardening. Everything else is solid.

@leogdion leogdion merged commit f799128 into v1.0.0-beta.1 May 15, 2026
47 of 48 checks passed
@leogdion leogdion deleted the claude/plan-issue-325-aQGRH branch May 18, 2026 09:29
leogdion added a commit that referenced this pull request May 18, 2026
commit de82483
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 21:14:35 2026 +0100

    git subrepo push Examples/CelestraCloud

    subrepo:
      subdir:   "Examples/CelestraCloud"
      merged:   "ea897c3"
    upstream:
      origin:   "git@github.com:brightdigit/CelestraCloud.git"
      branch:   "mistkit"
      commit:   "ea897c3"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "6f293daa9f"

commit 24c8719
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 21:14:31 2026 +0100

    git subrepo push Examples/BushelCloud

    subrepo:
      subdir:   "Examples/BushelCloud"
      merged:   "5bb4490"
    upstream:
      origin:   "git@github.com:brightdigit/BushelCloud.git"
      branch:   "mistkit"
      commit:   "5bb4490"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "6f293daa9f"

commit eee0670
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 21:14:13 2026 +0100

    docs: sync README/CLAUDE examples to v1.0.0-beta.1 API; pin BushelCloud CI; exclude internal Python from CodeFactor

    - README.md, Examples/BushelCloud/{CLAUDE.md,.docc,.claude/s2s-auth-details.md},
      Examples/CelestraCloud/{CLAUDE.md,README.md,.claude/IMPLEMENTATION_NOTES.md}:
      drop `try CloudKitService(... database: .public)` from init examples (init is
      non-throwing, `database:` moved per-call); rewrite Quick Start auth around
      `Credentials` + `APICredentials` / `ServerToServerCredentials` and show
      `database: .public(.prefers(.serverToServer))` at the call site.
    - Examples/BushelCloud/.github/workflows/{BushelCloud.yml,bushel-cloud-build.yml}:
      pin MISTKIT_BRANCH to v1.0.0-beta.1 (matches CelestraCloud) so the subrepo PR
      builds against the branch that actually carries the new API. Revert to `main`
      once #298 merges.
    - .codefactor.yml: exclude Scripts/mermaid-to-pptx.py (internal-use helper).

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

commit 4d60b19
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 20:10:45 2026 +0100

    git subrepo push Examples/CelestraCloud

    subrepo:
      subdir:   "Examples/CelestraCloud"
      merged:   "c44dc4f"
    upstream:
      origin:   "git@github.com:brightdigit/CelestraCloud.git"
      branch:   "mistkit"
      commit:   "c44dc4f"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "6f293daa9f"

commit 5bc403d
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 20:10:40 2026 +0100

    git subrepo push Examples/BushelCloud

    subrepo:
      subdir:   "Examples/BushelCloud"
      merged:   "55f2092"
    upstream:
      origin:   "git@github.com:brightdigit/BushelCloud.git"
      branch:   "mistkit"
      commit:   "55f2092"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "6f293daa9f"

commit bce1f23
Author: leogdion <leogdion@brightdigit.com>
Date:   Sun May 17 20:09:47 2026 +0100

    refactor!: prep for talk — shrink API, refactor auth, split OpenAPI (#279)

commit 7023a31
Author: leogdion <leogdion@brightdigit.com>
Date:   Fri May 15 12:56:58 2026 -0400

    Fixed Nonisolated Web Auth Token (#347)

commit f799128
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 14 20:27:28 2026 -0400

    Add MistDemo-Integration workflow for live CloudKit runs (#345)

commit 418e2e4
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 14 16:03:04 2026 -0400

    Resolve #342: v1.0.0-beta.1 follow-ups (#341 #327 #321 #317) + CI fixes (#343)

commit d65d20b
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 14 11:25:10 2026 -0400

    Resolve #330: interactive MistDemo (web toggle + native app refresh) (#332)

commit a28ab3c
Author: leogdion <leogdion@brightdigit.com>
Date:   Mon May 11 16:31:10 2026 -0400

    Resolve #313: paginationLimitExceeded carries accumulated records (#326)

commit 7a5da7a
Author: leogdion <leogdion@brightdigit.com>
Date:   Sat May 9 17:09:53 2026 -0400

    Fix CI failures + Claude review nits on PR #298 (v1.0.0-beta.1) (#322)

commit b3626c0
Author: leogdion <leogdion@brightdigit.com>
Date:   Sat May 9 16:06:20 2026 -0400

    Resolve #312: public+web-auth user-identity endpoints (#310, #311, #27, #28, #34, #35) (#315)

    * #312 library: add public+web-auth user-identity endpoints and users/caller migration

    Implements the library side of #312 — adding/renaming user-identity endpoints
    that require public-database routing with web-auth (user-context) credentials,
    and unblocking the convenience initializers from their hardcoded database/
    environment defaults.

    #310: `CloudKitService` convenience initializers now accept `database:` and
    `environment:` parameters with defaults that preserve current behavior.

    #311: `users/current` → `users/caller`. Renamed in openapi.yaml and the
    generated client; added a hand-written `fetchCaller()` plus an
    `@available(*, deprecated, renamed: "fetchCaller")` `fetchCurrentUser()`
    shim that forwards to the new method.

    #28: GET `/users/discover` (`discoverAllUserIdentities`).

    #34: POST `/users/lookup/email` (`lookupUsersByEmail`).

    #35: POST `/users/lookup/id` (`lookupUsersByRecordName`).

    The three new endpoints reuse `DiscoverResponse` for parsing — Apple returns
    `{ users: [UserIdentity] }` for all of them. Each ships with a 5-file
    test suite mirroring the existing `DiscoverUserIdentities` pattern.

    #33 (`users/lookup/contacts`) intentionally not implemented: Apple has marked
    the endpoint deprecated. To be closed as not-planned with a pointer to #34/#35.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #312 MistDemo: separate database from authentication and add user-context phases

    Refactors MistDemo's CloudKit configuration model and integration runner to
    support the public+web-auth combination required by the user-identity
    endpoints landed in the prior commit.

    **Configuration refactor.** Replaces the `DatabaseCredentials` enum (which
    coupled database choice to a single auth method per case, baking in a
    public⇒S2S/private⇒webAuth assumption) with two orthogonal types:

      - `AuthenticationCredentials` — `serverToServer(keyID:privateKey:)` /
        `webAuth(apiToken:webAuthToken:)`
      - `DatabaseConfiguration` — pairs a `MistKit.Database` with an
        `AuthenticationCredentials`. The `make(database:authentication:)` factory
        rejects private+S2S and shared+S2S (which CloudKit rejects) so invalid
        combinations remain unrepresentable, while public+webAuth is now a valid
        construction.

    `MistKitClientFactory.create(for:)` consumes `toPrimaryConfiguration()`;
    the new `createUserContext(for:)` returns the optional public+web-auth
    service from `toUserContextConfiguration()` when web-auth tokens are
    configured.

    **Phase plumbing.** `PhaseContext` and `IntegrationTestRunner` now thread an
    optional `userContextService: CloudKitService?`. `PublicDatabaseTest` takes
    `includeUserContextPhases:` and conditionally appends the new user-identity
    phases:

      - `FetchCallerPhase` (renamed from `FetchCurrentUserPhase`)
      - `DiscoverUserIdentitiesPhase` (existed; updated to use userContextService)
      - `DiscoverAllUserIdentitiesPhase` (#28)
      - `LookupUsersByEmailPhase` (#34)
      - `LookupUsersByRecordNamePhase` (#35)

    `PrivateDatabaseTest` no longer includes `FetchCurrentUserPhase`: CloudKit
    rejects `users/caller` against the private database, matching the rest of
    the user-identity family.

    **Call-site updates.** `CurrentUserCommand` and `DemoErrorsRunner` swap
    `fetchCurrentUser()` → `fetchCaller()`. `TestIntegrationCommand` and
    `TestPrivateCommand` now build and pass `userContextService`.

    Tests for `AuthenticationCredentials`, `DatabaseConfiguration.make`
    validation, and `MistDemoConfig.toPrimaryConfiguration` /
    `toUserContextConfiguration` ship alongside.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #312: mark discoverAllUserIdentities() unavailable pending #28 investigation

    Live verification on 2026-05-08 against iCloud.com.brightdigit.MistDemo
    returned HTTP 500 from Apple's GET /users/discover. The first 12 phases
    of mistdemo test-integration --verbose run green (the 8 base public+S2S
    phases plus FetchCallerPhase, DiscoverUserIdentitiesPhase,
    LookupUsersByEmailPhase, LookupUsersByRecordNamePhase) — only
    discoverAllUserIdentities fails, blocking phases beyond it.

    The endpoint is referenced in CloudKitJS but does not appear in Apple's
    CloudKit Web Services REST documentation. The actual REST shape is still
    under investigation under #28.

    Changes:
    - Marked `CloudKitService.discoverAllUserIdentities()`
      `@available(*, unavailable, message: ...)` with a pointer to #28.
    - Removed `DiscoverAllUserIdentitiesPhase` from MistDemo and from
      `PublicDatabaseTest.phases`.
    - Removed the `CloudKitServiceDiscoverAllUserIdentities` test directory
      (the unavailable method cannot be called from Swift code).

    The OpenAPI definition, generated client, path builder, response
    processor, Output extension, and Swift wrapper are all retained.
    Unblocking is a one-line `@available` removal once the correct REST
    shape is determined under #28.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #315: resolve PR review — Credentials API, per-call database, cascade unavailable

    Addresses all four review threads on PR #315:

    - Comment #1 (error wording): removed `unsupportedDatabaseAuthCombination`
      along with `MistDemo.DatabaseConfiguration`; invalid combos now surface as
      `CloudKitError.missingCredentials` from the library.
    - Comment #2 (per-call database): user-identity ops in
      `CloudKitService+UserOperations` hardcode `.public`; record/zone/asset/sync
      ops accept `database: Database? = nil` falling back to a service-level
      default.
    - Comment #3 (unified credentials): new `Credentials` /
      `ServerToServerCredentials` / `APICredentials` value types replace the
      legacy `apiToken:`/`webAuthToken:` initializers. The token manager is
      selected based on the target database (S2S for `.public`, web-auth for
      `.private`/`.shared`). Lifted `PrivateKeyMaterial` into the library.
    - Comment #4 (cascade unavailable): removed
      `Operations.discoverAllUserIdentities.Output: CloudKitResponseType`
      conformance entirely; `processDiscoverAllUserIdentitiesResponse` is now
      `@available(*, unavailable)` with a `fatalError` body.

    Also migrates ~15 MistKit test helpers and the MistDemo factory to the new
    Credentials API.

    Breaking changes (pre-1.0): removed legacy `CloudKitService` initializers
    taking `apiToken:`/`webAuthToken:`; `CloudKitService.apiToken` is removed,
    `.database` is now `internal`.

    Out of scope: per-call `TokenManager` dispatch (would let one service mix
    S2S-for-public and web-auth-for-user-context). MistDemo still constructs a
    separate `userContextService` for that scenario.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #315: drop service-level database, per-call credential resolution [skip ci]

    Resolves the architectural feedback in the PR-315 review:

    * CloudKitService no longer carries `database` — operations take
      `database:` per call (defaulting to `.public`); user-identity routes
      drop the parameter since CloudKit pins them to `.public`. Subsumes
      Claude's "fetchCaller bypasses self.database" finding.
    * Credentials.makeTokenManager(for:requiresUserContext:) resolves the
      appropriate token manager at dispatch time. A single service can now
      serve public-database S2S record ops and user-identity web-auth
      routes from one fully-populated `Credentials`. MistKitClient.swift is
      obsolete and removed; per-call dispatch lives in
      CloudKitService+ClientDispatch.
    * Credentials.swift split per SwiftLint one_file_per_declaration into
      ServerToServerCredentials.swift + APICredentials.swift +
      Credentials.swift. New typed CredentialsValidationError; init asserts
      in debug, throws in release (no more precondition crash for dynamic
      config).
    * MistDemo: userContextService workaround collapsed — single service
      handles all phases via per-call resolution.
    * CI hotfix: 11 unused `public import` lines demoted to `internal`
      (the warnings-as-errors regression flagged in the review).
    * Tests: 12-case routing-matrix unit suite for makeTokenManager and a
      fetchCaller suite parallel to LookupUsers* (success + validation).
      Obsolete MistKitClient tests removed.
    * Polish: shorter @available message on discoverAllUserIdentities,
      structural comment for GET /users/discover in openapi.yaml,
      ConfigurationError.missingAPIToken (unused) removed.

    475/475 tests pass. Library + MistDemo build clean.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * Per review on PR #315: listZones, lookupZones, fetchZoneChanges now
    default to .private since the public database only contains
    _defaultZone, making .public a degenerate default. MistDemo callers
    pass context.database / config.base.database explicitly so the
    --database flag still drives the test runs.

    Also repairs MistDemo test breakage from 7debe8d:
    toUserContextCredentials() was removed but tests still referenced it;
    rewritten against the replacement surface (toPrimaryCredentials embeds
    apiAuth on .public, plus the new hasUserContextCredentials boolean).
    The CredentialsValidationTests suite was deleted — it asserted
    init-time validation that no longer exists under per-call credential
    resolution; the equivalent .missingCredentials behavior is covered in
    MistKitTests.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #312: gate @available(*,unavailable) on processDiscoverAllUserIdentitiesResponse to Swift 6.2+

    Swift 6.1 rejects calls to an unavailable function from within another
    unavailable function; 6.2 relaxed that rule. The internal helper
    processDiscoverAllUserIdentitiesResponse is unavailable in lockstep with
    its only caller — the also-unavailable CloudKitService.discoverAllUserIdentities() —
    which built fine on 6.2+ but failed on Swift 6.1 with:

        error: 'processDiscoverAllUserIdentitiesResponse' is unavailable:
               Pending #28: discoverAllUserIdentities is not yet ready.

    Wrap just the attribute in `#if swift(>=6.2)` so the body is shared and
    6.1 compiles. Inline doc records the intent and the one-line cleanup
    (delete the #if/#endif) once 6.1 is dropped from the matrix.

    A `swiftlint:disable:next unavailable_function` is required because
    swiftlint does not evaluate #if and otherwise sees a fatalError-only
    function without the attribute.

    Verified: swift build + swift test pass on Swift 6.1.3 (Linux container)
    and on macOS Swift 6.2+ (475/475 tests).

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #315: split unhandled-response logging into debug (full body) + warning (type/status only)

    CodeQL's swift/cleartext-logging flagged the existing warning logs
    because lookupUsersByEmail(_:) propagates email-PII taint through the
    response object. Move full \(response) interpolation to .debug so the
    detail stays available for development without flowing into ops logs;
    keep .warning at type(of:) + HTTP status code only.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #312: add --lookup-email / CLOUDKIT_LOOKUP_EMAIL to exercise users/lookup/email

    LookupUsersByEmailPhase previously skipped whenever fetchCaller() didn't
    return an email (which is the common case). Plumb a configurable lookup
    email through TestIntegrationConfig / TestPrivateConfig → PhaseContext so
    the phase can be driven against a known-discoverable iCloud account.
    Falls back to caller email, then to a clearer skip message naming the
    flag/env var.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * docs: point CLAUDE.md lint section at mise (and Scripts/lint.sh)

    swift-format / swiftlint / periphery are pinned in mise.toml; the
    previous "requires swiftlint installation" wording led to PATH lookups
    that fail in this repo. Replace with `mise exec --` invocations and
    flag the full ./Scripts/lint.sh pipeline.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #315: address review punch list — invalidPrivateKey, recoverable unavailable response, supportsUserContextPhases derivation

    - CloudKitError: add invalidPrivateKey(path:underlying:) so PEM-load failures
      carry the file path + original error instead of bare Foundation NSError.
      Wrap loadPEM() at the single call site in Credentials+TokenManager. Add
      PrivateKeyMaterial.filePath accessor for the diagnostic.

    - processDiscoverAllUserIdentitiesResponse: replace fatalError with
      throw CloudKitError.unsupportedOperationType so a stray Swift 6.1 caller
      (where the @available cascade does not apply) gets a recoverable error
      instead of a crash.

    - TestPrivateCommand: derive supportsUserContextPhases from
      config.base.hasUserContextCredentials, mirroring TestIntegrationCommand,
      so user-identity phases skip cleanly when web-auth env vars are absent.

    - toPrimaryCredentials: replace try? with do/catch + stderr INFO line so
      operators see when web-auth is missing on a .public setup.

    - CLAUDE.md: annotate discoverAllUserIdentities() as unavailable pending #28.

    - CredentialsTokenManagerTests: fill the missing routing-matrix branches
      (user-context × .private/.shared, .shared + token-only) and cover the new
      .invalidPrivateKey path.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---------

    Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

commit 6f92a71
Author: leogdion <leogdion@brightdigit.com>
Date:   Fri May 8 13:16:56 2026 -0400

    Resolve #308: docs refresh + CI fixes + sub-issues #165, #285 (#309)

commit a1e2162
Author: leogdion <leogdion@brightdigit.com>
Date:   Fri May 8 07:16:10 2026 -0400

    Add query pagination support with continuation markers (#306)

commit c62bf44
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 15:52:45 2026 -0400

    Improve error handling: typed TokenManagerError and safe RecordOperation conversion (#305)

commit 7c4b678
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 11:27:10 2026 -0400

    git subrepo push Examples/CelestraCloud

    subrepo:
      subdir:   "Examples/CelestraCloud"
      merged:   "4244497"
    upstream:
      origin:   "git@github.com:brightdigit/CelestraCloud.git"
      branch:   "mistkit"
      commit:   "4244497"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "b9763ee528"

commit f14e751
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 11:27:07 2026 -0400

    git subrepo push Examples/BushelCloud

    subrepo:
      subdir:   "Examples/BushelCloud"
      merged:   "123a732"
    upstream:
      origin:   "git@github.com:brightdigit/BushelCloud.git"
      branch:   "mistkit"
      commit:   "123a732"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "b9763ee528"

commit a0f0af9
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 11:26:32 2026 -0400

    updating example packages

commit 125dab5
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 11:01:18 2026 -0400

    Refactor AuthenticationMiddleware so each Authenticator applies itself (#294)

commit f989fd1
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 10:23:23 2026 -0400

    Strengthen environment and database configuration validation (#293)

commit b0f00a7
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 10:18:52 2026 -0400

    Add operation classification and batch sync result tracking (#296)

commit 63a4e50
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 10:09:27 2026 -0400

    Move CloudKitResponseType default implementations to protocol extension (#292)

commit ae1af15
Author: leogdion <leogdion@brightdigit.com>
Date:   Wed May 6 20:20:44 2026 -0400

    Test suite improvements for v1.0.0-beta.1 (#286) (#287)

commit 5475bfa
Author: leogdion <leogdion@brightdigit.com>
Date:   Tue May 5 20:21:32 2026 -0400

    MistDemo: --database flag + demo-errors command (closes #259, #269) (#282)

commit 8b21425
Author: leogdion <leogdion@brightdigit.com>
Date:   Tue May 5 20:21:17 2026 -0400

    Refactor IntegrationTestRunner into protocol-based phase pipeline (#254) (#283)

commit 9709f3d
Author: leogdion <leogdion@brightdigit.com>
Date:   Tue May 5 08:54:16 2026 -0400

    Replace custom AsyncChannel with swift-async-algorithms (#280)

commit d53467a
Author: leogdion <leogdion@brightdigit.com>
Date:   Mon May 4 12:49:25 2026 -0400

    CI Updates for May 2026 (#277)

commit d7b1a21
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Thu Apr 30 09:39:09 2026 -0400

    MistDemo improvements: test split, CRUD, auth fix, native app (#271) (#273)

commit 0ab2ab6
Author: leogdion <leogdion@brightdigit.com>
Date:   Wed Apr 29 15:49:34 2026 -0400

    First Draft Revision of Docs (#268)
leogdion added a commit that referenced this pull request May 18, 2026
commit de82483
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 21:14:35 2026 +0100

    git subrepo push Examples/CelestraCloud

    subrepo:
      subdir:   "Examples/CelestraCloud"
      merged:   "ea897c3"
    upstream:
      origin:   "git@github.com:brightdigit/CelestraCloud.git"
      branch:   "mistkit"
      commit:   "ea897c3"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "6f293daa9f"

commit 24c8719
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 21:14:31 2026 +0100

    git subrepo push Examples/BushelCloud

    subrepo:
      subdir:   "Examples/BushelCloud"
      merged:   "5bb4490"
    upstream:
      origin:   "git@github.com:brightdigit/BushelCloud.git"
      branch:   "mistkit"
      commit:   "5bb4490"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "6f293daa9f"

commit eee0670
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 21:14:13 2026 +0100

    docs: sync README/CLAUDE examples to v1.0.0-beta.1 API; pin BushelCloud CI; exclude internal Python from CodeFactor

    - README.md, Examples/BushelCloud/{CLAUDE.md,.docc,.claude/s2s-auth-details.md},
      Examples/CelestraCloud/{CLAUDE.md,README.md,.claude/IMPLEMENTATION_NOTES.md}:
      drop `try CloudKitService(... database: .public)` from init examples (init is
      non-throwing, `database:` moved per-call); rewrite Quick Start auth around
      `Credentials` + `APICredentials` / `ServerToServerCredentials` and show
      `database: .public(.prefers(.serverToServer))` at the call site.
    - Examples/BushelCloud/.github/workflows/{BushelCloud.yml,bushel-cloud-build.yml}:
      pin MISTKIT_BRANCH to v1.0.0-beta.1 (matches CelestraCloud) so the subrepo PR
      builds against the branch that actually carries the new API. Revert to `main`
      once #298 merges.
    - .codefactor.yml: exclude Scripts/mermaid-to-pptx.py (internal-use helper).

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

commit 4d60b19
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 20:10:45 2026 +0100

    git subrepo push Examples/CelestraCloud

    subrepo:
      subdir:   "Examples/CelestraCloud"
      merged:   "c44dc4f"
    upstream:
      origin:   "git@github.com:brightdigit/CelestraCloud.git"
      branch:   "mistkit"
      commit:   "c44dc4f"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "6f293daa9f"

commit 5bc403d
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 20:10:40 2026 +0100

    git subrepo push Examples/BushelCloud

    subrepo:
      subdir:   "Examples/BushelCloud"
      merged:   "55f2092"
    upstream:
      origin:   "git@github.com:brightdigit/BushelCloud.git"
      branch:   "mistkit"
      commit:   "55f2092"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "6f293daa9f"

commit bce1f23
Author: leogdion <leogdion@brightdigit.com>
Date:   Sun May 17 20:09:47 2026 +0100

    refactor!: prep for talk — shrink API, refactor auth, split OpenAPI (#279)

commit 7023a31
Author: leogdion <leogdion@brightdigit.com>
Date:   Fri May 15 12:56:58 2026 -0400

    Fixed Nonisolated Web Auth Token (#347)

commit f799128
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 14 20:27:28 2026 -0400

    Add MistDemo-Integration workflow for live CloudKit runs (#345)

commit 418e2e4
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 14 16:03:04 2026 -0400

    Resolve #342: v1.0.0-beta.1 follow-ups (#341 #327 #321 #317) + CI fixes (#343)

commit d65d20b
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 14 11:25:10 2026 -0400

    Resolve #330: interactive MistDemo (web toggle + native app refresh) (#332)

commit a28ab3c
Author: leogdion <leogdion@brightdigit.com>
Date:   Mon May 11 16:31:10 2026 -0400

    Resolve #313: paginationLimitExceeded carries accumulated records (#326)

commit 7a5da7a
Author: leogdion <leogdion@brightdigit.com>
Date:   Sat May 9 17:09:53 2026 -0400

    Fix CI failures + Claude review nits on PR #298 (v1.0.0-beta.1) (#322)

commit b3626c0
Author: leogdion <leogdion@brightdigit.com>
Date:   Sat May 9 16:06:20 2026 -0400

    Resolve #312: public+web-auth user-identity endpoints (#310, #311, #27, #28, #34, #35) (#315)

    * #312 library: add public+web-auth user-identity endpoints and users/caller migration

    Implements the library side of #312 — adding/renaming user-identity endpoints
    that require public-database routing with web-auth (user-context) credentials,
    and unblocking the convenience initializers from their hardcoded database/
    environment defaults.

    #310: `CloudKitService` convenience initializers now accept `database:` and
    `environment:` parameters with defaults that preserve current behavior.

    #311: `users/current` → `users/caller`. Renamed in openapi.yaml and the
    generated client; added a hand-written `fetchCaller()` plus an
    `@available(*, deprecated, renamed: "fetchCaller")` `fetchCurrentUser()`
    shim that forwards to the new method.

    #28: GET `/users/discover` (`discoverAllUserIdentities`).

    #34: POST `/users/lookup/email` (`lookupUsersByEmail`).

    #35: POST `/users/lookup/id` (`lookupUsersByRecordName`).

    The three new endpoints reuse `DiscoverResponse` for parsing — Apple returns
    `{ users: [UserIdentity] }` for all of them. Each ships with a 5-file
    test suite mirroring the existing `DiscoverUserIdentities` pattern.

    #33 (`users/lookup/contacts`) intentionally not implemented: Apple has marked
    the endpoint deprecated. To be closed as not-planned with a pointer to #34/#35.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #312 MistDemo: separate database from authentication and add user-context phases

    Refactors MistDemo's CloudKit configuration model and integration runner to
    support the public+web-auth combination required by the user-identity
    endpoints landed in the prior commit.

    **Configuration refactor.** Replaces the `DatabaseCredentials` enum (which
    coupled database choice to a single auth method per case, baking in a
    public⇒S2S/private⇒webAuth assumption) with two orthogonal types:

      - `AuthenticationCredentials` — `serverToServer(keyID:privateKey:)` /
        `webAuth(apiToken:webAuthToken:)`
      - `DatabaseConfiguration` — pairs a `MistKit.Database` with an
        `AuthenticationCredentials`. The `make(database:authentication:)` factory
        rejects private+S2S and shared+S2S (which CloudKit rejects) so invalid
        combinations remain unrepresentable, while public+webAuth is now a valid
        construction.

    `MistKitClientFactory.create(for:)` consumes `toPrimaryConfiguration()`;
    the new `createUserContext(for:)` returns the optional public+web-auth
    service from `toUserContextConfiguration()` when web-auth tokens are
    configured.

    **Phase plumbing.** `PhaseContext` and `IntegrationTestRunner` now thread an
    optional `userContextService: CloudKitService?`. `PublicDatabaseTest` takes
    `includeUserContextPhases:` and conditionally appends the new user-identity
    phases:

      - `FetchCallerPhase` (renamed from `FetchCurrentUserPhase`)
      - `DiscoverUserIdentitiesPhase` (existed; updated to use userContextService)
      - `DiscoverAllUserIdentitiesPhase` (#28)
      - `LookupUsersByEmailPhase` (#34)
      - `LookupUsersByRecordNamePhase` (#35)

    `PrivateDatabaseTest` no longer includes `FetchCurrentUserPhase`: CloudKit
    rejects `users/caller` against the private database, matching the rest of
    the user-identity family.

    **Call-site updates.** `CurrentUserCommand` and `DemoErrorsRunner` swap
    `fetchCurrentUser()` → `fetchCaller()`. `TestIntegrationCommand` and
    `TestPrivateCommand` now build and pass `userContextService`.

    Tests for `AuthenticationCredentials`, `DatabaseConfiguration.make`
    validation, and `MistDemoConfig.toPrimaryConfiguration` /
    `toUserContextConfiguration` ship alongside.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #312: mark discoverAllUserIdentities() unavailable pending #28 investigation

    Live verification on 2026-05-08 against iCloud.com.brightdigit.MistDemo
    returned HTTP 500 from Apple's GET /users/discover. The first 12 phases
    of mistdemo test-integration --verbose run green (the 8 base public+S2S
    phases plus FetchCallerPhase, DiscoverUserIdentitiesPhase,
    LookupUsersByEmailPhase, LookupUsersByRecordNamePhase) — only
    discoverAllUserIdentities fails, blocking phases beyond it.

    The endpoint is referenced in CloudKitJS but does not appear in Apple's
    CloudKit Web Services REST documentation. The actual REST shape is still
    under investigation under #28.

    Changes:
    - Marked `CloudKitService.discoverAllUserIdentities()`
      `@available(*, unavailable, message: ...)` with a pointer to #28.
    - Removed `DiscoverAllUserIdentitiesPhase` from MistDemo and from
      `PublicDatabaseTest.phases`.
    - Removed the `CloudKitServiceDiscoverAllUserIdentities` test directory
      (the unavailable method cannot be called from Swift code).

    The OpenAPI definition, generated client, path builder, response
    processor, Output extension, and Swift wrapper are all retained.
    Unblocking is a one-line `@available` removal once the correct REST
    shape is determined under #28.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #315: resolve PR review — Credentials API, per-call database, cascade unavailable

    Addresses all four review threads on PR #315:

    - Comment #1 (error wording): removed `unsupportedDatabaseAuthCombination`
      along with `MistDemo.DatabaseConfiguration`; invalid combos now surface as
      `CloudKitError.missingCredentials` from the library.
    - Comment #2 (per-call database): user-identity ops in
      `CloudKitService+UserOperations` hardcode `.public`; record/zone/asset/sync
      ops accept `database: Database? = nil` falling back to a service-level
      default.
    - Comment #3 (unified credentials): new `Credentials` /
      `ServerToServerCredentials` / `APICredentials` value types replace the
      legacy `apiToken:`/`webAuthToken:` initializers. The token manager is
      selected based on the target database (S2S for `.public`, web-auth for
      `.private`/`.shared`). Lifted `PrivateKeyMaterial` into the library.
    - Comment #4 (cascade unavailable): removed
      `Operations.discoverAllUserIdentities.Output: CloudKitResponseType`
      conformance entirely; `processDiscoverAllUserIdentitiesResponse` is now
      `@available(*, unavailable)` with a `fatalError` body.

    Also migrates ~15 MistKit test helpers and the MistDemo factory to the new
    Credentials API.

    Breaking changes (pre-1.0): removed legacy `CloudKitService` initializers
    taking `apiToken:`/`webAuthToken:`; `CloudKitService.apiToken` is removed,
    `.database` is now `internal`.

    Out of scope: per-call `TokenManager` dispatch (would let one service mix
    S2S-for-public and web-auth-for-user-context). MistDemo still constructs a
    separate `userContextService` for that scenario.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #315: drop service-level database, per-call credential resolution [skip ci]

    Resolves the architectural feedback in the PR-315 review:

    * CloudKitService no longer carries `database` — operations take
      `database:` per call (defaulting to `.public`); user-identity routes
      drop the parameter since CloudKit pins them to `.public`. Subsumes
      Claude's "fetchCaller bypasses self.database" finding.
    * Credentials.makeTokenManager(for:requiresUserContext:) resolves the
      appropriate token manager at dispatch time. A single service can now
      serve public-database S2S record ops and user-identity web-auth
      routes from one fully-populated `Credentials`. MistKitClient.swift is
      obsolete and removed; per-call dispatch lives in
      CloudKitService+ClientDispatch.
    * Credentials.swift split per SwiftLint one_file_per_declaration into
      ServerToServerCredentials.swift + APICredentials.swift +
      Credentials.swift. New typed CredentialsValidationError; init asserts
      in debug, throws in release (no more precondition crash for dynamic
      config).
    * MistDemo: userContextService workaround collapsed — single service
      handles all phases via per-call resolution.
    * CI hotfix: 11 unused `public import` lines demoted to `internal`
      (the warnings-as-errors regression flagged in the review).
    * Tests: 12-case routing-matrix unit suite for makeTokenManager and a
      fetchCaller suite parallel to LookupUsers* (success + validation).
      Obsolete MistKitClient tests removed.
    * Polish: shorter @available message on discoverAllUserIdentities,
      structural comment for GET /users/discover in openapi.yaml,
      ConfigurationError.missingAPIToken (unused) removed.

    475/475 tests pass. Library + MistDemo build clean.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * Per review on PR #315: listZones, lookupZones, fetchZoneChanges now
    default to .private since the public database only contains
    _defaultZone, making .public a degenerate default. MistDemo callers
    pass context.database / config.base.database explicitly so the
    --database flag still drives the test runs.

    Also repairs MistDemo test breakage from 7debe8d:
    toUserContextCredentials() was removed but tests still referenced it;
    rewritten against the replacement surface (toPrimaryCredentials embeds
    apiAuth on .public, plus the new hasUserContextCredentials boolean).
    The CredentialsValidationTests suite was deleted — it asserted
    init-time validation that no longer exists under per-call credential
    resolution; the equivalent .missingCredentials behavior is covered in
    MistKitTests.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #312: gate @available(*,unavailable) on processDiscoverAllUserIdentitiesResponse to Swift 6.2+

    Swift 6.1 rejects calls to an unavailable function from within another
    unavailable function; 6.2 relaxed that rule. The internal helper
    processDiscoverAllUserIdentitiesResponse is unavailable in lockstep with
    its only caller — the also-unavailable CloudKitService.discoverAllUserIdentities() —
    which built fine on 6.2+ but failed on Swift 6.1 with:

        error: 'processDiscoverAllUserIdentitiesResponse' is unavailable:
               Pending #28: discoverAllUserIdentities is not yet ready.

    Wrap just the attribute in `#if swift(>=6.2)` so the body is shared and
    6.1 compiles. Inline doc records the intent and the one-line cleanup
    (delete the #if/#endif) once 6.1 is dropped from the matrix.

    A `swiftlint:disable:next unavailable_function` is required because
    swiftlint does not evaluate #if and otherwise sees a fatalError-only
    function without the attribute.

    Verified: swift build + swift test pass on Swift 6.1.3 (Linux container)
    and on macOS Swift 6.2+ (475/475 tests).

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #315: split unhandled-response logging into debug (full body) + warning (type/status only)

    CodeQL's swift/cleartext-logging flagged the existing warning logs
    because lookupUsersByEmail(_:) propagates email-PII taint through the
    response object. Move full \(response) interpolation to .debug so the
    detail stays available for development without flowing into ops logs;
    keep .warning at type(of:) + HTTP status code only.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #312: add --lookup-email / CLOUDKIT_LOOKUP_EMAIL to exercise users/lookup/email

    LookupUsersByEmailPhase previously skipped whenever fetchCaller() didn't
    return an email (which is the common case). Plumb a configurable lookup
    email through TestIntegrationConfig / TestPrivateConfig → PhaseContext so
    the phase can be driven against a known-discoverable iCloud account.
    Falls back to caller email, then to a clearer skip message naming the
    flag/env var.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * docs: point CLAUDE.md lint section at mise (and Scripts/lint.sh)

    swift-format / swiftlint / periphery are pinned in mise.toml; the
    previous "requires swiftlint installation" wording led to PATH lookups
    that fail in this repo. Replace with `mise exec --` invocations and
    flag the full ./Scripts/lint.sh pipeline.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #315: address review punch list — invalidPrivateKey, recoverable unavailable response, supportsUserContextPhases derivation

    - CloudKitError: add invalidPrivateKey(path:underlying:) so PEM-load failures
      carry the file path + original error instead of bare Foundation NSError.
      Wrap loadPEM() at the single call site in Credentials+TokenManager. Add
      PrivateKeyMaterial.filePath accessor for the diagnostic.

    - processDiscoverAllUserIdentitiesResponse: replace fatalError with
      throw CloudKitError.unsupportedOperationType so a stray Swift 6.1 caller
      (where the @available cascade does not apply) gets a recoverable error
      instead of a crash.

    - TestPrivateCommand: derive supportsUserContextPhases from
      config.base.hasUserContextCredentials, mirroring TestIntegrationCommand,
      so user-identity phases skip cleanly when web-auth env vars are absent.

    - toPrimaryCredentials: replace try? with do/catch + stderr INFO line so
      operators see when web-auth is missing on a .public setup.

    - CLAUDE.md: annotate discoverAllUserIdentities() as unavailable pending #28.

    - CredentialsTokenManagerTests: fill the missing routing-matrix branches
      (user-context × .private/.shared, .shared + token-only) and cover the new
      .invalidPrivateKey path.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---------

    Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

commit 6f92a71
Author: leogdion <leogdion@brightdigit.com>
Date:   Fri May 8 13:16:56 2026 -0400

    Resolve #308: docs refresh + CI fixes + sub-issues #165, #285 (#309)

commit a1e2162
Author: leogdion <leogdion@brightdigit.com>
Date:   Fri May 8 07:16:10 2026 -0400

    Add query pagination support with continuation markers (#306)

commit c62bf44
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 15:52:45 2026 -0400

    Improve error handling: typed TokenManagerError and safe RecordOperation conversion (#305)

commit 7c4b678
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 11:27:10 2026 -0400

    git subrepo push Examples/CelestraCloud

    subrepo:
      subdir:   "Examples/CelestraCloud"
      merged:   "4244497"
    upstream:
      origin:   "git@github.com:brightdigit/CelestraCloud.git"
      branch:   "mistkit"
      commit:   "4244497"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "b9763ee528"

commit f14e751
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 11:27:07 2026 -0400

    git subrepo push Examples/BushelCloud

    subrepo:
      subdir:   "Examples/BushelCloud"
      merged:   "123a732"
    upstream:
      origin:   "git@github.com:brightdigit/BushelCloud.git"
      branch:   "mistkit"
      commit:   "123a732"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "b9763ee528"

commit a0f0af9
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 11:26:32 2026 -0400

    updating example packages

commit 125dab5
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 11:01:18 2026 -0400

    Refactor AuthenticationMiddleware so each Authenticator applies itself (#294)

commit f989fd1
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 10:23:23 2026 -0400

    Strengthen environment and database configuration validation (#293)

commit b0f00a7
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 10:18:52 2026 -0400

    Add operation classification and batch sync result tracking (#296)

commit 63a4e50
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 10:09:27 2026 -0400

    Move CloudKitResponseType default implementations to protocol extension (#292)

commit ae1af15
Author: leogdion <leogdion@brightdigit.com>
Date:   Wed May 6 20:20:44 2026 -0400

    Test suite improvements for v1.0.0-beta.1 (#286) (#287)

commit 5475bfa
Author: leogdion <leogdion@brightdigit.com>
Date:   Tue May 5 20:21:32 2026 -0400

    MistDemo: --database flag + demo-errors command (closes #259, #269) (#282)

commit 8b21425
Author: leogdion <leogdion@brightdigit.com>
Date:   Tue May 5 20:21:17 2026 -0400

    Refactor IntegrationTestRunner into protocol-based phase pipeline (#254) (#283)

commit 9709f3d
Author: leogdion <leogdion@brightdigit.com>
Date:   Tue May 5 08:54:16 2026 -0400

    Replace custom AsyncChannel with swift-async-algorithms (#280)

commit d53467a
Author: leogdion <leogdion@brightdigit.com>
Date:   Mon May 4 12:49:25 2026 -0400

    CI Updates for May 2026 (#277)

commit d7b1a21
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Thu Apr 30 09:39:09 2026 -0400

    MistDemo improvements: test split, CRUD, auth fix, native app (#271) (#273)

commit 0ab2ab6
Author: leogdion <leogdion@brightdigit.com>
Date:   Wed Apr 29 15:49:34 2026 -0400

    First Draft Revision of Docs (#268)
leogdion added a commit that referenced this pull request May 19, 2026
commit de82483
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 21:14:35 2026 +0100

    git subrepo push Examples/CelestraCloud

    subrepo:
      subdir:   "Examples/CelestraCloud"
      merged:   "ea897c3"
    upstream:
      origin:   "git@github.com:brightdigit/CelestraCloud.git"
      branch:   "mistkit"
      commit:   "ea897c3"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "6f293daa9f"

commit 24c8719
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 21:14:31 2026 +0100

    git subrepo push Examples/BushelCloud

    subrepo:
      subdir:   "Examples/BushelCloud"
      merged:   "5bb4490"
    upstream:
      origin:   "git@github.com:brightdigit/BushelCloud.git"
      branch:   "mistkit"
      commit:   "5bb4490"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "6f293daa9f"

commit eee0670
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 21:14:13 2026 +0100

    docs: sync README/CLAUDE examples to v1.0.0-beta.1 API; pin BushelCloud CI; exclude internal Python from CodeFactor

    - README.md, Examples/BushelCloud/{CLAUDE.md,.docc,.claude/s2s-auth-details.md},
      Examples/CelestraCloud/{CLAUDE.md,README.md,.claude/IMPLEMENTATION_NOTES.md}:
      drop `try CloudKitService(... database: .public)` from init examples (init is
      non-throwing, `database:` moved per-call); rewrite Quick Start auth around
      `Credentials` + `APICredentials` / `ServerToServerCredentials` and show
      `database: .public(.prefers(.serverToServer))` at the call site.
    - Examples/BushelCloud/.github/workflows/{BushelCloud.yml,bushel-cloud-build.yml}:
      pin MISTKIT_BRANCH to v1.0.0-beta.1 (matches CelestraCloud) so the subrepo PR
      builds against the branch that actually carries the new API. Revert to `main`
      once #298 merges.
    - .codefactor.yml: exclude Scripts/mermaid-to-pptx.py (internal-use helper).

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

commit 4d60b19
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 20:10:45 2026 +0100

    git subrepo push Examples/CelestraCloud

    subrepo:
      subdir:   "Examples/CelestraCloud"
      merged:   "c44dc4f"
    upstream:
      origin:   "git@github.com:brightdigit/CelestraCloud.git"
      branch:   "mistkit"
      commit:   "c44dc4f"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "6f293daa9f"

commit 5bc403d
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Sun May 17 20:10:40 2026 +0100

    git subrepo push Examples/BushelCloud

    subrepo:
      subdir:   "Examples/BushelCloud"
      merged:   "55f2092"
    upstream:
      origin:   "git@github.com:brightdigit/BushelCloud.git"
      branch:   "mistkit"
      commit:   "55f2092"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "6f293daa9f"

commit bce1f23
Author: leogdion <leogdion@brightdigit.com>
Date:   Sun May 17 20:09:47 2026 +0100

    refactor!: prep for talk — shrink API, refactor auth, split OpenAPI (#279)

commit 7023a31
Author: leogdion <leogdion@brightdigit.com>
Date:   Fri May 15 12:56:58 2026 -0400

    Fixed Nonisolated Web Auth Token (#347)

commit f799128
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 14 20:27:28 2026 -0400

    Add MistDemo-Integration workflow for live CloudKit runs (#345)

commit 418e2e4
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 14 16:03:04 2026 -0400

    Resolve #342: v1.0.0-beta.1 follow-ups (#341 #327 #321 #317) + CI fixes (#343)

commit d65d20b
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 14 11:25:10 2026 -0400

    Resolve #330: interactive MistDemo (web toggle + native app refresh) (#332)

commit a28ab3c
Author: leogdion <leogdion@brightdigit.com>
Date:   Mon May 11 16:31:10 2026 -0400

    Resolve #313: paginationLimitExceeded carries accumulated records (#326)

commit 7a5da7a
Author: leogdion <leogdion@brightdigit.com>
Date:   Sat May 9 17:09:53 2026 -0400

    Fix CI failures + Claude review nits on PR #298 (v1.0.0-beta.1) (#322)

commit b3626c0
Author: leogdion <leogdion@brightdigit.com>
Date:   Sat May 9 16:06:20 2026 -0400

    Resolve #312: public+web-auth user-identity endpoints (#310, #311, #27, #28, #34, #35) (#315)

    * #312 library: add public+web-auth user-identity endpoints and users/caller migration

    Implements the library side of #312 — adding/renaming user-identity endpoints
    that require public-database routing with web-auth (user-context) credentials,
    and unblocking the convenience initializers from their hardcoded database/
    environment defaults.

    #310: `CloudKitService` convenience initializers now accept `database:` and
    `environment:` parameters with defaults that preserve current behavior.

    #311: `users/current` → `users/caller`. Renamed in openapi.yaml and the
    generated client; added a hand-written `fetchCaller()` plus an
    `@available(*, deprecated, renamed: "fetchCaller")` `fetchCurrentUser()`
    shim that forwards to the new method.

    #28: GET `/users/discover` (`discoverAllUserIdentities`).

    #34: POST `/users/lookup/email` (`lookupUsersByEmail`).

    #35: POST `/users/lookup/id` (`lookupUsersByRecordName`).

    The three new endpoints reuse `DiscoverResponse` for parsing — Apple returns
    `{ users: [UserIdentity] }` for all of them. Each ships with a 5-file
    test suite mirroring the existing `DiscoverUserIdentities` pattern.

    #33 (`users/lookup/contacts`) intentionally not implemented: Apple has marked
    the endpoint deprecated. To be closed as not-planned with a pointer to #34/#35.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #312 MistDemo: separate database from authentication and add user-context phases

    Refactors MistDemo's CloudKit configuration model and integration runner to
    support the public+web-auth combination required by the user-identity
    endpoints landed in the prior commit.

    **Configuration refactor.** Replaces the `DatabaseCredentials` enum (which
    coupled database choice to a single auth method per case, baking in a
    public⇒S2S/private⇒webAuth assumption) with two orthogonal types:

      - `AuthenticationCredentials` — `serverToServer(keyID:privateKey:)` /
        `webAuth(apiToken:webAuthToken:)`
      - `DatabaseConfiguration` — pairs a `MistKit.Database` with an
        `AuthenticationCredentials`. The `make(database:authentication:)` factory
        rejects private+S2S and shared+S2S (which CloudKit rejects) so invalid
        combinations remain unrepresentable, while public+webAuth is now a valid
        construction.

    `MistKitClientFactory.create(for:)` consumes `toPrimaryConfiguration()`;
    the new `createUserContext(for:)` returns the optional public+web-auth
    service from `toUserContextConfiguration()` when web-auth tokens are
    configured.

    **Phase plumbing.** `PhaseContext` and `IntegrationTestRunner` now thread an
    optional `userContextService: CloudKitService?`. `PublicDatabaseTest` takes
    `includeUserContextPhases:` and conditionally appends the new user-identity
    phases:

      - `FetchCallerPhase` (renamed from `FetchCurrentUserPhase`)
      - `DiscoverUserIdentitiesPhase` (existed; updated to use userContextService)
      - `DiscoverAllUserIdentitiesPhase` (#28)
      - `LookupUsersByEmailPhase` (#34)
      - `LookupUsersByRecordNamePhase` (#35)

    `PrivateDatabaseTest` no longer includes `FetchCurrentUserPhase`: CloudKit
    rejects `users/caller` against the private database, matching the rest of
    the user-identity family.

    **Call-site updates.** `CurrentUserCommand` and `DemoErrorsRunner` swap
    `fetchCurrentUser()` → `fetchCaller()`. `TestIntegrationCommand` and
    `TestPrivateCommand` now build and pass `userContextService`.

    Tests for `AuthenticationCredentials`, `DatabaseConfiguration.make`
    validation, and `MistDemoConfig.toPrimaryConfiguration` /
    `toUserContextConfiguration` ship alongside.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #312: mark discoverAllUserIdentities() unavailable pending #28 investigation

    Live verification on 2026-05-08 against iCloud.com.brightdigit.MistDemo
    returned HTTP 500 from Apple's GET /users/discover. The first 12 phases
    of mistdemo test-integration --verbose run green (the 8 base public+S2S
    phases plus FetchCallerPhase, DiscoverUserIdentitiesPhase,
    LookupUsersByEmailPhase, LookupUsersByRecordNamePhase) — only
    discoverAllUserIdentities fails, blocking phases beyond it.

    The endpoint is referenced in CloudKitJS but does not appear in Apple's
    CloudKit Web Services REST documentation. The actual REST shape is still
    under investigation under #28.

    Changes:
    - Marked `CloudKitService.discoverAllUserIdentities()`
      `@available(*, unavailable, message: ...)` with a pointer to #28.
    - Removed `DiscoverAllUserIdentitiesPhase` from MistDemo and from
      `PublicDatabaseTest.phases`.
    - Removed the `CloudKitServiceDiscoverAllUserIdentities` test directory
      (the unavailable method cannot be called from Swift code).

    The OpenAPI definition, generated client, path builder, response
    processor, Output extension, and Swift wrapper are all retained.
    Unblocking is a one-line `@available` removal once the correct REST
    shape is determined under #28.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #315: resolve PR review — Credentials API, per-call database, cascade unavailable

    Addresses all four review threads on PR #315:

    - Comment #1 (error wording): removed `unsupportedDatabaseAuthCombination`
      along with `MistDemo.DatabaseConfiguration`; invalid combos now surface as
      `CloudKitError.missingCredentials` from the library.
    - Comment #2 (per-call database): user-identity ops in
      `CloudKitService+UserOperations` hardcode `.public`; record/zone/asset/sync
      ops accept `database: Database? = nil` falling back to a service-level
      default.
    - Comment #3 (unified credentials): new `Credentials` /
      `ServerToServerCredentials` / `APICredentials` value types replace the
      legacy `apiToken:`/`webAuthToken:` initializers. The token manager is
      selected based on the target database (S2S for `.public`, web-auth for
      `.private`/`.shared`). Lifted `PrivateKeyMaterial` into the library.
    - Comment #4 (cascade unavailable): removed
      `Operations.discoverAllUserIdentities.Output: CloudKitResponseType`
      conformance entirely; `processDiscoverAllUserIdentitiesResponse` is now
      `@available(*, unavailable)` with a `fatalError` body.

    Also migrates ~15 MistKit test helpers and the MistDemo factory to the new
    Credentials API.

    Breaking changes (pre-1.0): removed legacy `CloudKitService` initializers
    taking `apiToken:`/`webAuthToken:`; `CloudKitService.apiToken` is removed,
    `.database` is now `internal`.

    Out of scope: per-call `TokenManager` dispatch (would let one service mix
    S2S-for-public and web-auth-for-user-context). MistDemo still constructs a
    separate `userContextService` for that scenario.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #315: drop service-level database, per-call credential resolution [skip ci]

    Resolves the architectural feedback in the PR-315 review:

    * CloudKitService no longer carries `database` — operations take
      `database:` per call (defaulting to `.public`); user-identity routes
      drop the parameter since CloudKit pins them to `.public`. Subsumes
      Claude's "fetchCaller bypasses self.database" finding.
    * Credentials.makeTokenManager(for:requiresUserContext:) resolves the
      appropriate token manager at dispatch time. A single service can now
      serve public-database S2S record ops and user-identity web-auth
      routes from one fully-populated `Credentials`. MistKitClient.swift is
      obsolete and removed; per-call dispatch lives in
      CloudKitService+ClientDispatch.
    * Credentials.swift split per SwiftLint one_file_per_declaration into
      ServerToServerCredentials.swift + APICredentials.swift +
      Credentials.swift. New typed CredentialsValidationError; init asserts
      in debug, throws in release (no more precondition crash for dynamic
      config).
    * MistDemo: userContextService workaround collapsed — single service
      handles all phases via per-call resolution.
    * CI hotfix: 11 unused `public import` lines demoted to `internal`
      (the warnings-as-errors regression flagged in the review).
    * Tests: 12-case routing-matrix unit suite for makeTokenManager and a
      fetchCaller suite parallel to LookupUsers* (success + validation).
      Obsolete MistKitClient tests removed.
    * Polish: shorter @available message on discoverAllUserIdentities,
      structural comment for GET /users/discover in openapi.yaml,
      ConfigurationError.missingAPIToken (unused) removed.

    475/475 tests pass. Library + MistDemo build clean.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * Per review on PR #315: listZones, lookupZones, fetchZoneChanges now
    default to .private since the public database only contains
    _defaultZone, making .public a degenerate default. MistDemo callers
    pass context.database / config.base.database explicitly so the
    --database flag still drives the test runs.

    Also repairs MistDemo test breakage from 7debe8d:
    toUserContextCredentials() was removed but tests still referenced it;
    rewritten against the replacement surface (toPrimaryCredentials embeds
    apiAuth on .public, plus the new hasUserContextCredentials boolean).
    The CredentialsValidationTests suite was deleted — it asserted
    init-time validation that no longer exists under per-call credential
    resolution; the equivalent .missingCredentials behavior is covered in
    MistKitTests.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #312: gate @available(*,unavailable) on processDiscoverAllUserIdentitiesResponse to Swift 6.2+

    Swift 6.1 rejects calls to an unavailable function from within another
    unavailable function; 6.2 relaxed that rule. The internal helper
    processDiscoverAllUserIdentitiesResponse is unavailable in lockstep with
    its only caller — the also-unavailable CloudKitService.discoverAllUserIdentities() —
    which built fine on 6.2+ but failed on Swift 6.1 with:

        error: 'processDiscoverAllUserIdentitiesResponse' is unavailable:
               Pending #28: discoverAllUserIdentities is not yet ready.

    Wrap just the attribute in `#if swift(>=6.2)` so the body is shared and
    6.1 compiles. Inline doc records the intent and the one-line cleanup
    (delete the #if/#endif) once 6.1 is dropped from the matrix.

    A `swiftlint:disable:next unavailable_function` is required because
    swiftlint does not evaluate #if and otherwise sees a fatalError-only
    function without the attribute.

    Verified: swift build + swift test pass on Swift 6.1.3 (Linux container)
    and on macOS Swift 6.2+ (475/475 tests).

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #315: split unhandled-response logging into debug (full body) + warning (type/status only)

    CodeQL's swift/cleartext-logging flagged the existing warning logs
    because lookupUsersByEmail(_:) propagates email-PII taint through the
    response object. Move full \(response) interpolation to .debug so the
    detail stays available for development without flowing into ops logs;
    keep .warning at type(of:) + HTTP status code only.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #312: add --lookup-email / CLOUDKIT_LOOKUP_EMAIL to exercise users/lookup/email

    LookupUsersByEmailPhase previously skipped whenever fetchCaller() didn't
    return an email (which is the common case). Plumb a configurable lookup
    email through TestIntegrationConfig / TestPrivateConfig → PhaseContext so
    the phase can be driven against a known-discoverable iCloud account.
    Falls back to caller email, then to a clearer skip message naming the
    flag/env var.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * docs: point CLAUDE.md lint section at mise (and Scripts/lint.sh)

    swift-format / swiftlint / periphery are pinned in mise.toml; the
    previous "requires swiftlint installation" wording led to PATH lookups
    that fail in this repo. Replace with `mise exec --` invocations and
    flag the full ./Scripts/lint.sh pipeline.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    * #315: address review punch list — invalidPrivateKey, recoverable unavailable response, supportsUserContextPhases derivation

    - CloudKitError: add invalidPrivateKey(path:underlying:) so PEM-load failures
      carry the file path + original error instead of bare Foundation NSError.
      Wrap loadPEM() at the single call site in Credentials+TokenManager. Add
      PrivateKeyMaterial.filePath accessor for the diagnostic.

    - processDiscoverAllUserIdentitiesResponse: replace fatalError with
      throw CloudKitError.unsupportedOperationType so a stray Swift 6.1 caller
      (where the @available cascade does not apply) gets a recoverable error
      instead of a crash.

    - TestPrivateCommand: derive supportsUserContextPhases from
      config.base.hasUserContextCredentials, mirroring TestIntegrationCommand,
      so user-identity phases skip cleanly when web-auth env vars are absent.

    - toPrimaryCredentials: replace try? with do/catch + stderr INFO line so
      operators see when web-auth is missing on a .public setup.

    - CLAUDE.md: annotate discoverAllUserIdentities() as unavailable pending #28.

    - CredentialsTokenManagerTests: fill the missing routing-matrix branches
      (user-context × .private/.shared, .shared + token-only) and cover the new
      .invalidPrivateKey path.

    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

    ---------

    Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

commit 6f92a71
Author: leogdion <leogdion@brightdigit.com>
Date:   Fri May 8 13:16:56 2026 -0400

    Resolve #308: docs refresh + CI fixes + sub-issues #165, #285 (#309)

commit a1e2162
Author: leogdion <leogdion@brightdigit.com>
Date:   Fri May 8 07:16:10 2026 -0400

    Add query pagination support with continuation markers (#306)

commit c62bf44
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 15:52:45 2026 -0400

    Improve error handling: typed TokenManagerError and safe RecordOperation conversion (#305)

commit 7c4b678
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 11:27:10 2026 -0400

    git subrepo push Examples/CelestraCloud

    subrepo:
      subdir:   "Examples/CelestraCloud"
      merged:   "4244497"
    upstream:
      origin:   "git@github.com:brightdigit/CelestraCloud.git"
      branch:   "mistkit"
      commit:   "4244497"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "b9763ee528"

commit f14e751
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 11:27:07 2026 -0400

    git subrepo push Examples/BushelCloud

    subrepo:
      subdir:   "Examples/BushelCloud"
      merged:   "123a732"
    upstream:
      origin:   "git@github.com:brightdigit/BushelCloud.git"
      branch:   "mistkit"
      commit:   "123a732"
    git-subrepo:
      version:  "0.4.9"
      origin:   "https://github.com/Homebrew/brew"
      commit:   "b9763ee528"

commit a0f0af9
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 11:26:32 2026 -0400

    updating example packages

commit 125dab5
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 11:01:18 2026 -0400

    Refactor AuthenticationMiddleware so each Authenticator applies itself (#294)

commit f989fd1
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 10:23:23 2026 -0400

    Strengthen environment and database configuration validation (#293)

commit b0f00a7
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 10:18:52 2026 -0400

    Add operation classification and batch sync result tracking (#296)

commit 63a4e50
Author: leogdion <leogdion@brightdigit.com>
Date:   Thu May 7 10:09:27 2026 -0400

    Move CloudKitResponseType default implementations to protocol extension (#292)

commit ae1af15
Author: leogdion <leogdion@brightdigit.com>
Date:   Wed May 6 20:20:44 2026 -0400

    Test suite improvements for v1.0.0-beta.1 (#286) (#287)

commit 5475bfa
Author: leogdion <leogdion@brightdigit.com>
Date:   Tue May 5 20:21:32 2026 -0400

    MistDemo: --database flag + demo-errors command (closes #259, #269) (#282)

commit 8b21425
Author: leogdion <leogdion@brightdigit.com>
Date:   Tue May 5 20:21:17 2026 -0400

    Refactor IntegrationTestRunner into protocol-based phase pipeline (#254) (#283)

commit 9709f3d
Author: leogdion <leogdion@brightdigit.com>
Date:   Tue May 5 08:54:16 2026 -0400

    Replace custom AsyncChannel with swift-async-algorithms (#280)

commit d53467a
Author: leogdion <leogdion@brightdigit.com>
Date:   Mon May 4 12:49:25 2026 -0400

    CI Updates for May 2026 (#277)

commit d7b1a21
Author: Leo Dion <leogdion@brightdigit.com>
Date:   Thu Apr 30 09:39:09 2026 -0400

    MistDemo improvements: test split, CRUD, auth fix, native app (#271) (#273)

commit 0ab2ab6
Author: leogdion <leogdion@brightdigit.com>
Date:   Wed Apr 29 15:49:34 2026 -0400

    First Draft Revision of Docs (#268)
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.

2 participants