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: Preserve version tag in response column names for multi-version …
…queries

When version-qualified refs (e.g. fv@v1:feat, fv@v2:feat) are used,
include the version tag in full_feature_names output so multi-version
queries produce distinct columns (fv@v1__feat vs fv@v2__feat). Also
fix proto roundtrip test to match -1 sentinel behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
  • Loading branch information
franciscojavierarceo and claude committed Mar 17, 2026
commit d23c4bb4b4d0170dfea7c11fe0be34096fd0a36f
35 changes: 16 additions & 19 deletions sdk/python/feast/utils.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 @@ -543,21 +543,9 @@ def _validate_feature_refs(feature_refs: List[str], full_feature_names: bool = F
collided_feature_refs = []

if full_feature_names:
# Use clean names (without @vN) to detect collisions, since the response
# strips version tags. E.g. 'fv@v1:feat' and 'fv@v2:feat' both produce 'fv__feat'.
clean_refs = [
f"{_parse_feature_ref(ref)[0]}__{_parse_feature_ref(ref)[2]}"
for ref in feature_refs
collided_feature_refs = [
ref for ref, occurrences in Counter(feature_refs).items() if occurrences > 1
]
collided_clean = [
name for name, count in Counter(clean_refs).items() if count > 1
]
if collided_clean:
collided_feature_refs = [
ref
for ref, clean in zip(feature_refs, clean_refs)
if clean in collided_clean
]
else:
feature_names = [_parse_feature_ref(ref)[2] for ref in feature_refs]
collided_feature_names = [
Expand Down Expand Up @@ -1122,10 +1110,13 @@ def _populate_response_from_feature_data(
output_len: The number of result rows in `online_features_response`.
"""
# Add the feature names to the response.
# Use clean name without version tag for response feature names
# Use name_to_use() which includes version tag (e.g. "fv@v2") when a
# version-qualified ref was used, so multi-version queries produce
# distinct column names like "fv@v1__feat" and "fv@v2__feat".
table_name = table.projection.name_to_use()
clean_table_name = table.projection.name_alias or table.projection.name
requested_feature_refs = [
f"{clean_table_name}__{feature_name}" if full_feature_names else feature_name
f"{table_name}__{feature_name}" if full_feature_names else feature_name
for feature_name in requested_features
]
online_features_response.metadata.feature_names.val.extend(requested_feature_refs)
Expand Down Expand Up @@ -1408,12 +1399,18 @@ def _get_online_request_context(
requested_on_demand_feature_views,
)

# Build expected result names using clean FV names (without @vN syntax)
# Build expected result names, including version tag when present so
# multi-version queries (e.g. fv@v1:feat, fv@v2:feat) match the response.
requested_result_row_names = set()
for feat_ref in _feature_refs:
fv_name, _, feature_name = _parse_feature_ref(feat_ref)
fv_name, version_num, feature_name = _parse_feature_ref(feat_ref)
if full_feature_names:
requested_result_row_names.add(f"{fv_name}__{feature_name}")
if version_num is not None:
requested_result_row_names.add(
f"{fv_name}@v{version_num}__{feature_name}"
)
else:
requested_result_row_names.add(f"{fv_name}__{feature_name}")
else:
requested_result_row_names.add(feature_name)

Expand Down
9 changes: 4 additions & 5 deletions sdk/python/tests/unit/test_feature_view_versioning.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,8 @@ def test_feature_view_proto_roundtrip_v0(self):
assert fv2.current_version_number == 0

def test_feature_view_proto_roundtrip_latest_zero(self):
"""version='latest' with current_version_number=None becomes 0 after
proto roundtrip because proto3 cannot distinguish unset int32 from 0.
This is acceptable — 0 is the correct initial version number."""
"""version='latest' with current_version_number=None is preserved as
None through proto roundtrip using a -1 sentinel in the proto."""
from datetime import timedelta

from feast.entity import Entity
Expand All @@ -196,8 +195,8 @@ def test_feature_view_proto_roundtrip_latest_zero(self):
proto = fv.to_proto()
fv2 = FeatureView.from_proto(proto)
assert fv2.version == "latest"
# proto3 int32 default is 0; with version="latest" set, we preserve 0
assert fv2.current_version_number == 0
# -1 sentinel in proto correctly preserves None through roundtrip
assert fv2.current_version_number is None

def test_feature_view_equality_with_version(self):
from datetime import timedelta
Expand Down
Loading