Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
a90cb7f
feat: Add version tracking to FeatureView, StreamFeatureView, and OnD…
franciscojavierarceo Mar 12, 2026
f28942b
fix: Address PR review feedback from Devin
franciscojavierarceo Mar 12, 2026
171785e
docs: Add feature view versioning documentation
franciscojavierarceo Mar 13, 2026
f035e96
fix: Address second round of PR review feedback from Devin
franciscojavierarceo Mar 13, 2026
0c12655
fix: Clean up version history on delete and use write_engine consiste…
franciscojavierarceo Mar 13, 2026
d32ed52
docs: Clarify versioning auto-increment behavior and pin/revert flow
franciscojavierarceo Mar 13, 2026
f9e896f
fix: Add pin conflict detection to both file and SQL registries
franciscojavierarceo Mar 13, 2026
2069b22
fix: Address Devin review feedback on versioning
franciscojavierarceo Mar 13, 2026
83393aa
docs: Document concurrent multi-version serving limitations
franciscojavierarceo Mar 13, 2026
94afe6e
feat: Implement version-qualified feature references (@v<N>)
franciscojavierarceo Mar 14, 2026
76d1afc
fix: Resolve mypy type errors in proto_registry_utils.py
franciscojavierarceo Mar 15, 2026
2541e41
feat: Add version metadata to clean @v2 syntax from feature names
franciscojavierarceo Mar 16, 2026
bceb052
fix: Update provider implementations with version metadata parameter
franciscojavierarceo Mar 16, 2026
14b2da0
fix: Add version metadata parameter to all online store implementations
franciscojavierarceo Mar 16, 2026
fd776fc
fix: Resolve mypy type errors in versioning code
franciscojavierarceo Mar 17, 2026
e9c4c68
fix: Address Devin review feedback on versioning
franciscojavierarceo Mar 17, 2026
903bda5
fix: Address additional Devin review feedback
franciscojavierarceo Mar 17, 2026
af47911
Merge branch 'master' into featureview-versioning
franciscojavierarceo Mar 17, 2026
dd31cdb
feat: Make feature view versioning opt-in via registry config
franciscojavierarceo Mar 17, 2026
8809805
fix: Address Devin review feedback on versioning issues
franciscojavierarceo Mar 17, 2026
d23c4bb
fix: Preserve version tag in response column names for multi-version …
franciscojavierarceo Mar 17, 2026
c5d4b49
feat: Handle version race conditions gracefully with retry and forwar…
franciscojavierarceo Mar 18, 2026
2a3e544
feat: Gate feature services that reference versioned feature views
franciscojavierarceo Mar 18, 2026
66c280b
fix: Resolve mypy errors and rename config field for clarity
franciscojavierarceo Mar 18, 2026
cfc038b
feat: Enable feature service serving for versioned feature views
franciscojavierarceo Mar 18, 2026
c9aea43
docs: Update RFC for feature service support and rename CLI command
franciscojavierarceo Mar 18, 2026
221e0ed
feat(ui): Add version display and Versions tab to feature view pages
franciscojavierarceo Mar 19, 2026
3efccbf
style(ui): Fix prettier formatting in feature view components
franciscojavierarceo Mar 19, 2026
6878fb0
updated utcnow
franciscojavierarceo Mar 20, 2026
280daf6
feat: Add version-aware materialization support
franciscojavierarceo Mar 20, 2026
43674ac
fix: Resolve three versioning regressions from review feedback
franciscojavierarceo Mar 20, 2026
01e4e77
feat: Add --no-promote flag to feast apply and fix versioned ref parsing
franciscojavierarceo Mar 23, 2026
1876060
docs: Consolidate versioning docs into alpha reference page
franciscojavierarceo Mar 23, 2026
760c003
docs: Add no_promote to apply_diff_to_registry docstring
franciscojavierarceo Mar 24, 2026
bc986ef
fix: Reject reserved chars in FV names and make version parser resilient
franciscojavierarceo Mar 24, 2026
b2d6c09
Merge branch 'master' into featureview-versioning
franciscojavierarceo Mar 24, 2026
3a73c87
fix: Add ensure_valid() call in Snowflake registry apply_feature_view
franciscojavierarceo Mar 24, 2026
1468bc5
Merge branch 'master' into featureview-versioning
franciscojavierarceo Mar 25, 2026
3c1ddbe
fix: Make version_tag optional in proto and use HasField() for correc…
franciscojavierarceo Mar 25, 2026
8c1259f
fix: Address versioning review feedback (Snowflake, Go server, SQL re…
franciscojavierarceo Mar 26, 2026
ac0348d
Merge branch 'master' into featureview-versioning
franciscojavierarceo Mar 26, 2026
7dfc447
fix: Handle @latest in Go feature server and pre-compile version regex
franciscojavierarceo Mar 26, 2026
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
Prev Previous commit
Next Next commit
fix: Address second round of PR review feedback from Devin
- Fix current_version_number roundtrip bug: version="latest" (always
  truthy) caused None to become 0 after proto roundtrip; now check
  that spec.version is not "latest" before treating 0 as intentional
- Use write_engine (not read_engine) for pre/post apply reads in
  SqlRegistry to avoid read replica lag causing missed version snapshots
- Remove redundant version check in StreamFeatureView.__eq__ (parent
  FeatureView.__eq__ already checks it)
- Add else clause to StreamFeatureView.from_proto for consistency
- Add test for latest/None roundtrip preservation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
  • Loading branch information
franciscojavierarceo and claude committed Mar 13, 2026
commit f035e96d45b8b0b276ec64c8f11c3e03a2c06df5
4 changes: 3 additions & 1 deletion sdk/python/feast/feature_view.py
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -644,14 +644,16 @@ def _from_proto_internal(
# Restore version fields.
feature_view.version = feature_view_proto.spec.version or "latest"
# proto3 int32 defaults to 0, so use spec.version to distinguish
# "actually version 0" from "no version set"
# "actually version 0" from "no version set". A version of "latest"
# (or empty) with current_version_number==0 means "not versioned yet".
if feature_view_proto.meta.current_version_number:
feature_view.current_version_number = (
feature_view_proto.meta.current_version_number
)
elif (
feature_view_proto.meta.current_version_number == 0
and feature_view_proto.spec.version
and feature_view_proto.spec.version.lower() != "latest"
):
feature_view.current_version_number = 0
else:
Expand Down
7 changes: 4 additions & 3 deletions sdk/python/feast/infra/registry/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -637,9 +637,10 @@ def apply_feature_view(
)

# Normal (latest) apply: snapshot old version if changed, then save new
# First check if the FV already exists so we can snapshot the old one
# First check if the FV already exists so we can snapshot the old one.
# Use write_engine for both reads to avoid read replica lag issues.
old_proto_bytes = None
with self.read_engine.begin() as conn:
with self.write_engine.begin() as conn:
stmt = select(fv_table).where(
fv_table.c.feature_view_name == feature_view.name,
fv_table.c.project_id == project,
Expand All @@ -656,7 +657,7 @@ def apply_feature_view(
)

# After apply, read the current proto to see if it changed
with self.read_engine.begin() as conn:
with self.write_engine.begin() as conn:
stmt = select(fv_table).where(
fv_table.c.feature_view_name == feature_view.name,
fv_table.c.project_id == project,
Expand Down
1 change: 1 addition & 0 deletions sdk/python/feast/on_demand_feature_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@ def from_proto(
elif (
on_demand_feature_view_proto.meta.current_version_number == 0
and on_demand_feature_view_proto.spec.version
and on_demand_feature_view_proto.spec.version.lower() != "latest"
):
on_demand_feature_view_obj.current_version_number = 0
else:
Expand Down
11 changes: 7 additions & 4 deletions sdk/python/feast/stream_feature_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
)
from feast.transformation.base import Transformation
from feast.transformation.mode import TransformationMode
from feast.version_utils import normalize_version_string

warnings.simplefilter("once", RuntimeWarning)

Expand Down Expand Up @@ -227,8 +226,6 @@ def __eq__(self, other):
or self.udf.__code__.co_code != other.udf.__code__.co_code
or self.udf_string != other.udf_string
or self.aggregations != other.aggregations
or normalize_version_string(self.version)
!= normalize_version_string(other.version)
):
return False
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.

Expand Down Expand Up @@ -364,8 +361,14 @@ def from_proto(cls, sfv_proto):
stream_feature_view.current_version_number = (
sfv_proto.meta.current_version_number
)
elif sfv_proto.meta.current_version_number == 0 and sfv_proto.spec.version:
elif (
sfv_proto.meta.current_version_number == 0
and sfv_proto.spec.version
and sfv_proto.spec.version.lower() != "latest"
):
stream_feature_view.current_version_number = 0
else:
stream_feature_view.current_version_number = None

stream_feature_view.entities = list(sfv_proto.spec.entities)

Expand Down
21 changes: 21 additions & 0 deletions sdk/python/tests/unit/test_feature_view_versioning.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,27 @@ def test_feature_view_proto_roundtrip_v0(self):
assert fv2.version == "v0"
assert fv2.current_version_number == 0

def test_feature_view_proto_roundtrip_latest_none(self):
"""version='latest' with current_version_number=None must not become 0."""
from datetime import timedelta

from feast.entity import Entity
from feast.feature_view import FeatureView

entity = Entity(name="entity_id", join_keys=["entity_id"])
fv = FeatureView(
name="test_fv",
entities=[entity],
ttl=timedelta(days=1),
# default version="latest", current_version_number=None
)
assert fv.current_version_number is None

proto = fv.to_proto()
fv2 = FeatureView.from_proto(proto)
assert fv2.version == "latest"
assert fv2.current_version_number is None

def test_feature_view_equality_with_version(self):
from datetime import timedelta

Expand Down
Loading