feat(features): plumb product attrs through FeatureDataLoader (#116)#118
Conversation
Extends FeatureDataLoader so the lifecycle feature family lights up at the HTTP boundary -- closes the last open gap from the PRP-3.1 umbrella (was a PRP-3.1E §16 Open Question 2 follow-up). Changes: * FeatureDataLoader.load_product_attrs(db, product_ids) -- new method loading product.id, launch_date, discontinue_date. No cutoff filter needed (launch/discontinue are timeless product attributes, not facts). Returns an empty DataFrame with the correct columns when no products match, mirroring the load_calendar_data / load_replenishment_events shape. * compute_features_for_series() calls load_product_attrs when config.lifecycle_config is set and merges onto the sales frame via product_id BEFORE constructing the FeatureEngineeringService. The merge attaches the same per-product values to every sales row; _compute_lifecycle_features derives the per-row delta + shift(N) downstream. * test_phase2_integration.py: PHASE2_EXPECTED_COLUMNS expanded to include days_since_launch_lag1 and days_since_discontinue_lag1. The seeded product has launch_date=date(2023, 6, 1) and discontinue_date=None, so launch resolves to a real integer; the discontinue column appears with all-NaN values (header still emitted). * docs/PHASE/3-FEATURE_ENGINEERING.md: removed the "at the HTTP boundary, the current FeatureDataLoader does not yet join..." note and replaced with a positive statement about the end-to-end wiring. Validation: * uv run ruff check . && uv run ruff format --check . -- clean. * uv run mypy app/ -- 0 errors. * uv run pyright app/features/featuresets/ -- 0 errors. * uv run pytest app/features/featuresets/ -v -m "not integration" -- 106 passed. * uv run pytest app/features/featuresets/tests/test_phase2_integration.py -v -m integration -- 3 passed (now exercising the lifecycle path end-to-end against real Postgres). * uv run pytest app/ -m "not integration" -- 952 passed (no regression outside featuresets).
There was a problem hiding this comment.
Sorry @w7-mgfcode, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
Closes #116. Extends
FeatureDataLoaderso the lifecycle feature family lights up at the HTTP boundary — the last open gap from the PRP-3.1 umbrella (was a PRP-3.1E §16 Open Question 2 follow-up that #115 explicitly deferred).FeatureDataLoader.load_product_attrs(db, product_ids)— new method loadingproduct.id/launch_date/discontinue_date. No cutoff filter needed (launch/discontinue are timeless product attributes, not facts). Returns an empty DataFrame with the correct columns when no products match — same shape asload_calendar_data/load_replenishment_events.compute_features_for_series()— callsload_product_attrswhenconfig.lifecycle_config is setand merges onto the sales frame viaproduct_idBEFORE constructing the service. The merge attaches the same per-product values to every sales row;_compute_lifecycle_featuresderives the per-row delta +shift(N)downstream.test_phase2_integration.py—PHASE2_EXPECTED_COLUMNSexpanded to includedays_since_launch_lag1anddays_since_discontinue_lag1. The seeded product haslaunch_date=date(2023, 6, 1)anddiscontinue_date=None, so launch resolves to a real integer; the discontinue column appears with all-NaN values (header still emitted, per the compute method's contract).docs/PHASE/3-FEATURE_ENGINEERING.md— removed the "the currentFeatureDataLoaderdoes not yet join…" note and replaced with a positive statement about the end-to-end wiring.Test plan
uv run ruff check . && uv run ruff format --check .— cleanuv run mypy app/— 0 errorsuv run pyright app/features/featuresets/— 0 errorsuv run pytest app/features/featuresets/ -v -m "not integration"— 106 passeduv run pytest app/features/featuresets/tests/test_phase2_integration.py -v -m integration— 3 passed (now exercising the lifecycle path end-to-end against real Postgres)uv run pytest app/ -m "not integration"— 952 passed (no regression outside featuresets)Diff stat
After this lands
The PRP-3.1 umbrella is fully complete at every layer:
#117 (
ConfigDict(strict=True)audit) remains the only open follow-up.