[bugfix] honor sequence_fields on simple sequence features - #675
Merged
tiankongdeguiji merged 4 commits intoSep 18, 2026
Merged
Conversation
Covers ExprFeature as a grouped sequence sub-feature with a scalar user-side variable and a sequence user-side variable declared via sequence_fields, for both the dense and the bucketized output paths. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tq3essxgD2zr8RuNxeKUJW
ExprFeature._fg_json() only emitted sequence_fields for grouped sequence sub-features, so a simple sequence_expr_feature whose sequence variable is user side silently lost the declaration. pyfg then had no item-side variable to infer the sequence field from and aborted the process with a CHECK failure in sequence_feature.cc. Emit sequence_fields whenever the feature is a sequence; the grouped path and the item-side default are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tq3essxgD2zr8RuNxeKUJW
Same gating as the expr feature: lookup, match, combo, overlap and kv_dot_product only emitted sequence_fields for grouped sequence sub-features, so a simple sequence feature whose sequence input is user side lost the declaration, leaving fg with no item-side input to infer the sequence field from, and it aborted the process with a CHECK failure. Emit sequence_fields whenever the feature is a sequence. The lookup stub chain declaration stays grouped only, fg resolves that reference on its own for a standalone sequence feature. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tq3essxgD2zr8RuNxeKUJW
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tq3essxgD2zr8RuNxeKUJW
tiankongdeguiji
force-pushed
the
chore/grouped-seq-expr-test
branch
from
September 17, 2026 12:01
5615b19 to
13f3d39
Compare
Comment on lines
+694
to
+697
| self.assertEqual(seq_feat.inputs, ["kv_cate", "cate"]) | ||
| self.assertEqual( | ||
| seq_feat.fg_json()[0].get("sequence_fields"), sequence_fields or None | ||
| ) |
Contributor
There was a problem hiding this comment.
Non-blocking: this is the only test covering the value_dim>1 stub+raw shape — the one behavior this PR deliberately made asymmetric (sequence_fields on the stub for simple sequences, raw-cfg __lookup declaration grouped-only). Two cheap pins:
self.assertEqual(seq_feat.sequence_input_names, ["cate"])— every sibling simple-sequence test asserts this; the value_dim variant only assertsinputs.self.assertNotIn("sequence_fields", seq_feat.fg_json()[1])— nothing in the repo asserts anything aboutfg_json()[1], so a future edit that mis-scopes the raw-cfg declaration to simple sequences too (or drops it in a way the grouped parse test doesn't exercise) would pass CI silently.
The grouped value_dim=2 parse case does catch outright removal of the stub declaration (fg aborts without it), so this is just about pinning the simple-mode contract at the json level.
Contributor
|
Review summary Five review passes ran (code quality, performance, test coverage, docs accuracy, security) — all completed. Overall: the fix is correct, surgical, and well-tested. Details and the few non-blocking suggestions below. Verified
Suggestions (non-blocking)
|
eric-gecheng
approved these changes
Sep 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
sequence_fieldswas only emitted for grouped sequence sub-features, so any simple sequence feature (sequence_expr_feature,sequence_lookup_feature, …) whose sequence input is user side silently lost the declaration on its way to the fg json. fg then had no item-side input left to infer the sequence field from and aborted the process withCheck failed: !seq_fields_.empty()insequence_feature.cc— a process abort, not a Python exception.Fix
Emit
sequence_fieldswhenever the feature is a sequence, inExprFeature,LookupFeature,MatchFeature,ComboFeature,OverlapFeatureandKvDotProduct. The grouped path and the item-side default (e.g.variables: ["user:request_time", "item:event_time"]with nosequence_fields) are unchanged.LookupFeature's second declaration — the one pointing the chained raw bucketizer at the__lookupstub forvalue_dim > 1— stays grouped only, since fg resolves that reference on its own for a standalone sequence feature (verified both ways).Single-input features (id / raw / tokenize / combine / regex_replace) need no change: fg already treats their one non-
feature:input as the sequence.CustomFeaturealso needs none, its operator handles the sequence itself.Tests
The shape throughout is the classic time-diff
request_time - event_time,request_timescalar user-side andevent_timethe sequence field.expr_feature_test.py:test_sequence_expr_feature_dense/..._with_boundaries— grouped sub-feature. BecauseExprFeatureis not inSINGLE_INPUT_FEATURE_CLASSESand both variables areuser:-side, the default rule would mark neither as a sequence input; onlysequence_fields=["event_time"]makes it resolve to the group-prefixedclick_50_seq__event_timewhilerequest_timestays scalar. Dense (SequenceDenseData) and bucketized (SequenceSparseData) paths, a string-typed scalar, and null scalar / null sequence rows falling back todefault_value.test_simple_sequence_expr_feature_denseand one new simple-sequence test per cross feature (lookup with boundaries, lookup withvalue_dim=2, match, combo, overlap, kv_dot_product), each parameterized over the item-side default and the user-side field declared throughsequence_fields, asserting the emitted fg json and identical parsed output from both shapes.Docs: a note in the simple-sequence section of
docs/source/feature/feature.mdon whensequence_fieldsis needed there.Test Plan
python -m unittest discover -s tzrec/features -p "*_test.py" -t .— 329 tests pass (was 317 before the new cases).python -m unittest tzrec.datasets.data_parser_test tzrec.datasets.dataset_test— 51 tests pass.pre-commit run --files ...andpyrefly checkclean.Expected values were taken from live pyfg 1.0.6 runs rather than derived by hand, and the user-side cases are cross-checked against the item-side ones, which produce the same numbers.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Tq3essxgD2zr8RuNxeKUJW