fix(quality_nudge,bluesky): gate Instagram nudge on EXCLUDE_SOURCES + anchor bluesky tests at resolver

This commit is contained in:
Trevin Chow
2026-05-17 00:32:38 -07:00
parent f236cff86a
commit 1814bb1967
4 changed files with 68 additions and 7 deletions
-1
View File
@@ -24,7 +24,6 @@ from . import http, log
BSKY_SESSION_URL = "https://bsky.social/xrpc/com.atproto.server.createSession" BSKY_SESSION_URL = "https://bsky.social/xrpc/com.atproto.server.createSession"
_DEFAULT_BSKY_SEARCH_HOST = "api.bsky.app" _DEFAULT_BSKY_SEARCH_HOST = "api.bsky.app"
BSKY_SEARCH_URL = f"https://{_DEFAULT_BSKY_SEARCH_HOST}/xrpc/app.bsky.feed.searchPosts"
def _resolve_search_url(config: Optional[Dict[str, Any]] = None) -> str: def _resolve_search_url(config: Optional[Dict[str, Any]] = None) -> str:
@@ -86,6 +86,17 @@ def _is_instagram_silent_failure(config: dict, research_results: dict) -> bool:
""" """
if not config.get("SCRAPECREATORS_API_KEY"): if not config.get("SCRAPECREATORS_API_KEY"):
return False # not configured — not a silent failure return False # not configured — not a silent failure
# Honor EXCLUDE_SOURCES: a user who set EXCLUDE_SOURCES=instagram
# intentionally turned the source off, so a zero-item count is
# expected, not a silent failure. Mirror the canonical parsing
# pattern from pipeline.available_sources().
excluded = {
s.strip().lower()
for s in (config.get("EXCLUDE_SOURCES") or "").split(",")
if s.strip()
}
if "instagram" in excluded:
return False
count = research_results.get("instagram_items_count") count = research_results.get("instagram_items_count")
if count is None: if count is None:
return False # source not run this invocation return False # source not run this invocation
+11 -6
View File
@@ -231,13 +231,18 @@ class TestSearchEndpointHostResolution(unittest.TestCase):
else: else:
os.environ.pop("BSKY_SEARCH_HOST", None) os.environ.pop("BSKY_SEARCH_HOST", None)
def test_module_constant_uses_canonical_appview(self): def test_resolver_default_uses_canonical_appview(self):
# Regression guard against the public mirror reappearing as the default # Regression guard against the public mirror reappearing as the default.
self.assertIn("api.bsky.app", bluesky.BSKY_SEARCH_URL) # Anchored at the resolver because that is the code path search_bluesky
# actually calls; a module-level constant would not catch a resolver
# regression.
self.assertIn("api.bsky.app", bluesky._resolve_search_url())
def test_module_constant_does_not_use_public_mirror(self): def test_resolver_default_does_not_use_public_mirror(self):
# Hard regression guard — the exact host that BunnyCDN was blocking # Hard regression guard — the exact host that BunnyCDN was blocking.
self.assertNotIn("public.api.bsky.app", bluesky.BSKY_SEARCH_URL) # Asserted at the resolver level (the runtime path) so a default-host
# regression in _resolve_search_url is actually caught.
self.assertNotIn("public.api.bsky.app", bluesky._resolve_search_url())
def test_resolver_default_when_no_override(self): def test_resolver_default_when_no_override(self):
self.assertEqual( self.assertEqual(
+46
View File
@@ -469,3 +469,49 @@ class TestInstagramSilentFailure:
q = _compute() q = _compute()
assert q.get("bonus_errored") == [] assert q.get("bonus_errored") == []
def test_exclude_sources_instagram_suppresses_silent_failure(self):
"""User set EXCLUDE_SOURCES=instagram - the source intentionally did
not run, so the zero-count instagram_items_count written by
last30days.py is a non-event, not a silent failure. Pre-fix: the
nudge fired anyway because the gate only checked SC-key + count.
"""
q = _compute(
config_overrides={
"AUTH_TOKEN": "tok123",
"SCRAPECREATORS_API_KEY": "sc_key",
"EXCLUDE_SOURCES": "instagram",
},
ytdlp_installed=True,
result_overrides={"instagram_items_count": 0},
)
assert "instagram" not in q["bonus_errored"]
assert q["nudge_text"] is None
def test_exclude_sources_multi_value_with_instagram(self):
"""Canonical parsing pattern is comma-separated; case-insensitive."""
q = _compute(
config_overrides={
"AUTH_TOKEN": "tok123",
"SCRAPECREATORS_API_KEY": "sc_key",
"EXCLUDE_SOURCES": "threads, Instagram , pinterest",
},
ytdlp_installed=True,
result_overrides={"instagram_items_count": 0},
)
assert "instagram" not in q["bonus_errored"]
def test_exclude_sources_other_value_still_flags(self):
"""EXCLUDE_SOURCES that does not mention instagram must not suppress
the silent-failure nudge for instagram.
"""
q = _compute(
config_overrides={
"AUTH_TOKEN": "tok123",
"SCRAPECREATORS_API_KEY": "sc_key",
"EXCLUDE_SOURCES": "threads",
},
ytdlp_installed=True,
result_overrides={"instagram_items_count": 0},
)
assert "instagram" in q["bonus_errored"]