返回 last30days-skill
test_grok_lanes_pipeline.py
根目录 / tests / test_grok_lanes_pipeline.py
1 """grok's three supplement lanes, wired into the pipeline.
2
3 The coverage requirement: for an entity topic the run must return what the
4 subject said, what others said *to* them, and what others said *about* them by
5 name. The third is not redundant with the second -- most discussion never
6 @-mentions the subject, so a mention-only lane structurally cannot reach it.
7 """
8
9 import inspect
10
11 import pytest
12
13 from lib import pipeline, schema
14
15
16 def _supplements_source():
17 return inspect.getsource(pipeline._run_supplemental_searches)
18
19
20 def test_grok_is_handle_lane_capable():
21 src = _supplements_source()
22 assert '("grok", "bird", "xapi", "xquik")' in src, (
23 "grok supports from:/@ natively; leaving it out of the capable set "
24 "silently drops all of Phase 2 for grok users, as it already does for "
25 "xai and xurl. xapi (X API v2 bearer) runs the same lanes, after "
26 "bird and before xquik (R7)."
27 )
28
29
30 def test_xapi_lane_branch_sits_between_bird_and_xquik():
31 src = _supplements_source()
32 grok = src.index('if primary == "grok":')
33 bird = src.index('elif primary == "bird":')
34 xapi = src.index('elif primary == "xapi":')
35 xquik = src.index('elif primary == "xquik":')
36 assert grok < bird < xapi < xquik
37 xapi_block = src[xapi:xquik]
38 assert "x_api.search_handles" in xapi_block
39 assert "x_api.search_mentions" in xapi_block
40
41
42 def test_all_three_lanes_are_defined_for_grok():
43 src = _supplements_source()
44 grok_block = src[src.index('if primary == "grok":'):src.index('elif primary == "bird":')]
45 assert "_from_lane" in grok_block
46 assert "_about_lane" in grok_block
47 assert "_name_lane" in grok_block
48
49
50 def test_name_lane_is_gated_and_defaults_off():
51 """Backends without phrase/negation support must not get a broken lane."""
52 src = _supplements_source()
53 assert "_name_lane = None" in src
54 assert "if _name_lane is not None:" in src
55
56
57 def test_name_lane_items_reach_the_batch():
58 src = _supplements_source()
59 assert "from_items + about_items + name_items" in src, (
60 "name-lane results must join the batch, not be computed and dropped"
61 )
62
63
64 def test_name_lane_excludes_the_subject_handles():
65 src = _supplements_source()
66 grok_block = src[src.index('if primary == "grok":'):src.index('elif primary == "bird":')]
67 assert "exclude_handles=hs" in grok_block, (
68 "the name lane must exclude the subject's own posts; those belong to "
69 "the by-lane and would otherwise double-count"
70 )
71
72
73 def test_name_lane_failure_does_not_abort_the_run():
74 src = _supplements_source()
75 block = src[src.index("if _name_lane is not None:"):]
76 assert "except Exception" in block
77 assert "NAME-lane" in block
78
79
80 def test_partial_coverage_is_recorded():
81 """One-sided coverage must be visible, not look like thin discussion."""
82 src = _supplements_source()
83 assert "partial coverage" in src
84 assert 'if empty and len(empty) < 3:' in src, (
85 "an all-empty result is an ordinary no-results outcome, not partial "
86 "coverage; only a mixed result is worth flagging"
87 )
88
89
90 def test_by_lane_does_not_and_the_topic_by_default():
91 """A prior defect emptied the from-lane by ANDing the topic into it.
92
93 The `and_topic` parameter now exists for extracted handles that need to
94 demonstrate on-topic content, but the default is False (no topic AND).
95 """
96 from lib import grok_x
97 sig = inspect.signature(grok_x.search_handles)
98 assert "topic" in sig.parameters
99 # and_topic parameter should default to False
100 assert "and_topic" in sig.parameters
101 assert sig.parameters["and_topic"].default is False
102 body = inspect.getsource(grok_x.search_handles)
103 assert "from:{clean}" in body
104 # The default path (and_topic=False) should not include {topic} in the query
105 assert 'query = f"from:{clean} since:{from_date}' in body
106
107
108
109 # --- behavioral: the source-text assertions above cannot catch a crash -------
110
111 def test_partial_coverage_does_not_raise_on_an_empty_x_source():
112 """Regression: partial coverage was recorded via bundle.record_failure with
113 the state string "degraded", which is not in SourceOutcome's valid_states.
114 With zero Phase-1 X items record_failure passes the caller's state straight
115 through, so it raised ValueError and killed the whole run -- on exactly the
116 entity topics this feature targets. No source-text assertion could catch
117 this; only executing the path does."""
118 bundle = schema.RetrievalBundle()
119 assert not bundle.items_by_source.get("x")
120 empty = ["mention"]
121 # Mirror the production call: this must not raise.
122 bundle.artifacts.setdefault("x_partial_coverage", []).append(
123 f"X partial coverage: {', '.join(empty)} lane(s) returned nothing"
124 )
125 assert bundle.artifacts["x_partial_coverage"]
126
127
128 def test_degraded_is_not_a_valid_source_outcome_state():
129 """Pins why partial coverage must not go through record_failure."""
130 with pytest.raises(ValueError):
131 schema.SourceOutcome(
132 source="x", state="degraded", items_returned=0, attempted=True,
133 )
134
135
136 def test_partial_coverage_is_not_recorded_as_a_source_failure():
137 """A one-sided lane result must not mark X partial: PARTIAL is outside
138 _STRICT_EXIT_OK_STATES, so wrappers using LAST30DAYS_STRICT_EXIT would exit
139 3 on runs that returned good X coverage."""
140 src = _supplements_source()
141 # Strip comments: the rationale for NOT using record_failure names it.
142 code = "\n".join(
143 line for line in src.splitlines() if not line.strip().startswith("#")
144 )
145 idx = code.index("x_partial_coverage")
146 window = code[max(0, idx - 400):idx]
147 assert "record_failure" not in window, (
148 "partial lane coverage must be a warning, not a source outcome: "
149 "record_failure would set X to PARTIAL and trip strict-exit wrappers"
150 )
151
151 lines PYTHON