Skip to content

fix: Surface FeatureViewPinConflict and version changes during feast plan#6391

Open
Abhishek8108 wants to merge 1 commit intofeast-dev:masterfrom
Abhishek8108:fix/plan-mode-version-pin-conflict-sql-registry
Open

fix: Surface FeatureViewPinConflict and version changes during feast plan#6391
Abhishek8108 wants to merge 1 commit intofeast-dev:masterfrom
Abhishek8108:fix/plan-mode-version-pin-conflict-sql-registry

Conversation

@Abhishek8108
Copy link
Copy Markdown
Contributor

Summary

Closes #6104

Three gaps existed in the plan-mode versioning flow introduced by #6101:

1. FeatureViewPinConflict never raised during feast plan
The conflict check (simultaneous version pin + schema change) only ran inside apply_feature_view(). Users had no way to discover pin conflicts without running feast apply — defeating the purpose of plan mode.

2. Version changes not visible in plan output
diff_registry_objects iterated over spec fields and compared version as a raw proto string ("latest" -> "v2"). The resolved numeric pin target from meta.current_version_number was never surfaced, so users could not see which numeric version they were pinning to or from.

3. No tests for plan-mode versioning
No unit tests covered either of the above.

Changes

BaseRegistry.check_version_pin_conflict() (new method)

Read-only plan-time guard that mirrors the conflict detection inside apply_feature_view. Implemented on BaseRegistry using get_feature_view_by_version and get_any_feature_view — both already declared on BaseRegistry — so it works for both file and SQL registries without duplicating per-registry logic.

Conflict condition: user is simultaneously pinning to an existing version AND the feature view definition differs from the active version (schema or UDF change).

store.plan() — calls the conflict check

Iterates all feature views (FeatureView, StreamFeatureView, OnDemandFeatureView) in desired_repo_contents and calls registry.check_version_pin_conflict() for each, surfacing FeatureViewPinConflict before feast apply runs.

diff_registry_objects() — human-readable version display

  • Added "version" to FIELDS_TO_IGNORE (excluded from generic spec field loop)
  • Added a dedicated version display block that reads meta.current_version_number for the current state and spec.version for the desired state, producing output like:
    Updated feature_view driver_stats
        version: latest -> v2 (pin)
    
    Updated feature_view orders
        version: v1 (pin) -> latest
    

Test plan

  • TestCheckVersionPinConflict::test_latest_version_no_conflict — no-op for latest
  • TestCheckVersionPinConflict::test_forward_declaration_no_conflict — pinning to a non-existent version (forward declaration) does not raise
  • TestCheckVersionPinConflict::test_pin_no_schema_change_no_conflict — pinning to an existing version without schema change does not raise
  • TestCheckVersionPinConflict::test_pin_with_schema_change_raises — pinning to an existing version while also changing schema raises FeatureViewPinConflict
  • TestVersionDiffDisplay::test_no_version_change_no_version_diff — identical FVs produce no version property diff
  • TestVersionDiffDisplay::test_pin_shows_in_diff — pinning shows "v1 (pin)" in declared value
  • TestVersionDiffDisplay::test_unpin_shows_in_diff — unpinning shows "v1 (pin)" in existing value and "latest" in declared
  • TestVersionDiffDisplay::test_plan_calls_pin_conflict_check — plan loop calls check_version_pin_conflict for each FV
  • ruff format --check and ruff check — clean on all 4 modified files

…plan

Resolves feast-dev#6104

Three gaps existed in the plan-mode versioning flow:

1. FeatureViewPinConflict was never raised during `feast plan` — the check
   only ran inside apply_feature_view. Users could not discover pin conflicts
   until after running `feast apply`.

2. The `version` spec field was compared as a raw proto string in
   diff_registry_objects, producing unhelpful output like "latest -> v2".
   The resolved numeric pin target (from meta.current_version_number) was
   never shown.

3. No tests covered plan-mode behaviour for versioned feature views.

Changes:
- BaseRegistry.check_version_pin_conflict(): new read-only method that
  mirrors the conflict detection in apply_feature_view. Uses
  get_feature_view_by_version and get_any_feature_view (both available on
  BaseRegistry) so it works for both file and SQL registries without
  duplicating per-registry logic.

- store.plan(): calls check_version_pin_conflict for every feature view
  (FeatureView, StreamFeatureView, OnDemandFeatureView) in the desired
  repo contents, surfacing conflicts before apply runs.

- diff_registry_objects(): excludes `version` from the generic spec field
  loop (added to FIELDS_TO_IGNORE) and adds a dedicated version display
  block that reads meta.current_version_number for the current state,
  producing output like "v2 (pin) -> v1 (pin)" or "v1 (pin) -> latest".

- 8 new unit tests across TestCheckVersionPinConflict and
  TestVersionDiffDisplay covering: latest-version no-op, forward
  declarations, schema-only changes, pin+schema conflicts, pin display,
  unpin display, and plan-loop wiring.

Signed-off-by: Abhishek8108 <87538407+Abhishek8108@users.noreply.github.com>
@Abhishek8108 Abhishek8108 requested a review from a team as a code owner May 9, 2026 09:46
@Abhishek8108 Abhishek8108 changed the title fix: surface FeatureViewPinConflict and version changes during feast plan fix: Surface FeatureViewPinConflict and version changes during feast plan May 9, 2026
@Abhishek8108
Copy link
Copy Markdown
Contributor Author

Abhishek8108 commented May 9, 2026

The unit-test-python (3.12, macos-14) failure appears to be a pre-existing macOS subprocess flake unrelated to this PR.

Failing test: test_cli_apply_duplicated_featureview_names
Symptom: rc=-1, output=b'' — the subprocess was killed (signal) after ~60 s with no output
Evidence:

  • The test ran for exactly 61 s on the gw2 xdist worker, then reported an empty result — classic subprocess timeout/SIGHUP pattern
  • The nearly identical test test_cli_apply_imported_featureview_with_duplication passed on the same runner seconds later
  • All three Ubuntu matrix jobs and the macOS-14/3.11 job passed
  • The changes in this PR (BaseRegistry.check_version_pin_conflict, store.plan() loop, diff_registry_objects version display) do not touch the duplicate-name validation path — _validate_all_feature_views raises ConflictingFeatureViewNames before any of the new code is reached

This is the same pattern as the test_e2e_local macOS flake seen in past PRs. Could someone please trigger a re-run when you get a chance? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add plan mode support to SQL registry for feature view versioning

1 participant