Skip to content

Docs/talk prep archive#355

Draft
leogdion wants to merge 30 commits into
v1.0.0-beta.2from
docs/talk-prep-archive
Draft

Docs/talk prep archive#355
leogdion wants to merge 30 commits into
v1.0.0-beta.2from
docs/talk-prep-archive

Conversation

@leogdion
Copy link
Copy Markdown
Member

No description provided.

leogdion and others added 30 commits May 11, 2026 15:14
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"
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"
#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>
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"
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"
…ud 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>
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"
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"
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

Important

Review skipped

Draft detected.

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: 7fb50df5-62ad-45f1-b55f-340918400449

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 docs/talk-prep-archive

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.

@claude
Copy link
Copy Markdown

claude Bot commented May 19, 2026

Code Review — PR #355 (DRAFT)

Note: This PR is marked DRAFT and targets v1.0.0-beta.2 (not main). Review notes are intended as early feedback for when it's ready to finalize.


Overview

This is a large archival/prep PR (~80k additions, ~47k deletions across 100+ files) that bundles roughly 25 commits covering:

  • CI/CD overhaul — new MistDemo-Integration.yml and MistDemo.yml workflows, a reusable setup-tools action, cache cleanup workflow, devcontainer refresh (Swift 6.3 replaces 6.3-nightly)
  • API refactoring — per-call credential resolution (Credentials / ServerToServerCredentials / APICredentials), database routing moved from service level to call site
  • New user-identity endpointsfetchCaller, lookupUsersByEmail, lookupUsersByRecordName
  • Example app updates — BushelCloud and CelestraCloud both significantly evolved (new KeyIDValidator, ExitError, UpdateCommand+Reporting, ConfigurationError, CloudKitRecordOperating protocol expansion, JSON output support)
  • Documentation — CLAUDE.md, READMEs, and .claude/docs/ refreshed to match the beta.1 API surface

Code Quality & Best Practices

Positive observations from commit history:

  • The credentials refactor (Credentials split into ServerToServerCredentials + APICredentials) is a clean separation of concerns that avoids the previous "database coupled to auth method" design smell.
  • The @available(*, unavailable) cascade on discoverAllUserIdentities() (with a #if swift(>=6.2) guard for 6.1 compatibility) is handled carefully — keeping the OpenAPI definition and generated code intact while preventing premature usage.
  • A CodeQL cleartext-logging finding was addressed by moving full \(response) interpolation to .debug and keeping .warning at type/status-only — good security hygiene.
  • The invalidPrivateKey(path:underlying:) error case improvement over a bare Foundation NSError is exactly the right direction for diagnostics.
  • discoverAllUserIdentities marked @available(*, unavailable) with a fatalErrorthrow CloudKitError.unsupportedOperationType replacement is better (recoverable errors > crashes).

Potential concerns to verify before un-drafting:

  1. Bundle size / reviewability — 25+ squashed commits covering multiple independent features makes this very hard to review atomically. Consider whether some of the CI/tooling changes (e.g., the setup-tools action, cleanup-caches.yml) can be broken out separately, or at minimum ensure the commit messages in the final PR squash are accurate.

  2. Base branch — The PR targets v1.0.0-beta.2, and MISTKIT_BRANCH in BushelCloud/CelestraCloud workflows is pinned to v1.0.0-beta.1 pending v1.0.0 beta.1 #298 merging. Verify this pin gets updated to v1.0.0-beta.2 (or main) before this lands, otherwise the example CI builds may test against an older API surface.

  3. KeyIDValidator.swift (BushelCloud, 89 lines, new file) — Not readable via the API in this review pass, but given the context (server-to-server auth key validation), ensure:

    • Validation errors use the project's CloudKitError.invalidPrivateKey(path:underlying:) type rather than generic Error.
    • No key material is logged at any level (.debug included), only paths or non-sensitive metadata.
  4. ExitError.swift (CelestraCloud, 31 lines) — Verify it conforms to LocalizedError (per CLAUDE.md: "typed errors conforming to LocalizedError") and includes a meaningful errorDescription.

  5. UpdateCommand+Reporting.swift (134 lines) — If this touches console/log output, make sure sensitive fields (tokens, record names used as IDs) don't appear at .info level or above.

  6. Import access modifiers — All non-generated Swift files must use internal import X or public import X (bare import X is a CLAUDE.md violation, though not lint-enforced). This should be verified before merge given the large number of new files.

  7. discoverAllUserIdentities Swift 6.1 carve-out — The #if swift(>=6.2) … @available(*, unavailable) … #endif pattern is documented in CLAUDE.md as intentional. Confirm a TODO or GitHub issue (File Apple Feedback Assistant report: discoverAllUserIdentities returns HTTP 500 #28) tracks removing the #if/#endif once Swift 6.1 support is dropped.


CI / Workflow Changes

  • New MistDemo-Integration.yml (203 lines) runs live CloudKit integration tests — confirm it only runs on trusted inputs (no pull_request trigger from forks, or uses pull_request_target carefully) to avoid credential leakage.
  • cleanup-caches.yml is a welcome addition if it targets stale branch caches.
  • The new setup-tools reusable action consolidates mise + tool setup — good DRY improvement if it replaces copy-pasted steps in multiple workflows.

Test Coverage

The commit messages describe test additions for:

  • makeTokenManager routing-matrix (12-case suite)
  • fetchCaller (success + validation)
  • AuthenticationCredentials, DatabaseConfiguration.make validation

No obvious gaps from commit descriptions, but with this many changes the overall coverage picture should be verified once CI runs clean.


Minor / Nits

  • .codefactor.yml adds an exclusion for Scripts/mermaid-to-pptx.py — confirm this script isn't in-scope for any security scanning (CodeQL, etc.) separately.
  • swiftlint:disable:next unavailable_function on the discoverAllUserIdentities helper is noted in commit messages as required because SwiftLint doesn't evaluate #if. Consider adding a comment explaining this workaround inline for future maintainers.

Summary

The code direction and decisions reflected in the commit messages look solid. The main pre-merge items are: (a) verify the MISTKIT_BRANCH pin in examples, (b) check KeyIDValidator doesn't log sensitive key material, (c) audit new files for bare import violations, and (d) ensure the integration workflow isn't triggerable from forked PRs.

Once CI is green and the DRAFT is lifted, this looks close to mergeable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant