Context
PRP-3.1B landed _compute_lifecycle_features() and unit-tested it, but at the HTTP boundary POST /featuresets/compute emits zero lifecycle columns because FeatureDataLoader.load_sales_data() only returns sales columns — never joins product.launch_date / product.discontinue_date. The compute method silently skips when both source columns are absent (app/features/featuresets/service.py:489).
PRP-3.1E (#115 closes #109) ships the E2E integration test against the wired-up parts (replenishment + promotion) and explicitly omits lifecycle columns from PHASE2_EXPECTED_COLUMNS, with a docstring + PHASE doc note pointing at this gap.
Goal
Extend FeatureDataLoader so compute_features_for_series() joins product attrs onto the sales frame before calling service.compute_features(). After the change:
days_since_launch_lag1 and days_since_discontinue_lag1 should appear in the response when lifecycle_config is set.
TestPhase2EndToEnd::test_phase2_columns_appear should be extended to expect them (or a new test added).
- The PHASE-3 doc note ("at the HTTP boundary, the current FeatureDataLoader does not yet join …") should be removed.
Acceptance
Out of scope
- Changing the lifecycle compute method itself (PRP-3.1B is the source of truth).
- Plumbing promotion rows through
FeatureDataLoader (separate follow-up — _promotion_rows_df defaults to empty at the HTTP boundary too, but promotion columns DO appear because the compute method emits them with all-zero values).
Refs
- PRP-3.1E §16 Open Question 2
app/features/featuresets/service.py:489 (silent-skip condition)
app/features/featuresets/tests/test_phase2_integration.py (module docstring)
docs/PHASE/3-FEATURE_ENGINEERING.md ("Phase 2 Features (Retail-Depth)" section, lifecycle note)
Context
PRP-3.1B landed
_compute_lifecycle_features()and unit-tested it, but at the HTTP boundaryPOST /featuresets/computeemits zero lifecycle columns becauseFeatureDataLoader.load_sales_data()only returns sales columns — never joinsproduct.launch_date/product.discontinue_date. The compute method silently skips when both source columns are absent (app/features/featuresets/service.py:489).PRP-3.1E (#115 closes #109) ships the E2E integration test against the wired-up parts (replenishment + promotion) and explicitly omits lifecycle columns from
PHASE2_EXPECTED_COLUMNS, with a docstring + PHASE doc note pointing at this gap.Goal
Extend
FeatureDataLoadersocompute_features_for_series()joins product attrs onto the sales frame before callingservice.compute_features(). After the change:days_since_launch_lag1anddays_since_discontinue_lag1should appear in the response whenlifecycle_configis set.TestPhase2EndToEnd::test_phase2_columns_appearshould be extended to expect them (or a new test added).Acceptance
FeatureDataLoader.load_product_attrs(db, product_ids)(or equivalent) added with SQL-side filter onproduct.id.compute_features_for_series()calls it whenconfig.lifecycle_config is not Noneand merges ontodfbefore constructing the service.test_phase2_integration.py::PHASE2_EXPECTED_COLUMNSexpanded to include the lifecycle columns.Out of scope
FeatureDataLoader(separate follow-up —_promotion_rows_dfdefaults to empty at the HTTP boundary too, but promotion columns DO appear because the compute method emits them with all-zero values).Refs
app/features/featuresets/service.py:489(silent-skip condition)app/features/featuresets/tests/test_phase2_integration.py(module docstring)docs/PHASE/3-FEATURE_ENGINEERING.md("Phase 2 Features (Retail-Depth)" section, lifecycle note)