epic-3/story-3: Add Default Segments and Custom Segment Evaluation - #35
Conversation
There was a problem hiding this comment.
Code Review
This pull request implements custom segment evaluation and default segment persistence (Story 3.3). It introduces a new CustomSegmentsResult class, adds local custom segment evaluation logic in segments.py, and updates Context, ContextState, and Core to handle default_segments separately from visitor attributes. Additionally, conversion tracking has been updated to carry these segments, and comprehensive tests have been added. Feedback on the changes suggests defensively guarding the iteration over snapshot.segments in _resolve_segments to prevent potential TypeError or AttributeError if the segments list or its elements are None.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| by_key = { | ||
| str(segment.get("key")): segment | ||
| for segment in snapshot.segments | ||
| if segment.get("key") is not None | ||
| } |
There was a problem hiding this comment.
To prevent a potential TypeError if snapshot.segments is None, or an AttributeError if any element within snapshot.segments is None, we should defensively guard the iteration and dictionary comprehension.
| by_key = { | |
| str(segment.get("key")): segment | |
| for segment in snapshot.segments | |
| if segment.get("key") is not None | |
| } | |
| by_key = { | |
| str(segment.get("key")): segment | |
| for segment in (snapshot.segments or []) | |
| if segment is not None and segment.get("key") is not None | |
| } |
Beads: ai-driven-product-dev-x45k Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…— implementation (GREEN) Beads: ai-driven-product-dev-x45k Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Beads: ai-driven-product-dev-xsac Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ate — implementation (GREEN) Beads: ai-driven-product-dev-xsac Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Beads: ai-driven-product-dev-l3jz Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… implementation (GREEN) Beads: ai-driven-product-dev-l3jz Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Beads: ai-driven-product-dev-sqzb Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…on segments — implementation (GREEN) Beads: ai-driven-product-dev-sqzb Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…integration round-trip — tests (GREEN) Beads: ai-driven-product-dev-gze9 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
c9d9d13 to
2298a37
Compare
e29bd5f to
231dc35
Compare
…h in custom-segment evaluation — F-066 select_custom_segments evaluated each segment's rule independently, diverging from the JS (segments-manager.ts:100-121) and PHP (SegmentsManager.php:104-128) `segmentsMatched` latch: once an earlier segment's rule matches, subsequent segments are recorded without re-evaluating their own rules. Ordered list [us-visitors, de-visitors] for a US visitor now records [s_us, s_de] (was [s_us]). Rule-less-unconditional, duplicate-skip, and typed-no-match semantics preserved. Added two ordered-multi-segment parity tests. Full suite green (472 passed); segments.py passes ruff + mypy --strict cleanly (pre-existing repo lint/type debt in other files is untouched). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
F-066 — custom-segment matching now applies the JS/PHP
|
|
Superseded — all commits already in main (bc76b64). Closing without merge as part of post-sprint cleanup. |
Story 3.3: Add Default Segments and Custom Segment Evaluation
Part of sprint
sprint/2026-04-06-convert-python-sdk. Stacked on epic-3/story-2 (#34 → #33 → … → #24). Segments-only (FR14 + FR15); entity-lookup is the separate Story 3.4.What was built
domain/context_state.py— DISTINCT immutabledefault_segmentsfield on the frozenContextState+with_segments(...)immutable update (mirrors 3.2'swith_attributes); kept separate fromvisitor_attributes.context.py— publicContext.set_segments(segments: dict[str, str]) -> None(default-segment association) andContext.run_custom_segments(segment_keys, rule_data=None) -> CustomSegmentsResult | None(local custom-segment evaluation). Both reuse the 3.2 rebind + persist-through-DataStorepattern and the 3.1/3.2visitor_state_key()derivation.evaluation/segments.py(NEW, L2) — resolvesConfigSegmententities from the immutableConfigSnapshotand delegates each rule match to the existingevaluation/rules.pyengine (Story 1.4). Fully local, no network.core.py— persistedContextStateevolved to a structured envelope{"attributes": {...}, "segments": {...}}with backward-compatible hydration of the 3.2 plain-attributes dict;create_contextrehydrates segments through the SAME store/key path.tracking/conversions.py+tracker.py— wires the visitor's activedefault_segmentsinto the conversion event'ssegmentsso a tracked conversion's payload reflects them (the seamtracking/payloads.py:_build_visitor_segmentswas waiting on per Story 2.2's TODO). Serializer shape unchanged.domain/results.py— new typedCustomSegmentsResult(exported fromconvert_sdk/__init__.py).Naming resolution
Public methods are the PRD-frozen Pythonic names
set_segments/run_custom_segments(NOT JSsetDefaultSegments/runCustomSegments, NOT the superseded bundled file'sset_default_segments). Per the story's "Concrete Story 3.3 decisions" + Critical Warning #3.Beads
Epic
ai-driven-product-dev-52q2; tasks-x45k,-xsac,-l3jz,-sqzb,-gze9— all closed.Tests
415 → 462 (+47), zero regressions. New
tests/test_segments.py; extendedtests/test_context_creation.py,tests/test_context_state.py,tests/test_conversion_tracking.py,tests/test_layering.py,tests/integration/test_in_memory_store.py(qs-06 round-trip). Two Story 3.2 internal-shape assertions updated for the envelope serialization (behavior unchanged).New public export
CustomSegmentsResultadded to__all__; all previously frozen exports unchanged.Sprint-mode notes
default_segmentsvalue type, persisted serialization shape). See conductor'swork/2026-06-08-add-default-segments-and-custom-segment-evaluation/readiness-assessment.md.🤖 Generated with Claude Code