[sub-spm-optional-products] LCFeatureControl review fixes: JWT log leak, platforms, request coalescing #13

Merged
daniel-loverde merged 2 commits from feature/spm/lcfeaturecontrol into main 2026-09-16 13:31:39 -03:00
Collaborator

Follow-up fixes on top of the LCECryptoKit/LCFeatureControl sub-SPM commit, from a code review of 2ba487a.

Changes

  • JWT log leak (critical): all api.request(...) call sites in FeatureControlManager/FeatureControlNotificationsClient now pass debug: false. The API default is debug: true with no #if DEBUG gate, so Authorization: Bearer <jwt> was printing on every request, including in release builds.
  • Platforms: dropped macOS/tvOS from Package.swiftLCEssentials.API (used by LCFeatureControl) is iOS/watchOS-only, and the vendored LCECryptoKit.xcframework has no macOS/tvOS slice.
  • Request coalescing: concurrent evaluate() calls on a cold cache now share a single in-flight request per cache key instead of firing one per caller.
  • Envelope validation: a 200 response carrying {"error": true} is now treated as a failure in evaluate/evaluateOrThrow and list, instead of being cached/returned as success.
  • Pagination: list(status:limit:cursor:) now threads a cursor through so the already-decoded nextCursor can actually be used to page.
  • Tests: 9 new tests (coalescing, envelope-error-on-200, cursor param, a real object payload decoded through a full evaluate response, date-decode failures). 45 → 54 tests in LCFeatureControlTests. Removed the 7 remaining force-unwraps in test scaffolding.
  • Docs: new Documentation/FeatureControl.md, cross-linked from README.md and Extensions.md.

Test plan

  • xcodebuild test -scheme LCEssentials-Package -destination 'platform=iOS Simulator,...' — 84/84 passing (30 LCEssentialsTests + 54 LCFeatureControlTests), 0 failures.
  • swift build --product LCEssentials — clean.
Follow-up fixes on top of the LCECryptoKit/LCFeatureControl sub-SPM commit, from a code review of `2ba487a`. ## Changes - **JWT log leak (critical):** all `api.request(...)` call sites in `FeatureControlManager`/`FeatureControlNotificationsClient` now pass `debug: false`. The `API` default is `debug: true` with no `#if DEBUG` gate, so `Authorization: Bearer <jwt>` was printing on every request, including in release builds. - **Platforms:** dropped macOS/tvOS from `Package.swift` — `LCEssentials.API` (used by `LCFeatureControl`) is iOS/watchOS-only, and the vendored `LCECryptoKit.xcframework` has no macOS/tvOS slice. - **Request coalescing:** concurrent `evaluate()` calls on a cold cache now share a single in-flight request per cache key instead of firing one per caller. - **Envelope validation:** a `200` response carrying `{"error": true}` is now treated as a failure in `evaluate`/`evaluateOrThrow` and `list`, instead of being cached/returned as success. - **Pagination:** `list(status:limit:cursor:)` now threads a cursor through so the already-decoded `nextCursor` can actually be used to page. - **Tests:** 9 new tests (coalescing, envelope-error-on-200, cursor param, a real object `payload` decoded through a full evaluate response, date-decode failures). 45 → 54 tests in `LCFeatureControlTests`. Removed the 7 remaining force-unwraps in test scaffolding. - **Docs:** new `Documentation/FeatureControl.md`, cross-linked from `README.md` and `Extensions.md`. ## Test plan - [x] `xcodebuild test -scheme LCEssentials-Package -destination 'platform=iOS Simulator,...'` — 84/84 passing (30 `LCEssentialsTests` + 54 `LCFeatureControlTests`), 0 failures. - [x] `swift build --product LCEssentials` — clean.
claude_cli added 2 commits 2026-09-16 13:31:13 -03:00
LCEssentials installs standalone; each sub target-depends on it so linking a
sub's product always pulls LCEssentials in too, without the consumer having to
declare it separately.

- LCECryptoKit: internalized from the remote LCECryptoKitBinary git dependency
  (embedded token URL removed) into a local binaryTarget vendoring
  Frameworks/LCECryptoKit.xcframework. LCECryptoKitManager moved out of
  LCEssentials core into its own LCECryptoKitManager target/product; the
  no-op fallback for when the binary wasn't linked is gone (breaking change
  for existing consumers, see decisions/2026-09-15-sub-spm-optional-products.md).
- LCFeatureControl: new product wrapping Atomenta's Feature Control API
  (flag evaluation with TTL cache + safe-degrade fallback to defaults,
  notifications inbox, batched exposure telemetry). 45 new tests.
- FeatureControlManager/NotificationsClient: pass debug: false at every
  api.request(...) call site — the API default (debug: true) was printing
  Authorization: Bearer <jwt> on every request, release builds included.
- Package.swift: drop macOS/tvOS from platforms — LCEssentials.API (used by
  LCFeatureControl) is iOS/watchOS-only and the vendored xcframework has no
  macOS/tvOS slice.
- FeatureControlManager: coalesce concurrent evaluate() calls on a cold cache
  into a single in-flight request per key instead of firing one per caller.
- FeatureControlManager/NotificationsClient: treat a 200 response carrying
  {"error": true} as a failure instead of caching/returning it as success.
- FeatureControlNotificationsClient: thread a cursor param through list() so
  the already-decoded nextCursor can actually be used to page.
- Tests: 9 new tests (coalescing, envelope-error-on-200, cursor param, a real
  object payload decoded through a full evaluate response, date-decode
  failures) and removed the 7 remaining force-unwraps in test scaffolding.
- Documentation/FeatureControl.md: new guide for the LCFeatureControl product,
  cross-linked from README.md and Extensions.md.
daniel-loverde approved these changes 2026-09-16 13:31:34 -03:00
daniel-loverde merged commit b1f370f7db into main 2026-09-16 13:31:39 -03:00
daniel-loverde deleted branch feature/spm/lcfeaturecontrol 2026-09-16 13:31:40 -03:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Loverde-Company-LTDA/LCEssentials#13
No description provided.