feat(features): mirror invalidatedBy into Python ProfileFeature (#61)
Adds invalidated_by: tuple[str, ...] to ProfileFeature, mirroring the invalidatedBy bus subjects from registry.ts. Adds a test that parses the TS source and asserts Python stays in sync — same drift-detection pattern used for names and ttlSec. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,10 +10,12 @@ Update this file whenever you add or rename a feature in the TS registry.
|
||||
The accompanying test asserts the two stay in sync at the name level.
|
||||
|
||||
Feature-spec fields (issue #61):
|
||||
freshness — "batched": value cached in profile store, recomputed on TTL/event.
|
||||
ttl_sec — cache lifetime in seconds; mirrors ``ttlSec`` in registry.ts.
|
||||
source — where the value originates.
|
||||
fallback — raw value returned when the feature is unavailable (null stored).
|
||||
freshness — "batched": value cached in profile store, recomputed on TTL/event.
|
||||
ttl_sec — cache lifetime in seconds; mirrors ``ttlSec`` in registry.ts.
|
||||
source — where the value originates.
|
||||
fallback — raw value returned when the feature is unavailable (null stored).
|
||||
invalidated_by — bus event subjects that trigger recompute for the affected user;
|
||||
mirrors ``invalidatedBy`` in registry.ts. Empty = TTL-only refresh.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -37,6 +39,7 @@ class ProfileFeature:
|
||||
ttl_sec: int
|
||||
source: str
|
||||
fallback: str
|
||||
invalidated_by: tuple[str, ...] = ()
|
||||
|
||||
|
||||
PROFILE_FEATURES: tuple[ProfileFeature, ...] = (
|
||||
@@ -48,6 +51,7 @@ PROFILE_FEATURES: tuple[ProfileFeature, ...] = (
|
||||
ttl_sec=6 * _HOUR,
|
||||
source="profile_store",
|
||||
fallback="0.0",
|
||||
invalidated_by=("signals.tip.feedback",),
|
||||
),
|
||||
ProfileFeature(
|
||||
name="dismiss_rate_30d",
|
||||
@@ -57,6 +61,7 @@ PROFILE_FEATURES: tuple[ProfileFeature, ...] = (
|
||||
ttl_sec=6 * _HOUR,
|
||||
source="profile_store",
|
||||
fallback="0.0",
|
||||
invalidated_by=("signals.tip.feedback",),
|
||||
),
|
||||
ProfileFeature(
|
||||
name="mean_dwell_ms_30d",
|
||||
@@ -66,6 +71,7 @@ PROFILE_FEATURES: tuple[ProfileFeature, ...] = (
|
||||
ttl_sec=6 * _HOUR,
|
||||
source="profile_store",
|
||||
fallback="null — serving normalises to 0.0",
|
||||
invalidated_by=("signals.tip.feedback",),
|
||||
),
|
||||
ProfileFeature(
|
||||
name="preferred_hour",
|
||||
@@ -75,6 +81,7 @@ PROFILE_FEATURES: tuple[ProfileFeature, ...] = (
|
||||
ttl_sec=_DAY,
|
||||
source="profile_store",
|
||||
fallback="null — serving normalises to 0.5 (neutral alignment)",
|
||||
invalidated_by=("signals.tip.feedback",),
|
||||
),
|
||||
ProfileFeature(
|
||||
name="tip_volume_30d",
|
||||
@@ -84,6 +91,7 @@ PROFILE_FEATURES: tuple[ProfileFeature, ...] = (
|
||||
ttl_sec=_HOUR,
|
||||
source="profile_store",
|
||||
fallback="0",
|
||||
invalidated_by=("signals.tip.served",),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user