- 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.
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.