Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/quiet-booleans-match.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"posthog": patch
"posthog-server": patch
---

Retain `property_matching_version` in local-evaluation definitions and shared caches. Server-side local evaluation now uses explicit boolean matching for version 2, preserves legacy matching for missing/1, and keeps one definition snapshot through group, cohort, and dependency evaluation and version-only refreshes. In-flight remote evaluations retain their response errors and request metadata when definitions refresh, without repopulating the new result cache.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ public interface PostHogFlagDefinitionCacheProvider {
* Return cached flag definitions, or null when the cache is empty or unavailable.
*
* The data should use the shared local-evaluation definitions shape returned by PostHog's
* `/flags/definitions` endpoint: `flags`, `group_type_mapping`, and `cohorts`.
* `/flags/definitions` endpoint: `flags`, `group_type_mapping`, `cohorts`, and
* `property_matching_version`. Preserve the matching version with the definitions;
* older entries without it use legacy property matching.
*/
public fun getFlagDefinitions(): CompletionStage<Map<String, Any?>?>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import java.util.regex.PatternSyntaxException
*/
internal class FlagEvaluator(
private val config: PostHogConfig,
private val propertyMatchingVersion: Int? = null,
) {
companion object {
private const val LONG_SCALE = 0xFFFFFFFFFFFFFFF.toDouble()
Expand Down Expand Up @@ -240,7 +241,11 @@ internal class FlagEvaluator(
propertyValue: Any?,
overrideValue: Any?,
): Boolean {
if (isTruthyOrFalsyPropertyValue(propertyValue)) {
// Empty filters retain recursive ALL truthiness in both matching versions.
if (propertyValue is List<*> && propertyValue.isEmpty()) {
return isTruthyPropertyValue(overrideValue)
}
if (propertyMatchingVersion != 2 && isTruthyOrFalsyPropertyValue(propertyValue)) {
return isTruthyPropertyValue(propertyValue) == isTruthyPropertyValue(overrideValue)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ internal class PostHogFeatureFlagCache(
requestId: String? = null,
evaluatedAt: Long? = null,
error: String? = null,
) {
): FeatureFlagCacheEntry {
val currentTime = System.currentTimeMillis()
val entry =
FeatureFlagCacheEntry(
Expand All @@ -66,6 +66,7 @@ internal class PostHogFeatureFlagCache(
)

cache[key] = entry
return entry
}

/**
Expand Down
Loading
Loading